Index: projects/ipsec/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh =================================================================== --- projects/ipsec/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh (revision 313312) +++ projects/ipsec/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/usdt/tst.enabled2.ksh (revision 313313) @@ -1,113 +1,113 @@ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" # # This test is primarily intended to verify a fix for SPARC, but there's no # harm in running it on other platforms. Here, we verify that is-enabled # probes don't interfere with return values from previously invoked functions. # if [ $# != 1 ]; then echo expected one argument: '<'dtrace-path'>' exit 2 fi dtrace=$1 DIR=/var/tmp/dtest.$$ mkdir $DIR cd $DIR cat > prov.d < test.c < #include "prov.h" int foo(void) { return (24); } int main(int argc, char **argv) { int a = foo(); if (TEST_PROV_GO_ENABLED()) { TEST_PROV_GO(); } (void) printf("%d %d %d\n", a, a, a); return (0); } EOF -cc -c -xO2 test.c +cc -c -O2 test.c if [ $? -ne 0 ]; then print -u2 "failed to compile test.c" exit 1 fi $dtrace -G -s prov.d test.o if [ $? -ne 0 ]; then print -u2 "failed to create DOF" exit 1 fi cc -o test test.o prov.o if [ $? -ne 0 ]; then print -u2 "failed to link final executable" exit 1 fi script() { ./test $dtrace -c ./test -qs /dev/stdin < defines _DTRACE_VERSION +# Make sure defines _DTRACE_VERSION DIR=/var/tmp/dtest.$$ mkdir $DIR cd $DIR cat > test.c < +#include int main(int argc, char **argv) { #ifdef _DTRACE_VERSION return (0); #else return (1); #endif } EOF -cc -xarch=generic -o test test.c +cc -o test test.c if [ $? -ne 0 ]; then print -u2 "failed to compile test.c" exit 1 fi ./test status=$? cd / /bin/rm -rf $DIR exit $status Index: projects/ipsec/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c =================================================================== --- projects/ipsec/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c (revision 313312) +++ projects/ipsec/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c (revision 313313) @@ -1,986 +1,976 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011 by Delphix. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include #ifdef illumos #include #endif #include #ifdef illumos #include #endif #include #include #include #include #include #include #include #include #include #include void dt_dof_init(dtrace_hdl_t *dtp) { dt_dof_t *ddo = &dtp->dt_dof; ddo->ddo_hdl = dtp; ddo->ddo_nsecs = 0; ddo->ddo_strsec = DOF_SECIDX_NONE; ddo->ddo_xlimport = NULL; ddo->ddo_xlexport = NULL; dt_buf_create(dtp, &ddo->ddo_secs, "section headers", 0); dt_buf_create(dtp, &ddo->ddo_strs, "string table", 0); dt_buf_create(dtp, &ddo->ddo_ldata, "loadable data", 0); dt_buf_create(dtp, &ddo->ddo_udata, "unloadable data", 0); dt_buf_create(dtp, &ddo->ddo_probes, "probe data", 0); dt_buf_create(dtp, &ddo->ddo_args, "probe args", 0); dt_buf_create(dtp, &ddo->ddo_offs, "probe offs", 0); dt_buf_create(dtp, &ddo->ddo_enoffs, "probe is-enabled offs", 0); dt_buf_create(dtp, &ddo->ddo_rels, "probe rels", 0); dt_buf_create(dtp, &ddo->ddo_xlms, "xlate members", 0); } void dt_dof_fini(dtrace_hdl_t *dtp) { dt_dof_t *ddo = &dtp->dt_dof; dt_free(dtp, ddo->ddo_xlimport); dt_free(dtp, ddo->ddo_xlexport); dt_buf_destroy(dtp, &ddo->ddo_secs); dt_buf_destroy(dtp, &ddo->ddo_strs); dt_buf_destroy(dtp, &ddo->ddo_ldata); dt_buf_destroy(dtp, &ddo->ddo_udata); dt_buf_destroy(dtp, &ddo->ddo_probes); dt_buf_destroy(dtp, &ddo->ddo_args); dt_buf_destroy(dtp, &ddo->ddo_offs); dt_buf_destroy(dtp, &ddo->ddo_enoffs); dt_buf_destroy(dtp, &ddo->ddo_rels); dt_buf_destroy(dtp, &ddo->ddo_xlms); } static int dt_dof_reset(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) { dt_dof_t *ddo = &dtp->dt_dof; uint_t i, nx = dtp->dt_xlatorid; assert(ddo->ddo_hdl == dtp); ddo->ddo_pgp = pgp; ddo->ddo_nsecs = 0; ddo->ddo_strsec = DOF_SECIDX_NONE; dt_free(dtp, ddo->ddo_xlimport); dt_free(dtp, ddo->ddo_xlexport); ddo->ddo_xlimport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx); ddo->ddo_xlexport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx); if (nx != 0 && (ddo->ddo_xlimport == NULL || ddo->ddo_xlexport == NULL)) return (-1); /* errno is set for us */ for (i = 0; i < nx; i++) { ddo->ddo_xlimport[i] = DOF_SECIDX_NONE; ddo->ddo_xlexport[i] = DOF_SECIDX_NONE; } dt_buf_reset(dtp, &ddo->ddo_secs); dt_buf_reset(dtp, &ddo->ddo_strs); dt_buf_reset(dtp, &ddo->ddo_ldata); dt_buf_reset(dtp, &ddo->ddo_udata); dt_buf_reset(dtp, &ddo->ddo_probes); dt_buf_reset(dtp, &ddo->ddo_args); dt_buf_reset(dtp, &ddo->ddo_offs); dt_buf_reset(dtp, &ddo->ddo_enoffs); dt_buf_reset(dtp, &ddo->ddo_rels); dt_buf_reset(dtp, &ddo->ddo_xlms); return (0); } /* * Add a loadable DOF section to the file using the specified data buffer and * the specified DOF section attributes. DOF_SECF_LOAD must be set in flags. * If 'data' is NULL, the caller is responsible for manipulating the ldata buf. */ static dof_secidx_t dof_add_lsect(dt_dof_t *ddo, const void *data, uint32_t type, uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size) { dtrace_hdl_t *dtp = ddo->ddo_hdl; dof_sec_t s; s.dofs_type = type; s.dofs_align = align; s.dofs_flags = flags | DOF_SECF_LOAD; s.dofs_entsize = entsize; s.dofs_offset = dt_buf_offset(&ddo->ddo_ldata, align); s.dofs_size = size; dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t)); if (data != NULL) dt_buf_write(dtp, &ddo->ddo_ldata, data, size, align); return (ddo->ddo_nsecs++); } /* * Add an unloadable DOF section to the file using the specified data buffer * and DOF section attributes. DOF_SECF_LOAD must *not* be set in flags. * If 'data' is NULL, the caller is responsible for manipulating the udata buf. */ static dof_secidx_t dof_add_usect(dt_dof_t *ddo, const void *data, uint32_t type, uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size) { dtrace_hdl_t *dtp = ddo->ddo_hdl; dof_sec_t s; s.dofs_type = type; s.dofs_align = align; s.dofs_flags = flags & ~DOF_SECF_LOAD; s.dofs_entsize = entsize; s.dofs_offset = dt_buf_offset(&ddo->ddo_udata, align); s.dofs_size = size; dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t)); if (data != NULL) dt_buf_write(dtp, &ddo->ddo_udata, data, size, align); return (ddo->ddo_nsecs++); } /* * Add a string to the global string table associated with the DOF. The offset * of the string is returned as an index into the string table. */ static dof_stridx_t dof_add_string(dt_dof_t *ddo, const char *s) { dt_buf_t *bp = &ddo->ddo_strs; dof_stridx_t i = dt_buf_len(bp); if (i != 0 && (s == NULL || *s == '\0')) return (0); /* string table has \0 at offset 0 */ dt_buf_write(ddo->ddo_hdl, bp, s, strlen(s) + 1, sizeof (char)); return (i); } static dof_attr_t dof_attr(const dtrace_attribute_t *ap) { return (DOF_ATTR(ap->dtat_name, ap->dtat_data, ap->dtat_class)); } static dof_secidx_t dof_add_difo(dt_dof_t *ddo, const dtrace_difo_t *dp) { dof_secidx_t dsecs[5]; /* enough for all possible DIFO sections */ uint_t nsecs = 0; dof_difohdr_t *dofd; dof_relohdr_t dofr; dof_secidx_t relsec; dof_secidx_t strsec = DOF_SECIDX_NONE; dof_secidx_t intsec = DOF_SECIDX_NONE; dof_secidx_t hdrsec = DOF_SECIDX_NONE; if (dp->dtdo_buf != NULL) { dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_buf, DOF_SECT_DIF, sizeof (dif_instr_t), 0, sizeof (dif_instr_t), sizeof (dif_instr_t) * dp->dtdo_len); } if (dp->dtdo_inttab != NULL) { dsecs[nsecs++] = intsec = dof_add_lsect(ddo, dp->dtdo_inttab, DOF_SECT_INTTAB, sizeof (uint64_t), 0, sizeof (uint64_t), sizeof (uint64_t) * dp->dtdo_intlen); } if (dp->dtdo_strtab != NULL) { dsecs[nsecs++] = strsec = dof_add_lsect(ddo, dp->dtdo_strtab, DOF_SECT_STRTAB, sizeof (char), 0, 0, dp->dtdo_strlen); } if (dp->dtdo_vartab != NULL) { dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_vartab, DOF_SECT_VARTAB, sizeof (uint_t), 0, sizeof (dtrace_difv_t), sizeof (dtrace_difv_t) * dp->dtdo_varlen); } if (dp->dtdo_xlmtab != NULL) { dof_xlref_t *xlt, *xlp; dt_node_t **pnp; xlt = alloca(sizeof (dof_xlref_t) * dp->dtdo_xlmlen); pnp = dp->dtdo_xlmtab; /* * dtdo_xlmtab contains pointers to the translator members. * The translator itself is in sect ddo_xlimport[dxp->dx_id]. * The XLMEMBERS entries are in order by their dn_membid, so * the member section offset is the population count of bits * in ddo_pgp->dp_xlrefs[] up to and not including dn_membid. */ for (xlp = xlt; xlp < xlt + dp->dtdo_xlmlen; xlp++) { dt_node_t *dnp = *pnp++; dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator; xlp->dofxr_xlator = ddo->ddo_xlimport[dxp->dx_id]; xlp->dofxr_member = dt_popcb( ddo->ddo_pgp->dp_xrefs[dxp->dx_id], dnp->dn_membid); xlp->dofxr_argn = (uint32_t)dxp->dx_arg; } dsecs[nsecs++] = dof_add_lsect(ddo, xlt, DOF_SECT_XLTAB, sizeof (dof_secidx_t), 0, sizeof (dof_xlref_t), sizeof (dof_xlref_t) * dp->dtdo_xlmlen); } /* * Copy the return type and the array of section indices that form the * DIFO into a single dof_difohdr_t and then add DOF_SECT_DIFOHDR. */ assert(nsecs <= sizeof (dsecs) / sizeof (dsecs[0])); dofd = alloca(sizeof (dtrace_diftype_t) + sizeof (dsecs)); bcopy(&dp->dtdo_rtype, &dofd->dofd_rtype, sizeof (dtrace_diftype_t)); bcopy(dsecs, &dofd->dofd_links, sizeof (dof_secidx_t) * nsecs); hdrsec = dof_add_lsect(ddo, dofd, DOF_SECT_DIFOHDR, sizeof (dof_secidx_t), 0, 0, sizeof (dtrace_diftype_t) + sizeof (dof_secidx_t) * nsecs); /* * Add any other sections related to dtrace_difo_t. These are not * referenced in dof_difohdr_t because they are not used by emulation. */ if (dp->dtdo_kreltab != NULL) { relsec = dof_add_lsect(ddo, dp->dtdo_kreltab, DOF_SECT_RELTAB, sizeof (uint64_t), 0, sizeof (dof_relodesc_t), sizeof (dof_relodesc_t) * dp->dtdo_krelen); /* * This code assumes the target of all relocations is the * integer table 'intsec' (DOF_SECT_INTTAB). If other sections * need relocation in the future this will need to change. */ dofr.dofr_strtab = strsec; dofr.dofr_relsec = relsec; dofr.dofr_tgtsec = intsec; (void) dof_add_lsect(ddo, &dofr, DOF_SECT_KRELHDR, sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t)); } if (dp->dtdo_ureltab != NULL) { relsec = dof_add_lsect(ddo, dp->dtdo_ureltab, DOF_SECT_RELTAB, sizeof (uint64_t), 0, sizeof (dof_relodesc_t), sizeof (dof_relodesc_t) * dp->dtdo_urelen); /* * This code assumes the target of all relocations is the * integer table 'intsec' (DOF_SECT_INTTAB). If other sections * need relocation in the future this will need to change. */ dofr.dofr_strtab = strsec; dofr.dofr_relsec = relsec; dofr.dofr_tgtsec = intsec; (void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR, sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t)); } return (hdrsec); } static void dof_add_translator(dt_dof_t *ddo, const dt_xlator_t *dxp, uint_t type) { dtrace_hdl_t *dtp = ddo->ddo_hdl; dof_xlmember_t dofxm; dof_xlator_t dofxl; dof_secidx_t *xst; char buf[DT_TYPE_NAMELEN]; dt_node_t *dnp; uint_t i = 0; assert(type == DOF_SECT_XLIMPORT || type == DOF_SECT_XLEXPORT); xst = type == DOF_SECT_XLIMPORT ? ddo->ddo_xlimport : ddo->ddo_xlexport; if (xst[dxp->dx_id] != DOF_SECIDX_NONE) return; /* translator has already been emitted */ dt_buf_reset(dtp, &ddo->ddo_xlms); /* * Generate an array of dof_xlmember_t's into ddo_xlms. If we are * importing the translator, add only those members referenced by the * program and set the dofxm_difo reference of each member to NONE. If * we're exporting the translator, add all members and a DIFO for each. */ for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list, i++) { if (type == DOF_SECT_XLIMPORT) { if (!BT_TEST(ddo->ddo_pgp->dp_xrefs[dxp->dx_id], i)) continue; /* member is not referenced */ dofxm.dofxm_difo = DOF_SECIDX_NONE; } else { dofxm.dofxm_difo = dof_add_difo(ddo, dxp->dx_membdif[dnp->dn_membid]); } dofxm.dofxm_name = dof_add_string(ddo, dnp->dn_membname); dt_node_diftype(dtp, dnp, &dofxm.dofxm_type); dt_buf_write(dtp, &ddo->ddo_xlms, &dofxm, sizeof (dofxm), sizeof (uint32_t)); } dofxl.dofxl_members = dof_add_lsect(ddo, NULL, DOF_SECT_XLMEMBERS, sizeof (uint32_t), 0, sizeof (dofxm), dt_buf_len(&ddo->ddo_xlms)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_xlms, sizeof (uint32_t)); dofxl.dofxl_strtab = ddo->ddo_strsec; dofxl.dofxl_argv = dof_add_string(ddo, ctf_type_name( dxp->dx_src_ctfp, dxp->dx_src_type, buf, sizeof (buf))); dofxl.dofxl_argc = 1; dofxl.dofxl_type = dof_add_string(ddo, ctf_type_name( dxp->dx_dst_ctfp, dxp->dx_dst_type, buf, sizeof (buf))); dofxl.dofxl_attr = dof_attr(&dxp->dx_souid.di_attr); xst[dxp->dx_id] = dof_add_lsect(ddo, &dofxl, type, sizeof (uint32_t), 0, 0, sizeof (dofxl)); } /*ARGSUSED*/ static int dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) { dt_dof_t *ddo = data; dtrace_hdl_t *dtp = ddo->ddo_hdl; dt_probe_t *prp = idp->di_data; dof_probe_t dofpr; dof_relodesc_t dofr; dt_probe_instance_t *pip; dt_node_t *dnp; char buf[DT_TYPE_NAMELEN]; uint_t i; dofpr.dofpr_addr = 0; dofpr.dofpr_name = dof_add_string(ddo, prp->pr_name); dofpr.dofpr_nargv = dt_buf_len(&ddo->ddo_strs); for (dnp = prp->pr_nargs; dnp != NULL; dnp = dnp->dn_list) { (void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp, dnp->dn_type, buf, sizeof (buf))); } dofpr.dofpr_xargv = dt_buf_len(&ddo->ddo_strs); for (dnp = prp->pr_xargs; dnp != NULL; dnp = dnp->dn_list) { (void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp, dnp->dn_type, buf, sizeof (buf))); } dofpr.dofpr_argidx = dt_buf_len(&ddo->ddo_args) / sizeof (uint8_t); for (i = 0; i < prp->pr_xargc; i++) { dt_buf_write(dtp, &ddo->ddo_args, &prp->pr_mapping[i], sizeof (uint8_t), sizeof (uint8_t)); } dofpr.dofpr_nargc = prp->pr_nargc; dofpr.dofpr_xargc = prp->pr_xargc; dofpr.dofpr_pad1 = 0; dofpr.dofpr_pad2 = 0; for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) { dt_dprintf("adding probe for %s:%s\n", pip->pi_fname, prp->pr_name); dofpr.dofpr_func = dof_add_string(ddo, pip->pi_fname); /* * There should be one probe offset or is-enabled probe offset * or else this probe instance won't have been created. The * kernel will reject DOF which has a probe with no offsets. */ assert(pip->pi_noffs + pip->pi_nenoffs > 0); dofpr.dofpr_offidx = dt_buf_len(&ddo->ddo_offs) / sizeof (uint32_t); dofpr.dofpr_noffs = pip->pi_noffs; dt_buf_write(dtp, &ddo->ddo_offs, pip->pi_offs, pip->pi_noffs * sizeof (uint32_t), sizeof (uint32_t)); dofpr.dofpr_enoffidx = dt_buf_len(&ddo->ddo_enoffs) / sizeof (uint32_t); dofpr.dofpr_nenoffs = pip->pi_nenoffs; dt_buf_write(dtp, &ddo->ddo_enoffs, pip->pi_enoffs, pip->pi_nenoffs * sizeof (uint32_t), sizeof (uint32_t)); - /* - * If pi_rname isn't set, the relocation will be against the - * function name. If it is, the relocation will be against - * pi_rname. This will be used if the function is scoped - * locally so an alternate symbol is added for the purpose - * of this relocation. - */ - if (pip->pi_rname == NULL) - dofr.dofr_name = dofpr.dofpr_func; - else - dofr.dofr_name = dof_add_string(ddo, pip->pi_rname); - dofr.dofr_type = DOF_RELO_SETX; + dofr.dofr_name = dof_add_string(ddo, pip->pi_rname); + dofr.dofr_type = DOF_RELO_DOFREL; dofr.dofr_offset = dt_buf_len(&ddo->ddo_probes); dofr.dofr_data = 0; dt_buf_write(dtp, &ddo->ddo_rels, &dofr, sizeof (dofr), sizeof (uint64_t)); dt_buf_write(dtp, &ddo->ddo_probes, &dofpr, sizeof (dofpr), sizeof (uint64_t)); } return (0); } static int dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp) { dtrace_hdl_t *dtp = ddo->ddo_hdl; dof_provider_t dofpv; dof_relohdr_t dofr; dof_secidx_t *dofs; ulong_t xr, nxr; size_t sz; id_t i; if (pvp->pv_flags & DT_PROVIDER_IMPL) { /* * ignore providers that are exported by dtrace(7D) */ return (0); } nxr = dt_popcb(pvp->pv_xrefs, pvp->pv_xrmax); dofs = alloca(sizeof (dof_secidx_t) * (nxr + 1)); xr = 1; /* reserve dofs[0] for the provider itself */ /* * For each translator referenced by the provider (pv_xrefs), emit an * exported translator section for it if one hasn't been created yet. */ for (i = 0; i < pvp->pv_xrmax; i++) { if (BT_TEST(pvp->pv_xrefs, i) && dtp->dt_xlatemode == DT_XL_DYNAMIC) { dof_add_translator(ddo, dt_xlator_lookup_id(dtp, i), DOF_SECT_XLEXPORT); dofs[xr++] = ddo->ddo_xlexport[i]; } } dt_buf_reset(dtp, &ddo->ddo_probes); dt_buf_reset(dtp, &ddo->ddo_args); dt_buf_reset(dtp, &ddo->ddo_offs); dt_buf_reset(dtp, &ddo->ddo_enoffs); dt_buf_reset(dtp, &ddo->ddo_rels); (void) dt_idhash_iter(pvp->pv_probes, dof_add_probe, ddo); if (dt_buf_len(&ddo->ddo_probes) == 0) return (dt_set_errno(dtp, EDT_NOPROBES)); dofpv.dofpv_probes = dof_add_lsect(ddo, NULL, DOF_SECT_PROBES, sizeof (uint64_t), 0, sizeof (dof_probe_t), dt_buf_len(&ddo->ddo_probes)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_probes, sizeof (uint64_t)); dofpv.dofpv_prargs = dof_add_lsect(ddo, NULL, DOF_SECT_PRARGS, sizeof (uint8_t), 0, sizeof (uint8_t), dt_buf_len(&ddo->ddo_args)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_args, sizeof (uint8_t)); dofpv.dofpv_proffs = dof_add_lsect(ddo, NULL, DOF_SECT_PROFFS, sizeof (uint_t), 0, sizeof (uint_t), dt_buf_len(&ddo->ddo_offs)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_offs, sizeof (uint_t)); if ((sz = dt_buf_len(&ddo->ddo_enoffs)) != 0) { dofpv.dofpv_prenoffs = dof_add_lsect(ddo, NULL, DOF_SECT_PRENOFFS, sizeof (uint_t), 0, sizeof (uint_t), sz); } else { dofpv.dofpv_prenoffs = DOF_SECT_NONE; } dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_enoffs, sizeof (uint_t)); dofpv.dofpv_strtab = ddo->ddo_strsec; dofpv.dofpv_name = dof_add_string(ddo, pvp->pv_desc.dtvd_name); dofpv.dofpv_provattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_provider); dofpv.dofpv_modattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_mod); dofpv.dofpv_funcattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_func); dofpv.dofpv_nameattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_name); dofpv.dofpv_argsattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_args); dofs[0] = dof_add_lsect(ddo, &dofpv, DOF_SECT_PROVIDER, sizeof (dof_secidx_t), 0, 0, sizeof (dof_provider_t)); dofr.dofr_strtab = dofpv.dofpv_strtab; dofr.dofr_tgtsec = dofpv.dofpv_probes; dofr.dofr_relsec = dof_add_lsect(ddo, NULL, DOF_SECT_RELTAB, sizeof (uint64_t), 0, sizeof (dof_relodesc_t), dt_buf_len(&ddo->ddo_rels)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_rels, sizeof (uint64_t)); (void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR, sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t)); if (nxr != 0 && dtp->dt_xlatemode == DT_XL_DYNAMIC) { (void) dof_add_lsect(ddo, dofs, DOF_SECT_PREXPORT, sizeof (dof_secidx_t), 0, sizeof (dof_secidx_t), sizeof (dof_secidx_t) * (nxr + 1)); } return (0); } static int dof_hdr(dtrace_hdl_t *dtp, uint8_t dofversion, dof_hdr_t *hp) { /* * If our config values cannot fit in a uint8_t, we can't generate a * DOF header since the values won't fit. This can only happen if the * user forcibly compiles a program with an artificial configuration. */ if (dtp->dt_conf.dtc_difversion > UINT8_MAX || dtp->dt_conf.dtc_difintregs > UINT8_MAX || dtp->dt_conf.dtc_diftupregs > UINT8_MAX) return (dt_set_errno(dtp, EOVERFLOW)); bzero(hp, sizeof (dof_hdr_t)); hp->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; hp->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; hp->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; hp->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_LP64; else hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_ILP32; hp->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; hp->dofh_ident[DOF_ID_VERSION] = dofversion; hp->dofh_ident[DOF_ID_DIFVERS] = dtp->dt_conf.dtc_difversion; hp->dofh_ident[DOF_ID_DIFIREG] = dtp->dt_conf.dtc_difintregs; hp->dofh_ident[DOF_ID_DIFTREG] = dtp->dt_conf.dtc_diftupregs; hp->dofh_hdrsize = sizeof (dof_hdr_t); hp->dofh_secsize = sizeof (dof_sec_t); hp->dofh_secoff = sizeof (dof_hdr_t); return (0); } void * dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags) { dt_dof_t *ddo = &dtp->dt_dof; const dtrace_ecbdesc_t *edp, *last; const dtrace_probedesc_t *pdp; const dtrace_actdesc_t *ap; const dt_stmt_t *stp; uint_t maxacts = 0; uint_t maxfmt = 0; dt_provider_t *pvp; dt_xlator_t *dxp; dof_actdesc_t *dofa; dof_sec_t *sp; size_t ssize, lsize; dof_hdr_t h; dt_buf_t dof; char *fmt; uint_t i; if (flags & ~DTRACE_D_MASK) { (void) dt_set_errno(dtp, EINVAL); return (NULL); } flags |= dtp->dt_dflags; if (dof_hdr(dtp, pgp->dp_dofversion, &h) != 0) return (NULL); if (dt_dof_reset(dtp, pgp) != 0) return (NULL); /* * Iterate through the statement list computing the maximum number of * actions and the maximum format string for allocating local buffers. */ for (last = NULL, stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = dt_list_next(stp), last = edp) { dtrace_stmtdesc_t *sdp = stp->ds_desc; dtrace_actdesc_t *ap = sdp->dtsd_action; if (sdp->dtsd_fmtdata != NULL) { i = dtrace_printf_format(dtp, sdp->dtsd_fmtdata, NULL, 0); maxfmt = MAX(maxfmt, i); } if ((edp = sdp->dtsd_ecbdesc) == last) continue; /* same ecb as previous statement */ for (i = 0, ap = edp->dted_action; ap; ap = ap->dtad_next) i++; maxacts = MAX(maxacts, i); } dofa = alloca(sizeof (dof_actdesc_t) * maxacts); fmt = alloca(maxfmt + 1); ddo->ddo_strsec = dof_add_lsect(ddo, NULL, DOF_SECT_STRTAB, 1, 0, 0, 0); (void) dof_add_string(ddo, ""); /* * If there are references to dynamic translators in the program, add * an imported translator table entry for each referenced translator. */ if (pgp->dp_xrefslen != 0) { for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = dt_list_next(dxp)) { if (dxp->dx_id < pgp->dp_xrefslen && pgp->dp_xrefs[dxp->dx_id] != NULL) dof_add_translator(ddo, dxp, DOF_SECT_XLIMPORT); } } /* * Now iterate through the statement list, creating the DOF section * headers and data for each one and adding them to our buffers. */ for (last = NULL, stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = dt_list_next(stp), last = edp) { dof_secidx_t probesec = DOF_SECIDX_NONE; dof_secidx_t prdsec = DOF_SECIDX_NONE; dof_secidx_t actsec = DOF_SECIDX_NONE; const dt_stmt_t *next = stp; dtrace_stmtdesc_t *sdp = stp->ds_desc; dof_stridx_t strndx = 0; dof_probedesc_t dofp; dof_ecbdesc_t dofe; uint_t i; if ((edp = stp->ds_desc->dtsd_ecbdesc) == last) continue; /* same ecb as previous statement */ pdp = &edp->dted_probe; /* * Add a DOF_SECT_PROBEDESC for the ECB's probe description, * and copy the probe description strings into the string table. */ dofp.dofp_strtab = ddo->ddo_strsec; dofp.dofp_provider = dof_add_string(ddo, pdp->dtpd_provider); dofp.dofp_mod = dof_add_string(ddo, pdp->dtpd_mod); dofp.dofp_func = dof_add_string(ddo, pdp->dtpd_func); dofp.dofp_name = dof_add_string(ddo, pdp->dtpd_name); dofp.dofp_id = pdp->dtpd_id; probesec = dof_add_lsect(ddo, &dofp, DOF_SECT_PROBEDESC, sizeof (dof_secidx_t), 0, sizeof (dof_probedesc_t), sizeof (dof_probedesc_t)); /* * If there is a predicate DIFO associated with the ecbdesc, * write out the DIFO sections and save the DIFO section index. */ if (edp->dted_pred.dtpdd_difo != NULL) prdsec = dof_add_difo(ddo, edp->dted_pred.dtpdd_difo); /* * Now iterate through the action list generating DIFOs as * referenced therein and adding action descriptions to 'dofa'. */ for (i = 0, ap = edp->dted_action; ap != NULL; ap = ap->dtad_next, i++) { if (ap->dtad_difo != NULL) { dofa[i].dofa_difo = dof_add_difo(ddo, ap->dtad_difo); } else dofa[i].dofa_difo = DOF_SECIDX_NONE; /* * If the first action in a statement has string data, * add the string to the global string table. This can * be due either to a printf() format string * (dtsd_fmtdata) or a print() type string * (dtsd_strdata). */ if (sdp != NULL && ap == sdp->dtsd_action) { if (sdp->dtsd_fmtdata != NULL) { (void) dtrace_printf_format(dtp, sdp->dtsd_fmtdata, fmt, maxfmt + 1); strndx = dof_add_string(ddo, fmt); } else if (sdp->dtsd_strdata != NULL) { strndx = dof_add_string(ddo, sdp->dtsd_strdata); } else { strndx = 0; /* use dtad_arg instead */ } if ((next = dt_list_next(next)) != NULL) sdp = next->ds_desc; else sdp = NULL; } if (strndx != 0) { dofa[i].dofa_arg = strndx; dofa[i].dofa_strtab = ddo->ddo_strsec; } else { dofa[i].dofa_arg = ap->dtad_arg; dofa[i].dofa_strtab = DOF_SECIDX_NONE; } dofa[i].dofa_kind = ap->dtad_kind; dofa[i].dofa_ntuple = ap->dtad_ntuple; dofa[i].dofa_uarg = ap->dtad_uarg; } if (i > 0) { actsec = dof_add_lsect(ddo, dofa, DOF_SECT_ACTDESC, sizeof (uint64_t), 0, sizeof (dof_actdesc_t), sizeof (dof_actdesc_t) * i); } /* * Now finally, add the DOF_SECT_ECBDESC referencing all the * previously created sub-sections. */ dofe.dofe_probes = probesec; dofe.dofe_pred = prdsec; dofe.dofe_actions = actsec; dofe.dofe_pad = 0; dofe.dofe_uarg = edp->dted_uarg; (void) dof_add_lsect(ddo, &dofe, DOF_SECT_ECBDESC, sizeof (uint64_t), 0, 0, sizeof (dof_ecbdesc_t)); } /* * If any providers are user-defined, output DOF sections corresponding * to the providers and the probes and arguments that they define. */ if (flags & DTRACE_D_PROBES) { for (pvp = dt_list_next(&dtp->dt_provlist); pvp != NULL; pvp = dt_list_next(pvp)) { if (dof_add_provider(ddo, pvp) != 0) return (NULL); } } /* * If we're not stripping unloadable sections, generate compiler * comments and any other unloadable miscellany. */ if (!(flags & DTRACE_D_STRIP)) { (void) dof_add_usect(ddo, _dtrace_version, DOF_SECT_COMMENTS, sizeof (char), 0, 0, strlen(_dtrace_version) + 1); (void) dof_add_usect(ddo, &dtp->dt_uts, DOF_SECT_UTSNAME, sizeof (char), 0, 0, sizeof (struct utsname)); } /* * Compute and fill in the appropriate values for the dof_hdr_t's * dofh_secnum, dofh_loadsz, and dofh_filez values. */ h.dofh_secnum = ddo->ddo_nsecs; ssize = sizeof (h) + dt_buf_len(&ddo->ddo_secs); h.dofh_loadsz = ssize + dt_buf_len(&ddo->ddo_ldata) + dt_buf_len(&ddo->ddo_strs); if (dt_buf_len(&ddo->ddo_udata) != 0) { lsize = roundup(h.dofh_loadsz, sizeof (uint64_t)); h.dofh_filesz = lsize + dt_buf_len(&ddo->ddo_udata); } else { lsize = h.dofh_loadsz; h.dofh_filesz = lsize; } /* * Set the global DOF_SECT_STRTAB's offset to be after the header, * section headers, and other loadable data. Since we're going to * iterate over the buffer data directly, we must check for errors. */ if ((i = dt_buf_error(&ddo->ddo_secs)) != 0) { (void) dt_set_errno(dtp, i); return (NULL); } sp = dt_buf_ptr(&ddo->ddo_secs); assert(sp[ddo->ddo_strsec].dofs_type == DOF_SECT_STRTAB); assert(ssize == sizeof (h) + sizeof (dof_sec_t) * ddo->ddo_nsecs); sp[ddo->ddo_strsec].dofs_offset = ssize + dt_buf_len(&ddo->ddo_ldata); sp[ddo->ddo_strsec].dofs_size = dt_buf_len(&ddo->ddo_strs); /* * Now relocate all the other section headers by adding the appropriate * delta to their respective dofs_offset values. */ for (i = 0; i < ddo->ddo_nsecs; i++, sp++) { if (i == ddo->ddo_strsec) continue; /* already relocated above */ if (sp->dofs_flags & DOF_SECF_LOAD) sp->dofs_offset += ssize; else sp->dofs_offset += lsize; } /* * Finally, assemble the complete in-memory DOF buffer by writing the * header and then concatenating all our buffers. dt_buf_concat() will * propagate any errors and cause dt_buf_claim() to return NULL. */ dt_buf_create(dtp, &dof, "dof", h.dofh_filesz); dt_buf_write(dtp, &dof, &h, sizeof (h), sizeof (uint64_t)); dt_buf_concat(dtp, &dof, &ddo->ddo_secs, sizeof (uint64_t)); dt_buf_concat(dtp, &dof, &ddo->ddo_ldata, sizeof (uint64_t)); dt_buf_concat(dtp, &dof, &ddo->ddo_strs, sizeof (char)); dt_buf_concat(dtp, &dof, &ddo->ddo_udata, sizeof (uint64_t)); return (dt_buf_claim(dtp, &dof)); } void dtrace_dof_destroy(dtrace_hdl_t *dtp, void *dof) { dt_free(dtp, dof); } void * dtrace_getopt_dof(dtrace_hdl_t *dtp) { dof_hdr_t *dof; dof_sec_t *sec; dof_optdesc_t *dofo; int i, nopts = 0, len = sizeof (dof_hdr_t) + roundup(sizeof (dof_sec_t), sizeof (uint64_t)); for (i = 0; i < DTRACEOPT_MAX; i++) { if (dtp->dt_options[i] != DTRACEOPT_UNSET) nopts++; } len += sizeof (dof_optdesc_t) * nopts; if ((dof = dt_zalloc(dtp, len)) == NULL || dof_hdr(dtp, DOF_VERSION, dof) != 0) { dt_free(dtp, dof); return (NULL); } dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */ dof->dofh_loadsz = len; dof->dofh_filesz = len; /* * Fill in the option section header... */ sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t)); sec->dofs_type = DOF_SECT_OPTDESC; sec->dofs_align = sizeof (uint64_t); sec->dofs_flags = DOF_SECF_LOAD; sec->dofs_entsize = sizeof (dof_optdesc_t); dofo = (dof_optdesc_t *)((uintptr_t)sec + roundup(sizeof (dof_sec_t), sizeof (uint64_t))); sec->dofs_offset = (uintptr_t)dofo - (uintptr_t)dof; sec->dofs_size = sizeof (dof_optdesc_t) * nopts; for (i = 0; i < DTRACEOPT_MAX; i++) { if (dtp->dt_options[i] == DTRACEOPT_UNSET) continue; dofo->dofo_option = i; dofo->dofo_strtab = DOF_SECIDX_NONE; dofo->dofo_value = dtp->dt_options[i]; dofo++; } return (dof); } void * dtrace_geterr_dof(dtrace_hdl_t *dtp) { if (dtp->dt_errprog != NULL) return (dtrace_dof_create(dtp, dtp->dt_errprog, 0)); (void) dt_set_errno(dtp, EDT_BADERROR); return (NULL); } Index: projects/ipsec/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c =================================================================== --- projects/ipsec/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c (revision 313312) +++ projects/ipsec/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c (revision 313313) @@ -1,1983 +1,1945 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #define ELF_TARGET_ALL #include #include #ifdef illumos #include #else #define P2ROUNDUP(x, align) (-(-(x) & -(align))) #endif #include #include #ifdef illumos #include #endif #include #include #include #include #include #include #ifdef illumos #include #else #include #include #include #include #endif #include #include #include #include #include #include #define ESHDR_NULL 0 #define ESHDR_SHSTRTAB 1 #define ESHDR_DOF 2 #define ESHDR_STRTAB 3 #define ESHDR_SYMTAB 4 #define ESHDR_REL 5 #define ESHDR_NUM 6 #define PWRITE_SCN(index, data) \ (lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \ (off64_t)elf_file.shdr[(index)].sh_offset || \ dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \ elf_file.shdr[(index)].sh_size) static const char DTRACE_SHSTRTAB32[] = "\0" ".shstrtab\0" /* 1 */ ".SUNW_dof\0" /* 11 */ ".strtab\0" /* 21 */ ".symtab\0" /* 29 */ #ifdef __sparc ".rela.SUNW_dof"; /* 37 */ #else ".rel.SUNW_dof"; /* 37 */ #endif static const char DTRACE_SHSTRTAB64[] = "\0" ".shstrtab\0" /* 1 */ ".SUNW_dof\0" /* 11 */ ".strtab\0" /* 21 */ ".symtab\0" /* 29 */ ".rela.SUNW_dof"; /* 37 */ static const char DOFSTR[] = "__SUNW_dof"; static const char DOFLAZYSTR[] = "___SUNW_dof"; typedef struct dt_link_pair { struct dt_link_pair *dlp_next; /* next pair in linked list */ void *dlp_str; /* buffer for string table */ void *dlp_sym; /* buffer for symbol table */ } dt_link_pair_t; typedef struct dof_elf32 { uint32_t de_nrel; /* relocation count */ #ifdef __sparc Elf32_Rela *de_rel; /* array of relocations for sparc */ #else Elf32_Rel *de_rel; /* array of relocations for x86 */ #endif uint32_t de_nsym; /* symbol count */ Elf32_Sym *de_sym; /* array of symbols */ uint32_t de_strlen; /* size of of string table */ char *de_strtab; /* string table */ uint32_t de_global; /* index of the first global symbol */ } dof_elf32_t; static int prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) { dof_sec_t *dofs, *s; dof_relohdr_t *dofrh; dof_relodesc_t *dofr; char *strtab; int i, j, nrel; size_t strtabsz = 1; uint32_t count = 0; size_t base; Elf32_Sym *sym; #ifdef __sparc Elf32_Rela *rel; #else Elf32_Rel *rel; #endif /*LINTED*/ dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); /* * First compute the size of the string table and the number of * relocations present in the DOF. */ for (i = 0; i < dof->dofh_secnum; i++) { if (dofs[i].dofs_type != DOF_SECT_URELHDR) continue; /*LINTED*/ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); s = &dofs[dofrh->dofr_strtab]; strtab = (char *)dof + s->dofs_offset; assert(strtab[0] == '\0'); strtabsz += s->dofs_size - 1; s = &dofs[dofrh->dofr_relsec]; /*LINTED*/ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); count += s->dofs_size / s->dofs_entsize; } dep->de_strlen = strtabsz; dep->de_nrel = count; dep->de_nsym = count + 1; /* the first symbol is always null */ if (dtp->dt_lazyload) { dep->de_strlen += sizeof (DOFLAZYSTR); dep->de_nsym++; } else { dep->de_strlen += sizeof (DOFSTR); dep->de_nsym++; } if ((dep->de_rel = calloc(dep->de_nrel, sizeof (dep->de_rel[0]))) == NULL) { return (dt_set_errno(dtp, EDT_NOMEM)); } if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) { free(dep->de_rel); return (dt_set_errno(dtp, EDT_NOMEM)); } if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { free(dep->de_rel); free(dep->de_sym); return (dt_set_errno(dtp, EDT_NOMEM)); } count = 0; strtabsz = 1; dep->de_strtab[0] = '\0'; rel = dep->de_rel; sym = dep->de_sym; dep->de_global = 1; /* * The first symbol table entry must be zeroed and is always ignored. */ bzero(sym, sizeof (Elf32_Sym)); sym++; /* * Take a second pass through the DOF sections filling in the * memory we allocated. */ for (i = 0; i < dof->dofh_secnum; i++) { if (dofs[i].dofs_type != DOF_SECT_URELHDR) continue; /*LINTED*/ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); s = &dofs[dofrh->dofr_strtab]; strtab = (char *)dof + s->dofs_offset; bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); base = strtabsz; strtabsz += s->dofs_size - 1; s = &dofs[dofrh->dofr_relsec]; /*LINTED*/ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); nrel = s->dofs_size / s->dofs_entsize; s = &dofs[dofrh->dofr_tgtsec]; for (j = 0; j < nrel; j++) { #if defined(__aarch64__) /* XXX */ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); #elif defined(__arm__) /* XXX */ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); #elif defined(__i386) || defined(__amd64) rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; rel->r_info = ELF32_R_INFO(count + dep->de_global, - R_386_32); + R_386_PC32); #elif defined(__mips__) /* XXX */ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); #elif defined(__powerpc__) /* * Add 4 bytes to hit the low half of this 64-bit * big-endian address. */ rel->r_offset = s->dofs_offset + dofr[j].dofr_offset + 4; rel->r_info = ELF32_R_INFO(count + dep->de_global, R_PPC_REL32); #elif defined(__riscv__) /* XXX */ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); -#elif defined(__sparc) - /* - * Add 4 bytes to hit the low half of this 64-bit - * big-endian address. - */ - rel->r_offset = s->dofs_offset + - dofr[j].dofr_offset + 4; - rel->r_info = ELF32_R_INFO(count + dep->de_global, - R_SPARC_32); #else #error unknown ISA #endif sym->st_name = base + dofr[j].dofr_name - 1; sym->st_value = 0; sym->st_size = 0; sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC); - sym->st_other = 0; + sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN); sym->st_shndx = SHN_UNDEF; rel++; sym++; count++; } } /* * Add a symbol for the DOF itself. We use a different symbol for * lazily and actively loaded DOF to make them easy to distinguish. */ sym->st_name = strtabsz; sym->st_value = 0; sym->st_size = dof->dofh_filesz; sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT); -#ifdef illumos - sym->st_other = 0; -#else sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN); -#endif sym->st_shndx = ESHDR_DOF; sym++; if (dtp->dt_lazyload) { bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, sizeof (DOFLAZYSTR)); strtabsz += sizeof (DOFLAZYSTR); } else { bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); strtabsz += sizeof (DOFSTR); } assert(count == dep->de_nrel); assert(strtabsz == dep->de_strlen); return (0); } typedef struct dof_elf64 { uint32_t de_nrel; Elf64_Rela *de_rel; uint32_t de_nsym; Elf64_Sym *de_sym; uint32_t de_strlen; char *de_strtab; uint32_t de_global; } dof_elf64_t; static int prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) { dof_sec_t *dofs, *s; dof_relohdr_t *dofrh; dof_relodesc_t *dofr; char *strtab; int i, j, nrel; size_t strtabsz = 1; #ifdef illumos uint32_t count = 0; #else uint64_t count = 0; #endif size_t base; Elf64_Sym *sym; Elf64_Rela *rel; /*LINTED*/ dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); /* * First compute the size of the string table and the number of * relocations present in the DOF. */ for (i = 0; i < dof->dofh_secnum; i++) { if (dofs[i].dofs_type != DOF_SECT_URELHDR) continue; /*LINTED*/ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); s = &dofs[dofrh->dofr_strtab]; strtab = (char *)dof + s->dofs_offset; assert(strtab[0] == '\0'); strtabsz += s->dofs_size - 1; s = &dofs[dofrh->dofr_relsec]; /*LINTED*/ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); count += s->dofs_size / s->dofs_entsize; } dep->de_strlen = strtabsz; dep->de_nrel = count; dep->de_nsym = count + 1; /* the first symbol is always null */ if (dtp->dt_lazyload) { dep->de_strlen += sizeof (DOFLAZYSTR); dep->de_nsym++; } else { dep->de_strlen += sizeof (DOFSTR); dep->de_nsym++; } if ((dep->de_rel = calloc(dep->de_nrel, sizeof (dep->de_rel[0]))) == NULL) { return (dt_set_errno(dtp, EDT_NOMEM)); } if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) { free(dep->de_rel); return (dt_set_errno(dtp, EDT_NOMEM)); } if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { free(dep->de_rel); free(dep->de_sym); return (dt_set_errno(dtp, EDT_NOMEM)); } count = 0; strtabsz = 1; dep->de_strtab[0] = '\0'; rel = dep->de_rel; sym = dep->de_sym; dep->de_global = 1; /* * The first symbol table entry must be zeroed and is always ignored. */ bzero(sym, sizeof (Elf64_Sym)); sym++; /* * Take a second pass through the DOF sections filling in the * memory we allocated. */ for (i = 0; i < dof->dofh_secnum; i++) { if (dofs[i].dofs_type != DOF_SECT_URELHDR) continue; /*LINTED*/ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); s = &dofs[dofrh->dofr_strtab]; strtab = (char *)dof + s->dofs_offset; bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); base = strtabsz; strtabsz += s->dofs_size - 1; s = &dofs[dofrh->dofr_relsec]; /*LINTED*/ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); nrel = s->dofs_size / s->dofs_entsize; s = &dofs[dofrh->dofr_tgtsec]; for (j = 0; j < nrel; j++) { #if defined(__aarch64__) /* XXX */ #elif defined(__arm__) /* XXX */ #elif defined(__mips__) /* XXX */ #elif defined(__powerpc__) rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; rel->r_info = ELF64_R_INFO(count + dep->de_global, R_PPC64_REL64); #elif defined(__riscv__) /* XXX */ #elif defined(__i386) || defined(__amd64) rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; -#ifdef illumos rel->r_info = ELF64_R_INFO(count + dep->de_global, - R_AMD64_64); + R_X86_64_PC64); #else - rel->r_info = ELF64_R_INFO(count + dep->de_global, - R_X86_64_RELATIVE); -#endif -#elif defined(__sparc) - rel->r_offset = s->dofs_offset + - dofr[j].dofr_offset; - rel->r_info = ELF64_R_INFO(count + dep->de_global, - R_SPARC_64); -#else #error unknown ISA #endif sym->st_name = base + dofr[j].dofr_name - 1; sym->st_value = 0; sym->st_size = 0; sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); - sym->st_other = 0; + sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN); sym->st_shndx = SHN_UNDEF; rel++; sym++; count++; } } /* * Add a symbol for the DOF itself. We use a different symbol for * lazily and actively loaded DOF to make them easy to distinguish. */ sym->st_name = strtabsz; sym->st_value = 0; sym->st_size = dof->dofh_filesz; sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT); -#ifdef illumos - sym->st_other = 0; -#else sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN); -#endif sym->st_shndx = ESHDR_DOF; sym++; if (dtp->dt_lazyload) { bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, sizeof (DOFLAZYSTR)); strtabsz += sizeof (DOFLAZYSTR); } else { bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); strtabsz += sizeof (DOFSTR); } assert(count == dep->de_nrel); assert(strtabsz == dep->de_strlen); return (0); } /* * Write out an ELF32 file prologue consisting of a header, section headers, * and a section header string table. The DOF data will follow this prologue * and complete the contents of the given ELF file. */ static int dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) { struct { Elf32_Ehdr ehdr; Elf32_Shdr shdr[ESHDR_NUM]; } elf_file; Elf32_Shdr *shp; Elf32_Off off; dof_elf32_t de; int ret = 0; uint_t nshdr; if (prepare_elf32(dtp, dof, &de) != 0) return (-1); /* errno is set for us */ /* * If there are no relocations, we only need enough sections for * the shstrtab and the DOF. */ nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; bzero(&elf_file, sizeof (elf_file)); elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32; #if BYTE_ORDER == _BIG_ENDIAN elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; #else elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; #endif #if defined(__FreeBSD__) elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; #endif elf_file.ehdr.e_type = ET_REL; #if defined(__arm__) elf_file.ehdr.e_machine = EM_ARM; #elif defined(__mips__) elf_file.ehdr.e_machine = EM_MIPS; #elif defined(__powerpc__) elf_file.ehdr.e_machine = EM_PPC; #elif defined(__sparc) elf_file.ehdr.e_machine = EM_SPARC; #elif defined(__i386) || defined(__amd64) elf_file.ehdr.e_machine = EM_386; #endif elf_file.ehdr.e_version = EV_CURRENT; elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr); elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr); elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr); elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr); elf_file.ehdr.e_shnum = nshdr; elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr); shp = &elf_file.shdr[ESHDR_SHSTRTAB]; shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */ shp->sh_type = SHT_STRTAB; shp->sh_offset = off; shp->sh_size = sizeof (DTRACE_SHSTRTAB32); shp->sh_addralign = sizeof (char); off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); shp = &elf_file.shdr[ESHDR_DOF]; shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_SUNW_dof; shp->sh_offset = off; shp->sh_size = dof->dofh_filesz; shp->sh_addralign = 8; off = shp->sh_offset + shp->sh_size; shp = &elf_file.shdr[ESHDR_STRTAB]; shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_STRTAB; shp->sh_offset = off; shp->sh_size = de.de_strlen; shp->sh_addralign = sizeof (char); off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); shp = &elf_file.shdr[ESHDR_SYMTAB]; shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_SYMTAB; shp->sh_entsize = sizeof (Elf32_Sym); shp->sh_link = ESHDR_STRTAB; shp->sh_offset = off; shp->sh_info = de.de_global; shp->sh_size = de.de_nsym * sizeof (Elf32_Sym); shp->sh_addralign = 4; off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); if (de.de_nrel == 0) { if (dt_write(dtp, fd, &elf_file, sizeof (elf_file)) != sizeof (elf_file) || PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || PWRITE_SCN(ESHDR_DOF, dof)) { ret = dt_set_errno(dtp, errno); } } else { shp = &elf_file.shdr[ESHDR_REL]; shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */ shp->sh_flags = SHF_ALLOC; #ifdef __sparc shp->sh_type = SHT_RELA; #else shp->sh_type = SHT_REL; #endif shp->sh_entsize = sizeof (de.de_rel[0]); shp->sh_link = ESHDR_SYMTAB; shp->sh_info = ESHDR_DOF; shp->sh_offset = off; shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); shp->sh_addralign = 4; if (dt_write(dtp, fd, &elf_file, sizeof (elf_file)) != sizeof (elf_file) || PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || PWRITE_SCN(ESHDR_REL, de.de_rel) || PWRITE_SCN(ESHDR_DOF, dof)) { ret = dt_set_errno(dtp, errno); } } free(de.de_strtab); free(de.de_sym); free(de.de_rel); return (ret); } /* * Write out an ELF64 file prologue consisting of a header, section headers, * and a section header string table. The DOF data will follow this prologue * and complete the contents of the given ELF file. */ static int dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) { struct { Elf64_Ehdr ehdr; Elf64_Shdr shdr[ESHDR_NUM]; } elf_file; Elf64_Shdr *shp; Elf64_Off off; dof_elf64_t de; int ret = 0; uint_t nshdr; if (prepare_elf64(dtp, dof, &de) != 0) return (-1); /* errno is set for us */ /* * If there are no relocations, we only need enough sections for * the shstrtab and the DOF. */ nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; bzero(&elf_file, sizeof (elf_file)); elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64; #if BYTE_ORDER == _BIG_ENDIAN elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; #else elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; #endif #if defined(__FreeBSD__) elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; #endif elf_file.ehdr.e_type = ET_REL; #if defined(__arm__) elf_file.ehdr.e_machine = EM_ARM; #elif defined(__mips__) elf_file.ehdr.e_machine = EM_MIPS; #elif defined(__powerpc64__) elf_file.ehdr.e_machine = EM_PPC64; #elif defined(__sparc) elf_file.ehdr.e_machine = EM_SPARCV9; #elif defined(__i386) || defined(__amd64) elf_file.ehdr.e_machine = EM_AMD64; #endif elf_file.ehdr.e_version = EV_CURRENT; elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr); elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr); elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr); elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr); elf_file.ehdr.e_shnum = nshdr; elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr); shp = &elf_file.shdr[ESHDR_SHSTRTAB]; shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */ shp->sh_type = SHT_STRTAB; shp->sh_offset = off; shp->sh_size = sizeof (DTRACE_SHSTRTAB64); shp->sh_addralign = sizeof (char); off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); shp = &elf_file.shdr[ESHDR_DOF]; shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_SUNW_dof; shp->sh_offset = off; shp->sh_size = dof->dofh_filesz; shp->sh_addralign = 8; off = shp->sh_offset + shp->sh_size; shp = &elf_file.shdr[ESHDR_STRTAB]; shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_STRTAB; shp->sh_offset = off; shp->sh_size = de.de_strlen; shp->sh_addralign = sizeof (char); off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); shp = &elf_file.shdr[ESHDR_SYMTAB]; shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_SYMTAB; shp->sh_entsize = sizeof (Elf64_Sym); shp->sh_link = ESHDR_STRTAB; shp->sh_offset = off; shp->sh_info = de.de_global; shp->sh_size = de.de_nsym * sizeof (Elf64_Sym); shp->sh_addralign = 8; off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); if (de.de_nrel == 0) { if (dt_write(dtp, fd, &elf_file, sizeof (elf_file)) != sizeof (elf_file) || PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || PWRITE_SCN(ESHDR_DOF, dof)) { ret = dt_set_errno(dtp, errno); } } else { shp = &elf_file.shdr[ESHDR_REL]; shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_RELA; shp->sh_entsize = sizeof (de.de_rel[0]); shp->sh_link = ESHDR_SYMTAB; shp->sh_info = ESHDR_DOF; shp->sh_offset = off; shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); shp->sh_addralign = 8; if (dt_write(dtp, fd, &elf_file, sizeof (elf_file)) != sizeof (elf_file) || PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || PWRITE_SCN(ESHDR_REL, de.de_rel) || PWRITE_SCN(ESHDR_DOF, dof)) { ret = dt_set_errno(dtp, errno); } } free(de.de_strtab); free(de.de_sym); free(de.de_rel); return (ret); } static int -dt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn, - GElf_Sym *sym, int uses_funcdesc, Elf *elf) +dt_symtab_lookup(Elf_Data *data_sym, int start, int end, uintptr_t addr, + uint_t shn, GElf_Sym *sym, int uses_funcdesc, Elf *elf) { - int i, ret = -1; Elf64_Addr symval; Elf_Scn *opd_scn; Elf_Data *opd_desc; - GElf_Sym s; + int i; - for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) { + for (i = start; i < end && gelf_getsym(data_sym, i, sym) != NULL; i++) { if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) { symval = sym->st_value; if (uses_funcdesc) { opd_scn = elf_getscn(elf, sym->st_shndx); opd_desc = elf_rawdata(opd_scn, NULL); symval = *(uint64_t*)((char *)opd_desc->d_buf + symval); } if ((uses_funcdesc || shn == sym->st_shndx) && - symval <= addr && - addr < symval + sym->st_size) { - if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) - return (0); - - ret = 0; - s = *sym; - } + symval <= addr && addr < symval + sym->st_size) + return (0); } } - if (ret == 0) - *sym = s; - return (ret); + return (-1); } #if defined(__aarch64__) /* XXX */ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); return (0); } #elif defined(__arm__) /* XXX */ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); return (0); } #elif defined(__mips__) /* XXX */ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); return (0); } #elif defined(__powerpc__) /* The sentinel is 'xor r3,r3,r3'. */ #define DT_OP_XOR_R3 0x7c631a78 #define DT_OP_NOP 0x60000000 #define DT_OP_BLR 0x4e800020 /* This captures all forms of branching to address. */ #define DT_IS_BRANCH(inst) ((inst & 0xfc000000) == 0x48000000) #define DT_IS_BL(inst) (DT_IS_BRANCH(inst) && (inst & 0x01)) /* XXX */ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { uint32_t *ip; if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) return (-1); /*LINTED*/ ip = (uint32_t *)(p + rela->r_offset); /* * We only know about some specific relocation types. */ if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 && GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24) return (-1); /* * We may have already processed this object file in an earlier linker * invocation. Check to see if the present instruction sequence matches * the one we would install below. */ if (isenabled) { if (ip[0] == DT_OP_XOR_R3) { (*off) += sizeof (ip[0]); return (0); } } else { if (ip[0] == DT_OP_NOP) { (*off) += sizeof (ip[0]); return (0); } } /* * We only expect branch to address instructions. */ if (!DT_IS_BRANCH(ip[0])) { dt_dprintf("found %x instead of a branch instruction at %llx\n", ip[0], (u_longlong_t)rela->r_offset); return (-1); } if (isenabled) { /* * It would necessarily indicate incorrect usage if an is- * enabled probe were tail-called so flag that as an error. * It's also potentially (very) tricky to handle gracefully, * but could be done if this were a desired use scenario. */ if (!DT_IS_BL(ip[0])) { dt_dprintf("tail call to is-enabled probe at %llx\n", (u_longlong_t)rela->r_offset); return (-1); } ip[0] = DT_OP_XOR_R3; (*off) += sizeof (ip[0]); } else { if (DT_IS_BL(ip[0])) ip[0] = DT_OP_NOP; else ip[0] = DT_OP_BLR; } return (0); } #elif defined(__riscv__) /* XXX */ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); return (0); } #elif defined(__sparc) #define DT_OP_RET 0x81c7e008 #define DT_OP_NOP 0x01000000 #define DT_OP_CALL 0x40000000 #define DT_OP_CLR_O0 0x90102000 #define DT_IS_MOV_O7(inst) (((inst) & 0xffffe000) == 0x9e100000) #define DT_IS_RESTORE(inst) (((inst) & 0xc1f80000) == 0x81e80000) #define DT_IS_RETL(inst) (((inst) & 0xfff83fff) == 0x81c02008) #define DT_RS2(inst) ((inst) & 0x1f) #define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14)) /*ARGSUSED*/ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { uint32_t *ip; if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) return (-1); /*LINTED*/ ip = (uint32_t *)(p + rela->r_offset); /* * We only know about some specific relocation types. */ if (GELF_R_TYPE(rela->r_info) != R_SPARC_WDISP30 && GELF_R_TYPE(rela->r_info) != R_SPARC_WPLT30) return (-1); /* * We may have already processed this object file in an earlier linker * invocation. Check to see if the present instruction sequence matches * the one we would install below. */ if (isenabled) { if (ip[0] == DT_OP_NOP) { (*off) += sizeof (ip[0]); return (0); } } else { if (DT_IS_RESTORE(ip[1])) { if (ip[0] == DT_OP_RET) { (*off) += sizeof (ip[0]); return (0); } } else if (DT_IS_MOV_O7(ip[1])) { if (DT_IS_RETL(ip[0])) return (0); } else { if (ip[0] == DT_OP_NOP) { (*off) += sizeof (ip[0]); return (0); } } } /* * We only expect call instructions with a displacement of 0. */ if (ip[0] != DT_OP_CALL) { dt_dprintf("found %x instead of a call instruction at %llx\n", ip[0], (u_longlong_t)rela->r_offset); return (-1); } if (isenabled) { /* * It would necessarily indicate incorrect usage if an is- * enabled probe were tail-called so flag that as an error. * It's also potentially (very) tricky to handle gracefully, * but could be done if this were a desired use scenario. */ if (DT_IS_RESTORE(ip[1]) || DT_IS_MOV_O7(ip[1])) { dt_dprintf("tail call to is-enabled probe at %llx\n", (u_longlong_t)rela->r_offset); return (-1); } /* * On SPARC, we take advantage of the fact that the first * argument shares the same register as for the return value. * The macro handles the work of zeroing that register so we * don't need to do anything special here. We instrument the * instruction in the delay slot as we'll need to modify the * return register after that instruction has been emulated. */ ip[0] = DT_OP_NOP; (*off) += sizeof (ip[0]); } else { /* * If the call is followed by a restore, it's a tail call so * change the call to a ret. If the call if followed by a mov * of a register into %o7, it's a tail call in leaf context * so change the call to a retl-like instruction that returns * to that register value + 8 (rather than the typical %o7 + * 8); the delay slot instruction is left, but should have no * effect. Otherwise we change the call to be a nop. We * identify the subsequent instruction as the probe point in * all but the leaf tail-call case to ensure that arguments to * the probe are complete and consistent. An astute, though * largely hypothetical, observer would note that there is the * possibility of a false-positive probe firing if the function * contained a branch to the instruction in the delay slot of * the call. Fixing this would require significant in-kernel * modifications, and isn't worth doing until we see it in the * wild. */ if (DT_IS_RESTORE(ip[1])) { ip[0] = DT_OP_RET; (*off) += sizeof (ip[0]); } else if (DT_IS_MOV_O7(ip[1])) { ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); } else { ip[0] = DT_OP_NOP; (*off) += sizeof (ip[0]); } } return (0); } #elif defined(__i386) || defined(__amd64) #define DT_OP_NOP 0x90 #define DT_OP_RET 0xc3 #define DT_OP_CALL 0xe8 #define DT_OP_JMP32 0xe9 #define DT_OP_REX_RAX 0x48 #define DT_OP_XOR_EAX_0 0x33 #define DT_OP_XOR_EAX_1 0xc0 static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); uint8_t ret; /* * On x86, the first byte of the instruction is the call opcode and * the next four bytes are the 32-bit address; the relocation is for * the address operand. We back up the offset to the first byte of * the instruction. For is-enabled probes, we later advance the offset * so that it hits the first nop in the instruction sequence. */ (*off) -= 1; /* * We only know about some specific relocation types. Luckily * these types have the same values on both 32-bit and 64-bit * x86 architectures. */ if (GELF_R_TYPE(rela->r_info) != R_386_PC32 && GELF_R_TYPE(rela->r_info) != R_386_PLT32) return (-1); /* * We may have already processed this object file in an earlier linker * invocation. Check to see if the present instruction sequence matches * the one we would install. For is-enabled probes, we advance the * offset to the first nop instruction in the sequence to match the * text modification code below. */ if (!isenabled) { if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) && ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) return (0); } else if (dtp->dt_oflags & DTRACE_O_LP64) { if (ip[0] == DT_OP_REX_RAX && ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 && (ip[3] == DT_OP_NOP || ip[3] == DT_OP_RET) && ip[4] == DT_OP_NOP) { (*off) += 3; return (0); } } else { if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 && (ip[2] == DT_OP_NOP || ip[2] == DT_OP_RET) && ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) { (*off) += 2; return (0); } } /* * We expect either a call instrution with a 32-bit displacement or a * jmp instruction with a 32-bit displacement acting as a tail-call. */ if (ip[0] != DT_OP_CALL && ip[0] != DT_OP_JMP32) { dt_dprintf("found %x instead of a call or jmp instruction at " "%llx\n", ip[0], (u_longlong_t)rela->r_offset); return (-1); } ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP; /* * Establish the instruction sequence -- all nops for probes, and an * instruction to clear the return value register (%eax/%rax) followed * by nops for is-enabled probes. For is-enabled probes, we advance * the offset to the first nop. This isn't stricly necessary but makes * for more readable disassembly when the probe is enabled. */ if (!isenabled) { ip[0] = ret; ip[1] = DT_OP_NOP; ip[2] = DT_OP_NOP; ip[3] = DT_OP_NOP; ip[4] = DT_OP_NOP; } else if (dtp->dt_oflags & DTRACE_O_LP64) { ip[0] = DT_OP_REX_RAX; ip[1] = DT_OP_XOR_EAX_0; ip[2] = DT_OP_XOR_EAX_1; ip[3] = ret; ip[4] = DT_OP_NOP; (*off) += 3; } else { ip[0] = DT_OP_XOR_EAX_0; ip[1] = DT_OP_XOR_EAX_1; ip[2] = ret; ip[3] = DT_OP_NOP; ip[4] = DT_OP_NOP; (*off) += 2; } return (0); } #else #error unknown ISA #endif /*PRINTFLIKE5*/ static int dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs, const char *format, ...) { va_list ap; dt_link_pair_t *pair; va_start(ap, format); dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); va_end(ap); if (elf != NULL) (void) elf_end(elf); if (fd >= 0) (void) close(fd); while ((pair = bufs) != NULL) { bufs = pair->dlp_next; dt_free(dtp, pair->dlp_str); dt_free(dtp, pair->dlp_sym); dt_free(dtp, pair); } return (dt_set_errno(dtp, EDT_COMPILER)); } static int process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) { static const char dt_prefix[] = "__dtrace"; static const char dt_enabled[] = "enabled"; static const char dt_symprefix[] = "$dtrace"; static const char dt_symfmt[] = "%s%ld.%s"; char probename[DTRACE_NAMELEN]; int fd, i, ndx, eprobe, mod = 0; Elf *elf = NULL; GElf_Ehdr ehdr; Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt; Elf_Data *data_rel, *data_sym, *data_str, *data_tgt; GElf_Shdr shdr_rel, shdr_sym, shdr_str, shdr_tgt; GElf_Sym rsym, fsym, dsym; GElf_Rela rela; char *s, *p, *r; char pname[DTRACE_PROVNAMELEN]; dt_provider_t *pvp; dt_probe_t *prp; uint32_t off, eclass, emachine1, emachine2; - size_t symsize, nsym, isym, istr, len; + size_t symsize, osym, nsym, isym, istr, len; key_t objkey; dt_link_pair_t *pair, *bufs = NULL; dt_strtab_t *strtab; + void *tmp; if ((fd = open64(obj, O_RDWR)) == -1) { return (dt_link_error(dtp, elf, fd, bufs, "failed to open %s: %s", obj, strerror(errno))); } if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { return (dt_link_error(dtp, elf, fd, bufs, "failed to process %s: %s", obj, elf_errmsg(elf_errno()))); } switch (elf_kind(elf)) { case ELF_K_ELF: break; case ELF_K_AR: return (dt_link_error(dtp, elf, fd, bufs, "archives are not " "permitted; use the contents of the archive instead: %s", obj)); default: return (dt_link_error(dtp, elf, fd, bufs, "invalid file type: %s", obj)); } if (gelf_getehdr(elf, &ehdr) == NULL) { return (dt_link_error(dtp, elf, fd, bufs, "corrupt file: %s", obj)); } if (dtp->dt_oflags & DTRACE_O_LP64) { eclass = ELFCLASS64; #if defined(__mips__) emachine1 = emachine2 = EM_MIPS; #elif defined(__powerpc__) emachine1 = emachine2 = EM_PPC64; #elif defined(__sparc) emachine1 = emachine2 = EM_SPARCV9; #elif defined(__i386) || defined(__amd64) emachine1 = emachine2 = EM_AMD64; #endif symsize = sizeof (Elf64_Sym); } else { eclass = ELFCLASS32; #if defined(__arm__) emachine1 = emachine2 = EM_ARM; #elif defined(__mips__) emachine1 = emachine2 = EM_MIPS; #elif defined(__powerpc__) emachine1 = emachine2 = EM_PPC; #elif defined(__sparc) emachine1 = EM_SPARC; emachine2 = EM_SPARC32PLUS; #elif defined(__i386) || defined(__amd64) emachine1 = emachine2 = EM_386; #endif symsize = sizeof (Elf32_Sym); } if (ehdr.e_ident[EI_CLASS] != eclass) { return (dt_link_error(dtp, elf, fd, bufs, "incorrect ELF class for object file: %s", obj)); } if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) { return (dt_link_error(dtp, elf, fd, bufs, "incorrect ELF machine type for object file: %s", obj)); } /* * We use this token as a relatively unique handle for this file on the * system in order to disambiguate potential conflicts between files of * the same name which contain identially named local symbols. */ if ((objkey = ftok(obj, 0)) == (key_t)-1) { return (dt_link_error(dtp, elf, fd, bufs, "failed to generate unique key for object file: %s", obj)); } scn_rel = NULL; while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) goto err; /* * Skip any non-relocation sections. */ if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) continue; if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL) goto err; /* * Grab the section, section header and section data for the * symbol table that this relocation section references. */ if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL || gelf_getshdr(scn_sym, &shdr_sym) == NULL || (data_sym = elf_getdata(scn_sym, NULL)) == NULL) goto err; /* * Ditto for that symbol table's string table. */ if ((scn_str = elf_getscn(elf, shdr_sym.sh_link)) == NULL || gelf_getshdr(scn_str, &shdr_str) == NULL || (data_str = elf_getdata(scn_str, NULL)) == NULL) goto err; /* * Grab the section, section header and section data for the * target section for the relocations. For the relocations * we're looking for -- this will typically be the text of the * object file. */ if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL || gelf_getshdr(scn_tgt, &shdr_tgt) == NULL || (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL) goto err; /* * We're looking for relocations to symbols matching this form: * * __dtrace[enabled]____ * * For the generated object, we need to record the location * identified by the relocation, and create a new relocation * in the generated object that will be resolved at link time * to the location of the function in which the probe is * embedded. In the target object, we change the matched symbol * so that it will be ignored at link time, and we modify the * target (text) section to replace the call instruction with * one or more nops. * - * If the function containing the probe is locally scoped - * (static), we create an alias used by the relocation in the - * generated object. The alias, a new symbol, will be global - * (so that the relocation from the generated object can be - * resolved), and hidden (so that it is converted to a local - * symbol at link time). Such aliases have this form: + * To avoid runtime overhead, the relocations added to the + * generated object should be resolved at static link time. We + * therefore create aliases for the functions that contain + * probes. An alias is global (so that the relocation from the + * generated object can be resolved), and hidden (so that its + * address is known at static link time). Such aliases have this + * form: * * $dtrace. * * We take a first pass through all the relocations to * populate our string table and count the number of extra * symbols we'll require. */ strtab = dt_strtab_create(1); nsym = 0; isym = data_sym->d_size / symsize; istr = data_str->d_size; for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { if (shdr_rel.sh_type == SHT_RELA) { if (gelf_getrela(data_rel, i, &rela) == NULL) continue; } else { GElf_Rel rel; if (gelf_getrel(data_rel, i, &rel) == NULL) continue; rela.r_offset = rel.r_offset; rela.r_info = rel.r_info; rela.r_addend = 0; } if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info), &rsym) == NULL) { dt_strtab_destroy(strtab); goto err; } s = (char *)data_str->d_buf + rsym.st_name; if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) continue; - if (dt_symtab_lookup(data_sym, isym, rela.r_offset, - shdr_rel.sh_info, &fsym, - (emachine1 == EM_PPC64), elf) != 0) { + if (dt_symtab_lookup(data_sym, 0, isym, rela.r_offset, + shdr_rel.sh_info, &fsym, (emachine1 == EM_PPC64), + elf) != 0) { dt_strtab_destroy(strtab); goto err; } - if (GELF_ST_BIND(fsym.st_info) != STB_LOCAL) - continue; - if (fsym.st_name > data_str->d_size) { dt_strtab_destroy(strtab); goto err; } s = (char *)data_str->d_buf + fsym.st_name; /* * If this symbol isn't of type function, we've really * driven off the rails or the object file is corrupt. */ if (GELF_ST_TYPE(fsym.st_info) != STT_FUNC) { dt_strtab_destroy(strtab); return (dt_link_error(dtp, elf, fd, bufs, "expected %s to be of type function", s)); } len = snprintf(NULL, 0, dt_symfmt, dt_symprefix, objkey, s) + 1; if ((p = dt_alloc(dtp, len)) == NULL) { dt_strtab_destroy(strtab); goto err; } (void) snprintf(p, len, dt_symfmt, dt_symprefix, objkey, s); if (dt_strtab_index(strtab, p) == -1) { nsym++; (void) dt_strtab_insert(strtab, p); } dt_free(dtp, p); } /* - * If needed, allocate the additional space for the symbol - * table and string table copying the old data into the new - * buffers, and marking the buffers as dirty. We inject those - * newly allocated buffers into the libelf data structures, but - * are still responsible for freeing them once we're done with - * the elf handle. + * If any probes were found, allocate the additional space for + * the symbol table and string table, copying the old data into + * the new buffers, and marking the buffers as dirty. We inject + * those newly allocated buffers into the libelf data + * structures, but are still responsible for freeing them once + * we're done with the elf handle. */ if (nsym > 0) { /* * The first byte of the string table is reserved for * the \0 entry. */ len = dt_strtab_size(strtab) - 1; assert(len > 0); assert(dt_strtab_index(strtab, "") == 0); dt_strtab_destroy(strtab); if ((pair = dt_alloc(dtp, sizeof (*pair))) == NULL) goto err; if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size + len)) == NULL) { dt_free(dtp, pair); goto err; } if ((pair->dlp_sym = dt_alloc(dtp, data_sym->d_size + nsym * symsize)) == NULL) { dt_free(dtp, pair->dlp_str); dt_free(dtp, pair); goto err; } pair->dlp_next = bufs; bufs = pair; bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size); + tmp = data_str->d_buf; data_str->d_buf = pair->dlp_str; + pair->dlp_str = tmp; data_str->d_size += len; (void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY); shdr_str.sh_size += len; (void) gelf_update_shdr(scn_str, &shdr_str); bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size); + tmp = data_sym->d_buf; data_sym->d_buf = pair->dlp_sym; + pair->dlp_sym = tmp; data_sym->d_size += nsym * symsize; (void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY); shdr_sym.sh_size += nsym * symsize; (void) gelf_update_shdr(scn_sym, &shdr_sym); + osym = isym; nsym += isym; } else { dt_strtab_destroy(strtab); + continue; } /* * Now that the tables have been allocated, perform the * modifications described above. */ for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { if (shdr_rel.sh_type == SHT_RELA) { if (gelf_getrela(data_rel, i, &rela) == NULL) continue; } else { GElf_Rel rel; if (gelf_getrel(data_rel, i, &rel) == NULL) continue; rela.r_offset = rel.r_offset; rela.r_info = rel.r_info; rela.r_addend = 0; } ndx = GELF_R_SYM(rela.r_info); if (gelf_getsym(data_sym, ndx, &rsym) == NULL || rsym.st_name > data_str->d_size) goto err; s = (char *)data_str->d_buf + rsym.st_name; if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) continue; s += sizeof (dt_prefix) - 1; /* * Check to see if this is an 'is-enabled' check as * opposed to a normal probe. */ if (strncmp(s, dt_enabled, sizeof (dt_enabled) - 1) == 0) { s += sizeof (dt_enabled) - 1; eprobe = 1; *eprobesp = 1; dt_dprintf("is-enabled probe\n"); } else { eprobe = 0; dt_dprintf("normal probe\n"); } if (*s++ != '_') goto err; if ((p = strstr(s, "___")) == NULL || p - s >= sizeof (pname)) goto err; bcopy(s, pname, p - s); pname[p - s] = '\0'; - if (dt_symtab_lookup(data_sym, isym, rela.r_offset, - shdr_rel.sh_info, &fsym, + if (dt_symtab_lookup(data_sym, osym, isym, + rela.r_offset, shdr_rel.sh_info, &fsym, + (emachine1 == EM_PPC64), elf) != 0 && + dt_symtab_lookup(data_sym, 0, osym, + rela.r_offset, shdr_rel.sh_info, &fsym, (emachine1 == EM_PPC64), elf) != 0) goto err; if (fsym.st_name > data_str->d_size) goto err; assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); /* - * If a NULL relocation name is passed to - * dt_probe_define(), the function name is used for the - * relocation. The relocation needs to use a mangled - * name if the symbol is locally scoped; the function - * name may need to change if we've found the global - * alias for the locally scoped symbol (we prefer - * global symbols to locals in dt_symtab_lookup()). + * If this is our first time encountering this symbol, + * emit an alias. */ s = (char *)data_str->d_buf + fsym.st_name; - r = NULL; - if (GELF_ST_BIND(fsym.st_info) == STB_LOCAL) { + if (strncmp(s, dt_symprefix, + sizeof (dt_symprefix) - 1) != 0) { + u_int bind = GELF_ST_BIND(fsym.st_info); + dsym = fsym; dsym.st_name = istr; - dsym.st_info = GELF_ST_INFO(STB_GLOBAL, - STT_FUNC); - dsym.st_other = - ELF64_ST_VISIBILITY(STV_ELIMINATE); + dsym.st_info = GELF_ST_INFO(bind == STB_LOCAL ? + STB_GLOBAL : bind, STT_FUNC); + dsym.st_other = GELF_ST_VISIBILITY(STV_HIDDEN); (void) gelf_update_sym(data_sym, isym, &dsym); - - r = (char *)data_str->d_buf + istr; - istr += 1 + sprintf(r, dt_symfmt, - dt_symprefix, objkey, s); + r = (char *) data_str->d_buf + istr; + istr += 1 + sprintf(r, dt_symfmt, dt_symprefix, objkey, + s); isym++; assert(isym <= nsym); - - } else if (strncmp(s, dt_symprefix, - strlen(dt_symprefix)) == 0) { + } else { r = s; - if ((s = strchr(s, '.')) == NULL) - goto err; + s = strchr(s, '.'); + assert(s != NULL); s++; } if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) { return (dt_link_error(dtp, elf, fd, bufs, "no such provider %s", pname)); } if (strlcpy(probename, p + 3, sizeof (probename)) >= sizeof (probename)) return (dt_link_error(dtp, elf, fd, bufs, "invalid probe name %s", probename)); (void) strhyphenate(probename); if ((prp = dt_probe_lookup(pvp, probename)) == NULL) return (dt_link_error(dtp, elf, fd, bufs, "no such probe %s", probename)); assert(fsym.st_value <= rela.r_offset); off = rela.r_offset - fsym.st_value; if (dt_modtext(dtp, data_tgt->d_buf, eprobe, &rela, &off) != 0) goto err; if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) { return (dt_link_error(dtp, elf, fd, bufs, "failed to allocate space for probe")); } #ifndef illumos /* * Our linker doesn't understand the SUNW_IGNORE ndx and * will try to use this relocation when we build the * final executable. Since we are done processing this * relocation, mark it as inexistant and let libelf * remove it from the file. * If this wasn't done, we would have garbage added to * the executable file as the symbol is going to be * change from UND to ABS. */ if (shdr_rel.sh_type == SHT_RELA) { rela.r_offset = 0; rela.r_info = 0; rela.r_addend = 0; (void) gelf_update_rela(data_rel, i, &rela); } else { GElf_Rel rel; rel.r_offset = 0; rel.r_info = 0; (void) gelf_update_rel(data_rel, i, &rel); } #endif mod = 1; (void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY); /* * This symbol may already have been marked to * be ignored by another relocation referencing * the same symbol or if this object file has * already been processed by an earlier link * invocation. */ #ifndef illumos #define SHN_SUNW_IGNORE SHN_ABS #endif if (rsym.st_shndx != SHN_SUNW_IGNORE) { rsym.st_shndx = SHN_SUNW_IGNORE; (void) gelf_update_sym(data_sym, ndx, &rsym); } } } if (mod && elf_update(elf, ELF_C_WRITE) == -1) goto err; (void) elf_end(elf); (void) close(fd); -#ifndef illumos - if (nsym > 0) -#endif while ((pair = bufs) != NULL) { bufs = pair->dlp_next; dt_free(dtp, pair->dlp_str); dt_free(dtp, pair->dlp_sym); dt_free(dtp, pair); } return (0); err: return (dt_link_error(dtp, elf, fd, bufs, "an error was encountered while processing %s", obj)); } int dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, const char *file, int objc, char *const objv[]) { #ifndef illumos char tfile[PATH_MAX]; #endif char drti[PATH_MAX]; dof_hdr_t *dof; int fd, status, i, cur; char *cmd, tmp; size_t len; int eprobes = 0, ret = 0; #ifndef illumos if (access(file, R_OK) == 0) { fprintf(stderr, "dtrace: target object (%s) already exists. " "Please remove the target\ndtrace: object and rebuild all " "the source objects if you wish to run the DTrace\n" "dtrace: linking process again\n", file); /* * Several build infrastructures run DTrace twice (e.g. * postgres) and we don't want the build to fail. Return * 0 here since this isn't really a fatal error. */ return (0); } #endif /* * A NULL program indicates a special use in which we just link * together a bunch of object files specified in objv and then * unlink(2) those object files. */ if (pgp == NULL) { const char *fmt = "%s -o %s -r"; len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1; for (i = 0; i < objc; i++) len += strlen(objv[i]) + 1; cmd = alloca(len); cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file); for (i = 0; i < objc; i++) cur += snprintf(cmd + cur, len - cur, " %s", objv[i]); if ((status = system(cmd)) == -1) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to run %s: %s", dtp->dt_ld_path, strerror(errno))); } if (WIFSIGNALED(status)) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to link %s: %s failed due to signal %d", file, dtp->dt_ld_path, WTERMSIG(status))); } if (WEXITSTATUS(status) != 0) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to link %s: %s exited with status %d\n", file, dtp->dt_ld_path, WEXITSTATUS(status))); } for (i = 0; i < objc; i++) { if (strcmp(objv[i], file) != 0) (void) unlink(objv[i]); } return (0); } for (i = 0; i < objc; i++) { if (process_obj(dtp, objv[i], &eprobes) != 0) return (-1); /* errno is set for us */ } /* * If there are is-enabled probes then we need to force use of DOF * version 2. */ if (eprobes && pgp->dp_dofversion < DOF_VERSION_2) pgp->dp_dofversion = DOF_VERSION_2; if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) return (-1); /* errno is set for us */ #ifdef illumos /* * Create a temporary file and then unlink it if we're going to * combine it with drti.o later. We can still refer to it in child * processes as /dev/fd/. */ if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to open %s: %s", file, strerror(errno))); } #else snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file); if ((fd = mkostemp(tfile, O_CLOEXEC)) == -1) return (dt_link_error(dtp, NULL, -1, NULL, "failed to create temporary file %s: %s", tfile, strerror(errno))); #endif /* * If -xlinktype=DOF has been selected, just write out the DOF. * Otherwise proceed to the default of generating and linking ELF. */ switch (dtp->dt_linktype) { case DT_LTYP_DOF: if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) ret = errno; if (close(fd) != 0 && ret == 0) ret = errno; if (ret != 0) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to write %s: %s", file, strerror(ret))); } return (0); case DT_LTYP_ELF: break; /* fall through to the rest of dtrace_program_link() */ default: return (dt_link_error(dtp, NULL, -1, NULL, "invalid link type %u\n", dtp->dt_linktype)); } #ifdef illumos if (!dtp->dt_lazyload) (void) unlink(file); #endif if (dtp->dt_oflags & DTRACE_O_LP64) status = dump_elf64(dtp, dof, fd); else status = dump_elf32(dtp, dof, fd); #ifdef illumos if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to write %s: %s", file, strerror(errno))); } #else if (status != 0) return (dt_link_error(dtp, NULL, -1, NULL, "failed to write %s: %s", tfile, strerror(dtrace_errno(dtp)))); #endif if (!dtp->dt_lazyload) { #ifdef illumos const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s"; if (dtp->dt_oflags & DTRACE_O_LP64) { (void) snprintf(drti, sizeof (drti), "%s/64/drti.o", _dtrace_libdir); } else { (void) snprintf(drti, sizeof (drti), "%s/drti.o", _dtrace_libdir); } len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, fd, drti) + 1; cmd = alloca(len); (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti); #else const char *fmt = "%s -o %s -r %s %s"; dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path); (void) snprintf(drti, sizeof (drti), "%s/drti.o", dp->dir_path); len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile, drti) + 1; cmd = alloca(len); (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile, drti); #endif if ((status = system(cmd)) == -1) { ret = dt_link_error(dtp, NULL, fd, NULL, "failed to run %s: %s", dtp->dt_ld_path, strerror(errno)); goto done; } if (WIFSIGNALED(status)) { ret = dt_link_error(dtp, NULL, fd, NULL, "failed to link %s: %s failed due to signal %d", file, dtp->dt_ld_path, WTERMSIG(status)); goto done; } if (WEXITSTATUS(status) != 0) { ret = dt_link_error(dtp, NULL, fd, NULL, "failed to link %s: %s exited with status %d\n", file, dtp->dt_ld_path, WEXITSTATUS(status)); goto done; } (void) close(fd); /* release temporary file */ #ifdef __FreeBSD__ /* * Now that we've linked drti.o, reduce the global __SUNW_dof * symbol to a local symbol. This is needed to so that multiple * generated object files (for different providers, for * instance) can be linked together. This is accomplished using * the -Blocal flag with Sun's linker, but GNU ld doesn't appear * to have an equivalent option. */ asprintf(&cmd, "%s --localize-hidden %s", dtp->dt_objcopy_path, file); if ((status = system(cmd)) == -1) { ret = dt_link_error(dtp, NULL, -1, NULL, "failed to run %s: %s", dtp->dt_objcopy_path, strerror(errno)); free(cmd); goto done; } free(cmd); if (WIFSIGNALED(status)) { ret = dt_link_error(dtp, NULL, -1, NULL, "failed to link %s: %s failed due to signal %d", file, dtp->dt_objcopy_path, WTERMSIG(status)); goto done; } if (WEXITSTATUS(status) != 0) { ret = dt_link_error(dtp, NULL, -1, NULL, "failed to link %s: %s exited with status %d\n", file, dtp->dt_objcopy_path, WEXITSTATUS(status)); goto done; } #endif } else { #ifdef __FreeBSD__ if (rename(tfile, file) != 0) { ret = dt_link_error(dtp, NULL, fd, NULL, "failed to rename %s to %s: %s", tfile, file, strerror(errno)); goto done; } #endif (void) close(fd); } done: dtrace_dof_destroy(dtp, dof); #ifdef __FreeBSD__ if (!dtp->dt_lazyload) (void) unlink(tfile); #endif return (ret); } Index: projects/ipsec/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c =================================================================== --- projects/ipsec/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c (revision 313312) +++ projects/ipsec/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c (revision 313313) @@ -1,902 +1,900 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include #ifdef illumos #include #endif #include #include #include #include #ifdef illumos #include #endif #include #include #include #include #include #include #include #include static dt_provider_t * dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h) { dt_list_append(&dtp->dt_provlist, pvp); pvp->pv_next = dtp->dt_provs[h]; dtp->dt_provs[h] = pvp; dtp->dt_nprovs++; return (pvp); } dt_provider_t * dt_provider_lookup(dtrace_hdl_t *dtp, const char *name) { uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_provbuckets; dtrace_providerdesc_t desc; dt_provider_t *pvp; for (pvp = dtp->dt_provs[h]; pvp != NULL; pvp = pvp->pv_next) { if (strcmp(pvp->pv_desc.dtvd_name, name) == 0) return (pvp); } if (strisglob(name) || name[0] == '\0') { (void) dt_set_errno(dtp, EDT_NOPROV); return (NULL); } bzero(&desc, sizeof (desc)); (void) strlcpy(desc.dtvd_name, name, DTRACE_PROVNAMELEN); if (dt_ioctl(dtp, DTRACEIOC_PROVIDER, &desc) == -1) { (void) dt_set_errno(dtp, errno == ESRCH ? EDT_NOPROV : errno); return (NULL); } if ((pvp = dt_provider_create(dtp, name)) == NULL) return (NULL); /* dt_errno is set for us */ bcopy(&desc, &pvp->pv_desc, sizeof (desc)); pvp->pv_flags |= DT_PROVIDER_IMPL; return (pvp); } dt_provider_t * dt_provider_create(dtrace_hdl_t *dtp, const char *name) { dt_provider_t *pvp; if ((pvp = dt_zalloc(dtp, sizeof (dt_provider_t))) == NULL) return (NULL); (void) strlcpy(pvp->pv_desc.dtvd_name, name, DTRACE_PROVNAMELEN); pvp->pv_probes = dt_idhash_create(pvp->pv_desc.dtvd_name, NULL, 0, 0); pvp->pv_gen = dtp->dt_gen; pvp->pv_hdl = dtp; if (pvp->pv_probes == NULL) { dt_free(dtp, pvp); (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } pvp->pv_desc.dtvd_attr.dtpa_provider = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_mod = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_func = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_name = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_args = _dtrace_prvattr; return (dt_provider_insert(dtp, pvp, dt_strtab_hash(name, NULL) % dtp->dt_provbuckets)); } void dt_provider_destroy(dtrace_hdl_t *dtp, dt_provider_t *pvp) { dt_provider_t **pp; uint_t h; assert(pvp->pv_hdl == dtp); h = dt_strtab_hash(pvp->pv_desc.dtvd_name, NULL) % dtp->dt_provbuckets; pp = &dtp->dt_provs[h]; while (*pp != NULL && *pp != pvp) pp = &(*pp)->pv_next; assert(*pp != NULL && *pp == pvp); *pp = pvp->pv_next; dt_list_delete(&dtp->dt_provlist, pvp); dtp->dt_nprovs--; if (pvp->pv_probes != NULL) dt_idhash_destroy(pvp->pv_probes); dt_node_link_free(&pvp->pv_nodes); dt_free(dtp, pvp->pv_xrefs); dt_free(dtp, pvp); } int dt_provider_xref(dtrace_hdl_t *dtp, dt_provider_t *pvp, id_t id) { size_t oldsize = BT_SIZEOFMAP(pvp->pv_xrmax); size_t newsize = BT_SIZEOFMAP(dtp->dt_xlatorid); assert(id >= 0 && id < dtp->dt_xlatorid); if (newsize > oldsize) { ulong_t *xrefs = dt_zalloc(dtp, newsize); if (xrefs == NULL) return (-1); bcopy(pvp->pv_xrefs, xrefs, oldsize); dt_free(dtp, pvp->pv_xrefs); pvp->pv_xrefs = xrefs; pvp->pv_xrmax = dtp->dt_xlatorid; } BT_SET(pvp->pv_xrefs, id); return (0); } static uint8_t dt_probe_argmap(dt_node_t *xnp, dt_node_t *nnp) { uint8_t i; for (i = 0; nnp != NULL; i++) { if (nnp->dn_string != NULL && strcmp(nnp->dn_string, xnp->dn_string) == 0) break; else nnp = nnp->dn_list; } return (i); } static dt_node_t * dt_probe_alloc_args(dt_provider_t *pvp, int argc) { dt_node_t *args = NULL, *pnp = NULL, *dnp; int i; for (i = 0; i < argc; i++, pnp = dnp) { if ((dnp = dt_node_xalloc(pvp->pv_hdl, DT_NODE_TYPE)) == NULL) return (NULL); dnp->dn_link = pvp->pv_nodes; pvp->pv_nodes = dnp; if (args == NULL) args = dnp; else pnp->dn_list = dnp; } return (args); } static size_t dt_probe_keylen(const dtrace_probedesc_t *pdp) { return (strlen(pdp->dtpd_mod) + 1 + strlen(pdp->dtpd_func) + 1 + strlen(pdp->dtpd_name) + 1); } static char * dt_probe_key(const dtrace_probedesc_t *pdp, char *s) { (void) snprintf(s, INT_MAX, "%s:%s:%s", pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name); return (s); } /* * If a probe was discovered from the kernel, ask dtrace(7D) for a description * of each of its arguments, including native and translated types. */ static dt_probe_t * dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp) { dtrace_hdl_t *dtp = pvp->pv_hdl; char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp))); dt_node_t *xargs, *nargs; dt_ident_t *idp; dt_probe_t *prp; dtrace_typeinfo_t dtt; int i, nc, xc; int adc = _dtrace_argmax; dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc); dtrace_argdesc_t *adp = adv; assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0); assert(pdp->dtpd_id != DTRACE_IDNONE); dt_dprintf("discovering probe %s:%s id=%d\n", pvp->pv_desc.dtvd_name, name, pdp->dtpd_id); for (nc = -1, i = 0; i < adc; i++, adp++) { bzero(adp, sizeof (dtrace_argdesc_t)); adp->dtargd_ndx = i; adp->dtargd_id = pdp->dtpd_id; if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) { (void) dt_set_errno(dtp, errno); return (NULL); } if (adp->dtargd_ndx == DTRACE_ARGNONE) break; /* all argument descs have been retrieved */ nc = MAX(nc, adp->dtargd_mapping); } xc = i; nc++; /* * The pid provider believes in giving the kernel a break. No reason to * give the kernel all the ctf containers that we're keeping ourselves * just to get it back from it. So if we're coming from a pid provider * probe and the kernel gave us no argument information we'll get some * here. If for some crazy reason the kernel knows about our userland * types then we just ignore this. */ if (xc == 0 && nc == 0 && strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) { nc = adc; dt_pid_get_types(dtp, pdp, adv, &nc); xc = nc; } /* * Now that we have discovered the number of native and translated * arguments from the argument descriptions, allocate a new probe ident * and corresponding dt_probe_t and hash it into the provider. */ xargs = dt_probe_alloc_args(pvp, xc); nargs = dt_probe_alloc_args(pvp, nc); if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL)) return (NULL); /* dt_errno is set for us */ idp = dt_ident_create(name, DT_IDENT_PROBE, DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0, &dt_idops_probe, NULL, dtp->dt_gen); if (idp == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } if ((prp = dt_probe_create(dtp, idp, 2, nargs, nc, xargs, xc)) == NULL) { dt_ident_destroy(idp); return (NULL); } dt_probe_declare(pvp, prp); /* * Once our new dt_probe_t is fully constructed, iterate over the * cached argument descriptions and assign types to prp->pr_nargv[] * and prp->pr_xargv[] and assign mappings to prp->pr_mapping[]. */ for (adp = adv, i = 0; i < xc; i++, adp++) { if (dtrace_type_strcompile(dtp, adp->dtargd_native, &dtt) != 0) { dt_dprintf("failed to resolve input type %s " "for %s:%s arg #%d: %s\n", adp->dtargd_native, pvp->pv_desc.dtvd_name, name, i + 1, dtrace_errmsg(dtp, dtrace_errno(dtp))); dtt.dtt_object = NULL; dtt.dtt_ctfp = NULL; dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping], dtt.dtt_ctfp, dtt.dtt_type, dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE); } if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' || strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) { dt_node_type_propagate(prp->pr_nargv[ adp->dtargd_mapping], prp->pr_xargv[i]); } else if (dtrace_type_strcompile(dtp, adp->dtargd_xlate, &dtt) != 0) { dt_dprintf("failed to resolve output type %s " "for %s:%s arg #%d: %s\n", adp->dtargd_xlate, pvp->pv_desc.dtvd_name, name, i + 1, dtrace_errmsg(dtp, dtrace_errno(dtp))); dtt.dtt_object = NULL; dtt.dtt_ctfp = NULL; dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_xargv[i], dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); } prp->pr_mapping[i] = adp->dtargd_mapping; prp->pr_argv[i] = dtt; } return (prp); } /* * Lookup a probe declaration based on a known provider and full or partially * specified module, function, and name. If the probe is not known to us yet, * ask dtrace(7D) to match the description and then cache any useful results. */ dt_probe_t * dt_probe_lookup(dt_provider_t *pvp, const char *s) { dtrace_hdl_t *dtp = pvp->pv_hdl; dtrace_probedesc_t pd; dt_ident_t *idp; size_t keylen; char *key; if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, s, &pd) != 0) return (NULL); /* dt_errno is set for us */ keylen = dt_probe_keylen(&pd); key = dt_probe_key(&pd, alloca(keylen)); /* * If the probe is already declared, then return the dt_probe_t from * the existing identifier. This could come from a static declaration * or it could have been cached from an earlier call to this function. */ if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL) return (idp->di_data); /* * If the probe isn't known, use the probe description computed above * to ask dtrace(7D) to find the first matching probe. */ if (dt_ioctl(dtp, DTRACEIOC_PROBEMATCH, &pd) == 0) return (dt_probe_discover(pvp, &pd)); if (errno == ESRCH || errno == EBADF) (void) dt_set_errno(dtp, EDT_NOPROBE); else (void) dt_set_errno(dtp, errno); return (NULL); } dt_probe_t * dt_probe_create(dtrace_hdl_t *dtp, dt_ident_t *idp, int protoc, dt_node_t *nargs, uint_t nargc, dt_node_t *xargs, uint_t xargc) { dt_module_t *dmp; dt_probe_t *prp; const char *p; uint_t i; assert(idp->di_kind == DT_IDENT_PROBE); assert(idp->di_data == NULL); /* * If only a single prototype is given, set xargc/s to nargc/s to * simplify subsequent use. Note that we can have one or both of nargs * and xargs be specified but set to NULL, indicating a void prototype. */ if (protoc < 2) { assert(xargs == NULL); assert(xargc == 0); xargs = nargs; xargc = nargc; } if ((prp = dt_alloc(dtp, sizeof (dt_probe_t))) == NULL) return (NULL); prp->pr_pvp = NULL; prp->pr_ident = idp; p = strrchr(idp->di_name, ':'); assert(p != NULL); prp->pr_name = p + 1; prp->pr_nargs = nargs; prp->pr_nargv = dt_alloc(dtp, sizeof (dt_node_t *) * nargc); prp->pr_nargc = nargc; prp->pr_xargs = xargs; prp->pr_xargv = dt_alloc(dtp, sizeof (dt_node_t *) * xargc); prp->pr_xargc = xargc; prp->pr_mapping = dt_alloc(dtp, sizeof (uint8_t) * xargc); prp->pr_inst = NULL; prp->pr_argv = dt_alloc(dtp, sizeof (dtrace_typeinfo_t) * xargc); prp->pr_argc = xargc; if ((prp->pr_nargc != 0 && prp->pr_nargv == NULL) || (prp->pr_xargc != 0 && prp->pr_xargv == NULL) || (prp->pr_xargc != 0 && prp->pr_mapping == NULL) || (prp->pr_argc != 0 && prp->pr_argv == NULL)) { dt_probe_destroy(prp); return (NULL); } for (i = 0; i < xargc; i++, xargs = xargs->dn_list) { if (xargs->dn_string != NULL) prp->pr_mapping[i] = dt_probe_argmap(xargs, nargs); else prp->pr_mapping[i] = i; prp->pr_xargv[i] = xargs; if ((dmp = dt_module_lookup_by_ctf(dtp, xargs->dn_ctfp)) != NULL) prp->pr_argv[i].dtt_object = dmp->dm_name; else prp->pr_argv[i].dtt_object = NULL; prp->pr_argv[i].dtt_ctfp = xargs->dn_ctfp; prp->pr_argv[i].dtt_type = xargs->dn_type; } for (i = 0; i < nargc; i++, nargs = nargs->dn_list) prp->pr_nargv[i] = nargs; idp->di_data = prp; return (prp); } void dt_probe_declare(dt_provider_t *pvp, dt_probe_t *prp) { assert(prp->pr_ident->di_kind == DT_IDENT_PROBE); assert(prp->pr_ident->di_data == prp); assert(prp->pr_pvp == NULL); if (prp->pr_xargs != prp->pr_nargs) pvp->pv_flags &= ~DT_PROVIDER_INTF; prp->pr_pvp = pvp; dt_idhash_xinsert(pvp->pv_probes, prp->pr_ident); } void dt_probe_destroy(dt_probe_t *prp) { dt_probe_instance_t *pip, *pip_next; dtrace_hdl_t *dtp; if (prp->pr_pvp != NULL) dtp = prp->pr_pvp->pv_hdl; else dtp = yypcb->pcb_hdl; dt_node_list_free(&prp->pr_nargs); dt_node_list_free(&prp->pr_xargs); dt_free(dtp, prp->pr_nargv); dt_free(dtp, prp->pr_xargv); for (pip = prp->pr_inst; pip != NULL; pip = pip_next) { pip_next = pip->pi_next; dt_free(dtp, pip->pi_rname); dt_free(dtp, pip->pi_fname); dt_free(dtp, pip->pi_offs); dt_free(dtp, pip->pi_enoffs); dt_free(dtp, pip); } dt_free(dtp, prp->pr_mapping); dt_free(dtp, prp->pr_argv); dt_free(dtp, prp); } int dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp, const char *fname, const char *rname, uint32_t offset, int isenabled) { dtrace_hdl_t *dtp = pvp->pv_hdl; dt_probe_instance_t *pip; uint32_t **offs; uint_t *noffs, *maxoffs; assert(fname != NULL); for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) { if (strcmp(pip->pi_fname, fname) == 0 && - ((rname == NULL && pip->pi_rname == NULL) || - (rname != NULL && pip->pi_rname != NULL && - strcmp(pip->pi_rname, rname) == 0))) + strcmp(pip->pi_rname, rname) == 0) break; } if (pip == NULL) { if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL) return (-1); if ((pip->pi_offs = dt_zalloc(dtp, sizeof (uint32_t))) == NULL) goto nomem; if ((pip->pi_enoffs = dt_zalloc(dtp, sizeof (uint32_t))) == NULL) goto nomem; if ((pip->pi_fname = strdup(fname)) == NULL) goto nomem; - if (rname != NULL && (pip->pi_rname = strdup(rname)) == NULL) + if ((pip->pi_rname = strdup(rname)) == NULL) goto nomem; pip->pi_noffs = 0; pip->pi_maxoffs = 1; pip->pi_nenoffs = 0; pip->pi_maxenoffs = 1; pip->pi_next = prp->pr_inst; prp->pr_inst = pip; } if (isenabled) { offs = &pip->pi_enoffs; noffs = &pip->pi_nenoffs; maxoffs = &pip->pi_maxenoffs; } else { offs = &pip->pi_offs; noffs = &pip->pi_noffs; maxoffs = &pip->pi_maxoffs; } if (*noffs == *maxoffs) { uint_t new_max = *maxoffs * 2; uint32_t *new_offs = dt_alloc(dtp, sizeof (uint32_t) * new_max); if (new_offs == NULL) return (-1); bcopy(*offs, new_offs, sizeof (uint32_t) * *maxoffs); dt_free(dtp, *offs); *maxoffs = new_max; *offs = new_offs; } dt_dprintf("defined probe %s %s:%s %s() +0x%x (%s)\n", isenabled ? "(is-enabled)" : "", pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset, - rname != NULL ? rname : fname); + rname); assert(*noffs < *maxoffs); (*offs)[(*noffs)++] = offset; return (0); nomem: dt_free(dtp, pip->pi_fname); dt_free(dtp, pip->pi_enoffs); dt_free(dtp, pip->pi_offs); dt_free(dtp, pip); return (dt_set_errno(dtp, EDT_NOMEM)); } /* * Lookup the dynamic translator type tag for the specified probe argument and * assign the type to the specified node. If the type is not yet defined, add * it to the "D" module's type container as a typedef for an unknown type. */ dt_node_t * dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp) { dtrace_hdl_t *dtp = prp->pr_pvp->pv_hdl; dtrace_typeinfo_t dtt; size_t len; char *tag; len = snprintf(NULL, 0, "__dtrace_%s___%s_arg%u", prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn); tag = alloca(len + 1); (void) snprintf(tag, len + 1, "__dtrace_%s___%s_arg%u", prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn); if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS, tag, &dtt) != 0) { dtt.dtt_object = DTRACE_OBJ_DDEFS; dtt.dtt_ctfp = DT_DYN_CTFP(dtp); dtt.dtt_type = ctf_add_typedef(DT_DYN_CTFP(dtp), CTF_ADD_ROOT, tag, DT_DYN_TYPE(dtp)); if (dtt.dtt_type == CTF_ERR || ctf_update(dtt.dtt_ctfp) == CTF_ERR) { xyerror(D_UNKNOWN, "cannot define type %s: %s\n", tag, ctf_errmsg(ctf_errno(dtt.dtt_ctfp))); } } bzero(dnp, sizeof (dt_node_t)); dnp->dn_kind = DT_NODE_TYPE; dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); dt_node_attr_assign(dnp, _dtrace_defattr); return (dnp); } /*ARGSUSED*/ static int dt_probe_desc(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg) { if (((dtrace_probedesc_t *)arg)->dtpd_id == DTRACE_IDNONE) { bcopy(pdp, arg, sizeof (dtrace_probedesc_t)); return (0); } return (1); } dt_probe_t * dt_probe_info(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip) { int m_is_glob = pdp->dtpd_mod[0] == '\0' || strisglob(pdp->dtpd_mod); int f_is_glob = pdp->dtpd_func[0] == '\0' || strisglob(pdp->dtpd_func); int n_is_glob = pdp->dtpd_name[0] == '\0' || strisglob(pdp->dtpd_name); dt_probe_t *prp = NULL; const dtrace_pattr_t *pap; dt_provider_t *pvp; dt_ident_t *idp; /* * Attempt to lookup the probe in our existing cache for this provider. * If none is found and an explicit probe ID was specified, discover * that specific probe and cache its description and arguments. */ if ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) != NULL) { size_t keylen = dt_probe_keylen(pdp); char *key = dt_probe_key(pdp, alloca(keylen)); if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL) prp = idp->di_data; else if (pdp->dtpd_id != DTRACE_IDNONE) prp = dt_probe_discover(pvp, pdp); } /* * If no probe was found in our cache, convert the caller's partial * probe description into a fully-formed matching probe description by * iterating over up to at most two probes that match 'pdp'. We then * call dt_probe_discover() on the resulting probe identifier. */ if (prp == NULL) { dtrace_probedesc_t pd; int m; bzero(&pd, sizeof (pd)); pd.dtpd_id = DTRACE_IDNONE; /* * Call dtrace_probe_iter() to find matching probes. Our * dt_probe_desc() callback will produce the following results: * * m < 0 dtrace_probe_iter() found zero matches (or failed). * m > 0 dtrace_probe_iter() found more than one match. * m = 0 dtrace_probe_iter() found exactly one match. */ if ((m = dtrace_probe_iter(dtp, pdp, dt_probe_desc, &pd)) < 0) return (NULL); /* dt_errno is set for us */ if ((pvp = dt_provider_lookup(dtp, pd.dtpd_provider)) == NULL) return (NULL); /* dt_errno is set for us */ /* * If more than one probe was matched, then do not report probe * information if either of the following conditions is true: * * (a) The Arguments Data stability of the matched provider is * less than Evolving. * * (b) Any description component that is at least Evolving is * empty or is specified using a globbing expression. * * These conditions imply that providers that provide Evolving * or better Arguments Data stability must guarantee that all * probes with identical field names in a field of Evolving or * better Name stability have identical argument signatures. */ if (m > 0) { if (pvp->pv_desc.dtvd_attr.dtpa_args.dtat_data < DTRACE_STABILITY_EVOLVING) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } if (pvp->pv_desc.dtvd_attr.dtpa_mod.dtat_name >= DTRACE_STABILITY_EVOLVING && m_is_glob) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } if (pvp->pv_desc.dtvd_attr.dtpa_func.dtat_name >= DTRACE_STABILITY_EVOLVING && f_is_glob) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } if (pvp->pv_desc.dtvd_attr.dtpa_name.dtat_name >= DTRACE_STABILITY_EVOLVING && n_is_glob) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } } /* * If we matched a probe exported by dtrace(7D), then discover * the real attributes. Otherwise grab the static declaration. */ if (pd.dtpd_id != DTRACE_IDNONE) prp = dt_probe_discover(pvp, &pd); else prp = dt_probe_lookup(pvp, pd.dtpd_name); if (prp == NULL) return (NULL); /* dt_errno is set for us */ } assert(pvp != NULL && prp != NULL); /* * Compute the probe description attributes by taking the minimum of * the attributes of the specified fields. If no provider is specified * or a glob pattern is used for the provider, use Unstable attributes. */ if (pdp->dtpd_provider[0] == '\0' || strisglob(pdp->dtpd_provider)) pap = &_dtrace_prvdesc; else pap = &pvp->pv_desc.dtvd_attr; pip->dtp_attr = pap->dtpa_provider; if (!m_is_glob) pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_mod); if (!f_is_glob) pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_func); if (!n_is_glob) pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_name); pip->dtp_arga = pap->dtpa_args; pip->dtp_argv = prp->pr_argv; pip->dtp_argc = prp->pr_argc; return (prp); } int dtrace_probe_info(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip) { return (dt_probe_info(dtp, pdp, pip) != NULL ? 0 : -1); } /*ARGSUSED*/ static int dt_probe_iter(dt_idhash_t *ihp, dt_ident_t *idp, dt_probe_iter_t *pit) { const dt_probe_t *prp = idp->di_data; if (!dt_gmatch(prp->pr_name, pit->pit_pat)) return (0); /* continue on and examine next probe in hash */ (void) strlcpy(pit->pit_desc.dtpd_name, prp->pr_name, DTRACE_NAMELEN); pit->pit_desc.dtpd_id = idp->di_id; pit->pit_matches++; return (pit->pit_func(pit->pit_hdl, &pit->pit_desc, pit->pit_arg)); } int dtrace_probe_iter(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, dtrace_probe_f *func, void *arg) { const char *provider = pdp ? pdp->dtpd_provider : NULL; dtrace_id_t id = DTRACE_IDNONE; dtrace_probedesc_t pd; dt_probe_iter_t pit; int cmd, rv; bzero(&pit, sizeof (pit)); pit.pit_hdl = dtp; pit.pit_func = func; pit.pit_arg = arg; pit.pit_pat = pdp ? pdp->dtpd_name : NULL; for (pit.pit_pvp = dt_list_next(&dtp->dt_provlist); pit.pit_pvp != NULL; pit.pit_pvp = dt_list_next(pit.pit_pvp)) { if (pit.pit_pvp->pv_flags & DT_PROVIDER_IMPL) continue; /* we'll get these later using dt_ioctl() */ if (!dt_gmatch(pit.pit_pvp->pv_desc.dtvd_name, provider)) continue; (void) strlcpy(pit.pit_desc.dtpd_provider, pit.pit_pvp->pv_desc.dtvd_name, DTRACE_PROVNAMELEN); if ((rv = dt_idhash_iter(pit.pit_pvp->pv_probes, (dt_idhash_f *)dt_probe_iter, &pit)) != 0) return (rv); } if (pdp != NULL) cmd = DTRACEIOC_PROBEMATCH; else cmd = DTRACEIOC_PROBES; for (;;) { if (pdp != NULL) bcopy(pdp, &pd, sizeof (pd)); pd.dtpd_id = id; if (dt_ioctl(dtp, cmd, &pd) != 0) break; else if ((rv = func(dtp, &pd, arg)) != 0) return (rv); pit.pit_matches++; id = pd.dtpd_id + 1; } switch (errno) { case ESRCH: case EBADF: return (pit.pit_matches ? 0 : dt_set_errno(dtp, EDT_NOPROBE)); case EINVAL: return (dt_set_errno(dtp, EDT_BADPGLOB)); default: return (dt_set_errno(dtp, errno)); } } Index: projects/ipsec/cddl/contrib/opensolaris =================================================================== --- projects/ipsec/cddl/contrib/opensolaris (revision 313312) +++ projects/ipsec/cddl/contrib/opensolaris (revision 313313) Property changes on: projects/ipsec/cddl/contrib/opensolaris ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/cddl/contrib/opensolaris:r310414-313312 Index: projects/ipsec/cddl =================================================================== --- projects/ipsec/cddl (revision 313312) +++ projects/ipsec/cddl (revision 313313) Property changes on: projects/ipsec/cddl ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/cddl:r313116-313312 Index: projects/ipsec/etc/devd.conf =================================================================== --- projects/ipsec/etc/devd.conf (revision 313312) +++ projects/ipsec/etc/devd.conf (revision 313313) @@ -1,341 +1,341 @@ # $FreeBSD$ # # Refer to devd.conf(5) and devd(8) man pages for the details on how to # run and configure devd. # # NB: All regular expressions have an implicit ^$ around them. # NB: device-name is shorthand for 'match device-name' options { # Each "directory" directive adds a directory to the list of # directories that we scan for files. Files are loaded in the order # that they are returned from readdir(3). The rule-sets are combined # to create a DFA that's used to match events to actions. directory "/etc/devd"; directory "/usr/local/etc/devd"; pid-file "/var/run/devd.pid"; # Setup some shorthand for regex that we use later in the file. #XXX Yes, these are gross -- imp set scsi-controller-regex "(aac|adv|adw|aha|ahb|ahc|ahd|aic|amr|bt|ciss|ct|dpt|\ esp|ida|iir|ips|isp|mlx|mly|mpt|ncr|ncv|nsp|stg|sym|trm)\ [0-9]+"; set wifi-driver-regex "(ath|bwi|bwn|ipw|iwi|iwm|iwn|malo|mwl|ral|rsu|rtwn|rum|run|\ uath|upgt|ural|urtw|wi|wpi|wtap|zyd)[0-9]+"; }; # Note that the attach/detach with the highest value wins, so that one can # override these general rules. # # Configure the interface on attach. Due to a historical accident, this # script is called pccard_ether. # # NB: DETACH events are ignored; the kernel should handle all cleanup # (routes, arp cache). Beware of races against immediate create # of a device with the same name; e.g. # ifconfig bridge0 destroy; ifconfig bridge0 create # notify 0 { match "system" "IFNET"; match "subsystem" "!usbus[0-9]+"; match "type" "ATTACH"; action "/etc/pccard_ether $subsystem start"; }; # # Try to start dhclient on Ethernet-like interfaces when the link comes # up. Only devices that are configured to support DHCP will actually # run it. No link down rule exists because dhclient automatically exits # when the link goes down. # notify 0 { match "system" "IFNET"; match "type" "LINK_UP"; media-type "ethernet"; action "/etc/rc.d/dhclient quietstart $subsystem"; }; # # Like Ethernet devices, but separate because 802.11 require spawning # wlan(4) interface. # attach 0 { device-name "$wifi-driver-regex"; action "/etc/pccard_ether $device-name startchildren"; }; detach 0 { device-name "$wifi-driver-regex"; action "/etc/pccard_ether $device-name stopchildren"; }; notify 0 { match "system" "IFNET"; match "type" "LINK_UP"; media-type "802.11"; action "/etc/rc.d/dhclient quietstart $subsystem"; }; # An entry like this might be in a different file, but is included here # as an example of how to override things. Normally 'ed50' would match # the above attach/detach stuff, but the value of 100 makes it # hard wired to 1.2.3.4. attach 100 { device-name "ed50"; action "ifconfig $device-name inet 1.2.3.4 netmask 0xffff0000"; }; detach 100 { device-name "ed50"; }; # When a USB Bluetooth dongle appears, activate it attach 100 { device-name "ubt[0-9]+"; action "/etc/rc.d/bluetooth quietstart $device-name"; }; detach 100 { device-name "ubt[0-9]+"; action "/etc/rc.d/bluetooth quietstop $device-name"; }; # Firmware downloader for Atheros AR3011 based USB Bluetooth devices #attach 100 { # match "vendor" "0x0cf3"; # match "product" "0x3000"; # action "sleep 2 && /usr/sbin/ath3kfw -d $device-name -f /usr/local/etc/ath3k-1.fw"; #}; # When a USB keyboard arrives, attach it as the console keyboard. attach 100 { device-name "ukbd0"; action "/etc/rc.d/syscons setkeyboard /dev/ukbd0"; }; detach 100 { device-name "ukbd0"; action "/etc/rc.d/syscons setkeyboard /dev/kbd0"; }; notify 100 { match "system" "DEVFS"; match "subsystem" "CDEV"; match "type" "CREATE"; match "cdev" "atp[0-9]+"; action "/etc/rc.d/moused quietstart $cdev"; }; notify 100 { match "system" "DEVFS"; match "subsystem" "CDEV"; match "type" "CREATE"; match "cdev" "ums[0-9]+"; action "/etc/rc.d/moused quietstart $cdev"; }; notify 100 { match "system" "DEVFS"; match "subsystem" "CDEV"; match "type" "CREATE"; match "cdev" "wsp[0-9]+"; action "/etc/rc.d/moused quietstart $cdev"; }; notify 100 { match "system" "DEVFS"; match "subsystem" "CDEV"; match "type" "DESTROY"; match "cdev" "ums[0-9]+"; action "/etc/rc.d/moused stop $cdev"; }; # Firmware download into the ActiveWire board. After the firmware download is # done, the device detaches and reappears as something new and shiny # automatically. attach 100 { match "vendor" "0x0854"; match "product" "0x0100"; match "release" "0x0000"; action "/usr/local/bin/ezdownload -f /usr/local/share/usb/firmware/0854.0100.0_01.hex $device-name"; }; # Firmware download for Entrega Serial DB25 adapter. attach 100 { match "vendor" "0x1645"; match "product" "0x8001"; match "release" "0x0101"; action "if ! kldstat -n usio > /dev/null 2>&1 ; then kldload usio; fi; /usr/sbin/ezdownload -v -f /usr/share/usb/firmware/1645.8001.0101 /dev/$device-name"; }; # This entry starts the ColdSync tool in daemon mode. Make sure you have an up # to date /usr/local/etc/palms. We override the 'listen' settings for port and # type in /usr/local/etc/coldsync.conf. notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x082d"; match "product" "0x0100"; match "release" "0x0100"; action "/usr/local/bin/coldsync -md -p /dev/$cdev -t usb"; }; # # Rescan SCSI device-names on attach, but not detach. However, it is # disabled by default due to reports of problems. # attach 0 { device-name "$scsi-controller-regex"; // action "camcontrol rescan all"; }; # Don't even try to second guess what to do about drivers that don't # match here. Instead, pass it off to syslog. Commented out for the # moment, as the pnpinfo variable isn't set in devd yet. Individual # variables within the bus supplied pnpinfo are set. nomatch 0 { # action "logger Unknown device: $pnpinfo $location $bus"; }; # Various logging of unknown devices. nomatch 10 { match "bus" "uhub[0-9]+"; action "logger Unknown USB device: vendor $vendor product $product \ bus $bus"; }; # Some PC-CARDs don't offer numerical manufacturer/product IDs, just # show the CIS info there. nomatch 20 { match "bus" "pccard[0-9]+"; match "manufacturer" "0xffffffff"; match "product" "0xffffffff"; action "logger Unknown PCCARD device: CISproduct $cisproduct \ CIS-vendor $cisvendor bus $bus"; }; nomatch 10 { match "bus" "pccard[0-9]+"; action "logger Unknown PCCARD device: manufacturer $manufacturer \ product $product CISproduct $cisproduct CIS-vendor \ $cisvendor bus $bus"; }; nomatch 10 { match "bus" "cardbus[0-9]+"; action "logger Unknown Cardbus device: device $device class $class \ vendor $vendor bus $bus"; }; # Switch power profiles when the AC line state changes. notify 10 { match "system" "ACPI"; match "subsystem" "ACAD"; action "/etc/rc.d/power_profile $notify"; }; # Notify all users before beginning emergency shutdown when we get # a _CRT or _HOT thermal event and we're going to power down the system # very soon. notify 10 { match "system" "ACPI"; match "subsystem" "Thermal"; match "notify" "0xcc"; action "logger -p kern.emerg 'WARNING: system temperature too high, shutting down soon!'"; }; # User requested suspend, so perform preparation steps and then execute # the actual suspend process. notify 10 { match "system" "ACPI"; match "subsystem" "Suspend"; action "/etc/rc.suspend acpi $notify"; }; notify 10 { match "system" "ACPI"; match "subsystem" "Resume"; action "/etc/rc.resume acpi $notify"; }; /* EXAMPLES TO END OF FILE # An example of something that a vendor might install if you were to # add their device. This might reside in /usr/local/etc/devd/deqna.conf. # A deqna is, in this hypothetical example, a pccard ethernet-like device. # Students of history may know other devices by this name, and will get # the in-jokes in this entry. nomatch 10 { match "bus" "pccard[0-9]+"; match "manufacturer" "0x1234"; match "product" "0x2323"; - action "kldload if_deqna"; + action "kldload -n if_deqna"; }; attach 10 { device-name "deqna[0-9]+"; action "/etc/pccard_ether $device-name start"; }; detach 10 { device-name "deqna[0-9]+"; action "/etc/pccard_ether $device-name stop"; }; # Examples of notify hooks. A notify is a generic way for a kernel # subsystem to send event notification to userland. # Here are some examples of ACPI notify handlers. ACPI subsystems that # generate notifies include the AC adapter, power/sleep buttons, # control method batteries, lid switch, and thermal zones. # # Information returned is not always the same as the ACPI notify # events. See the ACPI specification for more information about # notifies. Here is the information returned for each subsystem: # # ACAD: AC line state (0 is offline, 1 is online) # Button: Button pressed (0 for power, 1 for sleep) # CMBAT: ACPI battery events # Lid: Lid state (0 is closed, 1 is open) # Suspend, Resume: Suspend and resume notification # Thermal: ACPI thermal zone events # # This example calls a script when the AC state changes, passing the # notify value as the first argument. If the state is 0x00, it might # call some sysctls to implement economy mode. If 0x01, it might set # the mode to performance. notify 10 { match "system" "ACPI"; match "subsystem" "ACAD"; action "/etc/acpi_ac $notify"; }; # This example works around a memory leak in PostgreSQL, restarting # it when the "user:pgsql:swap:devctl=1G" rctl(8) rule gets triggered. notify 0 { match "system" "RCTL"; match "rule" "user:70:swap:.*"; action "/usr/local/etc/rc.d/postgresql restart"; }; # Discard autofs caches, useful for the -media special map. notify 100 { match "system" "GEOM"; match "subsystem" "DEV"; action "/usr/sbin/automount -c"; }; # Handle userland coredumps. # This commented out handler makes it possible to run an # automated debugging session after the core dump is generated. # Replace action with a proper coredump handler, but be aware that # it will run with elevated privileges. notify 10 { match "system" "kernel"; match "subsystem" "signal"; match "type" "coredump"; action "logger $comm $core"; }; */ Index: projects/ipsec/sbin/decryptcore/decryptcore.c =================================================================== --- projects/ipsec/sbin/decryptcore/decryptcore.c (revision 313312) +++ projects/ipsec/sbin/decryptcore/decryptcore.c (revision 313313) @@ -1,373 +1,373 @@ /*- * Copyright (c) 2016 Konrad Witaszczyk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include "pjdlog.h" #define DECRYPTCORE_CRASHDIR "/var/crash" static void usage(void) { pjdlog_exitx(1, "usage: decryptcore [-Lv] -p privatekeyfile -k keyfile -e encryptedcore -c core\n" " decryptcore [-Lv] [-d crashdir] -p privatekeyfile -n dumpnr"); } static int wait_for_process(pid_t pid) { int status; if (waitpid(pid, &status, WUNTRACED | WEXITED) == -1) { pjdlog_errno(LOG_ERR, "Unable to wait for a child process"); return (1); } if (WIFEXITED(status)) return (WEXITSTATUS(status)); return (1); } static struct kerneldumpkey * read_key(int kfd) { struct kerneldumpkey *kdk; ssize_t size; size_t kdksize; PJDLOG_ASSERT(kfd >= 0); kdksize = sizeof(*kdk); kdk = calloc(1, kdksize); if (kdk == NULL) { pjdlog_errno(LOG_ERR, "Unable to allocate kernel dump key"); goto failed; } size = read(kfd, kdk, kdksize); if (size == (ssize_t)kdksize) { kdk->kdk_encryptedkeysize = dtoh32(kdk->kdk_encryptedkeysize); kdksize += (size_t)kdk->kdk_encryptedkeysize; kdk = realloc(kdk, kdksize); if (kdk == NULL) { pjdlog_errno(LOG_ERR, "Unable to reallocate kernel dump key"); goto failed; } size += read(kfd, &kdk->kdk_encryptedkey, kdk->kdk_encryptedkeysize); } if (size != (ssize_t)kdksize) { pjdlog_errno(LOG_ERR, "Unable to read key"); goto failed; } return (kdk); failed: free(kdk); return (NULL); } static bool decrypt(const char *privkeyfile, const char *keyfile, const char *input, const char *output) { uint8_t buf[KERNELDUMP_BUFFER_SIZE], key[KERNELDUMP_KEY_MAX_SIZE]; EVP_CIPHER_CTX ctx; const EVP_CIPHER *cipher; FILE *fp; struct kerneldumpkey *kdk; RSA *privkey; int ifd, kfd, ofd, olen, privkeysize; ssize_t bytes; pid_t pid; PJDLOG_ASSERT(privkeyfile != NULL); PJDLOG_ASSERT(keyfile != NULL); PJDLOG_ASSERT(input != NULL); PJDLOG_ASSERT(output != NULL); privkey = NULL; /* * Decrypt a core dump in a child process so we can unlink a partially * decrypted core if the child process fails. */ pid = fork(); if (pid == -1) { pjdlog_errno(LOG_ERR, "Unable to create child process"); return (false); } if (pid > 0) return (wait_for_process(pid) == 0); kfd = open(keyfile, O_RDONLY); if (kfd == -1) { pjdlog_errno(LOG_ERR, "Unable to open %s", keyfile); goto failed; } ifd = open(input, O_RDONLY); if (ifd == -1) { pjdlog_errno(LOG_ERR, "Unable to open %s", input); goto failed; } ofd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (ofd == -1) { pjdlog_errno(LOG_ERR, "Unable to open %s", output); goto failed; } fp = fopen(privkeyfile, "r"); if (fp == NULL) { pjdlog_errno(LOG_ERR, "Unable to open %s", privkeyfile); goto failed; } if (cap_enter() < 0 && errno != ENOSYS) { pjdlog_errno(LOG_ERR, "Unable to enter capability mode"); goto failed; } privkey = RSA_new(); if (privkey == NULL) { pjdlog_error("Unable to allocate an RSA structure: %s", ERR_error_string(ERR_get_error(), NULL)); goto failed; } EVP_CIPHER_CTX_init(&ctx); kdk = read_key(kfd); close(kfd); if (kdk == NULL) goto failed; privkey = PEM_read_RSAPrivateKey(fp, &privkey, NULL, NULL); fclose(fp); if (privkey == NULL) { pjdlog_error("Unable to read data from %s.", privkeyfile); goto failed; } privkeysize = RSA_size(privkey); if (privkeysize != (int)kdk->kdk_encryptedkeysize) { pjdlog_error("RSA modulus size mismatch: equals %db and should be %ub.", 8 * privkeysize, 8 * kdk->kdk_encryptedkeysize); goto failed; } switch (kdk->kdk_encryption) { case KERNELDUMP_ENC_AES_256_CBC: cipher = EVP_aes_256_cbc(); break; default: pjdlog_error("Invalid encryption algorithm."); goto failed; } if (RSA_private_decrypt(kdk->kdk_encryptedkeysize, kdk->kdk_encryptedkey, key, privkey, RSA_PKCS1_PADDING) != sizeof(key)) { pjdlog_error("Unable to decrypt key: %s", ERR_error_string(ERR_get_error(), NULL)); goto failed; } RSA_free(privkey); privkey = NULL; EVP_DecryptInit_ex(&ctx, cipher, NULL, key, kdk->kdk_iv); EVP_CIPHER_CTX_set_padding(&ctx, 0); explicit_bzero(key, sizeof(key)); do { bytes = read(ifd, buf, sizeof(buf)); if (bytes < 0) { pjdlog_errno(LOG_ERR, "Unable to read data from %s", input); goto failed; - } else if (bytes == 0) { - break; } if (bytes > 0) { if (EVP_DecryptUpdate(&ctx, buf, &olen, buf, bytes) == 0) { pjdlog_error("Unable to decrypt core."); goto failed; } } else { if (EVP_DecryptFinal_ex(&ctx, buf, &olen) == 0) { pjdlog_error("Unable to decrypt core."); goto failed; } } - if (olen == 0) - continue; - - if (write(ofd, buf, olen) != olen) { + if (olen > 0 && write(ofd, buf, olen) != olen) { pjdlog_errno(LOG_ERR, "Unable to write data to %s", output); goto failed; } } while (bytes > 0); explicit_bzero(buf, sizeof(buf)); EVP_CIPHER_CTX_cleanup(&ctx); exit(0); failed: explicit_bzero(key, sizeof(key)); explicit_bzero(buf, sizeof(buf)); RSA_free(privkey); EVP_CIPHER_CTX_cleanup(&ctx); exit(1); } int main(int argc, char **argv) { char core[PATH_MAX], encryptedcore[PATH_MAX], keyfile[PATH_MAX]; - struct stat sb; const char *crashdir, *dumpnr, *privatekey; int ch, debug; size_t ii; bool usesyslog; pjdlog_init(PJDLOG_MODE_STD); pjdlog_prefix_set("(decryptcore) "); debug = 0; *core = '\0'; crashdir = NULL; dumpnr = NULL; *encryptedcore = '\0'; *keyfile = '\0'; privatekey = NULL; usesyslog = false; while ((ch = getopt(argc, argv, "Lc:d:e:k:n:p:v")) != -1) { switch (ch) { case 'L': usesyslog = true; break; case 'c': - strncpy(core, optarg, sizeof(core)); + if (strlcpy(core, optarg, sizeof(core)) >= sizeof(core)) + pjdlog_exitx(1, "Core file path is too long."); break; case 'd': crashdir = optarg; break; case 'e': - strncpy(encryptedcore, optarg, sizeof(encryptedcore)); + if (strlcpy(encryptedcore, optarg, + sizeof(encryptedcore)) >= sizeof(encryptedcore)) { + pjdlog_exitx(1, "Encrypted core file path is too long."); + } break; case 'k': - strncpy(keyfile, optarg, sizeof(keyfile)); + if (strlcpy(keyfile, optarg, sizeof(keyfile)) >= + sizeof(keyfile)) { + pjdlog_exitx(1, "Key file path is too long."); + } break; case 'n': dumpnr = optarg; break; case 'p': privatekey = optarg; break; case 'v': debug++; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 0) usage(); /* Verify mutually exclusive options. */ if ((crashdir != NULL || dumpnr != NULL) && (*keyfile != '\0' || *encryptedcore != '\0' || *core != '\0')) { usage(); } /* * Set key, encryptedcore and core file names using crashdir and dumpnr. */ if (dumpnr != NULL) { for (ii = 0; ii < strnlen(dumpnr, PATH_MAX); ii++) { if (isdigit((int)dumpnr[ii]) == 0) usage(); } if (crashdir == NULL) crashdir = DECRYPTCORE_CRASHDIR; PJDLOG_VERIFY(snprintf(keyfile, sizeof(keyfile), "%s/key.%s", crashdir, dumpnr) > 0); PJDLOG_VERIFY(snprintf(core, sizeof(core), "%s/vmcore.%s", crashdir, dumpnr) > 0); PJDLOG_VERIFY(snprintf(encryptedcore, sizeof(encryptedcore), "%s/vmcore_encrypted.%s", crashdir, dumpnr) > 0); } if (privatekey == NULL || *keyfile == '\0' || *encryptedcore == '\0' || *core == '\0') { usage(); } if (usesyslog) pjdlog_mode_set(PJDLOG_MODE_SYSLOG); pjdlog_debug_set(debug); if (!decrypt(privatekey, keyfile, encryptedcore, core)) { - if (stat(core, &sb) == 0 && unlink(core) != 0) + if (unlink(core) == -1 && errno != ENOENT) pjdlog_exit(1, "Unable to remove core"); exit(1); } pjdlog_fini(); exit(0); } Index: projects/ipsec/sbin/hastctl/Makefile =================================================================== --- projects/ipsec/sbin/hastctl/Makefile (revision 313312) +++ projects/ipsec/sbin/hastctl/Makefile (revision 313313) @@ -1,46 +1,42 @@ # $FreeBSD$ .include PACKAGE=hast .PATH: ${.CURDIR}/../hastd PROG= hastctl SRCS= activemap.c SRCS+= crc32.c SRCS+= ebuf.c SRCS+= hast_checksum.c hast_compression.c hast_proto.c hastctl.c SRCS+= lzf.c SRCS+= metadata.c SRCS+= nv.c SRCS+= parse.y pjdlog.c SRCS+= proto.c proto_common.c proto_uds.c SRCS+= token.l SRCS+= subr.c SRCS+= y.tab.h MAN= hastctl.8 NO_WFORMAT= NO_WCAST_ALIGN= NO_WMISSING_VARIABLE_DECLARATIONS= CFLAGS+=-I${.CURDIR}/../hastd CFLAGS+=-DHAVE_CAPSICUM CFLAGS+=-DINET .if ${MK_INET6_SUPPORT} != "no" CFLAGS+=-DINET6 .endif # This is needed to have WARNS > 1. CFLAGS+=-DYY_NO_UNPUT CFLAGS+=-DYY_NO_INPUT -LIBADD= util -.if ${MK_OPENSSL} != "no" -LIBADD+= crypto -CFLAGS+=-DHAVE_CRYPTO -.endif +LIBADD= md util YFLAGS+=-v CLEANFILES=y.tab.c y.tab.h y.output .include Index: projects/ipsec/sbin/hastd/Makefile =================================================================== --- projects/ipsec/sbin/hastd/Makefile (revision 313312) +++ projects/ipsec/sbin/hastd/Makefile (revision 313313) @@ -1,44 +1,40 @@ # $FreeBSD$ .include PACKAGE=hast PROG= hastd SRCS= activemap.c SRCS+= control.c crc32.c SRCS+= ebuf.c event.c SRCS+= hast_checksum.c hast_compression.c hast_proto.c hastd.c hooks.c SRCS+= lzf.c SRCS+= metadata.c SRCS+= nv.c SRCS+= secondary.c SRCS+= parse.y pjdlog.c primary.c SRCS+= proto.c proto_common.c proto_socketpair.c proto_tcp.c proto_uds.c SRCS+= rangelock.c SRCS+= subr.c SRCS+= token.l SRCS+= y.tab.h MAN= hastd.8 hast.conf.5 NO_WFORMAT= NO_WCAST_ALIGN= NO_WMISSING_VARIABLE_DECLARATIONS= CFLAGS+=-I${.CURDIR} CFLAGS+=-DHAVE_CAPSICUM CFLAGS+=-DPROTO_TCP_DEFAULT_PORT=8457 CFLAGS+=-DINET .if ${MK_INET6_SUPPORT} != "no" CFLAGS+=-DINET6 .endif -LIBADD= geom pthread util -.if ${MK_OPENSSL} != "no" -LIBADD+= crypto -CFLAGS+=-DHAVE_CRYPTO -.endif +LIBADD= geom md pthread util YFLAGS+=-v CLEANFILES=y.tab.c y.tab.h y.output .include Index: projects/ipsec/sbin/hastd/hast_checksum.c =================================================================== --- projects/ipsec/sbin/hastd/hast_checksum.c (revision 313312) +++ projects/ipsec/sbin/hastd/hast_checksum.c (revision 313313) @@ -1,160 +1,147 @@ /*- * Copyright (c) 2011 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include -#ifdef HAVE_CRYPTO -#include -#endif - #include #include #include +#include #include #include "hast_checksum.h" -#ifdef HAVE_CRYPTO #define MAX_HASH_SIZE SHA256_DIGEST_LENGTH -#else -#define MAX_HASH_SIZE 4 -#endif static void hast_crc32_checksum(const unsigned char *data, size_t size, unsigned char *hash, size_t *hsizep) { uint32_t crc; crc = crc32(data, size); /* XXXPJD: Do we have to use htole32() on crc first? */ bcopy(&crc, hash, sizeof(crc)); *hsizep = sizeof(crc); } -#ifdef HAVE_CRYPTO static void hast_sha256_checksum(const unsigned char *data, size_t size, unsigned char *hash, size_t *hsizep) { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, data, size); SHA256_Final(hash, &ctx); *hsizep = SHA256_DIGEST_LENGTH; } -#endif /* HAVE_CRYPTO */ const char * checksum_name(int num) { switch (num) { case HAST_CHECKSUM_NONE: return ("none"); case HAST_CHECKSUM_CRC32: return ("crc32"); case HAST_CHECKSUM_SHA256: return ("sha256"); } return ("unknown"); } int checksum_send(const struct hast_resource *res, struct nv *nv, void **datap, size_t *sizep, bool *freedatap __unused) { unsigned char hash[MAX_HASH_SIZE]; size_t hsize; switch (res->hr_checksum) { case HAST_CHECKSUM_NONE: return (0); case HAST_CHECKSUM_CRC32: hast_crc32_checksum(*datap, *sizep, hash, &hsize); break; -#ifdef HAVE_CRYPTO case HAST_CHECKSUM_SHA256: hast_sha256_checksum(*datap, *sizep, hash, &hsize); break; -#endif default: PJDLOG_ABORT("Invalid checksum: %d.", res->hr_checksum); } nv_add_string(nv, checksum_name(res->hr_checksum), "checksum"); nv_add_uint8_array(nv, hash, hsize, "hash"); if (nv_error(nv) != 0) { errno = nv_error(nv); return (-1); } return (0); } int checksum_recv(const struct hast_resource *res __unused, struct nv *nv, void **datap, size_t *sizep, bool *freedatap __unused) { unsigned char chash[MAX_HASH_SIZE]; const unsigned char *rhash; size_t chsize, rhsize; const char *algo; algo = nv_get_string(nv, "checksum"); if (algo == NULL) return (0); /* No checksum. */ rhash = nv_get_uint8_array(nv, &rhsize, "hash"); if (rhash == NULL) { pjdlog_error("Hash is missing."); return (-1); /* Hash not found. */ } if (strcmp(algo, "crc32") == 0) hast_crc32_checksum(*datap, *sizep, chash, &chsize); -#ifdef HAVE_CRYPTO else if (strcmp(algo, "sha256") == 0) hast_sha256_checksum(*datap, *sizep, chash, &chsize); -#endif else { pjdlog_error("Unknown checksum algorithm '%s'.", algo); return (-1); /* Unknown checksum algorithm. */ } if (rhsize != chsize) { pjdlog_error("Invalid hash size (%zu) for %s, should be %zu.", rhsize, algo, chsize); return (-1); /* Different hash size. */ } if (bcmp(rhash, chash, chsize) != 0) { pjdlog_error("Hash mismatch."); return (-1); /* Hash mismatch. */ } return (0); } Index: projects/ipsec/sbin/hastd/hast_proto.c =================================================================== --- projects/ipsec/sbin/hastd/hast_proto.c (revision 313312) +++ projects/ipsec/sbin/hastd/hast_proto.c (revision 313313) @@ -1,222 +1,218 @@ /*- * Copyright (c) 2009-2010 The FreeBSD Foundation * Copyright (c) 2011 Pawel Jakub Dawidek * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include -#ifdef HAVE_CRYPTO #include "hast_checksum.h" -#endif #include "hast_compression.h" #include "hast_proto.h" struct hast_main_header { /* Protocol version. */ uint8_t version; /* Size of nv headers. */ uint32_t size; } __packed; typedef int hps_send_t(const struct hast_resource *, struct nv *nv, void **, size_t *, bool *); typedef int hps_recv_t(const struct hast_resource *, struct nv *nv, void **, size_t *, bool *); struct hast_pipe_stage { const char *hps_name; hps_send_t *hps_send; hps_recv_t *hps_recv; }; static struct hast_pipe_stage pipeline[] = { { "compression", compression_send, compression_recv }, -#ifdef HAVE_CRYPTO { "checksum", checksum_send, checksum_recv } -#endif }; /* * Send the given nv structure via conn. * We keep headers in nv structure and pass data in separate argument. * There can be no data at all (data is NULL then). */ int hast_proto_send(const struct hast_resource *res, struct proto_conn *conn, struct nv *nv, const void *data, size_t size) { struct hast_main_header hdr; struct ebuf *eb; bool freedata; void *dptr, *hptr; size_t hsize; int ret; dptr = (void *)(uintptr_t)data; freedata = false; ret = -1; if (data != NULL) { unsigned int ii; for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]); ii++) { (void)pipeline[ii].hps_send(res, nv, &dptr, &size, &freedata); } nv_add_uint32(nv, size, "size"); if (nv_error(nv) != 0) { errno = nv_error(nv); goto end; } } eb = nv_hton(nv); if (eb == NULL) goto end; hdr.version = res != NULL ? res->hr_version : HAST_PROTO_VERSION; hdr.size = htole32((uint32_t)ebuf_size(eb)); if (ebuf_add_head(eb, &hdr, sizeof(hdr)) == -1) goto end; hptr = ebuf_data(eb, &hsize); if (proto_send(conn, hptr, hsize) == -1) goto end; if (data != NULL && proto_send(conn, dptr, size) == -1) goto end; ret = 0; end: if (freedata) free(dptr); return (ret); } int hast_proto_recv_hdr(const struct proto_conn *conn, struct nv **nvp) { struct hast_main_header hdr; struct nv *nv; struct ebuf *eb; void *hptr; eb = NULL; nv = NULL; if (proto_recv(conn, &hdr, sizeof(hdr)) == -1) goto fail; if (hdr.version > HAST_PROTO_VERSION) { errno = ERPCMISMATCH; goto fail; } hdr.size = le32toh(hdr.size); eb = ebuf_alloc(hdr.size); if (eb == NULL) goto fail; if (ebuf_add_tail(eb, NULL, hdr.size) == -1) goto fail; hptr = ebuf_data(eb, NULL); PJDLOG_ASSERT(hptr != NULL); if (proto_recv(conn, hptr, hdr.size) == -1) goto fail; nv = nv_ntoh(eb); if (nv == NULL) goto fail; *nvp = nv; return (0); fail: if (eb != NULL) ebuf_free(eb); return (-1); } int hast_proto_recv_data(const struct hast_resource *res, struct proto_conn *conn, struct nv *nv, void *data, size_t size) { unsigned int ii; bool freedata; size_t dsize; void *dptr; int ret; PJDLOG_ASSERT(data != NULL); PJDLOG_ASSERT(size > 0); ret = -1; freedata = false; dptr = data; dsize = nv_get_uint32(nv, "size"); if (dsize > size) { errno = EINVAL; goto end; } else if (dsize == 0) { (void)nv_set_error(nv, 0); } else { if (proto_recv(conn, data, dsize) == -1) goto end; for (ii = sizeof(pipeline) / sizeof(pipeline[0]); ii > 0; ii--) { ret = pipeline[ii - 1].hps_recv(res, nv, &dptr, &dsize, &freedata); if (ret == -1) goto end; } ret = -1; if (dsize > size) { errno = EINVAL; goto end; } if (dptr != data) bcopy(dptr, data, dsize); } ret = 0; end: if (freedata) free(dptr); return (ret); } Index: projects/ipsec/sbin/ifconfig/ifieee80211.c =================================================================== --- projects/ipsec/sbin/ifconfig/ifieee80211.c (revision 313312) +++ projects/ipsec/sbin/ifconfig/ifieee80211.c (revision 313313) @@ -1,5741 +1,5741 @@ /* * Copyright 2001 The Aerospace Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of The Aerospace Corporation may not be used to endorse or * promote products derived from this software. * * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``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 AEROSPACE CORPORATION 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. * * $FreeBSD$ */ /*- * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * 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. * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* NB: for offsetof */ #include "ifconfig.h" #include #include #ifndef IEEE80211_FIXED_RATE_NONE #define IEEE80211_FIXED_RATE_NONE 0xff #endif /* XXX need these publicly defined or similar */ #ifndef IEEE80211_NODE_AUTH #define IEEE80211_NODE_AUTH 0x000001 /* authorized for data */ #define IEEE80211_NODE_QOS 0x000002 /* QoS enabled */ #define IEEE80211_NODE_ERP 0x000004 /* ERP enabled */ #define IEEE80211_NODE_PWR_MGT 0x000010 /* power save mode enabled */ #define IEEE80211_NODE_AREF 0x000020 /* authentication ref held */ #define IEEE80211_NODE_HT 0x000040 /* HT enabled */ #define IEEE80211_NODE_HTCOMPAT 0x000080 /* HT setup w/ vendor OUI's */ #define IEEE80211_NODE_WPS 0x000100 /* WPS association */ #define IEEE80211_NODE_TSN 0x000200 /* TSN association */ #define IEEE80211_NODE_AMPDU_RX 0x000400 /* AMPDU rx enabled */ #define IEEE80211_NODE_AMPDU_TX 0x000800 /* AMPDU tx enabled */ #define IEEE80211_NODE_MIMO_PS 0x001000 /* MIMO power save enabled */ #define IEEE80211_NODE_MIMO_RTS 0x002000 /* send RTS in MIMO PS */ #define IEEE80211_NODE_RIFS 0x004000 /* RIFS enabled */ #define IEEE80211_NODE_SGI20 0x008000 /* Short GI in HT20 enabled */ #define IEEE80211_NODE_SGI40 0x010000 /* Short GI in HT40 enabled */ #define IEEE80211_NODE_ASSOCID 0x020000 /* xmit requires associd */ #define IEEE80211_NODE_AMSDU_RX 0x040000 /* AMSDU rx enabled */ #define IEEE80211_NODE_AMSDU_TX 0x080000 /* AMSDU tx enabled */ #define IEEE80211_NODE_VHT 0x100000 /* VHT enabled */ #endif #define MAXCHAN 1536 /* max 1.5K channels */ #define MAXCOL 78 static int col; static char spacer; static void LINE_INIT(char c); static void LINE_BREAK(void); static void LINE_CHECK(const char *fmt, ...); static const char *modename[IEEE80211_MODE_MAX] = { [IEEE80211_MODE_AUTO] = "auto", [IEEE80211_MODE_11A] = "11a", [IEEE80211_MODE_11B] = "11b", [IEEE80211_MODE_11G] = "11g", [IEEE80211_MODE_FH] = "fh", [IEEE80211_MODE_TURBO_A] = "turboA", [IEEE80211_MODE_TURBO_G] = "turboG", [IEEE80211_MODE_STURBO_A] = "sturbo", [IEEE80211_MODE_11NA] = "11na", [IEEE80211_MODE_11NG] = "11ng", [IEEE80211_MODE_HALF] = "half", [IEEE80211_MODE_QUARTER] = "quarter", [IEEE80211_MODE_VHT_2GHZ] = "11acg", [IEEE80211_MODE_VHT_5GHZ] = "11ac", }; static void set80211(int s, int type, int val, int len, void *data); static int get80211(int s, int type, void *data, int len); static int get80211len(int s, int type, void *data, int len, int *plen); static int get80211val(int s, int type, int *val); static const char *get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp); static void print_string(const u_int8_t *buf, int len); static void print_regdomain(const struct ieee80211_regdomain *, int); static void print_channels(int, const struct ieee80211req_chaninfo *, int allchans, int verbose); static void regdomain_makechannels(struct ieee80211_regdomain_req *, const struct ieee80211_devcaps_req *); static const char *mesh_linkstate_string(uint8_t state); static struct ieee80211req_chaninfo *chaninfo; static struct ieee80211_regdomain regdomain; static int gotregdomain = 0; static struct ieee80211_roamparams_req roamparams; static int gotroam = 0; static struct ieee80211_txparams_req txparams; static int gottxparams = 0; static struct ieee80211_channel curchan; static int gotcurchan = 0; static struct ifmediareq *ifmr; static int htconf = 0; static int gothtconf = 0; static void gethtconf(int s) { if (gothtconf) return; if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0) warn("unable to get HT configuration information"); gothtconf = 1; } /* VHT */ static int vhtconf = 0; static int gotvhtconf = 0; static void getvhtconf(int s) { if (gotvhtconf) return; if (get80211val(s, IEEE80211_IOC_VHTCONF, &vhtconf) < 0) warn("unable to get VHT configuration information"); gotvhtconf = 1; } /* * Collect channel info from the kernel. We use this (mostly) * to handle mapping between frequency and IEEE channel number. */ static void getchaninfo(int s) { if (chaninfo != NULL) return; chaninfo = malloc(IEEE80211_CHANINFO_SIZE(MAXCHAN)); if (chaninfo == NULL) errx(1, "no space for channel list"); if (get80211(s, IEEE80211_IOC_CHANINFO, chaninfo, IEEE80211_CHANINFO_SIZE(MAXCHAN)) < 0) err(1, "unable to get channel information"); ifmr = ifmedia_getstate(s); gethtconf(s); getvhtconf(s); } static struct regdata * getregdata(void) { static struct regdata *rdp = NULL; if (rdp == NULL) { rdp = lib80211_alloc_regdata(); if (rdp == NULL) errx(-1, "missing or corrupted regdomain database"); } return rdp; } /* * Given the channel at index i with attributes from, * check if there is a channel with attributes to in * the channel table. With suitable attributes this * allows the caller to look for promotion; e.g. from * 11b > 11g. */ static int canpromote(int i, int from, int to) { const struct ieee80211_channel *fc = &chaninfo->ic_chans[i]; u_int j; if ((fc->ic_flags & from) != from) return i; /* NB: quick check exploiting ordering of chans w/ same frequency */ if (i+1 < chaninfo->ic_nchans && chaninfo->ic_chans[i+1].ic_freq == fc->ic_freq && (chaninfo->ic_chans[i+1].ic_flags & to) == to) return i+1; /* brute force search in case channel list is not ordered */ for (j = 0; j < chaninfo->ic_nchans; j++) { const struct ieee80211_channel *tc = &chaninfo->ic_chans[j]; if (j != i && tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to) return j; } return i; } /* * Handle channel promotion. When a channel is specified with * only a frequency we want to promote it to the ``best'' channel * available. The channel list has separate entries for 11b, 11g, * 11a, and 11n[ga] channels so specifying a frequency w/o any * attributes requires we upgrade, e.g. from 11b -> 11g. This * gets complicated when the channel is specified on the same * command line with a media request that constrains the available * channe list (e.g. mode 11a); we want to honor that to avoid * confusing behaviour. */ /* * XXX VHT */ static int promote(int i) { /* * Query the current mode of the interface in case it's * constrained (e.g. to 11a). We must do this carefully * as there may be a pending ifmedia request in which case * asking the kernel will give us the wrong answer. This * is an unfortunate side-effect of the way ifconfig is * structure for modularity (yech). * * NB: ifmr is actually setup in getchaninfo (above); we * assume it's called coincident with to this call so * we have a ``current setting''; otherwise we must pass * the socket descriptor down to here so we can make * the ifmedia_getstate call ourselves. */ int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO; /* when ambiguous promote to ``best'' */ /* NB: we abitrarily pick HT40+ over HT40- */ if (chanmode != IFM_IEEE80211_11B) i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G); if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) { i = canpromote(i, IEEE80211_CHAN_G, IEEE80211_CHAN_G | IEEE80211_CHAN_HT20); if (htconf & 2) { i = canpromote(i, IEEE80211_CHAN_G, IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D); i = canpromote(i, IEEE80211_CHAN_G, IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U); } } if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) { i = canpromote(i, IEEE80211_CHAN_A, IEEE80211_CHAN_A | IEEE80211_CHAN_HT20); if (htconf & 2) { i = canpromote(i, IEEE80211_CHAN_A, IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D); i = canpromote(i, IEEE80211_CHAN_A, IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U); } } return i; } static void mapfreq(struct ieee80211_channel *chan, int freq, int flags) { u_int i; for (i = 0; i < chaninfo->ic_nchans; i++) { const struct ieee80211_channel *c = &chaninfo->ic_chans[i]; if (c->ic_freq == freq && (c->ic_flags & flags) == flags) { if (flags == 0) { /* when ambiguous promote to ``best'' */ c = &chaninfo->ic_chans[promote(i)]; } *chan = *c; return; } } errx(1, "unknown/undefined frequency %u/0x%x", freq, flags); } static void mapchan(struct ieee80211_channel *chan, int ieee, int flags) { u_int i; for (i = 0; i < chaninfo->ic_nchans; i++) { const struct ieee80211_channel *c = &chaninfo->ic_chans[i]; if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) { if (flags == 0) { /* when ambiguous promote to ``best'' */ c = &chaninfo->ic_chans[promote(i)]; } *chan = *c; return; } } errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags); } static const struct ieee80211_channel * getcurchan(int s) { if (gotcurchan) return &curchan; if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) { int val; /* fall back to legacy ioctl */ if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0) err(-1, "cannot figure out current channel"); getchaninfo(s); mapchan(&curchan, val, 0); } gotcurchan = 1; return &curchan; } static enum ieee80211_phymode chan2mode(const struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_VHTA(c)) return IEEE80211_MODE_VHT_5GHZ; if (IEEE80211_IS_CHAN_VHTG(c)) return IEEE80211_MODE_VHT_2GHZ; if (IEEE80211_IS_CHAN_HTA(c)) return IEEE80211_MODE_11NA; if (IEEE80211_IS_CHAN_HTG(c)) return IEEE80211_MODE_11NG; if (IEEE80211_IS_CHAN_108A(c)) return IEEE80211_MODE_TURBO_A; if (IEEE80211_IS_CHAN_108G(c)) return IEEE80211_MODE_TURBO_G; if (IEEE80211_IS_CHAN_ST(c)) return IEEE80211_MODE_STURBO_A; if (IEEE80211_IS_CHAN_FHSS(c)) return IEEE80211_MODE_FH; if (IEEE80211_IS_CHAN_HALF(c)) return IEEE80211_MODE_HALF; if (IEEE80211_IS_CHAN_QUARTER(c)) return IEEE80211_MODE_QUARTER; if (IEEE80211_IS_CHAN_A(c)) return IEEE80211_MODE_11A; if (IEEE80211_IS_CHAN_ANYG(c)) return IEEE80211_MODE_11G; if (IEEE80211_IS_CHAN_B(c)) return IEEE80211_MODE_11B; return IEEE80211_MODE_AUTO; } static void getroam(int s) { if (gotroam) return; if (get80211(s, IEEE80211_IOC_ROAM, &roamparams, sizeof(roamparams)) < 0) err(1, "unable to get roaming parameters"); gotroam = 1; } static void setroam_cb(int s, void *arg) { struct ieee80211_roamparams_req *roam = arg; set80211(s, IEEE80211_IOC_ROAM, 0, sizeof(*roam), roam); } static void gettxparams(int s) { if (gottxparams) return; if (get80211(s, IEEE80211_IOC_TXPARAMS, &txparams, sizeof(txparams)) < 0) err(1, "unable to get transmit parameters"); gottxparams = 1; } static void settxparams_cb(int s, void *arg) { struct ieee80211_txparams_req *txp = arg; set80211(s, IEEE80211_IOC_TXPARAMS, 0, sizeof(*txp), txp); } static void getregdomain(int s) { if (gotregdomain) return; if (get80211(s, IEEE80211_IOC_REGDOMAIN, ®domain, sizeof(regdomain)) < 0) err(1, "unable to get regulatory domain info"); gotregdomain = 1; } static void getdevcaps(int s, struct ieee80211_devcaps_req *dc) { if (get80211(s, IEEE80211_IOC_DEVCAPS, dc, IEEE80211_DEVCAPS_SPACE(dc)) < 0) err(1, "unable to get device capabilities"); } static void setregdomain_cb(int s, void *arg) { struct ieee80211_regdomain_req *req; struct ieee80211_regdomain *rd = arg; struct ieee80211_devcaps_req *dc; struct regdata *rdp = getregdata(); if (rd->country != NO_COUNTRY) { const struct country *cc; /* * Check current country seting to make sure it's * compatible with the new regdomain. If not, then * override it with any default country for this * SKU. If we cannot arrange a match, then abort. */ cc = lib80211_country_findbycc(rdp, rd->country); if (cc == NULL) errx(1, "unknown ISO country code %d", rd->country); if (cc->rd->sku != rd->regdomain) { const struct regdomain *rp; /* * Check if country is incompatible with regdomain. * To enable multiple regdomains for a country code * we permit a mismatch between the regdomain and * the country's associated regdomain when the * regdomain is setup w/o a default country. For * example, US is bound to the FCC regdomain but * we allow US to be combined with FCC3 because FCC3 * has not default country. This allows bogus * combinations like FCC3+DK which are resolved when * constructing the channel list by deferring to the * regdomain to construct the channel list. */ rp = lib80211_regdomain_findbysku(rdp, rd->regdomain); if (rp == NULL) errx(1, "country %s (%s) is not usable with " "regdomain %d", cc->isoname, cc->name, rd->regdomain); else if (rp->cc != NULL && rp->cc != cc) errx(1, "country %s (%s) is not usable with " "regdomain %s", cc->isoname, cc->name, rp->name); } } /* * Fetch the device capabilities and calculate the * full set of netbands for which we request a new * channel list be constructed. Once that's done we * push the regdomain info + channel list to the kernel. */ dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN)); if (dc == NULL) errx(1, "no space for device capabilities"); dc->dc_chaninfo.ic_nchans = MAXCHAN; getdevcaps(s, dc); #if 0 if (verbose) { printf("drivercaps: 0x%x\n", dc->dc_drivercaps); printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps); printf("htcaps : 0x%x\n", dc->dc_htcaps); printf("vhtcaps : 0x%x\n", dc->dc_vhtcaps); #if 0 memcpy(chaninfo, &dc->dc_chaninfo, IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo)); print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/); #endif } #endif req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans)); if (req == NULL) errx(1, "no space for regdomain request"); req->rd = *rd; regdomain_makechannels(req, dc); if (verbose) { LINE_INIT(':'); print_regdomain(rd, 1/*verbose*/); LINE_BREAK(); /* blech, reallocate channel list for new data */ if (chaninfo != NULL) free(chaninfo); chaninfo = malloc(IEEE80211_CHANINFO_SPACE(&req->chaninfo)); if (chaninfo == NULL) errx(1, "no space for channel list"); memcpy(chaninfo, &req->chaninfo, IEEE80211_CHANINFO_SPACE(&req->chaninfo)); print_channels(s, &req->chaninfo, 1/*allchans*/, 1/*verbose*/); } if (req->chaninfo.ic_nchans == 0) errx(1, "no channels calculated"); set80211(s, IEEE80211_IOC_REGDOMAIN, 0, IEEE80211_REGDOMAIN_SPACE(req), req); free(req); free(dc); } static int ieee80211_mhz2ieee(int freq, int flags) { struct ieee80211_channel chan; mapfreq(&chan, freq, flags); return chan.ic_ieee; } static int isanyarg(const char *arg) { return (strncmp(arg, "-", 1) == 0 || strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0); } static void set80211ssid(const char *val, int d, int s, const struct afswtch *rafp) { int ssid; int len; u_int8_t data[IEEE80211_NWID_LEN]; ssid = 0; len = strlen(val); if (len > 2 && isdigit((int)val[0]) && val[1] == ':') { ssid = atoi(val)-1; val += 2; } bzero(data, sizeof(data)); len = sizeof(data); if (get_string(val, NULL, data, &len) == NULL) exit(1); set80211(s, IEEE80211_IOC_SSID, ssid, len, data); } static void set80211meshid(const char *val, int d, int s, const struct afswtch *rafp) { int len; u_int8_t data[IEEE80211_NWID_LEN]; memset(data, 0, sizeof(data)); len = sizeof(data); if (get_string(val, NULL, data, &len) == NULL) exit(1); set80211(s, IEEE80211_IOC_MESH_ID, 0, len, data); } static void set80211stationname(const char *val, int d, int s, const struct afswtch *rafp) { int len; u_int8_t data[33]; bzero(data, sizeof(data)); len = sizeof(data); get_string(val, NULL, data, &len); set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); } /* * Parse a channel specification for attributes/flags. * The syntax is: * freq/xx channel width (5,10,20,40,40+,40-) * freq:mode channel mode (a,b,g,h,n,t,s,d) * * These can be combined in either order; e.g. 2437:ng/40. * Modes are case insensitive. * * The result is not validated here; it's assumed to be * checked against the channel table fetched from the kernel. */ static int getchannelflags(const char *val, int freq) { #define _CHAN_HT 0x80000000 const char *cp; int flags; int is_vht = 0; flags = 0; cp = strchr(val, ':'); if (cp != NULL) { for (cp++; isalpha((int) *cp); cp++) { /* accept mixed case */ int c = *cp; if (isupper(c)) c = tolower(c); switch (c) { case 'a': /* 802.11a */ flags |= IEEE80211_CHAN_A; break; case 'b': /* 802.11b */ flags |= IEEE80211_CHAN_B; break; case 'g': /* 802.11g */ flags |= IEEE80211_CHAN_G; break; case 'v': /* vht: 802.11ac */ is_vht = 1; /* Fallthrough */ case 'h': /* ht = 802.11n */ case 'n': /* 802.11n */ flags |= _CHAN_HT; /* NB: private */ break; case 'd': /* dt = Atheros Dynamic Turbo */ flags |= IEEE80211_CHAN_TURBO; break; case 't': /* ht, dt, st, t */ /* dt and unadorned t specify Dynamic Turbo */ if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0) flags |= IEEE80211_CHAN_TURBO; break; case 's': /* st = Atheros Static Turbo */ flags |= IEEE80211_CHAN_STURBO; break; default: errx(-1, "%s: Invalid channel attribute %c\n", val, *cp); } } } cp = strchr(val, '/'); if (cp != NULL) { char *ep; u_long cw = strtoul(cp+1, &ep, 10); switch (cw) { case 5: flags |= IEEE80211_CHAN_QUARTER; break; case 10: flags |= IEEE80211_CHAN_HALF; break; case 20: /* NB: this may be removed below */ flags |= IEEE80211_CHAN_HT20; break; case 40: case 80: case 160: /* Handle the 80/160 VHT flag */ if (cw == 80) flags |= IEEE80211_CHAN_VHT80; else if (cw == 160) flags |= IEEE80211_CHAN_VHT160; /* Fallthrough */ if (ep != NULL && *ep == '+') flags |= IEEE80211_CHAN_HT40U; else if (ep != NULL && *ep == '-') flags |= IEEE80211_CHAN_HT40D; break; default: errx(-1, "%s: Invalid channel width\n", val); } } /* * Cleanup specifications. */ if ((flags & _CHAN_HT) == 0) { /* * If user specified freq/20 or freq/40 quietly remove * HT cw attributes depending on channel use. To give * an explicit 20/40 width for an HT channel you must * indicate it is an HT channel since all HT channels * are also usable for legacy operation; e.g. freq:n/40. */ flags &= ~IEEE80211_CHAN_HT; flags &= ~IEEE80211_CHAN_VHT; } else { /* * Remove private indicator that this is an HT channel * and if no explicit channel width has been given * provide the default settings. */ flags &= ~_CHAN_HT; if ((flags & IEEE80211_CHAN_HT) == 0) { struct ieee80211_channel chan; /* * Consult the channel list to see if we can use * HT40+ or HT40- (if both the map routines choose). */ if (freq > 255) mapfreq(&chan, freq, 0); else mapchan(&chan, freq, 0); flags |= (chan.ic_flags & IEEE80211_CHAN_HT); } /* * If VHT is enabled, then also set the VHT flag and the * relevant channel up/down. */ if (is_vht && (flags & IEEE80211_CHAN_HT)) { /* * XXX yes, maybe we should just have VHT, and reuse * HT20/HT40U/HT40D */ if (flags & IEEE80211_CHAN_VHT80) ; else if (flags & IEEE80211_CHAN_HT20) flags |= IEEE80211_CHAN_VHT20; else if (flags & IEEE80211_CHAN_HT40U) flags |= IEEE80211_CHAN_VHT40U; else if (flags & IEEE80211_CHAN_HT40D) flags |= IEEE80211_CHAN_VHT40D; } } return flags; #undef _CHAN_HT } static void getchannel(int s, struct ieee80211_channel *chan, const char *val) { int v, flags; char *eptr; memset(chan, 0, sizeof(*chan)); if (isanyarg(val)) { chan->ic_freq = IEEE80211_CHAN_ANY; return; } getchaninfo(s); errno = 0; v = strtol(val, &eptr, 10); if (val[0] == '\0' || val == eptr || errno == ERANGE || /* channel may be suffixed with nothing, :flag, or /width */ (eptr[0] != '\0' && eptr[0] != ':' && eptr[0] != '/')) errx(1, "invalid channel specification%s", errno == ERANGE ? " (out of range)" : ""); flags = getchannelflags(val, v); if (v > 255) { /* treat as frequency */ mapfreq(chan, v, flags); } else { mapchan(chan, v, flags); } } static void set80211channel(const char *val, int d, int s, const struct afswtch *rafp) { struct ieee80211_channel chan; getchannel(s, &chan, val); set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan); } static void set80211chanswitch(const char *val, int d, int s, const struct afswtch *rafp) { struct ieee80211_chanswitch_req csr; getchannel(s, &csr.csa_chan, val); csr.csa_mode = 1; csr.csa_count = 5; set80211(s, IEEE80211_IOC_CHANSWITCH, 0, sizeof(csr), &csr); } static void set80211authmode(const char *val, int d, int s, const struct afswtch *rafp) { int mode; if (strcasecmp(val, "none") == 0) { mode = IEEE80211_AUTH_NONE; } else if (strcasecmp(val, "open") == 0) { mode = IEEE80211_AUTH_OPEN; } else if (strcasecmp(val, "shared") == 0) { mode = IEEE80211_AUTH_SHARED; } else if (strcasecmp(val, "8021x") == 0) { mode = IEEE80211_AUTH_8021X; } else if (strcasecmp(val, "wpa") == 0) { mode = IEEE80211_AUTH_WPA; } else { errx(1, "unknown authmode"); } set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); } static void set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) { int mode; if (strcasecmp(val, "off") == 0) { mode = IEEE80211_POWERSAVE_OFF; } else if (strcasecmp(val, "on") == 0) { mode = IEEE80211_POWERSAVE_ON; } else if (strcasecmp(val, "cam") == 0) { mode = IEEE80211_POWERSAVE_CAM; } else if (strcasecmp(val, "psp") == 0) { mode = IEEE80211_POWERSAVE_PSP; } else if (strcasecmp(val, "psp-cam") == 0) { mode = IEEE80211_POWERSAVE_PSP_CAM; } else { errx(1, "unknown powersavemode"); } set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); } static void set80211powersave(const char *val, int d, int s, const struct afswtch *rafp) { if (d == 0) set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 0, NULL); else set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 0, NULL); } static void set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); } static void set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) { int mode; if (strcasecmp(val, "off") == 0) { mode = IEEE80211_WEP_OFF; } else if (strcasecmp(val, "on") == 0) { mode = IEEE80211_WEP_ON; } else if (strcasecmp(val, "mixed") == 0) { mode = IEEE80211_WEP_MIXED; } else { errx(1, "unknown wep mode"); } set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); } static void set80211wep(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); } static int isundefarg(const char *arg) { return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); } static void set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) { if (isundefarg(val)) set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); else set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); } static void set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) { int key = 0; int len; u_int8_t data[IEEE80211_KEYBUF_SIZE]; if (isdigit((int)val[0]) && val[1] == ':') { key = atoi(val)-1; val += 2; } bzero(data, sizeof(data)); len = sizeof(data); get_string(val, NULL, data, &len); set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); } /* * This function is purely a NetBSD compatibility interface. The NetBSD * interface is too inflexible, but it's there so we'll support it since * it's not all that hard. */ static void set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) { int txkey; int i, len; u_int8_t data[IEEE80211_KEYBUF_SIZE]; set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); if (isdigit((int)val[0]) && val[1] == ':') { txkey = val[0]-'0'-1; val += 2; for (i = 0; i < 4; i++) { bzero(data, sizeof(data)); len = sizeof(data); val = get_string(val, ",", data, &len); if (val == NULL) exit(1); set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); } } else { bzero(data, sizeof(data)); len = sizeof(data); get_string(val, NULL, data, &len); txkey = 0; set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); bzero(data, sizeof(data)); for (i = 1; i < 4; i++) set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); } set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); } static void set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_RTSTHRESHOLD, isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL); } static void set80211protmode(const char *val, int d, int s, const struct afswtch *rafp) { int mode; if (strcasecmp(val, "off") == 0) { mode = IEEE80211_PROTMODE_OFF; } else if (strcasecmp(val, "cts") == 0) { mode = IEEE80211_PROTMODE_CTS; } else if (strncasecmp(val, "rtscts", 3) == 0) { mode = IEEE80211_PROTMODE_RTSCTS; } else { errx(1, "unknown protection mode"); } set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); } static void set80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp) { int mode; if (strcasecmp(val, "off") == 0) { mode = IEEE80211_PROTMODE_OFF; } else if (strncasecmp(val, "rts", 3) == 0) { mode = IEEE80211_PROTMODE_RTSCTS; } else { errx(1, "unknown protection mode"); } set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL); } static void set80211txpower(const char *val, int d, int s, const struct afswtch *rafp) { double v = atof(val); int txpow; txpow = (int) (2*v); if (txpow != 2*v) errx(-1, "invalid tx power (must be .5 dBm units)"); set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL); } #define IEEE80211_ROAMING_DEVICE 0 #define IEEE80211_ROAMING_AUTO 1 #define IEEE80211_ROAMING_MANUAL 2 static void set80211roaming(const char *val, int d, int s, const struct afswtch *rafp) { int mode; if (strcasecmp(val, "device") == 0) { mode = IEEE80211_ROAMING_DEVICE; } else if (strcasecmp(val, "auto") == 0) { mode = IEEE80211_ROAMING_AUTO; } else if (strcasecmp(val, "manual") == 0) { mode = IEEE80211_ROAMING_MANUAL; } else { errx(1, "unknown roaming mode"); } set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); } static void set80211wme(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_WME, d, 0, NULL); } static void set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); } static void set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); } static void set80211fastframes(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_FF, d, 0, NULL); } static void set80211dturbo(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL); } static void set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) { struct ieee80211req_chanlist chanlist; char *temp, *cp, *tp; temp = malloc(strlen(val) + 1); if (temp == NULL) errx(1, "malloc failed"); strcpy(temp, val); memset(&chanlist, 0, sizeof(chanlist)); cp = temp; for (;;) { int first, last, f, c; tp = strchr(cp, ','); if (tp != NULL) *tp++ = '\0'; switch (sscanf(cp, "%u-%u", &first, &last)) { case 1: if (first > IEEE80211_CHAN_MAX) errx(-1, "channel %u out of range, max %u", first, IEEE80211_CHAN_MAX); setbit(chanlist.ic_channels, first); break; case 2: if (first > IEEE80211_CHAN_MAX) errx(-1, "channel %u out of range, max %u", first, IEEE80211_CHAN_MAX); if (last > IEEE80211_CHAN_MAX) errx(-1, "channel %u out of range, max %u", last, IEEE80211_CHAN_MAX); if (first > last) errx(-1, "void channel range, %u > %u", first, last); for (f = first; f <= last; f++) setbit(chanlist.ic_channels, f); break; } if (tp == NULL) break; c = *tp; while (isspace(c)) tp++; if (!isdigit(c)) break; cp = tp; } set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist); } static void set80211bssid(const char *val, int d, int s, const struct afswtch *rafp) { if (!isanyarg(val)) { char *temp; struct sockaddr_dl sdl; temp = malloc(strlen(val) + 2); /* ':' and '\0' */ if (temp == NULL) errx(1, "malloc failed"); temp[0] = ':'; strcpy(temp + 1, val); sdl.sdl_len = sizeof(sdl); link_addr(temp, &sdl); free(temp); if (sdl.sdl_alen != IEEE80211_ADDR_LEN) errx(1, "malformed link-level address"); set80211(s, IEEE80211_IOC_BSSID, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); } else { uint8_t zerobssid[IEEE80211_ADDR_LEN]; memset(zerobssid, 0, sizeof(zerobssid)); set80211(s, IEEE80211_IOC_BSSID, 0, IEEE80211_ADDR_LEN, zerobssid); } } static int getac(const char *ac) { if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) return WME_AC_BE; if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) return WME_AC_BK; if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) return WME_AC_VI; if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) return WME_AC_VO; errx(1, "unknown wme access class %s", ac); } static DECL_CMD_FUNC2(set80211cwmin, ac, val) { set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); } static DECL_CMD_FUNC2(set80211cwmax, ac, val) { set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); } static DECL_CMD_FUNC2(set80211aifs, ac, val) { set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); } static DECL_CMD_FUNC2(set80211txoplimit, ac, val) { set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); } static DECL_CMD_FUNC(set80211acm, ac, d) { set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL); } static DECL_CMD_FUNC(set80211noacm, ac, d) { set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL); } static DECL_CMD_FUNC(set80211ackpolicy, ac, d) { set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL); } static DECL_CMD_FUNC(set80211noackpolicy, ac, d) { set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL); } static DECL_CMD_FUNC2(set80211bsscwmin, ac, val) { set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); } static DECL_CMD_FUNC2(set80211bsscwmax, ac, val) { set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); } static DECL_CMD_FUNC2(set80211bssaifs, ac, val) { set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); } static DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) { set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); } static DECL_CMD_FUNC(set80211dtimperiod, val, d) { set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211bintval, val, d) { set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); } static void set80211macmac(int s, int op, const char *val) { char *temp; struct sockaddr_dl sdl; temp = malloc(strlen(val) + 2); /* ':' and '\0' */ if (temp == NULL) errx(1, "malloc failed"); temp[0] = ':'; strcpy(temp + 1, val); sdl.sdl_len = sizeof(sdl); link_addr(temp, &sdl); free(temp); if (sdl.sdl_alen != IEEE80211_ADDR_LEN) errx(1, "malformed link-level address"); set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); } static DECL_CMD_FUNC(set80211addmac, val, d) { set80211macmac(s, IEEE80211_IOC_ADDMAC, val); } static DECL_CMD_FUNC(set80211delmac, val, d) { set80211macmac(s, IEEE80211_IOC_DELMAC, val); } static DECL_CMD_FUNC(set80211kickmac, val, d) { char *temp; struct sockaddr_dl sdl; struct ieee80211req_mlme mlme; temp = malloc(strlen(val) + 2); /* ':' and '\0' */ if (temp == NULL) errx(1, "malloc failed"); temp[0] = ':'; strcpy(temp + 1, val); sdl.sdl_len = sizeof(sdl); link_addr(temp, &sdl); free(temp); if (sdl.sdl_alen != IEEE80211_ADDR_LEN) errx(1, "malformed link-level address"); memset(&mlme, 0, sizeof(mlme)); mlme.im_op = IEEE80211_MLME_DEAUTH; mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN); set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme); } static DECL_CMD_FUNC(set80211maccmd, val, d) { set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); } static void set80211meshrtmac(int s, int req, const char *val) { char *temp; struct sockaddr_dl sdl; temp = malloc(strlen(val) + 2); /* ':' and '\0' */ if (temp == NULL) errx(1, "malloc failed"); temp[0] = ':'; strcpy(temp + 1, val); sdl.sdl_len = sizeof(sdl); link_addr(temp, &sdl); free(temp); if (sdl.sdl_alen != IEEE80211_ADDR_LEN) errx(1, "malformed link-level address"); set80211(s, IEEE80211_IOC_MESH_RTCMD, req, IEEE80211_ADDR_LEN, LLADDR(&sdl)); } static DECL_CMD_FUNC(set80211addmeshrt, val, d) { set80211meshrtmac(s, IEEE80211_MESH_RTCMD_ADD, val); } static DECL_CMD_FUNC(set80211delmeshrt, val, d) { set80211meshrtmac(s, IEEE80211_MESH_RTCMD_DELETE, val); } static DECL_CMD_FUNC(set80211meshrtcmd, val, d) { set80211(s, IEEE80211_IOC_MESH_RTCMD, d, 0, NULL); } static DECL_CMD_FUNC(set80211hwmprootmode, val, d) { int mode; if (strcasecmp(val, "normal") == 0) mode = IEEE80211_HWMP_ROOTMODE_NORMAL; else if (strcasecmp(val, "proactive") == 0) mode = IEEE80211_HWMP_ROOTMODE_PROACTIVE; else if (strcasecmp(val, "rann") == 0) mode = IEEE80211_HWMP_ROOTMODE_RANN; else mode = IEEE80211_HWMP_ROOTMODE_DISABLED; set80211(s, IEEE80211_IOC_HWMP_ROOTMODE, mode, 0, NULL); } static DECL_CMD_FUNC(set80211hwmpmaxhops, val, d) { set80211(s, IEEE80211_IOC_HWMP_MAXHOPS, atoi(val), 0, NULL); } static void set80211pureg(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL); } static void set80211quiet(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_QUIET, d, 0, NULL); } static DECL_CMD_FUNC(set80211quietperiod, val, d) { set80211(s, IEEE80211_IOC_QUIET_PERIOD, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211quietcount, val, d) { set80211(s, IEEE80211_IOC_QUIET_COUNT, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211quietduration, val, d) { set80211(s, IEEE80211_IOC_QUIET_DUR, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211quietoffset, val, d) { set80211(s, IEEE80211_IOC_QUIET_OFFSET, atoi(val), 0, NULL); } static void set80211bgscan(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL); } static DECL_CMD_FUNC(set80211bgscanidle, val, d) { set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211bgscanintvl, val, d) { set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211scanvalid, val, d) { set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL); } /* * Parse an optional trailing specification of which netbands * to apply a parameter to. This is basically the same syntax * as used for channels but you can concatenate to specify * multiple. For example: * 14:abg apply to 11a, 11b, and 11g * 6:ht apply to 11na and 11ng * We don't make a big effort to catch silly things; this is * really a convenience mechanism. */ static int getmodeflags(const char *val) { const char *cp; int flags; flags = 0; cp = strchr(val, ':'); if (cp != NULL) { for (cp++; isalpha((int) *cp); cp++) { /* accept mixed case */ int c = *cp; if (isupper(c)) c = tolower(c); switch (c) { case 'a': /* 802.11a */ flags |= IEEE80211_CHAN_A; break; case 'b': /* 802.11b */ flags |= IEEE80211_CHAN_B; break; case 'g': /* 802.11g */ flags |= IEEE80211_CHAN_G; break; case 'n': /* 802.11n */ flags |= IEEE80211_CHAN_HT; break; case 'd': /* dt = Atheros Dynamic Turbo */ flags |= IEEE80211_CHAN_TURBO; break; case 't': /* ht, dt, st, t */ /* dt and unadorned t specify Dynamic Turbo */ if ((flags & (IEEE80211_CHAN_STURBO|IEEE80211_CHAN_HT)) == 0) flags |= IEEE80211_CHAN_TURBO; break; case 's': /* st = Atheros Static Turbo */ flags |= IEEE80211_CHAN_STURBO; break; case 'h': /* 1/2-width channels */ flags |= IEEE80211_CHAN_HALF; break; case 'q': /* 1/4-width channels */ flags |= IEEE80211_CHAN_QUARTER; break; case 'v': /* XXX set HT too? */ flags |= IEEE80211_CHAN_VHT; break; default: errx(-1, "%s: Invalid mode attribute %c\n", val, *cp); } } } return flags; } #define IEEE80211_CHAN_HTA (IEEE80211_CHAN_HT|IEEE80211_CHAN_5GHZ) #define IEEE80211_CHAN_HTG (IEEE80211_CHAN_HT|IEEE80211_CHAN_2GHZ) #define _APPLY(_flags, _base, _param, _v) do { \ if (_flags & IEEE80211_CHAN_HT) { \ if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\ _base.params[IEEE80211_MODE_11NA]._param = _v; \ _base.params[IEEE80211_MODE_11NG]._param = _v; \ } else if (_flags & IEEE80211_CHAN_5GHZ) \ _base.params[IEEE80211_MODE_11NA]._param = _v; \ else \ _base.params[IEEE80211_MODE_11NG]._param = _v; \ } \ if (_flags & IEEE80211_CHAN_TURBO) { \ if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\ _base.params[IEEE80211_MODE_TURBO_A]._param = _v; \ _base.params[IEEE80211_MODE_TURBO_G]._param = _v; \ } else if (_flags & IEEE80211_CHAN_5GHZ) \ _base.params[IEEE80211_MODE_TURBO_A]._param = _v; \ else \ _base.params[IEEE80211_MODE_TURBO_G]._param = _v; \ } \ if (_flags & IEEE80211_CHAN_STURBO) \ _base.params[IEEE80211_MODE_STURBO_A]._param = _v; \ if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \ _base.params[IEEE80211_MODE_11A]._param = _v; \ if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \ _base.params[IEEE80211_MODE_11G]._param = _v; \ if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \ _base.params[IEEE80211_MODE_11B]._param = _v; \ if (_flags & IEEE80211_CHAN_HALF) \ _base.params[IEEE80211_MODE_HALF]._param = _v; \ if (_flags & IEEE80211_CHAN_QUARTER) \ _base.params[IEEE80211_MODE_QUARTER]._param = _v; \ } while (0) #define _APPLY1(_flags, _base, _param, _v) do { \ if (_flags & IEEE80211_CHAN_HT) { \ if (_flags & IEEE80211_CHAN_5GHZ) \ _base.params[IEEE80211_MODE_11NA]._param = _v; \ else \ _base.params[IEEE80211_MODE_11NG]._param = _v; \ } else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A) \ _base.params[IEEE80211_MODE_TURBO_A]._param = _v; \ else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) \ _base.params[IEEE80211_MODE_TURBO_G]._param = _v; \ else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST) \ _base.params[IEEE80211_MODE_STURBO_A]._param = _v; \ else if (_flags & IEEE80211_CHAN_HALF) \ _base.params[IEEE80211_MODE_HALF]._param = _v; \ else if (_flags & IEEE80211_CHAN_QUARTER) \ _base.params[IEEE80211_MODE_QUARTER]._param = _v; \ else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \ _base.params[IEEE80211_MODE_11A]._param = _v; \ else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \ _base.params[IEEE80211_MODE_11G]._param = _v; \ else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \ _base.params[IEEE80211_MODE_11B]._param = _v; \ } while (0) #define _APPLY_RATE(_flags, _base, _param, _v) do { \ if (_flags & IEEE80211_CHAN_HT) { \ (_v) = (_v / 2) | IEEE80211_RATE_MCS; \ } \ _APPLY(_flags, _base, _param, _v); \ } while (0) #define _APPLY_RATE1(_flags, _base, _param, _v) do { \ if (_flags & IEEE80211_CHAN_HT) { \ (_v) = (_v / 2) | IEEE80211_RATE_MCS; \ } \ _APPLY1(_flags, _base, _param, _v); \ } while (0) static DECL_CMD_FUNC(set80211roamrssi, val, d) { double v = atof(val); int rssi, flags; rssi = (int) (2*v); if (rssi != 2*v) errx(-1, "invalid rssi (must be .5 dBm units)"); flags = getmodeflags(val); getroam(s); if (flags == 0) { /* NB: no flags => current channel */ flags = getcurchan(s)->ic_flags; _APPLY1(flags, roamparams, rssi, rssi); } else _APPLY(flags, roamparams, rssi, rssi); callback_register(setroam_cb, &roamparams); } static int getrate(const char *val, const char *tag) { double v = atof(val); int rate; rate = (int) (2*v); if (rate != 2*v) errx(-1, "invalid %s rate (must be .5 Mb/s units)", tag); return rate; /* NB: returns 2x the specified value */ } static DECL_CMD_FUNC(set80211roamrate, val, d) { int rate, flags; rate = getrate(val, "roam"); flags = getmodeflags(val); getroam(s); if (flags == 0) { /* NB: no flags => current channel */ flags = getcurchan(s)->ic_flags; _APPLY_RATE1(flags, roamparams, rate, rate); } else _APPLY_RATE(flags, roamparams, rate, rate); callback_register(setroam_cb, &roamparams); } static DECL_CMD_FUNC(set80211mcastrate, val, d) { int rate, flags; rate = getrate(val, "mcast"); flags = getmodeflags(val); gettxparams(s); if (flags == 0) { /* NB: no flags => current channel */ flags = getcurchan(s)->ic_flags; _APPLY_RATE1(flags, txparams, mcastrate, rate); } else _APPLY_RATE(flags, txparams, mcastrate, rate); callback_register(settxparams_cb, &txparams); } static DECL_CMD_FUNC(set80211mgtrate, val, d) { int rate, flags; rate = getrate(val, "mgmt"); flags = getmodeflags(val); gettxparams(s); if (flags == 0) { /* NB: no flags => current channel */ flags = getcurchan(s)->ic_flags; _APPLY_RATE1(flags, txparams, mgmtrate, rate); } else _APPLY_RATE(flags, txparams, mgmtrate, rate); callback_register(settxparams_cb, &txparams); } static DECL_CMD_FUNC(set80211ucastrate, val, d) { int flags; gettxparams(s); flags = getmodeflags(val); if (isanyarg(val)) { if (flags == 0) { /* NB: no flags => current channel */ flags = getcurchan(s)->ic_flags; _APPLY1(flags, txparams, ucastrate, IEEE80211_FIXED_RATE_NONE); } else _APPLY(flags, txparams, ucastrate, IEEE80211_FIXED_RATE_NONE); } else { int rate = getrate(val, "ucast"); if (flags == 0) { /* NB: no flags => current channel */ flags = getcurchan(s)->ic_flags; _APPLY_RATE1(flags, txparams, ucastrate, rate); } else _APPLY_RATE(flags, txparams, ucastrate, rate); } callback_register(settxparams_cb, &txparams); } static DECL_CMD_FUNC(set80211maxretry, val, d) { int v = atoi(val), flags; flags = getmodeflags(val); gettxparams(s); if (flags == 0) { /* NB: no flags => current channel */ flags = getcurchan(s)->ic_flags; _APPLY1(flags, txparams, maxretry, v); } else _APPLY(flags, txparams, maxretry, v); callback_register(settxparams_cb, &txparams); } #undef _APPLY_RATE #undef _APPLY #undef IEEE80211_CHAN_HTA #undef IEEE80211_CHAN_HTG static DECL_CMD_FUNC(set80211fragthreshold, val, d) { set80211(s, IEEE80211_IOC_FRAGTHRESHOLD, isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211bmissthreshold, val, d) { set80211(s, IEEE80211_IOC_BMISSTHRESHOLD, isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL); } static void set80211burst(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_BURST, d, 0, NULL); } static void set80211doth(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL); } static void set80211dfs(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_DFS, d, 0, NULL); } static void set80211shortgi(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_SHORTGI, d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0, 0, NULL); } static void set80211ampdu(const char *val, int d, int s, const struct afswtch *rafp) { int ampdu; if (get80211val(s, IEEE80211_IOC_AMPDU, &du) < 0) errx(-1, "cannot set AMPDU setting"); if (d < 0) { d = -d; ampdu &= ~d; } else ampdu |= d; set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL); } static void set80211stbc(const char *val, int d, int s, const struct afswtch *rafp) { int stbc; if (get80211val(s, IEEE80211_IOC_STBC, &stbc) < 0) errx(-1, "cannot set STBC setting"); if (d < 0) { d = -d; stbc &= ~d; } else stbc |= d; set80211(s, IEEE80211_IOC_STBC, stbc, 0, NULL); } static void set80211ldpc(const char *val, int d, int s, const struct afswtch *rafp) { int ldpc; if (get80211val(s, IEEE80211_IOC_LDPC, &ldpc) < 0) errx(-1, "cannot set LDPC setting"); if (d < 0) { d = -d; ldpc &= ~d; } else ldpc |= d; set80211(s, IEEE80211_IOC_LDPC, ldpc, 0, NULL); } static DECL_CMD_FUNC(set80211ampdulimit, val, d) { int v; switch (atoi(val)) { case 8: case 8*1024: v = IEEE80211_HTCAP_MAXRXAMPDU_8K; break; case 16: case 16*1024: v = IEEE80211_HTCAP_MAXRXAMPDU_16K; break; case 32: case 32*1024: v = IEEE80211_HTCAP_MAXRXAMPDU_32K; break; case 64: case 64*1024: v = IEEE80211_HTCAP_MAXRXAMPDU_64K; break; default: errx(-1, "invalid A-MPDU limit %s", val); } set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL); } static DECL_CMD_FUNC(set80211ampdudensity, val, d) { int v; if (isanyarg(val) || strcasecmp(val, "na") == 0) v = IEEE80211_HTCAP_MPDUDENSITY_NA; else switch ((int)(atof(val)*4)) { case 0: v = IEEE80211_HTCAP_MPDUDENSITY_NA; break; case 1: v = IEEE80211_HTCAP_MPDUDENSITY_025; break; case 2: v = IEEE80211_HTCAP_MPDUDENSITY_05; break; case 4: v = IEEE80211_HTCAP_MPDUDENSITY_1; break; case 8: v = IEEE80211_HTCAP_MPDUDENSITY_2; break; case 16: v = IEEE80211_HTCAP_MPDUDENSITY_4; break; case 32: v = IEEE80211_HTCAP_MPDUDENSITY_8; break; case 64: v = IEEE80211_HTCAP_MPDUDENSITY_16; break; default: errx(-1, "invalid A-MPDU density %s", val); } set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL); } static void set80211amsdu(const char *val, int d, int s, const struct afswtch *rafp) { int amsdu; if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0) err(-1, "cannot get AMSDU setting"); if (d < 0) { d = -d; amsdu &= ~d; } else amsdu |= d; set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL); } static DECL_CMD_FUNC(set80211amsdulimit, val, d) { set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL); } static void set80211puren(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL); } static void set80211htcompat(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL); } static void set80211htconf(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL); htconf = d; } static void set80211dwds(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_DWDS, d, 0, NULL); } static void set80211inact(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL); } static void set80211tsn(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_TSN, d, 0, NULL); } static void set80211dotd(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_DOTD, d, 0, NULL); } static void set80211smps(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_SMPS, d, 0, NULL); } static void set80211rifs(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL); } static void set80211vhtconf(const char *val, int d, int s, const struct afswtch *rafp) { if (get80211val(s, IEEE80211_IOC_VHTCONF, &vhtconf) < 0) errx(-1, "cannot set VHT setting"); printf("%s: vhtconf=0x%08x, d=%d\n", __func__, vhtconf, d); if (d < 0) { d = -d; vhtconf &= ~d; } else vhtconf |= d; printf("%s: vhtconf is now 0x%08x\n", __func__, vhtconf); set80211(s, IEEE80211_IOC_VHTCONF, vhtconf, 0, NULL); } static DECL_CMD_FUNC(set80211tdmaslot, val, d) { set80211(s, IEEE80211_IOC_TDMA_SLOT, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211tdmaslotcnt, val, d) { set80211(s, IEEE80211_IOC_TDMA_SLOTCNT, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211tdmaslotlen, val, d) { set80211(s, IEEE80211_IOC_TDMA_SLOTLEN, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211tdmabintval, val, d) { set80211(s, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211meshttl, val, d) { set80211(s, IEEE80211_IOC_MESH_TTL, atoi(val), 0, NULL); } static DECL_CMD_FUNC(set80211meshforward, val, d) { set80211(s, IEEE80211_IOC_MESH_FWRD, d, 0, NULL); } static DECL_CMD_FUNC(set80211meshgate, val, d) { set80211(s, IEEE80211_IOC_MESH_GATE, d, 0, NULL); } static DECL_CMD_FUNC(set80211meshpeering, val, d) { set80211(s, IEEE80211_IOC_MESH_AP, d, 0, NULL); } static DECL_CMD_FUNC(set80211meshmetric, val, d) { char v[12]; memcpy(v, val, sizeof(v)); set80211(s, IEEE80211_IOC_MESH_PR_METRIC, 0, 0, v); } static DECL_CMD_FUNC(set80211meshpath, val, d) { char v[12]; memcpy(v, val, sizeof(v)); set80211(s, IEEE80211_IOC_MESH_PR_PATH, 0, 0, v); } static int regdomain_sort(const void *a, const void *b) { #define CHAN_ALL \ (IEEE80211_CHAN_ALLTURBO|IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER) const struct ieee80211_channel *ca = a; const struct ieee80211_channel *cb = b; return ca->ic_freq == cb->ic_freq ? (ca->ic_flags & CHAN_ALL) - (cb->ic_flags & CHAN_ALL) : ca->ic_freq - cb->ic_freq; #undef CHAN_ALL } static const struct ieee80211_channel * chanlookup(const struct ieee80211_channel chans[], int nchans, int freq, int flags) { int i; flags &= IEEE80211_CHAN_ALLTURBO; for (i = 0; i < nchans; i++) { const struct ieee80211_channel *c = &chans[i]; if (c->ic_freq == freq && (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) return c; } return NULL; } static int chanfind(const struct ieee80211_channel chans[], int nchans, int flags) { int i; for (i = 0; i < nchans; i++) { const struct ieee80211_channel *c = &chans[i]; if ((c->ic_flags & flags) == flags) return 1; } return 0; } /* * Check channel compatibility. */ static int checkchan(const struct ieee80211req_chaninfo *avail, int freq, int flags) { flags &= ~REQ_FLAGS; /* * Check if exact channel is in the calibration table; * everything below is to deal with channels that we * want to include but that are not explicitly listed. */ if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags) != NULL) return 1; if (flags & IEEE80211_CHAN_GSM) { /* * XXX GSM frequency mapping is handled in the kernel * so we cannot find them in the calibration table; * just accept the channel and the kernel will reject * the channel list if it's wrong. */ return 1; } /* * If this is a 1/2 or 1/4 width channel allow it if a full * width channel is present for this frequency, and the device * supports fractional channels on this band. This is a hack * that avoids bloating the calibration table; it may be better * by per-band attributes though (we are effectively calculating * this attribute by scanning the channel list ourself). */ if ((flags & (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == 0) return 0; if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags &~ (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == NULL) return 0; if (flags & IEEE80211_CHAN_HALF) { return chanfind(avail->ic_chans, avail->ic_nchans, IEEE80211_CHAN_HALF | (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ))); } else { return chanfind(avail->ic_chans, avail->ic_nchans, IEEE80211_CHAN_QUARTER | (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ))); } } static void regdomain_addchans(struct ieee80211req_chaninfo *ci, const netband_head *bands, const struct ieee80211_regdomain *reg, uint32_t chanFlags, const struct ieee80211req_chaninfo *avail) { const struct netband *nb; const struct freqband *b; struct ieee80211_channel *c, *prev; int freq, hi_adj, lo_adj, channelSep; uint32_t flags; hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0; lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0; channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40; LIST_FOREACH(nb, bands, next) { b = nb->band; if (verbose) { printf("%s:", __func__); printb(" chanFlags", chanFlags, IEEE80211_CHAN_BITS); printb(" bandFlags", nb->flags | b->flags, IEEE80211_CHAN_BITS); putchar('\n'); } prev = NULL; for (freq = b->freqStart + lo_adj; freq <= b->freqEnd + hi_adj; freq += b->chanSep) { /* * Construct flags for the new channel. We take * the attributes from the band descriptions except * for HT40 which is enabled generically (i.e. +/- * extension channel) in the band description and * then constrained according by channel separation. */ flags = nb->flags | b->flags; /* * VHT first - HT is a subset. * * XXX TODO: VHT80p80, VHT160 is not yet done. */ if (flags & IEEE80211_CHAN_VHT) { if ((chanFlags & IEEE80211_CHAN_VHT20) && (flags & IEEE80211_CHAN_VHT20) == 0) { if (verbose) printf("%u: skip, not a " "VHT20 channel\n", freq); continue; } if ((chanFlags & IEEE80211_CHAN_VHT40) && (flags & IEEE80211_CHAN_VHT40) == 0) { if (verbose) printf("%u: skip, not a " "VHT40 channel\n", freq); continue; } if ((chanFlags & IEEE80211_CHAN_VHT80) && (flags & IEEE80211_CHAN_VHT80) == 0) { if (verbose) printf("%u: skip, not a " "VHT80 channel\n", freq); continue; } flags &= ~IEEE80211_CHAN_VHT; flags |= chanFlags & IEEE80211_CHAN_VHT; } /* Now, constrain HT */ if (flags & IEEE80211_CHAN_HT) { /* * HT channels are generated specially; we're * called to add HT20, HT40+, and HT40- chan's * so we need to expand only band specs for * the HT channel type being added. */ if ((chanFlags & IEEE80211_CHAN_HT20) && (flags & IEEE80211_CHAN_HT20) == 0) { if (verbose) printf("%u: skip, not an " "HT20 channel\n", freq); continue; } if ((chanFlags & IEEE80211_CHAN_HT40) && (flags & IEEE80211_CHAN_HT40) == 0) { if (verbose) printf("%u: skip, not an " "HT40 channel\n", freq); continue; } /* NB: HT attribute comes from caller */ flags &= ~IEEE80211_CHAN_HT; flags |= chanFlags & IEEE80211_CHAN_HT; } /* * Check if device can operate on this frequency. */ if (!checkchan(avail, freq, flags)) { if (verbose) { printf("%u: skip, ", freq); printb("flags", flags, IEEE80211_CHAN_BITS); printf(" not available\n"); } continue; } if ((flags & REQ_ECM) && !reg->ecm) { if (verbose) printf("%u: skip, ECM channel\n", freq); continue; } if ((flags & REQ_INDOOR) && reg->location == 'O') { if (verbose) printf("%u: skip, indoor channel\n", freq); continue; } if ((flags & REQ_OUTDOOR) && reg->location == 'I') { if (verbose) printf("%u: skip, outdoor channel\n", freq); continue; } if ((flags & IEEE80211_CHAN_HT40) && prev != NULL && (freq - prev->ic_freq) < channelSep) { if (verbose) printf("%u: skip, only %u channel " "separation, need %d\n", freq, freq - prev->ic_freq, channelSep); continue; } if (ci->ic_nchans == IEEE80211_CHAN_MAX) { if (verbose) printf("%u: skip, channel table full\n", freq); break; } c = &ci->ic_chans[ci->ic_nchans++]; memset(c, 0, sizeof(*c)); c->ic_freq = freq; c->ic_flags = flags; if (c->ic_flags & IEEE80211_CHAN_DFS) c->ic_maxregpower = nb->maxPowerDFS; else c->ic_maxregpower = nb->maxPower; if (verbose) { printf("[%3d] add freq %u ", ci->ic_nchans-1, c->ic_freq); printb("flags", c->ic_flags, IEEE80211_CHAN_BITS); printf(" power %u\n", c->ic_maxregpower); } /* NB: kernel fills in other fields */ prev = c; } } } static void regdomain_makechannels( struct ieee80211_regdomain_req *req, const struct ieee80211_devcaps_req *dc) { struct regdata *rdp = getregdata(); const struct country *cc; const struct ieee80211_regdomain *reg = &req->rd; struct ieee80211req_chaninfo *ci = &req->chaninfo; const struct regdomain *rd; /* * Locate construction table for new channel list. We treat * the regdomain/SKU as definitive so a country can be in * multiple with different properties (e.g. US in FCC+FCC3). * If no regdomain is specified then we fallback on the country * code to find the associated regdomain since countries always * belong to at least one regdomain. */ if (reg->regdomain == 0) { cc = lib80211_country_findbycc(rdp, reg->country); if (cc == NULL) errx(1, "internal error, country %d not found", reg->country); rd = cc->rd; } else rd = lib80211_regdomain_findbysku(rdp, reg->regdomain); if (rd == NULL) errx(1, "internal error, regdomain %d not found", reg->regdomain); if (rd->sku != SKU_DEBUG) { /* * regdomain_addchans incrememnts the channel count for * each channel it adds so initialize ic_nchans to zero. * Note that we know we have enough space to hold all possible * channels because the devcaps list size was used to * allocate our request. */ ci->ic_nchans = 0; if (!LIST_EMPTY(&rd->bands_11b)) regdomain_addchans(ci, &rd->bands_11b, reg, IEEE80211_CHAN_B, &dc->dc_chaninfo); if (!LIST_EMPTY(&rd->bands_11g)) regdomain_addchans(ci, &rd->bands_11g, reg, IEEE80211_CHAN_G, &dc->dc_chaninfo); if (!LIST_EMPTY(&rd->bands_11a)) regdomain_addchans(ci, &rd->bands_11a, reg, IEEE80211_CHAN_A, &dc->dc_chaninfo); if (!LIST_EMPTY(&rd->bands_11na) && dc->dc_htcaps != 0) { regdomain_addchans(ci, &rd->bands_11na, reg, IEEE80211_CHAN_A | IEEE80211_CHAN_HT20, &dc->dc_chaninfo); if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) { regdomain_addchans(ci, &rd->bands_11na, reg, IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U, &dc->dc_chaninfo); regdomain_addchans(ci, &rd->bands_11na, reg, IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D, &dc->dc_chaninfo); } } if (!LIST_EMPTY(&rd->bands_11ac) && dc->dc_vhtcaps != 0) { regdomain_addchans(ci, &rd->bands_11ac, reg, IEEE80211_CHAN_A | IEEE80211_CHAN_HT20 | IEEE80211_CHAN_VHT20, &dc->dc_chaninfo); /* VHT40 is a function of HT40.. */ if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) { regdomain_addchans(ci, &rd->bands_11ac, reg, IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U | IEEE80211_CHAN_VHT40U, &dc->dc_chaninfo); regdomain_addchans(ci, &rd->bands_11ac, reg, IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D | IEEE80211_CHAN_VHT40D, &dc->dc_chaninfo); } /* VHT80 */ /* XXX dc_vhtcap? */ if (1) { regdomain_addchans(ci, &rd->bands_11ac, reg, IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U | IEEE80211_CHAN_VHT80, &dc->dc_chaninfo); regdomain_addchans(ci, &rd->bands_11ac, reg, IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D | IEEE80211_CHAN_VHT80, &dc->dc_chaninfo); } /* XXX TODO: VHT80_80, VHT160 */ } if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) { regdomain_addchans(ci, &rd->bands_11ng, reg, IEEE80211_CHAN_G | IEEE80211_CHAN_HT20, &dc->dc_chaninfo); if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) { regdomain_addchans(ci, &rd->bands_11ng, reg, IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U, &dc->dc_chaninfo); regdomain_addchans(ci, &rd->bands_11ng, reg, IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D, &dc->dc_chaninfo); } } qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]), regdomain_sort); } else memcpy(ci, &dc->dc_chaninfo, IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo)); } static void list_countries(void) { struct regdata *rdp = getregdata(); const struct country *cp; const struct regdomain *dp; int i; i = 0; printf("\nCountry codes:\n"); LIST_FOREACH(cp, &rdp->countries, next) { printf("%2s %-15.15s%s", cp->isoname, cp->name, ((i+1)%4) == 0 ? "\n" : " "); i++; } i = 0; printf("\nRegulatory domains:\n"); LIST_FOREACH(dp, &rdp->domains, next) { printf("%-15.15s%s", dp->name, ((i+1)%4) == 0 ? "\n" : " "); i++; } printf("\n"); } static void defaultcountry(const struct regdomain *rd) { struct regdata *rdp = getregdata(); const struct country *cc; cc = lib80211_country_findbycc(rdp, rd->cc->code); if (cc == NULL) errx(1, "internal error, ISO country code %d not " "defined for regdomain %s", rd->cc->code, rd->name); regdomain.country = cc->code; regdomain.isocc[0] = cc->isoname[0]; regdomain.isocc[1] = cc->isoname[1]; } static DECL_CMD_FUNC(set80211regdomain, val, d) { struct regdata *rdp = getregdata(); const struct regdomain *rd; rd = lib80211_regdomain_findbyname(rdp, val); if (rd == NULL) { char *eptr; long sku = strtol(val, &eptr, 0); if (eptr != val) rd = lib80211_regdomain_findbysku(rdp, sku); if (eptr == val || rd == NULL) errx(1, "unknown regdomain %s", val); } getregdomain(s); regdomain.regdomain = rd->sku; if (regdomain.country == 0 && rd->cc != NULL) { /* * No country code setup and there's a default * one for this regdomain fill it in. */ defaultcountry(rd); } callback_register(setregdomain_cb, ®domain); } static DECL_CMD_FUNC(set80211country, val, d) { struct regdata *rdp = getregdata(); const struct country *cc; cc = lib80211_country_findbyname(rdp, val); if (cc == NULL) { char *eptr; long code = strtol(val, &eptr, 0); if (eptr != val) cc = lib80211_country_findbycc(rdp, code); if (eptr == val || cc == NULL) errx(1, "unknown ISO country code %s", val); } getregdomain(s); regdomain.regdomain = cc->rd->sku; regdomain.country = cc->code; regdomain.isocc[0] = cc->isoname[0]; regdomain.isocc[1] = cc->isoname[1]; callback_register(setregdomain_cb, ®domain); } static void set80211location(const char *val, int d, int s, const struct afswtch *rafp) { getregdomain(s); regdomain.location = d; callback_register(setregdomain_cb, ®domain); } static void set80211ecm(const char *val, int d, int s, const struct afswtch *rafp) { getregdomain(s); regdomain.ecm = d; callback_register(setregdomain_cb, ®domain); } static void LINE_INIT(char c) { spacer = c; if (c == '\t') col = 8; else col = 1; } static void LINE_BREAK(void) { if (spacer != '\t') { printf("\n"); spacer = '\t'; } col = 8; /* 8-col tab */ } static void LINE_CHECK(const char *fmt, ...) { char buf[80]; va_list ap; int n; va_start(ap, fmt); n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap); va_end(ap); col += 1+n; if (col > MAXCOL) { LINE_BREAK(); col += n; } buf[0] = spacer; printf("%s", buf); spacer = ' '; } static int getmaxrate(const uint8_t rates[15], uint8_t nrates) { int i, maxrate = -1; for (i = 0; i < nrates; i++) { int rate = rates[i] & IEEE80211_RATE_VAL; if (rate > maxrate) maxrate = rate; } return maxrate / 2; } static const char * getcaps(int capinfo) { static char capstring[32]; char *cp = capstring; if (capinfo & IEEE80211_CAPINFO_ESS) *cp++ = 'E'; if (capinfo & IEEE80211_CAPINFO_IBSS) *cp++ = 'I'; if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) *cp++ = 'c'; if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) *cp++ = 'C'; if (capinfo & IEEE80211_CAPINFO_PRIVACY) *cp++ = 'P'; if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) *cp++ = 'S'; if (capinfo & IEEE80211_CAPINFO_PBCC) *cp++ = 'B'; if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) *cp++ = 'A'; if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) *cp++ = 's'; if (capinfo & IEEE80211_CAPINFO_RSN) *cp++ = 'R'; if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) *cp++ = 'D'; *cp = '\0'; return capstring; } static const char * getflags(int flags) { static char flagstring[32]; char *cp = flagstring; if (flags & IEEE80211_NODE_AUTH) *cp++ = 'A'; if (flags & IEEE80211_NODE_QOS) *cp++ = 'Q'; if (flags & IEEE80211_NODE_ERP) *cp++ = 'E'; if (flags & IEEE80211_NODE_PWR_MGT) *cp++ = 'P'; if (flags & IEEE80211_NODE_HT) { *cp++ = 'H'; if (flags & IEEE80211_NODE_HTCOMPAT) *cp++ = '+'; } if (flags & IEEE80211_NODE_VHT) *cp++ = 'V'; if (flags & IEEE80211_NODE_WPS) *cp++ = 'W'; if (flags & IEEE80211_NODE_TSN) *cp++ = 'N'; if (flags & IEEE80211_NODE_AMPDU_TX) *cp++ = 'T'; if (flags & IEEE80211_NODE_AMPDU_RX) *cp++ = 'R'; if (flags & IEEE80211_NODE_MIMO_PS) { *cp++ = 'M'; if (flags & IEEE80211_NODE_MIMO_RTS) *cp++ = '+'; } if (flags & IEEE80211_NODE_RIFS) *cp++ = 'I'; if (flags & IEEE80211_NODE_SGI40) { *cp++ = 'S'; if (flags & IEEE80211_NODE_SGI20) *cp++ = '+'; } else if (flags & IEEE80211_NODE_SGI20) *cp++ = 's'; if (flags & IEEE80211_NODE_AMSDU_TX) *cp++ = 't'; if (flags & IEEE80211_NODE_AMSDU_RX) *cp++ = 'r'; *cp = '\0'; return flagstring; } static void printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { maxlen -= strlen(tag)+2; if (2*ielen > maxlen) maxlen--; printf("<"); for (; ielen > 0; ie++, ielen--) { if (maxlen-- <= 0) break; printf("%02x", *ie); } if (ielen != 0) printf("-"); printf(">"); } } #define LE_READ_2(p) \ ((u_int16_t) \ ((((const u_int8_t *)(p))[0] ) | \ (((const u_int8_t *)(p))[1] << 8))) #define LE_READ_4(p) \ ((u_int32_t) \ ((((const u_int8_t *)(p))[0] ) | \ (((const u_int8_t *)(p))[1] << 8) | \ (((const u_int8_t *)(p))[2] << 16) | \ (((const u_int8_t *)(p))[3] << 24))) /* * NB: The decoding routines assume a properly formatted ie * which should be safe as the kernel only retains them * if they parse ok. */ static void printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { #define MS(_v, _f) (((_v) & _f) >> _f##_S) static const char *acnames[] = { "BE", "BK", "VO", "VI" }; const struct ieee80211_wme_param *wme = (const struct ieee80211_wme_param *) ie; int i; printf("%s", tag); if (!verbose) return; printf("param_qosInfo); ie += offsetof(struct ieee80211_wme_param, params_acParams); for (i = 0; i < WME_NUM_AC; i++) { const struct ieee80211_wme_acparams *ac = &wme->params_acParams[i]; printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]" , acnames[i] , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : "" , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN) , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN) , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX) , LE_READ_2(&ac->acp_txop) ); } printf(">"); #undef MS } static void printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const struct ieee80211_wme_info *wme = (const struct ieee80211_wme_info *) ie; printf("", wme->wme_version, wme->wme_info); } } static void printvhtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const struct ieee80211_ie_vhtcap *vhtcap = (const struct ieee80211_ie_vhtcap *) ie; uint32_t vhtcap_info = LE_READ_4(&vhtcap->vht_cap_info); printf("supp_mcs.rx_mcs_map)); printf(" rx_highest %d", LE_READ_2(&vhtcap->supp_mcs.rx_highest) & 0x1fff); printf(" tx_mcs_map 0x%x", LE_READ_2(&vhtcap->supp_mcs.tx_mcs_map)); printf(" tx_highest %d", LE_READ_2(&vhtcap->supp_mcs.tx_highest) & 0x1fff); printf(">"); } } static void printvhtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const struct ieee80211_ie_vht_operation *vhtinfo = (const struct ieee80211_ie_vht_operation *) ie; printf("", vhtinfo->chan_width, vhtinfo->center_freq_seg1_idx, vhtinfo->center_freq_seg2_idx, LE_READ_2(&vhtinfo->basic_mcs_set)); } } static void printvhtpwrenv(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); static const char *txpwrmap[] = { "20", "40", "80", "160", }; if (verbose) { const struct ieee80211_ie_vht_txpwrenv *vhtpwr = (const struct ieee80211_ie_vht_txpwrenv *) ie; int i, n; const char *sep = ""; /* Get count; trim at ielen */ n = (vhtpwr->tx_info & IEEE80211_VHT_TXPWRENV_INFO_COUNT_MASK) + 1; /* Trim at ielen */ if (n > ielen - 3) n = ielen - 3; printf("tx_info); for (i = 0; i < n; i++) { printf("%s%s:%.2f", sep, txpwrmap[i], ((float) ((int8_t) ie[i+3])) / 2.0); sep = " "; } printf("]>"); } } static void printhtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const struct ieee80211_ie_htcap *htcap = (const struct ieee80211_ie_htcap *) ie; const char *sep; int i, j; printf("hc_cap), htcap->hc_param); printf(" mcsset["); sep = ""; for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) if (isset(htcap->hc_mcsset, i)) { for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) if (isclr(htcap->hc_mcsset, j)) break; j--; if (i == j) printf("%s%u", sep, i); else printf("%s%u-%u", sep, i, j); i += j-i; sep = ","; } printf("] extcap 0x%x txbf 0x%x antenna 0x%x>", LE_READ_2(&htcap->hc_extcap), LE_READ_4(&htcap->hc_txbf), htcap->hc_antenna); } } static void printhtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const struct ieee80211_ie_htinfo *htinfo = (const struct ieee80211_ie_htinfo *) ie; const char *sep; int i, j; printf("hi_ctrlchannel, htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3, LE_READ_2(&htinfo->hi_byte45)); printf(" basicmcs["); sep = ""; for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) if (isset(htinfo->hi_basicmcsset, i)) { for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) if (isclr(htinfo->hi_basicmcsset, j)) break; j--; if (i == j) printf("%s%u", sep, i); else printf("%s%u-%u", sep, i, j); i += j-i; sep = ","; } printf("]>"); } } static void printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const struct ieee80211_ath_ie *ath = (const struct ieee80211_ath_ie *)ie; printf("<"); if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME) printf("DTURBO,"); if (ath->ath_capability & ATHEROS_CAP_COMPRESSION) printf("COMP,"); if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME) printf("FF,"); if (ath->ath_capability & ATHEROS_CAP_XR) printf("XR,"); if (ath->ath_capability & ATHEROS_CAP_AR) printf("AR,"); if (ath->ath_capability & ATHEROS_CAP_BURST) printf("BURST,"); if (ath->ath_capability & ATHEROS_CAP_WME) printf("WME,"); if (ath->ath_capability & ATHEROS_CAP_BOOST) printf("BOOST,"); printf("0x%x>", LE_READ_2(ath->ath_defkeyix)); } } static void printmeshconf(const char *tag, const uint8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const struct ieee80211_meshconf_ie *mconf = (const struct ieee80211_meshconf_ie *)ie; printf("conf_pselid == IEEE80211_MESHCONF_PATH_HWMP) printf("HWMP"); else printf("UNKNOWN"); printf(" LINK:"); if (mconf->conf_pmetid == IEEE80211_MESHCONF_METRIC_AIRTIME) printf("AIRTIME"); else printf("UNKNOWN"); printf(" CONGESTION:"); if (mconf->conf_ccid == IEEE80211_MESHCONF_CC_DISABLED) printf("DISABLED"); else printf("UNKNOWN"); printf(" SYNC:"); if (mconf->conf_syncid == IEEE80211_MESHCONF_SYNC_NEIGHOFF) printf("NEIGHOFF"); else printf("UNKNOWN"); printf(" AUTH:"); if (mconf->conf_authid == IEEE80211_MESHCONF_AUTH_DISABLED) printf("DISABLED"); else printf("UNKNOWN"); printf(" FORM:0x%x CAPS:0x%x>", mconf->conf_form, mconf->conf_cap); } } static void printbssload(const char *tag, const uint8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const struct ieee80211_bss_load_ie *bssload = (const struct ieee80211_bss_load_ie *) ie; printf("", LE_READ_2(&bssload->sta_count), bssload->chan_load, bssload->aac); } } static void printapchanrep(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const struct ieee80211_ap_chan_report_ie *ap = (const struct ieee80211_ap_chan_report_ie *) ie; const char *sep = ""; int i; printf("i_class); for (i = 3; i < ielen; i++) { printf("%s%u", sep, ie[i]); sep = ","; } printf("]>"); } } static const char * wpa_cipher(const u_int8_t *sel) { #define WPA_SEL(x) (((x)<<24)|WPA_OUI) u_int32_t w = LE_READ_4(sel); switch (w) { case WPA_SEL(WPA_CSE_NULL): return "NONE"; case WPA_SEL(WPA_CSE_WEP40): return "WEP40"; case WPA_SEL(WPA_CSE_WEP104): return "WEP104"; case WPA_SEL(WPA_CSE_TKIP): return "TKIP"; case WPA_SEL(WPA_CSE_CCMP): return "AES-CCMP"; } return "?"; /* NB: so 1<< is discarded */ #undef WPA_SEL } static const char * wpa_keymgmt(const u_int8_t *sel) { #define WPA_SEL(x) (((x)<<24)|WPA_OUI) u_int32_t w = LE_READ_4(sel); switch (w) { case WPA_SEL(WPA_ASE_8021X_UNSPEC): return "8021X-UNSPEC"; case WPA_SEL(WPA_ASE_8021X_PSK): return "8021X-PSK"; case WPA_SEL(WPA_ASE_NONE): return "NONE"; } return "?"; #undef WPA_SEL } static void printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { u_int8_t len = ie[1]; printf("%s", tag); if (verbose) { const char *sep; int n; ie += 6, len -= 4; /* NB: len is payload only */ printf(" 0; n--) { printf("%s%s", sep, wpa_cipher(ie)); ie += 4, len -= 4; sep = "+"; } /* key management algorithms */ n = LE_READ_2(ie); ie += 2, len -= 2; sep = " km:"; for (; n > 0; n--) { printf("%s%s", sep, wpa_keymgmt(ie)); ie += 4, len -= 4; sep = "+"; } if (len > 2) /* optional capabilities */ printf(", caps 0x%x", LE_READ_2(ie)); printf(">"); } } static const char * rsn_cipher(const u_int8_t *sel) { #define RSN_SEL(x) (((x)<<24)|RSN_OUI) u_int32_t w = LE_READ_4(sel); switch (w) { case RSN_SEL(RSN_CSE_NULL): return "NONE"; case RSN_SEL(RSN_CSE_WEP40): return "WEP40"; case RSN_SEL(RSN_CSE_WEP104): return "WEP104"; case RSN_SEL(RSN_CSE_TKIP): return "TKIP"; case RSN_SEL(RSN_CSE_CCMP): return "AES-CCMP"; case RSN_SEL(RSN_CSE_WRAP): return "AES-OCB"; } return "?"; #undef WPA_SEL } static const char * rsn_keymgmt(const u_int8_t *sel) { #define RSN_SEL(x) (((x)<<24)|RSN_OUI) u_int32_t w = LE_READ_4(sel); switch (w) { case RSN_SEL(RSN_ASE_8021X_UNSPEC): return "8021X-UNSPEC"; case RSN_SEL(RSN_ASE_8021X_PSK): return "8021X-PSK"; case RSN_SEL(RSN_ASE_NONE): return "NONE"; } return "?"; #undef RSN_SEL } static void printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose) { const char *sep; int n; ie += 2, ielen -= 2; printf(" 0; n--) { printf("%s%s", sep, rsn_cipher(ie)); ie += 4, ielen -= 4; sep = "+"; } /* key management algorithms */ n = LE_READ_2(ie); ie += 2, ielen -= 2; sep = " km:"; for (; n > 0; n--) { printf("%s%s", sep, rsn_keymgmt(ie)); ie += 4, ielen -= 4; sep = "+"; } if (ielen > 2) /* optional capabilities */ printf(", caps 0x%x", LE_READ_2(ie)); /* XXXPMKID */ printf(">"); } } /* XXX move to a public include file */ #define IEEE80211_WPS_DEV_PASS_ID 0x1012 #define IEEE80211_WPS_SELECTED_REG 0x1041 #define IEEE80211_WPS_SETUP_STATE 0x1044 #define IEEE80211_WPS_UUID_E 0x1047 #define IEEE80211_WPS_VERSION 0x104a #define BE_READ_2(p) \ ((u_int16_t) \ ((((const u_int8_t *)(p))[1] ) | \ (((const u_int8_t *)(p))[0] << 8))) static void printwpsie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { u_int8_t len = ie[1]; printf("%s", tag); if (verbose) { static const char *dev_pass_id[] = { "D", /* Default (PIN) */ "U", /* User-specified */ "M", /* Machine-specified */ "K", /* Rekey */ "P", /* PushButton */ "R" /* Registrar-specified */ }; int n; ie +=6, len -= 4; /* NB: len is payload only */ /* WPS IE in Beacon and Probe Resp frames have different fields */ printf("<"); while (len) { uint16_t tlv_type = BE_READ_2(ie); uint16_t tlv_len = BE_READ_2(ie + 2); ie += 4, len -= 4; switch (tlv_type) { case IEEE80211_WPS_VERSION: printf("v:%d.%d", *ie >> 4, *ie & 0xf); break; case IEEE80211_WPS_SETUP_STATE: /* Only 1 and 2 are valid */ if (*ie == 0 || *ie >= 3) printf(" state:B"); else printf(" st:%s", *ie == 1 ? "N" : "C"); break; case IEEE80211_WPS_SELECTED_REG: printf(" sel:%s", *ie ? "T" : "F"); break; case IEEE80211_WPS_DEV_PASS_ID: n = LE_READ_2(ie); if (n < nitems(dev_pass_id)) printf(" dpi:%s", dev_pass_id[n]); break; case IEEE80211_WPS_UUID_E: printf(" uuid-e:"); for (n = 0; n < (tlv_len - 1); n++) printf("%02x-", ie[n]); printf("%02x", ie[n]); break; } ie += tlv_len, len -= tlv_len; } printf(">"); } } static void printtdmaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { printf("%s", tag); if (verbose && ielen >= sizeof(struct ieee80211_tdma_param)) { const struct ieee80211_tdma_param *tdma = (const struct ieee80211_tdma_param *) ie; /* XXX tstamp */ printf("", tdma->tdma_version, tdma->tdma_slot, tdma->tdma_slotcnt, LE_READ_2(&tdma->tdma_slotlen), tdma->tdma_bintval, tdma->tdma_inuse[0]); } } /* * Copy the ssid string contents into buf, truncating to fit. If the * ssid is entirely printable then just copy intact. Otherwise convert * to hexadecimal. If the result is truncated then replace the last * three characters with "...". */ static int copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) { const u_int8_t *p; size_t maxlen; u_int i; if (essid_len > bufsize) maxlen = bufsize; else maxlen = essid_len; /* determine printable or not */ for (i = 0, p = essid; i < maxlen; i++, p++) { if (*p < ' ' || *p > 0x7e) break; } if (i != maxlen) { /* not printable, print as hex */ if (bufsize < 3) return 0; strlcpy(buf, "0x", bufsize); bufsize -= 2; p = essid; for (i = 0; i < maxlen && bufsize >= 2; i++) { sprintf(&buf[2+2*i], "%02x", p[i]); bufsize -= 2; } if (i != essid_len) memcpy(&buf[2+2*i-3], "...", 3); } else { /* printable, truncate as needed */ memcpy(buf, essid, maxlen); if (maxlen != essid_len) memcpy(&buf[maxlen-3], "...", 3); } return maxlen; } static void printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { char ssid[2*IEEE80211_NWID_LEN+1]; printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid); } static void printrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { const char *sep; int i; printf("%s", tag); sep = "<"; for (i = 2; i < ielen; i++) { printf("%s%s%d", sep, ie[i] & IEEE80211_RATE_BASIC ? "B" : "", ie[i] & IEEE80211_RATE_VAL); sep = ","; } printf(">"); } static void printcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { const struct ieee80211_country_ie *cie = (const struct ieee80211_country_ie *) ie; int i, nbands, schan, nchan; printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]); nbands = (cie->len - 3) / sizeof(cie->band[0]); for (i = 0; i < nbands; i++) { schan = cie->band[i].schan; nchan = cie->band[i].nchan; if (nchan != 1) printf(" %u-%u,%u", schan, schan + nchan-1, cie->band[i].maxtxpwr); else printf(" %u,%u", schan, cie->band[i].maxtxpwr); } printf(">"); } static __inline int iswpaoui(const u_int8_t *frm) { return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); } static __inline int iswmeinfo(const u_int8_t *frm) { return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && frm[6] == WME_INFO_OUI_SUBTYPE; } static __inline int iswmeparam(const u_int8_t *frm) { return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && frm[6] == WME_PARAM_OUI_SUBTYPE; } static __inline int isatherosoui(const u_int8_t *frm) { return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); } static __inline int istdmaoui(const uint8_t *frm) { return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI); } static __inline int iswpsoui(const uint8_t *frm) { return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI); } static const char * iename(int elemid) { switch (elemid) { case IEEE80211_ELEMID_FHPARMS: return " FHPARMS"; case IEEE80211_ELEMID_CFPARMS: return " CFPARMS"; case IEEE80211_ELEMID_TIM: return " TIM"; case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS"; case IEEE80211_ELEMID_BSSLOAD: return " BSSLOAD"; case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE"; case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR"; case IEEE80211_ELEMID_PWRCAP: return " PWRCAP"; case IEEE80211_ELEMID_TPCREQ: return " TPCREQ"; case IEEE80211_ELEMID_TPCREP: return " TPCREP"; case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN"; case IEEE80211_ELEMID_CSA: return " CSA"; case IEEE80211_ELEMID_MEASREQ: return " MEASREQ"; case IEEE80211_ELEMID_MEASREP: return " MEASREP"; case IEEE80211_ELEMID_QUIET: return " QUIET"; case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS"; case IEEE80211_ELEMID_TPC: return " TPC"; case IEEE80211_ELEMID_CCKM: return " CCKM"; } return " ???"; } static void printies(const u_int8_t *vp, int ielen, int maxcols) { while (ielen > 0) { switch (vp[0]) { case IEEE80211_ELEMID_SSID: if (verbose) printssid(" SSID", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_RATES: case IEEE80211_ELEMID_XRATES: if (verbose) printrates(vp[0] == IEEE80211_ELEMID_RATES ? " RATES" : " XRATES", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_DSPARMS: if (verbose) printf(" DSPARMS<%u>", vp[2]); break; case IEEE80211_ELEMID_COUNTRY: if (verbose) printcountry(" COUNTRY", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_ERP: if (verbose) printf(" ERP<0x%x>", vp[2]); break; case IEEE80211_ELEMID_VENDOR: if (iswpaoui(vp)) printwpaie(" WPA", vp, 2+vp[1], maxcols); else if (iswmeinfo(vp)) printwmeinfo(" WME", vp, 2+vp[1], maxcols); else if (iswmeparam(vp)) printwmeparam(" WME", vp, 2+vp[1], maxcols); else if (isatherosoui(vp)) printathie(" ATH", vp, 2+vp[1], maxcols); else if (iswpsoui(vp)) printwpsie(" WPS", vp, 2+vp[1], maxcols); else if (istdmaoui(vp)) printtdmaie(" TDMA", vp, 2+vp[1], maxcols); else if (verbose) printie(" VEN", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_RSN: printrsnie(" RSN", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_HTCAP: printhtcap(" HTCAP", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_HTINFO: if (verbose) printhtinfo(" HTINFO", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_MESHID: if (verbose) printssid(" MESHID", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_MESHCONF: printmeshconf(" MESHCONF", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_VHT_CAP: printvhtcap(" VHTCAP", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_VHT_OPMODE: printvhtinfo(" VHTOPMODE", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_VHT_PWR_ENV: printvhtpwrenv(" VHTPWRENV", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_BSSLOAD: printbssload(" BSSLOAD", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_APCHANREP: printapchanrep(" APCHANREP", vp, 2+vp[1], maxcols); break; default: if (verbose) printie(iename(vp[0]), vp, 2+vp[1], maxcols); break; } ielen -= 2+vp[1]; vp += 2+vp[1]; } } static void printmimo(const struct ieee80211_mimo_info *mi) { /* NB: don't muddy display unless there's something to show */ if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) { /* XXX ignore EVM for now */ printf(" (rssi %.1f:%.1f:%.1f nf %d:%d:%d)", mi->rssi[0] / 2.0, mi->rssi[1] / 2.0, mi->rssi[2] / 2.0, mi->noise[0], mi->noise[1], mi->noise[2]); } } static void list_scan(int s) { uint8_t buf[24*1024]; char ssid[IEEE80211_NWID_LEN+1]; const uint8_t *cp; int len, ssidmax, idlen; if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0) errx(1, "unable to get scan results"); if (len < sizeof(struct ieee80211req_scan_result)) return; getchaninfo(s); ssidmax = verbose ? IEEE80211_NWID_LEN : 14; printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n" , ssidmax, ssidmax, "SSID/MESH ID" , "BSSID" , "CHAN" , "RATE" , " S:N" , "INT" , "CAPS" ); cp = buf; do { const struct ieee80211req_scan_result *sr; const uint8_t *vp, *idp; sr = (const struct ieee80211req_scan_result *) cp; vp = cp + sr->isr_ie_off; if (sr->isr_meshid_len) { idp = vp + sr->isr_ssid_len; idlen = sr->isr_meshid_len; } else { idp = vp; idlen = sr->isr_ssid_len; } printf("%-*.*s %s %3d %3dM %4d:%-4d %4d %-4.4s" , ssidmax , copy_essid(ssid, ssidmax, idp, idlen) , ssid , ether_ntoa((const struct ether_addr *) sr->isr_bssid) , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) , getmaxrate(sr->isr_rates, sr->isr_nrates) , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise , sr->isr_intval , getcaps(sr->isr_capinfo) ); printies(vp + sr->isr_ssid_len + sr->isr_meshid_len, sr->isr_ie_len, 24); printf("\n"); cp += sr->isr_len, len -= sr->isr_len; } while (len >= sizeof(struct ieee80211req_scan_result)); } static void scan_and_wait(int s) { struct ieee80211_scan_req sr; struct ieee80211req ireq; int sroute; sroute = socket(PF_ROUTE, SOCK_RAW, 0); if (sroute < 0) { perror("socket(PF_ROUTE,SOCK_RAW)"); return; } (void) memset(&ireq, 0, sizeof(ireq)); (void) strlcpy(ireq.i_name, name, sizeof(ireq.i_name)); ireq.i_type = IEEE80211_IOC_SCAN_REQ; memset(&sr, 0, sizeof(sr)); sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_BGSCAN | IEEE80211_IOC_SCAN_NOPICK | IEEE80211_IOC_SCAN_ONCE; sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; sr.sr_nssid = 0; ireq.i_data = &sr; ireq.i_len = sizeof(sr); /* * NB: only root can trigger a scan so ignore errors. Also ignore * possible errors from net80211, even if no new scan could be * started there might still be a valid scan cache. */ if (ioctl(s, SIOCS80211, &ireq) == 0) { char buf[2048]; struct if_announcemsghdr *ifan; struct rt_msghdr *rtm; do { if (read(sroute, buf, sizeof(buf)) < 0) { perror("read(PF_ROUTE)"); break; } rtm = (struct rt_msghdr *) buf; if (rtm->rtm_version != RTM_VERSION) break; ifan = (struct if_announcemsghdr *) rtm; } while (rtm->rtm_type != RTM_IEEE80211 || ifan->ifan_what != RTM_IEEE80211_SCAN); } close(sroute); } static DECL_CMD_FUNC(set80211scan, val, d) { scan_and_wait(s); list_scan(s); } static enum ieee80211_opmode get80211opmode(int s); static int gettxseq(const struct ieee80211req_sta_info *si) { int i, txseq; if ((si->isi_state & IEEE80211_NODE_QOS) == 0) return si->isi_txseqs[0]; /* XXX not right but usually what folks want */ txseq = 0; for (i = 0; i < IEEE80211_TID_SIZE; i++) if (si->isi_txseqs[i] > txseq) txseq = si->isi_txseqs[i]; return txseq; } static int getrxseq(const struct ieee80211req_sta_info *si) { int i, rxseq; if ((si->isi_state & IEEE80211_NODE_QOS) == 0) return si->isi_rxseqs[0]; /* XXX not right but usually what folks want */ rxseq = 0; for (i = 0; i < IEEE80211_TID_SIZE; i++) if (si->isi_rxseqs[i] > rxseq) rxseq = si->isi_rxseqs[i]; return rxseq; } static void list_stations(int s) { union { struct ieee80211req_sta_req req; uint8_t buf[24*1024]; } u; enum ieee80211_opmode opmode = get80211opmode(s); const uint8_t *cp; int len; /* broadcast address =>'s get all stations */ (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); if (opmode == IEEE80211_M_STA) { /* * Get information about the associated AP. */ (void) get80211(s, IEEE80211_IOC_BSSID, u.req.is_u.macaddr, IEEE80211_ADDR_LEN); } if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0) errx(1, "unable to get station information"); if (len < sizeof(struct ieee80211req_sta_info)) return; getchaninfo(s); if (opmode == IEEE80211_M_MBSS) printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n" , "ADDR" , "CHAN" , "LOCAL" , "PEER" , "STATE" , "RATE" , "RSSI" , "IDLE" , "TXSEQ" , "RXSEQ" ); else printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n" , "ADDR" , "AID" , "CHAN" , "RATE" , "RSSI" , "IDLE" , "TXSEQ" , "RXSEQ" , "CAPS" , "FLAG" ); cp = (const uint8_t *) u.req.info; do { const struct ieee80211req_sta_info *si; si = (const struct ieee80211req_sta_info *) cp; if (si->isi_len < sizeof(*si)) break; if (opmode == IEEE80211_M_MBSS) printf("%s %4d %5x %5x %7.7s %3dM %4.1f %4d %6d %6d" , ether_ntoa((const struct ether_addr*) si->isi_macaddr) , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags) , si->isi_localid , si->isi_peerid , mesh_linkstate_string(si->isi_peerstate) , si->isi_txmbps/2 , si->isi_rssi/2. , si->isi_inact , gettxseq(si) , getrxseq(si) ); else printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-7.7s" , ether_ntoa((const struct ether_addr*) si->isi_macaddr) , IEEE80211_AID(si->isi_associd) , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags) , si->isi_txmbps/2 , si->isi_rssi/2. , si->isi_inact , gettxseq(si) , getrxseq(si) , getcaps(si->isi_capinfo) , getflags(si->isi_state) ); printies(cp + si->isi_ie_off, si->isi_ie_len, 24); printmimo(&si->isi_mimo); printf("\n"); cp += si->isi_len, len -= si->isi_len; } while (len >= sizeof(struct ieee80211req_sta_info)); } static const char * mesh_linkstate_string(uint8_t state) { static const char *state_names[] = { [0] = "IDLE", [1] = "OPEN-TX", [2] = "OPEN-RX", [3] = "CONF-RX", [4] = "ESTAB", [5] = "HOLDING", }; if (state >= nitems(state_names)) { static char buf[10]; snprintf(buf, sizeof(buf), "#%u", state); return buf; } else return state_names[state]; } static const char * get_chaninfo(const struct ieee80211_channel *c, int precise, char buf[], size_t bsize) { buf[0] = '\0'; if (IEEE80211_IS_CHAN_FHSS(c)) strlcat(buf, " FHSS", bsize); if (IEEE80211_IS_CHAN_A(c)) strlcat(buf, " 11a", bsize); else if (IEEE80211_IS_CHAN_ANYG(c)) strlcat(buf, " 11g", bsize); else if (IEEE80211_IS_CHAN_B(c)) strlcat(buf, " 11b", bsize); if (IEEE80211_IS_CHAN_HALF(c)) strlcat(buf, "/10MHz", bsize); if (IEEE80211_IS_CHAN_QUARTER(c)) strlcat(buf, "/5MHz", bsize); if (IEEE80211_IS_CHAN_TURBO(c)) strlcat(buf, " Turbo", bsize); if (precise) { /* XXX should make VHT80U, VHT80D */ if (IEEE80211_IS_CHAN_VHT80(c) && IEEE80211_IS_CHAN_HT40D(c)) strlcat(buf, " vht/80-", bsize); else if (IEEE80211_IS_CHAN_VHT80(c) && IEEE80211_IS_CHAN_HT40U(c)) strlcat(buf, " vht/80+", bsize); else if (IEEE80211_IS_CHAN_VHT80(c)) strlcat(buf, " vht/80", bsize); else if (IEEE80211_IS_CHAN_VHT40D(c)) strlcat(buf, " vht/40-", bsize); else if (IEEE80211_IS_CHAN_VHT40U(c)) strlcat(buf, " vht/40+", bsize); else if (IEEE80211_IS_CHAN_VHT20(c)) strlcat(buf, " vht/20", bsize); else if (IEEE80211_IS_CHAN_HT20(c)) strlcat(buf, " ht/20", bsize); else if (IEEE80211_IS_CHAN_HT40D(c)) strlcat(buf, " ht/40-", bsize); else if (IEEE80211_IS_CHAN_HT40U(c)) strlcat(buf, " ht/40+", bsize); } else { if (IEEE80211_IS_CHAN_VHT(c)) strlcat(buf, " vht", bsize); else if (IEEE80211_IS_CHAN_HT(c)) strlcat(buf, " ht", bsize); } return buf; } static void print_chaninfo(const struct ieee80211_channel *c, int verb) { char buf[14]; if (verb) printf("Channel %3u : %u%c%c%c%c%c MHz%-14.14s", ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', IEEE80211_IS_CHAN_DFS(c) ? 'D' : ' ', IEEE80211_IS_CHAN_RADAR(c) ? 'R' : ' ', IEEE80211_IS_CHAN_CWINT(c) ? 'I' : ' ', IEEE80211_IS_CHAN_CACDONE(c) ? 'C' : ' ', get_chaninfo(c, verb, buf, sizeof(buf))); else printf("Channel %3u : %u%c MHz%-14.14s", ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', get_chaninfo(c, verb, buf, sizeof(buf))); } static int chanpref(const struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_VHT160(c)) return 80; if (IEEE80211_IS_CHAN_VHT80_80(c)) return 75; if (IEEE80211_IS_CHAN_VHT80(c)) return 70; if (IEEE80211_IS_CHAN_VHT40(c)) return 60; if (IEEE80211_IS_CHAN_VHT20(c)) return 50; if (IEEE80211_IS_CHAN_HT40(c)) return 40; if (IEEE80211_IS_CHAN_HT20(c)) return 30; if (IEEE80211_IS_CHAN_HALF(c)) return 10; if (IEEE80211_IS_CHAN_QUARTER(c)) return 5; if (IEEE80211_IS_CHAN_TURBO(c)) return 25; if (IEEE80211_IS_CHAN_A(c)) return 20; if (IEEE80211_IS_CHAN_G(c)) return 20; if (IEEE80211_IS_CHAN_B(c)) return 15; if (IEEE80211_IS_CHAN_PUREG(c)) return 15; return 0; } static void print_channels(int s, const struct ieee80211req_chaninfo *chans, int allchans, int verb) { struct ieee80211req_chaninfo *achans; uint8_t reported[IEEE80211_CHAN_BYTES]; const struct ieee80211_channel *c; int i, half; achans = malloc(IEEE80211_CHANINFO_SPACE(chans)); if (achans == NULL) errx(1, "no space for active channel list"); achans->ic_nchans = 0; memset(reported, 0, sizeof(reported)); if (!allchans) { struct ieee80211req_chanlist active; if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0) errx(1, "unable to get active channel list"); for (i = 0; i < chans->ic_nchans; i++) { c = &chans->ic_chans[i]; if (!isset(active.ic_channels, c->ic_ieee)) continue; /* * Suppress compatible duplicates unless * verbose. The kernel gives us it's * complete channel list which has separate * entries for 11g/11b and 11a/turbo. */ if (isset(reported, c->ic_ieee) && !verb) { /* XXX we assume duplicates are adjacent */ achans->ic_chans[achans->ic_nchans-1] = *c; } else { achans->ic_chans[achans->ic_nchans++] = *c; setbit(reported, c->ic_ieee); } } } else { for (i = 0; i < chans->ic_nchans; i++) { c = &chans->ic_chans[i]; /* suppress duplicates as above */ if (isset(reported, c->ic_ieee) && !verb) { /* XXX we assume duplicates are adjacent */ struct ieee80211_channel *a = &achans->ic_chans[achans->ic_nchans-1]; if (chanpref(c) > chanpref(a)) *a = *c; } else { achans->ic_chans[achans->ic_nchans++] = *c; setbit(reported, c->ic_ieee); } } } half = achans->ic_nchans / 2; if (achans->ic_nchans % 2) half++; for (i = 0; i < achans->ic_nchans / 2; i++) { print_chaninfo(&achans->ic_chans[i], verb); print_chaninfo(&achans->ic_chans[half+i], verb); printf("\n"); } if (achans->ic_nchans % 2) { print_chaninfo(&achans->ic_chans[i], verb); printf("\n"); } free(achans); } static void list_channels(int s, int allchans) { getchaninfo(s); print_channels(s, chaninfo, allchans, verbose); } static void print_txpow(const struct ieee80211_channel *c) { printf("Channel %3u : %u MHz %3.1f reg %2d ", c->ic_ieee, c->ic_freq, c->ic_maxpower/2., c->ic_maxregpower); } static void print_txpow_verbose(const struct ieee80211_channel *c) { print_chaninfo(c, 1); printf("min %4.1f dBm max %3.1f dBm reg %2d dBm", c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower); /* indicate where regulatory cap limits power use */ if (c->ic_maxpower > 2*c->ic_maxregpower) printf(" <"); } static void list_txpow(int s) { struct ieee80211req_chaninfo *achans; uint8_t reported[IEEE80211_CHAN_BYTES]; struct ieee80211_channel *c, *prev; int i, half; getchaninfo(s); achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo)); if (achans == NULL) errx(1, "no space for active channel list"); achans->ic_nchans = 0; memset(reported, 0, sizeof(reported)); for (i = 0; i < chaninfo->ic_nchans; i++) { c = &chaninfo->ic_chans[i]; /* suppress duplicates as above */ if (isset(reported, c->ic_ieee) && !verbose) { /* XXX we assume duplicates are adjacent */ assert(achans->ic_nchans > 0); prev = &achans->ic_chans[achans->ic_nchans-1]; /* display highest power on channel */ if (c->ic_maxpower > prev->ic_maxpower) *prev = *c; } else { achans->ic_chans[achans->ic_nchans++] = *c; setbit(reported, c->ic_ieee); } } if (!verbose) { half = achans->ic_nchans / 2; if (achans->ic_nchans % 2) half++; for (i = 0; i < achans->ic_nchans / 2; i++) { print_txpow(&achans->ic_chans[i]); print_txpow(&achans->ic_chans[half+i]); printf("\n"); } if (achans->ic_nchans % 2) { print_txpow(&achans->ic_chans[i]); printf("\n"); } } else { for (i = 0; i < achans->ic_nchans; i++) { print_txpow_verbose(&achans->ic_chans[i]); printf("\n"); } } free(achans); } static void list_keys(int s) { } static void list_capabilities(int s) { struct ieee80211_devcaps_req *dc; if (verbose) dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN)); else dc = malloc(IEEE80211_DEVCAPS_SIZE(1)); if (dc == NULL) errx(1, "no space for device capabilities"); dc->dc_chaninfo.ic_nchans = verbose ? MAXCHAN : 1; getdevcaps(s, dc); printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS); if (dc->dc_cryptocaps != 0 || verbose) { putchar('\n'); printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS); } if (dc->dc_htcaps != 0 || verbose) { putchar('\n'); printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS); } if (dc->dc_vhtcaps != 0 || verbose) { putchar('\n'); printb("vhtcaps", dc->dc_vhtcaps, IEEE80211_VHTCAP_BITS); } putchar('\n'); if (verbose) { chaninfo = &dc->dc_chaninfo; /* XXX */ print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, verbose); } free(dc); } static int get80211wme(int s, int param, int ac, int *val) { struct ieee80211req ireq; (void) memset(&ireq, 0, sizeof(ireq)); (void) strlcpy(ireq.i_name, name, sizeof(ireq.i_name)); ireq.i_type = param; ireq.i_len = ac; if (ioctl(s, SIOCG80211, &ireq) < 0) { warn("cannot get WME parameter %d, ac %d%s", param, ac & IEEE80211_WMEPARAM_VAL, ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : ""); return -1; } *val = ireq.i_val; return 0; } static void list_wme_aci(int s, const char *tag, int ac) { int val; printf("\t%s", tag); /* show WME BSS parameters */ if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1) printf(" cwmin %2u", val); if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1) printf(" cwmax %2u", val); if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1) printf(" aifs %2u", val); if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1) printf(" txopLimit %3u", val); if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) { if (val) printf(" acm"); else if (verbose) printf(" -acm"); } /* !BSS only */ if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) { if (!val) printf(" -ack"); else if (verbose) printf(" ack"); } } printf("\n"); } static void list_wme(int s) { static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; int ac; if (verbose) { /* display both BSS and local settings */ for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { again: if (ac & IEEE80211_WMEPARAM_BSS) list_wme_aci(s, " ", ac); else list_wme_aci(s, acnames[ac], ac); if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { ac |= IEEE80211_WMEPARAM_BSS; goto again; } else ac &= ~IEEE80211_WMEPARAM_BSS; } } else { /* display only channel settings */ for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) list_wme_aci(s, acnames[ac], ac); } } static void list_roam(int s) { const struct ieee80211_roamparam *rp; int mode; getroam(s); for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) { rp = &roamparams.params[mode]; if (rp->rssi == 0 && rp->rate == 0) continue; if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) { if (rp->rssi & 1) LINE_CHECK("roam:%-7.7s rssi %2u.5dBm MCS %2u ", modename[mode], rp->rssi/2, rp->rate &~ IEEE80211_RATE_MCS); else LINE_CHECK("roam:%-7.7s rssi %4udBm MCS %2u ", modename[mode], rp->rssi/2, rp->rate &~ IEEE80211_RATE_MCS); } else { if (rp->rssi & 1) LINE_CHECK("roam:%-7.7s rssi %2u.5dBm rate %2u Mb/s", modename[mode], rp->rssi/2, rp->rate/2); else LINE_CHECK("roam:%-7.7s rssi %4udBm rate %2u Mb/s", modename[mode], rp->rssi/2, rp->rate/2); } } } static void list_txparams(int s) { const struct ieee80211_txparam *tp; int mode; gettxparams(s); for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) { tp = &txparams.params[mode]; if (tp->mgmtrate == 0 && tp->mcastrate == 0) continue; if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) { if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) LINE_CHECK("%-7.7s ucast NONE mgmt %2u MCS " "mcast %2u MCS maxretry %u", modename[mode], tp->mgmtrate &~ IEEE80211_RATE_MCS, tp->mcastrate &~ IEEE80211_RATE_MCS, tp->maxretry); else LINE_CHECK("%-7.7s ucast %2u MCS mgmt %2u MCS " "mcast %2u MCS maxretry %u", modename[mode], tp->ucastrate &~ IEEE80211_RATE_MCS, tp->mgmtrate &~ IEEE80211_RATE_MCS, tp->mcastrate &~ IEEE80211_RATE_MCS, tp->maxretry); } else { if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) LINE_CHECK("%-7.7s ucast NONE mgmt %2u Mb/s " "mcast %2u Mb/s maxretry %u", modename[mode], tp->mgmtrate/2, tp->mcastrate/2, tp->maxretry); else LINE_CHECK("%-7.7s ucast %2u Mb/s mgmt %2u Mb/s " "mcast %2u Mb/s maxretry %u", modename[mode], tp->ucastrate/2, tp->mgmtrate/2, tp->mcastrate/2, tp->maxretry); } } } static void printpolicy(int policy) { switch (policy) { case IEEE80211_MACCMD_POLICY_OPEN: printf("policy: open\n"); break; case IEEE80211_MACCMD_POLICY_ALLOW: printf("policy: allow\n"); break; case IEEE80211_MACCMD_POLICY_DENY: printf("policy: deny\n"); break; case IEEE80211_MACCMD_POLICY_RADIUS: printf("policy: radius\n"); break; default: printf("policy: unknown (%u)\n", policy); break; } } static void list_mac(int s) { struct ieee80211req ireq; struct ieee80211req_maclist *acllist; int i, nacls, policy, len; uint8_t *data; char c; (void) memset(&ireq, 0, sizeof(ireq)); (void) strlcpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ ireq.i_type = IEEE80211_IOC_MACCMD; ireq.i_val = IEEE80211_MACCMD_POLICY; if (ioctl(s, SIOCG80211, &ireq) < 0) { if (errno == EINVAL) { printf("No acl policy loaded\n"); return; } err(1, "unable to get mac policy"); } policy = ireq.i_val; if (policy == IEEE80211_MACCMD_POLICY_OPEN) { c = '*'; } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { c = '+'; } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { c = '-'; } else if (policy == IEEE80211_MACCMD_POLICY_RADIUS) { c = 'r'; /* NB: should never have entries */ } else { printf("policy: unknown (%u)\n", policy); c = '?'; } if (verbose || c == '?') printpolicy(policy); ireq.i_val = IEEE80211_MACCMD_LIST; ireq.i_len = 0; if (ioctl(s, SIOCG80211, &ireq) < 0) err(1, "unable to get mac acl list size"); if (ireq.i_len == 0) { /* NB: no acls */ if (!(verbose || c == '?')) printpolicy(policy); return; } len = ireq.i_len; data = malloc(len); if (data == NULL) err(1, "out of memory for acl list"); ireq.i_data = data; if (ioctl(s, SIOCG80211, &ireq) < 0) err(1, "unable to get mac acl list"); nacls = len / sizeof(*acllist); acllist = (struct ieee80211req_maclist *) data; for (i = 0; i < nacls; i++) printf("%c%s\n", c, ether_ntoa( (const struct ether_addr *) acllist[i].ml_macaddr)); free(data); } static void print_regdomain(const struct ieee80211_regdomain *reg, int verb) { if ((reg->regdomain != 0 && reg->regdomain != reg->country) || verb) { const struct regdomain *rd = lib80211_regdomain_findbysku(getregdata(), reg->regdomain); if (rd == NULL) LINE_CHECK("regdomain %d", reg->regdomain); else LINE_CHECK("regdomain %s", rd->name); } if (reg->country != 0 || verb) { const struct country *cc = lib80211_country_findbycc(getregdata(), reg->country); if (cc == NULL) LINE_CHECK("country %d", reg->country); else LINE_CHECK("country %s", cc->isoname); } if (reg->location == 'I') LINE_CHECK("indoor"); else if (reg->location == 'O') LINE_CHECK("outdoor"); else if (verb) LINE_CHECK("anywhere"); if (reg->ecm) LINE_CHECK("ecm"); else if (verb) LINE_CHECK("-ecm"); } static void list_regdomain(int s, int channelsalso) { getregdomain(s); if (channelsalso) { getchaninfo(s); spacer = ':'; print_regdomain(®domain, 1); LINE_BREAK(); print_channels(s, chaninfo, 1/*allchans*/, 1/*verbose*/); } else print_regdomain(®domain, verbose); } static void list_mesh(int s) { struct ieee80211req ireq; struct ieee80211req_mesh_route routes[128]; struct ieee80211req_mesh_route *rt; (void) memset(&ireq, 0, sizeof(ireq)); (void) strlcpy(ireq.i_name, name, sizeof(ireq.i_name)); ireq.i_type = IEEE80211_IOC_MESH_RTCMD; ireq.i_val = IEEE80211_MESH_RTCMD_LIST; ireq.i_data = &routes; ireq.i_len = sizeof(routes); if (ioctl(s, SIOCG80211, &ireq) < 0) err(1, "unable to get the Mesh routing table"); printf("%-17.17s %-17.17s %4s %4s %4s %6s %s\n" , "DEST" , "NEXT HOP" , "HOPS" , "METRIC" , "LIFETIME" , "MSEQ" , "FLAGS"); for (rt = &routes[0]; rt - &routes[0] < ireq.i_len / sizeof(*rt); rt++){ printf("%s ", ether_ntoa((const struct ether_addr *)rt->imr_dest)); printf("%s %4u %4u %6u %6u %c%c\n", ether_ntoa((const struct ether_addr *)rt->imr_nexthop), rt->imr_nhops, rt->imr_metric, rt->imr_lifetime, rt->imr_lastmseq, (rt->imr_flags & IEEE80211_MESHRT_FLAGS_DISCOVER) ? 'D' : (rt->imr_flags & IEEE80211_MESHRT_FLAGS_VALID) ? 'V' : '!', (rt->imr_flags & IEEE80211_MESHRT_FLAGS_PROXY) ? 'P' : (rt->imr_flags & IEEE80211_MESHRT_FLAGS_GATE) ? 'G' :' '); } } static DECL_CMD_FUNC(set80211list, arg, d) { #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) LINE_INIT('\t'); if (iseq(arg, "sta")) list_stations(s); else if (iseq(arg, "scan") || iseq(arg, "ap")) list_scan(s); else if (iseq(arg, "chan") || iseq(arg, "freq")) list_channels(s, 1); else if (iseq(arg, "active")) list_channels(s, 0); else if (iseq(arg, "keys")) list_keys(s); else if (iseq(arg, "caps")) list_capabilities(s); else if (iseq(arg, "wme") || iseq(arg, "wmm")) list_wme(s); else if (iseq(arg, "mac")) list_mac(s); else if (iseq(arg, "txpow")) list_txpow(s); else if (iseq(arg, "roam")) list_roam(s); else if (iseq(arg, "txparam") || iseq(arg, "txparm")) list_txparams(s); else if (iseq(arg, "regdomain")) list_regdomain(s, 1); else if (iseq(arg, "countries")) list_countries(); else if (iseq(arg, "mesh")) list_mesh(s); else errx(1, "Don't know how to list %s for %s", arg, name); LINE_BREAK(); #undef iseq } static enum ieee80211_opmode get80211opmode(int s) { struct ifmediareq ifmr; (void) memset(&ifmr, 0, sizeof(ifmr)); (void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) { if (ifmr.ifm_current & IFM_FLAG0) return IEEE80211_M_AHDEMO; else return IEEE80211_M_IBSS; } if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) return IEEE80211_M_HOSTAP; if (ifmr.ifm_current & IFM_IEEE80211_IBSS) return IEEE80211_M_IBSS; if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) return IEEE80211_M_MONITOR; if (ifmr.ifm_current & IFM_IEEE80211_MBSS) return IEEE80211_M_MBSS; } return IEEE80211_M_STA; } #if 0 static void printcipher(int s, struct ieee80211req *ireq, int keylenop) { switch (ireq->i_val) { case IEEE80211_CIPHER_WEP: ireq->i_type = keylenop; if (ioctl(s, SIOCG80211, ireq) != -1) printf("WEP-%s", ireq->i_len <= 5 ? "40" : ireq->i_len <= 13 ? "104" : "128"); else printf("WEP"); break; case IEEE80211_CIPHER_TKIP: printf("TKIP"); break; case IEEE80211_CIPHER_AES_OCB: printf("AES-OCB"); break; case IEEE80211_CIPHER_AES_CCM: printf("AES-CCM"); break; case IEEE80211_CIPHER_CKIP: printf("CKIP"); break; case IEEE80211_CIPHER_NONE: printf("NONE"); break; default: printf("UNKNOWN (0x%x)", ireq->i_val); break; } } #endif static void printkey(const struct ieee80211req_key *ik) { static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; u_int keylen = ik->ik_keylen; int printcontents; printcontents = printkeys && (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); if (printcontents) LINE_BREAK(); switch (ik->ik_type) { case IEEE80211_CIPHER_WEP: /* compatibility */ LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1, keylen <= 5 ? "40-bit" : keylen <= 13 ? "104-bit" : "128-bit"); break; case IEEE80211_CIPHER_TKIP: if (keylen > 128/8) keylen -= 128/8; /* ignore MIC for now */ LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); break; case IEEE80211_CIPHER_AES_OCB: LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen); break; case IEEE80211_CIPHER_AES_CCM: LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen); break; case IEEE80211_CIPHER_CKIP: LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); break; case IEEE80211_CIPHER_NONE: LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen); break; default: LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit", ik->ik_type, ik->ik_keyix+1, 8*keylen); break; } if (printcontents) { u_int i; printf(" <"); for (i = 0; i < keylen; i++) printf("%02x", ik->ik_keydata[i]); printf(">"); if (ik->ik_type != IEEE80211_CIPHER_WEP && (ik->ik_keyrsc != 0 || verbose)) printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); if (ik->ik_type != IEEE80211_CIPHER_WEP && (ik->ik_keytsc != 0 || verbose)) printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); if (ik->ik_flags != 0 && verbose) { const char *sep = " "; if (ik->ik_flags & IEEE80211_KEY_XMIT) printf("%stx", sep), sep = "+"; if (ik->ik_flags & IEEE80211_KEY_RECV) printf("%srx", sep), sep = "+"; if (ik->ik_flags & IEEE80211_KEY_DEFAULT) printf("%sdef", sep), sep = "+"; } LINE_BREAK(); } } static void printrate(const char *tag, int v, int defrate, int defmcs) { if ((v & IEEE80211_RATE_MCS) == 0) { if (v != defrate) { if (v & 1) LINE_CHECK("%s %d.5", tag, v/2); else LINE_CHECK("%s %d", tag, v/2); } } else { if (v != defmcs) LINE_CHECK("%s %d", tag, v &~ 0x80); } } static int getid(int s, int ix, void *data, size_t len, int *plen, int mesh) { struct ieee80211req ireq; (void) memset(&ireq, 0, sizeof(ireq)); (void) strlcpy(ireq.i_name, name, sizeof(ireq.i_name)); ireq.i_type = (!mesh) ? IEEE80211_IOC_SSID : IEEE80211_IOC_MESH_ID; ireq.i_val = ix; ireq.i_data = data; ireq.i_len = len; if (ioctl(s, SIOCG80211, &ireq) < 0) return -1; *plen = ireq.i_len; return 0; } static void ieee80211_status(int s) { static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; enum ieee80211_opmode opmode = get80211opmode(s); int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode; uint8_t data[32]; const struct ieee80211_channel *c; const struct ieee80211_roamparam *rp; const struct ieee80211_txparam *tp; if (getid(s, -1, data, sizeof(data), &len, 0) < 0) { /* If we can't get the SSID, this isn't an 802.11 device. */ return; } /* * Invalidate cached state so printing status for multiple * if's doesn't reuse the first interfaces' cached state. */ gotcurchan = 0; gotroam = 0; gottxparams = 0; gothtconf = 0; gotregdomain = 0; printf("\t"); if (opmode == IEEE80211_M_MBSS) { printf("meshid "); getid(s, 0, data, sizeof(data), &len, 1); print_string(data, len); } else { if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0) num = 0; printf("ssid "); if (num > 1) { for (i = 0; i < num; i++) { if (getid(s, i, data, sizeof(data), &len, 0) >= 0 && len > 0) { printf(" %d:", i + 1); print_string(data, len); } } } else print_string(data, len); } c = getcurchan(s); if (c->ic_freq != IEEE80211_CHAN_ANY) { char buf[14]; printf(" channel %d (%u MHz%s)", c->ic_ieee, c->ic_freq, get_chaninfo(c, 1, buf, sizeof(buf))); } else if (verbose) printf(" channel UNDEF"); if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 && (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) printf(" bssid %s", ether_ntoa((struct ether_addr *)data)); if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) { printf("\n\tstationname "); print_string(data, len); } spacer = ' '; /* force first break */ LINE_BREAK(); list_regdomain(s, 0); wpa = 0; if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) { switch (val) { case IEEE80211_AUTH_NONE: LINE_CHECK("authmode NONE"); break; case IEEE80211_AUTH_OPEN: LINE_CHECK("authmode OPEN"); break; case IEEE80211_AUTH_SHARED: LINE_CHECK("authmode SHARED"); break; case IEEE80211_AUTH_8021X: LINE_CHECK("authmode 802.1x"); break; case IEEE80211_AUTH_WPA: if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0) wpa = 1; /* default to WPA1 */ switch (wpa) { case 2: LINE_CHECK("authmode WPA2/802.11i"); break; case 3: LINE_CHECK("authmode WPA1+WPA2/802.11i"); break; default: LINE_CHECK("authmode WPA"); break; } break; case IEEE80211_AUTH_AUTO: LINE_CHECK("authmode AUTO"); break; default: LINE_CHECK("authmode UNKNOWN (0x%x)", val); break; } } if (wpa || verbose) { if (get80211val(s, IEEE80211_IOC_WPS, &val) != -1) { if (val) LINE_CHECK("wps"); else if (verbose) LINE_CHECK("-wps"); } if (get80211val(s, IEEE80211_IOC_TSN, &val) != -1) { if (val) LINE_CHECK("tsn"); else if (verbose) LINE_CHECK("-tsn"); } if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) { if (val) LINE_CHECK("countermeasures"); else if (verbose) LINE_CHECK("-countermeasures"); } #if 0 /* XXX not interesting with WPA done in user space */ ireq.i_type = IEEE80211_IOC_KEYMGTALGS; if (ioctl(s, SIOCG80211, &ireq) != -1) { } ireq.i_type = IEEE80211_IOC_MCASTCIPHER; if (ioctl(s, SIOCG80211, &ireq) != -1) { LINE_CHECK("mcastcipher "); printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); spacer = ' '; } ireq.i_type = IEEE80211_IOC_UCASTCIPHER; if (ioctl(s, SIOCG80211, &ireq) != -1) { LINE_CHECK("ucastcipher "); printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); } if (wpa & 2) { ireq.i_type = IEEE80211_IOC_RSNCAPS; if (ioctl(s, SIOCG80211, &ireq) != -1) { LINE_CHECK("RSN caps 0x%x", ireq.i_val); spacer = ' '; } } ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; if (ioctl(s, SIOCG80211, &ireq) != -1) { } #endif } if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 && wepmode != IEEE80211_WEP_NOSUP) { switch (wepmode) { case IEEE80211_WEP_OFF: LINE_CHECK("privacy OFF"); break; case IEEE80211_WEP_ON: LINE_CHECK("privacy ON"); break; case IEEE80211_WEP_MIXED: LINE_CHECK("privacy MIXED"); break; default: LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); break; } /* * If we get here then we've got WEP support so we need * to print WEP status. */ if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) { warn("WEP support, but no tx key!"); goto end; } if (val != -1) LINE_CHECK("deftxkey %d", val+1); else if (wepmode != IEEE80211_WEP_OFF || verbose) LINE_CHECK("deftxkey UNDEF"); if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) { warn("WEP support, but no NUMWEPKEYS support!"); goto end; } for (i = 0; i < num; i++) { struct ieee80211req_key ik; memset(&ik, 0, sizeof(ik)); ik.ik_keyix = i; if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) { warn("WEP support, but can get keys!"); goto end; } if (ik.ik_keylen != 0) { if (verbose) LINE_BREAK(); printkey(&ik); } } end: ; } if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 && val != IEEE80211_POWERSAVE_NOSUP ) { if (val != IEEE80211_POWERSAVE_OFF || verbose) { switch (val) { case IEEE80211_POWERSAVE_OFF: LINE_CHECK("powersavemode OFF"); break; case IEEE80211_POWERSAVE_CAM: LINE_CHECK("powersavemode CAM"); break; case IEEE80211_POWERSAVE_PSP: LINE_CHECK("powersavemode PSP"); break; case IEEE80211_POWERSAVE_PSP_CAM: LINE_CHECK("powersavemode PSP-CAM"); break; } if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1) LINE_CHECK("powersavesleep %d", val); } } if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) { if (val & 1) LINE_CHECK("txpower %d.5", val/2); else LINE_CHECK("txpower %d", val/2); } if (verbose) { if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1) LINE_CHECK("txpowmax %.1f", val/2.); } if (get80211val(s, IEEE80211_IOC_DOTD, &val) != -1) { if (val) LINE_CHECK("dotd"); else if (verbose) LINE_CHECK("-dotd"); } if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) { if (val != IEEE80211_RTS_MAX || verbose) LINE_CHECK("rtsthreshold %d", val); } if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) { if (val != IEEE80211_FRAG_MAX || verbose) LINE_CHECK("fragthreshold %d", val); } if (opmode == IEEE80211_M_STA || verbose) { if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) { if (val != IEEE80211_HWBMISS_MAX || verbose) LINE_CHECK("bmiss %d", val); } } if (!verbose) { gettxparams(s); tp = &txparams.params[chan2mode(c)]; printrate("ucastrate", tp->ucastrate, IEEE80211_FIXED_RATE_NONE, IEEE80211_FIXED_RATE_NONE); printrate("mcastrate", tp->mcastrate, 2*1, IEEE80211_RATE_MCS|0); printrate("mgmtrate", tp->mgmtrate, 2*1, IEEE80211_RATE_MCS|0); if (tp->maxretry != 6) /* XXX */ LINE_CHECK("maxretry %d", tp->maxretry); } else { LINE_BREAK(); list_txparams(s); } bgscaninterval = -1; (void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval); if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) { if (val != bgscaninterval || verbose) LINE_CHECK("scanvalid %u", val); } bgscan = 0; if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) { if (bgscan) LINE_CHECK("bgscan"); else if (verbose) LINE_CHECK("-bgscan"); } if (bgscan || verbose) { if (bgscaninterval != -1) LINE_CHECK("bgscanintvl %u", bgscaninterval); if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1) LINE_CHECK("bgscanidle %u", val); if (!verbose) { getroam(s); rp = &roamparams.params[chan2mode(c)]; if (rp->rssi & 1) LINE_CHECK("roam:rssi %u.5", rp->rssi/2); else LINE_CHECK("roam:rssi %u", rp->rssi/2); LINE_CHECK("roam:rate %u", rp->rate/2); } else { LINE_BREAK(); list_roam(s); LINE_BREAK(); } } if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) { if (val) LINE_CHECK("pureg"); else if (verbose) LINE_CHECK("-pureg"); } if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) { switch (val) { case IEEE80211_PROTMODE_OFF: LINE_CHECK("protmode OFF"); break; case IEEE80211_PROTMODE_CTS: LINE_CHECK("protmode CTS"); break; case IEEE80211_PROTMODE_RTSCTS: LINE_CHECK("protmode RTSCTS"); break; default: LINE_CHECK("protmode UNKNOWN (0x%x)", val); break; } } } if (IEEE80211_IS_CHAN_HT(c) || verbose) { gethtconf(s); switch (htconf & 3) { case 0: case 2: LINE_CHECK("-ht"); break; case 1: LINE_CHECK("ht20"); break; case 3: if (verbose) LINE_CHECK("ht"); break; } if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) { if (!val) LINE_CHECK("-htcompat"); else if (verbose) LINE_CHECK("htcompat"); } if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) { switch (val) { case 0: LINE_CHECK("-ampdu"); break; case 1: LINE_CHECK("ampdutx -ampdurx"); break; case 2: LINE_CHECK("-ampdutx ampdurx"); break; case 3: if (verbose) LINE_CHECK("ampdu"); break; } } if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) { switch (val) { case IEEE80211_HTCAP_MAXRXAMPDU_8K: LINE_CHECK("ampdulimit 8k"); break; case IEEE80211_HTCAP_MAXRXAMPDU_16K: LINE_CHECK("ampdulimit 16k"); break; case IEEE80211_HTCAP_MAXRXAMPDU_32K: LINE_CHECK("ampdulimit 32k"); break; case IEEE80211_HTCAP_MAXRXAMPDU_64K: LINE_CHECK("ampdulimit 64k"); break; } } if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) { switch (val) { case IEEE80211_HTCAP_MPDUDENSITY_NA: if (verbose) LINE_CHECK("ampdudensity NA"); break; case IEEE80211_HTCAP_MPDUDENSITY_025: LINE_CHECK("ampdudensity .25"); break; case IEEE80211_HTCAP_MPDUDENSITY_05: LINE_CHECK("ampdudensity .5"); break; case IEEE80211_HTCAP_MPDUDENSITY_1: LINE_CHECK("ampdudensity 1"); break; case IEEE80211_HTCAP_MPDUDENSITY_2: LINE_CHECK("ampdudensity 2"); break; case IEEE80211_HTCAP_MPDUDENSITY_4: LINE_CHECK("ampdudensity 4"); break; case IEEE80211_HTCAP_MPDUDENSITY_8: LINE_CHECK("ampdudensity 8"); break; case IEEE80211_HTCAP_MPDUDENSITY_16: LINE_CHECK("ampdudensity 16"); break; } } if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) { switch (val) { case 0: LINE_CHECK("-amsdu"); break; case 1: LINE_CHECK("amsdutx -amsdurx"); break; case 2: LINE_CHECK("-amsdutx amsdurx"); break; case 3: if (verbose) LINE_CHECK("amsdu"); break; } } /* XXX amsdu limit */ if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) { if (val) LINE_CHECK("shortgi"); else if (verbose) LINE_CHECK("-shortgi"); } if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) { if (val == IEEE80211_PROTMODE_OFF) LINE_CHECK("htprotmode OFF"); else if (val != IEEE80211_PROTMODE_RTSCTS) LINE_CHECK("htprotmode UNKNOWN (0x%x)", val); else if (verbose) LINE_CHECK("htprotmode RTSCTS"); } if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) { if (val) LINE_CHECK("puren"); else if (verbose) LINE_CHECK("-puren"); } if (get80211val(s, IEEE80211_IOC_SMPS, &val) != -1) { if (val == IEEE80211_HTCAP_SMPS_DYNAMIC) LINE_CHECK("smpsdyn"); else if (val == IEEE80211_HTCAP_SMPS_ENA) LINE_CHECK("smps"); else if (verbose) LINE_CHECK("-smps"); } if (get80211val(s, IEEE80211_IOC_RIFS, &val) != -1) { if (val) LINE_CHECK("rifs"); else if (verbose) LINE_CHECK("-rifs"); } if (get80211val(s, IEEE80211_IOC_STBC, &val) != -1) { switch (val) { case 0: LINE_CHECK("-stbc"); break; case 1: LINE_CHECK("stbctx -stbcrx"); break; case 2: LINE_CHECK("-stbctx stbcrx"); break; case 3: if (verbose) LINE_CHECK("stbc"); break; } } if (get80211val(s, IEEE80211_IOC_LDPC, &val) != -1) { switch (val) { case 0: LINE_CHECK("-ldpc"); break; case 1: LINE_CHECK("ldpctx -ldpcrx"); break; case 2: LINE_CHECK("-ldpctx ldpcrx"); break; case 3: if (verbose) LINE_CHECK("ldpc"); break; } } } if (IEEE80211_IS_CHAN_VHT(c) || verbose) { getvhtconf(s); if (vhtconf & 0x1) LINE_CHECK("vht"); else LINE_CHECK("-vht"); if (vhtconf & 0x2) LINE_CHECK("vht40"); else LINE_CHECK("-vht40"); if (vhtconf & 0x4) LINE_CHECK("vht80"); else LINE_CHECK("-vht80"); if (vhtconf & 0x8) LINE_CHECK("vht80p80"); else LINE_CHECK("-vht80p80"); if (vhtconf & 0x10) LINE_CHECK("vht160"); else LINE_CHECK("-vht160"); } if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) { if (wme) LINE_CHECK("wme"); else if (verbose) LINE_CHECK("-wme"); } else wme = 0; if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) { if (val) LINE_CHECK("burst"); else if (verbose) LINE_CHECK("-burst"); } if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) { if (val) LINE_CHECK("ff"); else if (verbose) LINE_CHECK("-ff"); } if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) { if (val) LINE_CHECK("dturbo"); else if (verbose) LINE_CHECK("-dturbo"); } if (get80211val(s, IEEE80211_IOC_DWDS, &val) != -1) { if (val) LINE_CHECK("dwds"); else if (verbose) LINE_CHECK("-dwds"); } if (opmode == IEEE80211_M_HOSTAP) { if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) { if (val) LINE_CHECK("hidessid"); else if (verbose) LINE_CHECK("-hidessid"); } if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) { if (!val) LINE_CHECK("-apbridge"); else if (verbose) LINE_CHECK("apbridge"); } if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1) LINE_CHECK("dtimperiod %u", val); if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) { if (!val) LINE_CHECK("-doth"); else if (verbose) LINE_CHECK("doth"); } if (get80211val(s, IEEE80211_IOC_DFS, &val) != -1) { if (!val) LINE_CHECK("-dfs"); else if (verbose) LINE_CHECK("dfs"); } if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) { if (!val) LINE_CHECK("-inact"); else if (verbose) LINE_CHECK("inact"); } } else { if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) { if (val != IEEE80211_ROAMING_AUTO || verbose) { switch (val) { case IEEE80211_ROAMING_DEVICE: LINE_CHECK("roaming DEVICE"); break; case IEEE80211_ROAMING_AUTO: LINE_CHECK("roaming AUTO"); break; case IEEE80211_ROAMING_MANUAL: LINE_CHECK("roaming MANUAL"); break; default: LINE_CHECK("roaming UNKNOWN (0x%x)", val); break; } } } } if (opmode == IEEE80211_M_AHDEMO) { if (get80211val(s, IEEE80211_IOC_TDMA_SLOT, &val) != -1) LINE_CHECK("tdmaslot %u", val); if (get80211val(s, IEEE80211_IOC_TDMA_SLOTCNT, &val) != -1) LINE_CHECK("tdmaslotcnt %u", val); if (get80211val(s, IEEE80211_IOC_TDMA_SLOTLEN, &val) != -1) LINE_CHECK("tdmaslotlen %u", val); if (get80211val(s, IEEE80211_IOC_TDMA_BINTERVAL, &val) != -1) LINE_CHECK("tdmabintval %u", val); } else if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) { /* XXX default define not visible */ if (val != 100 || verbose) LINE_CHECK("bintval %u", val); } if (wme && verbose) { LINE_BREAK(); list_wme(s); } if (opmode == IEEE80211_M_MBSS) { if (get80211val(s, IEEE80211_IOC_MESH_TTL, &val) != -1) { LINE_CHECK("meshttl %u", val); } if (get80211val(s, IEEE80211_IOC_MESH_AP, &val) != -1) { if (val) LINE_CHECK("meshpeering"); else LINE_CHECK("-meshpeering"); } if (get80211val(s, IEEE80211_IOC_MESH_FWRD, &val) != -1) { if (val) LINE_CHECK("meshforward"); else LINE_CHECK("-meshforward"); } if (get80211val(s, IEEE80211_IOC_MESH_GATE, &val) != -1) { if (val) LINE_CHECK("meshgate"); else LINE_CHECK("-meshgate"); } if (get80211len(s, IEEE80211_IOC_MESH_PR_METRIC, data, 12, &len) != -1) { data[len] = '\0'; LINE_CHECK("meshmetric %s", data); } if (get80211len(s, IEEE80211_IOC_MESH_PR_PATH, data, 12, &len) != -1) { data[len] = '\0'; LINE_CHECK("meshpath %s", data); } if (get80211val(s, IEEE80211_IOC_HWMP_ROOTMODE, &val) != -1) { switch (val) { case IEEE80211_HWMP_ROOTMODE_DISABLED: LINE_CHECK("hwmprootmode DISABLED"); break; case IEEE80211_HWMP_ROOTMODE_NORMAL: LINE_CHECK("hwmprootmode NORMAL"); break; case IEEE80211_HWMP_ROOTMODE_PROACTIVE: LINE_CHECK("hwmprootmode PROACTIVE"); break; case IEEE80211_HWMP_ROOTMODE_RANN: LINE_CHECK("hwmprootmode RANN"); break; default: LINE_CHECK("hwmprootmode UNKNOWN(%d)", val); break; } } if (get80211val(s, IEEE80211_IOC_HWMP_MAXHOPS, &val) != -1) { LINE_CHECK("hwmpmaxhops %u", val); } } LINE_BREAK(); } static int get80211(int s, int type, void *data, int len) { return (lib80211_get80211(s, name, type, data, len)); } static int get80211len(int s, int type, void *data, int len, int *plen) { return (lib80211_get80211len(s, name, type, data, len, plen)); } static int get80211val(int s, int type, int *val) { return (lib80211_get80211val(s, name, type, val)); } static void set80211(int s, int type, int val, int len, void *data) { int ret; ret = lib80211_set80211(s, name, type, val, len, data); if (ret < 0) err(1, "SIOCS80211"); } static const char * get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) { int len; int hexstr; u_int8_t *p; len = *lenp; p = buf; hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); if (hexstr) val += 2; for (;;) { if (*val == '\0') break; if (sep != NULL && strchr(sep, *val) != NULL) { val++; break; } if (hexstr) { if (!isxdigit((u_char)val[0])) { warnx("bad hexadecimal digits"); return NULL; } if (!isxdigit((u_char)val[1])) { warnx("odd count hexadecimal digits"); return NULL; } } if (p >= buf + len) { if (hexstr) warnx("hexadecimal digits too long"); else warnx("string too long"); return NULL; } if (hexstr) { #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) *p++ = (tohex((u_char)val[0]) << 4) | tohex((u_char)val[1]); #undef tohex val += 2; } else *p++ = *val++; } len = p - buf; /* The string "-" is treated as the empty string. */ if (!hexstr && len == 1 && buf[0] == '-') { len = 0; memset(buf, 0, *lenp); } else if (len < *lenp) memset(p, 0, *lenp - len); *lenp = len; return val; } static void print_string(const u_int8_t *buf, int len) { int i; int hasspc; i = 0; hasspc = 0; for (; i < len; i++) { if (!isprint(buf[i]) && buf[i] != '\0') break; if (isspace(buf[i])) hasspc++; } if (i == len) { if (hasspc || len == 0 || buf[0] == '\0') printf("\"%.*s\"", len, buf); else printf("%.*s", len, buf); } else { printf("0x"); for (i = 0; i < len; i++) printf("%02x", buf[i]); } } static void setdefregdomain(int s) { struct regdata *rdp = getregdata(); const struct regdomain *rd; /* Check if regdomain/country was already set by a previous call. */ /* XXX is it possible? */ if (regdomain.regdomain != 0 || regdomain.country != CTRY_DEFAULT) return; getregdomain(s); /* Check if it was already set by the driver. */ if (regdomain.regdomain != 0 || regdomain.country != CTRY_DEFAULT) return; /* Set FCC/US as default. */ rd = lib80211_regdomain_findbysku(rdp, SKU_FCC); if (rd == NULL) errx(1, "FCC regdomain was not found"); regdomain.regdomain = rd->sku; if (rd->cc != NULL) defaultcountry(rd); /* Send changes to net80211. */ setregdomain_cb(s, ®domain); /* Cleanup (so it can be overriden by subsequent parameters). */ regdomain.regdomain = 0; regdomain.country = CTRY_DEFAULT; regdomain.isocc[0] = 0; regdomain.isocc[1] = 0; } /* * Virtual AP cloning support. */ static struct ieee80211_clone_params params = { .icp_opmode = IEEE80211_M_STA, /* default to station mode */ }; static void wlan_create(int s, struct ifreq *ifr) { static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; char orig_name[IFNAMSIZ]; if (params.icp_parent[0] == '\0') errx(1, "must specify a parent device (wlandev) when creating " "a wlan device"); if (params.icp_opmode == IEEE80211_M_WDS && memcmp(params.icp_bssid, zerobssid, sizeof(zerobssid)) == 0) errx(1, "no bssid specified for WDS (use wlanbssid)"); ifr->ifr_data = (caddr_t) ¶ms; if (ioctl(s, SIOCIFCREATE2, ifr) < 0) err(1, "SIOCIFCREATE2"); /* XXX preserve original name for ifclonecreate(). */ strlcpy(orig_name, name, sizeof(orig_name)); strlcpy(name, ifr->ifr_name, sizeof(name)); setdefregdomain(s); strlcpy(name, orig_name, sizeof(name)); } static DECL_CMD_FUNC(set80211clone_wlandev, arg, d) { strlcpy(params.icp_parent, arg, IFNAMSIZ); } static DECL_CMD_FUNC(set80211clone_wlanbssid, arg, d) { const struct ether_addr *ea; ea = ether_aton(arg); if (ea == NULL) errx(1, "%s: cannot parse bssid", arg); memcpy(params.icp_bssid, ea->octet, IEEE80211_ADDR_LEN); } static DECL_CMD_FUNC(set80211clone_wlanaddr, arg, d) { const struct ether_addr *ea; ea = ether_aton(arg); if (ea == NULL) errx(1, "%s: cannot parse address", arg); memcpy(params.icp_macaddr, ea->octet, IEEE80211_ADDR_LEN); params.icp_flags |= IEEE80211_CLONE_MACADDR; } static DECL_CMD_FUNC(set80211clone_wlanmode, arg, d) { #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) if (iseq(arg, "sta")) params.icp_opmode = IEEE80211_M_STA; else if (iseq(arg, "ahdemo") || iseq(arg, "adhoc-demo")) params.icp_opmode = IEEE80211_M_AHDEMO; else if (iseq(arg, "ibss") || iseq(arg, "adhoc")) params.icp_opmode = IEEE80211_M_IBSS; else if (iseq(arg, "ap") || iseq(arg, "host")) params.icp_opmode = IEEE80211_M_HOSTAP; else if (iseq(arg, "wds")) params.icp_opmode = IEEE80211_M_WDS; else if (iseq(arg, "monitor")) params.icp_opmode = IEEE80211_M_MONITOR; else if (iseq(arg, "tdma")) { params.icp_opmode = IEEE80211_M_AHDEMO; params.icp_flags |= IEEE80211_CLONE_TDMA; } else if (iseq(arg, "mesh") || iseq(arg, "mp")) /* mesh point */ params.icp_opmode = IEEE80211_M_MBSS; else errx(1, "Don't know to create %s for %s", arg, name); #undef iseq } static void set80211clone_beacons(const char *val, int d, int s, const struct afswtch *rafp) { /* NB: inverted sense */ if (d) params.icp_flags &= ~IEEE80211_CLONE_NOBEACONS; else params.icp_flags |= IEEE80211_CLONE_NOBEACONS; } static void set80211clone_bssid(const char *val, int d, int s, const struct afswtch *rafp) { if (d) params.icp_flags |= IEEE80211_CLONE_BSSID; else params.icp_flags &= ~IEEE80211_CLONE_BSSID; } static void set80211clone_wdslegacy(const char *val, int d, int s, const struct afswtch *rafp) { if (d) params.icp_flags |= IEEE80211_CLONE_WDSLEGACY; else params.icp_flags &= ~IEEE80211_CLONE_WDSLEGACY; } static struct cmd ieee80211_cmds[] = { DEF_CMD_ARG("ssid", set80211ssid), DEF_CMD_ARG("nwid", set80211ssid), DEF_CMD_ARG("meshid", set80211meshid), DEF_CMD_ARG("stationname", set80211stationname), DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ DEF_CMD_ARG("channel", set80211channel), DEF_CMD_ARG("authmode", set80211authmode), DEF_CMD_ARG("powersavemode", set80211powersavemode), DEF_CMD("powersave", 1, set80211powersave), DEF_CMD("-powersave", 0, set80211powersave), DEF_CMD_ARG("powersavesleep", set80211powersavesleep), DEF_CMD_ARG("wepmode", set80211wepmode), DEF_CMD("wep", 1, set80211wep), DEF_CMD("-wep", 0, set80211wep), DEF_CMD_ARG("deftxkey", set80211weptxkey), DEF_CMD_ARG("weptxkey", set80211weptxkey), DEF_CMD_ARG("wepkey", set80211wepkey), DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), DEF_CMD_ARG("protmode", set80211protmode), DEF_CMD_ARG("txpower", set80211txpower), DEF_CMD_ARG("roaming", set80211roaming), DEF_CMD("wme", 1, set80211wme), DEF_CMD("-wme", 0, set80211wme), DEF_CMD("wmm", 1, set80211wme), DEF_CMD("-wmm", 0, set80211wme), DEF_CMD("hidessid", 1, set80211hidessid), DEF_CMD("-hidessid", 0, set80211hidessid), DEF_CMD("apbridge", 1, set80211apbridge), DEF_CMD("-apbridge", 0, set80211apbridge), DEF_CMD_ARG("chanlist", set80211chanlist), DEF_CMD_ARG("bssid", set80211bssid), DEF_CMD_ARG("ap", set80211bssid), DEF_CMD("scan", 0, set80211scan), DEF_CMD_ARG("list", set80211list), DEF_CMD_ARG2("cwmin", set80211cwmin), DEF_CMD_ARG2("cwmax", set80211cwmax), DEF_CMD_ARG2("aifs", set80211aifs), DEF_CMD_ARG2("txoplimit", set80211txoplimit), DEF_CMD_ARG("acm", set80211acm), DEF_CMD_ARG("-acm", set80211noacm), DEF_CMD_ARG("ack", set80211ackpolicy), DEF_CMD_ARG("-ack", set80211noackpolicy), DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), DEF_CMD_ARG2("bss:aifs", set80211bssaifs), DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), DEF_CMD_ARG("dtimperiod", set80211dtimperiod), DEF_CMD_ARG("bintval", set80211bintval), DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), DEF_CMD("mac:radius", IEEE80211_MACCMD_POLICY_RADIUS, set80211maccmd), DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), DEF_CMD_ARG("mac:add", set80211addmac), DEF_CMD_ARG("mac:del", set80211delmac), DEF_CMD_ARG("mac:kick", set80211kickmac), DEF_CMD("pureg", 1, set80211pureg), DEF_CMD("-pureg", 0, set80211pureg), DEF_CMD("ff", 1, set80211fastframes), DEF_CMD("-ff", 0, set80211fastframes), DEF_CMD("dturbo", 1, set80211dturbo), DEF_CMD("-dturbo", 0, set80211dturbo), DEF_CMD("bgscan", 1, set80211bgscan), DEF_CMD("-bgscan", 0, set80211bgscan), DEF_CMD_ARG("bgscanidle", set80211bgscanidle), DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl), DEF_CMD_ARG("scanvalid", set80211scanvalid), - DEF_CMD("quiet", 1, set80211quiet), - DEF_CMD("-quiet", 0, set80211quiet), - DEF_CMD_ARG("quiet_count", set80211quietcount), - DEF_CMD_ARG("quiet_period", set80211quietperiod), - DEF_CMD_ARG("quiet_dur", set80211quietduration), - DEF_CMD_ARG("quiet_offset", set80211quietoffset), + DEF_CMD("quiet", 1, set80211quiet), + DEF_CMD("-quiet", 0, set80211quiet), + DEF_CMD_ARG("quiet_count", set80211quietcount), + DEF_CMD_ARG("quiet_period", set80211quietperiod), + DEF_CMD_ARG("quiet_duration", set80211quietduration), + DEF_CMD_ARG("quiet_offset", set80211quietoffset), DEF_CMD_ARG("roam:rssi", set80211roamrssi), DEF_CMD_ARG("roam:rate", set80211roamrate), DEF_CMD_ARG("mcastrate", set80211mcastrate), DEF_CMD_ARG("ucastrate", set80211ucastrate), DEF_CMD_ARG("mgtrate", set80211mgtrate), DEF_CMD_ARG("mgmtrate", set80211mgtrate), DEF_CMD_ARG("maxretry", set80211maxretry), DEF_CMD_ARG("fragthreshold", set80211fragthreshold), DEF_CMD("burst", 1, set80211burst), DEF_CMD("-burst", 0, set80211burst), DEF_CMD_ARG("bmiss", set80211bmissthreshold), DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold), DEF_CMD("shortgi", 1, set80211shortgi), DEF_CMD("-shortgi", 0, set80211shortgi), DEF_CMD("ampdurx", 2, set80211ampdu), DEF_CMD("-ampdurx", -2, set80211ampdu), DEF_CMD("ampdutx", 1, set80211ampdu), DEF_CMD("-ampdutx", -1, set80211ampdu), DEF_CMD("ampdu", 3, set80211ampdu), /* NB: tx+rx */ DEF_CMD("-ampdu", -3, set80211ampdu), DEF_CMD_ARG("ampdulimit", set80211ampdulimit), DEF_CMD_ARG("ampdudensity", set80211ampdudensity), DEF_CMD("amsdurx", 2, set80211amsdu), DEF_CMD("-amsdurx", -2, set80211amsdu), DEF_CMD("amsdutx", 1, set80211amsdu), DEF_CMD("-amsdutx", -1, set80211amsdu), DEF_CMD("amsdu", 3, set80211amsdu), /* NB: tx+rx */ DEF_CMD("-amsdu", -3, set80211amsdu), DEF_CMD_ARG("amsdulimit", set80211amsdulimit), DEF_CMD("stbcrx", 2, set80211stbc), DEF_CMD("-stbcrx", -2, set80211stbc), DEF_CMD("stbctx", 1, set80211stbc), DEF_CMD("-stbctx", -1, set80211stbc), DEF_CMD("stbc", 3, set80211stbc), /* NB: tx+rx */ DEF_CMD("-stbc", -3, set80211stbc), DEF_CMD("ldpcrx", 2, set80211ldpc), DEF_CMD("-ldpcrx", -2, set80211ldpc), DEF_CMD("ldpctx", 1, set80211ldpc), DEF_CMD("-ldpctx", -1, set80211ldpc), DEF_CMD("ldpc", 3, set80211ldpc), /* NB: tx+rx */ DEF_CMD("-ldpc", -3, set80211ldpc), DEF_CMD("puren", 1, set80211puren), DEF_CMD("-puren", 0, set80211puren), DEF_CMD("doth", 1, set80211doth), DEF_CMD("-doth", 0, set80211doth), DEF_CMD("dfs", 1, set80211dfs), DEF_CMD("-dfs", 0, set80211dfs), DEF_CMD("htcompat", 1, set80211htcompat), DEF_CMD("-htcompat", 0, set80211htcompat), DEF_CMD("dwds", 1, set80211dwds), DEF_CMD("-dwds", 0, set80211dwds), DEF_CMD("inact", 1, set80211inact), DEF_CMD("-inact", 0, set80211inact), DEF_CMD("tsn", 1, set80211tsn), DEF_CMD("-tsn", 0, set80211tsn), DEF_CMD_ARG("regdomain", set80211regdomain), DEF_CMD_ARG("country", set80211country), DEF_CMD("indoor", 'I', set80211location), DEF_CMD("-indoor", 'O', set80211location), DEF_CMD("outdoor", 'O', set80211location), DEF_CMD("-outdoor", 'I', set80211location), DEF_CMD("anywhere", ' ', set80211location), DEF_CMD("ecm", 1, set80211ecm), DEF_CMD("-ecm", 0, set80211ecm), DEF_CMD("dotd", 1, set80211dotd), DEF_CMD("-dotd", 0, set80211dotd), DEF_CMD_ARG("htprotmode", set80211htprotmode), DEF_CMD("ht20", 1, set80211htconf), DEF_CMD("-ht20", 0, set80211htconf), DEF_CMD("ht40", 3, set80211htconf), /* NB: 20+40 */ DEF_CMD("-ht40", 0, set80211htconf), DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */ DEF_CMD("-ht", 0, set80211htconf), DEF_CMD("vht", 1, set80211vhtconf), DEF_CMD("-vht", 0, set80211vhtconf), DEF_CMD("vht40", 2, set80211vhtconf), DEF_CMD("-vht40", -2, set80211vhtconf), DEF_CMD("vht80", 4, set80211vhtconf), DEF_CMD("-vht80", -4, set80211vhtconf), DEF_CMD("vht80p80", 8, set80211vhtconf), DEF_CMD("-vht80p80", -8, set80211vhtconf), DEF_CMD("vht160", 16, set80211vhtconf), DEF_CMD("-vht160", -16, set80211vhtconf), DEF_CMD("rifs", 1, set80211rifs), DEF_CMD("-rifs", 0, set80211rifs), DEF_CMD("smps", IEEE80211_HTCAP_SMPS_ENA, set80211smps), DEF_CMD("smpsdyn", IEEE80211_HTCAP_SMPS_DYNAMIC, set80211smps), DEF_CMD("-smps", IEEE80211_HTCAP_SMPS_OFF, set80211smps), /* XXX for testing */ DEF_CMD_ARG("chanswitch", set80211chanswitch), DEF_CMD_ARG("tdmaslot", set80211tdmaslot), DEF_CMD_ARG("tdmaslotcnt", set80211tdmaslotcnt), DEF_CMD_ARG("tdmaslotlen", set80211tdmaslotlen), DEF_CMD_ARG("tdmabintval", set80211tdmabintval), DEF_CMD_ARG("meshttl", set80211meshttl), DEF_CMD("meshforward", 1, set80211meshforward), DEF_CMD("-meshforward", 0, set80211meshforward), DEF_CMD("meshgate", 1, set80211meshgate), DEF_CMD("-meshgate", 0, set80211meshgate), DEF_CMD("meshpeering", 1, set80211meshpeering), DEF_CMD("-meshpeering", 0, set80211meshpeering), DEF_CMD_ARG("meshmetric", set80211meshmetric), DEF_CMD_ARG("meshpath", set80211meshpath), DEF_CMD("meshrt:flush", IEEE80211_MESH_RTCMD_FLUSH, set80211meshrtcmd), DEF_CMD_ARG("meshrt:add", set80211addmeshrt), DEF_CMD_ARG("meshrt:del", set80211delmeshrt), DEF_CMD_ARG("hwmprootmode", set80211hwmprootmode), DEF_CMD_ARG("hwmpmaxhops", set80211hwmpmaxhops), /* vap cloning support */ DEF_CLONE_CMD_ARG("wlanaddr", set80211clone_wlanaddr), DEF_CLONE_CMD_ARG("wlanbssid", set80211clone_wlanbssid), DEF_CLONE_CMD_ARG("wlandev", set80211clone_wlandev), DEF_CLONE_CMD_ARG("wlanmode", set80211clone_wlanmode), DEF_CLONE_CMD("beacons", 1, set80211clone_beacons), DEF_CLONE_CMD("-beacons", 0, set80211clone_beacons), DEF_CLONE_CMD("bssid", 1, set80211clone_bssid), DEF_CLONE_CMD("-bssid", 0, set80211clone_bssid), DEF_CLONE_CMD("wdslegacy", 1, set80211clone_wdslegacy), DEF_CLONE_CMD("-wdslegacy", 0, set80211clone_wdslegacy), }; static struct afswtch af_ieee80211 = { .af_name = "af_ieee80211", .af_af = AF_UNSPEC, .af_other_status = ieee80211_status, }; static __constructor void ieee80211_ctor(void) { int i; for (i = 0; i < nitems(ieee80211_cmds); i++) cmd_register(&ieee80211_cmds[i]); af_register(&af_ieee80211); clone_setdefcallback("wlan", wlan_create); } Index: projects/ipsec/sbin/kldload/kldload.c =================================================================== --- projects/ipsec/sbin/kldload/kldload.c (revision 313312) +++ projects/ipsec/sbin/kldload/kldload.c (revision 313313) @@ -1,214 +1,201 @@ /*- * Copyright (c) 1997 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #define PATHCTL "kern.module_path" -static int path_check(const char *, int); -static void usage(void); - /* * Check to see if the requested module is specified as a filename with no * path. If so and if a file by the same name exists in the module path, * warn the user that the module in the path will be used in preference. */ static int path_check(const char *kldname, int quiet) { - int mib[5], found; - size_t miblen, pathlen; - char kldpath[MAXPATHLEN]; char *path, *tmppath, *element; struct stat sb; + int mib[5]; + char kldpath[MAXPATHLEN]; + size_t miblen, pathlen; dev_t dev; ino_t ino; + int found; - if (strchr(kldname, '/') != NULL) { + if (strchr(kldname, '/') != NULL) return (0); - } - if (strstr(kldname, ".ko") == NULL) { + if (strstr(kldname, ".ko") == NULL) return (0); - } - if (stat(kldname, &sb) != 0) { + if (stat(kldname, &sb) != 0) return (0); - } found = 0; dev = sb.st_dev; ino = sb.st_ino; miblen = nitems(mib); - if (sysctlnametomib(PATHCTL, mib, &miblen) != 0) { + if (sysctlnametomib(PATHCTL, mib, &miblen) != 0) err(1, "sysctlnametomib(%s)", PATHCTL); - } - if (sysctl(mib, miblen, NULL, &pathlen, NULL, 0) == -1) { + if (sysctl(mib, miblen, NULL, &pathlen, NULL, 0) == -1) err(1, "getting path: sysctl(%s) - size only", PATHCTL); - } path = malloc(pathlen + 1); - if (path == NULL) { + if (path == NULL) err(1, "allocating %lu bytes for the path", (unsigned long)pathlen + 1); - } - if (sysctl(mib, miblen, path, &pathlen, NULL, 0) == -1) { + if (sysctl(mib, miblen, path, &pathlen, NULL, 0) == -1) err(1, "getting path: sysctl(%s)", PATHCTL); - } tmppath = path; while ((element = strsep(&tmppath, ";")) != NULL) { strlcpy(kldpath, element, MAXPATHLEN); if (kldpath[strlen(kldpath) - 1] != '/') { strlcat(kldpath, "/", MAXPATHLEN); } strlcat(kldpath, kldname, MAXPATHLEN); - - if (stat(kldpath, &sb) == -1) { + + if (stat(kldpath, &sb) == -1) continue; - } found = 1; if (sb.st_dev != dev || sb.st_ino != ino) { - if (!quiet) { + if (!quiet) warnx("%s will be loaded from %s, not the " "current directory", kldname, element); - } break; - } else if (sb.st_dev == dev && sb.st_ino == ino) { + } else if (sb.st_dev == dev && sb.st_ino == ino) break; - } } free(path); - + if (!found) { - if (!quiet) { + if (!quiet) warnx("%s is not in the module path", kldname); - } return (-1); } - + return (0); } static void usage(void) { + fprintf(stderr, "usage: kldload [-nqv] file ...\n"); exit(1); } int main(int argc, char** argv) { int c; + int check_loaded; int errors; int fileid; - int verbose; int quiet; - int check_loaded; + int verbose; errors = 0; verbose = 0; quiet = 0; check_loaded = 0; - + while ((c = getopt(argc, argv, "nqv")) != -1) { switch (c) { case 'q': quiet = 1; verbose = 0; break; case 'v': verbose = 1; quiet = 0; break; case 'n': check_loaded = 1; break; default: usage(); } } argc -= optind; argv += optind; if (argc == 0) usage(); while (argc-- != 0) { if (path_check(argv[0], quiet) == 0) { fileid = kldload(argv[0]); if (fileid < 0) { if (check_loaded != 0 && errno == EEXIST) { if (verbose) printf("%s is already " "loaded\n", argv[0]); } else { switch (errno) { case EEXIST: warnx("can't load %s: module " "already loaded or " "in kernel", argv[0]); break; case ENOEXEC: warnx("an error occurred while " "loading the module. " "Please check dmesg(8) for " "more details."); break; default: warn("can't load %s", argv[0]); break; } errors++; } } else { if (verbose) printf("Loaded %s, id=%d\n", argv[0], fileid); } - } else { + } else errors++; - } argv++; } return (errors ? 1 : 0); } Index: projects/ipsec/sbin/nvmecontrol/Makefile =================================================================== --- projects/ipsec/sbin/nvmecontrol/Makefile (revision 313312) +++ projects/ipsec/sbin/nvmecontrol/Makefile (revision 313313) @@ -1,11 +1,11 @@ # $FreeBSD$ PACKAGE=runtime PROG= nvmecontrol SRCS= nvmecontrol.c devlist.c firmware.c identify.c logpage.c \ - perftest.c reset.c nvme_util.c power.c + perftest.c reset.c nvme_util.c power.c wdc.c MAN= nvmecontrol.8 .PATH: ${.CURDIR}/../../sys/dev/nvme .include Index: projects/ipsec/sbin/nvmecontrol/firmware.c =================================================================== --- projects/ipsec/sbin/nvmecontrol/firmware.c (revision 313312) +++ projects/ipsec/sbin/nvmecontrol/firmware.c (revision 313313) @@ -1,322 +1,322 @@ /*- * Copyright (c) 2013 EMC Corp. * All rights reserved. * * Copyright (C) 2012-2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nvmecontrol.h" static int slot_has_valid_firmware(int fd, int slot) { struct nvme_firmware_page fw; int has_fw = false; read_logpage(fd, NVME_LOG_FIRMWARE_SLOT, NVME_GLOBAL_NAMESPACE_TAG, &fw, sizeof(fw)); if (fw.revision[slot-1] != 0LLU) has_fw = true; return (has_fw); } static void read_image_file(char *path, void **buf, int32_t *size) { struct stat sb; int32_t filesize; int fd; *size = 0; *buf = NULL; if ((fd = open(path, O_RDONLY)) < 0) err(1, "unable to open '%s'", path); if (fstat(fd, &sb) < 0) err(1, "unable to stat '%s'", path); /* * The NVMe spec does not explicitly state a maximum firmware image * size, although one can be inferred from the dword size limitation * for the size and offset fields in the Firmware Image Download * command. * * Technically, the max is UINT32_MAX * sizeof(uint32_t), since the * size and offsets are specified in terms of dwords (not bytes), but * realistically INT32_MAX is sufficient here and simplifies matters * a bit. */ if (sb.st_size > INT32_MAX) errx(1, "size of file '%s' is too large (%jd bytes)", path, (intmax_t)sb.st_size); filesize = (int32_t)sb.st_size; if ((*buf = malloc(filesize)) == NULL) errx(1, "unable to malloc %d bytes", filesize); if ((*size = read(fd, *buf, filesize)) < 0) err(1, "error reading '%s'", path); /* XXX assuming no short reads */ if (*size != filesize) errx(1, "error reading '%s' (read %d bytes, requested %d bytes)", path, *size, filesize); } static void update_firmware(int fd, uint8_t *payload, int32_t payload_size) { struct nvme_pt_command pt; int32_t off, resid, size; void *chunk; off = 0; resid = payload_size; - if ((chunk = aligned_alloc(NVME_MAX_XFER_SIZE, PAGE_SIZE)) == NULL) + if ((chunk = aligned_alloc(PAGE_SIZE, NVME_MAX_XFER_SIZE)) == NULL) errx(1, "unable to malloc %d bytes", NVME_MAX_XFER_SIZE); while (resid > 0) { size = (resid >= NVME_MAX_XFER_SIZE) ? NVME_MAX_XFER_SIZE : resid; memcpy(chunk, payload + off, size); memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD; pt.cmd.cdw10 = (size / sizeof(uint32_t)) - 1; pt.cmd.cdw11 = (off / sizeof(uint32_t)); pt.buf = chunk; pt.len = size; pt.is_read = 0; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "firmware download request failed"); if (nvme_completion_is_error(&pt.cpl)) errx(1, "firmware download request returned error"); resid -= size; off += size; } } static int activate_firmware(int fd, int slot, int activate_action) { struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_FIRMWARE_ACTIVATE; pt.cmd.cdw10 = (activate_action << 3) | slot; pt.is_read = 0; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "firmware activate request failed"); if (pt.cpl.status.sct == NVME_SCT_COMMAND_SPECIFIC && pt.cpl.status.sc == NVME_SC_FIRMWARE_REQUIRES_RESET) return 1; if (nvme_completion_is_error(&pt.cpl)) errx(1, "firmware activate request returned error"); return 0; } static void firmware_usage(void) { fprintf(stderr, "usage:\n"); fprintf(stderr, FIRMWARE_USAGE); exit(1); } void firmware(int argc, char *argv[]) { int fd = -1, slot = 0; int a_flag, s_flag, f_flag; int activate_action, reboot_required; char ch, *p, *image = NULL; char *controller = NULL, prompt[64]; void *buf = NULL; int32_t size = 0; struct nvme_controller_data cdata; a_flag = s_flag = f_flag = false; while ((ch = getopt(argc, argv, "af:s:")) != -1) { switch (ch) { case 'a': a_flag = true; break; case 's': slot = strtol(optarg, &p, 0); if (p != NULL && *p != '\0') { fprintf(stderr, "\"%s\" not valid slot.\n", optarg); firmware_usage(); } else if (slot == 0) { fprintf(stderr, "0 is not a valid slot number. " "Slot numbers start at 1.\n"); firmware_usage(); } else if (slot > 7) { fprintf(stderr, "Slot number %s specified which is " "greater than max allowed slot number of " "7.\n", optarg); firmware_usage(); } s_flag = true; break; case 'f': image = optarg; f_flag = true; break; } } /* Check that a controller (and not a namespace) was specified. */ if (optind >= argc || strstr(argv[optind], NVME_NS_PREFIX) != NULL) firmware_usage(); if (!f_flag && !a_flag) { fprintf(stderr, "Neither a replace ([-f path_to_firmware]) nor " "activate ([-a]) firmware image action\n" "was specified.\n"); firmware_usage(); } if (!f_flag && a_flag && slot == 0) { fprintf(stderr, "Slot number to activate not specified.\n"); firmware_usage(); } controller = argv[optind]; open_dev(controller, &fd, 1, 1); read_controller_data(fd, &cdata); if (cdata.oacs.firmware == 0) errx(1, "controller does not support firmware activate/download"); if (f_flag && slot == 1 && cdata.frmw.slot1_ro) errx(1, "slot %d is marked as read only", slot); if (slot > cdata.frmw.num_slots) errx(1, "slot %d specified but controller only supports %d slots", slot, cdata.frmw.num_slots); if (a_flag && !f_flag && !slot_has_valid_firmware(fd, slot)) errx(1, "slot %d does not contain valid firmware,\n" "try 'nvmecontrol logpage -p 3 %s' to get a list " "of available images\n", slot, controller); if (f_flag) read_image_file(image, &buf, &size); if (f_flag && a_flag) printf("You are about to download and activate " "firmware image (%s) to controller %s.\n" "This may damage your controller and/or " "overwrite an existing firmware image.\n", image, controller); else if (a_flag) printf("You are about to activate a new firmware " "image on controller %s.\n" "This may damage your controller.\n", controller); else if (f_flag) printf("You are about to download firmware image " "(%s) to controller %s.\n" "This may damage your controller and/or " "overwrite an existing firmware image.\n", image, controller); printf("Are you sure you want to continue? (yes/no) "); while (1) { fgets(prompt, sizeof(prompt), stdin); if (strncasecmp(prompt, "yes", 3) == 0) break; if (strncasecmp(prompt, "no", 2) == 0) exit(1); printf("Please answer \"yes\" or \"no\". "); } if (f_flag) { update_firmware(fd, buf, size); if (a_flag) activate_action = NVME_AA_REPLACE_ACTIVATE; else activate_action = NVME_AA_REPLACE_NO_ACTIVATE; } else { activate_action = NVME_AA_ACTIVATE; } reboot_required = activate_firmware(fd, slot, activate_action); if (a_flag) { if (reboot_required) { printf("New firmware image activated but requires " "conventional reset (i.e. reboot) to " "complete activation.\n"); } else { printf("New firmware image activated and will take " "effect after next controller reset.\n" "Controller reset can be initiated via " "'nvmecontrol reset %s'\n", controller); } } close(fd); exit(0); } Index: projects/ipsec/sbin/nvmecontrol/logpage.c =================================================================== --- projects/ipsec/sbin/nvmecontrol/logpage.c (revision 313312) +++ projects/ipsec/sbin/nvmecontrol/logpage.c (revision 313313) @@ -1,975 +1,988 @@ /*- * Copyright (c) 2013 EMC Corp. * All rights reserved. * * Copyright (C) 2012-2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #if _BYTE_ORDER != _LITTLE_ENDIAN #error "Code only works on little endian machines" #endif #include "nvmecontrol.h" #define DEFAULT_SIZE (4096) #define MAX_FW_SLOTS (7) typedef void (*print_fn_t)(void *buf, uint32_t size); struct kv_name { uint32_t key; const char *name; }; static const char * kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key) { static char bad[32]; size_t i; for (i = 0; i < kv_count; i++, kv++) if (kv->key == key) return kv->name; snprintf(bad, sizeof(bad), "Attribute %#x", key); return bad; } +static void +print_bin(void *data, uint32_t length) +{ + write(STDOUT_FILENO, data, length); +} + /* * 128-bit integer augments to standard values. On i386 this * doesn't exist, so we use 64-bit values. The 128-bit counters * are crazy anyway, since for this purpose, you'd need a * billion IOPs for billions of seconds to overflow them. * So, on 32-bit i386, you'll get truncated values. */ #define UINT128_DIG 39 #ifdef __i386__ typedef uint64_t uint128_t; #else typedef __uint128_t uint128_t; #endif static inline uint128_t to128(void *p) { return *(uint128_t *)p; } static char * uint128_to_str(uint128_t u, char *buf, size_t buflen) { char *end = buf + buflen - 1; *end-- = '\0'; if (u == 0) *end-- = '0'; while (u && end >= buf) { *end-- = u % 10 + '0'; u /= 10; } end++; if (u != 0) return NULL; return end; } /* "Missing" from endian.h */ static __inline uint64_t le48dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return (((uint64_t)le16dec(p + 4) << 32) | le32dec(p)); } static void * get_log_buffer(uint32_t size) { void *buf; if ((buf = malloc(size)) == NULL) errx(1, "unable to malloc %u bytes", size); memset(buf, 0, size); return (buf); } void read_logpage(int fd, uint8_t log_page, int nsid, void *payload, uint32_t payload_size) { struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_GET_LOG_PAGE; pt.cmd.nsid = nsid; pt.cmd.cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16; pt.cmd.cdw10 |= log_page; pt.buf = payload; pt.len = payload_size; pt.is_read = 1; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "get log page request failed"); if (nvme_completion_is_error(&pt.cpl)) errx(1, "get log page request returned error"); } static void print_log_error(void *buf, uint32_t size) { int i, nentries; struct nvme_error_information_entry *entry = buf; struct nvme_status *status; printf("Error Information Log\n"); printf("=====================\n"); if (entry->error_count == 0) { printf("No error entries found\n"); return; } nentries = size/sizeof(struct nvme_error_information_entry); for (i = 0; i < nentries; i++, entry++) { if (entry->error_count == 0) break; status = &entry->status; printf("Entry %02d\n", i + 1); printf("=========\n"); printf(" Error count: %ju\n", entry->error_count); printf(" Submission queue ID: %u\n", entry->sqid); printf(" Command ID: %u\n", entry->cid); /* TODO: Export nvme_status_string structures from kernel? */ printf(" Status:\n"); printf(" Phase tag: %d\n", status->p); printf(" Status code: %d\n", status->sc); printf(" Status code type: %d\n", status->sct); printf(" More: %d\n", status->m); printf(" DNR: %d\n", status->dnr); printf(" Error location: %u\n", entry->error_location); printf(" LBA: %ju\n", entry->lba); printf(" Namespace ID: %u\n", entry->nsid); printf(" Vendor specific info: %u\n", entry->vendor_specific); } } static void print_temp(uint16_t t) { printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15, (float)t * 9 / 5 - 459.67); } static void print_log_health(void *buf, uint32_t size __unused) { struct nvme_health_information_page *health = buf; char cbuf[UINT128_DIG + 1]; int i; printf("SMART/Health Information Log\n"); printf("============================\n"); printf("Critical Warning State: 0x%02x\n", health->critical_warning.raw); printf(" Available spare: %d\n", health->critical_warning.bits.available_spare); printf(" Temperature: %d\n", health->critical_warning.bits.temperature); printf(" Device reliability: %d\n", health->critical_warning.bits.device_reliability); printf(" Read only: %d\n", health->critical_warning.bits.read_only); printf(" Volatile memory backup: %d\n", health->critical_warning.bits.volatile_memory_backup); printf("Temperature: "); print_temp(health->temperature); printf("Available spare: %u\n", health->available_spare); printf("Available spare threshold: %u\n", health->available_spare_threshold); printf("Percentage used: %u\n", health->percentage_used); printf("Data units (512,000 byte) read: %s\n", uint128_to_str(to128(health->data_units_read), cbuf, sizeof(cbuf))); printf("Data units written: %s\n", uint128_to_str(to128(health->data_units_written), cbuf, sizeof(cbuf))); printf("Host read commands: %s\n", uint128_to_str(to128(health->host_read_commands), cbuf, sizeof(cbuf))); printf("Host write commands: %s\n", uint128_to_str(to128(health->host_write_commands), cbuf, sizeof(cbuf))); printf("Controller busy time (minutes): %s\n", uint128_to_str(to128(health->controller_busy_time), cbuf, sizeof(cbuf))); printf("Power cycles: %s\n", uint128_to_str(to128(health->power_cycles), cbuf, sizeof(cbuf))); printf("Power on hours: %s\n", uint128_to_str(to128(health->power_on_hours), cbuf, sizeof(cbuf))); printf("Unsafe shutdowns: %s\n", uint128_to_str(to128(health->unsafe_shutdowns), cbuf, sizeof(cbuf))); printf("Media errors: %s\n", uint128_to_str(to128(health->media_errors), cbuf, sizeof(cbuf))); printf("No. error info log entries: %s\n", uint128_to_str(to128(health->num_error_info_log_entries), cbuf, sizeof(cbuf))); printf("Warning Temp Composite Time: %d\n", health->warning_temp_time); printf("Error Temp Composite Time: %d\n", health->error_temp_time); for (i = 0; i < 7; i++) { if (health->temp_sensor[i] == 0) continue; printf("Temperature Sensor %d: ", i + 1); print_temp(health->temp_sensor[i]); } } static void print_log_firmware(void *buf, uint32_t size __unused) { int i; const char *status; struct nvme_firmware_page *fw = buf; printf("Firmware Slot Log\n"); printf("=================\n"); for (i = 0; i < MAX_FW_SLOTS; i++) { printf("Slot %d: ", i + 1); if (fw->afi.slot == i + 1) status = " Active"; else status = "Inactive"; if (fw->revision[i] == 0LLU) printf("Empty\n"); else if (isprint(*(char *)&fw->revision[i])) printf("[%s] %.8s\n", status, (char *)&fw->revision[i]); else printf("[%s] %016jx\n", status, fw->revision[i]); } } /* * Intel specific log pages from * http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/ssd-dc-p3700-spec.pdf * * Though the version as of this date has a typo for the size of log page 0xca, * offset 147: it is only 1 byte, not 6. */ static void print_intel_temp_stats(void *buf, uint32_t size __unused) { struct intel_log_temp_stats *temp = buf; printf("Intel Temperature Log\n"); printf("=====================\n"); printf("Current: "); print_temp(temp->current); printf("Overtemp Last Flags %#jx\n", (uintmax_t)temp->overtemp_flag_last); printf("Overtemp Lifetime Flags %#jx\n", (uintmax_t)temp->overtemp_flag_life); printf("Max Temperature "); print_temp(temp->max_temp); printf("Min Temperature "); print_temp(temp->min_temp); printf("Max Operating Temperature "); print_temp(temp->max_oper_temp); printf("Min Operating Temperature "); print_temp(temp->min_oper_temp); printf("Estimated Temperature Offset: %ju C/K\n", (uintmax_t)temp->est_offset); } /* * Format from Table 22, section 5.7 IO Command Latency Statistics. * Read and write stats pages have identical encoding. */ static void print_intel_read_write_lat_log(void *buf, uint32_t size __unused) { const char *walker = buf; int i; printf("Major: %d\n", le16dec(walker + 0)); printf("Minor: %d\n", le16dec(walker + 2)); for (i = 0; i < 32; i++) printf("%4dus-%4dus: %ju\n", i * 32, (i + 1) * 32, (uintmax_t)le32dec(walker + 4 + i * 4)); for (i = 1; i < 32; i++) printf("%4dms-%4dms: %ju\n", i, i + 1, (uintmax_t)le32dec(walker + 132 + i * 4)); for (i = 1; i < 32; i++) printf("%4dms-%4dms: %ju\n", i * 32, (i + 1) * 32, (uintmax_t)le32dec(walker + 256 + i * 4)); } static void print_intel_read_lat_log(void *buf, uint32_t size) { printf("Intel Read Latency Log\n"); printf("======================\n"); print_intel_read_write_lat_log(buf, size); } static void print_intel_write_lat_log(void *buf, uint32_t size) { printf("Intel Write Latency Log\n"); printf("=======================\n"); print_intel_read_write_lat_log(buf, size); } /* * Table 19. 5.4 SMART Attributes */ static void print_intel_add_smart(void *buf, uint32_t size __unused) { uint8_t *walker = buf; uint8_t *end = walker + 150; const char *name; uint64_t raw; uint8_t normalized; static struct kv_name kv[] = { { 0xab, "Program Fail Count" }, { 0xac, "Erase Fail Count" }, { 0xad, "Wear Leveling Count" }, { 0xb8, "End to End Error Count" }, { 0xc7, "CRC Error Count" }, { 0xe2, "Timed: Media Wear" }, { 0xe3, "Timed: Host Read %" }, { 0xe4, "Timed: Elapsed Time" }, { 0xea, "Thermal Throttle Status" }, { 0xf0, "Retry Buffer Overflows" }, { 0xf3, "PLL Lock Loss Count" }, { 0xf4, "NAND Bytes Written" }, { 0xf5, "Host Bytes Written" }, }; printf("Additional SMART Data Log\n"); printf("=========================\n"); /* * walker[0] = Key * walker[1,2] = reserved * walker[3] = Normalized Value * walker[4] = reserved * walker[5..10] = Little Endian Raw value * (or other represenations) * walker[11] = reserved */ while (walker < end) { name = kv_lookup(kv, nitems(kv), *walker); normalized = walker[3]; raw = le48dec(walker + 5); switch (*walker){ case 0: break; case 0xad: printf("%-32s: %3d min: %u max: %u ave: %u\n", name, normalized, le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9)); break; case 0xe2: printf("%-32s: %3d %.3f%%\n", name, normalized, raw / 1024.0); break; case 0xea: printf("%-32s: %3d %d%% %d times\n", name, normalized, walker[5], le32dec(walker+6)); break; default: printf("%-32s: %3d %ju\n", name, normalized, (uintmax_t)raw); break; } walker += 12; } } /* * HGST's 0xc1 page. This is a grab bag of additional data. Please see * https://www.hgst.com/sites/default/files/resources/US_SN150_ProdManual.pdf * https://www.hgst.com/sites/default/files/resources/US_SN100_ProdManual.pdf * Appendix A for details */ typedef void (*subprint_fn_t)(void *buf, uint16_t subtype, uint8_t res, uint32_t size); struct subpage_print { uint16_t key; subprint_fn_t fn; }; static void print_hgst_info_write_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static void print_hgst_info_read_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static void print_hgst_info_verify_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static void print_hgst_info_self_test(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static void print_hgst_info_background_scan(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static void print_hgst_info_erase_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static void print_hgst_info_erase_counts(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static void print_hgst_info_temp_history(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static void print_hgst_info_ssd_perf(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static void print_hgst_info_firmware_load(void *buf, uint16_t subtype, uint8_t res, uint32_t size); static struct subpage_print hgst_subpage[] = { { 0x02, print_hgst_info_write_errors }, { 0x03, print_hgst_info_read_errors }, { 0x05, print_hgst_info_verify_errors }, { 0x10, print_hgst_info_self_test }, { 0x15, print_hgst_info_background_scan }, { 0x30, print_hgst_info_erase_errors }, { 0x31, print_hgst_info_erase_counts }, { 0x32, print_hgst_info_temp_history }, { 0x37, print_hgst_info_ssd_perf }, { 0x38, print_hgst_info_firmware_load }, }; /* Print a subpage that is basically just key value pairs */ static void print_hgst_info_subpage_gen(void *buf, uint16_t subtype __unused, uint32_t size, const struct kv_name *kv, size_t kv_count) { uint8_t *wsp, *esp; uint16_t ptype; uint8_t plen; uint64_t param; int i; wsp = buf; esp = wsp + size; while (wsp < esp) { ptype = le16dec(wsp); wsp += 2; wsp++; /* Flags, just ignore */ plen = *wsp++; param = 0; for (i = 0; i < plen; i++) param |= (uint64_t)*wsp++ << (i * 8); printf(" %-30s: %jd\n", kv_lookup(kv, kv_count, ptype), (uintmax_t)param); } } static void print_hgst_info_write_errors(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) { static struct kv_name kv[] = { { 0x0000, "Corrected Without Delay" }, { 0x0001, "Corrected Maybe Delayed" }, { 0x0002, "Re-Writes" }, { 0x0003, "Errors Corrected" }, { 0x0004, "Correct Algorithm Used" }, { 0x0005, "Bytes Processed" }, { 0x0006, "Uncorrected Errors" }, { 0x8000, "Flash Write Commands" }, { 0x8001, "HGST Special" }, }; printf("Write Errors Subpage:\n"); print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); } static void print_hgst_info_read_errors(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) { static struct kv_name kv[] = { { 0x0000, "Corrected Without Delay" }, { 0x0001, "Corrected Maybe Delayed" }, { 0x0002, "Re-Reads" }, { 0x0003, "Errors Corrected" }, { 0x0004, "Correct Algorithm Used" }, { 0x0005, "Bytes Processed" }, { 0x0006, "Uncorrected Errors" }, { 0x8000, "Flash Read Commands" }, { 0x8001, "XOR Recovered" }, { 0x8002, "Total Corrected Bits" }, }; printf("Read Errors Subpage:\n"); print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); } static void print_hgst_info_verify_errors(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) { static struct kv_name kv[] = { { 0x0000, "Corrected Without Delay" }, { 0x0001, "Corrected Maybe Delayed" }, { 0x0002, "Re-Reads" }, { 0x0003, "Errors Corrected" }, { 0x0004, "Correct Algorithm Used" }, { 0x0005, "Bytes Processed" }, { 0x0006, "Uncorrected Errors" }, { 0x8000, "Commands Processed" }, }; printf("Verify Errors Subpage:\n"); print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); } static void print_hgst_info_self_test(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size) { size_t i; uint8_t *walker = buf; uint16_t code, hrs; uint32_t lba; printf("Self Test Subpage:\n"); for (i = 0; i < size / 20; i++) { /* Each entry is 20 bytes */ code = le16dec(walker); walker += 2; walker++; /* Ignore fixed flags */ if (*walker == 0) /* Last entry is zero length */ break; if (*walker++ != 0x10) { printf("Bad length for self test report\n"); return; } printf(" %-30s: %d\n", "Recent Test", code); printf(" %-28s: %#x\n", "Self-Test Results", *walker & 0xf); printf(" %-28s: %#x\n", "Self-Test Code", (*walker >> 5) & 0x7); walker++; printf(" %-28s: %#x\n", "Self-Test Number", *walker++); hrs = le16dec(walker); walker += 2; lba = le32dec(walker); walker += 4; printf(" %-28s: %u\n", "Total Power On Hrs", hrs); printf(" %-28s: %#jx (%jd)\n", "LBA", (uintmax_t)lba, (uintmax_t)lba); printf(" %-28s: %#x\n", "Sense Key", *walker++ & 0xf); printf(" %-28s: %#x\n", "Additional Sense Code", *walker++); printf(" %-28s: %#x\n", "Additional Sense Qualifier", *walker++); printf(" %-28s: %#x\n", "Vendor Specific Detail", *walker++); } } static void print_hgst_info_background_scan(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size) { uint8_t *walker = buf; uint8_t status; uint16_t code, nscan, progress; uint32_t pom, nand; printf("Background Media Scan Subpage:\n"); /* Decode the header */ code = le16dec(walker); walker += 2; walker++; /* Ignore fixed flags */ if (*walker++ != 0x10) { printf("Bad length for background scan header\n"); return; } if (code != 0) { printf("Expceted code 0, found code %#x\n", code); return; } pom = le32dec(walker); walker += 4; walker++; /* Reserved */ status = *walker++; nscan = le16dec(walker); walker += 2; progress = le16dec(walker); walker += 2; walker += 6; /* Reserved */ printf(" %-30s: %d\n", "Power On Minutes", pom); printf(" %-30s: %x (%s)\n", "BMS Status", status, status == 0 ? "idle" : (status == 1 ? "active" : (status == 8 ? "suspended" : "unknown"))); printf(" %-30s: %d\n", "Number of BMS", nscan); printf(" %-30s: %d\n", "Progress Current BMS", progress); /* Report retirements */ if (walker - (uint8_t *)buf != 20) { printf("Coding error, offset not 20\n"); return; } size -= 20; printf(" %-30s: %d\n", "BMS retirements", size / 0x18); while (size > 0) { code = le16dec(walker); walker += 2; walker++; if (*walker++ != 0x14) { printf("Bad length parameter\n"); return; } pom = le32dec(walker); walker += 4; /* * Spec sheet says the following are hard coded, if true, just * print the NAND retirement. */ if (walker[0] == 0x41 && walker[1] == 0x0b && walker[2] == 0x01 && walker[3] == 0x00 && walker[4] == 0x00 && walker[5] == 0x00 && walker[6] == 0x00 && walker[7] == 0x00) { walker += 8; walker += 4; /* Skip reserved */ nand = le32dec(walker); walker += 4; printf(" %-30s: %d\n", "Retirement number", code); printf(" %-28s: %#x\n", "NAND (C/T)BBBPPP", nand); } else { printf("Parameter %#x entry corrupt\n", code); walker += 16; } } } static void print_hgst_info_erase_errors(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size) { static struct kv_name kv[] = { { 0x0000, "Corrected Without Delay" }, { 0x0001, "Corrected Maybe Delayed" }, { 0x0002, "Re-Erase" }, { 0x0003, "Errors Corrected" }, { 0x0004, "Correct Algorithm Used" }, { 0x0005, "Bytes Processed" }, { 0x0006, "Uncorrected Errors" }, { 0x8000, "Flash Erase Commands" }, { 0x8001, "Mfg Defect Count" }, { 0x8002, "Grown Defect Count" }, { 0x8003, "Erase Count -- User" }, { 0x8004, "Erase Count -- System" }, }; printf("Erase Errors Subpage:\n"); print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); } static void print_hgst_info_erase_counts(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) { /* My drive doesn't export this -- so not coding up */ printf("XXX: Erase counts subpage: %p, %#x %d\n", buf, subtype, size); } static void print_hgst_info_temp_history(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size __unused) { uint8_t *walker = buf; uint32_t min; printf("Temperature History:\n"); printf(" %-30s: %d C\n", "Current Temperature", *walker++); printf(" %-30s: %d C\n", "Reference Temperature", *walker++); printf(" %-30s: %d C\n", "Maximum Temperature", *walker++); printf(" %-30s: %d C\n", "Minimum Temperature", *walker++); min = le32dec(walker); walker += 4; printf(" %-30s: %d:%02d:00\n", "Max Temperture Time", min / 60, min % 60); min = le32dec(walker); walker += 4; printf(" %-30s: %d:%02d:00\n", "Over Temperture Duration", min / 60, min % 60); min = le32dec(walker); walker += 4; printf(" %-30s: %d:%02d:00\n", "Min Temperture Time", min / 60, min % 60); } static void print_hgst_info_ssd_perf(void *buf, uint16_t subtype __unused, uint8_t res, uint32_t size __unused) { uint8_t *walker = buf; uint64_t val; printf("SSD Performance Subpage Type %d:\n", res); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Read Commands", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Read Blocks", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Cache Read Hits Commands", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Cache Read Hits Blocks", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Read Commands Stalled", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Write Commands", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Write Blocks", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Write Odd Start Commands", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Write Odd End Commands", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "Host Write Commands Stalled", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "NAND Read Commands", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "NAND Read Blocks", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "NAND Write Commands", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "NAND Write Blocks", val); val = le64dec(walker); walker += 8; printf(" %-30s: %ju\n", "NAND Read Before Writes", val); } static void print_hgst_info_firmware_load(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size __unused) { uint8_t *walker = buf; printf("Firmware Load Subpage:\n"); printf(" %-30s: %d\n", "Firmware Downloads", le32dec(walker)); } static void kv_indirect(void *buf, uint32_t subtype, uint8_t res, uint32_t size, struct subpage_print *sp, size_t nsp) { size_t i; for (i = 0; i < nsp; i++, sp++) { if (sp->key == subtype) { sp->fn(buf, subtype, res, size); return; } } printf("No handler for page type %x\n", subtype); } static void print_hgst_info_log(void *buf, uint32_t size __unused) { uint8_t *walker, *end, *subpage; int pages; uint16_t len; uint8_t subtype, res; printf("HGST Extra Info Log\n"); printf("===================\n"); walker = buf; pages = *walker++; walker++; len = le16dec(walker); walker += 2; end = walker + len; /* Length is exclusive of this header */ while (walker < end) { subpage = walker + 4; subtype = *walker++ & 0x3f; /* subtype */ res = *walker++; /* Reserved */ len = le16dec(walker); walker += len + 2; /* Length, not incl header */ if (walker > end) { printf("Ooops! Off the end of the list\n"); break; } kv_indirect(subpage, subtype, res, len, hgst_subpage, nitems(hgst_subpage)); } } /* * Table of log page printer / sizing. * * This includes Intel specific pages that are widely implemented. Not * sure how best to switch between different vendors. */ static struct logpage_function { uint8_t log_page; const char *vendor; print_fn_t print_fn; size_t size; } logfuncs[] = { {NVME_LOG_ERROR, NULL, print_log_error, 0}, {NVME_LOG_HEALTH_INFORMATION, NULL, print_log_health, sizeof(struct nvme_health_information_page)}, {NVME_LOG_FIRMWARE_SLOT, NULL, print_log_firmware, sizeof(struct nvme_firmware_page)}, {HGST_INFO_LOG, "hgst", print_hgst_info_log, DEFAULT_SIZE}, + {HGST_INFO_LOG, "wdc", print_hgst_info_log, + DEFAULT_SIZE}, {INTEL_LOG_TEMP_STATS, "intel", print_intel_temp_stats, sizeof(struct intel_log_temp_stats)}, {INTEL_LOG_READ_LAT_LOG, "intel", print_intel_read_lat_log, DEFAULT_SIZE}, {INTEL_LOG_WRITE_LAT_LOG, "intel", print_intel_write_lat_log, DEFAULT_SIZE}, {INTEL_LOG_ADD_SMART, "intel", print_intel_add_smart, DEFAULT_SIZE}, {0, NULL, NULL, 0}, }; static void logpage_usage(void) { fprintf(stderr, "usage:\n"); fprintf(stderr, LOGPAGE_USAGE); exit(1); } void logpage(int argc, char *argv[]) { int fd, nsid; int log_page = 0, pageflag = false; - int hexflag = false, ns_specified; + int binflag = false, hexflag = false, ns_specified; char ch, *p; char cname[64]; uint32_t size; void *buf; const char *vendor = NULL; struct logpage_function *f; struct nvme_controller_data cdata; print_fn_t print_fn; - while ((ch = getopt(argc, argv, "p:xv:")) != -1) { + while ((ch = getopt(argc, argv, "bp:xv:")) != -1) { switch (ch) { + case 'b': + binflag = true; + break; case 'p': /* TODO: Add human-readable ASCII page IDs */ log_page = strtol(optarg, &p, 0); if (p != NULL && *p != '\0') { fprintf(stderr, "\"%s\" not valid log page id.\n", optarg); logpage_usage(); } pageflag = true; break; case 'x': hexflag = true; break; case 'v': vendor = optarg; break; } } if (!pageflag) { printf("Missing page_id (-p).\n"); logpage_usage(); } /* Check that a controller and/or namespace was specified. */ if (optind >= argc) logpage_usage(); if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { ns_specified = true; parse_ns_str(argv[optind], cname, &nsid); open_dev(cname, &fd, 1, 1); } else { ns_specified = false; nsid = NVME_GLOBAL_NAMESPACE_TAG; open_dev(argv[optind], &fd, 1, 1); } read_controller_data(fd, &cdata); /* * The log page attribtues indicate whether or not the controller * supports the SMART/Health information log page on a per * namespace basis. */ if (ns_specified) { if (log_page != NVME_LOG_HEALTH_INFORMATION) errx(1, "log page %d valid only at controller level", log_page); if (cdata.lpa.ns_smart == 0) errx(1, "controller does not support per namespace " "smart/health information"); } print_fn = print_hex; size = DEFAULT_SIZE; - if (!hexflag) { + if (binflag) + print_fn = print_bin; + if (!binflag && !hexflag) { /* * See if there is a pretty print function for the specified log * page. If one isn't found, we just revert to the default * (print_hex). If there was a vendor specified bt the user, and * the page is vendor specific, don't match the print function * unless the vendors match. */ for (f = logfuncs; f->log_page > 0; f++) { if (f->vendor != NULL && vendor != NULL && strcmp(f->vendor, vendor) != 0) continue; if (log_page != f->log_page) continue; print_fn = f->print_fn; size = f->size; break; } } if (log_page == NVME_LOG_ERROR) { size = sizeof(struct nvme_error_information_entry); size *= (cdata.elpe + 1); } /* Read the log page */ buf = get_log_buffer(size); read_logpage(fd, log_page, nsid, buf, size); print_fn(buf, size); close(fd); exit(0); } Index: projects/ipsec/sbin/nvmecontrol/nvmecontrol.8 =================================================================== --- projects/ipsec/sbin/nvmecontrol/nvmecontrol.8 (revision 313312) +++ projects/ipsec/sbin/nvmecontrol/nvmecontrol.8 (revision 313313) @@ -1,152 +1,203 @@ .\" .\" Copyright (c) 2012 Intel Corporation .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions, and the following disclaimer, .\" without modification. .\" 2. Redistributions in binary form must reproduce at minimum a disclaimer .\" substantially similar to the "NO WARRANTY" disclaimer below .\" ("Disclaimer") and any redistribution must be conditioned upon .\" including a substantially similar Disclaimer requirement for further .\" binary redistribution. .\" .\" NO WARRANTY .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. .\" .\" nvmecontrol man page. .\" .\" Author: Jim Harris .\" .\" $FreeBSD$ .\" -.Dd September 10, 2016 +.Dd February 4, 2017 .Dt NVMECONTROL 8 .Os .Sh NAME .Nm nvmecontrol .Nd NVM Express control utility .Sh SYNOPSIS .Nm .Ic devlist .Nm .Ic identify .Op Fl v .Op Fl x .Aq device id .Nm .Ic perftest .Aq Fl n Ar num_threads .Aq Fl o Ar read|write .Op Fl p .Aq Fl s Ar size_in_bytes .Aq Fl t Ar time_in_sec .Aq namespace id .Nm .Ic reset .Aq controller id .Nm .Ic logpage .Aq Fl p Ar page_id .Op Fl x +.Op Fl v Ar vendor-string +.Op Fl b .Aq device id .Aq namespace id .Nm .Ic firmware .Op Fl s Ar slot .Op Fl f Ar path_to_firmware .Op Fl a .Aq device id .Nm .Ic power .Op Fl l .Op Fl p power_state -.Op fl w workload_hint +.Op Fl w workload_hint +.Nm +.Ic wdc cap-diag +.Op Fl o path_template +.Aq device id +.Nm +.Ic wdc drive-log +.Op Fl o path_template +.Aq device id +.Nm +.Ic wdc get-crash-dump +.Op Fl o path_template +.Aq device id +.\" .Nm +.\" .Ic wdc purge +.\" .Aq device id +.\" .Nm +.\" .Ic wdc purge-monitor +.\" .Aq device id .Sh DESCRIPTION NVM Express (NVMe) is a storage protocol standard, for SSDs and other high-speed storage devices over PCI Express. +.Pp +.Ss logpage +The logpage command knows how to print log pages of various types. +It also knows about vendor specific log pages from hgst/wdc and intel. +Page 0xc1 for hgst/wdc contains the advanced smart information about +the drive. +Page 0xc1 is read latency stats for intel. +Page 0xc2 is write latency stats for intel. +Page 0xc5 is temperature stats for intel. +Page 0xca is advanced smart information for intel. +.Ss wdc +The various wdc command retrieve log data from the wdc/hgst drives. +The +.Fl o +flag specifies a path template to use to output the files. +Each file takes the path template (which defaults to nothing), appends +the drive's serial number and the type of dump it is followed +by .bin. +These logs must be sent to the vendor for analysis. +This tool only provides a way to extract them. .Sh EXAMPLES .Dl nvmecontrol devlist .Pp Display a list of NVMe controllers and namespaces along with their device nodes. .Pp .Dl nvmecontrol identify nvme0 .Pp Display a human-readable summary of the nvme0 IDENTIFY_CONTROLLER data. .Pp .Dl nvmecontrol identify -x -v nvme0ns1 .Pp Display an hexadecimal dump of the nvme0 IDENTIFY_NAMESPACE data for namespace 1. .Pp .Dl nvmecontrol perftest -n 32 -o read -s 512 -t 30 nvme0ns1 .Pp Run a performance test on nvme0ns1 using 32 kernel threads for 30 seconds. Each thread will issue a single 512 byte read command. Results are printed to stdout when 30 seconds expires. .Pp .Dl nvmecontrol reset nvme0 .Pp Perform a controller-level reset of the nvme0 controller. .Pp .Dl nvmecontrol logpage -p 1 nvme0 .Pp Display a human-readable summary of the nvme0 controller's Error Information Log. Log pages defined by the NVMe specification include Error Information Log (ID=1), SMART/Health Information Log (ID=2), and Firmware Slot Log (ID=3). .Pp +.Dl nvmecontrol logpage -p 0xc1 -v wdc nvme0 +.Pp +Display a human-readable summary of the nvme0's wdc-specific advanced +SMART data. +.Pp .Dl nvmecontrol logpage -p 1 -x nvme0 .Pp Display a hexadecimal dump of the nvme0 controller's Error Information Log. +.Pp +.Dl nvmecontrol logpage -p 0xcb -b nvme0 > /tmp/page-cb.bin +.Pp +Print the contents of vendor specific page 0xcb as binary data on +standard out. +Redirect it to a temporary file. .Pp .Dl nvmecontrol firmware -s 2 -f /tmp/nvme_firmware nvme0 .Pp Download the firmware image contained in "/tmp/nvme_firmware" to slot 2 of the nvme0 controller, but do not activate the image. .Pp .Dl nvmecontrol firmware -s 4 -a nvme0 .Pp Activate the firmware in slot 4 of the nvme0 controller on the next reset. .Pp .Dl nvmecontrol firmware -s 7 -f /tmp/nvme_firmware -a nvme0 .Pp Download the firmware image contained in "/tmp/nvme_firmware" to slot 7 of the nvme0 controller and activate it on the next reset. .Pp .Dl nvmecontrol power -l nvme0 .Pp List all the current power modes. .Pp .Dl nvmecontrol power -p 3 nvme0 .Pp Set the current power mode. .Pp .Dl nvmecontrol power nvme0 .Pp Get the current power mode. .Sh HISTORY The .Nm utility appeared in .Fx 9.2 . .Sh AUTHORS .An -nosplit .Nm was developed by Intel and originally written by .An Jim Harris Aq Mt jimharris@FreeBSD.org . .Pp This man page was written by .An Jim Harris Aq Mt jimharris@FreeBSD.org . Index: projects/ipsec/sbin/nvmecontrol/nvmecontrol.c =================================================================== --- projects/ipsec/sbin/nvmecontrol/nvmecontrol.c (revision 313312) +++ projects/ipsec/sbin/nvmecontrol/nvmecontrol.c (revision 313313) @@ -1,235 +1,236 @@ /*- * Copyright (C) 2012-2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nvmecontrol.h" -typedef void (*nvme_fn_t)(int argc, char *argv[]); -static struct nvme_function { - const char *name; - nvme_fn_t fn; - const char *usage; -} funcs[] = { +static struct nvme_function funcs[] = { {"devlist", devlist, DEVLIST_USAGE}, {"identify", identify, IDENTIFY_USAGE}, {"perftest", perftest, PERFTEST_USAGE}, {"reset", reset, RESET_USAGE}, {"logpage", logpage, LOGPAGE_USAGE}, {"firmware", firmware, FIRMWARE_USAGE}, {"power", power, POWER_USAGE}, + {"wdc", wdc, WDC_USAGE}, {NULL, NULL, NULL}, }; -static void -usage(void) +void +gen_usage(struct nvme_function *f) { - struct nvme_function *f; - f = funcs; fprintf(stderr, "usage:\n"); while (f->name != NULL) { fprintf(stderr, "%s", f->usage); f++; } exit(1); } +void +dispatch(int argc, char *argv[], struct nvme_function *tbl) +{ + struct nvme_function *f = tbl; + + while (f->name != NULL) { + if (strcmp(argv[1], f->name) == 0) + f->fn(argc-1, &argv[1]); + f++; + } + + fprintf(stderr, "Unknown command: %s\n", argv[1]); + gen_usage(tbl); +} + static void print_bytes(void *data, uint32_t length) { uint32_t i, j; uint8_t *p, *end; end = (uint8_t *)data + length; for (i = 0; i < length; i++) { p = (uint8_t *)data + (i*16); printf("%03x: ", i*16); for (j = 0; j < 16 && p < end; j++) printf("%02x ", *p++); if (p >= end) break; printf("\n"); } printf("\n"); } static void print_dwords(void *data, uint32_t length) { uint32_t *p; uint32_t i, j; p = (uint32_t *)data; length /= sizeof(uint32_t); for (i = 0; i < length; i+=8) { printf("%03x: ", i*4); for (j = 0; j < 8; j++) printf("%08x ", p[i+j]); printf("\n"); } printf("\n"); } void print_hex(void *data, uint32_t length) { if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0) print_dwords(data, length); else print_bytes(data, length); } void read_controller_data(int fd, struct nvme_controller_data *cdata) { struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_IDENTIFY; pt.cmd.cdw10 = 1; pt.buf = cdata; pt.len = sizeof(*cdata); pt.is_read = 1; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "identify request failed"); if (nvme_completion_is_error(&pt.cpl)) errx(1, "identify request returned error"); } void read_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata) { struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_IDENTIFY; pt.cmd.nsid = nsid; pt.buf = nsdata; pt.len = sizeof(*nsdata); pt.is_read = 1; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "identify request failed"); if (nvme_completion_is_error(&pt.cpl)) errx(1, "identify request returned error"); } int open_dev(const char *str, int *fd, int show_error, int exit_on_error) { char full_path[64]; if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) { if (show_error) warnx("controller/namespace ids must begin with '%s'", NVME_CTRLR_PREFIX); if (exit_on_error) exit(1); else return (EINVAL); } snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str); *fd = open(full_path, O_RDWR); if (*fd < 0) { if (show_error) warn("could not open %s", full_path); if (exit_on_error) exit(1); else return (errno); } return (0); } void parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid) { char *nsloc; /* * Pull the namespace id from the string. +2 skips past the "ns" part * of the string. Don't search past 10 characters into the string, * otherwise we know it is malformed. */ nsloc = strnstr(ns_str, NVME_NS_PREFIX, 10); if (nsloc != NULL) *nsid = strtol(nsloc + 2, NULL, 10); if (nsloc == NULL || (*nsid == 0 && errno != 0)) errx(1, "invalid namespace ID '%s'", ns_str); /* * The controller string will include only the nvmX part of the * nvmeXnsY string. */ snprintf(ctrlr_str, nsloc - ns_str + 1, "%s", ns_str); } int main(int argc, char *argv[]) { - struct nvme_function *f; if (argc < 2) - usage(); + gen_usage(funcs); - f = funcs; - while (f->name != NULL) { - if (strcmp(argv[1], f->name) == 0) - f->fn(argc-1, &argv[1]); - f++; - } - - usage(); + dispatch(argc, argv, funcs); return (0); } Index: projects/ipsec/sbin/nvmecontrol/nvmecontrol.h =================================================================== --- projects/ipsec/sbin/nvmecontrol/nvmecontrol.h (revision 313312) +++ projects/ipsec/sbin/nvmecontrol/nvmecontrol.h (revision 313313) @@ -1,78 +1,92 @@ /*- * Copyright (C) 2012-2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $FreeBSD$ */ #ifndef __NVMECONTROL_H__ #define __NVMECONTROL_H__ #include +typedef void (*nvme_fn_t)(int argc, char *argv[]); + +struct nvme_function { + const char *name; + nvme_fn_t fn; + const char *usage; +}; + #define NVME_CTRLR_PREFIX "nvme" #define NVME_NS_PREFIX "ns" #define DEVLIST_USAGE \ " nvmecontrol devlist\n" #define IDENTIFY_USAGE \ " nvmecontrol identify [-x [-v]] \n" #define PERFTEST_USAGE \ " nvmecontrol perftest <-n num_threads> <-o read|write>\n" \ " <-s size_in_bytes> <-t time_in_seconds>\n" \ " <-i intr|wait> [-f refthread] [-p]\n" \ " \n" #define RESET_USAGE \ " nvmecontrol reset \n" #define LOGPAGE_USAGE \ " nvmecontrol logpage <-p page_id> [-x] \n" \ #define FIRMWARE_USAGE \ " nvmecontrol firmware [-s slot] [-f path_to_firmware] [-a] \n" #define POWER_USAGE \ " nvmecontrol power [-l] [-p new-state [-w workload-hint]] \n" +#define WDC_USAGE \ +" nvmecontrol wdc (cap-diag|drive-log|get-crash-dump|purge|purge-montior)\n" + void devlist(int argc, char *argv[]); void identify(int argc, char *argv[]); void perftest(int argc, char *argv[]); void reset(int argc, char *argv[]); void logpage(int argc, char *argv[]); void firmware(int argc, char *argv[]); void power(int argc, char *argv[]); +void wdc(int argc, char *argv[]); int open_dev(const char *str, int *fd, int show_error, int exit_on_error); void parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid); void read_controller_data(int fd, struct nvme_controller_data *cdata); void read_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata); void print_hex(void *data, uint32_t length); void read_logpage(int fd, uint8_t log_page, int nsid, void *payload, uint32_t payload_size); +void gen_usage(struct nvme_function *); +void dispatch(int argc, char *argv[], struct nvme_function *f); #endif Index: projects/ipsec/sbin/nvmecontrol/wdc.c =================================================================== --- projects/ipsec/sbin/nvmecontrol/wdc.c (nonexistent) +++ projects/ipsec/sbin/nvmecontrol/wdc.c (revision 313313) @@ -0,0 +1,342 @@ +/*- + * Copyright (c) 2017 Netflix, Inc + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nvmecontrol.h" + +#define WDC_NVME_TOC_SIZE 8 + +#define WDC_NVME_CAP_DIAG_OPCODE 0xe6 +#define WDC_NVME_CAP_DIAG_CMD 0x0000 + +#define WDC_NVME_DIAG_OPCODE 0xc6 +#define WDC_NVME_DRIVE_LOG_SIZE_CMD 0x0120 +#define WDC_NVME_DRIVE_LOG_CMD 0x0020 +#define WDC_NVME_CRASH_DUMP_SIZE_CMD 0x0320 +#define WDC_NVME_CRASH_DUMP_CMD 0x0420 +#define WDC_NVME_PFAIL_DUMP_SIZE_CMD 0x0520 +#define WDC_NVME_PFAIL_DUMP_CMD 0x0620 + +#define WDC_NVME_CLEAR_DUMP_OPCODE 0xff +#define WDC_NVME_CLEAR_CRASH_DUMP_CMD 0x0503 +#define WDC_NVME_CLEAR_PFAIL_DUMP_CMD 0x0603 + +static void wdc_cap_diag(int argc, char *argv[]); +static void wdc_drive_log(int argc, char *argv[]); +static void wdc_get_crash_dump(int argc, char *argv[]); +static void wdc_purge(int argc, char *argv[]); +static void wdc_purge_monitor(int argc, char *argv[]); + +#define WDC_CAP_DIAG_USAGE "\tnvmecontrol wdc cap-diag [-o path-template]\n" +#define WDC_DRIVE_LOG_USAGE "\tnvmecontrol wdc drive-log [-o path-template]\n" +#define WDC_GET_CRASH_DUMP_USAGE "\tnvmecontrol wdc get-crash-dump [-o path-template]\n" +#define WDC_PURGE_USAGE "\tnvmecontrol wdc purge [-o path-template]\n" +#define WDC_PURGE_MONITOR_USAGE "\tnvmecontrol wdc purge-monitor\n" + +static struct nvme_function wdc_funcs[] = { + {"cap-diag", wdc_cap_diag, WDC_CAP_DIAG_USAGE}, + {"drive-log", wdc_drive_log, WDC_DRIVE_LOG_USAGE}, + {"get-crash-dump", wdc_get_crash_dump, WDC_GET_CRASH_DUMP_USAGE}, + {"purge", wdc_purge, WDC_PURGE_USAGE}, + {"purge_monitor", wdc_purge_monitor, WDC_PURGE_MONITOR_USAGE}, + {NULL, NULL, NULL}, +}; + +static void +wdc_append_serial_name(int fd, char *buf, size_t len, const char *suffix) +{ + struct nvme_controller_data cdata; + char sn[NVME_SERIAL_NUMBER_LENGTH + 1]; + char *walker; + + len -= strlen(buf); + buf += strlen(buf); + read_controller_data(fd, &cdata); + memcpy(sn, cdata.sn, NVME_SERIAL_NUMBER_LENGTH); + walker = sn + NVME_SERIAL_NUMBER_LENGTH - 1; + while (walker > sn && *walker == ' ') + walker--; + *++walker = '\0'; + snprintf(buf, len, "%s%s.bin", sn, suffix); +} + +static void +wdc_get_data(int fd, uint32_t opcode, uint32_t len, uint32_t off, uint32_t cmd, + uint8_t *buffer, size_t buflen) +{ + struct nvme_pt_command pt; + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = opcode; + pt.cmd.cdw10 = len / sizeof(uint32_t); /* - 1 like all the others ??? */ + pt.cmd.cdw11 = off / sizeof(uint32_t); + pt.cmd.cdw12 = cmd; + pt.buf = buffer; + pt.len = buflen; + pt.is_read = 1; +// printf("opcode %#x cdw10(len) %#x cdw11(offset?) %#x cdw12(cmd/sub) %#x buflen %zd\n", +// (int)opcode, (int)cdw10, (int)cdw11, (int)cdw12, buflen); + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "wdc_get_data request failed"); + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "wdc_get_data request returned error"); +} + +static void +wdc_do_dump(int fd, char *tmpl, const char *suffix, uint32_t opcode, + uint32_t size_cmd, uint32_t cmd, int len_off) +{ + int fd2; + uint8_t *buf; + uint32_t len, offset; + ssize_t resid; + + wdc_append_serial_name(fd, tmpl, MAXPATHLEN, suffix); + + buf = aligned_alloc(PAGE_SIZE, WDC_NVME_TOC_SIZE); + if (buf == NULL) + errx(1, "Can't get buffer to get size"); + wdc_get_data(fd, opcode, WDC_NVME_TOC_SIZE, + 0, size_cmd, buf, WDC_NVME_TOC_SIZE); + len = be32dec(buf + len_off); + + if (len == 0) + errx(1, "No data for %s", suffix); + + printf("Dumping %d bytes to %s\n", len, tmpl); + /* XXX overwrite protection? */ + fd2 = open(tmpl, O_WRONLY | O_CREAT | O_TRUNC); + if (fd2 < 0) + err(1, "open %s", tmpl); + offset = 0; + buf = aligned_alloc(PAGE_SIZE, NVME_MAX_XFER_SIZE); + if (buf == NULL) + errx(1, "Can't get buffer to read dump"); + while (len > 0) { + resid = len > NVME_MAX_XFER_SIZE ? NVME_MAX_XFER_SIZE : len; + wdc_get_data(fd, opcode, resid, offset, cmd, buf, resid); + if (write(fd2, buf, resid) != resid) + err(1, "write"); + offset += resid; + len -= resid; + } + free(buf); + close(fd2); +} + +static void +wdc_do_clear_dump(int fd, uint32_t opcode, uint32_t cmd) +{ + struct nvme_pt_command pt; + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = opcode; + pt.cmd.cdw12 = cmd; + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "wdc_do_clear_dump request failed"); + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "wdc_do_clear_dump request returned error"); +} + +static void +wdc_cap_diag_usage() +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, WDC_CAP_DIAG_USAGE); + exit(1); +} + +static void +wdc_cap_diag(int argc, char *argv[]) +{ + char path_tmpl[MAXPATHLEN]; + int ch, fd; + + path_tmpl[0] = '\0'; + while ((ch = getopt(argc, argv, "o:")) != -1) { + switch ((char)ch) { + case 'o': + strlcpy(path_tmpl, optarg, MAXPATHLEN); + break; + default: + wdc_cap_diag_usage(); + } + } + /* Check that a controller was specified. */ + if (optind >= argc) + wdc_cap_diag_usage(); + open_dev(argv[optind], &fd, 1, 1); + + wdc_do_dump(fd, path_tmpl, "cap_diag", WDC_NVME_CAP_DIAG_OPCODE, + WDC_NVME_CAP_DIAG_CMD, WDC_NVME_CAP_DIAG_CMD, 4); + + close(fd); + + exit(1); +} + +static void +wdc_drive_log_usage() +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, WDC_DRIVE_LOG_USAGE); + exit(1); +} + +static void +wdc_drive_log(int argc, char *argv[]) +{ + char path_tmpl[MAXPATHLEN]; + int ch, fd; + + path_tmpl[0] = '\0'; + while ((ch = getopt(argc, argv, "o:")) != -1) { + switch ((char)ch) { + case 'o': + strlcpy(path_tmpl, optarg, MAXPATHLEN); + break; + default: + wdc_drive_log_usage(); + } + } + /* Check that a controller was specified. */ + if (optind >= argc) + wdc_drive_log_usage(); + open_dev(argv[optind], &fd, 1, 1); + + wdc_do_dump(fd, path_tmpl, "drive_log", WDC_NVME_DIAG_OPCODE, + WDC_NVME_DRIVE_LOG_SIZE_CMD, WDC_NVME_DRIVE_LOG_CMD, 0); + + close(fd); + + exit(1); +} + +static void +wdc_get_crash_dump_usage() +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, WDC_CAP_DIAG_USAGE); + exit(1); +} + +static void +wdc_get_crash_dump(int argc, char *argv[]) +{ + char path_tmpl[MAXPATHLEN]; + int ch, fd; + + while ((ch = getopt(argc, argv, "o:")) != -1) { + switch ((char)ch) { + case 'o': + strlcpy(path_tmpl, optarg, MAXPATHLEN); + break; + default: + wdc_get_crash_dump_usage(); + } + } + /* Check that a controller was specified. */ + if (optind >= argc) + wdc_get_crash_dump_usage(); + open_dev(argv[optind], &fd, 1, 1); + + wdc_do_dump(fd, path_tmpl, "crash_dump", WDC_NVME_DIAG_OPCODE, + WDC_NVME_CRASH_DUMP_SIZE_CMD, WDC_NVME_CRASH_DUMP_CMD, 0); + wdc_do_clear_dump(fd, WDC_NVME_CLEAR_DUMP_OPCODE, + WDC_NVME_CLEAR_CRASH_DUMP_CMD); +// wdc_led_beacon_disable(fd); + wdc_do_dump(fd, path_tmpl, "pfail_dump", WDC_NVME_DIAG_OPCODE, + WDC_NVME_PFAIL_DUMP_SIZE_CMD, WDC_NVME_PFAIL_DUMP_CMD, 0); + wdc_do_clear_dump(fd, WDC_NVME_CLEAR_DUMP_OPCODE, + WDC_NVME_CLEAR_PFAIL_DUMP_CMD); + + close(fd); + + exit(1); +} + +static void +wdc_purge(int argc, char *argv[]) +{ + char path_tmpl[MAXPATHLEN]; + int ch; + + while ((ch = getopt(argc, argv, "o:")) != -1) { + switch ((char)ch) { + case 'o': + strlcpy(path_tmpl, optarg, MAXPATHLEN); + break; + default: + wdc_cap_diag_usage(); + } + } + + printf("purge has not been implemented.\n"); + exit(1); +} + +static void +wdc_purge_monitor(int argc, char *argv[]) +{ + char path_tmpl[MAXPATHLEN]; + int ch; + + while ((ch = getopt(argc, argv, "o:")) != -1) { + switch ((char)ch) { + case 'o': + strlcpy(path_tmpl, optarg, MAXPATHLEN); + break; + default: + wdc_cap_diag_usage(); + } + } + + printf("purge has not been implemented.\n"); + exit(1); +} + +void +wdc(int argc, char *argv[]) +{ + + dispatch(argc, argv, wdc_funcs); +} Property changes on: projects/ipsec/sbin/nvmecontrol/wdc.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ipsec/sbin/savecore/savecore.c =================================================================== --- projects/ipsec/sbin/savecore/savecore.c (revision 313312) +++ projects/ipsec/sbin/savecore/savecore.c (revision 313313) @@ -1,948 +1,951 @@ /*- * Copyright (c) 2002 Poul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the * DARPA CHATS research program. * * 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. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * Copyright (c) 1986, 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* The size of the buffer used for I/O. */ #define BUFFERSIZE (1024*1024) #define STATUS_BAD 0 #define STATUS_GOOD 1 #define STATUS_UNKNOWN 2 static int checkfor, compress, clear, force, keep, verbose; /* flags */ static int nfound, nsaved, nerr; /* statistics */ static int maxdumps; extern FILE *zopen(const char *, const char *); static sig_atomic_t got_siginfo; static void infohandler(int); static void printheader(xo_handle_t *xo, const struct kerneldumpheader *h, const char *device, int bounds, const int status) { uint64_t dumplen; time_t t; const char *stat_str; xo_flush_h(xo); xo_emit_h(xo, "{Lwc:Dump header from device}{:dump_device/%s}\n", device); xo_emit_h(xo, "{P: }{Lwc:Architecture}{:architecture/%s}\n", h->architecture); xo_emit_h(xo, "{P: }{Lwc:Architecture Version}{:architecture_version/%u}\n", dtoh32(h->architectureversion)); dumplen = dtoh64(h->dumplength); xo_emit_h(xo, "{P: }{Lwc:Dump Length}{:dump_length_bytes/%lld}\n", (long long)dumplen); xo_emit_h(xo, "{P: }{Lwc:Blocksize}{:blocksize/%d}\n", dtoh32(h->blocksize)); t = dtoh64(h->dumptime); xo_emit_h(xo, "{P: }{Lwc:Dumptime}{:dumptime/%s}", ctime(&t)); xo_emit_h(xo, "{P: }{Lwc:Hostname}{:hostname/%s}\n", h->hostname); xo_emit_h(xo, "{P: }{Lwc:Magic}{:magic/%s}\n", h->magic); xo_emit_h(xo, "{P: }{Lwc:Version String}{:version_string/%s}", h->versionstring); xo_emit_h(xo, "{P: }{Lwc:Panic String}{:panic_string/%s}\n", h->panicstring); xo_emit_h(xo, "{P: }{Lwc:Dump Parity}{:dump_parity/%u}\n", h->parity); xo_emit_h(xo, "{P: }{Lwc:Bounds}{:bounds/%d}\n", bounds); switch(status) { case STATUS_BAD: stat_str = "bad"; break; case STATUS_GOOD: stat_str = "good"; break; default: stat_str = "unknown"; } xo_emit_h(xo, "{P: }{Lwc:Dump Status}{:dump_status/%s}\n", stat_str); xo_flush_h(xo); } static int getbounds(void) { FILE *fp; char buf[6]; int ret; ret = 0; if ((fp = fopen("bounds", "r")) == NULL) { if (verbose) printf("unable to open bounds file, using 0\n"); return (ret); } if (fgets(buf, sizeof buf, fp) == NULL) { if (feof(fp)) syslog(LOG_WARNING, "bounds file is empty, using 0"); else syslog(LOG_WARNING, "bounds file: %s", strerror(errno)); fclose(fp); return (ret); } errno = 0; ret = (int)strtol(buf, NULL, 10); if (ret == 0 && (errno == EINVAL || errno == ERANGE)) syslog(LOG_WARNING, "invalid value found in bounds, using 0"); fclose(fp); return (ret); } static void writebounds(int bounds) { FILE *fp; if ((fp = fopen("bounds", "w")) == NULL) { syslog(LOG_WARNING, "unable to write to bounds file: %m"); return; } if (verbose) printf("bounds number: %d\n", bounds); fprintf(fp, "%d\n", bounds); fclose(fp); } static bool writekey(const char *keyname, uint8_t *dumpkey, uint32_t dumpkeysize) { int fd; fd = open(keyname, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd == -1) { syslog(LOG_ERR, "Unable to open %s to write the key: %m.", keyname); return (false); } if (write(fd, dumpkey, dumpkeysize) != (ssize_t)dumpkeysize) { syslog(LOG_ERR, "Unable to write the key to %s: %m.", keyname); close(fd); return (false); } close(fd); return (true); } static off_t file_size(const char *path) { struct stat sb; /* Ignore all errors, those file may not exists. */ if (stat(path, &sb) == -1) return (0); return (sb.st_size); } static off_t saved_dump_size(int bounds) { static char path[PATH_MAX]; off_t dumpsize; dumpsize = 0; (void)snprintf(path, sizeof(path), "info.%d", bounds); dumpsize += file_size(path); (void)snprintf(path, sizeof(path), "vmcore.%d", bounds); dumpsize += file_size(path); (void)snprintf(path, sizeof(path), "vmcore.%d.gz", bounds); dumpsize += file_size(path); (void)snprintf(path, sizeof(path), "textdump.tar.%d", bounds); dumpsize += file_size(path); (void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds); dumpsize += file_size(path); return (dumpsize); } static void saved_dump_remove(int bounds) { static char path[PATH_MAX]; (void)snprintf(path, sizeof(path), "info.%d", bounds); (void)unlink(path); (void)snprintf(path, sizeof(path), "vmcore.%d", bounds); (void)unlink(path); (void)snprintf(path, sizeof(path), "vmcore.%d.gz", bounds); (void)unlink(path); (void)snprintf(path, sizeof(path), "textdump.tar.%d", bounds); (void)unlink(path); (void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds); (void)unlink(path); } static void symlinks_remove(void) { (void)unlink("info.last"); (void)unlink("key.last"); (void)unlink("vmcore.last"); (void)unlink("vmcore.last.gz"); (void)unlink("vmcore_encrypted.last"); (void)unlink("vmcore_encrypted.last.gz"); (void)unlink("textdump.tar.last"); (void)unlink("textdump.tar.last.gz"); } /* * Check that sufficient space is available on the disk that holds the * save directory. */ static int check_space(const char *savedir, off_t dumpsize, int bounds) { FILE *fp; off_t minfree, spacefree, totfree, needed; struct statfs fsbuf; char buf[100]; if (statfs(".", &fsbuf) < 0) { syslog(LOG_ERR, "%s: %m", savedir); exit(1); } spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024; if ((fp = fopen("minfree", "r")) == NULL) minfree = 0; else { if (fgets(buf, sizeof(buf), fp) == NULL) minfree = 0; else minfree = atoi(buf); (void)fclose(fp); } needed = dumpsize / 1024 + 2; /* 2 for info file */ needed -= saved_dump_size(bounds); if ((minfree > 0 ? spacefree : totfree) - needed < minfree) { syslog(LOG_WARNING, "no dump, not enough free space on device (%lld available, need %lld)", (long long)(minfree > 0 ? spacefree : totfree), (long long)needed); return (0); } if (spacefree - needed < 0) syslog(LOG_WARNING, "dump performed, but free space threshold crossed"); return (1); } #define BLOCKSIZE (1<<12) #define BLOCKMASK (~(BLOCKSIZE-1)) static int DoRegularFile(int fd, bool isencrypted, off_t dumpsize, char *buf, const char *device, const char *filename, FILE *fp) { int he, hs, nr, nw, wl; off_t dmpcnt, origsize; dmpcnt = 0; origsize = dumpsize; he = 0; while (dumpsize > 0) { wl = BUFFERSIZE; if (wl > dumpsize) wl = dumpsize; nr = read(fd, buf, wl); if (nr != wl) { if (nr == 0) syslog(LOG_WARNING, "WARNING: EOF on dump device"); else syslog(LOG_ERR, "read error on %s: %m", device); nerr++; return (-1); } if (compress || isencrypted) { nw = fwrite(buf, 1, wl, fp); } else { for (nw = 0; nw < nr; nw = he) { /* find a contiguous block of zeroes */ for (hs = nw; hs < nr; hs += BLOCKSIZE) { for (he = hs; he < nr && buf[he] == 0; ++he) /* nothing */ ; /* is the hole long enough to matter? */ if (he >= hs + BLOCKSIZE) break; } /* back down to a block boundary */ he &= BLOCKMASK; /* * 1) Don't go beyond the end of the buffer. * 2) If the end of the buffer is less than * BLOCKSIZE bytes away, we're at the end * of the file, so just grab what's left. */ if (hs + BLOCKSIZE > nr) hs = he = nr; /* * At this point, we have a partial ordering: * nw <= hs <= he <= nr * If hs > nw, buf[nw..hs] contains non-zero data. * If he > hs, buf[hs..he] is all zeroes. */ if (hs > nw) if (fwrite(buf + nw, hs - nw, 1, fp) != 1) break; if (he > hs) if (fseeko(fp, he - hs, SEEK_CUR) == -1) break; } } if (nw != wl) { syslog(LOG_ERR, "write error on %s file: %m", filename); syslog(LOG_WARNING, "WARNING: vmcore may be incomplete"); nerr++; return (-1); } if (verbose) { dmpcnt += wl; printf("%llu\r", (unsigned long long)dmpcnt); fflush(stdout); } dumpsize -= wl; if (got_siginfo) { printf("%s %.1lf%%\n", filename, (100.0 - (100.0 * (double)dumpsize / (double)origsize))); got_siginfo = 0; } } return (0); } /* * Specialized version of dump-reading logic for use with textdumps, which * are written backwards from the end of the partition, and must be reversed * before being written to the file. Textdumps are small, so do a bit less * work to optimize/sparsify. */ static int DoTextdumpFile(int fd, off_t dumpsize, off_t lasthd, char *buf, const char *device, const char *filename, FILE *fp) { int nr, nw, wl; off_t dmpcnt, totsize; totsize = dumpsize; dmpcnt = 0; wl = 512; if ((dumpsize % wl) != 0) { syslog(LOG_ERR, "textdump uneven multiple of 512 on %s", device); nerr++; return (-1); } while (dumpsize > 0) { nr = pread(fd, buf, wl, lasthd - (totsize - dumpsize) - wl); if (nr != wl) { if (nr == 0) syslog(LOG_WARNING, "WARNING: EOF on dump device"); else syslog(LOG_ERR, "read error on %s: %m", device); nerr++; return (-1); } nw = fwrite(buf, 1, wl, fp); if (nw != wl) { syslog(LOG_ERR, "write error on %s file: %m", filename); syslog(LOG_WARNING, "WARNING: textdump may be incomplete"); nerr++; return (-1); } if (verbose) { dmpcnt += wl; printf("%llu\r", (unsigned long long)dmpcnt); fflush(stdout); } dumpsize -= wl; } return (0); } static void DoFile(const char *savedir, const char *device) { xo_handle_t *xostdout, *xoinfo; static char infoname[PATH_MAX], corename[PATH_MAX], linkname[PATH_MAX]; static char keyname[PATH_MAX]; static char *buf = NULL; char *temp = NULL; struct kerneldumpheader kdhf, kdhl; uint8_t *dumpkey; off_t mediasize, dumpsize, firsthd, lasthd; FILE *info, *fp; mode_t oumask; int fd, fdinfo, error; int bounds, status; u_int sectorsize, xostyle; int istextdump; uint32_t dumpkeysize; bool isencrypted, ret; bounds = getbounds(); + dumpkey = NULL; mediasize = 0; status = STATUS_UNKNOWN; xostdout = xo_create_to_file(stdout, XO_STYLE_TEXT, 0); if (xostdout == NULL) { syslog(LOG_ERR, "%s: %m", infoname); return; } if (maxdumps > 0 && bounds == maxdumps) bounds = 0; if (buf == NULL) { buf = malloc(BUFFERSIZE); if (buf == NULL) { syslog(LOG_ERR, "%m"); return; } } if (verbose) printf("checking for kernel dump on device %s\n", device); fd = open(device, (checkfor || keep) ? O_RDONLY : O_RDWR); if (fd < 0) { syslog(LOG_ERR, "%s: %m", device); return; } error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); if (!error) error = ioctl(fd, DIOCGSECTORSIZE, §orsize); if (error) { syslog(LOG_ERR, "couldn't find media and/or sector size of %s: %m", device); goto closefd; } if (verbose) { printf("mediasize = %lld\n", (long long)mediasize); printf("sectorsize = %u\n", sectorsize); } if (sectorsize < sizeof(kdhl)) { syslog(LOG_ERR, "Sector size is less the kernel dump header %zu", sizeof(kdhl)); goto closefd; } lasthd = mediasize - sectorsize; temp = malloc(sectorsize); if (temp == NULL) { syslog(LOG_ERR, "%m"); goto closefd; } if (lseek(fd, lasthd, SEEK_SET) != lasthd || read(fd, temp, sectorsize) != (ssize_t)sectorsize) { syslog(LOG_ERR, "error reading last dump header at offset %lld in %s: %m", (long long)lasthd, device); goto closefd; } memcpy(&kdhl, temp, sizeof(kdhl)); istextdump = 0; if (strncmp(kdhl.magic, TEXTDUMPMAGIC, sizeof kdhl) == 0) { if (verbose) printf("textdump magic on last dump header on %s\n", device); istextdump = 1; if (dtoh32(kdhl.version) != KERNELDUMP_TEXT_VERSION) { syslog(LOG_ERR, "unknown version (%d) in last dump header on %s", dtoh32(kdhl.version), device); status = STATUS_BAD; if (force == 0) goto closefd; } } else if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic) == 0) { if (dtoh32(kdhl.version) != KERNELDUMPVERSION) { syslog(LOG_ERR, "unknown version (%d) in last dump header on %s", dtoh32(kdhl.version), device); status = STATUS_BAD; if (force == 0) goto closefd; } } else { if (verbose) printf("magic mismatch on last dump header on %s\n", device); status = STATUS_BAD; if (force == 0) goto closefd; if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic) == 0) { if (verbose) printf("forcing magic on %s\n", device); memcpy(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic); } else { syslog(LOG_ERR, "unable to force dump - bad magic"); goto closefd; } if (dtoh32(kdhl.version) != KERNELDUMPVERSION) { syslog(LOG_ERR, "unknown version (%d) in last dump header on %s", dtoh32(kdhl.version), device); status = STATUS_BAD; if (force == 0) goto closefd; } } nfound++; if (clear) goto nuke; if (kerneldump_parity(&kdhl)) { syslog(LOG_ERR, "parity error on last dump header on %s", device); nerr++; status = STATUS_BAD; if (force == 0) goto closefd; } dumpsize = dtoh64(kdhl.dumplength); dumpkeysize = dtoh32(kdhl.dumpkeysize); firsthd = lasthd - dumpsize - sectorsize - dumpkeysize; if (lseek(fd, firsthd, SEEK_SET) != firsthd || read(fd, temp, sectorsize) != (ssize_t)sectorsize) { syslog(LOG_ERR, "error reading first dump header at offset %lld in %s: %m", (long long)firsthd, device); nerr++; goto closefd; } memcpy(&kdhf, temp, sizeof(kdhf)); if (verbose >= 2) { printf("First dump headers:\n"); printheader(xostdout, &kdhf, device, bounds, -1); printf("\nLast dump headers:\n"); printheader(xostdout, &kdhl, device, bounds, -1); printf("\n"); } if (memcmp(&kdhl, &kdhf, sizeof(kdhl))) { syslog(LOG_ERR, "first and last dump headers disagree on %s", device); nerr++; status = STATUS_BAD; if (force == 0) goto closefd; } else { status = STATUS_GOOD; } if (checkfor) { printf("A dump exists on %s\n", device); close(fd); exit(0); } if (kdhl.panicstring[0] != '\0') syslog(LOG_ALERT, "reboot after panic: %*s", (int)sizeof(kdhl.panicstring), kdhl.panicstring); else syslog(LOG_ALERT, "reboot"); if (verbose) printf("Checking for available free space\n"); if (!check_space(savedir, dumpsize, bounds)) { nerr++; goto closefd; } writebounds(bounds + 1); saved_dump_remove(bounds); snprintf(infoname, sizeof(infoname), "info.%d", bounds); /* * Create or overwrite any existing dump header files. */ fdinfo = open(infoname, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fdinfo < 0) { syslog(LOG_ERR, "%s: %m", infoname); nerr++; goto closefd; } oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ isencrypted = (dumpkeysize > 0); if (compress) { snprintf(corename, sizeof(corename), "%s.%d.gz", istextdump ? "textdump.tar" : (isencrypted ? "vmcore_encrypted" : "vmcore"), bounds); fp = zopen(corename, "w"); } else { snprintf(corename, sizeof(corename), "%s.%d", istextdump ? "textdump.tar" : (isencrypted ? "vmcore_encrypted" : "vmcore"), bounds); fp = fopen(corename, "w"); } if (fp == NULL) { syslog(LOG_ERR, "%s: %m", corename); close(fdinfo); nerr++; goto closefd; } (void)umask(oumask); info = fdopen(fdinfo, "w"); if (info == NULL) { syslog(LOG_ERR, "fdopen failed: %m"); nerr++; goto closeall; } xostyle = xo_get_style(NULL); xoinfo = xo_create_to_file(info, xostyle, 0); if (xoinfo == NULL) { syslog(LOG_ERR, "%s: %m", infoname); nerr++; goto closeall; } xo_open_container_h(xoinfo, "crashdump"); if (verbose) printheader(xostdout, &kdhl, device, bounds, status); printheader(xoinfo, &kdhl, device, bounds, status); xo_close_container_h(xoinfo, "crashdump"); xo_flush_h(xoinfo); xo_finish_h(xoinfo); fclose(info); if (isencrypted) { dumpkey = calloc(1, dumpkeysize); if (dumpkey == NULL) { syslog(LOG_ERR, "Unable to allocate kernel dump key."); nerr++; goto closeall; } if (read(fd, dumpkey, dumpkeysize) != (ssize_t)dumpkeysize) { syslog(LOG_ERR, "Unable to read kernel dump key: %m."); nerr++; goto closeall; } snprintf(keyname, sizeof(keyname), "key.%d", bounds); ret = writekey(keyname, dumpkey, dumpkeysize); explicit_bzero(dumpkey, dumpkeysize); if (!ret) { nerr++; goto closeall; } } syslog(LOG_NOTICE, "writing %s%score to %s/%s", isencrypted ? "encrypted " : "", compress ? "compressed " : "", savedir, corename); if (istextdump) { if (DoTextdumpFile(fd, dumpsize, lasthd, buf, device, corename, fp) < 0) goto closeall; } else { if (DoRegularFile(fd, isencrypted, dumpsize, buf, device, corename, fp) < 0) { goto closeall; } } if (verbose) printf("\n"); if (fclose(fp) < 0) { syslog(LOG_ERR, "error on %s: %m", corename); nerr++; goto closefd; } symlinks_remove(); if (symlink(infoname, "info.last") == -1) { syslog(LOG_WARNING, "unable to create symlink %s/%s: %m", savedir, "info.last"); } if (isencrypted) { if (symlink(keyname, "key.last") == -1) { syslog(LOG_WARNING, "unable to create symlink %s/%s: %m", savedir, "key.last"); } } if (compress) { snprintf(linkname, sizeof(linkname), "%s.last.gz", istextdump ? "textdump.tar" : (isencrypted ? "vmcore_encrypted" : "vmcore")); } else { snprintf(linkname, sizeof(linkname), "%s.last", istextdump ? "textdump.tar" : (isencrypted ? "vmcore_encrypted" : "vmcore")); } if (symlink(corename, linkname) == -1) { syslog(LOG_WARNING, "unable to create symlink %s/%s: %m", savedir, linkname); } nsaved++; if (verbose) printf("dump saved\n"); nuke: if (!keep) { if (verbose) printf("clearing dump header\n"); memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof(kdhl.magic)); memcpy(temp, &kdhl, sizeof(kdhl)); if (lseek(fd, lasthd, SEEK_SET) != lasthd || write(fd, temp, sectorsize) != (ssize_t)sectorsize) syslog(LOG_ERR, "error while clearing the dump header: %m"); } xo_close_container_h(xostdout, "crashdump"); xo_finish_h(xostdout); + free(dumpkey); free(temp); close(fd); return; closeall: fclose(fp); closefd: + free(dumpkey); free(temp); close(fd); } static void usage(void) { xo_error("%s\n%s\n%s\n", "usage: savecore -c [-v] [device ...]", " savecore -C [-v] [device ...]", " savecore [-fkvz] [-m maxdumps] [directory [device ...]]"); exit(1); } int main(int argc, char **argv) { const char *savedir = "."; struct fstab *fsp; int i, ch, error; checkfor = compress = clear = force = keep = verbose = 0; nfound = nsaved = nerr = 0; openlog("savecore", LOG_PERROR, LOG_DAEMON); signal(SIGINFO, infohandler); argc = xo_parse_args(argc, argv); if (argc < 0) exit(1); while ((ch = getopt(argc, argv, "Ccfkm:vz")) != -1) switch(ch) { case 'C': checkfor = 1; break; case 'c': clear = 1; break; case 'f': force = 1; break; case 'k': keep = 1; break; case 'm': maxdumps = atoi(optarg); if (maxdumps <= 0) { syslog(LOG_ERR, "Invalid maxdump value"); exit(1); } break; case 'v': verbose++; break; case 'z': compress = 1; break; case '?': default: usage(); } if (checkfor && (clear || force || keep)) usage(); if (clear && (compress || keep)) usage(); if (maxdumps > 0 && (checkfor || clear)) usage(); argc -= optind; argv += optind; if (argc >= 1 && !checkfor && !clear) { error = chdir(argv[0]); if (error) { syslog(LOG_ERR, "chdir(%s): %m", argv[0]); exit(1); } savedir = argv[0]; argc--; argv++; } if (argc == 0) { for (;;) { fsp = getfsent(); if (fsp == NULL) break; if (strcmp(fsp->fs_vfstype, "swap") && strcmp(fsp->fs_vfstype, "dump")) continue; DoFile(savedir, fsp->fs_spec); } endfsent(); } else { for (i = 0; i < argc; i++) DoFile(savedir, argv[i]); } /* Emit minimal output. */ if (nfound == 0) { if (checkfor) { if (verbose) printf("No dump exists\n"); exit(1); } if (verbose) syslog(LOG_WARNING, "no dumps found"); } else if (nsaved == 0) { if (nerr != 0) { if (verbose) syslog(LOG_WARNING, "unsaved dumps found but not saved"); exit(1); } else if (verbose) syslog(LOG_WARNING, "no unsaved dumps found"); } return (0); } static void infohandler(int sig __unused) { got_siginfo = 1; } Index: projects/ipsec/sys/amd64/include/pcpu.h =================================================================== --- projects/ipsec/sys/amd64/include/pcpu.h (revision 313312) +++ projects/ipsec/sys/amd64/include/pcpu.h (revision 313313) @@ -1,262 +1,252 @@ /*- * Copyright (c) Peter Wemm * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _MACHINE_PCPU_H_ #define _MACHINE_PCPU_H_ #ifndef _SYS_CDEFS_H_ #error "sys/cdefs.h is a prerequisite for this file" #endif /* * The SMP parts are setup in pmap.c and locore.s for the BSP, and * mp_machdep.c sets up the data for the AP's to "see" when they awake. * The reason for doing it via a struct is so that an array of pointers * to each CPU's data can be set up for things like "check curproc on all * other processors" */ #define PCPU_MD_FIELDS \ char pc_monitorbuf[128] __aligned(128); /* cache line */ \ struct pcpu *pc_prvspace; /* Self-reference */ \ struct pmap *pc_curpmap; \ struct amd64tss *pc_tssp; /* TSS segment active on CPU */ \ struct amd64tss *pc_commontssp;/* Common TSS for the CPU */ \ register_t pc_rsp0; \ register_t pc_scratch_rsp; /* User %rsp in syscall */ \ u_int pc_apic_id; \ u_int pc_acpi_id; /* ACPI CPU id */ \ /* Pointer to the CPU %fs descriptor */ \ struct user_segment_descriptor *pc_fs32p; \ /* Pointer to the CPU %gs descriptor */ \ struct user_segment_descriptor *pc_gs32p; \ /* Pointer to the CPU LDT descriptor */ \ struct system_segment_descriptor *pc_ldt; \ /* Pointer to the CPU TSS descriptor */ \ struct system_segment_descriptor *pc_tss; \ uint64_t pc_pm_save_cnt; \ u_int pc_cmci_mask; /* MCx banks for CMCI */ \ uint64_t pc_dbreg[16]; /* ddb debugging regs */ \ int pc_dbreg_cmd; /* ddb debugging reg cmd */ \ u_int pc_vcpu_id; /* Xen vCPU ID */ \ uint32_t pc_pcid_next; \ uint32_t pc_pcid_gen; \ uint32_t pc_smp_tlb_done; /* TLB op acknowledgement */ \ char __pad[145] /* be divisor of PAGE_SIZE \ after cache alignment */ #define PC_DBREG_CMD_NONE 0 #define PC_DBREG_CMD_LOAD 1 #ifdef _KERNEL #ifdef lint extern struct pcpu *pcpup; -#define get_pcpu() (pcpup) #define PCPU_GET(member) (pcpup->pc_ ## member) #define PCPU_ADD(member, val) (pcpup->pc_ ## member += (val)) #define PCPU_INC(member) PCPU_ADD(member, 1) #define PCPU_PTR(member) (&pcpup->pc_ ## member) #define PCPU_SET(member, val) (pcpup->pc_ ## member = (val)) #elif defined(__GNUCLIKE_ASM) && defined(__GNUCLIKE___TYPEOF) /* * Evaluates to the byte offset of the per-cpu variable name. */ #define __pcpu_offset(name) \ __offsetof(struct pcpu, name) /* * Evaluates to the type of the per-cpu variable name. */ #define __pcpu_type(name) \ __typeof(((struct pcpu *)0)->name) /* * Evaluates to the address of the per-cpu variable name. */ #define __PCPU_PTR(name) __extension__ ({ \ __pcpu_type(name) *__p; \ \ __asm __volatile("movq %%gs:%1,%0; addq %2,%0" \ : "=r" (__p) \ : "m" (*(struct pcpu *)(__pcpu_offset(pc_prvspace))), \ "i" (__pcpu_offset(name))); \ \ __p; \ }) /* * Evaluates to the value of the per-cpu variable name. */ #define __PCPU_GET(name) __extension__ ({ \ __pcpu_type(name) __res; \ struct __s { \ u_char __b[MIN(sizeof(__pcpu_type(name)), 8)]; \ } __s; \ \ if (sizeof(__res) == 1 || sizeof(__res) == 2 || \ sizeof(__res) == 4 || sizeof(__res) == 8) { \ __asm __volatile("mov %%gs:%1,%0" \ : "=r" (__s) \ : "m" (*(struct __s *)(__pcpu_offset(name)))); \ *(struct __s *)(void *)&__res = __s; \ } else { \ __res = *__PCPU_PTR(name); \ } \ __res; \ }) /* * Adds the value to the per-cpu counter name. The implementation * must be atomic with respect to interrupts. */ #define __PCPU_ADD(name, val) do { \ __pcpu_type(name) __val; \ struct __s { \ u_char __b[MIN(sizeof(__pcpu_type(name)), 8)]; \ } __s; \ \ __val = (val); \ if (sizeof(__val) == 1 || sizeof(__val) == 2 || \ sizeof(__val) == 4 || sizeof(__val) == 8) { \ __s = *(struct __s *)(void *)&__val; \ __asm __volatile("add %1,%%gs:%0" \ : "=m" (*(struct __s *)(__pcpu_offset(name))) \ : "r" (__s)); \ } else \ *__PCPU_PTR(name) += __val; \ } while (0) /* * Increments the value of the per-cpu counter name. The implementation * must be atomic with respect to interrupts. */ #define __PCPU_INC(name) do { \ CTASSERT(sizeof(__pcpu_type(name)) == 1 || \ sizeof(__pcpu_type(name)) == 2 || \ sizeof(__pcpu_type(name)) == 4 || \ sizeof(__pcpu_type(name)) == 8); \ if (sizeof(__pcpu_type(name)) == 1) { \ __asm __volatile("incb %%gs:%0" \ : "=m" (*(__pcpu_type(name) *)(__pcpu_offset(name)))\ : "m" (*(__pcpu_type(name) *)(__pcpu_offset(name))));\ } else if (sizeof(__pcpu_type(name)) == 2) { \ __asm __volatile("incw %%gs:%0" \ : "=m" (*(__pcpu_type(name) *)(__pcpu_offset(name)))\ : "m" (*(__pcpu_type(name) *)(__pcpu_offset(name))));\ } else if (sizeof(__pcpu_type(name)) == 4) { \ __asm __volatile("incl %%gs:%0" \ : "=m" (*(__pcpu_type(name) *)(__pcpu_offset(name)))\ : "m" (*(__pcpu_type(name) *)(__pcpu_offset(name))));\ } else if (sizeof(__pcpu_type(name)) == 8) { \ __asm __volatile("incq %%gs:%0" \ : "=m" (*(__pcpu_type(name) *)(__pcpu_offset(name)))\ : "m" (*(__pcpu_type(name) *)(__pcpu_offset(name))));\ } \ } while (0) /* * Sets the value of the per-cpu variable name to value val. */ #define __PCPU_SET(name, val) { \ __pcpu_type(name) __val; \ struct __s { \ u_char __b[MIN(sizeof(__pcpu_type(name)), 8)]; \ } __s; \ \ __val = (val); \ if (sizeof(__val) == 1 || sizeof(__val) == 2 || \ sizeof(__val) == 4 || sizeof(__val) == 8) { \ __s = *(struct __s *)(void *)&__val; \ __asm __volatile("mov %1,%%gs:%0" \ : "=m" (*(struct __s *)(__pcpu_offset(name))) \ : "r" (__s)); \ } else { \ *__PCPU_PTR(name) = __val; \ } \ } - -#define get_pcpu() __extension__ ({ \ - struct pcpu *__pc; \ - \ - __asm __volatile("movq %%gs:%1,%0" \ - : "=r" (__pc) \ - : "m" (*(struct pcpu *)(__pcpu_offset(pc_prvspace)))); \ - __pc; \ -}) #define PCPU_GET(member) __PCPU_GET(pc_ ## member) #define PCPU_ADD(member, val) __PCPU_ADD(pc_ ## member, val) #define PCPU_INC(member) __PCPU_INC(pc_ ## member) #define PCPU_PTR(member) __PCPU_PTR(pc_ ## member) #define PCPU_SET(member, val) __PCPU_SET(pc_ ## member, val) #define OFFSETOF_CURTHREAD 0 #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnull-dereference" #endif static __inline __pure2 struct thread * __curthread(void) { struct thread *td; __asm("movq %%gs:%1,%0" : "=r" (td) : "m" (*(char *)OFFSETOF_CURTHREAD)); return (td); } #ifdef __clang__ #pragma clang diagnostic pop #endif #define curthread (__curthread()) #define OFFSETOF_CURPCB 32 static __inline __pure2 struct pcb * __curpcb(void) { struct pcb *pcb; __asm("movq %%gs:%1,%0" : "=r" (pcb) : "m" (*(char *)OFFSETOF_CURPCB)); return (pcb); } #define curpcb (__curpcb()) #define IS_BSP() (PCPU_GET(cpuid) == 0) #else /* !lint || defined(__GNUCLIKE_ASM) && defined(__GNUCLIKE___TYPEOF) */ #error "this file needs to be ported to your compiler" #endif /* lint, etc. */ #endif /* _KERNEL */ #endif /* !_MACHINE_PCPU_H_ */ Index: projects/ipsec/sys/amd64/linux/linux_dummy.c =================================================================== --- projects/ipsec/sys/amd64/linux/linux_dummy.c (revision 313312) +++ projects/ipsec/sys/amd64/linux/linux_dummy.c (revision 313313) @@ -1,140 +1,185 @@ /*- * Copyright (c) 2013 Dmitry Chagin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #include #include #include #include #include #include /* DTrace init */ LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); DUMMY(mincore); DUMMY(sendfile); DUMMY(ptrace); DUMMY(syslog); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(sysfs); DUMMY(vhangup); DUMMY(pivot_root); DUMMY(adjtimex); DUMMY(swapoff); DUMMY(create_module); DUMMY(init_module); DUMMY(delete_module); DUMMY(get_kernel_syms); DUMMY(query_module); DUMMY(quotactl); DUMMY(nfsservctl); DUMMY(getpmsg); DUMMY(putpmsg); DUMMY(afs_syscall); DUMMY(tuxcall); DUMMY(security); DUMMY(set_thread_area); DUMMY(lookup_dcookie); DUMMY(epoll_ctl_old); DUMMY(epoll_wait_old); DUMMY(remap_file_pages); DUMMY(semtimedop); DUMMY(mbind); DUMMY(get_mempolicy); DUMMY(set_mempolicy); DUMMY(mq_open); DUMMY(mq_unlink); DUMMY(mq_timedsend); DUMMY(mq_timedreceive); DUMMY(mq_notify); DUMMY(mq_getsetattr); DUMMY(kexec_load); +/* linux 2.6.11: */ DUMMY(add_key); DUMMY(request_key); DUMMY(keyctl); +/* linux 2.6.13: */ DUMMY(ioprio_set); DUMMY(ioprio_get); DUMMY(inotify_init); DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); +/* linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(unshare); +/* linux 2.6.17: */ DUMMY(splice); DUMMY(tee); DUMMY(sync_file_range); DUMMY(vmsplice); +/* linux 2.6.18: */ DUMMY(move_pages); +/* linux 2.6.22: */ DUMMY(signalfd); -DUMMY(timerfd); +DUMMY(timerfd_create); +/* linux 2.6.25: */ DUMMY(timerfd_settime); DUMMY(timerfd_gettime); +/* linux 2.6.27: */ DUMMY(signalfd4); DUMMY(inotify_init1); +/* linux 2.6.30: */ DUMMY(preadv); DUMMY(pwritev); -DUMMY(rt_tsigqueueinfo); +/* linux 2.6.31: */ +DUMMY(rt_tgsigqueueinfo); DUMMY(perf_event_open); +/* linux 2.6.38: */ DUMMY(fanotify_init); DUMMY(fanotify_mark); +/* linux 2.6.39: */ DUMMY(name_to_handle_at); DUMMY(open_by_handle_at); DUMMY(clock_adjtime); +/* linux 3.0: */ DUMMY(setns); +DUMMY(getcpu); +/* linux 3.2: */ DUMMY(process_vm_readv); DUMMY(process_vm_writev); +/* linux 3.5: */ DUMMY(kcmp); +/* linux 3.8: */ DUMMY(finit_module); +DUMMY(sched_setattr); +DUMMY(sched_getattr); +/* linux 3.14: */ +DUMMY(renameat2); +/* linux 3.15: */ +DUMMY(seccomp); +DUMMY(getrandom); +DUMMY(memfd_create); +DUMMY(kexec_file_load); +/* linux 3.18: */ +DUMMY(bpf); +/* linux 3.19: */ +DUMMY(execveat); +/* linux 4.2: */ +DUMMY(userfaultfd); +/* linux 4.3: */ +DUMMY(membarrier); +/* linux 4.4: */ +DUMMY(mlock2); +/* linux 4.5: */ +DUMMY(copy_file_range); +/* linux 4.6: */ +DUMMY(preadv2); +DUMMY(pwritev2); +/* linux 4.8: */ +DUMMY(pkey_mprotect); +DUMMY(pkey_alloc); +DUMMY(pkey_free); #define DUMMY_XATTR(s) \ int \ linux_ ## s ## xattr( \ struct thread *td, struct linux_ ## s ## xattr_args *arg) \ { \ \ return (ENOATTR); \ } DUMMY_XATTR(set); DUMMY_XATTR(lset); DUMMY_XATTR(fset); DUMMY_XATTR(get); DUMMY_XATTR(lget); DUMMY_XATTR(fget); DUMMY_XATTR(list); DUMMY_XATTR(llist); DUMMY_XATTR(flist); DUMMY_XATTR(remove); DUMMY_XATTR(lremove); DUMMY_XATTR(fremove); Index: projects/ipsec/sys/amd64/linux/linux_proto.h =================================================================== --- projects/ipsec/sys/amd64/linux/linux_proto.h (revision 313312) +++ projects/ipsec/sys/amd64/linux/linux_proto.h (revision 313313) @@ -1,1670 +1,1841 @@ /* * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/amd64/linux/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ #ifndef _LINUX_SYSPROTO_H_ #define _LINUX_SYSPROTO_H_ #include #include #include #include #include #include #include #include struct proc; struct thread; #define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \ 0 : sizeof(register_t) - sizeof(t)) #if BYTE_ORDER == LITTLE_ENDIAN #define PADL_(t) 0 #define PADR_(t) PAD_(t) #else #define PADL_(t) PAD_(t) #define PADR_(t) 0 #endif #define nosys linux_nosys struct linux_open_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_newstat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; }; struct linux_newfstat_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; }; struct linux_newlstat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; }; struct linux_lseek_args { char fdes_l_[PADL_(l_uint)]; l_uint fdes; char fdes_r_[PADR_(l_uint)]; char off_l_[PADL_(l_off_t)]; l_off_t off; char off_r_[PADR_(l_off_t)]; char whence_l_[PADL_(l_int)]; l_int whence; char whence_r_[PADR_(l_int)]; }; struct linux_mmap2_args { char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; char len_l_[PADL_(l_ulong)]; l_ulong len; char len_r_[PADR_(l_ulong)]; char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; char pgoff_l_[PADL_(l_ulong)]; l_ulong pgoff; char pgoff_r_[PADR_(l_ulong)]; }; struct linux_mprotect_args { char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)]; char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)]; }; struct linux_brk_args { char dsend_l_[PADL_(l_ulong)]; l_ulong dsend; char dsend_r_[PADR_(l_ulong)]; }; struct linux_rt_sigaction_args { char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char act_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * act; char act_r_[PADR_(l_sigaction_t *)]; char oact_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * oact; char oact_r_[PADR_(l_sigaction_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigprocmask_args { char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; char omask_l_[PADL_(l_sigset_t *)]; l_sigset_t * omask; char omask_r_[PADR_(l_sigset_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigreturn_args { char ucp_l_[PADL_(struct l_ucontext *)]; struct l_ucontext * ucp; char ucp_r_[PADR_(struct l_ucontext *)]; }; struct linux_ioctl_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(uintptr_t)]; uintptr_t arg; char arg_r_[PADR_(uintptr_t)]; }; struct linux_pread_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; }; struct linux_pwrite_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; }; struct linux_access_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; }; struct linux_pipe_args { char pipefds_l_[PADL_(l_ulong *)]; l_ulong * pipefds; char pipefds_r_[PADR_(l_ulong *)]; }; struct linux_select_args { char nfds_l_[PADL_(l_int)]; l_int nfds; char nfds_r_[PADR_(l_int)]; char readfds_l_[PADL_(l_fd_set *)]; l_fd_set * readfds; char readfds_r_[PADR_(l_fd_set *)]; char writefds_l_[PADL_(l_fd_set *)]; l_fd_set * writefds; char writefds_r_[PADR_(l_fd_set *)]; char exceptfds_l_[PADL_(l_fd_set *)]; l_fd_set * exceptfds; char exceptfds_r_[PADR_(l_fd_set *)]; char timeout_l_[PADL_(struct l_timeval *)]; struct l_timeval * timeout; char timeout_r_[PADR_(struct l_timeval *)]; }; struct linux_mremap_args { char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; char old_len_l_[PADL_(l_ulong)]; l_ulong old_len; char old_len_r_[PADR_(l_ulong)]; char new_len_l_[PADL_(l_ulong)]; l_ulong new_len; char new_len_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; char new_addr_l_[PADL_(l_ulong)]; l_ulong new_addr; char new_addr_r_[PADR_(l_ulong)]; }; struct linux_msync_args { char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char fl_l_[PADL_(l_int)]; l_int fl; char fl_r_[PADR_(l_int)]; }; struct linux_mincore_args { char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char vec_l_[PADL_(u_char *)]; u_char * vec; char vec_r_[PADR_(u_char *)]; }; struct linux_shmget_args { char key_l_[PADL_(l_key_t)]; l_key_t key; char key_r_[PADR_(l_key_t)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; char shmflg_l_[PADL_(l_int)]; l_int shmflg; char shmflg_r_[PADR_(l_int)]; }; struct linux_shmat_args { char shmid_l_[PADL_(l_int)]; l_int shmid; char shmid_r_[PADR_(l_int)]; char shmaddr_l_[PADL_(char *)]; char * shmaddr; char shmaddr_r_[PADR_(char *)]; char shmflg_l_[PADL_(l_int)]; l_int shmflg; char shmflg_r_[PADR_(l_int)]; }; struct linux_shmctl_args { char shmid_l_[PADL_(l_int)]; l_int shmid; char shmid_r_[PADR_(l_int)]; char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; char buf_l_[PADL_(struct l_shmid_ds *)]; struct l_shmid_ds * buf; char buf_r_[PADR_(struct l_shmid_ds *)]; }; struct linux_pause_args { register_t dummy; }; struct linux_nanosleep_args { char rqtp_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * rqtp; char rqtp_r_[PADR_(const struct l_timespec *)]; char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; }; struct linux_getitimer_args { char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; }; struct linux_alarm_args { char secs_l_[PADL_(l_uint)]; l_uint secs; char secs_r_[PADR_(l_uint)]; }; struct linux_setitimer_args { char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; char oitv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * oitv; char oitv_r_[PADR_(struct l_itimerval *)]; }; struct linux_getpid_args { register_t dummy; }; struct linux_sendfile_args { char out_l_[PADL_(int)]; int out; char out_r_[PADR_(int)]; char in_l_[PADL_(int)]; int in; char in_r_[PADR_(int)]; char offset_l_[PADL_(l_long *)]; l_long * offset; char offset_r_[PADR_(l_long *)]; char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; }; struct linux_socket_args { char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; char protocol_l_[PADL_(l_int)]; l_int protocol; char protocol_r_[PADR_(l_int)]; }; struct linux_connect_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; }; struct linux_accept_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; }; struct linux_sendto_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char to_l_[PADL_(l_uintptr_t)]; l_uintptr_t to; char to_r_[PADR_(l_uintptr_t)]; char tolen_l_[PADL_(l_int)]; l_int tolen; char tolen_r_[PADR_(l_int)]; }; struct linux_recvfrom_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char buf_l_[PADL_(l_uintptr_t)]; l_uintptr_t buf; char buf_r_[PADR_(l_uintptr_t)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char from_l_[PADL_(l_uintptr_t)]; l_uintptr_t from; char from_r_[PADR_(l_uintptr_t)]; char fromlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t fromlen; char fromlen_r_[PADR_(l_uintptr_t)]; }; struct linux_sendmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_recvmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_shutdown_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; }; struct linux_bind_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; }; struct linux_listen_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char backlog_l_[PADL_(l_int)]; l_int backlog; char backlog_r_[PADR_(l_int)]; }; struct linux_getsockname_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; }; struct linux_getpeername_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; }; struct linux_socketpair_args { char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; char protocol_l_[PADL_(l_int)]; l_int protocol; char protocol_r_[PADR_(l_int)]; char rsv_l_[PADL_(l_uintptr_t)]; l_uintptr_t rsv; char rsv_r_[PADR_(l_uintptr_t)]; }; struct linux_setsockopt_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; char optlen_l_[PADL_(l_int)]; l_int optlen; char optlen_r_[PADR_(l_int)]; }; struct linux_getsockopt_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; char optlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t optlen; char optlen_r_[PADR_(l_uintptr_t)]; }; struct linux_clone_args { char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char stack_l_[PADL_(void *)]; void * stack; char stack_r_[PADR_(void *)]; char parent_tidptr_l_[PADL_(void *)]; void * parent_tidptr; char parent_tidptr_r_[PADR_(void *)]; char child_tidptr_l_[PADL_(void *)]; void * child_tidptr; char child_tidptr_r_[PADR_(void *)]; char tls_l_[PADL_(void *)]; void * tls; char tls_r_[PADR_(void *)]; }; struct linux_fork_args { register_t dummy; }; struct linux_vfork_args { register_t dummy; }; struct linux_execve_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char argp_l_[PADL_(char **)]; char ** argp; char argp_r_[PADR_(char **)]; char envp_l_[PADL_(char **)]; char ** envp; char envp_r_[PADR_(char **)]; }; struct linux_exit_args { char rval_l_[PADL_(int)]; int rval; char rval_r_[PADR_(int)]; }; struct linux_wait4_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char status_l_[PADL_(l_int *)]; l_int * status; char status_r_[PADR_(l_int *)]; char options_l_[PADL_(l_int)]; l_int options; char options_r_[PADR_(l_int)]; char rusage_l_[PADL_(struct rusage *)]; struct rusage * rusage; char rusage_r_[PADR_(struct rusage *)]; }; struct linux_kill_args { char pid_l_[PADL_(l_int)]; l_int pid; char pid_r_[PADR_(l_int)]; char signum_l_[PADL_(l_int)]; l_int signum; char signum_r_[PADR_(l_int)]; }; struct linux_newuname_args { char buf_l_[PADL_(struct l_new_utsname *)]; struct l_new_utsname * buf; char buf_r_[PADR_(struct l_new_utsname *)]; }; struct linux_semget_args { char key_l_[PADL_(l_key_t)]; l_key_t key; char key_r_[PADR_(l_key_t)]; char nsems_l_[PADL_(l_int)]; l_int nsems; char nsems_r_[PADR_(l_int)]; char semflg_l_[PADL_(l_int)]; l_int semflg; char semflg_r_[PADR_(l_int)]; }; struct linux_semop_args { char semid_l_[PADL_(l_int)]; l_int semid; char semid_r_[PADR_(l_int)]; char tsops_l_[PADL_(struct l_sembuf *)]; struct l_sembuf * tsops; char tsops_r_[PADR_(struct l_sembuf *)]; char nsops_l_[PADL_(l_uint)]; l_uint nsops; char nsops_r_[PADR_(l_uint)]; }; struct linux_semctl_args { char semid_l_[PADL_(l_int)]; l_int semid; char semid_r_[PADR_(l_int)]; char semnum_l_[PADL_(l_int)]; l_int semnum; char semnum_r_[PADR_(l_int)]; char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; char arg_l_[PADL_(union l_semun)]; union l_semun arg; char arg_r_[PADR_(union l_semun)]; }; struct linux_shmdt_args { char shmaddr_l_[PADL_(char *)]; char * shmaddr; char shmaddr_r_[PADR_(char *)]; }; struct linux_msgget_args { char key_l_[PADL_(l_key_t)]; l_key_t key; char key_r_[PADR_(l_key_t)]; char msgflg_l_[PADL_(l_int)]; l_int msgflg; char msgflg_r_[PADR_(l_int)]; }; struct linux_msgsnd_args { char msqid_l_[PADL_(l_int)]; l_int msqid; char msqid_r_[PADR_(l_int)]; char msgp_l_[PADL_(struct l_msgbuf *)]; struct l_msgbuf * msgp; char msgp_r_[PADR_(struct l_msgbuf *)]; char msgsz_l_[PADL_(l_size_t)]; l_size_t msgsz; char msgsz_r_[PADR_(l_size_t)]; char msgflg_l_[PADL_(l_int)]; l_int msgflg; char msgflg_r_[PADR_(l_int)]; }; struct linux_msgrcv_args { char msqid_l_[PADL_(l_int)]; l_int msqid; char msqid_r_[PADR_(l_int)]; char msgp_l_[PADL_(struct l_msgbuf *)]; struct l_msgbuf * msgp; char msgp_r_[PADR_(struct l_msgbuf *)]; char msgsz_l_[PADL_(l_size_t)]; l_size_t msgsz; char msgsz_r_[PADR_(l_size_t)]; char msgtyp_l_[PADL_(l_long)]; l_long msgtyp; char msgtyp_r_[PADR_(l_long)]; char msgflg_l_[PADL_(l_int)]; l_int msgflg; char msgflg_r_[PADR_(l_int)]; }; struct linux_msgctl_args { char msqid_l_[PADL_(l_int)]; l_int msqid; char msqid_r_[PADR_(l_int)]; char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; char buf_l_[PADL_(struct l_msqid_ds *)]; struct l_msqid_ds * buf; char buf_r_[PADR_(struct l_msqid_ds *)]; }; struct linux_fcntl_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(l_ulong)]; l_ulong arg; char arg_r_[PADR_(l_ulong)]; }; struct linux_fdatasync_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; }; struct linux_truncate_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char length_l_[PADL_(l_ulong)]; l_ulong length; char length_r_[PADR_(l_ulong)]; }; struct linux_ftruncate_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char length_l_[PADL_(l_long)]; l_long length; char length_r_[PADR_(l_long)]; }; struct linux_getdents_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char dent_l_[PADL_(void *)]; void * dent; char dent_r_[PADR_(void *)]; char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; }; struct linux_getcwd_args { char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)]; }; struct linux_chdir_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_rename_args { char from_l_[PADL_(char *)]; char * from; char from_r_[PADR_(char *)]; char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; }; struct linux_mkdir_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_rmdir_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_creat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_link_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; }; struct linux_unlink_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_symlink_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; }; struct linux_readlink_args { char name_l_[PADL_(char *)]; char * name; char name_r_[PADR_(char *)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char count_l_[PADL_(l_int)]; l_int count; char count_r_[PADR_(l_int)]; }; struct linux_chmod_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; }; struct linux_chown_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_lchown_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_getrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; }; struct linux_sysinfo_args { char info_l_[PADL_(struct l_sysinfo *)]; struct l_sysinfo * info; char info_r_[PADR_(struct l_sysinfo *)]; }; struct linux_times_args { char buf_l_[PADL_(struct l_times_argv *)]; struct l_times_argv * buf; char buf_r_[PADR_(struct l_times_argv *)]; }; struct linux_ptrace_args { char req_l_[PADL_(l_long)]; l_long req; char req_r_[PADR_(l_long)]; char pid_l_[PADL_(l_long)]; l_long pid; char pid_r_[PADR_(l_long)]; char addr_l_[PADL_(l_long)]; l_long addr; char addr_r_[PADR_(l_long)]; char data_l_[PADL_(l_long)]; l_long data; char data_r_[PADR_(l_long)]; }; struct linux_getuid_args { register_t dummy; }; struct linux_syslog_args { char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; }; struct linux_getgid_args { register_t dummy; }; struct linux_getppid_args { register_t dummy; }; struct linux_getgroups_args { char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; }; struct linux_setgroups_args { char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; }; struct linux_setfsuid_args { char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; }; struct linux_setfsgid_args { char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_getsid_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; }; struct linux_capget_args { char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; }; struct linux_capset_args { char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; }; struct linux_rt_sigpending_args { char set_l_[PADL_(l_sigset_t *)]; l_sigset_t * set; char set_r_[PADR_(l_sigset_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigtimedwait_args { char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; char ptr_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * ptr; char ptr_r_[PADR_(l_siginfo_t *)]; char timeout_l_[PADL_(struct l_timeval *)]; struct l_timeval * timeout; char timeout_r_[PADR_(struct l_timeval *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigqueueinfo_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; }; struct linux_rt_sigsuspend_args { char newset_l_[PADL_(l_sigset_t *)]; l_sigset_t * newset; char newset_r_[PADR_(l_sigset_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_sigaltstack_args { char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)]; char uoss_l_[PADL_(l_stack_t *)]; l_stack_t * uoss; char uoss_r_[PADR_(l_stack_t *)]; }; struct linux_utime_args { char fname_l_[PADL_(char *)]; char * fname; char fname_r_[PADR_(char *)]; char times_l_[PADL_(struct l_utimbuf *)]; struct l_utimbuf * times; char times_r_[PADR_(struct l_utimbuf *)]; }; struct linux_mknod_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char dev_l_[PADL_(l_dev_t)]; l_dev_t dev; char dev_r_[PADR_(l_dev_t)]; }; struct linux_personality_args { char per_l_[PADL_(l_uint)]; l_uint per; char per_r_[PADR_(l_uint)]; }; struct linux_ustat_args { char dev_l_[PADL_(l_dev_t)]; l_dev_t dev; char dev_r_[PADR_(l_dev_t)]; char ubuf_l_[PADL_(struct l_ustat *)]; struct l_ustat * ubuf; char ubuf_r_[PADR_(struct l_ustat *)]; }; struct linux_statfs_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; }; struct linux_fstatfs_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; }; struct linux_sysfs_args { char option_l_[PADL_(l_int)]; l_int option; char option_r_[PADR_(l_int)]; char arg1_l_[PADL_(l_ulong)]; l_ulong arg1; char arg1_r_[PADR_(l_ulong)]; char arg2_l_[PADL_(l_ulong)]; l_ulong arg2; char arg2_r_[PADR_(l_ulong)]; }; struct linux_getpriority_args { char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)]; char who_l_[PADL_(int)]; int who; char who_r_[PADR_(int)]; }; struct linux_sched_setparam_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; }; struct linux_sched_getparam_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; }; struct linux_sched_setscheduler_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; }; struct linux_sched_getscheduler_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; }; struct linux_sched_get_priority_max_args { char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; }; struct linux_sched_get_priority_min_args { char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; }; struct linux_sched_rr_get_interval_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char interval_l_[PADL_(struct l_timespec *)]; struct l_timespec * interval; char interval_r_[PADR_(struct l_timespec *)]; }; struct linux_vhangup_args { register_t dummy; }; struct linux_pivot_root_args { register_t dummy; }; struct linux_sysctl_args { char args_l_[PADL_(struct l___sysctl_args *)]; struct l___sysctl_args * args; char args_r_[PADR_(struct l___sysctl_args *)]; }; struct linux_prctl_args { char option_l_[PADL_(l_int)]; l_int option; char option_r_[PADR_(l_int)]; char arg2_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg2; char arg2_r_[PADR_(l_uintptr_t)]; char arg3_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg3; char arg3_r_[PADR_(l_uintptr_t)]; char arg4_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg4; char arg4_r_[PADR_(l_uintptr_t)]; char arg5_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg5; char arg5_r_[PADR_(l_uintptr_t)]; }; struct linux_arch_prctl_args { char code_l_[PADL_(l_int)]; l_int code; char code_r_[PADR_(l_int)]; char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; }; struct linux_adjtimex_args { register_t dummy; }; struct linux_setrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; }; struct linux_mount_args { char specialfile_l_[PADL_(char *)]; char * specialfile; char specialfile_r_[PADR_(char *)]; char dir_l_[PADL_(char *)]; char * dir; char dir_r_[PADR_(char *)]; char filesystemtype_l_[PADL_(char *)]; char * filesystemtype; char filesystemtype_r_[PADR_(char *)]; char rwflag_l_[PADL_(l_ulong)]; l_ulong rwflag; char rwflag_r_[PADR_(l_ulong)]; char data_l_[PADL_(void *)]; void * data; char data_r_[PADR_(void *)]; }; struct linux_umount_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_swapoff_args { register_t dummy; }; struct linux_reboot_args { char magic1_l_[PADL_(l_int)]; l_int magic1; char magic1_r_[PADR_(l_int)]; char magic2_l_[PADL_(l_int)]; l_int magic2; char magic2_r_[PADR_(l_int)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(void *)]; void * arg; char arg_r_[PADR_(void *)]; }; struct linux_sethostname_args { char hostname_l_[PADL_(char *)]; char * hostname; char hostname_r_[PADR_(char *)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; }; struct linux_setdomainname_args { char name_l_[PADL_(char *)]; char * name; char name_r_[PADR_(char *)]; char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; }; struct linux_iopl_args { char level_l_[PADL_(l_uint)]; l_uint level; char level_r_[PADR_(l_uint)]; }; struct linux_create_module_args { register_t dummy; }; struct linux_init_module_args { register_t dummy; }; struct linux_delete_module_args { register_t dummy; }; struct linux_get_kernel_syms_args { register_t dummy; }; struct linux_query_module_args { register_t dummy; }; struct linux_quotactl_args { register_t dummy; }; struct linux_nfsservctl_args { register_t dummy; }; struct linux_getpmsg_args { register_t dummy; }; struct linux_putpmsg_args { register_t dummy; }; struct linux_afs_syscall_args { register_t dummy; }; struct linux_tuxcall_args { register_t dummy; }; struct linux_security_args { register_t dummy; }; struct linux_gettid_args { register_t dummy; }; struct linux_setxattr_args { register_t dummy; }; struct linux_lsetxattr_args { register_t dummy; }; struct linux_fsetxattr_args { register_t dummy; }; struct linux_getxattr_args { register_t dummy; }; struct linux_lgetxattr_args { register_t dummy; }; struct linux_fgetxattr_args { register_t dummy; }; struct linux_listxattr_args { register_t dummy; }; struct linux_llistxattr_args { register_t dummy; }; struct linux_flistxattr_args { register_t dummy; }; struct linux_removexattr_args { register_t dummy; }; struct linux_lremovexattr_args { register_t dummy; }; struct linux_fremovexattr_args { register_t dummy; }; struct linux_tkill_args { char tid_l_[PADL_(int)]; int tid; char tid_r_[PADR_(int)]; char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; struct linux_time_args { char tm_l_[PADL_(l_time_t *)]; l_time_t * tm; char tm_r_[PADR_(l_time_t *)]; }; struct linux_sys_futex_args { char uaddr_l_[PADL_(void *)]; void * uaddr; char uaddr_r_[PADR_(void *)]; char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)]; char val_l_[PADL_(int)]; int val; char val_r_[PADR_(int)]; char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; char uaddr2_l_[PADL_(void *)]; void * uaddr2; char uaddr2_r_[PADR_(void *)]; char val3_l_[PADL_(int)]; int val3; char val3_r_[PADR_(int)]; }; struct linux_sched_setaffinity_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; }; struct linux_sched_getaffinity_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; }; struct linux_set_thread_area_args { register_t dummy; }; struct linux_lookup_dcookie_args { register_t dummy; }; struct linux_epoll_create_args { char size_l_[PADL_(l_int)]; l_int size; char size_r_[PADR_(l_int)]; }; struct linux_epoll_ctl_old_args { register_t dummy; }; struct linux_epoll_wait_old_args { register_t dummy; }; struct linux_remap_file_pages_args { register_t dummy; }; struct linux_getdents64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char dirent_l_[PADL_(void *)]; void * dirent; char dirent_r_[PADR_(void *)]; char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; }; struct linux_set_tid_address_args { char tidptr_l_[PADL_(int *)]; int * tidptr; char tidptr_r_[PADR_(int *)]; }; struct linux_semtimedop_args { register_t dummy; }; struct linux_fadvise64_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char advice_l_[PADL_(int)]; int advice; char advice_r_[PADR_(int)]; }; struct linux_timer_create_args { char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)]; char evp_l_[PADL_(struct sigevent *)]; struct sigevent * evp; char evp_r_[PADR_(struct sigevent *)]; char timerid_l_[PADL_(l_timer_t *)]; l_timer_t * timerid; char timerid_r_[PADR_(l_timer_t *)]; }; struct linux_timer_settime_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char new_l_[PADL_(const struct itimerspec *)]; const struct itimerspec * new; char new_r_[PADR_(const struct itimerspec *)]; char old_l_[PADL_(struct itimerspec *)]; struct itimerspec * old; char old_r_[PADR_(struct itimerspec *)]; }; struct linux_timer_gettime_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; char setting_l_[PADL_(struct itimerspec *)]; struct itimerspec * setting; char setting_r_[PADR_(struct itimerspec *)]; }; struct linux_timer_getoverrun_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; }; struct linux_timer_delete_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; }; struct linux_clock_settime_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; }; struct linux_clock_gettime_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; }; struct linux_clock_getres_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; }; struct linux_clock_nanosleep_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; char rqtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rqtp; char rqtp_r_[PADR_(struct l_timespec *)]; char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; }; struct linux_exit_group_args { char error_code_l_[PADL_(int)]; int error_code; char error_code_r_[PADR_(int)]; }; struct linux_epoll_wait_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; char timeout_l_[PADL_(l_int)]; l_int timeout; char timeout_r_[PADR_(l_int)]; }; struct linux_epoll_ctl_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char op_l_[PADL_(l_int)]; l_int op; char op_r_[PADR_(l_int)]; char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char event_l_[PADL_(struct epoll_event *)]; struct epoll_event * event; char event_r_[PADR_(struct epoll_event *)]; }; struct linux_tgkill_args { char tgid_l_[PADL_(int)]; int tgid; char tgid_r_[PADR_(int)]; char pid_l_[PADL_(int)]; int pid; char pid_r_[PADR_(int)]; char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; struct linux_utimes_args { char fname_l_[PADL_(char *)]; char * fname; char fname_r_[PADR_(char *)]; char tptr_l_[PADL_(struct l_timeval *)]; struct l_timeval * tptr; char tptr_r_[PADR_(struct l_timeval *)]; }; struct linux_mbind_args { register_t dummy; }; struct linux_set_mempolicy_args { register_t dummy; }; struct linux_get_mempolicy_args { register_t dummy; }; struct linux_mq_open_args { register_t dummy; }; struct linux_mq_unlink_args { register_t dummy; }; struct linux_mq_timedsend_args { register_t dummy; }; struct linux_mq_timedreceive_args { register_t dummy; }; struct linux_mq_notify_args { register_t dummy; }; struct linux_mq_getsetattr_args { register_t dummy; }; struct linux_kexec_load_args { register_t dummy; }; struct linux_waitid_args { char idtype_l_[PADL_(int)]; int idtype; char idtype_r_[PADR_(int)]; char id_l_[PADL_(l_pid_t)]; l_pid_t id; char id_r_[PADR_(l_pid_t)]; char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)]; char rusage_l_[PADL_(struct rusage *)]; struct rusage * rusage; char rusage_r_[PADR_(struct rusage *)]; }; struct linux_add_key_args { register_t dummy; }; struct linux_request_key_args { register_t dummy; }; struct linux_keyctl_args { register_t dummy; }; struct linux_ioprio_set_args { register_t dummy; }; struct linux_ioprio_get_args { register_t dummy; }; struct linux_inotify_init_args { register_t dummy; }; struct linux_inotify_add_watch_args { register_t dummy; }; struct linux_inotify_rm_watch_args { register_t dummy; }; struct linux_migrate_pages_args { register_t dummy; }; struct linux_openat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_mkdirat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_mknodat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char dev_l_[PADL_(l_uint)]; l_uint dev; char dev_r_[PADR_(l_uint)]; }; struct linux_fchownat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_futimesat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)]; char utimes_l_[PADL_(struct l_timeval *)]; struct l_timeval * utimes; char utimes_r_[PADR_(struct l_timeval *)]; }; struct linux_newfstatat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)]; char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_unlinkat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_renameat_args { char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; }; struct linux_linkat_args { char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_symlinkat_args { char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; }; struct linux_readlinkat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char bufsiz_l_[PADL_(l_int)]; l_int bufsiz; char bufsiz_r_[PADR_(l_int)]; }; struct linux_fchmodat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; }; struct linux_faccessat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; }; struct linux_pselect6_args { char nfds_l_[PADL_(l_int)]; l_int nfds; char nfds_r_[PADR_(l_int)]; char readfds_l_[PADL_(l_fd_set *)]; l_fd_set * readfds; char readfds_r_[PADR_(l_fd_set *)]; char writefds_l_[PADL_(l_fd_set *)]; l_fd_set * writefds; char writefds_r_[PADR_(l_fd_set *)]; char exceptfds_l_[PADL_(l_fd_set *)]; l_fd_set * exceptfds; char exceptfds_r_[PADR_(l_fd_set *)]; char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; char sig_l_[PADL_(l_uintptr_t *)]; l_uintptr_t * sig; char sig_r_[PADR_(l_uintptr_t *)]; }; struct linux_ppoll_args { char fds_l_[PADL_(struct pollfd *)]; struct pollfd * fds; char fds_r_[PADR_(struct pollfd *)]; char nfds_l_[PADL_(uint32_t)]; uint32_t nfds; char nfds_r_[PADR_(uint32_t)]; char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; char sset_l_[PADL_(l_sigset_t *)]; l_sigset_t * sset; char sset_r_[PADR_(l_sigset_t *)]; char ssize_l_[PADL_(l_size_t)]; l_size_t ssize; char ssize_r_[PADR_(l_size_t)]; }; struct linux_unshare_args { register_t dummy; }; struct linux_set_robust_list_args { char head_l_[PADL_(struct linux_robust_list_head *)]; struct linux_robust_list_head * head; char head_r_[PADR_(struct linux_robust_list_head *)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; }; struct linux_get_robust_list_args { char pid_l_[PADL_(l_int)]; l_int pid; char pid_r_[PADR_(l_int)]; char head_l_[PADL_(struct linux_robust_list_head **)]; struct linux_robust_list_head ** head; char head_r_[PADR_(struct linux_robust_list_head **)]; char len_l_[PADL_(l_size_t *)]; l_size_t * len; char len_r_[PADR_(l_size_t *)]; }; struct linux_splice_args { register_t dummy; }; struct linux_tee_args { register_t dummy; }; struct linux_sync_file_range_args { register_t dummy; }; struct linux_vmsplice_args { register_t dummy; }; struct linux_move_pages_args { register_t dummy; }; struct linux_utimensat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; char times_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * times; char times_r_[PADR_(const struct l_timespec *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_epoll_pwait_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; char timeout_l_[PADL_(l_int)]; l_int timeout; char timeout_r_[PADR_(l_int)]; char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; }; struct linux_signalfd_args { register_t dummy; }; -struct linux_timerfd_args { +struct linux_timerfd_create_args { register_t dummy; }; struct linux_eventfd_args { char initval_l_[PADL_(l_uint)]; l_uint initval; char initval_r_[PADR_(l_uint)]; }; struct linux_fallocate_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; char len_l_[PADL_(l_loff_t)]; l_loff_t len; char len_r_[PADR_(l_loff_t)]; }; struct linux_timerfd_settime_args { register_t dummy; }; struct linux_timerfd_gettime_args { register_t dummy; }; struct linux_accept4_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; }; struct linux_signalfd4_args { register_t dummy; }; struct linux_eventfd2_args { char initval_l_[PADL_(l_uint)]; l_uint initval; char initval_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_epoll_create1_args { char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_dup3_args { char oldfd_l_[PADL_(l_int)]; l_int oldfd; char oldfd_r_[PADR_(l_int)]; char newfd_l_[PADL_(l_int)]; l_int newfd; char newfd_r_[PADR_(l_int)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_pipe2_args { char pipefds_l_[PADL_(l_int *)]; l_int * pipefds; char pipefds_r_[PADR_(l_int *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_inotify_init1_args { - register_t dummy; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_preadv_args { - register_t dummy; + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; }; struct linux_pwritev_args { - register_t dummy; + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; }; -struct linux_rt_tsigqueueinfo_args { - register_t dummy; +struct linux_rt_tgsigqueueinfo_args { + char tgid_l_[PADL_(l_pid_t)]; l_pid_t tgid; char tgid_r_[PADR_(l_pid_t)]; + char tid_l_[PADL_(l_pid_t)]; l_pid_t tid; char tid_r_[PADR_(l_pid_t)]; + char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; + char uinfo_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * uinfo; char uinfo_r_[PADR_(l_siginfo_t *)]; }; struct linux_perf_event_open_args { register_t dummy; }; struct linux_recvmmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; }; struct linux_fanotify_init_args { register_t dummy; }; struct linux_fanotify_mark_args { register_t dummy; }; struct linux_prlimit64_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char new_l_[PADL_(struct rlimit *)]; struct rlimit * new; char new_r_[PADR_(struct rlimit *)]; char old_l_[PADL_(struct rlimit *)]; struct rlimit * old; char old_r_[PADR_(struct rlimit *)]; }; struct linux_name_to_handle_at_args { register_t dummy; }; struct linux_open_by_handle_at_args { register_t dummy; }; struct linux_clock_adjtime_args { register_t dummy; }; struct linux_syncfs_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; }; struct linux_sendmmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_setns_args { - register_t dummy; + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char nstype_l_[PADL_(l_int)]; l_int nstype; char nstype_r_[PADR_(l_int)]; }; +struct linux_getcpu_args { + char cpu_l_[PADL_(l_uint *)]; l_uint * cpu; char cpu_r_[PADR_(l_uint *)]; + char node_l_[PADL_(l_uint *)]; l_uint * node; char node_r_[PADR_(l_uint *)]; + char cache_l_[PADL_(void *)]; void * cache; char cache_r_[PADR_(void *)]; +}; struct linux_process_vm_readv_args { - register_t dummy; + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; + char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; }; struct linux_process_vm_writev_args { - register_t dummy; + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; + char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; }; struct linux_kcmp_args { - register_t dummy; + char pid1_l_[PADL_(l_pid_t)]; l_pid_t pid1; char pid1_r_[PADR_(l_pid_t)]; + char pid2_l_[PADL_(l_pid_t)]; l_pid_t pid2; char pid2_r_[PADR_(l_pid_t)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char idx1_l_[PADL_(l_ulong)]; l_ulong idx1; char idx1_r_[PADR_(l_ulong)]; + char idx_l_[PADL_(l_ulong)]; l_ulong idx; char idx_r_[PADR_(l_ulong)]; }; struct linux_finit_module_args { - register_t dummy; + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; +struct linux_sched_setattr_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_sched_getattr_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_renameat2_args { + char oldfd_l_[PADL_(l_int)]; l_int oldfd; char oldfd_r_[PADR_(l_int)]; + char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char newfd_l_[PADL_(l_int)]; l_int newfd; char newfd_r_[PADR_(l_int)]; + char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; + char flags_l_[PADL_(unsigned int)]; unsigned int flags; char flags_r_[PADR_(unsigned int)]; +}; +struct linux_seccomp_args { + char op_l_[PADL_(l_uint)]; l_uint op; char op_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; + char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; +}; +struct linux_getrandom_args { + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_memfd_create_args { + char uname_ptr_l_[PADL_(const char *)]; const char * uname_ptr; char uname_ptr_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_kexec_file_load_args { + char kernel_fd_l_[PADL_(l_int)]; l_int kernel_fd; char kernel_fd_r_[PADR_(l_int)]; + char initrd_fd_l_[PADL_(l_int)]; l_int initrd_fd; char initrd_fd_r_[PADR_(l_int)]; + char cmdline_len_l_[PADL_(l_ulong)]; l_ulong cmdline_len; char cmdline_len_r_[PADR_(l_ulong)]; + char cmdline_ptr_l_[PADL_(const char *)]; const char * cmdline_ptr; char cmdline_ptr_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; +}; +struct linux_bpf_args { + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; +}; +struct linux_execveat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char argv_l_[PADL_(const char **)]; const char ** argv; char argv_r_[PADR_(const char **)]; + char envp_l_[PADL_(const char **)]; const char ** envp; char envp_r_[PADR_(const char **)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_userfaultfd_args { + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_membarrier_args { + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_mlock2_args { + char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_copy_file_range_args { + char fd_in_l_[PADL_(l_int)]; l_int fd_in; char fd_in_r_[PADR_(l_int)]; + char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char fd_out_l_[PADL_(l_int)]; l_int fd_out; char fd_out_r_[PADR_(l_int)]; + char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_preadv2_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_pwritev2_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_pkey_mprotect_args { + char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; + char pkey_l_[PADL_(l_int)]; l_int pkey; char pkey_r_[PADR_(l_int)]; +}; +struct linux_pkey_alloc_args { + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; + char init_val_l_[PADL_(l_ulong)]; l_ulong init_val; char init_val_r_[PADR_(l_ulong)]; +}; +struct linux_pkey_free_args { + char pkey_l_[PADL_(l_int)]; l_int pkey; char pkey_r_[PADR_(l_int)]; +}; #define nosys linux_nosys int linux_open(struct thread *, struct linux_open_args *); int linux_newstat(struct thread *, struct linux_newstat_args *); int linux_newfstat(struct thread *, struct linux_newfstat_args *); int linux_newlstat(struct thread *, struct linux_newlstat_args *); int linux_lseek(struct thread *, struct linux_lseek_args *); int linux_mmap2(struct thread *, struct linux_mmap2_args *); int linux_mprotect(struct thread *, struct linux_mprotect_args *); int linux_brk(struct thread *, struct linux_brk_args *); int linux_rt_sigaction(struct thread *, struct linux_rt_sigaction_args *); int linux_rt_sigprocmask(struct thread *, struct linux_rt_sigprocmask_args *); int linux_rt_sigreturn(struct thread *, struct linux_rt_sigreturn_args *); int linux_ioctl(struct thread *, struct linux_ioctl_args *); int linux_pread(struct thread *, struct linux_pread_args *); int linux_pwrite(struct thread *, struct linux_pwrite_args *); int linux_access(struct thread *, struct linux_access_args *); int linux_pipe(struct thread *, struct linux_pipe_args *); int linux_select(struct thread *, struct linux_select_args *); int linux_mremap(struct thread *, struct linux_mremap_args *); int linux_msync(struct thread *, struct linux_msync_args *); int linux_mincore(struct thread *, struct linux_mincore_args *); int linux_shmget(struct thread *, struct linux_shmget_args *); int linux_shmat(struct thread *, struct linux_shmat_args *); int linux_shmctl(struct thread *, struct linux_shmctl_args *); int linux_pause(struct thread *, struct linux_pause_args *); int linux_nanosleep(struct thread *, struct linux_nanosleep_args *); int linux_getitimer(struct thread *, struct linux_getitimer_args *); int linux_alarm(struct thread *, struct linux_alarm_args *); int linux_setitimer(struct thread *, struct linux_setitimer_args *); int linux_getpid(struct thread *, struct linux_getpid_args *); int linux_sendfile(struct thread *, struct linux_sendfile_args *); int linux_socket(struct thread *, struct linux_socket_args *); int linux_connect(struct thread *, struct linux_connect_args *); int linux_accept(struct thread *, struct linux_accept_args *); int linux_sendto(struct thread *, struct linux_sendto_args *); int linux_recvfrom(struct thread *, struct linux_recvfrom_args *); int linux_sendmsg(struct thread *, struct linux_sendmsg_args *); int linux_recvmsg(struct thread *, struct linux_recvmsg_args *); int linux_shutdown(struct thread *, struct linux_shutdown_args *); int linux_bind(struct thread *, struct linux_bind_args *); int linux_listen(struct thread *, struct linux_listen_args *); int linux_getsockname(struct thread *, struct linux_getsockname_args *); int linux_getpeername(struct thread *, struct linux_getpeername_args *); int linux_socketpair(struct thread *, struct linux_socketpair_args *); int linux_setsockopt(struct thread *, struct linux_setsockopt_args *); int linux_getsockopt(struct thread *, struct linux_getsockopt_args *); int linux_clone(struct thread *, struct linux_clone_args *); int linux_fork(struct thread *, struct linux_fork_args *); int linux_vfork(struct thread *, struct linux_vfork_args *); int linux_execve(struct thread *, struct linux_execve_args *); int linux_exit(struct thread *, struct linux_exit_args *); int linux_wait4(struct thread *, struct linux_wait4_args *); int linux_kill(struct thread *, struct linux_kill_args *); int linux_newuname(struct thread *, struct linux_newuname_args *); int linux_semget(struct thread *, struct linux_semget_args *); int linux_semop(struct thread *, struct linux_semop_args *); int linux_semctl(struct thread *, struct linux_semctl_args *); int linux_shmdt(struct thread *, struct linux_shmdt_args *); int linux_msgget(struct thread *, struct linux_msgget_args *); int linux_msgsnd(struct thread *, struct linux_msgsnd_args *); int linux_msgrcv(struct thread *, struct linux_msgrcv_args *); int linux_msgctl(struct thread *, struct linux_msgctl_args *); int linux_fcntl(struct thread *, struct linux_fcntl_args *); int linux_fdatasync(struct thread *, struct linux_fdatasync_args *); int linux_truncate(struct thread *, struct linux_truncate_args *); int linux_ftruncate(struct thread *, struct linux_ftruncate_args *); int linux_getdents(struct thread *, struct linux_getdents_args *); int linux_getcwd(struct thread *, struct linux_getcwd_args *); int linux_chdir(struct thread *, struct linux_chdir_args *); int linux_rename(struct thread *, struct linux_rename_args *); int linux_mkdir(struct thread *, struct linux_mkdir_args *); int linux_rmdir(struct thread *, struct linux_rmdir_args *); int linux_creat(struct thread *, struct linux_creat_args *); int linux_link(struct thread *, struct linux_link_args *); int linux_unlink(struct thread *, struct linux_unlink_args *); int linux_symlink(struct thread *, struct linux_symlink_args *); int linux_readlink(struct thread *, struct linux_readlink_args *); int linux_chmod(struct thread *, struct linux_chmod_args *); int linux_chown(struct thread *, struct linux_chown_args *); int linux_lchown(struct thread *, struct linux_lchown_args *); int linux_getrlimit(struct thread *, struct linux_getrlimit_args *); int linux_sysinfo(struct thread *, struct linux_sysinfo_args *); int linux_times(struct thread *, struct linux_times_args *); int linux_ptrace(struct thread *, struct linux_ptrace_args *); int linux_getuid(struct thread *, struct linux_getuid_args *); int linux_syslog(struct thread *, struct linux_syslog_args *); int linux_getgid(struct thread *, struct linux_getgid_args *); int linux_getppid(struct thread *, struct linux_getppid_args *); int linux_getgroups(struct thread *, struct linux_getgroups_args *); int linux_setgroups(struct thread *, struct linux_setgroups_args *); int linux_setfsuid(struct thread *, struct linux_setfsuid_args *); int linux_setfsgid(struct thread *, struct linux_setfsgid_args *); int linux_getsid(struct thread *, struct linux_getsid_args *); int linux_capget(struct thread *, struct linux_capget_args *); int linux_capset(struct thread *, struct linux_capset_args *); int linux_rt_sigpending(struct thread *, struct linux_rt_sigpending_args *); int linux_rt_sigtimedwait(struct thread *, struct linux_rt_sigtimedwait_args *); int linux_rt_sigqueueinfo(struct thread *, struct linux_rt_sigqueueinfo_args *); int linux_rt_sigsuspend(struct thread *, struct linux_rt_sigsuspend_args *); int linux_sigaltstack(struct thread *, struct linux_sigaltstack_args *); int linux_utime(struct thread *, struct linux_utime_args *); int linux_mknod(struct thread *, struct linux_mknod_args *); int linux_personality(struct thread *, struct linux_personality_args *); int linux_ustat(struct thread *, struct linux_ustat_args *); int linux_statfs(struct thread *, struct linux_statfs_args *); int linux_fstatfs(struct thread *, struct linux_fstatfs_args *); int linux_sysfs(struct thread *, struct linux_sysfs_args *); int linux_getpriority(struct thread *, struct linux_getpriority_args *); int linux_sched_setparam(struct thread *, struct linux_sched_setparam_args *); int linux_sched_getparam(struct thread *, struct linux_sched_getparam_args *); int linux_sched_setscheduler(struct thread *, struct linux_sched_setscheduler_args *); int linux_sched_getscheduler(struct thread *, struct linux_sched_getscheduler_args *); int linux_sched_get_priority_max(struct thread *, struct linux_sched_get_priority_max_args *); int linux_sched_get_priority_min(struct thread *, struct linux_sched_get_priority_min_args *); int linux_sched_rr_get_interval(struct thread *, struct linux_sched_rr_get_interval_args *); int linux_vhangup(struct thread *, struct linux_vhangup_args *); int linux_pivot_root(struct thread *, struct linux_pivot_root_args *); int linux_sysctl(struct thread *, struct linux_sysctl_args *); int linux_prctl(struct thread *, struct linux_prctl_args *); int linux_arch_prctl(struct thread *, struct linux_arch_prctl_args *); int linux_adjtimex(struct thread *, struct linux_adjtimex_args *); int linux_setrlimit(struct thread *, struct linux_setrlimit_args *); int linux_mount(struct thread *, struct linux_mount_args *); int linux_umount(struct thread *, struct linux_umount_args *); int linux_swapoff(struct thread *, struct linux_swapoff_args *); int linux_reboot(struct thread *, struct linux_reboot_args *); int linux_sethostname(struct thread *, struct linux_sethostname_args *); int linux_setdomainname(struct thread *, struct linux_setdomainname_args *); int linux_iopl(struct thread *, struct linux_iopl_args *); int linux_create_module(struct thread *, struct linux_create_module_args *); int linux_init_module(struct thread *, struct linux_init_module_args *); int linux_delete_module(struct thread *, struct linux_delete_module_args *); int linux_get_kernel_syms(struct thread *, struct linux_get_kernel_syms_args *); int linux_query_module(struct thread *, struct linux_query_module_args *); int linux_quotactl(struct thread *, struct linux_quotactl_args *); int linux_nfsservctl(struct thread *, struct linux_nfsservctl_args *); int linux_getpmsg(struct thread *, struct linux_getpmsg_args *); int linux_putpmsg(struct thread *, struct linux_putpmsg_args *); int linux_afs_syscall(struct thread *, struct linux_afs_syscall_args *); int linux_tuxcall(struct thread *, struct linux_tuxcall_args *); int linux_security(struct thread *, struct linux_security_args *); int linux_gettid(struct thread *, struct linux_gettid_args *); int linux_setxattr(struct thread *, struct linux_setxattr_args *); int linux_lsetxattr(struct thread *, struct linux_lsetxattr_args *); int linux_fsetxattr(struct thread *, struct linux_fsetxattr_args *); int linux_getxattr(struct thread *, struct linux_getxattr_args *); int linux_lgetxattr(struct thread *, struct linux_lgetxattr_args *); int linux_fgetxattr(struct thread *, struct linux_fgetxattr_args *); int linux_listxattr(struct thread *, struct linux_listxattr_args *); int linux_llistxattr(struct thread *, struct linux_llistxattr_args *); int linux_flistxattr(struct thread *, struct linux_flistxattr_args *); int linux_removexattr(struct thread *, struct linux_removexattr_args *); int linux_lremovexattr(struct thread *, struct linux_lremovexattr_args *); int linux_fremovexattr(struct thread *, struct linux_fremovexattr_args *); int linux_tkill(struct thread *, struct linux_tkill_args *); int linux_time(struct thread *, struct linux_time_args *); int linux_sys_futex(struct thread *, struct linux_sys_futex_args *); int linux_sched_setaffinity(struct thread *, struct linux_sched_setaffinity_args *); int linux_sched_getaffinity(struct thread *, struct linux_sched_getaffinity_args *); int linux_set_thread_area(struct thread *, struct linux_set_thread_area_args *); int linux_lookup_dcookie(struct thread *, struct linux_lookup_dcookie_args *); int linux_epoll_create(struct thread *, struct linux_epoll_create_args *); int linux_epoll_ctl_old(struct thread *, struct linux_epoll_ctl_old_args *); int linux_epoll_wait_old(struct thread *, struct linux_epoll_wait_old_args *); int linux_remap_file_pages(struct thread *, struct linux_remap_file_pages_args *); int linux_getdents64(struct thread *, struct linux_getdents64_args *); int linux_set_tid_address(struct thread *, struct linux_set_tid_address_args *); int linux_semtimedop(struct thread *, struct linux_semtimedop_args *); int linux_fadvise64(struct thread *, struct linux_fadvise64_args *); int linux_timer_create(struct thread *, struct linux_timer_create_args *); int linux_timer_settime(struct thread *, struct linux_timer_settime_args *); int linux_timer_gettime(struct thread *, struct linux_timer_gettime_args *); int linux_timer_getoverrun(struct thread *, struct linux_timer_getoverrun_args *); int linux_timer_delete(struct thread *, struct linux_timer_delete_args *); int linux_clock_settime(struct thread *, struct linux_clock_settime_args *); int linux_clock_gettime(struct thread *, struct linux_clock_gettime_args *); int linux_clock_getres(struct thread *, struct linux_clock_getres_args *); int linux_clock_nanosleep(struct thread *, struct linux_clock_nanosleep_args *); int linux_exit_group(struct thread *, struct linux_exit_group_args *); int linux_epoll_wait(struct thread *, struct linux_epoll_wait_args *); int linux_epoll_ctl(struct thread *, struct linux_epoll_ctl_args *); int linux_tgkill(struct thread *, struct linux_tgkill_args *); int linux_utimes(struct thread *, struct linux_utimes_args *); int linux_mbind(struct thread *, struct linux_mbind_args *); int linux_set_mempolicy(struct thread *, struct linux_set_mempolicy_args *); int linux_get_mempolicy(struct thread *, struct linux_get_mempolicy_args *); int linux_mq_open(struct thread *, struct linux_mq_open_args *); int linux_mq_unlink(struct thread *, struct linux_mq_unlink_args *); int linux_mq_timedsend(struct thread *, struct linux_mq_timedsend_args *); int linux_mq_timedreceive(struct thread *, struct linux_mq_timedreceive_args *); int linux_mq_notify(struct thread *, struct linux_mq_notify_args *); int linux_mq_getsetattr(struct thread *, struct linux_mq_getsetattr_args *); int linux_kexec_load(struct thread *, struct linux_kexec_load_args *); int linux_waitid(struct thread *, struct linux_waitid_args *); int linux_add_key(struct thread *, struct linux_add_key_args *); int linux_request_key(struct thread *, struct linux_request_key_args *); int linux_keyctl(struct thread *, struct linux_keyctl_args *); int linux_ioprio_set(struct thread *, struct linux_ioprio_set_args *); int linux_ioprio_get(struct thread *, struct linux_ioprio_get_args *); int linux_inotify_init(struct thread *, struct linux_inotify_init_args *); int linux_inotify_add_watch(struct thread *, struct linux_inotify_add_watch_args *); int linux_inotify_rm_watch(struct thread *, struct linux_inotify_rm_watch_args *); int linux_migrate_pages(struct thread *, struct linux_migrate_pages_args *); int linux_openat(struct thread *, struct linux_openat_args *); int linux_mkdirat(struct thread *, struct linux_mkdirat_args *); int linux_mknodat(struct thread *, struct linux_mknodat_args *); int linux_fchownat(struct thread *, struct linux_fchownat_args *); int linux_futimesat(struct thread *, struct linux_futimesat_args *); int linux_newfstatat(struct thread *, struct linux_newfstatat_args *); int linux_unlinkat(struct thread *, struct linux_unlinkat_args *); int linux_renameat(struct thread *, struct linux_renameat_args *); int linux_linkat(struct thread *, struct linux_linkat_args *); int linux_symlinkat(struct thread *, struct linux_symlinkat_args *); int linux_readlinkat(struct thread *, struct linux_readlinkat_args *); int linux_fchmodat(struct thread *, struct linux_fchmodat_args *); int linux_faccessat(struct thread *, struct linux_faccessat_args *); int linux_pselect6(struct thread *, struct linux_pselect6_args *); int linux_ppoll(struct thread *, struct linux_ppoll_args *); int linux_unshare(struct thread *, struct linux_unshare_args *); int linux_set_robust_list(struct thread *, struct linux_set_robust_list_args *); int linux_get_robust_list(struct thread *, struct linux_get_robust_list_args *); int linux_splice(struct thread *, struct linux_splice_args *); int linux_tee(struct thread *, struct linux_tee_args *); int linux_sync_file_range(struct thread *, struct linux_sync_file_range_args *); int linux_vmsplice(struct thread *, struct linux_vmsplice_args *); int linux_move_pages(struct thread *, struct linux_move_pages_args *); int linux_utimensat(struct thread *, struct linux_utimensat_args *); int linux_epoll_pwait(struct thread *, struct linux_epoll_pwait_args *); int linux_signalfd(struct thread *, struct linux_signalfd_args *); -int linux_timerfd(struct thread *, struct linux_timerfd_args *); +int linux_timerfd_create(struct thread *, struct linux_timerfd_create_args *); int linux_eventfd(struct thread *, struct linux_eventfd_args *); int linux_fallocate(struct thread *, struct linux_fallocate_args *); int linux_timerfd_settime(struct thread *, struct linux_timerfd_settime_args *); int linux_timerfd_gettime(struct thread *, struct linux_timerfd_gettime_args *); int linux_accept4(struct thread *, struct linux_accept4_args *); int linux_signalfd4(struct thread *, struct linux_signalfd4_args *); int linux_eventfd2(struct thread *, struct linux_eventfd2_args *); int linux_epoll_create1(struct thread *, struct linux_epoll_create1_args *); int linux_dup3(struct thread *, struct linux_dup3_args *); int linux_pipe2(struct thread *, struct linux_pipe2_args *); int linux_inotify_init1(struct thread *, struct linux_inotify_init1_args *); int linux_preadv(struct thread *, struct linux_preadv_args *); int linux_pwritev(struct thread *, struct linux_pwritev_args *); -int linux_rt_tsigqueueinfo(struct thread *, struct linux_rt_tsigqueueinfo_args *); +int linux_rt_tgsigqueueinfo(struct thread *, struct linux_rt_tgsigqueueinfo_args *); int linux_perf_event_open(struct thread *, struct linux_perf_event_open_args *); int linux_recvmmsg(struct thread *, struct linux_recvmmsg_args *); int linux_fanotify_init(struct thread *, struct linux_fanotify_init_args *); int linux_fanotify_mark(struct thread *, struct linux_fanotify_mark_args *); int linux_prlimit64(struct thread *, struct linux_prlimit64_args *); int linux_name_to_handle_at(struct thread *, struct linux_name_to_handle_at_args *); int linux_open_by_handle_at(struct thread *, struct linux_open_by_handle_at_args *); int linux_clock_adjtime(struct thread *, struct linux_clock_adjtime_args *); int linux_syncfs(struct thread *, struct linux_syncfs_args *); int linux_sendmmsg(struct thread *, struct linux_sendmmsg_args *); int linux_setns(struct thread *, struct linux_setns_args *); +int linux_getcpu(struct thread *, struct linux_getcpu_args *); int linux_process_vm_readv(struct thread *, struct linux_process_vm_readv_args *); int linux_process_vm_writev(struct thread *, struct linux_process_vm_writev_args *); int linux_kcmp(struct thread *, struct linux_kcmp_args *); int linux_finit_module(struct thread *, struct linux_finit_module_args *); +int linux_sched_setattr(struct thread *, struct linux_sched_setattr_args *); +int linux_sched_getattr(struct thread *, struct linux_sched_getattr_args *); +int linux_renameat2(struct thread *, struct linux_renameat2_args *); +int linux_seccomp(struct thread *, struct linux_seccomp_args *); +int linux_getrandom(struct thread *, struct linux_getrandom_args *); +int linux_memfd_create(struct thread *, struct linux_memfd_create_args *); +int linux_kexec_file_load(struct thread *, struct linux_kexec_file_load_args *); +int linux_bpf(struct thread *, struct linux_bpf_args *); +int linux_execveat(struct thread *, struct linux_execveat_args *); +int linux_userfaultfd(struct thread *, struct linux_userfaultfd_args *); +int linux_membarrier(struct thread *, struct linux_membarrier_args *); +int linux_mlock2(struct thread *, struct linux_mlock2_args *); +int linux_copy_file_range(struct thread *, struct linux_copy_file_range_args *); +int linux_preadv2(struct thread *, struct linux_preadv2_args *); +int linux_pwritev2(struct thread *, struct linux_pwritev2_args *); +int linux_pkey_mprotect(struct thread *, struct linux_pkey_mprotect_args *); +int linux_pkey_alloc(struct thread *, struct linux_pkey_alloc_args *); +int linux_pkey_free(struct thread *, struct linux_pkey_free_args *); #ifdef COMPAT_43 #define nosys linux_nosys #endif /* COMPAT_43 */ #ifdef COMPAT_FREEBSD4 #define nosys linux_nosys #endif /* COMPAT_FREEBSD4 */ #ifdef COMPAT_FREEBSD6 #define nosys linux_nosys #endif /* COMPAT_FREEBSD6 */ #ifdef COMPAT_FREEBSD7 #define nosys linux_nosys #endif /* COMPAT_FREEBSD7 */ #ifdef COMPAT_FREEBSD10 #define nosys linux_nosys #endif /* COMPAT_FREEBSD10 */ #define LINUX_SYS_AUE_linux_open AUE_OPEN_RWTC #define LINUX_SYS_AUE_linux_newstat AUE_STAT #define LINUX_SYS_AUE_linux_newfstat AUE_FSTAT #define LINUX_SYS_AUE_linux_newlstat AUE_LSTAT #define LINUX_SYS_AUE_linux_lseek AUE_LSEEK #define LINUX_SYS_AUE_linux_mmap2 AUE_MMAP #define LINUX_SYS_AUE_linux_mprotect AUE_MPROTECT #define LINUX_SYS_AUE_linux_brk AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigaction AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigprocmask AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigreturn AUE_NULL #define LINUX_SYS_AUE_linux_ioctl AUE_IOCTL #define LINUX_SYS_AUE_linux_pread AUE_PREAD #define LINUX_SYS_AUE_linux_pwrite AUE_PWRITE #define LINUX_SYS_AUE_linux_access AUE_ACCESS #define LINUX_SYS_AUE_linux_pipe AUE_PIPE #define LINUX_SYS_AUE_linux_select AUE_SELECT #define LINUX_SYS_AUE_linux_mremap AUE_NULL #define LINUX_SYS_AUE_linux_msync AUE_MSYNC #define LINUX_SYS_AUE_linux_mincore AUE_MINCORE #define LINUX_SYS_AUE_linux_shmget AUE_NULL #define LINUX_SYS_AUE_linux_shmat AUE_NULL #define LINUX_SYS_AUE_linux_shmctl AUE_NULL #define LINUX_SYS_AUE_linux_pause AUE_NULL #define LINUX_SYS_AUE_linux_nanosleep AUE_NULL #define LINUX_SYS_AUE_linux_getitimer AUE_GETITIMER #define LINUX_SYS_AUE_linux_alarm AUE_NULL #define LINUX_SYS_AUE_linux_setitimer AUE_SETITIMER #define LINUX_SYS_AUE_linux_getpid AUE_GETPID #define LINUX_SYS_AUE_linux_sendfile AUE_SENDFILE #define LINUX_SYS_AUE_linux_socket AUE_SOCKET #define LINUX_SYS_AUE_linux_connect AUE_CONNECT #define LINUX_SYS_AUE_linux_accept AUE_ACCEPT #define LINUX_SYS_AUE_linux_sendto AUE_SENDTO #define LINUX_SYS_AUE_linux_recvfrom AUE_RECVFROM #define LINUX_SYS_AUE_linux_sendmsg AUE_SENDMSG #define LINUX_SYS_AUE_linux_recvmsg AUE_RECVMSG #define LINUX_SYS_AUE_linux_shutdown AUE_NULL #define LINUX_SYS_AUE_linux_bind AUE_BIND #define LINUX_SYS_AUE_linux_listen AUE_LISTEN #define LINUX_SYS_AUE_linux_getsockname AUE_GETSOCKNAME #define LINUX_SYS_AUE_linux_getpeername AUE_GETPEERNAME #define LINUX_SYS_AUE_linux_socketpair AUE_SOCKETPAIR #define LINUX_SYS_AUE_linux_setsockopt AUE_SETSOCKOPT #define LINUX_SYS_AUE_linux_getsockopt AUE_GETSOCKOPT #define LINUX_SYS_AUE_linux_clone AUE_RFORK #define LINUX_SYS_AUE_linux_fork AUE_FORK #define LINUX_SYS_AUE_linux_vfork AUE_VFORK #define LINUX_SYS_AUE_linux_execve AUE_EXECVE #define LINUX_SYS_AUE_linux_exit AUE_EXIT #define LINUX_SYS_AUE_linux_wait4 AUE_WAIT4 #define LINUX_SYS_AUE_linux_kill AUE_KILL #define LINUX_SYS_AUE_linux_newuname AUE_NULL #define LINUX_SYS_AUE_linux_semget AUE_NULL #define LINUX_SYS_AUE_linux_semop AUE_NULL #define LINUX_SYS_AUE_linux_semctl AUE_NULL #define LINUX_SYS_AUE_linux_shmdt AUE_NULL #define LINUX_SYS_AUE_linux_msgget AUE_NULL #define LINUX_SYS_AUE_linux_msgsnd AUE_NULL #define LINUX_SYS_AUE_linux_msgrcv AUE_NULL #define LINUX_SYS_AUE_linux_msgctl AUE_NULL #define LINUX_SYS_AUE_linux_fcntl AUE_FCNTL #define LINUX_SYS_AUE_linux_fdatasync AUE_NULL #define LINUX_SYS_AUE_linux_truncate AUE_TRUNCATE #define LINUX_SYS_AUE_linux_ftruncate AUE_FTRUNCATE #define LINUX_SYS_AUE_linux_getdents AUE_GETDIRENTRIES #define LINUX_SYS_AUE_linux_getcwd AUE_GETCWD #define LINUX_SYS_AUE_linux_chdir AUE_CHDIR #define LINUX_SYS_AUE_linux_rename AUE_RENAME #define LINUX_SYS_AUE_linux_mkdir AUE_MKDIR #define LINUX_SYS_AUE_linux_rmdir AUE_RMDIR #define LINUX_SYS_AUE_linux_creat AUE_CREAT #define LINUX_SYS_AUE_linux_link AUE_LINK #define LINUX_SYS_AUE_linux_unlink AUE_UNLINK #define LINUX_SYS_AUE_linux_symlink AUE_SYMLINK #define LINUX_SYS_AUE_linux_readlink AUE_READLINK #define LINUX_SYS_AUE_linux_chmod AUE_CHMOD #define LINUX_SYS_AUE_linux_chown AUE_LCHOWN #define LINUX_SYS_AUE_linux_lchown AUE_LCHOWN #define LINUX_SYS_AUE_linux_getrlimit AUE_GETRLIMIT #define LINUX_SYS_AUE_linux_sysinfo AUE_NULL #define LINUX_SYS_AUE_linux_times AUE_NULL #define LINUX_SYS_AUE_linux_ptrace AUE_PTRACE #define LINUX_SYS_AUE_linux_getuid AUE_GETUID #define LINUX_SYS_AUE_linux_syslog AUE_NULL #define LINUX_SYS_AUE_linux_getgid AUE_GETGID #define LINUX_SYS_AUE_linux_getppid AUE_GETPPID #define LINUX_SYS_AUE_linux_getgroups AUE_GETGROUPS #define LINUX_SYS_AUE_linux_setgroups AUE_SETGROUPS #define LINUX_SYS_AUE_linux_setfsuid AUE_SETFSUID #define LINUX_SYS_AUE_linux_setfsgid AUE_SETFSGID #define LINUX_SYS_AUE_linux_getsid AUE_GETSID #define LINUX_SYS_AUE_linux_capget AUE_CAPGET #define LINUX_SYS_AUE_linux_capset AUE_CAPSET #define LINUX_SYS_AUE_linux_rt_sigpending AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigtimedwait AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigqueueinfo AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigsuspend AUE_NULL #define LINUX_SYS_AUE_linux_sigaltstack AUE_NULL #define LINUX_SYS_AUE_linux_utime AUE_UTIME #define LINUX_SYS_AUE_linux_mknod AUE_MKNOD #define LINUX_SYS_AUE_linux_personality AUE_PERSONALITY #define LINUX_SYS_AUE_linux_ustat AUE_NULL #define LINUX_SYS_AUE_linux_statfs AUE_STATFS #define LINUX_SYS_AUE_linux_fstatfs AUE_FSTATFS #define LINUX_SYS_AUE_linux_sysfs AUE_NULL #define LINUX_SYS_AUE_linux_getpriority AUE_GETPRIORITY #define LINUX_SYS_AUE_linux_sched_setparam AUE_SCHED_SETPARAM #define LINUX_SYS_AUE_linux_sched_getparam AUE_SCHED_GETPARAM #define LINUX_SYS_AUE_linux_sched_setscheduler AUE_SCHED_SETSCHEDULER #define LINUX_SYS_AUE_linux_sched_getscheduler AUE_SCHED_GETSCHEDULER #define LINUX_SYS_AUE_linux_sched_get_priority_max AUE_SCHED_GET_PRIORITY_MAX #define LINUX_SYS_AUE_linux_sched_get_priority_min AUE_SCHED_GET_PRIORITY_MIN #define LINUX_SYS_AUE_linux_sched_rr_get_interval AUE_SCHED_RR_GET_INTERVAL #define LINUX_SYS_AUE_linux_vhangup AUE_NULL #define LINUX_SYS_AUE_linux_pivot_root AUE_PIVOT_ROOT #define LINUX_SYS_AUE_linux_sysctl AUE_SYSCTL #define LINUX_SYS_AUE_linux_prctl AUE_PRCTL #define LINUX_SYS_AUE_linux_arch_prctl AUE_PRCTL #define LINUX_SYS_AUE_linux_adjtimex AUE_ADJTIME #define LINUX_SYS_AUE_linux_setrlimit AUE_SETRLIMIT #define LINUX_SYS_AUE_linux_mount AUE_MOUNT #define LINUX_SYS_AUE_linux_umount AUE_UMOUNT #define LINUX_SYS_AUE_linux_swapoff AUE_SWAPOFF #define LINUX_SYS_AUE_linux_reboot AUE_REBOOT #define LINUX_SYS_AUE_linux_sethostname AUE_SYSCTL #define LINUX_SYS_AUE_linux_setdomainname AUE_SYSCTL #define LINUX_SYS_AUE_linux_iopl AUE_NULL #define LINUX_SYS_AUE_linux_create_module AUE_NULL #define LINUX_SYS_AUE_linux_init_module AUE_NULL #define LINUX_SYS_AUE_linux_delete_module AUE_NULL #define LINUX_SYS_AUE_linux_get_kernel_syms AUE_NULL #define LINUX_SYS_AUE_linux_query_module AUE_NULL #define LINUX_SYS_AUE_linux_quotactl AUE_QUOTACTL #define LINUX_SYS_AUE_linux_nfsservctl AUE_NULL #define LINUX_SYS_AUE_linux_getpmsg AUE_GETPMSG #define LINUX_SYS_AUE_linux_putpmsg AUE_PUTPMSG #define LINUX_SYS_AUE_linux_afs_syscall AUE_NULL #define LINUX_SYS_AUE_linux_tuxcall AUE_NULL #define LINUX_SYS_AUE_linux_security AUE_NULL #define LINUX_SYS_AUE_linux_gettid AUE_NULL #define LINUX_SYS_AUE_linux_setxattr AUE_NULL #define LINUX_SYS_AUE_linux_lsetxattr AUE_NULL #define LINUX_SYS_AUE_linux_fsetxattr AUE_NULL #define LINUX_SYS_AUE_linux_getxattr AUE_NULL #define LINUX_SYS_AUE_linux_lgetxattr AUE_NULL #define LINUX_SYS_AUE_linux_fgetxattr AUE_NULL #define LINUX_SYS_AUE_linux_listxattr AUE_NULL #define LINUX_SYS_AUE_linux_llistxattr AUE_NULL #define LINUX_SYS_AUE_linux_flistxattr AUE_NULL #define LINUX_SYS_AUE_linux_removexattr AUE_NULL #define LINUX_SYS_AUE_linux_lremovexattr AUE_NULL #define LINUX_SYS_AUE_linux_fremovexattr AUE_NULL #define LINUX_SYS_AUE_linux_tkill AUE_NULL #define LINUX_SYS_AUE_linux_time AUE_NULL #define LINUX_SYS_AUE_linux_sys_futex AUE_NULL #define LINUX_SYS_AUE_linux_sched_setaffinity AUE_NULL #define LINUX_SYS_AUE_linux_sched_getaffinity AUE_NULL #define LINUX_SYS_AUE_linux_set_thread_area AUE_NULL #define LINUX_SYS_AUE_linux_lookup_dcookie AUE_NULL #define LINUX_SYS_AUE_linux_epoll_create AUE_NULL #define LINUX_SYS_AUE_linux_epoll_ctl_old AUE_NULL #define LINUX_SYS_AUE_linux_epoll_wait_old AUE_NULL #define LINUX_SYS_AUE_linux_remap_file_pages AUE_NULL #define LINUX_SYS_AUE_linux_getdents64 AUE_GETDIRENTRIES #define LINUX_SYS_AUE_linux_set_tid_address AUE_NULL #define LINUX_SYS_AUE_linux_semtimedop AUE_NULL #define LINUX_SYS_AUE_linux_fadvise64 AUE_NULL #define LINUX_SYS_AUE_linux_timer_create AUE_NULL #define LINUX_SYS_AUE_linux_timer_settime AUE_NULL #define LINUX_SYS_AUE_linux_timer_gettime AUE_NULL #define LINUX_SYS_AUE_linux_timer_getoverrun AUE_NULL #define LINUX_SYS_AUE_linux_timer_delete AUE_NULL #define LINUX_SYS_AUE_linux_clock_settime AUE_CLOCK_SETTIME #define LINUX_SYS_AUE_linux_clock_gettime AUE_NULL #define LINUX_SYS_AUE_linux_clock_getres AUE_NULL #define LINUX_SYS_AUE_linux_clock_nanosleep AUE_NULL #define LINUX_SYS_AUE_linux_exit_group AUE_EXIT #define LINUX_SYS_AUE_linux_epoll_wait AUE_NULL #define LINUX_SYS_AUE_linux_epoll_ctl AUE_NULL #define LINUX_SYS_AUE_linux_tgkill AUE_NULL #define LINUX_SYS_AUE_linux_utimes AUE_UTIMES #define LINUX_SYS_AUE_linux_mbind AUE_NULL #define LINUX_SYS_AUE_linux_set_mempolicy AUE_NULL #define LINUX_SYS_AUE_linux_get_mempolicy AUE_NULL #define LINUX_SYS_AUE_linux_mq_open AUE_NULL #define LINUX_SYS_AUE_linux_mq_unlink AUE_NULL #define LINUX_SYS_AUE_linux_mq_timedsend AUE_NULL #define LINUX_SYS_AUE_linux_mq_timedreceive AUE_NULL #define LINUX_SYS_AUE_linux_mq_notify AUE_NULL #define LINUX_SYS_AUE_linux_mq_getsetattr AUE_NULL #define LINUX_SYS_AUE_linux_kexec_load AUE_NULL #define LINUX_SYS_AUE_linux_waitid AUE_WAIT6 #define LINUX_SYS_AUE_linux_add_key AUE_NULL #define LINUX_SYS_AUE_linux_request_key AUE_NULL #define LINUX_SYS_AUE_linux_keyctl AUE_NULL #define LINUX_SYS_AUE_linux_ioprio_set AUE_NULL #define LINUX_SYS_AUE_linux_ioprio_get AUE_NULL #define LINUX_SYS_AUE_linux_inotify_init AUE_NULL #define LINUX_SYS_AUE_linux_inotify_add_watch AUE_NULL #define LINUX_SYS_AUE_linux_inotify_rm_watch AUE_NULL #define LINUX_SYS_AUE_linux_migrate_pages AUE_NULL #define LINUX_SYS_AUE_linux_openat AUE_OPEN_RWTC #define LINUX_SYS_AUE_linux_mkdirat AUE_MKDIRAT #define LINUX_SYS_AUE_linux_mknodat AUE_MKNODAT #define LINUX_SYS_AUE_linux_fchownat AUE_FCHOWNAT #define LINUX_SYS_AUE_linux_futimesat AUE_FUTIMESAT #define LINUX_SYS_AUE_linux_newfstatat AUE_FSTATAT #define LINUX_SYS_AUE_linux_unlinkat AUE_UNLINKAT #define LINUX_SYS_AUE_linux_renameat AUE_RENAMEAT #define LINUX_SYS_AUE_linux_linkat AUE_LINKAT #define LINUX_SYS_AUE_linux_symlinkat AUE_SYMLINKAT #define LINUX_SYS_AUE_linux_readlinkat AUE_READLINKAT #define LINUX_SYS_AUE_linux_fchmodat AUE_FCHMODAT #define LINUX_SYS_AUE_linux_faccessat AUE_FACCESSAT #define LINUX_SYS_AUE_linux_pselect6 AUE_SELECT #define LINUX_SYS_AUE_linux_ppoll AUE_POLL #define LINUX_SYS_AUE_linux_unshare AUE_NULL #define LINUX_SYS_AUE_linux_set_robust_list AUE_NULL #define LINUX_SYS_AUE_linux_get_robust_list AUE_NULL #define LINUX_SYS_AUE_linux_splice AUE_NULL #define LINUX_SYS_AUE_linux_tee AUE_NULL #define LINUX_SYS_AUE_linux_sync_file_range AUE_NULL #define LINUX_SYS_AUE_linux_vmsplice AUE_NULL #define LINUX_SYS_AUE_linux_move_pages AUE_NULL #define LINUX_SYS_AUE_linux_utimensat AUE_FUTIMESAT #define LINUX_SYS_AUE_linux_epoll_pwait AUE_NULL #define LINUX_SYS_AUE_linux_signalfd AUE_NULL -#define LINUX_SYS_AUE_linux_timerfd AUE_NULL +#define LINUX_SYS_AUE_linux_timerfd_create AUE_NULL #define LINUX_SYS_AUE_linux_eventfd AUE_NULL #define LINUX_SYS_AUE_linux_fallocate AUE_NULL #define LINUX_SYS_AUE_linux_timerfd_settime AUE_NULL #define LINUX_SYS_AUE_linux_timerfd_gettime AUE_NULL #define LINUX_SYS_AUE_linux_accept4 AUE_ACCEPT #define LINUX_SYS_AUE_linux_signalfd4 AUE_NULL #define LINUX_SYS_AUE_linux_eventfd2 AUE_NULL #define LINUX_SYS_AUE_linux_epoll_create1 AUE_NULL #define LINUX_SYS_AUE_linux_dup3 AUE_NULL #define LINUX_SYS_AUE_linux_pipe2 AUE_NULL #define LINUX_SYS_AUE_linux_inotify_init1 AUE_NULL #define LINUX_SYS_AUE_linux_preadv AUE_NULL #define LINUX_SYS_AUE_linux_pwritev AUE_NULL -#define LINUX_SYS_AUE_linux_rt_tsigqueueinfo AUE_NULL +#define LINUX_SYS_AUE_linux_rt_tgsigqueueinfo AUE_NULL #define LINUX_SYS_AUE_linux_perf_event_open AUE_NULL #define LINUX_SYS_AUE_linux_recvmmsg AUE_NULL #define LINUX_SYS_AUE_linux_fanotify_init AUE_NULL #define LINUX_SYS_AUE_linux_fanotify_mark AUE_NULL #define LINUX_SYS_AUE_linux_prlimit64 AUE_NULL #define LINUX_SYS_AUE_linux_name_to_handle_at AUE_NULL #define LINUX_SYS_AUE_linux_open_by_handle_at AUE_NULL #define LINUX_SYS_AUE_linux_clock_adjtime AUE_NULL #define LINUX_SYS_AUE_linux_syncfs AUE_SYNC #define LINUX_SYS_AUE_linux_sendmmsg AUE_NULL #define LINUX_SYS_AUE_linux_setns AUE_NULL +#define LINUX_SYS_AUE_linux_getcpu AUE_NULL #define LINUX_SYS_AUE_linux_process_vm_readv AUE_NULL #define LINUX_SYS_AUE_linux_process_vm_writev AUE_NULL #define LINUX_SYS_AUE_linux_kcmp AUE_NULL #define LINUX_SYS_AUE_linux_finit_module AUE_NULL +#define LINUX_SYS_AUE_linux_sched_setattr AUE_NULL +#define LINUX_SYS_AUE_linux_sched_getattr AUE_NULL +#define LINUX_SYS_AUE_linux_renameat2 AUE_NULL +#define LINUX_SYS_AUE_linux_seccomp AUE_NULL +#define LINUX_SYS_AUE_linux_getrandom AUE_NULL +#define LINUX_SYS_AUE_linux_memfd_create AUE_NULL +#define LINUX_SYS_AUE_linux_kexec_file_load AUE_NULL +#define LINUX_SYS_AUE_linux_bpf AUE_NULL +#define LINUX_SYS_AUE_linux_execveat AUE_NULL +#define LINUX_SYS_AUE_linux_userfaultfd AUE_NULL +#define LINUX_SYS_AUE_linux_membarrier AUE_NULL +#define LINUX_SYS_AUE_linux_mlock2 AUE_NULL +#define LINUX_SYS_AUE_linux_copy_file_range AUE_NULL +#define LINUX_SYS_AUE_linux_preadv2 AUE_NULL +#define LINUX_SYS_AUE_linux_pwritev2 AUE_NULL +#define LINUX_SYS_AUE_linux_pkey_mprotect AUE_NULL +#define LINUX_SYS_AUE_linux_pkey_alloc AUE_NULL +#define LINUX_SYS_AUE_linux_pkey_free AUE_NULL #undef PAD_ #undef PADL_ #undef PADR_ #endif /* !_LINUX_SYSPROTO_H_ */ Index: projects/ipsec/sys/amd64/linux/linux_syscall.h =================================================================== --- projects/ipsec/sys/amd64/linux/linux_syscall.h (revision 313312) +++ projects/ipsec/sys/amd64/linux/linux_syscall.h (revision 313313) @@ -1,310 +1,329 @@ /* * System call numbers. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/amd64/linux/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ #define LINUX_SYS_read 0 #define LINUX_SYS_write 1 #define LINUX_SYS_linux_open 2 #define LINUX_SYS_close 3 #define LINUX_SYS_linux_newstat 4 #define LINUX_SYS_linux_newfstat 5 #define LINUX_SYS_linux_newlstat 6 #define LINUX_SYS_poll 7 #define LINUX_SYS_linux_lseek 8 #define LINUX_SYS_linux_mmap2 9 #define LINUX_SYS_linux_mprotect 10 #define LINUX_SYS_munmap 11 #define LINUX_SYS_linux_brk 12 #define LINUX_SYS_linux_rt_sigaction 13 #define LINUX_SYS_linux_rt_sigprocmask 14 #define LINUX_SYS_linux_rt_sigreturn 15 #define LINUX_SYS_linux_ioctl 16 #define LINUX_SYS_linux_pread 17 #define LINUX_SYS_linux_pwrite 18 #define LINUX_SYS_readv 19 #define LINUX_SYS_writev 20 #define LINUX_SYS_linux_access 21 #define LINUX_SYS_linux_pipe 22 #define LINUX_SYS_linux_select 23 #define LINUX_SYS_sched_yield 24 #define LINUX_SYS_linux_mremap 25 #define LINUX_SYS_linux_msync 26 #define LINUX_SYS_linux_mincore 27 #define LINUX_SYS_madvise 28 #define LINUX_SYS_linux_shmget 29 #define LINUX_SYS_linux_shmat 30 #define LINUX_SYS_linux_shmctl 31 #define LINUX_SYS_dup 32 #define LINUX_SYS_dup2 33 #define LINUX_SYS_linux_pause 34 #define LINUX_SYS_linux_nanosleep 35 #define LINUX_SYS_linux_getitimer 36 #define LINUX_SYS_linux_alarm 37 #define LINUX_SYS_linux_setitimer 38 #define LINUX_SYS_linux_getpid 39 #define LINUX_SYS_linux_sendfile 40 #define LINUX_SYS_linux_socket 41 #define LINUX_SYS_linux_connect 42 #define LINUX_SYS_linux_accept 43 #define LINUX_SYS_linux_sendto 44 #define LINUX_SYS_linux_recvfrom 45 #define LINUX_SYS_linux_sendmsg 46 #define LINUX_SYS_linux_recvmsg 47 #define LINUX_SYS_linux_shutdown 48 #define LINUX_SYS_linux_bind 49 #define LINUX_SYS_linux_listen 50 #define LINUX_SYS_linux_getsockname 51 #define LINUX_SYS_linux_getpeername 52 #define LINUX_SYS_linux_socketpair 53 #define LINUX_SYS_linux_setsockopt 54 #define LINUX_SYS_linux_getsockopt 55 #define LINUX_SYS_linux_clone 56 #define LINUX_SYS_linux_fork 57 #define LINUX_SYS_linux_vfork 58 #define LINUX_SYS_linux_execve 59 #define LINUX_SYS_linux_exit 60 #define LINUX_SYS_linux_wait4 61 #define LINUX_SYS_linux_kill 62 #define LINUX_SYS_linux_newuname 63 #define LINUX_SYS_linux_semget 64 #define LINUX_SYS_linux_semop 65 #define LINUX_SYS_linux_semctl 66 #define LINUX_SYS_linux_shmdt 67 #define LINUX_SYS_linux_msgget 68 #define LINUX_SYS_linux_msgsnd 69 #define LINUX_SYS_linux_msgrcv 70 #define LINUX_SYS_linux_msgctl 71 #define LINUX_SYS_linux_fcntl 72 #define LINUX_SYS_flock 73 #define LINUX_SYS_fsync 74 #define LINUX_SYS_linux_fdatasync 75 #define LINUX_SYS_linux_truncate 76 #define LINUX_SYS_linux_ftruncate 77 #define LINUX_SYS_linux_getdents 78 #define LINUX_SYS_linux_getcwd 79 #define LINUX_SYS_linux_chdir 80 #define LINUX_SYS_fchdir 81 #define LINUX_SYS_linux_rename 82 #define LINUX_SYS_linux_mkdir 83 #define LINUX_SYS_linux_rmdir 84 #define LINUX_SYS_linux_creat 85 #define LINUX_SYS_linux_link 86 #define LINUX_SYS_linux_unlink 87 #define LINUX_SYS_linux_symlink 88 #define LINUX_SYS_linux_readlink 89 #define LINUX_SYS_linux_chmod 90 #define LINUX_SYS_fchmod 91 #define LINUX_SYS_linux_chown 92 #define LINUX_SYS_fchown 93 #define LINUX_SYS_linux_lchown 94 #define LINUX_SYS_umask 95 #define LINUX_SYS_gettimeofday 96 #define LINUX_SYS_linux_getrlimit 97 #define LINUX_SYS_getrusage 98 #define LINUX_SYS_linux_sysinfo 99 #define LINUX_SYS_linux_times 100 #define LINUX_SYS_linux_ptrace 101 #define LINUX_SYS_linux_getuid 102 #define LINUX_SYS_linux_syslog 103 #define LINUX_SYS_linux_getgid 104 #define LINUX_SYS_setuid 105 #define LINUX_SYS_setgid 106 #define LINUX_SYS_geteuid 107 #define LINUX_SYS_getegid 108 #define LINUX_SYS_setpgid 109 #define LINUX_SYS_linux_getppid 110 #define LINUX_SYS_getpgrp 111 #define LINUX_SYS_setsid 112 #define LINUX_SYS_setreuid 113 #define LINUX_SYS_setregid 114 #define LINUX_SYS_linux_getgroups 115 #define LINUX_SYS_linux_setgroups 116 #define LINUX_SYS_setresuid 117 #define LINUX_SYS_getresuid 118 #define LINUX_SYS_setresgid 119 #define LINUX_SYS_getresgid 120 #define LINUX_SYS_getpgid 121 #define LINUX_SYS_linux_setfsuid 122 #define LINUX_SYS_linux_setfsgid 123 #define LINUX_SYS_linux_getsid 124 #define LINUX_SYS_linux_capget 125 #define LINUX_SYS_linux_capset 126 #define LINUX_SYS_linux_rt_sigpending 127 #define LINUX_SYS_linux_rt_sigtimedwait 128 #define LINUX_SYS_linux_rt_sigqueueinfo 129 #define LINUX_SYS_linux_rt_sigsuspend 130 #define LINUX_SYS_linux_sigaltstack 131 #define LINUX_SYS_linux_utime 132 #define LINUX_SYS_linux_mknod 133 #define LINUX_SYS_linux_personality 135 #define LINUX_SYS_linux_ustat 136 #define LINUX_SYS_linux_statfs 137 #define LINUX_SYS_linux_fstatfs 138 #define LINUX_SYS_linux_sysfs 139 #define LINUX_SYS_linux_getpriority 140 #define LINUX_SYS_setpriority 141 #define LINUX_SYS_linux_sched_setparam 142 #define LINUX_SYS_linux_sched_getparam 143 #define LINUX_SYS_linux_sched_setscheduler 144 #define LINUX_SYS_linux_sched_getscheduler 145 #define LINUX_SYS_linux_sched_get_priority_max 146 #define LINUX_SYS_linux_sched_get_priority_min 147 #define LINUX_SYS_linux_sched_rr_get_interval 148 #define LINUX_SYS_mlock 149 #define LINUX_SYS_munlock 150 #define LINUX_SYS_mlockall 151 #define LINUX_SYS_munlockall 152 #define LINUX_SYS_linux_vhangup 153 #define LINUX_SYS_linux_pivot_root 155 #define LINUX_SYS_linux_sysctl 156 #define LINUX_SYS_linux_prctl 157 #define LINUX_SYS_linux_arch_prctl 158 #define LINUX_SYS_linux_adjtimex 159 #define LINUX_SYS_linux_setrlimit 160 #define LINUX_SYS_chroot 161 #define LINUX_SYS_sync 162 #define LINUX_SYS_acct 163 #define LINUX_SYS_settimeofday 164 #define LINUX_SYS_linux_mount 165 #define LINUX_SYS_linux_umount 166 #define LINUX_SYS_swapon 167 #define LINUX_SYS_linux_swapoff 168 #define LINUX_SYS_linux_reboot 169 #define LINUX_SYS_linux_sethostname 170 #define LINUX_SYS_linux_setdomainname 171 #define LINUX_SYS_linux_iopl 172 #define LINUX_SYS_linux_create_module 174 #define LINUX_SYS_linux_init_module 175 #define LINUX_SYS_linux_delete_module 176 #define LINUX_SYS_linux_get_kernel_syms 177 #define LINUX_SYS_linux_query_module 178 #define LINUX_SYS_linux_quotactl 179 #define LINUX_SYS_linux_nfsservctl 180 #define LINUX_SYS_linux_getpmsg 181 #define LINUX_SYS_linux_putpmsg 182 #define LINUX_SYS_linux_afs_syscall 183 #define LINUX_SYS_linux_tuxcall 184 #define LINUX_SYS_linux_security 185 #define LINUX_SYS_linux_gettid 186 #define LINUX_SYS_linux_setxattr 188 #define LINUX_SYS_linux_lsetxattr 189 #define LINUX_SYS_linux_fsetxattr 190 #define LINUX_SYS_linux_getxattr 191 #define LINUX_SYS_linux_lgetxattr 192 #define LINUX_SYS_linux_fgetxattr 193 #define LINUX_SYS_linux_listxattr 194 #define LINUX_SYS_linux_llistxattr 195 #define LINUX_SYS_linux_flistxattr 196 #define LINUX_SYS_linux_removexattr 197 #define LINUX_SYS_linux_lremovexattr 198 #define LINUX_SYS_linux_fremovexattr 199 #define LINUX_SYS_linux_tkill 200 #define LINUX_SYS_linux_time 201 #define LINUX_SYS_linux_sys_futex 202 #define LINUX_SYS_linux_sched_setaffinity 203 #define LINUX_SYS_linux_sched_getaffinity 204 #define LINUX_SYS_linux_set_thread_area 205 #define LINUX_SYS_linux_lookup_dcookie 212 #define LINUX_SYS_linux_epoll_create 213 #define LINUX_SYS_linux_epoll_ctl_old 214 #define LINUX_SYS_linux_epoll_wait_old 215 #define LINUX_SYS_linux_remap_file_pages 216 #define LINUX_SYS_linux_getdents64 217 #define LINUX_SYS_linux_set_tid_address 218 #define LINUX_SYS_linux_semtimedop 220 #define LINUX_SYS_linux_fadvise64 221 #define LINUX_SYS_linux_timer_create 222 #define LINUX_SYS_linux_timer_settime 223 #define LINUX_SYS_linux_timer_gettime 224 #define LINUX_SYS_linux_timer_getoverrun 225 #define LINUX_SYS_linux_timer_delete 226 #define LINUX_SYS_linux_clock_settime 227 #define LINUX_SYS_linux_clock_gettime 228 #define LINUX_SYS_linux_clock_getres 229 #define LINUX_SYS_linux_clock_nanosleep 230 #define LINUX_SYS_linux_exit_group 231 #define LINUX_SYS_linux_epoll_wait 232 #define LINUX_SYS_linux_epoll_ctl 233 #define LINUX_SYS_linux_tgkill 234 #define LINUX_SYS_linux_utimes 235 #define LINUX_SYS_linux_mbind 237 #define LINUX_SYS_linux_set_mempolicy 238 #define LINUX_SYS_linux_get_mempolicy 239 #define LINUX_SYS_linux_mq_open 240 #define LINUX_SYS_linux_mq_unlink 241 #define LINUX_SYS_linux_mq_timedsend 242 #define LINUX_SYS_linux_mq_timedreceive 243 #define LINUX_SYS_linux_mq_notify 244 #define LINUX_SYS_linux_mq_getsetattr 245 #define LINUX_SYS_linux_kexec_load 246 #define LINUX_SYS_linux_waitid 247 #define LINUX_SYS_linux_add_key 248 #define LINUX_SYS_linux_request_key 249 #define LINUX_SYS_linux_keyctl 250 #define LINUX_SYS_linux_ioprio_set 251 #define LINUX_SYS_linux_ioprio_get 252 #define LINUX_SYS_linux_inotify_init 253 #define LINUX_SYS_linux_inotify_add_watch 254 #define LINUX_SYS_linux_inotify_rm_watch 255 #define LINUX_SYS_linux_migrate_pages 256 #define LINUX_SYS_linux_openat 257 #define LINUX_SYS_linux_mkdirat 258 #define LINUX_SYS_linux_mknodat 259 #define LINUX_SYS_linux_fchownat 260 #define LINUX_SYS_linux_futimesat 261 #define LINUX_SYS_linux_newfstatat 262 #define LINUX_SYS_linux_unlinkat 263 #define LINUX_SYS_linux_renameat 264 #define LINUX_SYS_linux_linkat 265 #define LINUX_SYS_linux_symlinkat 266 #define LINUX_SYS_linux_readlinkat 267 #define LINUX_SYS_linux_fchmodat 268 #define LINUX_SYS_linux_faccessat 269 #define LINUX_SYS_linux_pselect6 270 #define LINUX_SYS_linux_ppoll 271 #define LINUX_SYS_linux_unshare 272 #define LINUX_SYS_linux_set_robust_list 273 #define LINUX_SYS_linux_get_robust_list 274 #define LINUX_SYS_linux_splice 275 #define LINUX_SYS_linux_tee 276 #define LINUX_SYS_linux_sync_file_range 277 #define LINUX_SYS_linux_vmsplice 278 #define LINUX_SYS_linux_move_pages 279 #define LINUX_SYS_linux_utimensat 280 #define LINUX_SYS_linux_epoll_pwait 281 #define LINUX_SYS_linux_signalfd 282 -#define LINUX_SYS_linux_timerfd 283 +#define LINUX_SYS_linux_timerfd_create 283 #define LINUX_SYS_linux_eventfd 284 #define LINUX_SYS_linux_fallocate 285 #define LINUX_SYS_linux_timerfd_settime 286 #define LINUX_SYS_linux_timerfd_gettime 287 #define LINUX_SYS_linux_accept4 288 #define LINUX_SYS_linux_signalfd4 289 #define LINUX_SYS_linux_eventfd2 290 #define LINUX_SYS_linux_epoll_create1 291 #define LINUX_SYS_linux_dup3 292 #define LINUX_SYS_linux_pipe2 293 #define LINUX_SYS_linux_inotify_init1 294 #define LINUX_SYS_linux_preadv 295 #define LINUX_SYS_linux_pwritev 296 -#define LINUX_SYS_linux_rt_tsigqueueinfo 297 +#define LINUX_SYS_linux_rt_tgsigqueueinfo 297 #define LINUX_SYS_linux_perf_event_open 298 #define LINUX_SYS_linux_recvmmsg 299 #define LINUX_SYS_linux_fanotify_init 300 #define LINUX_SYS_linux_fanotify_mark 301 #define LINUX_SYS_linux_prlimit64 302 #define LINUX_SYS_linux_name_to_handle_at 303 #define LINUX_SYS_linux_open_by_handle_at 304 #define LINUX_SYS_linux_clock_adjtime 305 #define LINUX_SYS_linux_syncfs 306 #define LINUX_SYS_linux_sendmmsg 307 #define LINUX_SYS_linux_setns 308 -#define LINUX_SYS_linux_process_vm_readv 309 -#define LINUX_SYS_linux_process_vm_writev 310 -#define LINUX_SYS_linux_kcmp 311 -#define LINUX_SYS_linux_finit_module 312 -#define LINUX_SYS_MAXSYSCALL 314 +#define LINUX_SYS_linux_getcpu 309 +#define LINUX_SYS_linux_process_vm_readv 310 +#define LINUX_SYS_linux_process_vm_writev 311 +#define LINUX_SYS_linux_kcmp 312 +#define LINUX_SYS_linux_finit_module 313 +#define LINUX_SYS_linux_sched_setattr 314 +#define LINUX_SYS_linux_sched_getattr 315 +#define LINUX_SYS_linux_renameat2 316 +#define LINUX_SYS_linux_seccomp 317 +#define LINUX_SYS_linux_getrandom 318 +#define LINUX_SYS_linux_memfd_create 319 +#define LINUX_SYS_linux_kexec_file_load 320 +#define LINUX_SYS_linux_bpf 321 +#define LINUX_SYS_linux_execveat 322 +#define LINUX_SYS_linux_userfaultfd 323 +#define LINUX_SYS_linux_membarrier 324 +#define LINUX_SYS_linux_mlock2 325 +#define LINUX_SYS_linux_copy_file_range 326 +#define LINUX_SYS_linux_preadv2 327 +#define LINUX_SYS_linux_pwritev2 328 +#define LINUX_SYS_linux_pkey_mprotect 329 +#define LINUX_SYS_linux_pkey_alloc 330 +#define LINUX_SYS_linux_pkey_free 331 +#define LINUX_SYS_MAXSYSCALL 333 Index: projects/ipsec/sys/amd64/linux/linux_syscalls.c =================================================================== --- projects/ipsec/sys/amd64/linux/linux_syscalls.c (revision 313312) +++ projects/ipsec/sys/amd64/linux/linux_syscalls.c (revision 313313) @@ -1,325 +1,344 @@ /* * System call names. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/amd64/linux/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ const char *linux_syscallnames[] = { #define nosys linux_nosys "read", /* 0 = read */ "write", /* 1 = write */ "linux_open", /* 2 = linux_open */ "close", /* 3 = close */ "linux_newstat", /* 4 = linux_newstat */ "linux_newfstat", /* 5 = linux_newfstat */ "linux_newlstat", /* 6 = linux_newlstat */ "poll", /* 7 = poll */ "linux_lseek", /* 8 = linux_lseek */ "linux_mmap2", /* 9 = linux_mmap2 */ "linux_mprotect", /* 10 = linux_mprotect */ "munmap", /* 11 = munmap */ "linux_brk", /* 12 = linux_brk */ "linux_rt_sigaction", /* 13 = linux_rt_sigaction */ "linux_rt_sigprocmask", /* 14 = linux_rt_sigprocmask */ "linux_rt_sigreturn", /* 15 = linux_rt_sigreturn */ "linux_ioctl", /* 16 = linux_ioctl */ "linux_pread", /* 17 = linux_pread */ "linux_pwrite", /* 18 = linux_pwrite */ "readv", /* 19 = readv */ "writev", /* 20 = writev */ "linux_access", /* 21 = linux_access */ "linux_pipe", /* 22 = linux_pipe */ "linux_select", /* 23 = linux_select */ "sched_yield", /* 24 = sched_yield */ "linux_mremap", /* 25 = linux_mremap */ "linux_msync", /* 26 = linux_msync */ "linux_mincore", /* 27 = linux_mincore */ "madvise", /* 28 = madvise */ "linux_shmget", /* 29 = linux_shmget */ "linux_shmat", /* 30 = linux_shmat */ "linux_shmctl", /* 31 = linux_shmctl */ "dup", /* 32 = dup */ "dup2", /* 33 = dup2 */ "linux_pause", /* 34 = linux_pause */ "linux_nanosleep", /* 35 = linux_nanosleep */ "linux_getitimer", /* 36 = linux_getitimer */ "linux_alarm", /* 37 = linux_alarm */ "linux_setitimer", /* 38 = linux_setitimer */ "linux_getpid", /* 39 = linux_getpid */ "linux_sendfile", /* 40 = linux_sendfile */ "linux_socket", /* 41 = linux_socket */ "linux_connect", /* 42 = linux_connect */ "linux_accept", /* 43 = linux_accept */ "linux_sendto", /* 44 = linux_sendto */ "linux_recvfrom", /* 45 = linux_recvfrom */ "linux_sendmsg", /* 46 = linux_sendmsg */ "linux_recvmsg", /* 47 = linux_recvmsg */ "linux_shutdown", /* 48 = linux_shutdown */ "linux_bind", /* 49 = linux_bind */ "linux_listen", /* 50 = linux_listen */ "linux_getsockname", /* 51 = linux_getsockname */ "linux_getpeername", /* 52 = linux_getpeername */ "linux_socketpair", /* 53 = linux_socketpair */ "linux_setsockopt", /* 54 = linux_setsockopt */ "linux_getsockopt", /* 55 = linux_getsockopt */ "linux_clone", /* 56 = linux_clone */ "linux_fork", /* 57 = linux_fork */ "linux_vfork", /* 58 = linux_vfork */ "linux_execve", /* 59 = linux_execve */ "linux_exit", /* 60 = linux_exit */ "linux_wait4", /* 61 = linux_wait4 */ "linux_kill", /* 62 = linux_kill */ "linux_newuname", /* 63 = linux_newuname */ "linux_semget", /* 64 = linux_semget */ "linux_semop", /* 65 = linux_semop */ "linux_semctl", /* 66 = linux_semctl */ "linux_shmdt", /* 67 = linux_shmdt */ "linux_msgget", /* 68 = linux_msgget */ "linux_msgsnd", /* 69 = linux_msgsnd */ "linux_msgrcv", /* 70 = linux_msgrcv */ "linux_msgctl", /* 71 = linux_msgctl */ "linux_fcntl", /* 72 = linux_fcntl */ "flock", /* 73 = flock */ "fsync", /* 74 = fsync */ "linux_fdatasync", /* 75 = linux_fdatasync */ "linux_truncate", /* 76 = linux_truncate */ "linux_ftruncate", /* 77 = linux_ftruncate */ "linux_getdents", /* 78 = linux_getdents */ "linux_getcwd", /* 79 = linux_getcwd */ "linux_chdir", /* 80 = linux_chdir */ "fchdir", /* 81 = fchdir */ "linux_rename", /* 82 = linux_rename */ "linux_mkdir", /* 83 = linux_mkdir */ "linux_rmdir", /* 84 = linux_rmdir */ "linux_creat", /* 85 = linux_creat */ "linux_link", /* 86 = linux_link */ "linux_unlink", /* 87 = linux_unlink */ "linux_symlink", /* 88 = linux_symlink */ "linux_readlink", /* 89 = linux_readlink */ "linux_chmod", /* 90 = linux_chmod */ "fchmod", /* 91 = fchmod */ "linux_chown", /* 92 = linux_chown */ "fchown", /* 93 = fchown */ "linux_lchown", /* 94 = linux_lchown */ "umask", /* 95 = umask */ "gettimeofday", /* 96 = gettimeofday */ "linux_getrlimit", /* 97 = linux_getrlimit */ "getrusage", /* 98 = getrusage */ "linux_sysinfo", /* 99 = linux_sysinfo */ "linux_times", /* 100 = linux_times */ "linux_ptrace", /* 101 = linux_ptrace */ "linux_getuid", /* 102 = linux_getuid */ "linux_syslog", /* 103 = linux_syslog */ "linux_getgid", /* 104 = linux_getgid */ "setuid", /* 105 = setuid */ "setgid", /* 106 = setgid */ "geteuid", /* 107 = geteuid */ "getegid", /* 108 = getegid */ "setpgid", /* 109 = setpgid */ "linux_getppid", /* 110 = linux_getppid */ "getpgrp", /* 111 = getpgrp */ "setsid", /* 112 = setsid */ "setreuid", /* 113 = setreuid */ "setregid", /* 114 = setregid */ "linux_getgroups", /* 115 = linux_getgroups */ "linux_setgroups", /* 116 = linux_setgroups */ "setresuid", /* 117 = setresuid */ "getresuid", /* 118 = getresuid */ "setresgid", /* 119 = setresgid */ "getresgid", /* 120 = getresgid */ "getpgid", /* 121 = getpgid */ "linux_setfsuid", /* 122 = linux_setfsuid */ "linux_setfsgid", /* 123 = linux_setfsgid */ "linux_getsid", /* 124 = linux_getsid */ "linux_capget", /* 125 = linux_capget */ "linux_capset", /* 126 = linux_capset */ "linux_rt_sigpending", /* 127 = linux_rt_sigpending */ "linux_rt_sigtimedwait", /* 128 = linux_rt_sigtimedwait */ "linux_rt_sigqueueinfo", /* 129 = linux_rt_sigqueueinfo */ "linux_rt_sigsuspend", /* 130 = linux_rt_sigsuspend */ "linux_sigaltstack", /* 131 = linux_sigaltstack */ "linux_utime", /* 132 = linux_utime */ "linux_mknod", /* 133 = linux_mknod */ "#134", /* 134 = uselib */ "linux_personality", /* 135 = linux_personality */ "linux_ustat", /* 136 = linux_ustat */ "linux_statfs", /* 137 = linux_statfs */ "linux_fstatfs", /* 138 = linux_fstatfs */ "linux_sysfs", /* 139 = linux_sysfs */ "linux_getpriority", /* 140 = linux_getpriority */ "setpriority", /* 141 = setpriority */ "linux_sched_setparam", /* 142 = linux_sched_setparam */ "linux_sched_getparam", /* 143 = linux_sched_getparam */ "linux_sched_setscheduler", /* 144 = linux_sched_setscheduler */ "linux_sched_getscheduler", /* 145 = linux_sched_getscheduler */ "linux_sched_get_priority_max", /* 146 = linux_sched_get_priority_max */ "linux_sched_get_priority_min", /* 147 = linux_sched_get_priority_min */ "linux_sched_rr_get_interval", /* 148 = linux_sched_rr_get_interval */ "mlock", /* 149 = mlock */ "munlock", /* 150 = munlock */ "mlockall", /* 151 = mlockall */ "munlockall", /* 152 = munlockall */ "linux_vhangup", /* 153 = linux_vhangup */ "#154", /* 154 = modify_ldt */ "linux_pivot_root", /* 155 = linux_pivot_root */ "linux_sysctl", /* 156 = linux_sysctl */ "linux_prctl", /* 157 = linux_prctl */ "linux_arch_prctl", /* 158 = linux_arch_prctl */ "linux_adjtimex", /* 159 = linux_adjtimex */ "linux_setrlimit", /* 160 = linux_setrlimit */ "chroot", /* 161 = chroot */ "sync", /* 162 = sync */ "acct", /* 163 = acct */ "settimeofday", /* 164 = settimeofday */ "linux_mount", /* 165 = linux_mount */ "linux_umount", /* 166 = linux_umount */ "swapon", /* 167 = swapon */ "linux_swapoff", /* 168 = linux_swapoff */ "linux_reboot", /* 169 = linux_reboot */ "linux_sethostname", /* 170 = linux_sethostname */ "linux_setdomainname", /* 171 = linux_setdomainname */ "linux_iopl", /* 172 = linux_iopl */ "#173", /* 173 = ioperm */ "linux_create_module", /* 174 = linux_create_module */ "linux_init_module", /* 175 = linux_init_module */ "linux_delete_module", /* 176 = linux_delete_module */ "linux_get_kernel_syms", /* 177 = linux_get_kernel_syms */ "linux_query_module", /* 178 = linux_query_module */ "linux_quotactl", /* 179 = linux_quotactl */ "linux_nfsservctl", /* 180 = linux_nfsservctl */ "linux_getpmsg", /* 181 = linux_getpmsg */ "linux_putpmsg", /* 182 = linux_putpmsg */ "linux_afs_syscall", /* 183 = linux_afs_syscall */ "linux_tuxcall", /* 184 = linux_tuxcall */ "linux_security", /* 185 = linux_security */ "linux_gettid", /* 186 = linux_gettid */ "#187", /* 187 = linux_readahead */ "linux_setxattr", /* 188 = linux_setxattr */ "linux_lsetxattr", /* 189 = linux_lsetxattr */ "linux_fsetxattr", /* 190 = linux_fsetxattr */ "linux_getxattr", /* 191 = linux_getxattr */ "linux_lgetxattr", /* 192 = linux_lgetxattr */ "linux_fgetxattr", /* 193 = linux_fgetxattr */ "linux_listxattr", /* 194 = linux_listxattr */ "linux_llistxattr", /* 195 = linux_llistxattr */ "linux_flistxattr", /* 196 = linux_flistxattr */ "linux_removexattr", /* 197 = linux_removexattr */ "linux_lremovexattr", /* 198 = linux_lremovexattr */ "linux_fremovexattr", /* 199 = linux_fremovexattr */ "linux_tkill", /* 200 = linux_tkill */ "linux_time", /* 201 = linux_time */ "linux_sys_futex", /* 202 = linux_sys_futex */ "linux_sched_setaffinity", /* 203 = linux_sched_setaffinity */ "linux_sched_getaffinity", /* 204 = linux_sched_getaffinity */ "linux_set_thread_area", /* 205 = linux_set_thread_area */ "#206", /* 206 = linux_io_setup */ "#207", /* 207 = linux_io_destroy */ "#208", /* 208 = linux_io_getevents */ - "#209", /* 209 = inux_io_submit */ + "#209", /* 209 = linux_io_submit */ "#210", /* 210 = linux_io_cancel */ "#211", /* 211 = linux_get_thread_area */ "linux_lookup_dcookie", /* 212 = linux_lookup_dcookie */ "linux_epoll_create", /* 213 = linux_epoll_create */ "linux_epoll_ctl_old", /* 214 = linux_epoll_ctl_old */ "linux_epoll_wait_old", /* 215 = linux_epoll_wait_old */ "linux_remap_file_pages", /* 216 = linux_remap_file_pages */ "linux_getdents64", /* 217 = linux_getdents64 */ "linux_set_tid_address", /* 218 = linux_set_tid_address */ "#219", /* 219 = restart_syscall */ "linux_semtimedop", /* 220 = linux_semtimedop */ "linux_fadvise64", /* 221 = linux_fadvise64 */ "linux_timer_create", /* 222 = linux_timer_create */ "linux_timer_settime", /* 223 = linux_timer_settime */ "linux_timer_gettime", /* 224 = linux_timer_gettime */ "linux_timer_getoverrun", /* 225 = linux_timer_getoverrun */ "linux_timer_delete", /* 226 = linux_timer_delete */ "linux_clock_settime", /* 227 = linux_clock_settime */ "linux_clock_gettime", /* 228 = linux_clock_gettime */ "linux_clock_getres", /* 229 = linux_clock_getres */ "linux_clock_nanosleep", /* 230 = linux_clock_nanosleep */ "linux_exit_group", /* 231 = linux_exit_group */ "linux_epoll_wait", /* 232 = linux_epoll_wait */ "linux_epoll_ctl", /* 233 = linux_epoll_ctl */ "linux_tgkill", /* 234 = linux_tgkill */ "linux_utimes", /* 235 = linux_utimes */ "#236", /* 236 = vserver */ "linux_mbind", /* 237 = linux_mbind */ "linux_set_mempolicy", /* 238 = linux_set_mempolicy */ "linux_get_mempolicy", /* 239 = linux_get_mempolicy */ "linux_mq_open", /* 240 = linux_mq_open */ "linux_mq_unlink", /* 241 = linux_mq_unlink */ "linux_mq_timedsend", /* 242 = linux_mq_timedsend */ "linux_mq_timedreceive", /* 243 = linux_mq_timedreceive */ "linux_mq_notify", /* 244 = linux_mq_notify */ "linux_mq_getsetattr", /* 245 = linux_mq_getsetattr */ "linux_kexec_load", /* 246 = linux_kexec_load */ "linux_waitid", /* 247 = linux_waitid */ "linux_add_key", /* 248 = linux_add_key */ "linux_request_key", /* 249 = linux_request_key */ "linux_keyctl", /* 250 = linux_keyctl */ "linux_ioprio_set", /* 251 = linux_ioprio_set */ "linux_ioprio_get", /* 252 = linux_ioprio_get */ "linux_inotify_init", /* 253 = linux_inotify_init */ "linux_inotify_add_watch", /* 254 = linux_inotify_add_watch */ "linux_inotify_rm_watch", /* 255 = linux_inotify_rm_watch */ "linux_migrate_pages", /* 256 = linux_migrate_pages */ "linux_openat", /* 257 = linux_openat */ "linux_mkdirat", /* 258 = linux_mkdirat */ "linux_mknodat", /* 259 = linux_mknodat */ "linux_fchownat", /* 260 = linux_fchownat */ "linux_futimesat", /* 261 = linux_futimesat */ "linux_newfstatat", /* 262 = linux_newfstatat */ "linux_unlinkat", /* 263 = linux_unlinkat */ "linux_renameat", /* 264 = linux_renameat */ "linux_linkat", /* 265 = linux_linkat */ "linux_symlinkat", /* 266 = linux_symlinkat */ "linux_readlinkat", /* 267 = linux_readlinkat */ "linux_fchmodat", /* 268 = linux_fchmodat */ "linux_faccessat", /* 269 = linux_faccessat */ "linux_pselect6", /* 270 = linux_pselect6 */ "linux_ppoll", /* 271 = linux_ppoll */ "linux_unshare", /* 272 = linux_unshare */ "linux_set_robust_list", /* 273 = linux_set_robust_list */ "linux_get_robust_list", /* 274 = linux_get_robust_list */ "linux_splice", /* 275 = linux_splice */ "linux_tee", /* 276 = linux_tee */ "linux_sync_file_range", /* 277 = linux_sync_file_range */ "linux_vmsplice", /* 278 = linux_vmsplice */ "linux_move_pages", /* 279 = linux_move_pages */ "linux_utimensat", /* 280 = linux_utimensat */ "linux_epoll_pwait", /* 281 = linux_epoll_pwait */ "linux_signalfd", /* 282 = linux_signalfd */ - "linux_timerfd", /* 283 = linux_timerfd */ + "linux_timerfd_create", /* 283 = linux_timerfd_create */ "linux_eventfd", /* 284 = linux_eventfd */ "linux_fallocate", /* 285 = linux_fallocate */ "linux_timerfd_settime", /* 286 = linux_timerfd_settime */ "linux_timerfd_gettime", /* 287 = linux_timerfd_gettime */ "linux_accept4", /* 288 = linux_accept4 */ "linux_signalfd4", /* 289 = linux_signalfd4 */ "linux_eventfd2", /* 290 = linux_eventfd2 */ "linux_epoll_create1", /* 291 = linux_epoll_create1 */ "linux_dup3", /* 292 = linux_dup3 */ "linux_pipe2", /* 293 = linux_pipe2 */ "linux_inotify_init1", /* 294 = linux_inotify_init1 */ "linux_preadv", /* 295 = linux_preadv */ "linux_pwritev", /* 296 = linux_pwritev */ - "linux_rt_tsigqueueinfo", /* 297 = linux_rt_tsigqueueinfo */ + "linux_rt_tgsigqueueinfo", /* 297 = linux_rt_tgsigqueueinfo */ "linux_perf_event_open", /* 298 = linux_perf_event_open */ "linux_recvmmsg", /* 299 = linux_recvmmsg */ "linux_fanotify_init", /* 300 = linux_fanotify_init */ "linux_fanotify_mark", /* 301 = linux_fanotify_mark */ "linux_prlimit64", /* 302 = linux_prlimit64 */ "linux_name_to_handle_at", /* 303 = linux_name_to_handle_at */ "linux_open_by_handle_at", /* 304 = linux_open_by_handle_at */ "linux_clock_adjtime", /* 305 = linux_clock_adjtime */ "linux_syncfs", /* 306 = linux_syncfs */ "linux_sendmmsg", /* 307 = linux_sendmmsg */ "linux_setns", /* 308 = linux_setns */ - "linux_process_vm_readv", /* 309 = linux_process_vm_readv */ - "linux_process_vm_writev", /* 310 = linux_process_vm_writev */ - "linux_kcmp", /* 311 = linux_kcmp */ - "linux_finit_module", /* 312 = linux_finit_module */ - "#313", /* 313 = nosys */ + "linux_getcpu", /* 309 = linux_getcpu */ + "linux_process_vm_readv", /* 310 = linux_process_vm_readv */ + "linux_process_vm_writev", /* 311 = linux_process_vm_writev */ + "linux_kcmp", /* 312 = linux_kcmp */ + "linux_finit_module", /* 313 = linux_finit_module */ + "linux_sched_setattr", /* 314 = linux_sched_setattr */ + "linux_sched_getattr", /* 315 = linux_sched_getattr */ + "linux_renameat2", /* 316 = linux_renameat2 */ + "linux_seccomp", /* 317 = linux_seccomp */ + "linux_getrandom", /* 318 = linux_getrandom */ + "linux_memfd_create", /* 319 = linux_memfd_create */ + "linux_kexec_file_load", /* 320 = linux_kexec_file_load */ + "linux_bpf", /* 321 = linux_bpf */ + "linux_execveat", /* 322 = linux_execveat */ + "linux_userfaultfd", /* 323 = linux_userfaultfd */ + "linux_membarrier", /* 324 = linux_membarrier */ + "linux_mlock2", /* 325 = linux_mlock2 */ + "linux_copy_file_range", /* 326 = linux_copy_file_range */ + "linux_preadv2", /* 327 = linux_preadv2 */ + "linux_pwritev2", /* 328 = linux_pwritev2 */ + "linux_pkey_mprotect", /* 329 = linux_pkey_mprotect */ + "linux_pkey_alloc", /* 330 = linux_pkey_alloc */ + "linux_pkey_free", /* 331 = linux_pkey_free */ + "#332", /* 332 = nosys */ }; Index: projects/ipsec/sys/amd64/linux/linux_sysent.c =================================================================== --- projects/ipsec/sys/amd64/linux/linux_sysent.c (revision 313312) +++ projects/ipsec/sys/amd64/linux/linux_sysent.c (revision 313313) @@ -1,335 +1,354 @@ /* * System call switch table. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/amd64/linux/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ #include #include #include #include #include #include #define AS(name) (sizeof(struct name) / sizeof(register_t)) /* The casts are bogus but will do for now. */ struct sysent linux_sysent[] = { #define nosys linux_nosys { AS(read_args), (sy_call_t *)sys_read, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 0 = read */ { AS(write_args), (sy_call_t *)sys_write, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 1 = write */ { AS(linux_open_args), (sy_call_t *)linux_open, AUE_OPEN_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 2 = linux_open */ { AS(close_args), (sy_call_t *)sys_close, AUE_CLOSE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 3 = close */ { AS(linux_newstat_args), (sy_call_t *)linux_newstat, AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 4 = linux_newstat */ { AS(linux_newfstat_args), (sy_call_t *)linux_newfstat, AUE_FSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 5 = linux_newfstat */ { AS(linux_newlstat_args), (sy_call_t *)linux_newlstat, AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 6 = linux_newlstat */ { AS(poll_args), (sy_call_t *)sys_poll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 7 = poll */ { AS(linux_lseek_args), (sy_call_t *)linux_lseek, AUE_LSEEK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 8 = linux_lseek */ { AS(linux_mmap2_args), (sy_call_t *)linux_mmap2, AUE_MMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 9 = linux_mmap2 */ { AS(linux_mprotect_args), (sy_call_t *)linux_mprotect, AUE_MPROTECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 10 = linux_mprotect */ { AS(munmap_args), (sy_call_t *)sys_munmap, AUE_MUNMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 11 = munmap */ { AS(linux_brk_args), (sy_call_t *)linux_brk, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 12 = linux_brk */ { AS(linux_rt_sigaction_args), (sy_call_t *)linux_rt_sigaction, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 13 = linux_rt_sigaction */ { AS(linux_rt_sigprocmask_args), (sy_call_t *)linux_rt_sigprocmask, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 14 = linux_rt_sigprocmask */ { AS(linux_rt_sigreturn_args), (sy_call_t *)linux_rt_sigreturn, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 15 = linux_rt_sigreturn */ { AS(linux_ioctl_args), (sy_call_t *)linux_ioctl, AUE_IOCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 16 = linux_ioctl */ { AS(linux_pread_args), (sy_call_t *)linux_pread, AUE_PREAD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 17 = linux_pread */ { AS(linux_pwrite_args), (sy_call_t *)linux_pwrite, AUE_PWRITE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 18 = linux_pwrite */ { AS(readv_args), (sy_call_t *)sys_readv, AUE_READV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 19 = readv */ { AS(writev_args), (sy_call_t *)sys_writev, AUE_WRITEV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 20 = writev */ { AS(linux_access_args), (sy_call_t *)linux_access, AUE_ACCESS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 21 = linux_access */ { AS(linux_pipe_args), (sy_call_t *)linux_pipe, AUE_PIPE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 22 = linux_pipe */ { AS(linux_select_args), (sy_call_t *)linux_select, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 23 = linux_select */ { 0, (sy_call_t *)sys_sched_yield, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 24 = sched_yield */ { AS(linux_mremap_args), (sy_call_t *)linux_mremap, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 25 = linux_mremap */ { AS(linux_msync_args), (sy_call_t *)linux_msync, AUE_MSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 26 = linux_msync */ { AS(linux_mincore_args), (sy_call_t *)linux_mincore, AUE_MINCORE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 27 = linux_mincore */ { AS(madvise_args), (sy_call_t *)sys_madvise, AUE_MADVISE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 28 = madvise */ { AS(linux_shmget_args), (sy_call_t *)linux_shmget, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 29 = linux_shmget */ { AS(linux_shmat_args), (sy_call_t *)linux_shmat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 30 = linux_shmat */ { AS(linux_shmctl_args), (sy_call_t *)linux_shmctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 31 = linux_shmctl */ { AS(dup_args), (sy_call_t *)sys_dup, AUE_DUP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 32 = dup */ { AS(dup2_args), (sy_call_t *)sys_dup2, AUE_DUP2, NULL, 0, 0, 0, SY_THR_STATIC }, /* 33 = dup2 */ { 0, (sy_call_t *)linux_pause, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 34 = linux_pause */ { AS(linux_nanosleep_args), (sy_call_t *)linux_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 35 = linux_nanosleep */ { AS(linux_getitimer_args), (sy_call_t *)linux_getitimer, AUE_GETITIMER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 36 = linux_getitimer */ { AS(linux_alarm_args), (sy_call_t *)linux_alarm, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 37 = linux_alarm */ { AS(linux_setitimer_args), (sy_call_t *)linux_setitimer, AUE_SETITIMER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 38 = linux_setitimer */ { 0, (sy_call_t *)linux_getpid, AUE_GETPID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 39 = linux_getpid */ { AS(linux_sendfile_args), (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 40 = linux_sendfile */ { AS(linux_socket_args), (sy_call_t *)linux_socket, AUE_SOCKET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 41 = linux_socket */ { AS(linux_connect_args), (sy_call_t *)linux_connect, AUE_CONNECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 42 = linux_connect */ { AS(linux_accept_args), (sy_call_t *)linux_accept, AUE_ACCEPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 43 = linux_accept */ { AS(linux_sendto_args), (sy_call_t *)linux_sendto, AUE_SENDTO, NULL, 0, 0, 0, SY_THR_STATIC }, /* 44 = linux_sendto */ { AS(linux_recvfrom_args), (sy_call_t *)linux_recvfrom, AUE_RECVFROM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 45 = linux_recvfrom */ { AS(linux_sendmsg_args), (sy_call_t *)linux_sendmsg, AUE_SENDMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 46 = linux_sendmsg */ { AS(linux_recvmsg_args), (sy_call_t *)linux_recvmsg, AUE_RECVMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 47 = linux_recvmsg */ { AS(linux_shutdown_args), (sy_call_t *)linux_shutdown, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 48 = linux_shutdown */ { AS(linux_bind_args), (sy_call_t *)linux_bind, AUE_BIND, NULL, 0, 0, 0, SY_THR_STATIC }, /* 49 = linux_bind */ { AS(linux_listen_args), (sy_call_t *)linux_listen, AUE_LISTEN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 50 = linux_listen */ { AS(linux_getsockname_args), (sy_call_t *)linux_getsockname, AUE_GETSOCKNAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 51 = linux_getsockname */ { AS(linux_getpeername_args), (sy_call_t *)linux_getpeername, AUE_GETPEERNAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 52 = linux_getpeername */ { AS(linux_socketpair_args), (sy_call_t *)linux_socketpair, AUE_SOCKETPAIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 53 = linux_socketpair */ { AS(linux_setsockopt_args), (sy_call_t *)linux_setsockopt, AUE_SETSOCKOPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 54 = linux_setsockopt */ { AS(linux_getsockopt_args), (sy_call_t *)linux_getsockopt, AUE_GETSOCKOPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 55 = linux_getsockopt */ { AS(linux_clone_args), (sy_call_t *)linux_clone, AUE_RFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 56 = linux_clone */ { 0, (sy_call_t *)linux_fork, AUE_FORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 57 = linux_fork */ { 0, (sy_call_t *)linux_vfork, AUE_VFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 58 = linux_vfork */ { AS(linux_execve_args), (sy_call_t *)linux_execve, AUE_EXECVE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 59 = linux_execve */ { AS(linux_exit_args), (sy_call_t *)linux_exit, AUE_EXIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 60 = linux_exit */ { AS(linux_wait4_args), (sy_call_t *)linux_wait4, AUE_WAIT4, NULL, 0, 0, 0, SY_THR_STATIC }, /* 61 = linux_wait4 */ { AS(linux_kill_args), (sy_call_t *)linux_kill, AUE_KILL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 62 = linux_kill */ { AS(linux_newuname_args), (sy_call_t *)linux_newuname, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 63 = linux_newuname */ { AS(linux_semget_args), (sy_call_t *)linux_semget, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 64 = linux_semget */ { AS(linux_semop_args), (sy_call_t *)linux_semop, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 65 = linux_semop */ { AS(linux_semctl_args), (sy_call_t *)linux_semctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 66 = linux_semctl */ { AS(linux_shmdt_args), (sy_call_t *)linux_shmdt, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 67 = linux_shmdt */ { AS(linux_msgget_args), (sy_call_t *)linux_msgget, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 68 = linux_msgget */ { AS(linux_msgsnd_args), (sy_call_t *)linux_msgsnd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 69 = linux_msgsnd */ { AS(linux_msgrcv_args), (sy_call_t *)linux_msgrcv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 70 = linux_msgrcv */ { AS(linux_msgctl_args), (sy_call_t *)linux_msgctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 71 = linux_msgctl */ { AS(linux_fcntl_args), (sy_call_t *)linux_fcntl, AUE_FCNTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 72 = linux_fcntl */ { AS(flock_args), (sy_call_t *)sys_flock, AUE_FLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 73 = flock */ { AS(fsync_args), (sy_call_t *)sys_fsync, AUE_FSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 74 = fsync */ { AS(linux_fdatasync_args), (sy_call_t *)linux_fdatasync, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 75 = linux_fdatasync */ { AS(linux_truncate_args), (sy_call_t *)linux_truncate, AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 76 = linux_truncate */ { AS(linux_ftruncate_args), (sy_call_t *)linux_ftruncate, AUE_FTRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 77 = linux_ftruncate */ { AS(linux_getdents_args), (sy_call_t *)linux_getdents, AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 78 = linux_getdents */ { AS(linux_getcwd_args), (sy_call_t *)linux_getcwd, AUE_GETCWD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 79 = linux_getcwd */ { AS(linux_chdir_args), (sy_call_t *)linux_chdir, AUE_CHDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 80 = linux_chdir */ { AS(fchdir_args), (sy_call_t *)sys_fchdir, AUE_FCHDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 81 = fchdir */ { AS(linux_rename_args), (sy_call_t *)linux_rename, AUE_RENAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 82 = linux_rename */ { AS(linux_mkdir_args), (sy_call_t *)linux_mkdir, AUE_MKDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 83 = linux_mkdir */ { AS(linux_rmdir_args), (sy_call_t *)linux_rmdir, AUE_RMDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 84 = linux_rmdir */ { AS(linux_creat_args), (sy_call_t *)linux_creat, AUE_CREAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 85 = linux_creat */ { AS(linux_link_args), (sy_call_t *)linux_link, AUE_LINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 86 = linux_link */ { AS(linux_unlink_args), (sy_call_t *)linux_unlink, AUE_UNLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 87 = linux_unlink */ { AS(linux_symlink_args), (sy_call_t *)linux_symlink, AUE_SYMLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 88 = linux_symlink */ { AS(linux_readlink_args), (sy_call_t *)linux_readlink, AUE_READLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 89 = linux_readlink */ { AS(linux_chmod_args), (sy_call_t *)linux_chmod, AUE_CHMOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 90 = linux_chmod */ { AS(fchmod_args), (sy_call_t *)sys_fchmod, AUE_FCHMOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 91 = fchmod */ { AS(linux_chown_args), (sy_call_t *)linux_chown, AUE_LCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 92 = linux_chown */ { AS(fchown_args), (sy_call_t *)sys_fchown, AUE_FCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 93 = fchown */ { AS(linux_lchown_args), (sy_call_t *)linux_lchown, AUE_LCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 94 = linux_lchown */ { AS(umask_args), (sy_call_t *)sys_umask, AUE_UMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 95 = umask */ { AS(gettimeofday_args), (sy_call_t *)sys_gettimeofday, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 96 = gettimeofday */ { AS(linux_getrlimit_args), (sy_call_t *)linux_getrlimit, AUE_GETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 97 = linux_getrlimit */ { AS(getrusage_args), (sy_call_t *)sys_getrusage, AUE_GETRUSAGE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 98 = getrusage */ { AS(linux_sysinfo_args), (sy_call_t *)linux_sysinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 99 = linux_sysinfo */ { AS(linux_times_args), (sy_call_t *)linux_times, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 100 = linux_times */ { AS(linux_ptrace_args), (sy_call_t *)linux_ptrace, AUE_PTRACE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 101 = linux_ptrace */ { 0, (sy_call_t *)linux_getuid, AUE_GETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 102 = linux_getuid */ { AS(linux_syslog_args), (sy_call_t *)linux_syslog, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 103 = linux_syslog */ { 0, (sy_call_t *)linux_getgid, AUE_GETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 104 = linux_getgid */ { AS(setuid_args), (sy_call_t *)sys_setuid, AUE_SETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 105 = setuid */ { AS(setgid_args), (sy_call_t *)sys_setgid, AUE_SETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 106 = setgid */ { 0, (sy_call_t *)sys_geteuid, AUE_GETEUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 107 = geteuid */ { 0, (sy_call_t *)sys_getegid, AUE_GETEGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 108 = getegid */ { AS(setpgid_args), (sy_call_t *)sys_setpgid, AUE_SETPGRP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 109 = setpgid */ { 0, (sy_call_t *)linux_getppid, AUE_GETPPID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 110 = linux_getppid */ { 0, (sy_call_t *)sys_getpgrp, AUE_GETPGRP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 111 = getpgrp */ { 0, (sy_call_t *)sys_setsid, AUE_SETSID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 112 = setsid */ { AS(setreuid_args), (sy_call_t *)sys_setreuid, AUE_SETREUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 113 = setreuid */ { AS(setregid_args), (sy_call_t *)sys_setregid, AUE_SETREGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 114 = setregid */ { AS(linux_getgroups_args), (sy_call_t *)linux_getgroups, AUE_GETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 115 = linux_getgroups */ { AS(linux_setgroups_args), (sy_call_t *)linux_setgroups, AUE_SETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 116 = linux_setgroups */ { AS(setresuid_args), (sy_call_t *)sys_setresuid, AUE_SETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 117 = setresuid */ { AS(getresuid_args), (sy_call_t *)sys_getresuid, AUE_GETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 118 = getresuid */ { AS(setresgid_args), (sy_call_t *)sys_setresgid, AUE_SETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 119 = setresgid */ { AS(getresgid_args), (sy_call_t *)sys_getresgid, AUE_GETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 120 = getresgid */ { AS(getpgid_args), (sy_call_t *)sys_getpgid, AUE_GETPGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 121 = getpgid */ { AS(linux_setfsuid_args), (sy_call_t *)linux_setfsuid, AUE_SETFSUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 122 = linux_setfsuid */ { AS(linux_setfsgid_args), (sy_call_t *)linux_setfsgid, AUE_SETFSGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 123 = linux_setfsgid */ { AS(linux_getsid_args), (sy_call_t *)linux_getsid, AUE_GETSID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 124 = linux_getsid */ { AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 125 = linux_capget */ { AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 126 = linux_capset */ { AS(linux_rt_sigpending_args), (sy_call_t *)linux_rt_sigpending, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 127 = linux_rt_sigpending */ { AS(linux_rt_sigtimedwait_args), (sy_call_t *)linux_rt_sigtimedwait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 128 = linux_rt_sigtimedwait */ { AS(linux_rt_sigqueueinfo_args), (sy_call_t *)linux_rt_sigqueueinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 129 = linux_rt_sigqueueinfo */ { AS(linux_rt_sigsuspend_args), (sy_call_t *)linux_rt_sigsuspend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 130 = linux_rt_sigsuspend */ { AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 131 = linux_sigaltstack */ { AS(linux_utime_args), (sy_call_t *)linux_utime, AUE_UTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 132 = linux_utime */ { AS(linux_mknod_args), (sy_call_t *)linux_mknod, AUE_MKNOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 133 = linux_mknod */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 134 = uselib */ { AS(linux_personality_args), (sy_call_t *)linux_personality, AUE_PERSONALITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 135 = linux_personality */ { AS(linux_ustat_args), (sy_call_t *)linux_ustat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 136 = linux_ustat */ { AS(linux_statfs_args), (sy_call_t *)linux_statfs, AUE_STATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 137 = linux_statfs */ { AS(linux_fstatfs_args), (sy_call_t *)linux_fstatfs, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 138 = linux_fstatfs */ { AS(linux_sysfs_args), (sy_call_t *)linux_sysfs, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 139 = linux_sysfs */ { AS(linux_getpriority_args), (sy_call_t *)linux_getpriority, AUE_GETPRIORITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 140 = linux_getpriority */ { AS(setpriority_args), (sy_call_t *)sys_setpriority, AUE_SETPRIORITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 141 = setpriority */ { AS(linux_sched_setparam_args), (sy_call_t *)linux_sched_setparam, AUE_SCHED_SETPARAM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 142 = linux_sched_setparam */ { AS(linux_sched_getparam_args), (sy_call_t *)linux_sched_getparam, AUE_SCHED_GETPARAM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 143 = linux_sched_getparam */ { AS(linux_sched_setscheduler_args), (sy_call_t *)linux_sched_setscheduler, AUE_SCHED_SETSCHEDULER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 144 = linux_sched_setscheduler */ { AS(linux_sched_getscheduler_args), (sy_call_t *)linux_sched_getscheduler, AUE_SCHED_GETSCHEDULER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 145 = linux_sched_getscheduler */ { AS(linux_sched_get_priority_max_args), (sy_call_t *)linux_sched_get_priority_max, AUE_SCHED_GET_PRIORITY_MAX, NULL, 0, 0, 0, SY_THR_STATIC }, /* 146 = linux_sched_get_priority_max */ { AS(linux_sched_get_priority_min_args), (sy_call_t *)linux_sched_get_priority_min, AUE_SCHED_GET_PRIORITY_MIN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 147 = linux_sched_get_priority_min */ { AS(linux_sched_rr_get_interval_args), (sy_call_t *)linux_sched_rr_get_interval, AUE_SCHED_RR_GET_INTERVAL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 148 = linux_sched_rr_get_interval */ { AS(mlock_args), (sy_call_t *)sys_mlock, AUE_MLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 149 = mlock */ { AS(munlock_args), (sy_call_t *)sys_munlock, AUE_MUNLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 150 = munlock */ { AS(mlockall_args), (sy_call_t *)sys_mlockall, AUE_MLOCKALL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 151 = mlockall */ { 0, (sy_call_t *)sys_munlockall, AUE_MUNLOCKALL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 152 = munlockall */ { 0, (sy_call_t *)linux_vhangup, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 153 = linux_vhangup */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 154 = modify_ldt */ { 0, (sy_call_t *)linux_pivot_root, AUE_PIVOT_ROOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 155 = linux_pivot_root */ { AS(linux_sysctl_args), (sy_call_t *)linux_sysctl, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 156 = linux_sysctl */ { AS(linux_prctl_args), (sy_call_t *)linux_prctl, AUE_PRCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 157 = linux_prctl */ { AS(linux_arch_prctl_args), (sy_call_t *)linux_arch_prctl, AUE_PRCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 158 = linux_arch_prctl */ { 0, (sy_call_t *)linux_adjtimex, AUE_ADJTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 159 = linux_adjtimex */ { AS(linux_setrlimit_args), (sy_call_t *)linux_setrlimit, AUE_SETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 160 = linux_setrlimit */ { AS(chroot_args), (sy_call_t *)sys_chroot, AUE_CHROOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 161 = chroot */ { 0, (sy_call_t *)sys_sync, AUE_SYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 162 = sync */ { AS(acct_args), (sy_call_t *)sys_acct, AUE_ACCT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 163 = acct */ { AS(settimeofday_args), (sy_call_t *)sys_settimeofday, AUE_SETTIMEOFDAY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 164 = settimeofday */ { AS(linux_mount_args), (sy_call_t *)linux_mount, AUE_MOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 165 = linux_mount */ { AS(linux_umount_args), (sy_call_t *)linux_umount, AUE_UMOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 166 = linux_umount */ { AS(swapon_args), (sy_call_t *)sys_swapon, AUE_SWAPON, NULL, 0, 0, 0, SY_THR_STATIC }, /* 167 = swapon */ { 0, (sy_call_t *)linux_swapoff, AUE_SWAPOFF, NULL, 0, 0, 0, SY_THR_STATIC }, /* 168 = linux_swapoff */ { AS(linux_reboot_args), (sy_call_t *)linux_reboot, AUE_REBOOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 169 = linux_reboot */ { AS(linux_sethostname_args), (sy_call_t *)linux_sethostname, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 170 = linux_sethostname */ { AS(linux_setdomainname_args), (sy_call_t *)linux_setdomainname, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 171 = linux_setdomainname */ { AS(linux_iopl_args), (sy_call_t *)linux_iopl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 172 = linux_iopl */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 173 = ioperm */ { 0, (sy_call_t *)linux_create_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 174 = linux_create_module */ { 0, (sy_call_t *)linux_init_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 175 = linux_init_module */ { 0, (sy_call_t *)linux_delete_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 176 = linux_delete_module */ { 0, (sy_call_t *)linux_get_kernel_syms, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 177 = linux_get_kernel_syms */ { 0, (sy_call_t *)linux_query_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 178 = linux_query_module */ { 0, (sy_call_t *)linux_quotactl, AUE_QUOTACTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 179 = linux_quotactl */ { 0, (sy_call_t *)linux_nfsservctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 180 = linux_nfsservctl */ { 0, (sy_call_t *)linux_getpmsg, AUE_GETPMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 181 = linux_getpmsg */ { 0, (sy_call_t *)linux_putpmsg, AUE_PUTPMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 182 = linux_putpmsg */ { 0, (sy_call_t *)linux_afs_syscall, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 183 = linux_afs_syscall */ { 0, (sy_call_t *)linux_tuxcall, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 184 = linux_tuxcall */ { 0, (sy_call_t *)linux_security, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 185 = linux_security */ { 0, (sy_call_t *)linux_gettid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 186 = linux_gettid */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 187 = linux_readahead */ { 0, (sy_call_t *)linux_setxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 188 = linux_setxattr */ { 0, (sy_call_t *)linux_lsetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 189 = linux_lsetxattr */ { 0, (sy_call_t *)linux_fsetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 190 = linux_fsetxattr */ { 0, (sy_call_t *)linux_getxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 191 = linux_getxattr */ { 0, (sy_call_t *)linux_lgetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 192 = linux_lgetxattr */ { 0, (sy_call_t *)linux_fgetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 193 = linux_fgetxattr */ { 0, (sy_call_t *)linux_listxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 194 = linux_listxattr */ { 0, (sy_call_t *)linux_llistxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 195 = linux_llistxattr */ { 0, (sy_call_t *)linux_flistxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 196 = linux_flistxattr */ { 0, (sy_call_t *)linux_removexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 197 = linux_removexattr */ { 0, (sy_call_t *)linux_lremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 198 = linux_lremovexattr */ { 0, (sy_call_t *)linux_fremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 199 = linux_fremovexattr */ { AS(linux_tkill_args), (sy_call_t *)linux_tkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 200 = linux_tkill */ { AS(linux_time_args), (sy_call_t *)linux_time, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 201 = linux_time */ { AS(linux_sys_futex_args), (sy_call_t *)linux_sys_futex, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 202 = linux_sys_futex */ { AS(linux_sched_setaffinity_args), (sy_call_t *)linux_sched_setaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 203 = linux_sched_setaffinity */ { AS(linux_sched_getaffinity_args), (sy_call_t *)linux_sched_getaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 204 = linux_sched_getaffinity */ { 0, (sy_call_t *)linux_set_thread_area, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 205 = linux_set_thread_area */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 206 = linux_io_setup */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 207 = linux_io_destroy */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 208 = linux_io_getevents */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 209 = inux_io_submit */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 209 = linux_io_submit */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 210 = linux_io_cancel */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 211 = linux_get_thread_area */ { 0, (sy_call_t *)linux_lookup_dcookie, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 212 = linux_lookup_dcookie */ { AS(linux_epoll_create_args), (sy_call_t *)linux_epoll_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 213 = linux_epoll_create */ { 0, (sy_call_t *)linux_epoll_ctl_old, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 214 = linux_epoll_ctl_old */ { 0, (sy_call_t *)linux_epoll_wait_old, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 215 = linux_epoll_wait_old */ { 0, (sy_call_t *)linux_remap_file_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 216 = linux_remap_file_pages */ { AS(linux_getdents64_args), (sy_call_t *)linux_getdents64, AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 217 = linux_getdents64 */ { AS(linux_set_tid_address_args), (sy_call_t *)linux_set_tid_address, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 218 = linux_set_tid_address */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 219 = restart_syscall */ { 0, (sy_call_t *)linux_semtimedop, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 220 = linux_semtimedop */ { AS(linux_fadvise64_args), (sy_call_t *)linux_fadvise64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 221 = linux_fadvise64 */ { AS(linux_timer_create_args), (sy_call_t *)linux_timer_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 222 = linux_timer_create */ { AS(linux_timer_settime_args), (sy_call_t *)linux_timer_settime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 223 = linux_timer_settime */ { AS(linux_timer_gettime_args), (sy_call_t *)linux_timer_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 224 = linux_timer_gettime */ { AS(linux_timer_getoverrun_args), (sy_call_t *)linux_timer_getoverrun, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 225 = linux_timer_getoverrun */ { AS(linux_timer_delete_args), (sy_call_t *)linux_timer_delete, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 226 = linux_timer_delete */ { AS(linux_clock_settime_args), (sy_call_t *)linux_clock_settime, AUE_CLOCK_SETTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 227 = linux_clock_settime */ { AS(linux_clock_gettime_args), (sy_call_t *)linux_clock_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 228 = linux_clock_gettime */ { AS(linux_clock_getres_args), (sy_call_t *)linux_clock_getres, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 229 = linux_clock_getres */ { AS(linux_clock_nanosleep_args), (sy_call_t *)linux_clock_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 230 = linux_clock_nanosleep */ { AS(linux_exit_group_args), (sy_call_t *)linux_exit_group, AUE_EXIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 231 = linux_exit_group */ { AS(linux_epoll_wait_args), (sy_call_t *)linux_epoll_wait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 232 = linux_epoll_wait */ { AS(linux_epoll_ctl_args), (sy_call_t *)linux_epoll_ctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 233 = linux_epoll_ctl */ { AS(linux_tgkill_args), (sy_call_t *)linux_tgkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 234 = linux_tgkill */ { AS(linux_utimes_args), (sy_call_t *)linux_utimes, AUE_UTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 235 = linux_utimes */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 236 = vserver */ { 0, (sy_call_t *)linux_mbind, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 237 = linux_mbind */ { 0, (sy_call_t *)linux_set_mempolicy, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 238 = linux_set_mempolicy */ { 0, (sy_call_t *)linux_get_mempolicy, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 239 = linux_get_mempolicy */ { 0, (sy_call_t *)linux_mq_open, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 240 = linux_mq_open */ { 0, (sy_call_t *)linux_mq_unlink, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 241 = linux_mq_unlink */ { 0, (sy_call_t *)linux_mq_timedsend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 242 = linux_mq_timedsend */ { 0, (sy_call_t *)linux_mq_timedreceive, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 243 = linux_mq_timedreceive */ { 0, (sy_call_t *)linux_mq_notify, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 244 = linux_mq_notify */ { 0, (sy_call_t *)linux_mq_getsetattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 245 = linux_mq_getsetattr */ { 0, (sy_call_t *)linux_kexec_load, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 246 = linux_kexec_load */ { AS(linux_waitid_args), (sy_call_t *)linux_waitid, AUE_WAIT6, NULL, 0, 0, 0, SY_THR_STATIC }, /* 247 = linux_waitid */ { 0, (sy_call_t *)linux_add_key, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 248 = linux_add_key */ { 0, (sy_call_t *)linux_request_key, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 249 = linux_request_key */ { 0, (sy_call_t *)linux_keyctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 250 = linux_keyctl */ { 0, (sy_call_t *)linux_ioprio_set, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 251 = linux_ioprio_set */ { 0, (sy_call_t *)linux_ioprio_get, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 252 = linux_ioprio_get */ { 0, (sy_call_t *)linux_inotify_init, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 253 = linux_inotify_init */ { 0, (sy_call_t *)linux_inotify_add_watch, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 254 = linux_inotify_add_watch */ { 0, (sy_call_t *)linux_inotify_rm_watch, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 255 = linux_inotify_rm_watch */ { 0, (sy_call_t *)linux_migrate_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 256 = linux_migrate_pages */ { AS(linux_openat_args), (sy_call_t *)linux_openat, AUE_OPEN_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 257 = linux_openat */ { AS(linux_mkdirat_args), (sy_call_t *)linux_mkdirat, AUE_MKDIRAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 258 = linux_mkdirat */ { AS(linux_mknodat_args), (sy_call_t *)linux_mknodat, AUE_MKNODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 259 = linux_mknodat */ { AS(linux_fchownat_args), (sy_call_t *)linux_fchownat, AUE_FCHOWNAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 260 = linux_fchownat */ { AS(linux_futimesat_args), (sy_call_t *)linux_futimesat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 261 = linux_futimesat */ { AS(linux_newfstatat_args), (sy_call_t *)linux_newfstatat, AUE_FSTATAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 262 = linux_newfstatat */ { AS(linux_unlinkat_args), (sy_call_t *)linux_unlinkat, AUE_UNLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 263 = linux_unlinkat */ { AS(linux_renameat_args), (sy_call_t *)linux_renameat, AUE_RENAMEAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 264 = linux_renameat */ { AS(linux_linkat_args), (sy_call_t *)linux_linkat, AUE_LINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 265 = linux_linkat */ { AS(linux_symlinkat_args), (sy_call_t *)linux_symlinkat, AUE_SYMLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 266 = linux_symlinkat */ { AS(linux_readlinkat_args), (sy_call_t *)linux_readlinkat, AUE_READLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 267 = linux_readlinkat */ { AS(linux_fchmodat_args), (sy_call_t *)linux_fchmodat, AUE_FCHMODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 268 = linux_fchmodat */ { AS(linux_faccessat_args), (sy_call_t *)linux_faccessat, AUE_FACCESSAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 269 = linux_faccessat */ { AS(linux_pselect6_args), (sy_call_t *)linux_pselect6, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 270 = linux_pselect6 */ { AS(linux_ppoll_args), (sy_call_t *)linux_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 271 = linux_ppoll */ { 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 272 = linux_unshare */ { AS(linux_set_robust_list_args), (sy_call_t *)linux_set_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 273 = linux_set_robust_list */ { AS(linux_get_robust_list_args), (sy_call_t *)linux_get_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 274 = linux_get_robust_list */ { 0, (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 275 = linux_splice */ { 0, (sy_call_t *)linux_tee, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 276 = linux_tee */ { 0, (sy_call_t *)linux_sync_file_range, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 277 = linux_sync_file_range */ { 0, (sy_call_t *)linux_vmsplice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 278 = linux_vmsplice */ { 0, (sy_call_t *)linux_move_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 279 = linux_move_pages */ { AS(linux_utimensat_args), (sy_call_t *)linux_utimensat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 280 = linux_utimensat */ { AS(linux_epoll_pwait_args), (sy_call_t *)linux_epoll_pwait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 281 = linux_epoll_pwait */ { 0, (sy_call_t *)linux_signalfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 282 = linux_signalfd */ - { 0, (sy_call_t *)linux_timerfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 283 = linux_timerfd */ + { 0, (sy_call_t *)linux_timerfd_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 283 = linux_timerfd_create */ { AS(linux_eventfd_args), (sy_call_t *)linux_eventfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 284 = linux_eventfd */ { AS(linux_fallocate_args), (sy_call_t *)linux_fallocate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 285 = linux_fallocate */ { 0, (sy_call_t *)linux_timerfd_settime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 286 = linux_timerfd_settime */ { 0, (sy_call_t *)linux_timerfd_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 287 = linux_timerfd_gettime */ { AS(linux_accept4_args), (sy_call_t *)linux_accept4, AUE_ACCEPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 288 = linux_accept4 */ { 0, (sy_call_t *)linux_signalfd4, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 289 = linux_signalfd4 */ { AS(linux_eventfd2_args), (sy_call_t *)linux_eventfd2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 290 = linux_eventfd2 */ { AS(linux_epoll_create1_args), (sy_call_t *)linux_epoll_create1, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 291 = linux_epoll_create1 */ { AS(linux_dup3_args), (sy_call_t *)linux_dup3, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 292 = linux_dup3 */ { AS(linux_pipe2_args), (sy_call_t *)linux_pipe2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 293 = linux_pipe2 */ - { 0, (sy_call_t *)linux_inotify_init1, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 294 = linux_inotify_init1 */ - { 0, (sy_call_t *)linux_preadv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 295 = linux_preadv */ - { 0, (sy_call_t *)linux_pwritev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 296 = linux_pwritev */ - { 0, (sy_call_t *)linux_rt_tsigqueueinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 297 = linux_rt_tsigqueueinfo */ + { AS(linux_inotify_init1_args), (sy_call_t *)linux_inotify_init1, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 294 = linux_inotify_init1 */ + { AS(linux_preadv_args), (sy_call_t *)linux_preadv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 295 = linux_preadv */ + { AS(linux_pwritev_args), (sy_call_t *)linux_pwritev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 296 = linux_pwritev */ + { AS(linux_rt_tgsigqueueinfo_args), (sy_call_t *)linux_rt_tgsigqueueinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 297 = linux_rt_tgsigqueueinfo */ { 0, (sy_call_t *)linux_perf_event_open, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 298 = linux_perf_event_open */ { AS(linux_recvmmsg_args), (sy_call_t *)linux_recvmmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 299 = linux_recvmmsg */ { 0, (sy_call_t *)linux_fanotify_init, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 300 = linux_fanotify_init */ { 0, (sy_call_t *)linux_fanotify_mark, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 301 = linux_fanotify_mark */ { AS(linux_prlimit64_args), (sy_call_t *)linux_prlimit64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 302 = linux_prlimit64 */ { 0, (sy_call_t *)linux_name_to_handle_at, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 303 = linux_name_to_handle_at */ { 0, (sy_call_t *)linux_open_by_handle_at, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 304 = linux_open_by_handle_at */ { 0, (sy_call_t *)linux_clock_adjtime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 305 = linux_clock_adjtime */ { AS(linux_syncfs_args), (sy_call_t *)linux_syncfs, AUE_SYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 306 = linux_syncfs */ { AS(linux_sendmmsg_args), (sy_call_t *)linux_sendmmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 307 = linux_sendmmsg */ - { 0, (sy_call_t *)linux_setns, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 308 = linux_setns */ - { 0, (sy_call_t *)linux_process_vm_readv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 309 = linux_process_vm_readv */ - { 0, (sy_call_t *)linux_process_vm_writev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 310 = linux_process_vm_writev */ - { 0, (sy_call_t *)linux_kcmp, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 311 = linux_kcmp */ - { 0, (sy_call_t *)linux_finit_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 312 = linux_finit_module */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 313 = nosys */ + { AS(linux_setns_args), (sy_call_t *)linux_setns, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 308 = linux_setns */ + { AS(linux_getcpu_args), (sy_call_t *)linux_getcpu, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 309 = linux_getcpu */ + { AS(linux_process_vm_readv_args), (sy_call_t *)linux_process_vm_readv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 310 = linux_process_vm_readv */ + { AS(linux_process_vm_writev_args), (sy_call_t *)linux_process_vm_writev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 311 = linux_process_vm_writev */ + { AS(linux_kcmp_args), (sy_call_t *)linux_kcmp, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 312 = linux_kcmp */ + { AS(linux_finit_module_args), (sy_call_t *)linux_finit_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 313 = linux_finit_module */ + { AS(linux_sched_setattr_args), (sy_call_t *)linux_sched_setattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 314 = linux_sched_setattr */ + { AS(linux_sched_getattr_args), (sy_call_t *)linux_sched_getattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 315 = linux_sched_getattr */ + { AS(linux_renameat2_args), (sy_call_t *)linux_renameat2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 316 = linux_renameat2 */ + { AS(linux_seccomp_args), (sy_call_t *)linux_seccomp, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 317 = linux_seccomp */ + { AS(linux_getrandom_args), (sy_call_t *)linux_getrandom, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 318 = linux_getrandom */ + { AS(linux_memfd_create_args), (sy_call_t *)linux_memfd_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 319 = linux_memfd_create */ + { AS(linux_kexec_file_load_args), (sy_call_t *)linux_kexec_file_load, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 320 = linux_kexec_file_load */ + { AS(linux_bpf_args), (sy_call_t *)linux_bpf, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 321 = linux_bpf */ + { AS(linux_execveat_args), (sy_call_t *)linux_execveat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 322 = linux_execveat */ + { AS(linux_userfaultfd_args), (sy_call_t *)linux_userfaultfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 323 = linux_userfaultfd */ + { AS(linux_membarrier_args), (sy_call_t *)linux_membarrier, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 324 = linux_membarrier */ + { AS(linux_mlock2_args), (sy_call_t *)linux_mlock2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 325 = linux_mlock2 */ + { AS(linux_copy_file_range_args), (sy_call_t *)linux_copy_file_range, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 326 = linux_copy_file_range */ + { AS(linux_preadv2_args), (sy_call_t *)linux_preadv2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 327 = linux_preadv2 */ + { AS(linux_pwritev2_args), (sy_call_t *)linux_pwritev2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 328 = linux_pwritev2 */ + { AS(linux_pkey_mprotect_args), (sy_call_t *)linux_pkey_mprotect, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 329 = linux_pkey_mprotect */ + { AS(linux_pkey_alloc_args), (sy_call_t *)linux_pkey_alloc, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 330 = linux_pkey_alloc */ + { AS(linux_pkey_free_args), (sy_call_t *)linux_pkey_free, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 331 = linux_pkey_free */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 332 = nosys */ }; Index: projects/ipsec/sys/amd64/linux/linux_systrace_args.c =================================================================== --- projects/ipsec/sys/amd64/linux/linux_systrace_args.c (revision 313312) +++ projects/ipsec/sys/amd64/linux/linux_systrace_args.c (revision 313313) @@ -1,6885 +1,7715 @@ /* * System call argument to DTrace register array converstion. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ * This file is part of the DTrace syscall provider. */ static void systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) { int64_t *iarg = (int64_t *) uarg; switch (sysnum) { #define nosys linux_nosys /* read */ case 0: { struct read_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->buf; /* char * */ uarg[2] = p->nbyte; /* u_int */ *n_args = 3; break; } /* write */ case 1: { struct write_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->buf; /* char * */ uarg[2] = p->nbyte; /* u_int */ *n_args = 3; break; } /* linux_open */ case 2: { struct linux_open_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->flags; /* l_int */ iarg[2] = p->mode; /* l_int */ *n_args = 3; break; } /* close */ case 3: { struct close_args *p = params; iarg[0] = p->fd; /* int */ *n_args = 1; break; } /* linux_newstat */ case 4: { struct linux_newstat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->buf; /* struct l_newstat * */ *n_args = 2; break; } /* linux_newfstat */ case 5: { struct linux_newfstat_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* struct l_newstat * */ *n_args = 2; break; } /* linux_newlstat */ case 6: { struct linux_newlstat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->buf; /* struct l_newstat * */ *n_args = 2; break; } /* poll */ case 7: { struct poll_args *p = params; uarg[0] = (intptr_t) p->fds; /* struct pollfd * */ uarg[1] = p->nfds; /* u_int */ iarg[2] = p->timeout; /* int */ *n_args = 3; break; } /* linux_lseek */ case 8: { struct linux_lseek_args *p = params; iarg[0] = p->fdes; /* l_uint */ iarg[1] = p->off; /* l_off_t */ iarg[2] = p->whence; /* l_int */ *n_args = 3; break; } /* linux_mmap2 */ case 9: { struct linux_mmap2_args *p = params; iarg[0] = p->addr; /* l_ulong */ iarg[1] = p->len; /* l_ulong */ iarg[2] = p->prot; /* l_ulong */ iarg[3] = p->flags; /* l_ulong */ iarg[4] = p->fd; /* l_ulong */ iarg[5] = p->pgoff; /* l_ulong */ *n_args = 6; break; } /* linux_mprotect */ case 10: { struct linux_mprotect_args *p = params; uarg[0] = (intptr_t) p->addr; /* caddr_t */ iarg[1] = p->len; /* int */ iarg[2] = p->prot; /* int */ *n_args = 3; break; } /* munmap */ case 11: { struct munmap_args *p = params; uarg[0] = (intptr_t) p->addr; /* caddr_t */ iarg[1] = p->len; /* int */ *n_args = 2; break; } /* linux_brk */ case 12: { struct linux_brk_args *p = params; iarg[0] = p->dsend; /* l_ulong */ *n_args = 1; break; } /* linux_rt_sigaction */ case 13: { struct linux_rt_sigaction_args *p = params; iarg[0] = p->sig; /* l_int */ uarg[1] = (intptr_t) p->act; /* l_sigaction_t * */ uarg[2] = (intptr_t) p->oact; /* l_sigaction_t * */ iarg[3] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; } /* linux_rt_sigprocmask */ case 14: { struct linux_rt_sigprocmask_args *p = params; iarg[0] = p->how; /* l_int */ uarg[1] = (intptr_t) p->mask; /* l_sigset_t * */ uarg[2] = (intptr_t) p->omask; /* l_sigset_t * */ iarg[3] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; } /* linux_rt_sigreturn */ case 15: { struct linux_rt_sigreturn_args *p = params; uarg[0] = (intptr_t) p->ucp; /* struct l_ucontext * */ *n_args = 1; break; } /* linux_ioctl */ case 16: { struct linux_ioctl_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->cmd; /* l_uint */ uarg[2] = p->arg; /* uintptr_t */ *n_args = 3; break; } /* linux_pread */ case 17: { struct linux_pread_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->nbyte; /* l_size_t */ iarg[3] = p->offset; /* l_loff_t */ *n_args = 4; break; } /* linux_pwrite */ case 18: { struct linux_pwrite_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->nbyte; /* l_size_t */ iarg[3] = p->offset; /* l_loff_t */ *n_args = 4; break; } /* readv */ case 19: { struct readv_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->iovp; /* struct iovec * */ uarg[2] = p->iovcnt; /* u_int */ *n_args = 3; break; } /* writev */ case 20: { struct writev_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->iovp; /* struct iovec * */ uarg[2] = p->iovcnt; /* u_int */ *n_args = 3; break; } /* linux_access */ case 21: { struct linux_access_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->amode; /* l_int */ *n_args = 2; break; } /* linux_pipe */ case 22: { struct linux_pipe_args *p = params; uarg[0] = (intptr_t) p->pipefds; /* l_ulong * */ *n_args = 1; break; } /* linux_select */ case 23: { struct linux_select_args *p = params; iarg[0] = p->nfds; /* l_int */ uarg[1] = (intptr_t) p->readfds; /* l_fd_set * */ uarg[2] = (intptr_t) p->writefds; /* l_fd_set * */ uarg[3] = (intptr_t) p->exceptfds; /* l_fd_set * */ uarg[4] = (intptr_t) p->timeout; /* struct l_timeval * */ *n_args = 5; break; } /* sched_yield */ case 24: { *n_args = 0; break; } /* linux_mremap */ case 25: { struct linux_mremap_args *p = params; iarg[0] = p->addr; /* l_ulong */ iarg[1] = p->old_len; /* l_ulong */ iarg[2] = p->new_len; /* l_ulong */ iarg[3] = p->flags; /* l_ulong */ iarg[4] = p->new_addr; /* l_ulong */ *n_args = 5; break; } /* linux_msync */ case 26: { struct linux_msync_args *p = params; iarg[0] = p->addr; /* l_ulong */ iarg[1] = p->len; /* l_size_t */ iarg[2] = p->fl; /* l_int */ *n_args = 3; break; } /* linux_mincore */ case 27: { struct linux_mincore_args *p = params; iarg[0] = p->start; /* l_ulong */ iarg[1] = p->len; /* l_size_t */ uarg[2] = (intptr_t) p->vec; /* u_char * */ *n_args = 3; break; } /* madvise */ case 28: { struct madvise_args *p = params; uarg[0] = (intptr_t) p->addr; /* void * */ uarg[1] = p->len; /* size_t */ iarg[2] = p->behav; /* int */ *n_args = 3; break; } /* linux_shmget */ case 29: { struct linux_shmget_args *p = params; iarg[0] = p->key; /* l_key_t */ iarg[1] = p->size; /* l_size_t */ iarg[2] = p->shmflg; /* l_int */ *n_args = 3; break; } /* linux_shmat */ case 30: { struct linux_shmat_args *p = params; iarg[0] = p->shmid; /* l_int */ uarg[1] = (intptr_t) p->shmaddr; /* char * */ iarg[2] = p->shmflg; /* l_int */ *n_args = 3; break; } /* linux_shmctl */ case 31: { struct linux_shmctl_args *p = params; iarg[0] = p->shmid; /* l_int */ iarg[1] = p->cmd; /* l_int */ uarg[2] = (intptr_t) p->buf; /* struct l_shmid_ds * */ *n_args = 3; break; } /* dup */ case 32: { struct dup_args *p = params; uarg[0] = p->fd; /* u_int */ *n_args = 1; break; } /* dup2 */ case 33: { struct dup2_args *p = params; uarg[0] = p->from; /* u_int */ uarg[1] = p->to; /* u_int */ *n_args = 2; break; } /* linux_pause */ case 34: { *n_args = 0; break; } /* linux_nanosleep */ case 35: { struct linux_nanosleep_args *p = params; uarg[0] = (intptr_t) p->rqtp; /* const struct l_timespec * */ uarg[1] = (intptr_t) p->rmtp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_getitimer */ case 36: { struct linux_getitimer_args *p = params; iarg[0] = p->which; /* l_int */ uarg[1] = (intptr_t) p->itv; /* struct l_itimerval * */ *n_args = 2; break; } /* linux_alarm */ case 37: { struct linux_alarm_args *p = params; iarg[0] = p->secs; /* l_uint */ *n_args = 1; break; } /* linux_setitimer */ case 38: { struct linux_setitimer_args *p = params; iarg[0] = p->which; /* l_int */ uarg[1] = (intptr_t) p->itv; /* struct l_itimerval * */ uarg[2] = (intptr_t) p->oitv; /* struct l_itimerval * */ *n_args = 3; break; } /* linux_getpid */ case 39: { *n_args = 0; break; } /* linux_sendfile */ case 40: { struct linux_sendfile_args *p = params; iarg[0] = p->out; /* int */ iarg[1] = p->in; /* int */ uarg[2] = (intptr_t) p->offset; /* l_long * */ iarg[3] = p->count; /* l_size_t */ *n_args = 4; break; } /* linux_socket */ case 41: { struct linux_socket_args *p = params; iarg[0] = p->domain; /* l_int */ iarg[1] = p->type; /* l_int */ iarg[2] = p->protocol; /* l_int */ *n_args = 3; break; } /* linux_connect */ case 42: { struct linux_connect_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->name; /* l_uintptr_t */ iarg[2] = p->namelen; /* l_int */ *n_args = 3; break; } /* linux_accept */ case 43: { struct linux_accept_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->addr; /* l_uintptr_t */ iarg[2] = p->namelen; /* l_uintptr_t */ *n_args = 3; break; } /* linux_sendto */ case 44: { struct linux_sendto_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->msg; /* l_uintptr_t */ iarg[2] = p->len; /* l_int */ iarg[3] = p->flags; /* l_int */ iarg[4] = p->to; /* l_uintptr_t */ iarg[5] = p->tolen; /* l_int */ *n_args = 6; break; } /* linux_recvfrom */ case 45: { struct linux_recvfrom_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->buf; /* l_uintptr_t */ iarg[2] = p->len; /* l_size_t */ iarg[3] = p->flags; /* l_int */ iarg[4] = p->from; /* l_uintptr_t */ iarg[5] = p->fromlen; /* l_uintptr_t */ *n_args = 6; break; } /* linux_sendmsg */ case 46: { struct linux_sendmsg_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->msg; /* l_uintptr_t */ iarg[2] = p->flags; /* l_int */ *n_args = 3; break; } /* linux_recvmsg */ case 47: { struct linux_recvmsg_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->msg; /* l_uintptr_t */ iarg[2] = p->flags; /* l_int */ *n_args = 3; break; } /* linux_shutdown */ case 48: { struct linux_shutdown_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->how; /* l_int */ *n_args = 2; break; } /* linux_bind */ case 49: { struct linux_bind_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->name; /* l_uintptr_t */ iarg[2] = p->namelen; /* l_int */ *n_args = 3; break; } /* linux_listen */ case 50: { struct linux_listen_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->backlog; /* l_int */ *n_args = 2; break; } /* linux_getsockname */ case 51: { struct linux_getsockname_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->addr; /* l_uintptr_t */ iarg[2] = p->namelen; /* l_uintptr_t */ *n_args = 3; break; } /* linux_getpeername */ case 52: { struct linux_getpeername_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->addr; /* l_uintptr_t */ iarg[2] = p->namelen; /* l_uintptr_t */ *n_args = 3; break; } /* linux_socketpair */ case 53: { struct linux_socketpair_args *p = params; iarg[0] = p->domain; /* l_int */ iarg[1] = p->type; /* l_int */ iarg[2] = p->protocol; /* l_int */ iarg[3] = p->rsv; /* l_uintptr_t */ *n_args = 4; break; } /* linux_setsockopt */ case 54: { struct linux_setsockopt_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->level; /* l_int */ iarg[2] = p->optname; /* l_int */ iarg[3] = p->optval; /* l_uintptr_t */ iarg[4] = p->optlen; /* l_int */ *n_args = 5; break; } /* linux_getsockopt */ case 55: { struct linux_getsockopt_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->level; /* l_int */ iarg[2] = p->optname; /* l_int */ iarg[3] = p->optval; /* l_uintptr_t */ iarg[4] = p->optlen; /* l_uintptr_t */ *n_args = 5; break; } /* linux_clone */ case 56: { struct linux_clone_args *p = params; iarg[0] = p->flags; /* l_int */ uarg[1] = (intptr_t) p->stack; /* void * */ uarg[2] = (intptr_t) p->parent_tidptr; /* void * */ uarg[3] = (intptr_t) p->child_tidptr; /* void * */ uarg[4] = (intptr_t) p->tls; /* void * */ *n_args = 5; break; } /* linux_fork */ case 57: { *n_args = 0; break; } /* linux_vfork */ case 58: { *n_args = 0; break; } /* linux_execve */ case 59: { struct linux_execve_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->argp; /* char ** */ uarg[2] = (intptr_t) p->envp; /* char ** */ *n_args = 3; break; } /* linux_exit */ case 60: { struct linux_exit_args *p = params; iarg[0] = p->rval; /* int */ *n_args = 1; break; } /* linux_wait4 */ case 61: { struct linux_wait4_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->status; /* l_int * */ iarg[2] = p->options; /* l_int */ uarg[3] = (intptr_t) p->rusage; /* struct rusage * */ *n_args = 4; break; } /* linux_kill */ case 62: { struct linux_kill_args *p = params; iarg[0] = p->pid; /* l_int */ iarg[1] = p->signum; /* l_int */ *n_args = 2; break; } /* linux_newuname */ case 63: { struct linux_newuname_args *p = params; uarg[0] = (intptr_t) p->buf; /* struct l_new_utsname * */ *n_args = 1; break; } /* linux_semget */ case 64: { struct linux_semget_args *p = params; iarg[0] = p->key; /* l_key_t */ iarg[1] = p->nsems; /* l_int */ iarg[2] = p->semflg; /* l_int */ *n_args = 3; break; } /* linux_semop */ case 65: { struct linux_semop_args *p = params; iarg[0] = p->semid; /* l_int */ uarg[1] = (intptr_t) p->tsops; /* struct l_sembuf * */ iarg[2] = p->nsops; /* l_uint */ *n_args = 3; break; } /* linux_semctl */ case 66: { struct linux_semctl_args *p = params; iarg[0] = p->semid; /* l_int */ iarg[1] = p->semnum; /* l_int */ iarg[2] = p->cmd; /* l_int */ uarg[3] = p->arg.buf; /* union l_semun */ *n_args = 4; break; } /* linux_shmdt */ case 67: { struct linux_shmdt_args *p = params; uarg[0] = (intptr_t) p->shmaddr; /* char * */ *n_args = 1; break; } /* linux_msgget */ case 68: { struct linux_msgget_args *p = params; iarg[0] = p->key; /* l_key_t */ iarg[1] = p->msgflg; /* l_int */ *n_args = 2; break; } /* linux_msgsnd */ case 69: { struct linux_msgsnd_args *p = params; iarg[0] = p->msqid; /* l_int */ uarg[1] = (intptr_t) p->msgp; /* struct l_msgbuf * */ iarg[2] = p->msgsz; /* l_size_t */ iarg[3] = p->msgflg; /* l_int */ *n_args = 4; break; } /* linux_msgrcv */ case 70: { struct linux_msgrcv_args *p = params; iarg[0] = p->msqid; /* l_int */ uarg[1] = (intptr_t) p->msgp; /* struct l_msgbuf * */ iarg[2] = p->msgsz; /* l_size_t */ iarg[3] = p->msgtyp; /* l_long */ iarg[4] = p->msgflg; /* l_int */ *n_args = 5; break; } /* linux_msgctl */ case 71: { struct linux_msgctl_args *p = params; iarg[0] = p->msqid; /* l_int */ iarg[1] = p->cmd; /* l_int */ uarg[2] = (intptr_t) p->buf; /* struct l_msqid_ds * */ *n_args = 3; break; } /* linux_fcntl */ case 72: { struct linux_fcntl_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->cmd; /* l_uint */ iarg[2] = p->arg; /* l_ulong */ *n_args = 3; break; } /* flock */ case 73: { struct flock_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->how; /* int */ *n_args = 2; break; } /* fsync */ case 74: { struct fsync_args *p = params; iarg[0] = p->fd; /* int */ *n_args = 1; break; } /* linux_fdatasync */ case 75: { struct linux_fdatasync_args *p = params; iarg[0] = p->fd; /* l_uint */ *n_args = 1; break; } /* linux_truncate */ case 76: { struct linux_truncate_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->length; /* l_ulong */ *n_args = 2; break; } /* linux_ftruncate */ case 77: { struct linux_ftruncate_args *p = params; iarg[0] = p->fd; /* l_int */ iarg[1] = p->length; /* l_long */ *n_args = 2; break; } /* linux_getdents */ case 78: { struct linux_getdents_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->dent; /* void * */ iarg[2] = p->count; /* l_uint */ *n_args = 3; break; } /* linux_getcwd */ case 79: { struct linux_getcwd_args *p = params; uarg[0] = (intptr_t) p->buf; /* char * */ iarg[1] = p->bufsize; /* l_ulong */ *n_args = 2; break; } /* linux_chdir */ case 80: { struct linux_chdir_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* fchdir */ case 81: { struct fchdir_args *p = params; iarg[0] = p->fd; /* int */ *n_args = 1; break; } /* linux_rename */ case 82: { struct linux_rename_args *p = params; uarg[0] = (intptr_t) p->from; /* char * */ uarg[1] = (intptr_t) p->to; /* char * */ *n_args = 2; break; } /* linux_mkdir */ case 83: { struct linux_mkdir_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_int */ *n_args = 2; break; } /* linux_rmdir */ case 84: { struct linux_rmdir_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_creat */ case 85: { struct linux_creat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_int */ *n_args = 2; break; } /* linux_link */ case 86: { struct linux_link_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->to; /* char * */ *n_args = 2; break; } /* linux_unlink */ case 87: { struct linux_unlink_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_symlink */ case 88: { struct linux_symlink_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->to; /* char * */ *n_args = 2; break; } /* linux_readlink */ case 89: { struct linux_readlink_args *p = params; uarg[0] = (intptr_t) p->name; /* char * */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->count; /* l_int */ *n_args = 3; break; } /* linux_chmod */ case 90: { struct linux_chmod_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_mode_t */ *n_args = 2; break; } /* fchmod */ case 91: { struct fchmod_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->mode; /* int */ *n_args = 2; break; } /* linux_chown */ case 92: { struct linux_chown_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid_t */ iarg[2] = p->gid; /* l_gid_t */ *n_args = 3; break; } /* fchown */ case 93: { struct fchown_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->uid; /* int */ iarg[2] = p->gid; /* int */ *n_args = 3; break; } /* linux_lchown */ case 94: { struct linux_lchown_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid_t */ iarg[2] = p->gid; /* l_gid_t */ *n_args = 3; break; } /* umask */ case 95: { struct umask_args *p = params; iarg[0] = p->newmask; /* int */ *n_args = 1; break; } /* gettimeofday */ case 96: { struct gettimeofday_args *p = params; uarg[0] = (intptr_t) p->tp; /* struct l_timeval * */ uarg[1] = (intptr_t) p->tzp; /* struct timezone * */ *n_args = 2; break; } /* linux_getrlimit */ case 97: { struct linux_getrlimit_args *p = params; iarg[0] = p->resource; /* l_uint */ uarg[1] = (intptr_t) p->rlim; /* struct l_rlimit * */ *n_args = 2; break; } /* getrusage */ case 98: { struct getrusage_args *p = params; iarg[0] = p->who; /* int */ uarg[1] = (intptr_t) p->rusage; /* struct rusage * */ *n_args = 2; break; } /* linux_sysinfo */ case 99: { struct linux_sysinfo_args *p = params; uarg[0] = (intptr_t) p->info; /* struct l_sysinfo * */ *n_args = 1; break; } /* linux_times */ case 100: { struct linux_times_args *p = params; uarg[0] = (intptr_t) p->buf; /* struct l_times_argv * */ *n_args = 1; break; } /* linux_ptrace */ case 101: { struct linux_ptrace_args *p = params; iarg[0] = p->req; /* l_long */ iarg[1] = p->pid; /* l_long */ iarg[2] = p->addr; /* l_long */ iarg[3] = p->data; /* l_long */ *n_args = 4; break; } /* linux_getuid */ case 102: { *n_args = 0; break; } /* linux_syslog */ case 103: { struct linux_syslog_args *p = params; iarg[0] = p->type; /* l_int */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->len; /* l_int */ *n_args = 3; break; } /* linux_getgid */ case 104: { *n_args = 0; break; } /* setuid */ case 105: { struct setuid_args *p = params; uarg[0] = p->uid; /* uid_t */ *n_args = 1; break; } /* setgid */ case 106: { struct setgid_args *p = params; iarg[0] = p->gid; /* gid_t */ *n_args = 1; break; } /* geteuid */ case 107: { *n_args = 0; break; } /* getegid */ case 108: { *n_args = 0; break; } /* setpgid */ case 109: { struct setpgid_args *p = params; iarg[0] = p->pid; /* int */ iarg[1] = p->pgid; /* int */ *n_args = 2; break; } /* linux_getppid */ case 110: { *n_args = 0; break; } /* getpgrp */ case 111: { *n_args = 0; break; } /* setsid */ case 112: { *n_args = 0; break; } /* setreuid */ case 113: { struct setreuid_args *p = params; uarg[0] = p->ruid; /* uid_t */ uarg[1] = p->euid; /* uid_t */ *n_args = 2; break; } /* setregid */ case 114: { struct setregid_args *p = params; iarg[0] = p->rgid; /* gid_t */ iarg[1] = p->egid; /* gid_t */ *n_args = 2; break; } /* linux_getgroups */ case 115: { struct linux_getgroups_args *p = params; iarg[0] = p->gidsetsize; /* l_int */ uarg[1] = (intptr_t) p->grouplist; /* l_gid_t * */ *n_args = 2; break; } /* linux_setgroups */ case 116: { struct linux_setgroups_args *p = params; iarg[0] = p->gidsetsize; /* l_int */ uarg[1] = (intptr_t) p->grouplist; /* l_gid_t * */ *n_args = 2; break; } /* setresuid */ case 117: { struct setresuid_args *p = params; uarg[0] = p->ruid; /* uid_t */ uarg[1] = p->euid; /* uid_t */ uarg[2] = p->suid; /* uid_t */ *n_args = 3; break; } /* getresuid */ case 118: { struct getresuid_args *p = params; uarg[0] = (intptr_t) p->ruid; /* uid_t * */ uarg[1] = (intptr_t) p->euid; /* uid_t * */ uarg[2] = (intptr_t) p->suid; /* uid_t * */ *n_args = 3; break; } /* setresgid */ case 119: { struct setresgid_args *p = params; iarg[0] = p->rgid; /* gid_t */ iarg[1] = p->egid; /* gid_t */ iarg[2] = p->sgid; /* gid_t */ *n_args = 3; break; } /* getresgid */ case 120: { struct getresgid_args *p = params; uarg[0] = (intptr_t) p->rgid; /* gid_t * */ uarg[1] = (intptr_t) p->egid; /* gid_t * */ uarg[2] = (intptr_t) p->sgid; /* gid_t * */ *n_args = 3; break; } /* getpgid */ case 121: { struct getpgid_args *p = params; iarg[0] = p->pid; /* int */ *n_args = 1; break; } /* linux_setfsuid */ case 122: { struct linux_setfsuid_args *p = params; iarg[0] = p->uid; /* l_uid_t */ *n_args = 1; break; } /* linux_setfsgid */ case 123: { struct linux_setfsgid_args *p = params; iarg[0] = p->gid; /* l_gid_t */ *n_args = 1; break; } /* linux_getsid */ case 124: { struct linux_getsid_args *p = params; iarg[0] = p->pid; /* l_pid_t */ *n_args = 1; break; } /* linux_capget */ case 125: { struct linux_capget_args *p = params; uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */ uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */ *n_args = 2; break; } /* linux_capset */ case 126: { struct linux_capset_args *p = params; uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */ uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */ *n_args = 2; break; } /* linux_rt_sigpending */ case 127: { struct linux_rt_sigpending_args *p = params; uarg[0] = (intptr_t) p->set; /* l_sigset_t * */ iarg[1] = p->sigsetsize; /* l_size_t */ *n_args = 2; break; } /* linux_rt_sigtimedwait */ case 128: { struct linux_rt_sigtimedwait_args *p = params; uarg[0] = (intptr_t) p->mask; /* l_sigset_t * */ uarg[1] = (intptr_t) p->ptr; /* l_siginfo_t * */ uarg[2] = (intptr_t) p->timeout; /* struct l_timeval * */ iarg[3] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; } /* linux_rt_sigqueueinfo */ case 129: { struct linux_rt_sigqueueinfo_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->sig; /* l_int */ uarg[2] = (intptr_t) p->info; /* l_siginfo_t * */ *n_args = 3; break; } /* linux_rt_sigsuspend */ case 130: { struct linux_rt_sigsuspend_args *p = params; uarg[0] = (intptr_t) p->newset; /* l_sigset_t * */ iarg[1] = p->sigsetsize; /* l_size_t */ *n_args = 2; break; } /* linux_sigaltstack */ case 131: { struct linux_sigaltstack_args *p = params; uarg[0] = (intptr_t) p->uss; /* l_stack_t * */ uarg[1] = (intptr_t) p->uoss; /* l_stack_t * */ *n_args = 2; break; } /* linux_utime */ case 132: { struct linux_utime_args *p = params; uarg[0] = (intptr_t) p->fname; /* char * */ uarg[1] = (intptr_t) p->times; /* struct l_utimbuf * */ *n_args = 2; break; } /* linux_mknod */ case 133: { struct linux_mknod_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_int */ iarg[2] = p->dev; /* l_dev_t */ *n_args = 3; break; } /* linux_personality */ case 135: { struct linux_personality_args *p = params; iarg[0] = p->per; /* l_uint */ *n_args = 1; break; } /* linux_ustat */ case 136: { struct linux_ustat_args *p = params; iarg[0] = p->dev; /* l_dev_t */ uarg[1] = (intptr_t) p->ubuf; /* struct l_ustat * */ *n_args = 2; break; } /* linux_statfs */ case 137: { struct linux_statfs_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->buf; /* struct l_statfs_buf * */ *n_args = 2; break; } /* linux_fstatfs */ case 138: { struct linux_fstatfs_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* struct l_statfs_buf * */ *n_args = 2; break; } /* linux_sysfs */ case 139: { struct linux_sysfs_args *p = params; iarg[0] = p->option; /* l_int */ iarg[1] = p->arg1; /* l_ulong */ iarg[2] = p->arg2; /* l_ulong */ *n_args = 3; break; } /* linux_getpriority */ case 140: { struct linux_getpriority_args *p = params; iarg[0] = p->which; /* int */ iarg[1] = p->who; /* int */ *n_args = 2; break; } /* setpriority */ case 141: { struct setpriority_args *p = params; iarg[0] = p->which; /* int */ iarg[1] = p->who; /* int */ iarg[2] = p->prio; /* int */ *n_args = 3; break; } /* linux_sched_setparam */ case 142: { struct linux_sched_setparam_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->param; /* struct sched_param * */ *n_args = 2; break; } /* linux_sched_getparam */ case 143: { struct linux_sched_getparam_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->param; /* struct sched_param * */ *n_args = 2; break; } /* linux_sched_setscheduler */ case 144: { struct linux_sched_setscheduler_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->policy; /* l_int */ uarg[2] = (intptr_t) p->param; /* struct sched_param * */ *n_args = 3; break; } /* linux_sched_getscheduler */ case 145: { struct linux_sched_getscheduler_args *p = params; iarg[0] = p->pid; /* l_pid_t */ *n_args = 1; break; } /* linux_sched_get_priority_max */ case 146: { struct linux_sched_get_priority_max_args *p = params; iarg[0] = p->policy; /* l_int */ *n_args = 1; break; } /* linux_sched_get_priority_min */ case 147: { struct linux_sched_get_priority_min_args *p = params; iarg[0] = p->policy; /* l_int */ *n_args = 1; break; } /* linux_sched_rr_get_interval */ case 148: { struct linux_sched_rr_get_interval_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->interval; /* struct l_timespec * */ *n_args = 2; break; } /* mlock */ case 149: { struct mlock_args *p = params; uarg[0] = (intptr_t) p->addr; /* const void * */ uarg[1] = p->len; /* size_t */ *n_args = 2; break; } /* munlock */ case 150: { struct munlock_args *p = params; uarg[0] = (intptr_t) p->addr; /* const void * */ uarg[1] = p->len; /* size_t */ *n_args = 2; break; } /* mlockall */ case 151: { struct mlockall_args *p = params; iarg[0] = p->how; /* int */ *n_args = 1; break; } /* munlockall */ case 152: { *n_args = 0; break; } /* linux_vhangup */ case 153: { *n_args = 0; break; } /* linux_pivot_root */ case 155: { *n_args = 0; break; } /* linux_sysctl */ case 156: { struct linux_sysctl_args *p = params; uarg[0] = (intptr_t) p->args; /* struct l___sysctl_args * */ *n_args = 1; break; } /* linux_prctl */ case 157: { struct linux_prctl_args *p = params; iarg[0] = p->option; /* l_int */ iarg[1] = p->arg2; /* l_uintptr_t */ iarg[2] = p->arg3; /* l_uintptr_t */ iarg[3] = p->arg4; /* l_uintptr_t */ iarg[4] = p->arg5; /* l_uintptr_t */ *n_args = 5; break; } /* linux_arch_prctl */ case 158: { struct linux_arch_prctl_args *p = params; iarg[0] = p->code; /* l_int */ iarg[1] = p->addr; /* l_ulong */ *n_args = 2; break; } /* linux_adjtimex */ case 159: { *n_args = 0; break; } /* linux_setrlimit */ case 160: { struct linux_setrlimit_args *p = params; iarg[0] = p->resource; /* l_uint */ uarg[1] = (intptr_t) p->rlim; /* struct l_rlimit * */ *n_args = 2; break; } /* chroot */ case 161: { struct chroot_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* sync */ case 162: { *n_args = 0; break; } /* acct */ case 163: { struct acct_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* settimeofday */ case 164: { struct settimeofday_args *p = params; uarg[0] = (intptr_t) p->tv; /* struct l_timeval * */ uarg[1] = (intptr_t) p->tzp; /* struct timezone * */ *n_args = 2; break; } /* linux_mount */ case 165: { struct linux_mount_args *p = params; uarg[0] = (intptr_t) p->specialfile; /* char * */ uarg[1] = (intptr_t) p->dir; /* char * */ uarg[2] = (intptr_t) p->filesystemtype; /* char * */ iarg[3] = p->rwflag; /* l_ulong */ uarg[4] = (intptr_t) p->data; /* void * */ *n_args = 5; break; } /* linux_umount */ case 166: { struct linux_umount_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->flags; /* l_int */ *n_args = 2; break; } /* swapon */ case 167: { struct swapon_args *p = params; uarg[0] = (intptr_t) p->name; /* char * */ *n_args = 1; break; } /* linux_swapoff */ case 168: { *n_args = 0; break; } /* linux_reboot */ case 169: { struct linux_reboot_args *p = params; iarg[0] = p->magic1; /* l_int */ iarg[1] = p->magic2; /* l_int */ iarg[2] = p->cmd; /* l_uint */ uarg[3] = (intptr_t) p->arg; /* void * */ *n_args = 4; break; } /* linux_sethostname */ case 170: { struct linux_sethostname_args *p = params; uarg[0] = (intptr_t) p->hostname; /* char * */ iarg[1] = p->len; /* l_uint */ *n_args = 2; break; } /* linux_setdomainname */ case 171: { struct linux_setdomainname_args *p = params; uarg[0] = (intptr_t) p->name; /* char * */ iarg[1] = p->len; /* l_int */ *n_args = 2; break; } /* linux_iopl */ case 172: { struct linux_iopl_args *p = params; iarg[0] = p->level; /* l_uint */ *n_args = 1; break; } /* linux_create_module */ case 174: { *n_args = 0; break; } /* linux_init_module */ case 175: { *n_args = 0; break; } /* linux_delete_module */ case 176: { *n_args = 0; break; } /* linux_get_kernel_syms */ case 177: { *n_args = 0; break; } /* linux_query_module */ case 178: { *n_args = 0; break; } /* linux_quotactl */ case 179: { *n_args = 0; break; } /* linux_nfsservctl */ case 180: { *n_args = 0; break; } /* linux_getpmsg */ case 181: { *n_args = 0; break; } /* linux_putpmsg */ case 182: { *n_args = 0; break; } /* linux_afs_syscall */ case 183: { *n_args = 0; break; } /* linux_tuxcall */ case 184: { *n_args = 0; break; } /* linux_security */ case 185: { *n_args = 0; break; } /* linux_gettid */ case 186: { *n_args = 0; break; } /* linux_setxattr */ case 188: { *n_args = 0; break; } /* linux_lsetxattr */ case 189: { *n_args = 0; break; } /* linux_fsetxattr */ case 190: { *n_args = 0; break; } /* linux_getxattr */ case 191: { *n_args = 0; break; } /* linux_lgetxattr */ case 192: { *n_args = 0; break; } /* linux_fgetxattr */ case 193: { *n_args = 0; break; } /* linux_listxattr */ case 194: { *n_args = 0; break; } /* linux_llistxattr */ case 195: { *n_args = 0; break; } /* linux_flistxattr */ case 196: { *n_args = 0; break; } /* linux_removexattr */ case 197: { *n_args = 0; break; } /* linux_lremovexattr */ case 198: { *n_args = 0; break; } /* linux_fremovexattr */ case 199: { *n_args = 0; break; } /* linux_tkill */ case 200: { struct linux_tkill_args *p = params; iarg[0] = p->tid; /* int */ iarg[1] = p->sig; /* int */ *n_args = 2; break; } /* linux_time */ case 201: { struct linux_time_args *p = params; uarg[0] = (intptr_t) p->tm; /* l_time_t * */ *n_args = 1; break; } /* linux_sys_futex */ case 202: { struct linux_sys_futex_args *p = params; uarg[0] = (intptr_t) p->uaddr; /* void * */ iarg[1] = p->op; /* int */ iarg[2] = p->val; /* int */ uarg[3] = (intptr_t) p->timeout; /* struct l_timespec * */ uarg[4] = (intptr_t) p->uaddr2; /* void * */ iarg[5] = p->val3; /* int */ *n_args = 6; break; } /* linux_sched_setaffinity */ case 203: { struct linux_sched_setaffinity_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->len; /* l_uint */ uarg[2] = (intptr_t) p->user_mask_ptr; /* l_ulong * */ *n_args = 3; break; } /* linux_sched_getaffinity */ case 204: { struct linux_sched_getaffinity_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->len; /* l_uint */ uarg[2] = (intptr_t) p->user_mask_ptr; /* l_ulong * */ *n_args = 3; break; } /* linux_set_thread_area */ case 205: { *n_args = 0; break; } /* linux_lookup_dcookie */ case 212: { *n_args = 0; break; } /* linux_epoll_create */ case 213: { struct linux_epoll_create_args *p = params; iarg[0] = p->size; /* l_int */ *n_args = 1; break; } /* linux_epoll_ctl_old */ case 214: { *n_args = 0; break; } /* linux_epoll_wait_old */ case 215: { *n_args = 0; break; } /* linux_remap_file_pages */ case 216: { *n_args = 0; break; } /* linux_getdents64 */ case 217: { struct linux_getdents64_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->dirent; /* void * */ iarg[2] = p->count; /* l_uint */ *n_args = 3; break; } /* linux_set_tid_address */ case 218: { struct linux_set_tid_address_args *p = params; uarg[0] = (intptr_t) p->tidptr; /* int * */ *n_args = 1; break; } /* linux_semtimedop */ case 220: { *n_args = 0; break; } /* linux_fadvise64 */ case 221: { struct linux_fadvise64_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->offset; /* l_loff_t */ iarg[2] = p->len; /* l_size_t */ iarg[3] = p->advice; /* int */ *n_args = 4; break; } /* linux_timer_create */ case 222: { struct linux_timer_create_args *p = params; iarg[0] = p->clock_id; /* clockid_t */ uarg[1] = (intptr_t) p->evp; /* struct sigevent * */ uarg[2] = (intptr_t) p->timerid; /* l_timer_t * */ *n_args = 3; break; } /* linux_timer_settime */ case 223: { struct linux_timer_settime_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ iarg[1] = p->flags; /* l_int */ uarg[2] = (intptr_t) p->new; /* const struct itimerspec * */ uarg[3] = (intptr_t) p->old; /* struct itimerspec * */ *n_args = 4; break; } /* linux_timer_gettime */ case 224: { struct linux_timer_gettime_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ uarg[1] = (intptr_t) p->setting; /* struct itimerspec * */ *n_args = 2; break; } /* linux_timer_getoverrun */ case 225: { struct linux_timer_getoverrun_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ *n_args = 1; break; } /* linux_timer_delete */ case 226: { struct linux_timer_delete_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ *n_args = 1; break; } /* linux_clock_settime */ case 227: { struct linux_clock_settime_args *p = params; iarg[0] = p->which; /* clockid_t */ uarg[1] = (intptr_t) p->tp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_clock_gettime */ case 228: { struct linux_clock_gettime_args *p = params; iarg[0] = p->which; /* clockid_t */ uarg[1] = (intptr_t) p->tp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_clock_getres */ case 229: { struct linux_clock_getres_args *p = params; iarg[0] = p->which; /* clockid_t */ uarg[1] = (intptr_t) p->tp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_clock_nanosleep */ case 230: { struct linux_clock_nanosleep_args *p = params; iarg[0] = p->which; /* clockid_t */ iarg[1] = p->flags; /* int */ uarg[2] = (intptr_t) p->rqtp; /* struct l_timespec * */ uarg[3] = (intptr_t) p->rmtp; /* struct l_timespec * */ *n_args = 4; break; } /* linux_exit_group */ case 231: { struct linux_exit_group_args *p = params; iarg[0] = p->error_code; /* int */ *n_args = 1; break; } /* linux_epoll_wait */ case 232: { struct linux_epoll_wait_args *p = params; iarg[0] = p->epfd; /* l_int */ uarg[1] = (intptr_t) p->events; /* struct epoll_event * */ iarg[2] = p->maxevents; /* l_int */ iarg[3] = p->timeout; /* l_int */ *n_args = 4; break; } /* linux_epoll_ctl */ case 233: { struct linux_epoll_ctl_args *p = params; iarg[0] = p->epfd; /* l_int */ iarg[1] = p->op; /* l_int */ iarg[2] = p->fd; /* l_int */ uarg[3] = (intptr_t) p->event; /* struct epoll_event * */ *n_args = 4; break; } /* linux_tgkill */ case 234: { struct linux_tgkill_args *p = params; iarg[0] = p->tgid; /* int */ iarg[1] = p->pid; /* int */ iarg[2] = p->sig; /* int */ *n_args = 3; break; } /* linux_utimes */ case 235: { struct linux_utimes_args *p = params; uarg[0] = (intptr_t) p->fname; /* char * */ uarg[1] = (intptr_t) p->tptr; /* struct l_timeval * */ *n_args = 2; break; } /* linux_mbind */ case 237: { *n_args = 0; break; } /* linux_set_mempolicy */ case 238: { *n_args = 0; break; } /* linux_get_mempolicy */ case 239: { *n_args = 0; break; } /* linux_mq_open */ case 240: { *n_args = 0; break; } /* linux_mq_unlink */ case 241: { *n_args = 0; break; } /* linux_mq_timedsend */ case 242: { *n_args = 0; break; } /* linux_mq_timedreceive */ case 243: { *n_args = 0; break; } /* linux_mq_notify */ case 244: { *n_args = 0; break; } /* linux_mq_getsetattr */ case 245: { *n_args = 0; break; } /* linux_kexec_load */ case 246: { *n_args = 0; break; } /* linux_waitid */ case 247: { struct linux_waitid_args *p = params; iarg[0] = p->idtype; /* int */ iarg[1] = p->id; /* l_pid_t */ uarg[2] = (intptr_t) p->info; /* l_siginfo_t * */ iarg[3] = p->options; /* int */ uarg[4] = (intptr_t) p->rusage; /* struct rusage * */ *n_args = 5; break; } /* linux_add_key */ case 248: { *n_args = 0; break; } /* linux_request_key */ case 249: { *n_args = 0; break; } /* linux_keyctl */ case 250: { *n_args = 0; break; } /* linux_ioprio_set */ case 251: { *n_args = 0; break; } /* linux_ioprio_get */ case 252: { *n_args = 0; break; } /* linux_inotify_init */ case 253: { *n_args = 0; break; } /* linux_inotify_add_watch */ case 254: { *n_args = 0; break; } /* linux_inotify_rm_watch */ case 255: { *n_args = 0; break; } /* linux_migrate_pages */ case 256: { *n_args = 0; break; } /* linux_openat */ case 257: { struct linux_openat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->flags; /* l_int */ iarg[3] = p->mode; /* l_int */ *n_args = 4; break; } /* linux_mkdirat */ case 258: { struct linux_mkdirat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* const char * */ iarg[2] = p->mode; /* l_int */ *n_args = 3; break; } /* linux_mknodat */ case 259: { struct linux_mknodat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->mode; /* l_int */ iarg[3] = p->dev; /* l_uint */ *n_args = 4; break; } /* linux_fchownat */ case 260: { struct linux_fchownat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->uid; /* l_uid_t */ iarg[3] = p->gid; /* l_gid_t */ iarg[4] = p->flag; /* l_int */ *n_args = 5; break; } /* linux_futimesat */ case 261: { struct linux_futimesat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* char * */ uarg[2] = (intptr_t) p->utimes; /* struct l_timeval * */ *n_args = 3; break; } /* linux_newfstatat */ case 262: { struct linux_newfstatat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* char * */ uarg[2] = (intptr_t) p->statbuf; /* struct l_stat64 * */ iarg[3] = p->flag; /* l_int */ *n_args = 4; break; } /* linux_unlinkat */ case 263: { struct linux_unlinkat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* const char * */ iarg[2] = p->flag; /* l_int */ *n_args = 3; break; } /* linux_renameat */ case 264: { struct linux_renameat_args *p = params; iarg[0] = p->olddfd; /* l_int */ uarg[1] = (intptr_t) p->oldname; /* const char * */ iarg[2] = p->newdfd; /* l_int */ uarg[3] = (intptr_t) p->newname; /* const char * */ *n_args = 4; break; } /* linux_linkat */ case 265: { struct linux_linkat_args *p = params; iarg[0] = p->olddfd; /* l_int */ uarg[1] = (intptr_t) p->oldname; /* const char * */ iarg[2] = p->newdfd; /* l_int */ uarg[3] = (intptr_t) p->newname; /* const char * */ iarg[4] = p->flag; /* l_int */ *n_args = 5; break; } /* linux_symlinkat */ case 266: { struct linux_symlinkat_args *p = params; uarg[0] = (intptr_t) p->oldname; /* const char * */ iarg[1] = p->newdfd; /* l_int */ uarg[2] = (intptr_t) p->newname; /* const char * */ *n_args = 3; break; } /* linux_readlinkat */ case 267: { struct linux_readlinkat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->path; /* const char * */ uarg[2] = (intptr_t) p->buf; /* char * */ iarg[3] = p->bufsiz; /* l_int */ *n_args = 4; break; } /* linux_fchmodat */ case 268: { struct linux_fchmodat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->mode; /* l_mode_t */ *n_args = 3; break; } /* linux_faccessat */ case 269: { struct linux_faccessat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->amode; /* l_int */ *n_args = 3; break; } /* linux_pselect6 */ case 270: { struct linux_pselect6_args *p = params; iarg[0] = p->nfds; /* l_int */ uarg[1] = (intptr_t) p->readfds; /* l_fd_set * */ uarg[2] = (intptr_t) p->writefds; /* l_fd_set * */ uarg[3] = (intptr_t) p->exceptfds; /* l_fd_set * */ uarg[4] = (intptr_t) p->tsp; /* struct l_timespec * */ uarg[5] = (intptr_t) p->sig; /* l_uintptr_t * */ *n_args = 6; break; } /* linux_ppoll */ case 271: { struct linux_ppoll_args *p = params; uarg[0] = (intptr_t) p->fds; /* struct pollfd * */ uarg[1] = p->nfds; /* uint32_t */ uarg[2] = (intptr_t) p->tsp; /* struct l_timespec * */ uarg[3] = (intptr_t) p->sset; /* l_sigset_t * */ iarg[4] = p->ssize; /* l_size_t */ *n_args = 5; break; } /* linux_unshare */ case 272: { *n_args = 0; break; } /* linux_set_robust_list */ case 273: { struct linux_set_robust_list_args *p = params; uarg[0] = (intptr_t) p->head; /* struct linux_robust_list_head * */ iarg[1] = p->len; /* l_size_t */ *n_args = 2; break; } /* linux_get_robust_list */ case 274: { struct linux_get_robust_list_args *p = params; iarg[0] = p->pid; /* l_int */ uarg[1] = (intptr_t) p->head; /* struct linux_robust_list_head ** */ uarg[2] = (intptr_t) p->len; /* l_size_t * */ *n_args = 3; break; } /* linux_splice */ case 275: { *n_args = 0; break; } /* linux_tee */ case 276: { *n_args = 0; break; } /* linux_sync_file_range */ case 277: { *n_args = 0; break; } /* linux_vmsplice */ case 278: { *n_args = 0; break; } /* linux_move_pages */ case 279: { *n_args = 0; break; } /* linux_utimensat */ case 280: { struct linux_utimensat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* const char * */ uarg[2] = (intptr_t) p->times; /* const struct l_timespec * */ iarg[3] = p->flags; /* l_int */ *n_args = 4; break; } /* linux_epoll_pwait */ case 281: { struct linux_epoll_pwait_args *p = params; iarg[0] = p->epfd; /* l_int */ uarg[1] = (intptr_t) p->events; /* struct epoll_event * */ iarg[2] = p->maxevents; /* l_int */ iarg[3] = p->timeout; /* l_int */ uarg[4] = (intptr_t) p->mask; /* l_sigset_t * */ *n_args = 5; break; } /* linux_signalfd */ case 282: { *n_args = 0; break; } - /* linux_timerfd */ + /* linux_timerfd_create */ case 283: { *n_args = 0; break; } /* linux_eventfd */ case 284: { struct linux_eventfd_args *p = params; iarg[0] = p->initval; /* l_uint */ *n_args = 1; break; } /* linux_fallocate */ case 285: { struct linux_fallocate_args *p = params; iarg[0] = p->fd; /* l_int */ iarg[1] = p->mode; /* l_int */ iarg[2] = p->offset; /* l_loff_t */ iarg[3] = p->len; /* l_loff_t */ *n_args = 4; break; } /* linux_timerfd_settime */ case 286: { *n_args = 0; break; } /* linux_timerfd_gettime */ case 287: { *n_args = 0; break; } /* linux_accept4 */ case 288: { struct linux_accept4_args *p = params; iarg[0] = p->s; /* l_int */ iarg[1] = p->addr; /* l_uintptr_t */ iarg[2] = p->namelen; /* l_uintptr_t */ iarg[3] = p->flags; /* int */ *n_args = 4; break; } /* linux_signalfd4 */ case 289: { *n_args = 0; break; } /* linux_eventfd2 */ case 290: { struct linux_eventfd2_args *p = params; iarg[0] = p->initval; /* l_uint */ iarg[1] = p->flags; /* l_int */ *n_args = 2; break; } /* linux_epoll_create1 */ case 291: { struct linux_epoll_create1_args *p = params; iarg[0] = p->flags; /* l_int */ *n_args = 1; break; } /* linux_dup3 */ case 292: { struct linux_dup3_args *p = params; iarg[0] = p->oldfd; /* l_int */ iarg[1] = p->newfd; /* l_int */ iarg[2] = p->flags; /* l_int */ *n_args = 3; break; } /* linux_pipe2 */ case 293: { struct linux_pipe2_args *p = params; uarg[0] = (intptr_t) p->pipefds; /* l_int * */ iarg[1] = p->flags; /* l_int */ *n_args = 2; break; } /* linux_inotify_init1 */ case 294: { - *n_args = 0; + struct linux_inotify_init1_args *p = params; + iarg[0] = p->flags; /* l_int */ + *n_args = 1; break; } /* linux_preadv */ case 295: { - *n_args = 0; + struct linux_preadv_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + *n_args = 5; break; } /* linux_pwritev */ case 296: { - *n_args = 0; + struct linux_pwritev_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + *n_args = 5; break; } - /* linux_rt_tsigqueueinfo */ + /* linux_rt_tgsigqueueinfo */ case 297: { - *n_args = 0; + struct linux_rt_tgsigqueueinfo_args *p = params; + iarg[0] = p->tgid; /* l_pid_t */ + iarg[1] = p->tid; /* l_pid_t */ + iarg[2] = p->sig; /* l_int */ + uarg[3] = (intptr_t) p->uinfo; /* l_siginfo_t * */ + *n_args = 4; break; } /* linux_perf_event_open */ case 298: { *n_args = 0; break; } /* linux_recvmmsg */ case 299: { struct linux_recvmmsg_args *p = params; iarg[0] = p->s; /* l_int */ uarg[1] = (intptr_t) p->msg; /* struct l_mmsghdr * */ iarg[2] = p->vlen; /* l_uint */ iarg[3] = p->flags; /* l_uint */ uarg[4] = (intptr_t) p->timeout; /* struct l_timespec * */ *n_args = 5; break; } /* linux_fanotify_init */ case 300: { *n_args = 0; break; } /* linux_fanotify_mark */ case 301: { *n_args = 0; break; } /* linux_prlimit64 */ case 302: { struct linux_prlimit64_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->resource; /* l_uint */ uarg[2] = (intptr_t) p->new; /* struct rlimit * */ uarg[3] = (intptr_t) p->old; /* struct rlimit * */ *n_args = 4; break; } /* linux_name_to_handle_at */ case 303: { *n_args = 0; break; } /* linux_open_by_handle_at */ case 304: { *n_args = 0; break; } /* linux_clock_adjtime */ case 305: { *n_args = 0; break; } /* linux_syncfs */ case 306: { struct linux_syncfs_args *p = params; iarg[0] = p->fd; /* l_int */ *n_args = 1; break; } /* linux_sendmmsg */ case 307: { struct linux_sendmmsg_args *p = params; iarg[0] = p->s; /* l_int */ uarg[1] = (intptr_t) p->msg; /* struct l_mmsghdr * */ iarg[2] = p->vlen; /* l_uint */ iarg[3] = p->flags; /* l_uint */ *n_args = 4; break; } /* linux_setns */ case 308: { - *n_args = 0; + struct linux_setns_args *p = params; + iarg[0] = p->fd; /* l_int */ + iarg[1] = p->nstype; /* l_int */ + *n_args = 2; break; } - /* linux_process_vm_readv */ + /* linux_getcpu */ case 309: { - *n_args = 0; + struct linux_getcpu_args *p = params; + uarg[0] = (intptr_t) p->cpu; /* l_uint * */ + uarg[1] = (intptr_t) p->node; /* l_uint * */ + uarg[2] = (intptr_t) p->cache; /* void * */ + *n_args = 3; break; } - /* linux_process_vm_writev */ + /* linux_process_vm_readv */ case 310: { - *n_args = 0; + struct linux_process_vm_readv_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->lvec; /* const struct iovec * */ + iarg[2] = p->liovcnt; /* l_ulong */ + uarg[3] = (intptr_t) p->rvec; /* const struct iovec * */ + iarg[4] = p->riovcnt; /* l_ulong */ + iarg[5] = p->flags; /* l_ulong */ + *n_args = 6; break; } - /* linux_kcmp */ + /* linux_process_vm_writev */ case 311: { - *n_args = 0; + struct linux_process_vm_writev_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->lvec; /* const struct iovec * */ + iarg[2] = p->liovcnt; /* l_ulong */ + uarg[3] = (intptr_t) p->rvec; /* const struct iovec * */ + iarg[4] = p->riovcnt; /* l_ulong */ + iarg[5] = p->flags; /* l_ulong */ + *n_args = 6; break; } - /* linux_finit_module */ + /* linux_kcmp */ case 312: { - *n_args = 0; + struct linux_kcmp_args *p = params; + iarg[0] = p->pid1; /* l_pid_t */ + iarg[1] = p->pid2; /* l_pid_t */ + iarg[2] = p->type; /* l_int */ + iarg[3] = p->idx1; /* l_ulong */ + iarg[4] = p->idx; /* l_ulong */ + *n_args = 5; break; } + /* linux_finit_module */ + case 313: { + struct linux_finit_module_args *p = params; + iarg[0] = p->fd; /* l_int */ + uarg[1] = (intptr_t) p->uargs; /* const char * */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_sched_setattr */ + case 314: { + struct linux_sched_setattr_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->attr; /* void * */ + iarg[2] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_sched_getattr */ + case 315: { + struct linux_sched_getattr_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->attr; /* void * */ + iarg[2] = p->size; /* l_uint */ + iarg[3] = p->flags; /* l_uint */ + *n_args = 4; + break; + } + /* linux_renameat2 */ + case 316: { + struct linux_renameat2_args *p = params; + iarg[0] = p->oldfd; /* l_int */ + uarg[1] = (intptr_t) p->oldname; /* const char * */ + iarg[2] = p->newfd; /* l_int */ + uarg[3] = (intptr_t) p->newname; /* const char * */ + uarg[4] = p->flags; /* unsigned int */ + *n_args = 5; + break; + } + /* linux_seccomp */ + case 317: { + struct linux_seccomp_args *p = params; + iarg[0] = p->op; /* l_uint */ + iarg[1] = p->flags; /* l_uint */ + uarg[2] = (intptr_t) p->uargs; /* const char * */ + *n_args = 3; + break; + } + /* linux_getrandom */ + case 318: { + struct linux_getrandom_args *p = params; + uarg[0] = (intptr_t) p->buf; /* char * */ + iarg[1] = p->count; /* l_size_t */ + iarg[2] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_memfd_create */ + case 319: { + struct linux_memfd_create_args *p = params; + uarg[0] = (intptr_t) p->uname_ptr; /* const char * */ + iarg[1] = p->flags; /* l_uint */ + *n_args = 2; + break; + } + /* linux_kexec_file_load */ + case 320: { + struct linux_kexec_file_load_args *p = params; + iarg[0] = p->kernel_fd; /* l_int */ + iarg[1] = p->initrd_fd; /* l_int */ + iarg[2] = p->cmdline_len; /* l_ulong */ + uarg[3] = (intptr_t) p->cmdline_ptr; /* const char * */ + iarg[4] = p->flags; /* l_ulong */ + *n_args = 5; + break; + } + /* linux_bpf */ + case 321: { + struct linux_bpf_args *p = params; + iarg[0] = p->cmd; /* l_int */ + uarg[1] = (intptr_t) p->attr; /* void * */ + iarg[2] = p->size; /* l_uint */ + *n_args = 3; + break; + } + /* linux_execveat */ + case 322: { + struct linux_execveat_args *p = params; + iarg[0] = p->dfd; /* l_int */ + uarg[1] = (intptr_t) p->filename; /* const char * */ + uarg[2] = (intptr_t) p->argv; /* const char ** */ + uarg[3] = (intptr_t) p->envp; /* const char ** */ + iarg[4] = p->flags; /* l_int */ + *n_args = 5; + break; + } + /* linux_userfaultfd */ + case 323: { + struct linux_userfaultfd_args *p = params; + iarg[0] = p->flags; /* l_int */ + *n_args = 1; + break; + } + /* linux_membarrier */ + case 324: { + struct linux_membarrier_args *p = params; + iarg[0] = p->cmd; /* l_int */ + iarg[1] = p->flags; /* l_int */ + *n_args = 2; + break; + } + /* linux_mlock2 */ + case 325: { + struct linux_mlock2_args *p = params; + iarg[0] = p->start; /* l_ulong */ + iarg[1] = p->len; /* l_size_t */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_copy_file_range */ + case 326: { + struct linux_copy_file_range_args *p = params; + iarg[0] = p->fd_in; /* l_int */ + uarg[1] = (intptr_t) p->off_in; /* l_loff_t * */ + iarg[2] = p->fd_out; /* l_int */ + uarg[3] = (intptr_t) p->off_out; /* l_loff_t * */ + iarg[4] = p->len; /* l_size_t */ + iarg[5] = p->flags; /* l_uint */ + *n_args = 6; + break; + } + /* linux_preadv2 */ + case 327: { + struct linux_preadv2_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* const struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + iarg[5] = p->flags; /* l_int */ + *n_args = 6; + break; + } + /* linux_pwritev2 */ + case 328: { + struct linux_pwritev2_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* const struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + iarg[5] = p->flags; /* l_int */ + *n_args = 6; + break; + } + /* linux_pkey_mprotect */ + case 329: { + struct linux_pkey_mprotect_args *p = params; + iarg[0] = p->start; /* l_ulong */ + iarg[1] = p->len; /* l_size_t */ + iarg[2] = p->prot; /* l_ulong */ + iarg[3] = p->pkey; /* l_int */ + *n_args = 4; + break; + } + /* linux_pkey_alloc */ + case 330: { + struct linux_pkey_alloc_args *p = params; + iarg[0] = p->flags; /* l_ulong */ + iarg[1] = p->init_val; /* l_ulong */ + *n_args = 2; + break; + } + /* linux_pkey_free */ + case 331: { + struct linux_pkey_free_args *p = params; + iarg[0] = p->pkey; /* l_int */ + *n_args = 1; + break; + } default: *n_args = 0; break; }; } static void systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) { const char *p = NULL; switch (sysnum) { #define nosys linux_nosys /* read */ case 0: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland char *"; break; case 2: p = "u_int"; break; default: break; }; break; /* write */ case 1: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland char *"; break; case 2: p = "u_int"; break; default: break; }; break; /* linux_open */ case 2: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; default: break; }; break; /* close */ case 3: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_newstat */ case 4: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_newstat *"; break; default: break; }; break; /* linux_newfstat */ case 5: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_newstat *"; break; default: break; }; break; /* linux_newlstat */ case 6: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_newstat *"; break; default: break; }; break; /* poll */ case 7: switch(ndx) { case 0: p = "userland struct pollfd *"; break; case 1: p = "u_int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_lseek */ case 8: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_off_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_mmap2 */ case 9: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; case 3: p = "l_ulong"; break; case 4: p = "l_ulong"; break; case 5: p = "l_ulong"; break; default: break; }; break; /* linux_mprotect */ case 10: switch(ndx) { case 0: p = "caddr_t"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* munmap */ case 11: switch(ndx) { case 0: p = "caddr_t"; break; case 1: p = "int"; break; default: break; }; break; /* linux_brk */ case 12: switch(ndx) { case 0: p = "l_ulong"; break; default: break; }; break; /* linux_rt_sigaction */ case 13: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_sigaction_t *"; break; case 2: p = "userland l_sigaction_t *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigprocmask */ case 14: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_sigset_t *"; break; case 2: p = "userland l_sigset_t *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigreturn */ case 15: switch(ndx) { case 0: p = "userland struct l_ucontext *"; break; default: break; }; break; /* linux_ioctl */ case 16: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_uint"; break; case 2: p = "uintptr_t"; break; default: break; }; break; /* linux_pread */ case 17: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland char *"; break; case 2: p = "l_size_t"; break; case 3: p = "l_loff_t"; break; default: break; }; break; /* linux_pwrite */ case 18: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland char *"; break; case 2: p = "l_size_t"; break; case 3: p = "l_loff_t"; break; default: break; }; break; /* readv */ case 19: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland struct iovec *"; break; case 2: p = "u_int"; break; default: break; }; break; /* writev */ case 20: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland struct iovec *"; break; case 2: p = "u_int"; break; default: break; }; break; /* linux_access */ case 21: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_pipe */ case 22: switch(ndx) { case 0: p = "userland l_ulong *"; break; default: break; }; break; /* linux_select */ case 23: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_fd_set *"; break; case 2: p = "userland l_fd_set *"; break; case 3: p = "userland l_fd_set *"; break; case 4: p = "userland struct l_timeval *"; break; default: break; }; break; /* sched_yield */ case 24: break; /* linux_mremap */ case 25: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; case 3: p = "l_ulong"; break; case 4: p = "l_ulong"; break; default: break; }; break; /* linux_msync */ case 26: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_size_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_mincore */ case 27: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_size_t"; break; case 2: p = "userland u_char *"; break; default: break; }; break; /* madvise */ case 28: switch(ndx) { case 0: p = "userland void *"; break; case 1: p = "size_t"; break; case 2: p = "int"; break; default: break; }; break; /* linux_shmget */ case 29: switch(ndx) { case 0: p = "l_key_t"; break; case 1: p = "l_size_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_shmat */ case 30: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_shmctl */ case 31: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "userland struct l_shmid_ds *"; break; default: break; }; break; /* dup */ case 32: switch(ndx) { case 0: p = "u_int"; break; default: break; }; break; /* dup2 */ case 33: switch(ndx) { case 0: p = "u_int"; break; case 1: p = "u_int"; break; default: break; }; break; /* linux_pause */ case 34: break; /* linux_nanosleep */ case 35: switch(ndx) { case 0: p = "userland const struct l_timespec *"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_getitimer */ case 36: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_itimerval *"; break; default: break; }; break; /* linux_alarm */ case 37: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_setitimer */ case 38: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_itimerval *"; break; case 2: p = "userland struct l_itimerval *"; break; default: break; }; break; /* linux_getpid */ case 39: break; /* linux_sendfile */ case 40: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "userland l_long *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_socket */ case 41: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_connect */ case 42: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_accept */ case 43: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_uintptr_t"; break; default: break; }; break; /* linux_sendto */ case 44: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; case 4: p = "l_uintptr_t"; break; case 5: p = "l_int"; break; default: break; }; break; /* linux_recvfrom */ case 45: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_size_t"; break; case 3: p = "l_int"; break; case 4: p = "l_uintptr_t"; break; case 5: p = "l_uintptr_t"; break; default: break; }; break; /* linux_sendmsg */ case 46: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_recvmsg */ case 47: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_shutdown */ case 48: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_bind */ case 49: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_listen */ case 50: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_getsockname */ case 51: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_uintptr_t"; break; default: break; }; break; /* linux_getpeername */ case 52: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_uintptr_t"; break; default: break; }; break; /* linux_socketpair */ case 53: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "l_uintptr_t"; break; default: break; }; break; /* linux_setsockopt */ case 54: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "l_uintptr_t"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_getsockopt */ case 55: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "l_uintptr_t"; break; case 4: p = "l_uintptr_t"; break; default: break; }; break; /* linux_clone */ case 56: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland void *"; break; case 2: p = "userland void *"; break; case 3: p = "userland void *"; break; case 4: p = "userland void *"; break; default: break; }; break; /* linux_fork */ case 57: break; /* linux_vfork */ case 58: break; /* linux_execve */ case 59: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char **"; break; case 2: p = "userland char **"; break; default: break; }; break; /* linux_exit */ case 60: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_wait4 */ case 61: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland l_int *"; break; case 2: p = "l_int"; break; case 3: p = "userland struct rusage *"; break; default: break; }; break; /* linux_kill */ case 62: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_newuname */ case 63: switch(ndx) { case 0: p = "userland struct l_new_utsname *"; break; default: break; }; break; /* linux_semget */ case 64: switch(ndx) { case 0: p = "l_key_t"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_semop */ case 65: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_sembuf *"; break; case 2: p = "l_uint"; break; default: break; }; break; /* linux_semctl */ case 66: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "union l_semun"; break; default: break; }; break; /* linux_shmdt */ case 67: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_msgget */ case 68: switch(ndx) { case 0: p = "l_key_t"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_msgsnd */ case 69: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_msgbuf *"; break; case 2: p = "l_size_t"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_msgrcv */ case 70: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_msgbuf *"; break; case 2: p = "l_size_t"; break; case 3: p = "l_long"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_msgctl */ case 71: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "userland struct l_msqid_ds *"; break; default: break; }; break; /* linux_fcntl */ case 72: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_uint"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* flock */ case 73: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* fsync */ case 74: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_fdatasync */ case 75: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_truncate */ case 76: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_ulong"; break; default: break; }; break; /* linux_ftruncate */ case 77: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_long"; break; default: break; }; break; /* linux_getdents */ case 78: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland void *"; break; case 2: p = "l_uint"; break; default: break; }; break; /* linux_getcwd */ case 79: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_ulong"; break; default: break; }; break; /* linux_chdir */ case 80: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* fchdir */ case 81: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_rename */ case 82: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_mkdir */ case 83: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_rmdir */ case 84: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_creat */ case 85: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_link */ case 86: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_unlink */ case 87: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_symlink */ case 88: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_readlink */ case 89: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_chmod */ case 90: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_mode_t"; break; default: break; }; break; /* fchmod */ case 91: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* linux_chown */ case 92: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid_t"; break; case 2: p = "l_gid_t"; break; default: break; }; break; /* fchown */ case 93: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_lchown */ case 94: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid_t"; break; case 2: p = "l_gid_t"; break; default: break; }; break; /* umask */ case 95: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* gettimeofday */ case 96: switch(ndx) { case 0: p = "userland struct l_timeval *"; break; case 1: p = "userland struct timezone *"; break; default: break; }; break; /* linux_getrlimit */ case 97: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_rlimit *"; break; default: break; }; break; /* getrusage */ case 98: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland struct rusage *"; break; default: break; }; break; /* linux_sysinfo */ case 99: switch(ndx) { case 0: p = "userland struct l_sysinfo *"; break; default: break; }; break; /* linux_times */ case 100: switch(ndx) { case 0: p = "userland struct l_times_argv *"; break; default: break; }; break; /* linux_ptrace */ case 101: switch(ndx) { case 0: p = "l_long"; break; case 1: p = "l_long"; break; case 2: p = "l_long"; break; case 3: p = "l_long"; break; default: break; }; break; /* linux_getuid */ case 102: break; /* linux_syslog */ case 103: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_getgid */ case 104: break; /* setuid */ case 105: switch(ndx) { case 0: p = "uid_t"; break; default: break; }; break; /* setgid */ case 106: switch(ndx) { case 0: p = "gid_t"; break; default: break; }; break; /* geteuid */ case 107: break; /* getegid */ case 108: break; /* setpgid */ case 109: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* linux_getppid */ case 110: break; /* getpgrp */ case 111: break; /* setsid */ case 112: break; /* setreuid */ case 113: switch(ndx) { case 0: p = "uid_t"; break; case 1: p = "uid_t"; break; default: break; }; break; /* setregid */ case 114: switch(ndx) { case 0: p = "gid_t"; break; case 1: p = "gid_t"; break; default: break; }; break; /* linux_getgroups */ case 115: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_gid_t *"; break; default: break; }; break; /* linux_setgroups */ case 116: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_gid_t *"; break; default: break; }; break; /* setresuid */ case 117: switch(ndx) { case 0: p = "uid_t"; break; case 1: p = "uid_t"; break; case 2: p = "uid_t"; break; default: break; }; break; /* getresuid */ case 118: switch(ndx) { case 0: p = "userland uid_t *"; break; case 1: p = "userland uid_t *"; break; case 2: p = "userland uid_t *"; break; default: break; }; break; /* setresgid */ case 119: switch(ndx) { case 0: p = "gid_t"; break; case 1: p = "gid_t"; break; case 2: p = "gid_t"; break; default: break; }; break; /* getresgid */ case 120: switch(ndx) { case 0: p = "userland gid_t *"; break; case 1: p = "userland gid_t *"; break; case 2: p = "userland gid_t *"; break; default: break; }; break; /* getpgid */ case 121: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_setfsuid */ case 122: switch(ndx) { case 0: p = "l_uid_t"; break; default: break; }; break; /* linux_setfsgid */ case 123: switch(ndx) { case 0: p = "l_gid_t"; break; default: break; }; break; /* linux_getsid */ case 124: switch(ndx) { case 0: p = "l_pid_t"; break; default: break; }; break; /* linux_capget */ case 125: switch(ndx) { case 0: p = "userland struct l_user_cap_header *"; break; case 1: p = "userland struct l_user_cap_data *"; break; default: break; }; break; /* linux_capset */ case 126: switch(ndx) { case 0: p = "userland struct l_user_cap_header *"; break; case 1: p = "userland struct l_user_cap_data *"; break; default: break; }; break; /* linux_rt_sigpending */ case 127: switch(ndx) { case 0: p = "userland l_sigset_t *"; break; case 1: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigtimedwait */ case 128: switch(ndx) { case 0: p = "userland l_sigset_t *"; break; case 1: p = "userland l_siginfo_t *"; break; case 2: p = "userland struct l_timeval *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigqueueinfo */ case 129: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_int"; break; case 2: p = "userland l_siginfo_t *"; break; default: break; }; break; /* linux_rt_sigsuspend */ case 130: switch(ndx) { case 0: p = "userland l_sigset_t *"; break; case 1: p = "l_size_t"; break; default: break; }; break; /* linux_sigaltstack */ case 131: switch(ndx) { case 0: p = "userland l_stack_t *"; break; case 1: p = "userland l_stack_t *"; break; default: break; }; break; /* linux_utime */ case 132: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_utimbuf *"; break; default: break; }; break; /* linux_mknod */ case 133: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; case 2: p = "l_dev_t"; break; default: break; }; break; /* linux_personality */ case 135: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_ustat */ case 136: switch(ndx) { case 0: p = "l_dev_t"; break; case 1: p = "userland struct l_ustat *"; break; default: break; }; break; /* linux_statfs */ case 137: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_statfs_buf *"; break; default: break; }; break; /* linux_fstatfs */ case 138: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_statfs_buf *"; break; default: break; }; break; /* linux_sysfs */ case 139: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* linux_getpriority */ case 140: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* setpriority */ case 141: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_sched_setparam */ case 142: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland struct sched_param *"; break; default: break; }; break; /* linux_sched_getparam */ case 143: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland struct sched_param *"; break; default: break; }; break; /* linux_sched_setscheduler */ case 144: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_int"; break; case 2: p = "userland struct sched_param *"; break; default: break; }; break; /* linux_sched_getscheduler */ case 145: switch(ndx) { case 0: p = "l_pid_t"; break; default: break; }; break; /* linux_sched_get_priority_max */ case 146: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_sched_get_priority_min */ case 147: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_sched_rr_get_interval */ case 148: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* mlock */ case 149: switch(ndx) { case 0: p = "userland const void *"; break; case 1: p = "size_t"; break; default: break; }; break; /* munlock */ case 150: switch(ndx) { case 0: p = "userland const void *"; break; case 1: p = "size_t"; break; default: break; }; break; /* mlockall */ case 151: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* munlockall */ case 152: break; /* linux_vhangup */ case 153: break; /* linux_pivot_root */ case 155: break; /* linux_sysctl */ case 156: switch(ndx) { case 0: p = "userland struct l___sysctl_args *"; break; default: break; }; break; /* linux_prctl */ case 157: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_uintptr_t"; break; case 3: p = "l_uintptr_t"; break; case 4: p = "l_uintptr_t"; break; default: break; }; break; /* linux_arch_prctl */ case 158: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_ulong"; break; default: break; }; break; /* linux_adjtimex */ case 159: break; /* linux_setrlimit */ case 160: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_rlimit *"; break; default: break; }; break; /* chroot */ case 161: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* sync */ case 162: break; /* acct */ case 163: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* settimeofday */ case 164: switch(ndx) { case 0: p = "userland struct l_timeval *"; break; case 1: p = "userland struct timezone *"; break; default: break; }; break; /* linux_mount */ case 165: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; case 2: p = "userland char *"; break; case 3: p = "l_ulong"; break; case 4: p = "userland void *"; break; default: break; }; break; /* linux_umount */ case 166: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* swapon */ case 167: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_swapoff */ case 168: break; /* linux_reboot */ case 169: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_uint"; break; case 3: p = "userland void *"; break; default: break; }; break; /* linux_sethostname */ case 170: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uint"; break; default: break; }; break; /* linux_setdomainname */ case 171: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_iopl */ case 172: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_create_module */ case 174: break; /* linux_init_module */ case 175: break; /* linux_delete_module */ case 176: break; /* linux_get_kernel_syms */ case 177: break; /* linux_query_module */ case 178: break; /* linux_quotactl */ case 179: break; /* linux_nfsservctl */ case 180: break; /* linux_getpmsg */ case 181: break; /* linux_putpmsg */ case 182: break; /* linux_afs_syscall */ case 183: break; /* linux_tuxcall */ case 184: break; /* linux_security */ case 185: break; /* linux_gettid */ case 186: break; /* linux_setxattr */ case 188: break; /* linux_lsetxattr */ case 189: break; /* linux_fsetxattr */ case 190: break; /* linux_getxattr */ case 191: break; /* linux_lgetxattr */ case 192: break; /* linux_fgetxattr */ case 193: break; /* linux_listxattr */ case 194: break; /* linux_llistxattr */ case 195: break; /* linux_flistxattr */ case 196: break; /* linux_removexattr */ case 197: break; /* linux_lremovexattr */ case 198: break; /* linux_fremovexattr */ case 199: break; /* linux_tkill */ case 200: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* linux_time */ case 201: switch(ndx) { case 0: p = "userland l_time_t *"; break; default: break; }; break; /* linux_sys_futex */ case 202: switch(ndx) { case 0: p = "userland void *"; break; case 1: p = "int"; break; case 2: p = "int"; break; case 3: p = "userland struct l_timespec *"; break; case 4: p = "userland void *"; break; case 5: p = "int"; break; default: break; }; break; /* linux_sched_setaffinity */ case 203: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_uint"; break; case 2: p = "userland l_ulong *"; break; default: break; }; break; /* linux_sched_getaffinity */ case 204: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_uint"; break; case 2: p = "userland l_ulong *"; break; default: break; }; break; /* linux_set_thread_area */ case 205: break; /* linux_lookup_dcookie */ case 212: break; /* linux_epoll_create */ case 213: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_epoll_ctl_old */ case 214: break; /* linux_epoll_wait_old */ case 215: break; /* linux_remap_file_pages */ case 216: break; /* linux_getdents64 */ case 217: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland void *"; break; case 2: p = "l_uint"; break; default: break; }; break; /* linux_set_tid_address */ case 218: switch(ndx) { case 0: p = "userland int *"; break; default: break; }; break; /* linux_semtimedop */ case 220: break; /* linux_fadvise64 */ case 221: switch(ndx) { case 0: p = "int"; break; case 1: p = "l_loff_t"; break; case 2: p = "l_size_t"; break; case 3: p = "int"; break; default: break; }; break; /* linux_timer_create */ case 222: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct sigevent *"; break; case 2: p = "userland l_timer_t *"; break; default: break; }; break; /* linux_timer_settime */ case 223: switch(ndx) { case 0: p = "l_timer_t"; break; case 1: p = "l_int"; break; case 2: p = "userland const struct itimerspec *"; break; case 3: p = "userland struct itimerspec *"; break; default: break; }; break; /* linux_timer_gettime */ case 224: switch(ndx) { case 0: p = "l_timer_t"; break; case 1: p = "userland struct itimerspec *"; break; default: break; }; break; /* linux_timer_getoverrun */ case 225: switch(ndx) { case 0: p = "l_timer_t"; break; default: break; }; break; /* linux_timer_delete */ case 226: switch(ndx) { case 0: p = "l_timer_t"; break; default: break; }; break; /* linux_clock_settime */ case 227: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_clock_gettime */ case 228: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_clock_getres */ case 229: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_clock_nanosleep */ case 230: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "int"; break; case 2: p = "userland struct l_timespec *"; break; case 3: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_exit_group */ case 231: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_epoll_wait */ case 232: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct epoll_event *"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_epoll_ctl */ case 233: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "userland struct epoll_event *"; break; default: break; }; break; /* linux_tgkill */ case 234: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_utimes */ case 235: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_timeval *"; break; default: break; }; break; /* linux_mbind */ case 237: break; /* linux_set_mempolicy */ case 238: break; /* linux_get_mempolicy */ case 239: break; /* linux_mq_open */ case 240: break; /* linux_mq_unlink */ case 241: break; /* linux_mq_timedsend */ case 242: break; /* linux_mq_timedreceive */ case 243: break; /* linux_mq_notify */ case 244: break; /* linux_mq_getsetattr */ case 245: break; /* linux_kexec_load */ case 246: break; /* linux_waitid */ case 247: switch(ndx) { case 0: p = "int"; break; case 1: p = "l_pid_t"; break; case 2: p = "userland l_siginfo_t *"; break; case 3: p = "int"; break; case 4: p = "userland struct rusage *"; break; default: break; }; break; /* linux_add_key */ case 248: break; /* linux_request_key */ case 249: break; /* linux_keyctl */ case 250: break; /* linux_ioprio_set */ case 251: break; /* linux_ioprio_get */ case 252: break; /* linux_inotify_init */ case 253: break; /* linux_inotify_add_watch */ case 254: break; /* linux_inotify_rm_watch */ case 255: break; /* linux_migrate_pages */ case 256: break; /* linux_openat */ case 257: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_mkdirat */ case 258: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_mknodat */ case 259: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "l_uint"; break; default: break; }; break; /* linux_fchownat */ case 260: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_uid_t"; break; case 3: p = "l_gid_t"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_futimesat */ case 261: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "userland struct l_timeval *"; break; default: break; }; break; /* linux_newfstatat */ case 262: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "userland struct l_stat64 *"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_unlinkat */ case 263: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_renameat */ case 264: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "userland const char *"; break; default: break; }; break; /* linux_linkat */ case 265: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "userland const char *"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_symlinkat */ case 266: switch(ndx) { case 0: p = "userland const char *"; break; case 1: p = "l_int"; break; case 2: p = "userland const char *"; break; default: break; }; break; /* linux_readlinkat */ case 267: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "userland char *"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_fchmodat */ case 268: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_mode_t"; break; default: break; }; break; /* linux_faccessat */ case 269: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_pselect6 */ case 270: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_fd_set *"; break; case 2: p = "userland l_fd_set *"; break; case 3: p = "userland l_fd_set *"; break; case 4: p = "userland struct l_timespec *"; break; case 5: p = "userland l_uintptr_t *"; break; default: break; }; break; /* linux_ppoll */ case 271: switch(ndx) { case 0: p = "userland struct pollfd *"; break; case 1: p = "uint32_t"; break; case 2: p = "userland struct l_timespec *"; break; case 3: p = "userland l_sigset_t *"; break; case 4: p = "l_size_t"; break; default: break; }; break; /* linux_unshare */ case 272: break; /* linux_set_robust_list */ case 273: switch(ndx) { case 0: p = "userland struct linux_robust_list_head *"; break; case 1: p = "l_size_t"; break; default: break; }; break; /* linux_get_robust_list */ case 274: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct linux_robust_list_head **"; break; case 2: p = "userland l_size_t *"; break; default: break; }; break; /* linux_splice */ case 275: break; /* linux_tee */ case 276: break; /* linux_sync_file_range */ case 277: break; /* linux_vmsplice */ case 278: break; /* linux_move_pages */ case 279: break; /* linux_utimensat */ case 280: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "userland const struct l_timespec *"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_epoll_pwait */ case 281: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct epoll_event *"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; case 4: p = "userland l_sigset_t *"; break; default: break; }; break; /* linux_signalfd */ case 282: break; - /* linux_timerfd */ + /* linux_timerfd_create */ case 283: break; /* linux_eventfd */ case 284: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_fallocate */ case 285: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_loff_t"; break; case 3: p = "l_loff_t"; break; default: break; }; break; /* linux_timerfd_settime */ case 286: break; /* linux_timerfd_gettime */ case 287: break; /* linux_accept4 */ case 288: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_uintptr_t"; break; case 2: p = "l_uintptr_t"; break; case 3: p = "int"; break; default: break; }; break; /* linux_signalfd4 */ case 289: break; /* linux_eventfd2 */ case 290: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_epoll_create1 */ case 291: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_dup3 */ case 292: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_pipe2 */ case 293: switch(ndx) { case 0: p = "userland l_int *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_inotify_init1 */ case 294: + switch(ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; break; /* linux_preadv */ case 295: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; break; /* linux_pwritev */ case 296: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; break; - /* linux_rt_tsigqueueinfo */ + /* linux_rt_tgsigqueueinfo */ case 297: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland l_siginfo_t *"; + break; + default: + break; + }; break; /* linux_perf_event_open */ case 298: break; /* linux_recvmmsg */ case 299: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_mmsghdr *"; break; case 2: p = "l_uint"; break; case 3: p = "l_uint"; break; case 4: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_fanotify_init */ case 300: break; /* linux_fanotify_mark */ case 301: break; /* linux_prlimit64 */ case 302: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_uint"; break; case 2: p = "userland struct rlimit *"; break; case 3: p = "userland struct rlimit *"; break; default: break; }; break; /* linux_name_to_handle_at */ case 303: break; /* linux_open_by_handle_at */ case 304: break; /* linux_clock_adjtime */ case 305: break; /* linux_syncfs */ case 306: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_sendmmsg */ case 307: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_mmsghdr *"; break; case 2: p = "l_uint"; break; case 3: p = "l_uint"; break; default: break; }; break; /* linux_setns */ case 308: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; break; - /* linux_process_vm_readv */ + /* linux_getcpu */ case 309: + switch(ndx) { + case 0: + p = "userland l_uint *"; + break; + case 1: + p = "userland l_uint *"; + break; + case 2: + p = "userland void *"; + break; + default: + break; + }; break; - /* linux_process_vm_writev */ + /* linux_process_vm_readv */ case 310: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "userland const struct iovec *"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_ulong"; + break; + default: + break; + }; break; - /* linux_kcmp */ + /* linux_process_vm_writev */ case 311: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "userland const struct iovec *"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_ulong"; + break; + default: + break; + }; break; - /* linux_finit_module */ + /* linux_kcmp */ case 312: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; break; + /* linux_finit_module */ + case 313: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sched_setattr */ + case 314: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_sched_getattr */ + case 315: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + case 3: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_renameat2 */ + case 316: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland const char *"; + break; + case 4: + p = "unsigned int"; + break; + default: + break; + }; + break; + /* linux_seccomp */ + case 317: + switch(ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_getrandom */ + case 318: + switch(ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_memfd_create */ + case 319: + switch(ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_kexec_file_load */ + case 320: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "userland const char *"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_bpf */ + case 321: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_execveat */ + case 322: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland const char **"; + break; + case 3: + p = "userland const char **"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_userfaultfd */ + case 323: + switch(ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_membarrier */ + case 324: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_mlock2 */ + case 325: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_copy_file_range */ + case 326: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland l_loff_t *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland l_loff_t *"; + break; + case 4: + p = "l_size_t"; + break; + case 5: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_preadv2 */ + case 327: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pwritev2 */ + case 328: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pkey_mprotect */ + case 329: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pkey_alloc */ + case 330: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_pkey_free */ + case 331: + switch(ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; default: break; }; if (p != NULL) strlcpy(desc, p, descsz); } static void systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) { const char *p = NULL; switch (sysnum) { #define nosys linux_nosys /* read */ case 0: if (ndx == 0 || ndx == 1) p = "int"; break; /* write */ case 1: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_open */ case 2: if (ndx == 0 || ndx == 1) p = "int"; break; /* close */ case 3: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newstat */ case 4: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newfstat */ case 5: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newlstat */ case 6: if (ndx == 0 || ndx == 1) p = "int"; break; /* poll */ case 7: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lseek */ case 8: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mmap2 */ case 9: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mprotect */ case 10: if (ndx == 0 || ndx == 1) p = "int"; break; /* munmap */ case 11: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_brk */ case 12: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigaction */ case 13: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigprocmask */ case 14: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigreturn */ case 15: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ioctl */ case 16: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pread */ case 17: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pwrite */ case 18: if (ndx == 0 || ndx == 1) p = "int"; break; /* readv */ case 19: if (ndx == 0 || ndx == 1) p = "int"; break; /* writev */ case 20: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_access */ case 21: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pipe */ case 22: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_select */ case 23: if (ndx == 0 || ndx == 1) p = "int"; break; /* sched_yield */ case 24: /* linux_mremap */ case 25: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_msync */ case 26: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mincore */ case 27: if (ndx == 0 || ndx == 1) p = "int"; break; /* madvise */ case 28: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_shmget */ case 29: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_shmat */ case 30: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_shmctl */ case 31: if (ndx == 0 || ndx == 1) p = "int"; break; /* dup */ case 32: if (ndx == 0 || ndx == 1) p = "int"; break; /* dup2 */ case 33: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pause */ case 34: /* linux_nanosleep */ case 35: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getitimer */ case 36: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_alarm */ case 37: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setitimer */ case 38: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getpid */ case 39: /* linux_sendfile */ case 40: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_socket */ case 41: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_connect */ case 42: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_accept */ case 43: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sendto */ case 44: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_recvfrom */ case 45: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sendmsg */ case 46: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_recvmsg */ case 47: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_shutdown */ case 48: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_bind */ case 49: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_listen */ case 50: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getsockname */ case 51: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getpeername */ case 52: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_socketpair */ case 53: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setsockopt */ case 54: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getsockopt */ case 55: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clone */ case 56: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fork */ case 57: /* linux_vfork */ case 58: /* linux_execve */ case 59: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_exit */ case 60: if (ndx == 0 || ndx == 1) p = "void"; break; /* linux_wait4 */ case 61: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_kill */ case 62: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newuname */ case 63: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_semget */ case 64: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_semop */ case 65: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_semctl */ case 66: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_shmdt */ case 67: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_msgget */ case 68: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_msgsnd */ case 69: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_msgrcv */ case 70: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_msgctl */ case 71: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fcntl */ case 72: if (ndx == 0 || ndx == 1) p = "int"; break; /* flock */ case 73: if (ndx == 0 || ndx == 1) p = "int"; break; /* fsync */ case 74: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fdatasync */ case 75: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_truncate */ case 76: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ftruncate */ case 77: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getdents */ case 78: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getcwd */ case 79: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chdir */ case 80: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchdir */ case 81: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rename */ case 82: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mkdir */ case 83: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rmdir */ case 84: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_creat */ case 85: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_link */ case 86: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_unlink */ case 87: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_symlink */ case 88: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_readlink */ case 89: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chmod */ case 90: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchmod */ case 91: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chown */ case 92: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchown */ case 93: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lchown */ case 94: if (ndx == 0 || ndx == 1) p = "int"; break; /* umask */ case 95: if (ndx == 0 || ndx == 1) p = "int"; break; /* gettimeofday */ case 96: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getrlimit */ case 97: if (ndx == 0 || ndx == 1) p = "int"; break; /* getrusage */ case 98: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sysinfo */ case 99: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_times */ case 100: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ptrace */ case 101: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getuid */ case 102: /* linux_syslog */ case 103: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getgid */ case 104: /* setuid */ case 105: if (ndx == 0 || ndx == 1) p = "int"; break; /* setgid */ case 106: if (ndx == 0 || ndx == 1) p = "int"; break; /* geteuid */ case 107: /* getegid */ case 108: /* setpgid */ case 109: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getppid */ case 110: /* getpgrp */ case 111: /* setsid */ case 112: /* setreuid */ case 113: if (ndx == 0 || ndx == 1) p = "int"; break; /* setregid */ case 114: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getgroups */ case 115: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setgroups */ case 116: if (ndx == 0 || ndx == 1) p = "int"; break; /* setresuid */ case 117: if (ndx == 0 || ndx == 1) p = "int"; break; /* getresuid */ case 118: if (ndx == 0 || ndx == 1) p = "int"; break; /* setresgid */ case 119: if (ndx == 0 || ndx == 1) p = "int"; break; /* getresgid */ case 120: if (ndx == 0 || ndx == 1) p = "int"; break; /* getpgid */ case 121: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsuid */ case 122: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsgid */ case 123: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getsid */ case 124: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_capget */ case 125: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_capset */ case 126: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigpending */ case 127: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigtimedwait */ case 128: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigqueueinfo */ case 129: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigsuspend */ case 130: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigaltstack */ case 131: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_utime */ case 132: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mknod */ case 133: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_personality */ case 135: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ustat */ case 136: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_statfs */ case 137: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstatfs */ case 138: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sysfs */ case 139: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getpriority */ case 140: if (ndx == 0 || ndx == 1) p = "int"; break; /* setpriority */ case 141: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_setparam */ case 142: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_getparam */ case 143: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_setscheduler */ case 144: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_getscheduler */ case 145: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_get_priority_max */ case 146: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_get_priority_min */ case 147: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_rr_get_interval */ case 148: if (ndx == 0 || ndx == 1) p = "int"; break; /* mlock */ case 149: if (ndx == 0 || ndx == 1) p = "int"; break; /* munlock */ case 150: if (ndx == 0 || ndx == 1) p = "int"; break; /* mlockall */ case 151: if (ndx == 0 || ndx == 1) p = "int"; break; /* munlockall */ case 152: /* linux_vhangup */ case 153: /* linux_pivot_root */ case 155: /* linux_sysctl */ case 156: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_prctl */ case 157: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_arch_prctl */ case 158: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_adjtimex */ case 159: /* linux_setrlimit */ case 160: if (ndx == 0 || ndx == 1) p = "int"; break; /* chroot */ case 161: if (ndx == 0 || ndx == 1) p = "int"; break; /* sync */ case 162: /* acct */ case 163: if (ndx == 0 || ndx == 1) p = "int"; break; /* settimeofday */ case 164: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mount */ case 165: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_umount */ case 166: if (ndx == 0 || ndx == 1) p = "int"; break; /* swapon */ case 167: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_swapoff */ case 168: /* linux_reboot */ case 169: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sethostname */ case 170: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setdomainname */ case 171: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_iopl */ case 172: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_create_module */ case 174: /* linux_init_module */ case 175: /* linux_delete_module */ case 176: /* linux_get_kernel_syms */ case 177: /* linux_query_module */ case 178: /* linux_quotactl */ case 179: /* linux_nfsservctl */ case 180: /* linux_getpmsg */ case 181: /* linux_putpmsg */ case 182: /* linux_afs_syscall */ case 183: /* linux_tuxcall */ case 184: /* linux_security */ case 185: /* linux_gettid */ case 186: /* linux_setxattr */ case 188: /* linux_lsetxattr */ case 189: /* linux_fsetxattr */ case 190: /* linux_getxattr */ case 191: /* linux_lgetxattr */ case 192: /* linux_fgetxattr */ case 193: /* linux_listxattr */ case 194: /* linux_llistxattr */ case 195: /* linux_flistxattr */ case 196: /* linux_removexattr */ case 197: /* linux_lremovexattr */ case 198: /* linux_fremovexattr */ case 199: /* linux_tkill */ case 200: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_time */ case 201: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sys_futex */ case 202: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_setaffinity */ case 203: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_getaffinity */ case 204: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_set_thread_area */ case 205: /* linux_lookup_dcookie */ case 212: /* linux_epoll_create */ case 213: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_ctl_old */ case 214: /* linux_epoll_wait_old */ case 215: /* linux_remap_file_pages */ case 216: /* linux_getdents64 */ case 217: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_set_tid_address */ case 218: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_semtimedop */ case 220: /* linux_fadvise64 */ case 221: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_create */ case 222: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_settime */ case 223: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_gettime */ case 224: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_getoverrun */ case 225: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_delete */ case 226: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_settime */ case 227: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_gettime */ case 228: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_getres */ case 229: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_nanosleep */ case 230: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_exit_group */ case 231: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_wait */ case 232: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_ctl */ case 233: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_tgkill */ case 234: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_utimes */ case 235: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mbind */ case 237: /* linux_set_mempolicy */ case 238: /* linux_get_mempolicy */ case 239: /* linux_mq_open */ case 240: /* linux_mq_unlink */ case 241: /* linux_mq_timedsend */ case 242: /* linux_mq_timedreceive */ case 243: /* linux_mq_notify */ case 244: /* linux_mq_getsetattr */ case 245: /* linux_kexec_load */ case 246: /* linux_waitid */ case 247: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_add_key */ case 248: /* linux_request_key */ case 249: /* linux_keyctl */ case 250: /* linux_ioprio_set */ case 251: /* linux_ioprio_get */ case 252: /* linux_inotify_init */ case 253: /* linux_inotify_add_watch */ case 254: /* linux_inotify_rm_watch */ case 255: /* linux_migrate_pages */ case 256: /* linux_openat */ case 257: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mkdirat */ case 258: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mknodat */ case 259: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fchownat */ case 260: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_futimesat */ case 261: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newfstatat */ case 262: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_unlinkat */ case 263: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_renameat */ case 264: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_linkat */ case 265: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_symlinkat */ case 266: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_readlinkat */ case 267: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fchmodat */ case 268: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_faccessat */ case 269: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pselect6 */ case 270: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ppoll */ case 271: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_unshare */ case 272: /* linux_set_robust_list */ case 273: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_get_robust_list */ case 274: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_splice */ case 275: /* linux_tee */ case 276: /* linux_sync_file_range */ case 277: /* linux_vmsplice */ case 278: /* linux_move_pages */ case 279: /* linux_utimensat */ case 280: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_pwait */ case 281: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_signalfd */ case 282: - /* linux_timerfd */ + /* linux_timerfd_create */ case 283: /* linux_eventfd */ case 284: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fallocate */ case 285: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timerfd_settime */ case 286: /* linux_timerfd_gettime */ case 287: /* linux_accept4 */ case 288: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_signalfd4 */ case 289: /* linux_eventfd2 */ case 290: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_create1 */ case 291: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_dup3 */ case 292: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pipe2 */ case 293: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_inotify_init1 */ case 294: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_preadv */ case 295: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_pwritev */ case 296: - /* linux_rt_tsigqueueinfo */ + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_tgsigqueueinfo */ case 297: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_perf_event_open */ case 298: /* linux_recvmmsg */ case 299: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fanotify_init */ case 300: /* linux_fanotify_mark */ case 301: /* linux_prlimit64 */ case 302: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_name_to_handle_at */ case 303: /* linux_open_by_handle_at */ case 304: /* linux_clock_adjtime */ case 305: /* linux_syncfs */ case 306: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sendmmsg */ case 307: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setns */ case 308: - /* linux_process_vm_readv */ + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getcpu */ case 309: - /* linux_process_vm_writev */ + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_process_vm_readv */ case 310: - /* linux_kcmp */ + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_process_vm_writev */ case 311: - /* linux_finit_module */ + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_kcmp */ case 312: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_finit_module */ + case 313: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_setattr */ + case 314: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_getattr */ + case 315: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_renameat2 */ + case 316: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_seccomp */ + case 317: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getrandom */ + case 318: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_memfd_create */ + case 319: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_kexec_file_load */ + case 320: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_bpf */ + case 321: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_execveat */ + case 322: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_userfaultfd */ + case 323: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_membarrier */ + case 324: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mlock2 */ + case 325: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_copy_file_range */ + case 326: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_preadv2 */ + case 327: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pwritev2 */ + case 328: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_mprotect */ + case 329: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_alloc */ + case 330: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_free */ + case 331: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; if (p != NULL) strlcpy(desc, p, descsz); } Index: projects/ipsec/sys/amd64/linux/syscalls.master =================================================================== --- projects/ipsec/sys/amd64/linux/syscalls.master (revision 313312) +++ projects/ipsec/sys/amd64/linux/syscalls.master (revision 313313) @@ -1,515 +1,596 @@ $FreeBSD$ ; @(#)syscalls.master 8.1 (Berkeley) 7/19/93 ; System call name/number master file (or rather, slave, from LINUX). ; Processed to create linux_sysent.c, linux_proto.h and linux_syscall.h. ; Columns: number audit type nargs name alt{name,tag,rtyp}/comments ; number system call number, must be in order ; audit the audit event associated with the system call ; A value of AUE_NULL means no auditing, but it also means that ; there is no audit event for the call at this time. For the ; case where the event exists, but we don't want auditing, the ; event should be #defined to AUE_NULL in audit_kevents.h. -; type one of STD, OBSOL, UNIMPL +; type one of STD, NOPROTO, UNIMPL ; name psuedo-prototype of syscall routine ; If one of the following alts is different, then all appear: ; altname name of system call if different ; alttag name of args struct tag if different from [o]`name'"_args" ; altrtyp return type if not int (bogus - syscalls always return int) -; for UNIMPL/OBSOL, name continues with comments +; for UNIMPL, name continues with comments ; types: ; STD always included -; OBSOL obsolete, not included in system, only specifies name ; UNIMPL not implemented, placeholder only +; NOPROTO same as STD except do not create structure or +; function prototype in sys/sysproto.h. Does add a +; definition to syscall.h besides adding a sysent. #include #include #include #include #include #include ; Isn't pretty, but there seems to be no other way to trap nosys #define nosys linux_nosys ; #ifdef's, etc. may be included, and are copied to the output files. 0 AUE_NULL NOPROTO { int read(int fd, char *buf, \ u_int nbyte); } 1 AUE_NULL NOPROTO { int write(int fd, char *buf, \ u_int nbyte); } 2 AUE_OPEN_RWTC STD { int linux_open(char *path, l_int flags, \ l_int mode); } 3 AUE_CLOSE NOPROTO { int close(int fd); } 4 AUE_STAT STD { int linux_newstat(char *path, \ struct l_newstat *buf); } 5 AUE_FSTAT STD { int linux_newfstat(l_uint fd, \ struct l_newstat *buf); } 6 AUE_LSTAT STD { int linux_newlstat(char *path, \ struct l_newstat *buf); } 7 AUE_POLL NOPROTO { int poll(struct pollfd *fds, u_int nfds, \ int timeout); } 8 AUE_LSEEK STD { int linux_lseek(l_uint fdes, l_off_t off, \ l_int whence); } 9 AUE_MMAP STD { int linux_mmap2(l_ulong addr, l_ulong len, \ l_ulong prot, l_ulong flags, l_ulong fd, \ l_ulong pgoff); } 10 AUE_MPROTECT STD { int linux_mprotect(caddr_t addr, int len, \ int prot); } 11 AUE_MUNMAP NOPROTO { int munmap(caddr_t addr, int len); } 12 AUE_NULL STD { int linux_brk(l_ulong dsend); } 13 AUE_NULL STD { int linux_rt_sigaction(l_int sig, \ l_sigaction_t *act, l_sigaction_t *oact, \ l_size_t sigsetsize); } 14 AUE_NULL STD { int linux_rt_sigprocmask(l_int how, \ l_sigset_t *mask, l_sigset_t *omask, \ l_size_t sigsetsize); } 15 AUE_NULL STD { int linux_rt_sigreturn( \ struct l_ucontext *ucp); } 16 AUE_IOCTL STD { int linux_ioctl(l_uint fd, l_uint cmd, \ uintptr_t arg); } 17 AUE_PREAD STD { int linux_pread(l_uint fd, char *buf, \ l_size_t nbyte, l_loff_t offset); } 18 AUE_PWRITE STD { int linux_pwrite(l_uint fd, char *buf, \ l_size_t nbyte, l_loff_t offset); } 19 AUE_READV NOPROTO { int readv(int fd, struct iovec *iovp, \ u_int iovcnt); } 20 AUE_WRITEV NOPROTO { int writev(int fd, struct iovec *iovp, \ u_int iovcnt); } 21 AUE_ACCESS STD { int linux_access(char *path, l_int amode); } 22 AUE_PIPE STD { int linux_pipe(l_ulong *pipefds); } 23 AUE_SELECT STD { int linux_select(l_int nfds, \ l_fd_set *readfds, l_fd_set *writefds, \ l_fd_set *exceptfds, \ struct l_timeval *timeout); } 24 AUE_NULL NOPROTO { int sched_yield(void); } 25 AUE_NULL STD { int linux_mremap(l_ulong addr, \ l_ulong old_len, l_ulong new_len, \ l_ulong flags, l_ulong new_addr); } 26 AUE_MSYNC STD { int linux_msync(l_ulong addr, \ l_size_t len, l_int fl); } 27 AUE_MINCORE STD { int linux_mincore(l_ulong start, \ l_size_t len, u_char *vec); } 28 AUE_MADVISE NOPROTO { int madvise(void *addr, size_t len, \ int behav); } 29 AUE_NULL STD { int linux_shmget(l_key_t key, l_size_t size, \ l_int shmflg); } 30 AUE_NULL STD { int linux_shmat(l_int shmid, char *shmaddr, \ l_int shmflg); } 31 AUE_NULL STD { int linux_shmctl(l_int shmid, l_int cmd, \ struct l_shmid_ds *buf); } 32 AUE_DUP NOPROTO { int dup(u_int fd); } 33 AUE_DUP2 NOPROTO { int dup2(u_int from, u_int to); } 34 AUE_NULL STD { int linux_pause(void); } 35 AUE_NULL STD { int linux_nanosleep( \ const struct l_timespec *rqtp, \ struct l_timespec *rmtp); } 36 AUE_GETITIMER STD { int linux_getitimer(l_int which, \ struct l_itimerval *itv); } 37 AUE_NULL STD { int linux_alarm(l_uint secs); } 38 AUE_SETITIMER STD { int linux_setitimer(l_int which, \ struct l_itimerval *itv, \ struct l_itimerval *oitv); } 39 AUE_GETPID STD { int linux_getpid(void); } 40 AUE_SENDFILE STD { int linux_sendfile(int out, int in, \ l_long *offset, l_size_t count); } 41 AUE_SOCKET STD { int linux_socket(l_int domain, l_int type, \ l_int protocol); } 42 AUE_CONNECT STD { int linux_connect(l_int s, l_uintptr_t name, \ l_int namelen); } 43 AUE_ACCEPT STD { int linux_accept(l_int s, l_uintptr_t addr, \ l_uintptr_t namelen); } 44 AUE_SENDTO STD { int linux_sendto(l_int s, l_uintptr_t msg, \ l_int len, l_int flags, l_uintptr_t to, \ l_int tolen); } 45 AUE_RECVFROM STD { int linux_recvfrom(l_int s, l_uintptr_t buf, \ l_size_t len, l_int flags, l_uintptr_t from, \ l_uintptr_t fromlen); } 46 AUE_SENDMSG STD { int linux_sendmsg(l_int s, l_uintptr_t msg, \ l_int flags); } 47 AUE_RECVMSG STD { int linux_recvmsg(l_int s, l_uintptr_t msg, \ l_int flags); } 48 AUE_NULL STD { int linux_shutdown(l_int s, l_int how); } 49 AUE_BIND STD { int linux_bind(l_int s, l_uintptr_t name, \ l_int namelen); } 50 AUE_LISTEN STD { int linux_listen(l_int s, l_int backlog); } 51 AUE_GETSOCKNAME STD { int linux_getsockname(l_int s, \ l_uintptr_t addr, l_uintptr_t namelen); } 52 AUE_GETPEERNAME STD { int linux_getpeername(l_int s, \ l_uintptr_t addr, l_uintptr_t namelen); } 53 AUE_SOCKETPAIR STD { int linux_socketpair(l_int domain, \ l_int type, l_int protocol, l_uintptr_t rsv); } 54 AUE_SETSOCKOPT STD { int linux_setsockopt(l_int s, l_int level, \ l_int optname, l_uintptr_t optval, \ l_int optlen); } 55 AUE_GETSOCKOPT STD { int linux_getsockopt(l_int s, l_int level, \ l_int optname, l_uintptr_t optval, \ l_uintptr_t optlen); } 56 AUE_RFORK STD { int linux_clone(l_int flags, void *stack, \ void *parent_tidptr, void * child_tidptr, void *tls ); } 57 AUE_FORK STD { int linux_fork(void); } 58 AUE_VFORK STD { int linux_vfork(void); } 59 AUE_EXECVE STD { int linux_execve(char *path, char **argp, \ char **envp); } 60 AUE_EXIT STD { void linux_exit(int rval); } 61 AUE_WAIT4 STD { int linux_wait4(l_pid_t pid, \ l_int *status, l_int options, \ struct rusage *rusage); } 62 AUE_KILL STD { int linux_kill(l_int pid, l_int signum); } 63 AUE_NULL STD { int linux_newuname( \ struct l_new_utsname *buf); } 64 AUE_NULL STD { int linux_semget(l_key_t key, \ l_int nsems, l_int semflg); } 65 AUE_NULL STD { int linux_semop(l_int semid, \ struct l_sembuf *tsops, l_uint nsops); } 66 AUE_NULL STD { int linux_semctl(l_int semid, \ l_int semnum, l_int cmd, union l_semun arg); } 67 AUE_NULL STD { int linux_shmdt(char *shmaddr); } 68 AUE_NULL STD { int linux_msgget(l_key_t key, l_int msgflg); } 69 AUE_NULL STD { int linux_msgsnd(l_int msqid, \ struct l_msgbuf *msgp, l_size_t msgsz, \ l_int msgflg); } 70 AUE_NULL STD { int linux_msgrcv(l_int msqid, \ struct l_msgbuf *msgp, l_size_t msgsz, \ l_long msgtyp, l_int msgflg); } 71 AUE_NULL STD { int linux_msgctl(l_int msqid, l_int cmd, \ struct l_msqid_ds *buf); } 72 AUE_FCNTL STD { int linux_fcntl(l_uint fd, l_uint cmd, \ l_ulong arg); } 73 AUE_FLOCK NOPROTO { int flock(int fd, int how); } 74 AUE_FSYNC NOPROTO { int fsync(int fd); } 75 AUE_NULL STD { int linux_fdatasync(l_uint fd); } 76 AUE_TRUNCATE STD { int linux_truncate(char *path, \ l_ulong length); } 77 AUE_FTRUNCATE STD { int linux_ftruncate(l_int fd, l_long length); } 78 AUE_GETDIRENTRIES STD { int linux_getdents(l_uint fd, void *dent, \ l_uint count); } 79 AUE_GETCWD STD { int linux_getcwd(char *buf, \ l_ulong bufsize); } 80 AUE_CHDIR STD { int linux_chdir(char *path); } 81 AUE_FCHDIR NOPROTO { int fchdir(int fd); } 82 AUE_RENAME STD { int linux_rename(char *from, char *to); } 83 AUE_MKDIR STD { int linux_mkdir(char *path, l_int mode); } 84 AUE_RMDIR STD { int linux_rmdir(char *path); } 85 AUE_CREAT STD { int linux_creat(char *path, \ l_int mode); } 86 AUE_LINK STD { int linux_link(char *path, char *to); } 87 AUE_UNLINK STD { int linux_unlink(char *path); } 88 AUE_SYMLINK STD { int linux_symlink(char *path, char *to); } 89 AUE_READLINK STD { int linux_readlink(char *name, char *buf, \ l_int count); } 90 AUE_CHMOD STD { int linux_chmod(char *path, \ l_mode_t mode); } 91 AUE_FCHMOD NOPROTO { int fchmod(int fd, int mode); } 92 AUE_LCHOWN STD { int linux_chown(char *path, \ l_uid_t uid, l_gid_t gid); } 93 AUE_FCHOWN NOPROTO { int fchown(int fd, int uid, int gid); } 94 AUE_LCHOWN STD { int linux_lchown(char *path, l_uid_t uid, \ l_gid_t gid); } 95 AUE_UMASK NOPROTO { int umask(int newmask); } 96 AUE_NULL NOPROTO { int gettimeofday(struct l_timeval *tp, \ struct timezone *tzp); } 97 AUE_GETRLIMIT STD { int linux_getrlimit(l_uint resource, \ struct l_rlimit *rlim); } 98 AUE_GETRUSAGE NOPROTO { int getrusage(int who, struct rusage *rusage); } 99 AUE_NULL STD { int linux_sysinfo(struct l_sysinfo *info); } 100 AUE_NULL STD { int linux_times(struct l_times_argv *buf); } 101 AUE_PTRACE STD { int linux_ptrace(l_long req, l_long pid, \ l_long addr, l_long data); } 102 AUE_GETUID STD { int linux_getuid(void); } 103 AUE_NULL STD { int linux_syslog(l_int type, char *buf, \ l_int len); } 104 AUE_GETGID STD { int linux_getgid(void); } 105 AUE_SETUID NOPROTO { int setuid(uid_t uid); } 106 AUE_SETGID NOPROTO { int setgid(gid_t gid); } 107 AUE_GETEUID NOPROTO { int geteuid(void); } 108 AUE_GETEGID NOPROTO { int getegid(void); } 109 AUE_SETPGRP NOPROTO { int setpgid(int pid, int pgid); } 110 AUE_GETPPID STD { int linux_getppid(void); } 111 AUE_GETPGRP NOPROTO { int getpgrp(void); } 112 AUE_SETSID NOPROTO { int setsid(void); } 113 AUE_SETREUID NOPROTO { int setreuid(uid_t ruid, uid_t euid); } 114 AUE_SETREGID NOPROTO { int setregid(gid_t rgid, gid_t egid); } 115 AUE_GETGROUPS STD { int linux_getgroups(l_int gidsetsize, \ l_gid_t *grouplist); } 116 AUE_SETGROUPS STD { int linux_setgroups(l_int gidsetsize, \ l_gid_t *grouplist); } 117 AUE_SETRESUID NOPROTO { int setresuid(uid_t ruid, uid_t euid, \ uid_t suid); } 118 AUE_GETRESUID NOPROTO { int getresuid(uid_t *ruid, uid_t *euid, \ uid_t *suid); } 119 AUE_SETRESGID NOPROTO { int setresgid(gid_t rgid, gid_t egid, \ gid_t sgid); } 120 AUE_GETRESGID NOPROTO { int getresgid(gid_t *rgid, gid_t *egid, \ gid_t *sgid); } 121 AUE_GETPGID NOPROTO { int getpgid(int pid); } 122 AUE_SETFSUID STD { int linux_setfsuid(l_uid_t uid); } 123 AUE_SETFSGID STD { int linux_setfsgid(l_gid_t gid); } 124 AUE_GETSID STD { int linux_getsid(l_pid_t pid); } 125 AUE_CAPGET STD { int linux_capget(struct l_user_cap_header *hdrp, \ struct l_user_cap_data *datap); } 126 AUE_CAPSET STD { int linux_capset(struct l_user_cap_header *hdrp, \ struct l_user_cap_data *datap); } 127 AUE_NULL STD { int linux_rt_sigpending(l_sigset_t *set, \ l_size_t sigsetsize); } 128 AUE_NULL STD { int linux_rt_sigtimedwait(l_sigset_t *mask, \ l_siginfo_t *ptr, \ struct l_timeval *timeout, \ l_size_t sigsetsize); } 129 AUE_NULL STD { int linux_rt_sigqueueinfo(l_pid_t pid, l_int sig, \ l_siginfo_t *info); } 130 AUE_NULL STD { int linux_rt_sigsuspend( \ l_sigset_t *newset, \ l_size_t sigsetsize); } 131 AUE_NULL STD { int linux_sigaltstack(l_stack_t *uss, \ l_stack_t *uoss); } 132 AUE_UTIME STD { int linux_utime(char *fname, \ struct l_utimbuf *times); } 133 AUE_MKNOD STD { int linux_mknod(char *path, l_int mode, \ l_dev_t dev); } 134 AUE_USELIB UNIMPL uselib 135 AUE_PERSONALITY STD { int linux_personality(l_uint per); } 136 AUE_NULL STD { int linux_ustat(l_dev_t dev, \ struct l_ustat *ubuf); } 137 AUE_STATFS STD { int linux_statfs(char *path, \ struct l_statfs_buf *buf); } 138 AUE_FSTATFS STD { int linux_fstatfs(l_uint fd, \ struct l_statfs_buf *buf); } 139 AUE_NULL STD { int linux_sysfs(l_int option, \ l_ulong arg1, l_ulong arg2); } 140 AUE_GETPRIORITY STD { int linux_getpriority(int which, int who); } 141 AUE_SETPRIORITY NOPROTO { int setpriority(int which, int who, \ int prio); } 142 AUE_SCHED_SETPARAM STD { int linux_sched_setparam(l_pid_t pid, \ struct sched_param *param); } 143 AUE_SCHED_GETPARAM STD { int linux_sched_getparam(l_pid_t pid, \ struct sched_param *param); } 144 AUE_SCHED_SETSCHEDULER STD { int linux_sched_setscheduler( \ l_pid_t pid, l_int policy, \ struct sched_param *param); } 145 AUE_SCHED_GETSCHEDULER STD { int linux_sched_getscheduler( \ l_pid_t pid); } 146 AUE_SCHED_GET_PRIORITY_MAX STD { int linux_sched_get_priority_max( \ l_int policy); } 147 AUE_SCHED_GET_PRIORITY_MIN STD { int linux_sched_get_priority_min( \ l_int policy); } 148 AUE_SCHED_RR_GET_INTERVAL STD { int linux_sched_rr_get_interval(l_pid_t pid, \ struct l_timespec *interval); } 149 AUE_MLOCK NOPROTO { int mlock(const void *addr, size_t len); } 150 AUE_MUNLOCK NOPROTO { int munlock(const void *addr, size_t len); } 151 AUE_MLOCKALL NOPROTO { int mlockall(int how); } 152 AUE_MUNLOCKALL NOPROTO { int munlockall(void); } 153 AUE_NULL STD { int linux_vhangup(void); } 154 AUE_NULL UNIMPL modify_ldt 155 AUE_PIVOT_ROOT STD { int linux_pivot_root(void); } 156 AUE_SYSCTL STD { int linux_sysctl( \ struct l___sysctl_args *args); } 157 AUE_PRCTL STD { int linux_prctl(l_int option, l_uintptr_t arg2, \ l_uintptr_t arg3, l_uintptr_t arg4, \ l_uintptr_t arg5); } 158 AUE_PRCTL STD { int linux_arch_prctl(l_int code, l_ulong addr); } 159 AUE_ADJTIME STD { int linux_adjtimex(void); } 160 AUE_SETRLIMIT STD { int linux_setrlimit(l_uint resource, \ struct l_rlimit *rlim); } 161 AUE_CHROOT NOPROTO { int chroot(char *path); } 162 AUE_SYNC NOPROTO { int sync(void); } 163 AUE_ACCT NOPROTO { int acct(char *path); } 164 AUE_SETTIMEOFDAY NOPROTO { int settimeofday(struct l_timeval *tv, struct timezone *tzp); } 165 AUE_MOUNT STD { int linux_mount(char *specialfile, \ char *dir, char *filesystemtype, \ l_ulong rwflag, void *data); } 166 AUE_UMOUNT STD { int linux_umount(char *path, l_int flags); } 167 AUE_SWAPON NOPROTO { int swapon(char *name); } 168 AUE_SWAPOFF STD { int linux_swapoff(void); } 169 AUE_REBOOT STD { int linux_reboot(l_int magic1, \ l_int magic2, l_uint cmd, void *arg); } 170 AUE_SYSCTL STD { int linux_sethostname(char *hostname, \ l_uint len); } 171 AUE_SYSCTL STD { int linux_setdomainname(char *name, \ l_int len); } 172 AUE_NULL STD { int linux_iopl(l_uint level); } 173 AUE_NULL UNIMPL ioperm 174 AUE_NULL STD { int linux_create_module(void); } 175 AUE_NULL STD { int linux_init_module(void); } 176 AUE_NULL STD { int linux_delete_module(void); } 177 AUE_NULL STD { int linux_get_kernel_syms(void); } 178 AUE_NULL STD { int linux_query_module(void); } 179 AUE_QUOTACTL STD { int linux_quotactl(void); } 180 AUE_NULL STD { int linux_nfsservctl(void); } 181 AUE_GETPMSG STD { int linux_getpmsg(void); } 182 AUE_PUTPMSG STD { int linux_putpmsg(void); } 183 AUE_NULL STD { int linux_afs_syscall(void); } 184 AUE_NULL STD { int linux_tuxcall(void); } 185 AUE_NULL STD { int linux_security(void); } 186 AUE_NULL STD { int linux_gettid(void); } 187 AUE_NULL UNIMPL linux_readahead 188 AUE_NULL STD { int linux_setxattr(void); } 189 AUE_NULL STD { int linux_lsetxattr(void); } 190 AUE_NULL STD { int linux_fsetxattr(void); } 191 AUE_NULL STD { int linux_getxattr(void); } 192 AUE_NULL STD { int linux_lgetxattr(void); } 193 AUE_NULL STD { int linux_fgetxattr(void); } 194 AUE_NULL STD { int linux_listxattr(void); } 195 AUE_NULL STD { int linux_llistxattr(void); } 196 AUE_NULL STD { int linux_flistxattr(void); } 197 AUE_NULL STD { int linux_removexattr(void); } 198 AUE_NULL STD { int linux_lremovexattr(void); } 199 AUE_NULL STD { int linux_fremovexattr(void); } 200 AUE_NULL STD { int linux_tkill(int tid, int sig); } 201 AUE_NULL STD { int linux_time(l_time_t *tm); } 202 AUE_NULL STD { int linux_sys_futex(void *uaddr, int op, int val, \ struct l_timespec *timeout, void *uaddr2, int val3); } 203 AUE_NULL STD { int linux_sched_setaffinity(l_pid_t pid, l_uint len, \ l_ulong *user_mask_ptr); } 204 AUE_NULL STD { int linux_sched_getaffinity(l_pid_t pid, l_uint len, \ l_ulong *user_mask_ptr); } 205 AUE_NULL STD { int linux_set_thread_area(void); } 206 AUE_NULL UNIMPL linux_io_setup 207 AUE_NULL UNIMPL linux_io_destroy 208 AUE_NULL UNIMPL linux_io_getevents -209 AUE_NULL UNIMPL inux_io_submit +209 AUE_NULL UNIMPL linux_io_submit 210 AUE_NULL UNIMPL linux_io_cancel 211 AUE_NULL UNIMPL linux_get_thread_area 212 AUE_NULL STD { int linux_lookup_dcookie(void); } 213 AUE_NULL STD { int linux_epoll_create(l_int size); } 214 AUE_NULL STD { int linux_epoll_ctl_old(void); } 215 AUE_NULL STD { int linux_epoll_wait_old(void); } 216 AUE_NULL STD { int linux_remap_file_pages(void); } 217 AUE_GETDIRENTRIES STD { int linux_getdents64(l_uint fd, \ void *dirent, l_uint count); } 218 AUE_NULL STD { int linux_set_tid_address(int *tidptr); } 219 AUE_NULL UNIMPL restart_syscall 220 AUE_NULL STD { int linux_semtimedop(void); } 221 AUE_NULL STD { int linux_fadvise64(int fd, l_loff_t offset, \ l_size_t len, int advice); } 222 AUE_NULL STD { int linux_timer_create(clockid_t clock_id, \ struct sigevent *evp, l_timer_t *timerid); } 223 AUE_NULL STD { int linux_timer_settime(l_timer_t timerid, l_int flags, \ const struct itimerspec *new, struct itimerspec *old); } 224 AUE_NULL STD { int linux_timer_gettime(l_timer_t timerid, struct itimerspec *setting); } 225 AUE_NULL STD { int linux_timer_getoverrun(l_timer_t timerid); } 226 AUE_NULL STD { int linux_timer_delete(l_timer_t timerid); } 227 AUE_CLOCK_SETTIME STD { int linux_clock_settime(clockid_t which, struct l_timespec *tp); } 228 AUE_NULL STD { int linux_clock_gettime(clockid_t which, struct l_timespec *tp); } 229 AUE_NULL STD { int linux_clock_getres(clockid_t which, struct l_timespec *tp); } 230 AUE_NULL STD { int linux_clock_nanosleep(clockid_t which, int flags, \ struct l_timespec *rqtp, struct l_timespec *rmtp); } 231 AUE_EXIT STD { int linux_exit_group(int error_code); } 232 AUE_NULL STD { int linux_epoll_wait(l_int epfd, struct epoll_event *events, \ l_int maxevents, l_int timeout); } 233 AUE_NULL STD { int linux_epoll_ctl(l_int epfd, l_int op, l_int fd, \ struct epoll_event *event); } 234 AUE_NULL STD { int linux_tgkill(int tgid, int pid, int sig); } 235 AUE_UTIMES STD { int linux_utimes(char *fname, \ struct l_timeval *tptr); } 236 AUE_NULL UNIMPL vserver 237 AUE_NULL STD { int linux_mbind(void); } 238 AUE_NULL STD { int linux_set_mempolicy(void); } 239 AUE_NULL STD { int linux_get_mempolicy(void); } 240 AUE_NULL STD { int linux_mq_open(void); } 241 AUE_NULL STD { int linux_mq_unlink(void); } 242 AUE_NULL STD { int linux_mq_timedsend(void); } 243 AUE_NULL STD { int linux_mq_timedreceive(void); } 244 AUE_NULL STD { int linux_mq_notify(void); } 245 AUE_NULL STD { int linux_mq_getsetattr(void); } 246 AUE_NULL STD { int linux_kexec_load(void); } 247 AUE_WAIT6 STD { int linux_waitid(int idtype, l_pid_t id, \ l_siginfo_t *info, int options, \ struct rusage *rusage); } 248 AUE_NULL STD { int linux_add_key(void); } 249 AUE_NULL STD { int linux_request_key(void); } 250 AUE_NULL STD { int linux_keyctl(void); } 251 AUE_NULL STD { int linux_ioprio_set(void); } 252 AUE_NULL STD { int linux_ioprio_get(void); } 253 AUE_NULL STD { int linux_inotify_init(void); } 254 AUE_NULL STD { int linux_inotify_add_watch(void); } 255 AUE_NULL STD { int linux_inotify_rm_watch(void); } 256 AUE_NULL STD { int linux_migrate_pages(void); } 257 AUE_OPEN_RWTC STD { int linux_openat(l_int dfd, const char *filename, \ l_int flags, l_int mode); } 258 AUE_MKDIRAT STD { int linux_mkdirat(l_int dfd, const char *pathname, \ l_int mode); } 259 AUE_MKNODAT STD { int linux_mknodat(l_int dfd, const char *filename, \ l_int mode, l_uint dev); } 260 AUE_FCHOWNAT STD { int linux_fchownat(l_int dfd, const char *filename, \ l_uid_t uid, l_gid_t gid, l_int flag); } 261 AUE_FUTIMESAT STD { int linux_futimesat(l_int dfd, char *filename, \ struct l_timeval *utimes); } 262 AUE_FSTATAT STD { int linux_newfstatat(l_int dfd, char *pathname, \ struct l_stat64 *statbuf, l_int flag); } 263 AUE_UNLINKAT STD { int linux_unlinkat(l_int dfd, const char *pathname, \ l_int flag); } 264 AUE_RENAMEAT STD { int linux_renameat(l_int olddfd, const char *oldname, \ l_int newdfd, const char *newname); } 265 AUE_LINKAT STD { int linux_linkat(l_int olddfd, const char *oldname, \ l_int newdfd, const char *newname, l_int flag); } 266 AUE_SYMLINKAT STD { int linux_symlinkat(const char *oldname, l_int newdfd, \ const char *newname); } 267 AUE_READLINKAT STD { int linux_readlinkat(l_int dfd, const char *path, \ char *buf, l_int bufsiz); } 268 AUE_FCHMODAT STD { int linux_fchmodat(l_int dfd, const char *filename, \ l_mode_t mode); } 269 AUE_FACCESSAT STD { int linux_faccessat(l_int dfd, const char *filename, \ l_int amode); } 270 AUE_SELECT STD { int linux_pselect6(l_int nfds, \ l_fd_set *readfds, l_fd_set *writefds, l_fd_set *exceptfds, \ struct l_timespec *tsp, l_uintptr_t *sig); } 271 AUE_POLL STD { int linux_ppoll(struct pollfd *fds, uint32_t nfds, \ struct l_timespec *tsp, l_sigset_t *sset, l_size_t ssize); } 272 AUE_NULL STD { int linux_unshare(void); } 273 AUE_NULL STD { int linux_set_robust_list(struct linux_robust_list_head *head, \ l_size_t len); } 274 AUE_NULL STD { int linux_get_robust_list(l_int pid, \ struct linux_robust_list_head **head, l_size_t *len); } 275 AUE_NULL STD { int linux_splice(void); } 276 AUE_NULL STD { int linux_tee(void); } 277 AUE_NULL STD { int linux_sync_file_range(void); } 278 AUE_NULL STD { int linux_vmsplice(void); } 279 AUE_NULL STD { int linux_move_pages(void); } 280 AUE_FUTIMESAT STD { int linux_utimensat(l_int dfd, const char *pathname, \ const struct l_timespec *times, l_int flags); } 281 AUE_NULL STD { int linux_epoll_pwait(l_int epfd, struct epoll_event *events, \ l_int maxevents, l_int timeout, l_sigset_t *mask); } 282 AUE_NULL STD { int linux_signalfd(void); } -283 AUE_NULL STD { int linux_timerfd(void); } +283 AUE_NULL STD { int linux_timerfd_create(void); } 284 AUE_NULL STD { int linux_eventfd(l_uint initval); } 285 AUE_NULL STD { int linux_fallocate(l_int fd, l_int mode, \ l_loff_t offset, l_loff_t len); } 286 AUE_NULL STD { int linux_timerfd_settime(void); } 287 AUE_NULL STD { int linux_timerfd_gettime(void); } 288 AUE_ACCEPT STD { int linux_accept4(l_int s, l_uintptr_t addr, \ l_uintptr_t namelen, int flags); } +; linux 2.6.27: 289 AUE_NULL STD { int linux_signalfd4(void); } 290 AUE_NULL STD { int linux_eventfd2(l_uint initval, l_int flags); } 291 AUE_NULL STD { int linux_epoll_create1(l_int flags); } 292 AUE_NULL STD { int linux_dup3(l_int oldfd, \ l_int newfd, l_int flags); } 293 AUE_NULL STD { int linux_pipe2(l_int *pipefds, l_int flags); } -294 AUE_NULL STD { int linux_inotify_init1(void); } -295 AUE_NULL STD { int linux_preadv(void); } -296 AUE_NULL STD { int linux_pwritev(void); } -297 AUE_NULL STD { int linux_rt_tsigqueueinfo(void); } +294 AUE_NULL STD { int linux_inotify_init1(l_int flags); } +; linux 2.6.30: +295 AUE_NULL STD { int linux_preadv(l_ulong fd, \ + struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h); } +296 AUE_NULL STD { int linux_pwritev(l_ulong fd, \ + struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h); } +; linux 2.6.31: +297 AUE_NULL STD { int linux_rt_tgsigqueueinfo(l_pid_t tgid, \ + l_pid_t tid, l_int sig, l_siginfo_t *uinfo); } 298 AUE_NULL STD { int linux_perf_event_open(void); } +; linux 2.6.33: 299 AUE_NULL STD { int linux_recvmmsg(l_int s, \ struct l_mmsghdr *msg, l_uint vlen, \ l_uint flags, struct l_timespec *timeout); } +; linux 2.6.37: 300 AUE_NULL STD { int linux_fanotify_init(void); } 301 AUE_NULL STD { int linux_fanotify_mark(void); } +; linux 2.6.36: 302 AUE_NULL STD { int linux_prlimit64(l_pid_t pid, l_uint resource, \ struct rlimit *new, struct rlimit *old); } +; linux 2.6.39 (glibc 2.14): 303 AUE_NULL STD { int linux_name_to_handle_at(void); } 304 AUE_NULL STD { int linux_open_by_handle_at(void); } 305 AUE_NULL STD { int linux_clock_adjtime(void); } 306 AUE_SYNC STD { int linux_syncfs(l_int fd); } +; linux 3.0 (glibc 2.14): 307 AUE_NULL STD { int linux_sendmmsg(l_int s, \ struct l_mmsghdr *msg, l_uint vlen, \ l_uint flags); } -308 AUE_NULL STD { int linux_setns(void); } -309 AUE_NULL STD { int linux_process_vm_readv(void); } -310 AUE_NULL STD { int linux_process_vm_writev(void); } -311 AUE_NULL STD { int linux_kcmp(void); } -312 AUE_NULL STD { int linux_finit_module(void); } +308 AUE_NULL STD { int linux_setns(l_int fd, l_int nstype); } +; linux 2.6.19 (no glibc wrapper): +309 AUE_NULL STD { int linux_getcpu(l_uint *cpu, l_uint *node, \ + void *cache); } +; linux 3.2 (glibc 2.15): +310 AUE_NULL STD { int linux_process_vm_readv(l_pid_t pid, \ + const struct iovec *lvec, l_ulong liovcnt, \ + const struct iovec *rvec, l_ulong riovcnt, \ + l_ulong flags); } +311 AUE_NULL STD { int linux_process_vm_writev(l_pid_t pid, \ + const struct iovec *lvec, l_ulong liovcnt, \ + const struct iovec *rvec, l_ulong riovcnt, \ + l_ulong flags); } +; linux 3.5 (no glibc wrapper): +312 AUE_NULL STD { int linux_kcmp(l_pid_t pid1, l_pid_t pid2, \ + l_int type, l_ulong idx1, l_ulong idx); } +; linux 3.8 (no glibc wrapper): +313 AUE_NULL STD { int linux_finit_module(l_int fd, \ + const char *uargs, l_int flags); } +; linux 3.14: +314 AUE_NULL STD { int linux_sched_setattr(l_pid_t pid, \ + void *attr, l_uint flags); } +315 AUE_NULL STD { int linux_sched_getattr(l_pid_t pid, \ + void *attr, l_uint size, l_uint flags); } +; linux 3.15: +316 AUE_NULL STD { int linux_renameat2(l_int oldfd, \ + const char *oldname, l_int newfd, \ + const char *newname, unsigned int flags); } +; linux 3.17: +317 AUE_NULL STD { int linux_seccomp(l_uint op, l_uint flags, \ + const char *uargs); } +318 AUE_NULL STD { int linux_getrandom(char *buf, \ + l_size_t count, l_uint flags); } +319 AUE_NULL STD { int linux_memfd_create(const char *uname_ptr, \ + l_uint flags); } +320 AUE_NULL STD { int linux_kexec_file_load(l_int kernel_fd, \ + l_int initrd_fd, l_ulong cmdline_len, \ + const char *cmdline_ptr, l_ulong flags); } +; linux 3.18: +321 AUE_NULL STD { int linux_bpf(l_int cmd, void *attr, \ + l_uint size); } +; linux 3.19: +322 AUE_NULL STD { int linux_execveat(l_int dfd, \ + const char *filename, const char **argv, \ + const char **envp, l_int flags); } +; linux 4.2: +323 AUE_NULL STD { int linux_userfaultfd(l_int flags); } +; linux 4.3: +324 AUE_NULL STD { int linux_membarrier(l_int cmd, l_int flags); } +; linux 4.4: +325 AUE_NULL STD { int linux_mlock2(l_ulong start, l_size_t len, \ + l_int flags); } +; linux 4.5: +326 AUE_NULL STD { int linux_copy_file_range(l_int fd_in, \ + l_loff_t *off_in, l_int fd_out, \ + l_loff_t *off_out, l_size_t len, \ + l_uint flags); } +; linux 4.6: +327 AUE_NULL STD { int linux_preadv2(l_ulong fd, \ + const struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h, l_int flags); } +328 AUE_NULL STD { int linux_pwritev2(l_ulong fd, \ + const struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h, l_int flags); } +; linux 4.8: +329 AUE_NULL STD { int linux_pkey_mprotect(l_ulong start, \ + l_size_t len, l_ulong prot, l_int pkey); } +330 AUE_NULL STD { int linux_pkey_alloc(l_ulong flags, \ + l_ulong init_val); } +331 AUE_NULL STD { int linux_pkey_free(l_int pkey); } + ; please, keep this line at the end. -313 AUE_NULL UNIMPL nosys +332 AUE_NULL UNIMPL nosys Index: projects/ipsec/sys/amd64/linux32/linux32_dummy.c =================================================================== --- projects/ipsec/sys/amd64/linux32/linux32_dummy.c (revision 313312) +++ projects/ipsec/sys/amd64/linux32/linux32_dummy.c (revision 313313) @@ -1,149 +1,182 @@ /*- * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #include #include #include #include #include #include /* DTrace init */ LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); DUMMY(stime); DUMMY(olduname); DUMMY(syslog); DUMMY(uname); DUMMY(vhangup); DUMMY(swapoff); DUMMY(adjtimex); DUMMY(create_module); DUMMY(init_module); DUMMY(delete_module); DUMMY(get_kernel_syms); DUMMY(quotactl); DUMMY(bdflush); DUMMY(sysfs); DUMMY(query_module); DUMMY(nfsservctl); DUMMY(sendfile); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(pivot_root); DUMMY(mincore); DUMMY(ptrace); DUMMY(lookup_dcookie); DUMMY(remap_file_pages); DUMMY(mbind); DUMMY(get_mempolicy); DUMMY(set_mempolicy); DUMMY(mq_open); DUMMY(mq_unlink); DUMMY(mq_timedsend); DUMMY(mq_timedreceive); DUMMY(mq_notify); DUMMY(mq_getsetattr); DUMMY(kexec_load); /* linux 2.6.11: */ DUMMY(add_key); DUMMY(request_key); DUMMY(keyctl); /* linux 2.6.13: */ DUMMY(ioprio_set); DUMMY(ioprio_get); DUMMY(inotify_init); DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); /* linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(unshare); /* linux 2.6.17: */ DUMMY(splice); DUMMY(sync_file_range); DUMMY(tee); DUMMY(vmsplice); /* linux 2.6.18: */ DUMMY(move_pages); /* linux 2.6.19: */ DUMMY(getcpu); /* linux 2.6.22: */ DUMMY(signalfd); DUMMY(timerfd_create); /* linux 2.6.25: */ DUMMY(timerfd_settime); DUMMY(timerfd_gettime); /* linux 2.6.27: */ DUMMY(signalfd4); DUMMY(inotify_init1); /* linux 2.6.30: */ DUMMY(preadv); DUMMY(pwritev); /* linux 2.6.31: */ -DUMMY(rt_tsigqueueinfo); +DUMMY(rt_tgsigqueueinfo); DUMMY(perf_event_open); /* linux 2.6.33: */ DUMMY(fanotify_init); DUMMY(fanotify_mark); -/* later: */ +/* linux 2.6.39: */ DUMMY(name_to_handle_at); DUMMY(open_by_handle_at); DUMMY(clock_adjtime); +/* linux 3.0: */ DUMMY(setns); +/* linux 3.2: */ DUMMY(process_vm_readv); DUMMY(process_vm_writev); +/* linux 3.5: */ +DUMMY(kcmp); +/* linux 3.8: */ +DUMMY(finit_module); +DUMMY(sched_setattr); +DUMMY(sched_getattr); +/* linux 3.14: */ +DUMMY(renameat2); +/* linux 3.15: */ +DUMMY(seccomp); +DUMMY(getrandom); +DUMMY(memfd_create); +/* linux 3.18: */ +DUMMY(bpf); +/* linux 3.19: */ +DUMMY(execveat); +/* linux 4.2: */ +DUMMY(userfaultfd); +/* linux 4.3: */ +DUMMY(membarrier); +/* linux 4.4: */ +DUMMY(mlock2); +/* linux 4.5: */ +DUMMY(copy_file_range); +/* linux 4.6: */ +DUMMY(preadv2); +DUMMY(pwritev2); +/* linux 4.8: */ +DUMMY(pkey_mprotect); +DUMMY(pkey_alloc); +DUMMY(pkey_free); #define DUMMY_XATTR(s) \ int \ linux_ ## s ## xattr( \ struct thread *td, struct linux_ ## s ## xattr_args *arg) \ { \ \ return (ENOATTR); \ } DUMMY_XATTR(set); DUMMY_XATTR(lset); DUMMY_XATTR(fset); DUMMY_XATTR(get); DUMMY_XATTR(lget); DUMMY_XATTR(fget); DUMMY_XATTR(list); DUMMY_XATTR(llist); DUMMY_XATTR(flist); DUMMY_XATTR(remove); DUMMY_XATTR(lremove); DUMMY_XATTR(fremove); Index: projects/ipsec/sys/amd64/linux32/linux32_proto.h =================================================================== --- projects/ipsec/sys/amd64/linux32/linux32_proto.h (revision 313312) +++ projects/ipsec/sys/amd64/linux32/linux32_proto.h (revision 313313) @@ -1,1758 +1,2037 @@ /* * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ #ifndef _LINUX32_SYSPROTO_H_ #define _LINUX32_SYSPROTO_H_ #include #include #include #include #include #include #include #include struct proc; struct thread; #define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \ 0 : sizeof(register_t) - sizeof(t)) #if BYTE_ORDER == LITTLE_ENDIAN #define PADL_(t) 0 #define PADR_(t) PAD_(t) #else #define PADL_(t) PAD_(t) #define PADR_(t) 0 #endif #define nosys linux_nosys struct linux_exit_args { char rval_l_[PADL_(int)]; int rval; char rval_r_[PADR_(int)]; }; struct linux_fork_args { register_t dummy; }; struct linux_open_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_waitpid_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char status_l_[PADL_(l_int *)]; l_int * status; char status_r_[PADR_(l_int *)]; char options_l_[PADL_(l_int)]; l_int options; char options_r_[PADR_(l_int)]; }; struct linux_creat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_link_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; }; struct linux_unlink_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_execve_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char argp_l_[PADL_(uint32_t *)]; uint32_t * argp; char argp_r_[PADR_(uint32_t *)]; char envp_l_[PADL_(uint32_t *)]; uint32_t * envp; char envp_r_[PADR_(uint32_t *)]; }; struct linux_chdir_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_time_args { char tm_l_[PADL_(l_time_t *)]; l_time_t * tm; char tm_r_[PADR_(l_time_t *)]; }; struct linux_mknod_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char dev_l_[PADL_(l_dev_t)]; l_dev_t dev; char dev_r_[PADR_(l_dev_t)]; }; struct linux_chmod_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; }; struct linux_lchown16_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; }; struct linux_stat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char up_l_[PADL_(struct linux_stat *)]; struct linux_stat * up; char up_r_[PADR_(struct linux_stat *)]; }; struct linux_lseek_args { char fdes_l_[PADL_(l_uint)]; l_uint fdes; char fdes_r_[PADR_(l_uint)]; char off_l_[PADL_(l_off_t)]; l_off_t off; char off_r_[PADR_(l_off_t)]; char whence_l_[PADL_(l_int)]; l_int whence; char whence_r_[PADR_(l_int)]; }; struct linux_getpid_args { register_t dummy; }; struct linux_mount_args { char specialfile_l_[PADL_(char *)]; char * specialfile; char specialfile_r_[PADR_(char *)]; char dir_l_[PADL_(char *)]; char * dir; char dir_r_[PADR_(char *)]; char filesystemtype_l_[PADL_(char *)]; char * filesystemtype; char filesystemtype_r_[PADR_(char *)]; char rwflag_l_[PADL_(l_ulong)]; l_ulong rwflag; char rwflag_r_[PADR_(l_ulong)]; char data_l_[PADL_(void *)]; void * data; char data_r_[PADR_(void *)]; }; struct linux_oldumount_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_setuid16_args { char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; }; struct linux_getuid16_args { register_t dummy; }; struct linux_stime_args { register_t dummy; }; struct linux_ptrace_args { char req_l_[PADL_(l_long)]; l_long req; char req_r_[PADR_(l_long)]; char pid_l_[PADL_(l_long)]; l_long pid; char pid_r_[PADR_(l_long)]; char addr_l_[PADL_(l_long)]; l_long addr; char addr_r_[PADR_(l_long)]; char data_l_[PADL_(l_long)]; l_long data; char data_r_[PADR_(l_long)]; }; struct linux_alarm_args { char secs_l_[PADL_(l_uint)]; l_uint secs; char secs_r_[PADR_(l_uint)]; }; struct linux_pause_args { register_t dummy; }; struct linux_utime_args { char fname_l_[PADL_(char *)]; char * fname; char fname_r_[PADR_(char *)]; char times_l_[PADL_(struct l_utimbuf *)]; struct l_utimbuf * times; char times_r_[PADR_(struct l_utimbuf *)]; }; struct linux_access_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; }; struct linux_nice_args { char inc_l_[PADL_(l_int)]; l_int inc; char inc_r_[PADR_(l_int)]; }; struct linux_kill_args { char pid_l_[PADL_(l_int)]; l_int pid; char pid_r_[PADR_(l_int)]; char signum_l_[PADL_(l_int)]; l_int signum; char signum_r_[PADR_(l_int)]; }; struct linux_rename_args { char from_l_[PADL_(char *)]; char * from; char from_r_[PADR_(char *)]; char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; }; struct linux_mkdir_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_rmdir_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_pipe_args { char pipefds_l_[PADL_(l_int *)]; l_int * pipefds; char pipefds_r_[PADR_(l_int *)]; }; struct linux_times_args { char buf_l_[PADL_(struct l_times_argv *)]; struct l_times_argv * buf; char buf_r_[PADR_(struct l_times_argv *)]; }; struct linux_brk_args { char dsend_l_[PADL_(l_ulong)]; l_ulong dsend; char dsend_r_[PADR_(l_ulong)]; }; struct linux_setgid16_args { char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; }; struct linux_getgid16_args { register_t dummy; }; struct linux_signal_args { char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char handler_l_[PADL_(l_handler_t)]; l_handler_t handler; char handler_r_[PADR_(l_handler_t)]; }; struct linux_geteuid16_args { register_t dummy; }; struct linux_getegid16_args { register_t dummy; }; struct linux_umount_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_ioctl_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(uintptr_t)]; uintptr_t arg; char arg_r_[PADR_(uintptr_t)]; }; struct linux_fcntl_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(uintptr_t)]; uintptr_t arg; char arg_r_[PADR_(uintptr_t)]; }; struct linux_olduname_args { register_t dummy; }; struct linux_ustat_args { char dev_l_[PADL_(l_dev_t)]; l_dev_t dev; char dev_r_[PADR_(l_dev_t)]; char ubuf_l_[PADL_(struct l_ustat *)]; struct l_ustat * ubuf; char ubuf_r_[PADR_(struct l_ustat *)]; }; struct linux_getppid_args { register_t dummy; }; struct linux_sigaction_args { char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char nsa_l_[PADL_(l_osigaction_t *)]; l_osigaction_t * nsa; char nsa_r_[PADR_(l_osigaction_t *)]; char osa_l_[PADL_(l_osigaction_t *)]; l_osigaction_t * osa; char osa_r_[PADR_(l_osigaction_t *)]; }; struct linux_sgetmask_args { register_t dummy; }; struct linux_ssetmask_args { char mask_l_[PADL_(l_osigset_t)]; l_osigset_t mask; char mask_r_[PADR_(l_osigset_t)]; }; struct linux_setreuid16_args { char ruid_l_[PADL_(l_uid16_t)]; l_uid16_t ruid; char ruid_r_[PADR_(l_uid16_t)]; char euid_l_[PADL_(l_uid16_t)]; l_uid16_t euid; char euid_r_[PADR_(l_uid16_t)]; }; struct linux_setregid16_args { char rgid_l_[PADL_(l_gid16_t)]; l_gid16_t rgid; char rgid_r_[PADR_(l_gid16_t)]; char egid_l_[PADL_(l_gid16_t)]; l_gid16_t egid; char egid_r_[PADR_(l_gid16_t)]; }; struct linux_sigsuspend_args { char hist0_l_[PADL_(l_int)]; l_int hist0; char hist0_r_[PADR_(l_int)]; char hist1_l_[PADL_(l_int)]; l_int hist1; char hist1_r_[PADR_(l_int)]; char mask_l_[PADL_(l_osigset_t)]; l_osigset_t mask; char mask_r_[PADR_(l_osigset_t)]; }; struct linux_sigpending_args { char mask_l_[PADL_(l_osigset_t *)]; l_osigset_t * mask; char mask_r_[PADR_(l_osigset_t *)]; }; struct linux_sethostname_args { char hostname_l_[PADL_(char *)]; char * hostname; char hostname_r_[PADR_(char *)]; char len_l_[PADL_(u_int)]; u_int len; char len_r_[PADR_(u_int)]; }; struct linux_setrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; }; struct linux_old_getrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; }; struct linux_getrusage_args { char who_l_[PADL_(int)]; int who; char who_r_[PADR_(int)]; char rusage_l_[PADL_(struct l_rusage *)]; struct l_rusage * rusage; char rusage_r_[PADR_(struct l_rusage *)]; }; struct linux_gettimeofday_args { char tp_l_[PADL_(struct l_timeval *)]; struct l_timeval * tp; char tp_r_[PADR_(struct l_timeval *)]; char tzp_l_[PADL_(struct timezone *)]; struct timezone * tzp; char tzp_r_[PADR_(struct timezone *)]; }; struct linux_settimeofday_args { char tp_l_[PADL_(struct l_timeval *)]; struct l_timeval * tp; char tp_r_[PADR_(struct l_timeval *)]; char tzp_l_[PADL_(struct timezone *)]; struct timezone * tzp; char tzp_r_[PADR_(struct timezone *)]; }; struct linux_getgroups16_args { char gidsetsize_l_[PADL_(l_uint)]; l_uint gidsetsize; char gidsetsize_r_[PADR_(l_uint)]; char gidset_l_[PADL_(l_gid16_t *)]; l_gid16_t * gidset; char gidset_r_[PADR_(l_gid16_t *)]; }; struct linux_setgroups16_args { char gidsetsize_l_[PADL_(l_uint)]; l_uint gidsetsize; char gidsetsize_r_[PADR_(l_uint)]; char gidset_l_[PADL_(l_gid16_t *)]; l_gid16_t * gidset; char gidset_r_[PADR_(l_gid16_t *)]; }; struct linux_old_select_args { char ptr_l_[PADL_(struct l_old_select_argv *)]; struct l_old_select_argv * ptr; char ptr_r_[PADR_(struct l_old_select_argv *)]; }; struct linux_symlink_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; }; struct linux_lstat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char up_l_[PADL_(struct linux_lstat *)]; struct linux_lstat * up; char up_r_[PADR_(struct linux_lstat *)]; }; struct linux_readlink_args { char name_l_[PADL_(char *)]; char * name; char name_r_[PADR_(char *)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char count_l_[PADL_(l_int)]; l_int count; char count_r_[PADR_(l_int)]; }; struct linux_reboot_args { char magic1_l_[PADL_(l_int)]; l_int magic1; char magic1_r_[PADR_(l_int)]; char magic2_l_[PADL_(l_int)]; l_int magic2; char magic2_r_[PADR_(l_int)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(void *)]; void * arg; char arg_r_[PADR_(void *)]; }; struct linux_readdir_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char dent_l_[PADL_(struct l_dirent *)]; struct l_dirent * dent; char dent_r_[PADR_(struct l_dirent *)]; char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; }; struct linux_mmap_args { char ptr_l_[PADL_(struct l_mmap_argv *)]; struct l_mmap_argv * ptr; char ptr_r_[PADR_(struct l_mmap_argv *)]; }; struct linux_truncate_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char length_l_[PADL_(l_ulong)]; l_ulong length; char length_r_[PADR_(l_ulong)]; }; struct linux_ftruncate_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char length_l_[PADL_(long)]; long length; char length_r_[PADR_(long)]; }; struct linux_getpriority_args { char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)]; char who_l_[PADL_(int)]; int who; char who_r_[PADR_(int)]; }; struct linux_statfs_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; }; struct linux_fstatfs_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; }; struct linux_socketcall_args { char what_l_[PADL_(l_int)]; l_int what; char what_r_[PADR_(l_int)]; char args_l_[PADL_(l_ulong)]; l_ulong args; char args_r_[PADR_(l_ulong)]; }; struct linux_syslog_args { char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; }; struct linux_setitimer_args { char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; char oitv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * oitv; char oitv_r_[PADR_(struct l_itimerval *)]; }; struct linux_getitimer_args { char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; }; struct linux_newstat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; }; struct linux_newlstat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; }; struct linux_newfstat_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; }; struct linux_uname_args { register_t dummy; }; struct linux_iopl_args { char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; }; struct linux_vhangup_args { register_t dummy; }; struct linux_wait4_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char status_l_[PADL_(l_int *)]; l_int * status; char status_r_[PADR_(l_int *)]; char options_l_[PADL_(l_int)]; l_int options; char options_r_[PADR_(l_int)]; char rusage_l_[PADL_(struct l_rusage *)]; struct l_rusage * rusage; char rusage_r_[PADR_(struct l_rusage *)]; }; struct linux_swapoff_args { register_t dummy; }; struct linux_sysinfo_args { char info_l_[PADL_(struct l_sysinfo *)]; struct l_sysinfo * info; char info_r_[PADR_(struct l_sysinfo *)]; }; struct linux_ipc_args { char what_l_[PADL_(l_uint)]; l_uint what; char what_r_[PADR_(l_uint)]; char arg1_l_[PADL_(l_int)]; l_int arg1; char arg1_r_[PADR_(l_int)]; char arg2_l_[PADL_(l_int)]; l_int arg2; char arg2_r_[PADR_(l_int)]; char arg3_l_[PADL_(l_int)]; l_int arg3; char arg3_r_[PADR_(l_int)]; char ptr_l_[PADL_(void *)]; void * ptr; char ptr_r_[PADR_(void *)]; char arg5_l_[PADL_(l_long)]; l_long arg5; char arg5_r_[PADR_(l_long)]; }; struct linux_sigreturn_args { char sfp_l_[PADL_(struct l_sigframe *)]; struct l_sigframe * sfp; char sfp_r_[PADR_(struct l_sigframe *)]; }; struct linux_clone_args { char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char stack_l_[PADL_(void *)]; void * stack; char stack_r_[PADR_(void *)]; char parent_tidptr_l_[PADL_(void *)]; void * parent_tidptr; char parent_tidptr_r_[PADR_(void *)]; char tls_l_[PADL_(void *)]; void * tls; char tls_r_[PADR_(void *)]; char child_tidptr_l_[PADL_(void *)]; void * child_tidptr; char child_tidptr_r_[PADR_(void *)]; }; struct linux_setdomainname_args { char name_l_[PADL_(char *)]; char * name; char name_r_[PADR_(char *)]; char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)]; }; struct linux_newuname_args { char buf_l_[PADL_(struct l_new_utsname *)]; struct l_new_utsname * buf; char buf_r_[PADR_(struct l_new_utsname *)]; }; struct linux_adjtimex_args { register_t dummy; }; struct linux_mprotect_args { char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)]; char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)]; }; struct linux_sigprocmask_args { char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; char mask_l_[PADL_(l_osigset_t *)]; l_osigset_t * mask; char mask_r_[PADR_(l_osigset_t *)]; char omask_l_[PADL_(l_osigset_t *)]; l_osigset_t * omask; char omask_r_[PADR_(l_osigset_t *)]; }; struct linux_create_module_args { register_t dummy; }; struct linux_init_module_args { register_t dummy; }; struct linux_delete_module_args { register_t dummy; }; struct linux_get_kernel_syms_args { register_t dummy; }; struct linux_quotactl_args { register_t dummy; }; struct linux_bdflush_args { register_t dummy; }; struct linux_sysfs_args { char option_l_[PADL_(l_int)]; l_int option; char option_r_[PADR_(l_int)]; char arg1_l_[PADL_(l_ulong)]; l_ulong arg1; char arg1_r_[PADR_(l_ulong)]; char arg2_l_[PADL_(l_ulong)]; l_ulong arg2; char arg2_r_[PADR_(l_ulong)]; }; struct linux_personality_args { char per_l_[PADL_(l_uint)]; l_uint per; char per_r_[PADR_(l_uint)]; }; struct linux_setfsuid16_args { char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; }; struct linux_setfsgid16_args { char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; }; struct linux_llseek_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char ohigh_l_[PADL_(l_ulong)]; l_ulong ohigh; char ohigh_r_[PADR_(l_ulong)]; char olow_l_[PADL_(l_ulong)]; l_ulong olow; char olow_r_[PADR_(l_ulong)]; char res_l_[PADL_(l_loff_t *)]; l_loff_t * res; char res_r_[PADR_(l_loff_t *)]; char whence_l_[PADL_(l_uint)]; l_uint whence; char whence_r_[PADR_(l_uint)]; }; struct linux_getdents_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char dent_l_[PADL_(void *)]; void * dent; char dent_r_[PADR_(void *)]; char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; }; struct linux_select_args { char nfds_l_[PADL_(l_int)]; l_int nfds; char nfds_r_[PADR_(l_int)]; char readfds_l_[PADL_(l_fd_set *)]; l_fd_set * readfds; char readfds_r_[PADR_(l_fd_set *)]; char writefds_l_[PADL_(l_fd_set *)]; l_fd_set * writefds; char writefds_r_[PADR_(l_fd_set *)]; char exceptfds_l_[PADL_(l_fd_set *)]; l_fd_set * exceptfds; char exceptfds_r_[PADR_(l_fd_set *)]; char timeout_l_[PADL_(struct l_timeval *)]; struct l_timeval * timeout; char timeout_r_[PADR_(struct l_timeval *)]; }; struct linux_msync_args { char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char fl_l_[PADL_(l_int)]; l_int fl; char fl_r_[PADR_(l_int)]; }; struct linux_readv_args { char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; char iovp_l_[PADL_(struct l_iovec32 *)]; struct l_iovec32 * iovp; char iovp_r_[PADR_(struct l_iovec32 *)]; char iovcnt_l_[PADL_(l_ulong)]; l_ulong iovcnt; char iovcnt_r_[PADR_(l_ulong)]; }; struct linux_writev_args { char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; char iovp_l_[PADL_(struct l_iovec32 *)]; struct l_iovec32 * iovp; char iovp_r_[PADR_(struct l_iovec32 *)]; char iovcnt_l_[PADL_(l_ulong)]; l_ulong iovcnt; char iovcnt_r_[PADR_(l_ulong)]; }; struct linux_getsid_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; }; struct linux_fdatasync_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; }; struct linux_sysctl_args { char args_l_[PADL_(struct l___sysctl_args *)]; struct l___sysctl_args * args; char args_r_[PADR_(struct l___sysctl_args *)]; }; struct linux_sched_setparam_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; }; struct linux_sched_getparam_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; }; struct linux_sched_setscheduler_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; }; struct linux_sched_getscheduler_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; }; struct linux_sched_get_priority_max_args { char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; }; struct linux_sched_get_priority_min_args { char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; }; struct linux_sched_rr_get_interval_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char interval_l_[PADL_(struct l_timespec *)]; struct l_timespec * interval; char interval_r_[PADR_(struct l_timespec *)]; }; struct linux_nanosleep_args { char rqtp_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * rqtp; char rqtp_r_[PADR_(const struct l_timespec *)]; char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; }; struct linux_mremap_args { char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; char old_len_l_[PADL_(l_ulong)]; l_ulong old_len; char old_len_r_[PADR_(l_ulong)]; char new_len_l_[PADL_(l_ulong)]; l_ulong new_len; char new_len_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; char new_addr_l_[PADL_(l_ulong)]; l_ulong new_addr; char new_addr_r_[PADR_(l_ulong)]; }; struct linux_setresuid16_args { char ruid_l_[PADL_(l_uid16_t)]; l_uid16_t ruid; char ruid_r_[PADR_(l_uid16_t)]; char euid_l_[PADL_(l_uid16_t)]; l_uid16_t euid; char euid_r_[PADR_(l_uid16_t)]; char suid_l_[PADL_(l_uid16_t)]; l_uid16_t suid; char suid_r_[PADR_(l_uid16_t)]; }; struct linux_getresuid16_args { char ruid_l_[PADL_(l_uid16_t *)]; l_uid16_t * ruid; char ruid_r_[PADR_(l_uid16_t *)]; char euid_l_[PADL_(l_uid16_t *)]; l_uid16_t * euid; char euid_r_[PADR_(l_uid16_t *)]; char suid_l_[PADL_(l_uid16_t *)]; l_uid16_t * suid; char suid_r_[PADR_(l_uid16_t *)]; }; struct linux_query_module_args { register_t dummy; }; struct linux_nfsservctl_args { register_t dummy; }; struct linux_setresgid16_args { char rgid_l_[PADL_(l_gid16_t)]; l_gid16_t rgid; char rgid_r_[PADR_(l_gid16_t)]; char egid_l_[PADL_(l_gid16_t)]; l_gid16_t egid; char egid_r_[PADR_(l_gid16_t)]; char sgid_l_[PADL_(l_gid16_t)]; l_gid16_t sgid; char sgid_r_[PADR_(l_gid16_t)]; }; struct linux_getresgid16_args { char rgid_l_[PADL_(l_gid16_t *)]; l_gid16_t * rgid; char rgid_r_[PADR_(l_gid16_t *)]; char egid_l_[PADL_(l_gid16_t *)]; l_gid16_t * egid; char egid_r_[PADR_(l_gid16_t *)]; char sgid_l_[PADL_(l_gid16_t *)]; l_gid16_t * sgid; char sgid_r_[PADR_(l_gid16_t *)]; }; struct linux_prctl_args { char option_l_[PADL_(l_int)]; l_int option; char option_r_[PADR_(l_int)]; char arg2_l_[PADL_(l_int)]; l_int arg2; char arg2_r_[PADR_(l_int)]; char arg3_l_[PADL_(l_int)]; l_int arg3; char arg3_r_[PADR_(l_int)]; char arg4_l_[PADL_(l_int)]; l_int arg4; char arg4_r_[PADR_(l_int)]; char arg5_l_[PADL_(l_int)]; l_int arg5; char arg5_r_[PADR_(l_int)]; }; struct linux_rt_sigreturn_args { char ucp_l_[PADL_(struct l_ucontext *)]; struct l_ucontext * ucp; char ucp_r_[PADR_(struct l_ucontext *)]; }; struct linux_rt_sigaction_args { char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char act_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * act; char act_r_[PADR_(l_sigaction_t *)]; char oact_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * oact; char oact_r_[PADR_(l_sigaction_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigprocmask_args { char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; char omask_l_[PADL_(l_sigset_t *)]; l_sigset_t * omask; char omask_r_[PADR_(l_sigset_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigpending_args { char set_l_[PADL_(l_sigset_t *)]; l_sigset_t * set; char set_r_[PADR_(l_sigset_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigtimedwait_args { char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; char ptr_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * ptr; char ptr_r_[PADR_(l_siginfo_t *)]; char timeout_l_[PADL_(struct l_timeval *)]; struct l_timeval * timeout; char timeout_r_[PADR_(struct l_timeval *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigqueueinfo_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; }; struct linux_rt_sigsuspend_args { char newset_l_[PADL_(l_sigset_t *)]; l_sigset_t * newset; char newset_r_[PADR_(l_sigset_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_pread_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; }; struct linux_pwrite_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; }; struct linux_chown16_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; }; struct linux_getcwd_args { char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)]; }; struct linux_capget_args { char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; }; struct linux_capset_args { char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; }; struct linux_sigaltstack_args { char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)]; char uoss_l_[PADL_(l_stack_t *)]; l_stack_t * uoss; char uoss_r_[PADR_(l_stack_t *)]; }; struct linux_sendfile_args { register_t dummy; }; struct linux_vfork_args { register_t dummy; }; struct linux_getrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; }; struct linux_mmap2_args { char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; char len_l_[PADL_(l_ulong)]; l_ulong len; char len_r_[PADR_(l_ulong)]; char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; char pgoff_l_[PADL_(l_ulong)]; l_ulong pgoff; char pgoff_r_[PADR_(l_ulong)]; }; struct linux_truncate64_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char length_l_[PADL_(l_loff_t)]; l_loff_t length; char length_r_[PADR_(l_loff_t)]; }; struct linux_ftruncate64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char length_l_[PADL_(l_loff_t)]; l_loff_t length; char length_r_[PADR_(l_loff_t)]; }; struct linux_stat64_args { char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; }; struct linux_lstat64_args { char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; }; struct linux_fstat64_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; }; struct linux_lchown_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_getuid_args { register_t dummy; }; struct linux_getgid_args { register_t dummy; }; struct linux_getgroups_args { char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; }; struct linux_setgroups_args { char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; }; struct linux_chown_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_setfsuid_args { char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; }; struct linux_setfsgid_args { char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_pivot_root_args { char new_root_l_[PADL_(char *)]; char * new_root; char new_root_r_[PADR_(char *)]; char put_old_l_[PADL_(char *)]; char * put_old; char put_old_r_[PADR_(char *)]; }; struct linux_mincore_args { char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char vec_l_[PADL_(u_char *)]; u_char * vec; char vec_r_[PADR_(u_char *)]; }; struct linux_getdents64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char dirent_l_[PADL_(void *)]; void * dirent; char dirent_r_[PADR_(void *)]; char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; }; struct linux_fcntl64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(uintptr_t)]; uintptr_t arg; char arg_r_[PADR_(uintptr_t)]; }; struct linux_gettid_args { register_t dummy; }; struct linux_setxattr_args { register_t dummy; }; struct linux_lsetxattr_args { register_t dummy; }; struct linux_fsetxattr_args { register_t dummy; }; struct linux_getxattr_args { register_t dummy; }; struct linux_lgetxattr_args { register_t dummy; }; struct linux_fgetxattr_args { register_t dummy; }; struct linux_listxattr_args { register_t dummy; }; struct linux_llistxattr_args { register_t dummy; }; struct linux_flistxattr_args { register_t dummy; }; struct linux_removexattr_args { register_t dummy; }; struct linux_lremovexattr_args { register_t dummy; }; struct linux_fremovexattr_args { register_t dummy; }; struct linux_tkill_args { char tid_l_[PADL_(int)]; int tid; char tid_r_[PADR_(int)]; char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; struct linux_sys_futex_args { char uaddr_l_[PADL_(void *)]; void * uaddr; char uaddr_r_[PADR_(void *)]; char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)]; char val_l_[PADL_(uint32_t)]; uint32_t val; char val_r_[PADR_(uint32_t)]; char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; char uaddr2_l_[PADL_(uint32_t *)]; uint32_t * uaddr2; char uaddr2_r_[PADR_(uint32_t *)]; char val3_l_[PADL_(uint32_t)]; uint32_t val3; char val3_r_[PADR_(uint32_t)]; }; struct linux_sched_setaffinity_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; }; struct linux_sched_getaffinity_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; }; struct linux_set_thread_area_args { char desc_l_[PADL_(struct l_user_desc *)]; struct l_user_desc * desc; char desc_r_[PADR_(struct l_user_desc *)]; }; struct linux_fadvise64_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char advice_l_[PADL_(int)]; int advice; char advice_r_[PADR_(int)]; }; struct linux_exit_group_args { char error_code_l_[PADL_(int)]; int error_code; char error_code_r_[PADR_(int)]; }; struct linux_lookup_dcookie_args { register_t dummy; }; struct linux_epoll_create_args { char size_l_[PADL_(l_int)]; l_int size; char size_r_[PADR_(l_int)]; }; struct linux_epoll_ctl_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char op_l_[PADL_(l_int)]; l_int op; char op_r_[PADR_(l_int)]; char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char event_l_[PADL_(struct epoll_event *)]; struct epoll_event * event; char event_r_[PADR_(struct epoll_event *)]; }; struct linux_epoll_wait_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; char timeout_l_[PADL_(l_int)]; l_int timeout; char timeout_r_[PADR_(l_int)]; }; struct linux_remap_file_pages_args { register_t dummy; }; struct linux_set_tid_address_args { char tidptr_l_[PADL_(int *)]; int * tidptr; char tidptr_r_[PADR_(int *)]; }; struct linux_timer_create_args { char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)]; char evp_l_[PADL_(struct sigevent *)]; struct sigevent * evp; char evp_r_[PADR_(struct sigevent *)]; char timerid_l_[PADL_(l_timer_t *)]; l_timer_t * timerid; char timerid_r_[PADR_(l_timer_t *)]; }; struct linux_timer_settime_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char new_l_[PADL_(const struct itimerspec *)]; const struct itimerspec * new; char new_r_[PADR_(const struct itimerspec *)]; char old_l_[PADL_(struct itimerspec *)]; struct itimerspec * old; char old_r_[PADR_(struct itimerspec *)]; }; struct linux_timer_gettime_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; char setting_l_[PADL_(struct itimerspec *)]; struct itimerspec * setting; char setting_r_[PADR_(struct itimerspec *)]; }; struct linux_timer_getoverrun_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; }; struct linux_timer_delete_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; }; struct linux_clock_settime_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; }; struct linux_clock_gettime_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; }; struct linux_clock_getres_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; }; struct linux_clock_nanosleep_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; char rqtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rqtp; char rqtp_r_[PADR_(struct l_timespec *)]; char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; }; struct linux_statfs64_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char bufsize_l_[PADL_(size_t)]; size_t bufsize; char bufsize_r_[PADR_(size_t)]; char buf_l_[PADL_(struct l_statfs64_buf *)]; struct l_statfs64_buf * buf; char buf_r_[PADR_(struct l_statfs64_buf *)]; }; struct linux_fstatfs64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char bufsize_l_[PADL_(size_t)]; size_t bufsize; char bufsize_r_[PADR_(size_t)]; char buf_l_[PADL_(struct l_statfs64_buf *)]; struct l_statfs64_buf * buf; char buf_r_[PADR_(struct l_statfs64_buf *)]; }; struct linux_tgkill_args { char tgid_l_[PADL_(int)]; int tgid; char tgid_r_[PADR_(int)]; char pid_l_[PADL_(int)]; int pid; char pid_r_[PADR_(int)]; char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; struct linux_utimes_args { char fname_l_[PADL_(char *)]; char * fname; char fname_r_[PADR_(char *)]; char tptr_l_[PADL_(struct l_timeval *)]; struct l_timeval * tptr; char tptr_r_[PADR_(struct l_timeval *)]; }; struct linux_fadvise64_64_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; char len_l_[PADL_(l_loff_t)]; l_loff_t len; char len_r_[PADR_(l_loff_t)]; char advice_l_[PADL_(int)]; int advice; char advice_r_[PADR_(int)]; }; struct linux_mbind_args { register_t dummy; }; struct linux_get_mempolicy_args { register_t dummy; }; struct linux_set_mempolicy_args { register_t dummy; }; struct linux_mq_open_args { register_t dummy; }; struct linux_mq_unlink_args { register_t dummy; }; struct linux_mq_timedsend_args { register_t dummy; }; struct linux_mq_timedreceive_args { register_t dummy; }; struct linux_mq_notify_args { register_t dummy; }; struct linux_mq_getsetattr_args { register_t dummy; }; struct linux_kexec_load_args { register_t dummy; }; struct linux_waitid_args { char idtype_l_[PADL_(int)]; int idtype; char idtype_r_[PADR_(int)]; char id_l_[PADL_(l_pid_t)]; l_pid_t id; char id_r_[PADR_(l_pid_t)]; char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)]; char rusage_l_[PADL_(struct l_rusage *)]; struct l_rusage * rusage; char rusage_r_[PADR_(struct l_rusage *)]; }; struct linux_add_key_args { register_t dummy; }; struct linux_request_key_args { register_t dummy; }; struct linux_keyctl_args { register_t dummy; }; struct linux_ioprio_set_args { register_t dummy; }; struct linux_ioprio_get_args { register_t dummy; }; struct linux_inotify_init_args { register_t dummy; }; struct linux_inotify_add_watch_args { register_t dummy; }; struct linux_inotify_rm_watch_args { register_t dummy; }; struct linux_migrate_pages_args { register_t dummy; }; struct linux_openat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_mkdirat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_mknodat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char dev_l_[PADL_(l_uint)]; l_uint dev; char dev_r_[PADR_(l_uint)]; }; struct linux_fchownat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_futimesat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)]; char utimes_l_[PADL_(struct l_timeval *)]; struct l_timeval * utimes; char utimes_r_[PADR_(struct l_timeval *)]; }; struct linux_fstatat64_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)]; char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_unlinkat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_renameat_args { char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; }; struct linux_linkat_args { char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_symlinkat_args { char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; }; struct linux_readlinkat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char bufsiz_l_[PADL_(l_int)]; l_int bufsiz; char bufsiz_r_[PADR_(l_int)]; }; struct linux_fchmodat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; }; struct linux_faccessat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; }; struct linux_pselect6_args { char nfds_l_[PADL_(l_int)]; l_int nfds; char nfds_r_[PADR_(l_int)]; char readfds_l_[PADL_(l_fd_set *)]; l_fd_set * readfds; char readfds_r_[PADR_(l_fd_set *)]; char writefds_l_[PADL_(l_fd_set *)]; l_fd_set * writefds; char writefds_r_[PADR_(l_fd_set *)]; char exceptfds_l_[PADL_(l_fd_set *)]; l_fd_set * exceptfds; char exceptfds_r_[PADR_(l_fd_set *)]; char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; char sig_l_[PADL_(l_uintptr_t *)]; l_uintptr_t * sig; char sig_r_[PADR_(l_uintptr_t *)]; }; struct linux_ppoll_args { char fds_l_[PADL_(struct pollfd *)]; struct pollfd * fds; char fds_r_[PADR_(struct pollfd *)]; char nfds_l_[PADL_(uint32_t)]; uint32_t nfds; char nfds_r_[PADR_(uint32_t)]; char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; char sset_l_[PADL_(l_sigset_t *)]; l_sigset_t * sset; char sset_r_[PADR_(l_sigset_t *)]; char ssize_l_[PADL_(l_size_t)]; l_size_t ssize; char ssize_r_[PADR_(l_size_t)]; }; struct linux_unshare_args { register_t dummy; }; struct linux_set_robust_list_args { char head_l_[PADL_(struct linux_robust_list_head *)]; struct linux_robust_list_head * head; char head_r_[PADR_(struct linux_robust_list_head *)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; }; struct linux_get_robust_list_args { char pid_l_[PADL_(l_int)]; l_int pid; char pid_r_[PADR_(l_int)]; char head_l_[PADL_(struct linux_robust_list_head **)]; struct linux_robust_list_head ** head; char head_r_[PADR_(struct linux_robust_list_head **)]; char len_l_[PADL_(l_size_t *)]; l_size_t * len; char len_r_[PADR_(l_size_t *)]; }; struct linux_splice_args { register_t dummy; }; struct linux_sync_file_range_args { register_t dummy; }; struct linux_tee_args { register_t dummy; }; struct linux_vmsplice_args { register_t dummy; }; struct linux_move_pages_args { register_t dummy; }; struct linux_getcpu_args { register_t dummy; }; struct linux_epoll_pwait_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; char timeout_l_[PADL_(l_int)]; l_int timeout; char timeout_r_[PADR_(l_int)]; char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; }; struct linux_utimensat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; char times_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * times; char times_r_[PADR_(const struct l_timespec *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_signalfd_args { register_t dummy; }; struct linux_timerfd_create_args { register_t dummy; }; struct linux_eventfd_args { char initval_l_[PADL_(l_uint)]; l_uint initval; char initval_r_[PADR_(l_uint)]; }; struct linux_fallocate_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; char len_l_[PADL_(l_loff_t)]; l_loff_t len; char len_r_[PADR_(l_loff_t)]; }; struct linux_timerfd_settime_args { register_t dummy; }; struct linux_timerfd_gettime_args { register_t dummy; }; struct linux_signalfd4_args { register_t dummy; }; struct linux_eventfd2_args { char initval_l_[PADL_(l_uint)]; l_uint initval; char initval_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_epoll_create1_args { char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_dup3_args { char oldfd_l_[PADL_(l_int)]; l_int oldfd; char oldfd_r_[PADR_(l_int)]; char newfd_l_[PADL_(l_int)]; l_int newfd; char newfd_r_[PADR_(l_int)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_pipe2_args { char pipefds_l_[PADL_(l_int *)]; l_int * pipefds; char pipefds_r_[PADR_(l_int *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_inotify_init1_args { register_t dummy; }; struct linux_preadv_args { - register_t dummy; + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; }; struct linux_pwritev_args { - register_t dummy; + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; }; -struct linux_rt_tsigqueueinfo_args { - register_t dummy; +struct linux_rt_tgsigqueueinfo_args { + char tgid_l_[PADL_(l_pid_t)]; l_pid_t tgid; char tgid_r_[PADR_(l_pid_t)]; + char tid_l_[PADL_(l_pid_t)]; l_pid_t tid; char tid_r_[PADR_(l_pid_t)]; + char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; + char uinfo_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * uinfo; char uinfo_r_[PADR_(l_siginfo_t *)]; }; struct linux_perf_event_open_args { register_t dummy; }; struct linux_recvmmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; }; struct linux_fanotify_init_args { register_t dummy; }; struct linux_fanotify_mark_args { register_t dummy; }; struct linux_prlimit64_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char new_l_[PADL_(struct rlimit *)]; struct rlimit * new; char new_r_[PADR_(struct rlimit *)]; char old_l_[PADL_(struct rlimit *)]; struct rlimit * old; char old_r_[PADR_(struct rlimit *)]; }; struct linux_name_to_handle_at_args { register_t dummy; }; struct linux_open_by_handle_at_args { register_t dummy; }; struct linux_clock_adjtime_args { register_t dummy; }; struct linux_syncfs_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; }; struct linux_sendmmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_setns_args { register_t dummy; }; struct linux_process_vm_readv_args { - register_t dummy; + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; + char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; }; struct linux_process_vm_writev_args { - register_t dummy; + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; + char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; }; +struct linux_kcmp_args { + char pid1_l_[PADL_(l_pid_t)]; l_pid_t pid1; char pid1_r_[PADR_(l_pid_t)]; + char pid2_l_[PADL_(l_pid_t)]; l_pid_t pid2; char pid2_r_[PADR_(l_pid_t)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char idx1_l_[PADL_(l_ulong)]; l_ulong idx1; char idx1_r_[PADR_(l_ulong)]; + char idx_l_[PADL_(l_ulong)]; l_ulong idx; char idx_r_[PADR_(l_ulong)]; +}; +struct linux_finit_module_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_sched_setattr_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_sched_getattr_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_renameat2_args { + char oldfd_l_[PADL_(l_int)]; l_int oldfd; char oldfd_r_[PADR_(l_int)]; + char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char newfd_l_[PADL_(l_int)]; l_int newfd; char newfd_r_[PADR_(l_int)]; + char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; + char flags_l_[PADL_(unsigned int)]; unsigned int flags; char flags_r_[PADR_(unsigned int)]; +}; +struct linux_seccomp_args { + char op_l_[PADL_(l_uint)]; l_uint op; char op_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; + char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; +}; +struct linux_getrandom_args { + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_memfd_create_args { + char uname_ptr_l_[PADL_(const char *)]; const char * uname_ptr; char uname_ptr_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_bpf_args { + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; +}; +struct linux_execveat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char argv_l_[PADL_(const char **)]; const char ** argv; char argv_r_[PADR_(const char **)]; + char envp_l_[PADL_(const char **)]; const char ** envp; char envp_r_[PADR_(const char **)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_socket_args { + char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char protocol_l_[PADL_(l_int)]; l_int protocol; char protocol_r_[PADR_(l_int)]; +}; +struct linux_socketpair_args { + char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char protocol_l_[PADL_(l_int)]; l_int protocol; char protocol_r_[PADR_(l_int)]; + char rsv_l_[PADL_(l_uintptr_t)]; l_uintptr_t rsv; char rsv_r_[PADR_(l_uintptr_t)]; +}; +struct linux_bind_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; +}; +struct linux_connect_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; +}; +struct linux_listen_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char backlog_l_[PADL_(l_int)]; l_int backlog; char backlog_r_[PADR_(l_int)]; +}; +struct linux_accept4_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_getsockopt_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; + char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; + char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; + char optlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t optlen; char optlen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_setsockopt_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; + char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; + char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; + char optlen_l_[PADL_(l_int)]; l_int optlen; char optlen_r_[PADR_(l_int)]; +}; +struct linux_getsockname_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_getpeername_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_sendto_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; + char to_l_[PADL_(l_uintptr_t)]; l_uintptr_t to; char to_r_[PADR_(l_uintptr_t)]; + char tolen_l_[PADL_(l_int)]; l_int tolen; char tolen_r_[PADR_(l_int)]; +}; +struct linux_sendmsg_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_recvfrom_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char buf_l_[PADL_(l_uintptr_t)]; l_uintptr_t buf; char buf_r_[PADR_(l_uintptr_t)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; + char from_l_[PADL_(l_uintptr_t)]; l_uintptr_t from; char from_r_[PADR_(l_uintptr_t)]; + char fromlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t fromlen; char fromlen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_recvmsg_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_shutdown_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; +}; +struct linux_userfaultfd_args { + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_membarrier_args { + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_mlock2_args { + char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_copy_file_range_args { + char fd_in_l_[PADL_(l_int)]; l_int fd_in; char fd_in_r_[PADR_(l_int)]; + char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char fd_out_l_[PADL_(l_int)]; l_int fd_out; char fd_out_r_[PADR_(l_int)]; + char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_preadv2_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_pwritev2_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_pkey_mprotect_args { + char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; + char pkey_l_[PADL_(l_int)]; l_int pkey; char pkey_r_[PADR_(l_int)]; +}; +struct linux_pkey_alloc_args { + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; + char init_val_l_[PADL_(l_ulong)]; l_ulong init_val; char init_val_r_[PADR_(l_ulong)]; +}; +struct linux_pkey_free_args { + char pkey_l_[PADL_(l_int)]; l_int pkey; char pkey_r_[PADR_(l_int)]; +}; #define nosys linux_nosys int linux_exit(struct thread *, struct linux_exit_args *); int linux_fork(struct thread *, struct linux_fork_args *); int linux_open(struct thread *, struct linux_open_args *); int linux_waitpid(struct thread *, struct linux_waitpid_args *); int linux_creat(struct thread *, struct linux_creat_args *); int linux_link(struct thread *, struct linux_link_args *); int linux_unlink(struct thread *, struct linux_unlink_args *); int linux_execve(struct thread *, struct linux_execve_args *); int linux_chdir(struct thread *, struct linux_chdir_args *); int linux_time(struct thread *, struct linux_time_args *); int linux_mknod(struct thread *, struct linux_mknod_args *); int linux_chmod(struct thread *, struct linux_chmod_args *); int linux_lchown16(struct thread *, struct linux_lchown16_args *); int linux_stat(struct thread *, struct linux_stat_args *); int linux_lseek(struct thread *, struct linux_lseek_args *); int linux_getpid(struct thread *, struct linux_getpid_args *); int linux_mount(struct thread *, struct linux_mount_args *); int linux_oldumount(struct thread *, struct linux_oldumount_args *); int linux_setuid16(struct thread *, struct linux_setuid16_args *); int linux_getuid16(struct thread *, struct linux_getuid16_args *); int linux_stime(struct thread *, struct linux_stime_args *); int linux_ptrace(struct thread *, struct linux_ptrace_args *); int linux_alarm(struct thread *, struct linux_alarm_args *); int linux_pause(struct thread *, struct linux_pause_args *); int linux_utime(struct thread *, struct linux_utime_args *); int linux_access(struct thread *, struct linux_access_args *); int linux_nice(struct thread *, struct linux_nice_args *); int linux_kill(struct thread *, struct linux_kill_args *); int linux_rename(struct thread *, struct linux_rename_args *); int linux_mkdir(struct thread *, struct linux_mkdir_args *); int linux_rmdir(struct thread *, struct linux_rmdir_args *); int linux_pipe(struct thread *, struct linux_pipe_args *); int linux_times(struct thread *, struct linux_times_args *); int linux_brk(struct thread *, struct linux_brk_args *); int linux_setgid16(struct thread *, struct linux_setgid16_args *); int linux_getgid16(struct thread *, struct linux_getgid16_args *); int linux_signal(struct thread *, struct linux_signal_args *); int linux_geteuid16(struct thread *, struct linux_geteuid16_args *); int linux_getegid16(struct thread *, struct linux_getegid16_args *); int linux_umount(struct thread *, struct linux_umount_args *); int linux_ioctl(struct thread *, struct linux_ioctl_args *); int linux_fcntl(struct thread *, struct linux_fcntl_args *); int linux_olduname(struct thread *, struct linux_olduname_args *); int linux_ustat(struct thread *, struct linux_ustat_args *); int linux_getppid(struct thread *, struct linux_getppid_args *); int linux_sigaction(struct thread *, struct linux_sigaction_args *); int linux_sgetmask(struct thread *, struct linux_sgetmask_args *); int linux_ssetmask(struct thread *, struct linux_ssetmask_args *); int linux_setreuid16(struct thread *, struct linux_setreuid16_args *); int linux_setregid16(struct thread *, struct linux_setregid16_args *); int linux_sigsuspend(struct thread *, struct linux_sigsuspend_args *); int linux_sigpending(struct thread *, struct linux_sigpending_args *); int linux_sethostname(struct thread *, struct linux_sethostname_args *); int linux_setrlimit(struct thread *, struct linux_setrlimit_args *); int linux_old_getrlimit(struct thread *, struct linux_old_getrlimit_args *); int linux_getrusage(struct thread *, struct linux_getrusage_args *); int linux_gettimeofday(struct thread *, struct linux_gettimeofday_args *); int linux_settimeofday(struct thread *, struct linux_settimeofday_args *); int linux_getgroups16(struct thread *, struct linux_getgroups16_args *); int linux_setgroups16(struct thread *, struct linux_setgroups16_args *); int linux_old_select(struct thread *, struct linux_old_select_args *); int linux_symlink(struct thread *, struct linux_symlink_args *); int linux_lstat(struct thread *, struct linux_lstat_args *); int linux_readlink(struct thread *, struct linux_readlink_args *); int linux_reboot(struct thread *, struct linux_reboot_args *); int linux_readdir(struct thread *, struct linux_readdir_args *); int linux_mmap(struct thread *, struct linux_mmap_args *); int linux_truncate(struct thread *, struct linux_truncate_args *); int linux_ftruncate(struct thread *, struct linux_ftruncate_args *); int linux_getpriority(struct thread *, struct linux_getpriority_args *); int linux_statfs(struct thread *, struct linux_statfs_args *); int linux_fstatfs(struct thread *, struct linux_fstatfs_args *); int linux_socketcall(struct thread *, struct linux_socketcall_args *); int linux_syslog(struct thread *, struct linux_syslog_args *); int linux_setitimer(struct thread *, struct linux_setitimer_args *); int linux_getitimer(struct thread *, struct linux_getitimer_args *); int linux_newstat(struct thread *, struct linux_newstat_args *); int linux_newlstat(struct thread *, struct linux_newlstat_args *); int linux_newfstat(struct thread *, struct linux_newfstat_args *); int linux_uname(struct thread *, struct linux_uname_args *); int linux_iopl(struct thread *, struct linux_iopl_args *); int linux_vhangup(struct thread *, struct linux_vhangup_args *); int linux_wait4(struct thread *, struct linux_wait4_args *); int linux_swapoff(struct thread *, struct linux_swapoff_args *); int linux_sysinfo(struct thread *, struct linux_sysinfo_args *); int linux_ipc(struct thread *, struct linux_ipc_args *); int linux_sigreturn(struct thread *, struct linux_sigreturn_args *); int linux_clone(struct thread *, struct linux_clone_args *); int linux_setdomainname(struct thread *, struct linux_setdomainname_args *); int linux_newuname(struct thread *, struct linux_newuname_args *); int linux_adjtimex(struct thread *, struct linux_adjtimex_args *); int linux_mprotect(struct thread *, struct linux_mprotect_args *); int linux_sigprocmask(struct thread *, struct linux_sigprocmask_args *); int linux_create_module(struct thread *, struct linux_create_module_args *); int linux_init_module(struct thread *, struct linux_init_module_args *); int linux_delete_module(struct thread *, struct linux_delete_module_args *); int linux_get_kernel_syms(struct thread *, struct linux_get_kernel_syms_args *); int linux_quotactl(struct thread *, struct linux_quotactl_args *); int linux_bdflush(struct thread *, struct linux_bdflush_args *); int linux_sysfs(struct thread *, struct linux_sysfs_args *); int linux_personality(struct thread *, struct linux_personality_args *); int linux_setfsuid16(struct thread *, struct linux_setfsuid16_args *); int linux_setfsgid16(struct thread *, struct linux_setfsgid16_args *); int linux_llseek(struct thread *, struct linux_llseek_args *); int linux_getdents(struct thread *, struct linux_getdents_args *); int linux_select(struct thread *, struct linux_select_args *); int linux_msync(struct thread *, struct linux_msync_args *); int linux_readv(struct thread *, struct linux_readv_args *); int linux_writev(struct thread *, struct linux_writev_args *); int linux_getsid(struct thread *, struct linux_getsid_args *); int linux_fdatasync(struct thread *, struct linux_fdatasync_args *); int linux_sysctl(struct thread *, struct linux_sysctl_args *); int linux_sched_setparam(struct thread *, struct linux_sched_setparam_args *); int linux_sched_getparam(struct thread *, struct linux_sched_getparam_args *); int linux_sched_setscheduler(struct thread *, struct linux_sched_setscheduler_args *); int linux_sched_getscheduler(struct thread *, struct linux_sched_getscheduler_args *); int linux_sched_get_priority_max(struct thread *, struct linux_sched_get_priority_max_args *); int linux_sched_get_priority_min(struct thread *, struct linux_sched_get_priority_min_args *); int linux_sched_rr_get_interval(struct thread *, struct linux_sched_rr_get_interval_args *); int linux_nanosleep(struct thread *, struct linux_nanosleep_args *); int linux_mremap(struct thread *, struct linux_mremap_args *); int linux_setresuid16(struct thread *, struct linux_setresuid16_args *); int linux_getresuid16(struct thread *, struct linux_getresuid16_args *); int linux_query_module(struct thread *, struct linux_query_module_args *); int linux_nfsservctl(struct thread *, struct linux_nfsservctl_args *); int linux_setresgid16(struct thread *, struct linux_setresgid16_args *); int linux_getresgid16(struct thread *, struct linux_getresgid16_args *); int linux_prctl(struct thread *, struct linux_prctl_args *); int linux_rt_sigreturn(struct thread *, struct linux_rt_sigreturn_args *); int linux_rt_sigaction(struct thread *, struct linux_rt_sigaction_args *); int linux_rt_sigprocmask(struct thread *, struct linux_rt_sigprocmask_args *); int linux_rt_sigpending(struct thread *, struct linux_rt_sigpending_args *); int linux_rt_sigtimedwait(struct thread *, struct linux_rt_sigtimedwait_args *); int linux_rt_sigqueueinfo(struct thread *, struct linux_rt_sigqueueinfo_args *); int linux_rt_sigsuspend(struct thread *, struct linux_rt_sigsuspend_args *); int linux_pread(struct thread *, struct linux_pread_args *); int linux_pwrite(struct thread *, struct linux_pwrite_args *); int linux_chown16(struct thread *, struct linux_chown16_args *); int linux_getcwd(struct thread *, struct linux_getcwd_args *); int linux_capget(struct thread *, struct linux_capget_args *); int linux_capset(struct thread *, struct linux_capset_args *); int linux_sigaltstack(struct thread *, struct linux_sigaltstack_args *); int linux_sendfile(struct thread *, struct linux_sendfile_args *); int linux_vfork(struct thread *, struct linux_vfork_args *); int linux_getrlimit(struct thread *, struct linux_getrlimit_args *); int linux_mmap2(struct thread *, struct linux_mmap2_args *); int linux_truncate64(struct thread *, struct linux_truncate64_args *); int linux_ftruncate64(struct thread *, struct linux_ftruncate64_args *); int linux_stat64(struct thread *, struct linux_stat64_args *); int linux_lstat64(struct thread *, struct linux_lstat64_args *); int linux_fstat64(struct thread *, struct linux_fstat64_args *); int linux_lchown(struct thread *, struct linux_lchown_args *); int linux_getuid(struct thread *, struct linux_getuid_args *); int linux_getgid(struct thread *, struct linux_getgid_args *); int linux_getgroups(struct thread *, struct linux_getgroups_args *); int linux_setgroups(struct thread *, struct linux_setgroups_args *); int linux_chown(struct thread *, struct linux_chown_args *); int linux_setfsuid(struct thread *, struct linux_setfsuid_args *); int linux_setfsgid(struct thread *, struct linux_setfsgid_args *); int linux_pivot_root(struct thread *, struct linux_pivot_root_args *); int linux_mincore(struct thread *, struct linux_mincore_args *); int linux_getdents64(struct thread *, struct linux_getdents64_args *); int linux_fcntl64(struct thread *, struct linux_fcntl64_args *); int linux_gettid(struct thread *, struct linux_gettid_args *); int linux_setxattr(struct thread *, struct linux_setxattr_args *); int linux_lsetxattr(struct thread *, struct linux_lsetxattr_args *); int linux_fsetxattr(struct thread *, struct linux_fsetxattr_args *); int linux_getxattr(struct thread *, struct linux_getxattr_args *); int linux_lgetxattr(struct thread *, struct linux_lgetxattr_args *); int linux_fgetxattr(struct thread *, struct linux_fgetxattr_args *); int linux_listxattr(struct thread *, struct linux_listxattr_args *); int linux_llistxattr(struct thread *, struct linux_llistxattr_args *); int linux_flistxattr(struct thread *, struct linux_flistxattr_args *); int linux_removexattr(struct thread *, struct linux_removexattr_args *); int linux_lremovexattr(struct thread *, struct linux_lremovexattr_args *); int linux_fremovexattr(struct thread *, struct linux_fremovexattr_args *); int linux_tkill(struct thread *, struct linux_tkill_args *); int linux_sys_futex(struct thread *, struct linux_sys_futex_args *); int linux_sched_setaffinity(struct thread *, struct linux_sched_setaffinity_args *); int linux_sched_getaffinity(struct thread *, struct linux_sched_getaffinity_args *); int linux_set_thread_area(struct thread *, struct linux_set_thread_area_args *); int linux_fadvise64(struct thread *, struct linux_fadvise64_args *); int linux_exit_group(struct thread *, struct linux_exit_group_args *); int linux_lookup_dcookie(struct thread *, struct linux_lookup_dcookie_args *); int linux_epoll_create(struct thread *, struct linux_epoll_create_args *); int linux_epoll_ctl(struct thread *, struct linux_epoll_ctl_args *); int linux_epoll_wait(struct thread *, struct linux_epoll_wait_args *); int linux_remap_file_pages(struct thread *, struct linux_remap_file_pages_args *); int linux_set_tid_address(struct thread *, struct linux_set_tid_address_args *); int linux_timer_create(struct thread *, struct linux_timer_create_args *); int linux_timer_settime(struct thread *, struct linux_timer_settime_args *); int linux_timer_gettime(struct thread *, struct linux_timer_gettime_args *); int linux_timer_getoverrun(struct thread *, struct linux_timer_getoverrun_args *); int linux_timer_delete(struct thread *, struct linux_timer_delete_args *); int linux_clock_settime(struct thread *, struct linux_clock_settime_args *); int linux_clock_gettime(struct thread *, struct linux_clock_gettime_args *); int linux_clock_getres(struct thread *, struct linux_clock_getres_args *); int linux_clock_nanosleep(struct thread *, struct linux_clock_nanosleep_args *); int linux_statfs64(struct thread *, struct linux_statfs64_args *); int linux_fstatfs64(struct thread *, struct linux_fstatfs64_args *); int linux_tgkill(struct thread *, struct linux_tgkill_args *); int linux_utimes(struct thread *, struct linux_utimes_args *); int linux_fadvise64_64(struct thread *, struct linux_fadvise64_64_args *); int linux_mbind(struct thread *, struct linux_mbind_args *); int linux_get_mempolicy(struct thread *, struct linux_get_mempolicy_args *); int linux_set_mempolicy(struct thread *, struct linux_set_mempolicy_args *); int linux_mq_open(struct thread *, struct linux_mq_open_args *); int linux_mq_unlink(struct thread *, struct linux_mq_unlink_args *); int linux_mq_timedsend(struct thread *, struct linux_mq_timedsend_args *); int linux_mq_timedreceive(struct thread *, struct linux_mq_timedreceive_args *); int linux_mq_notify(struct thread *, struct linux_mq_notify_args *); int linux_mq_getsetattr(struct thread *, struct linux_mq_getsetattr_args *); int linux_kexec_load(struct thread *, struct linux_kexec_load_args *); int linux_waitid(struct thread *, struct linux_waitid_args *); int linux_add_key(struct thread *, struct linux_add_key_args *); int linux_request_key(struct thread *, struct linux_request_key_args *); int linux_keyctl(struct thread *, struct linux_keyctl_args *); int linux_ioprio_set(struct thread *, struct linux_ioprio_set_args *); int linux_ioprio_get(struct thread *, struct linux_ioprio_get_args *); int linux_inotify_init(struct thread *, struct linux_inotify_init_args *); int linux_inotify_add_watch(struct thread *, struct linux_inotify_add_watch_args *); int linux_inotify_rm_watch(struct thread *, struct linux_inotify_rm_watch_args *); int linux_migrate_pages(struct thread *, struct linux_migrate_pages_args *); int linux_openat(struct thread *, struct linux_openat_args *); int linux_mkdirat(struct thread *, struct linux_mkdirat_args *); int linux_mknodat(struct thread *, struct linux_mknodat_args *); int linux_fchownat(struct thread *, struct linux_fchownat_args *); int linux_futimesat(struct thread *, struct linux_futimesat_args *); int linux_fstatat64(struct thread *, struct linux_fstatat64_args *); int linux_unlinkat(struct thread *, struct linux_unlinkat_args *); int linux_renameat(struct thread *, struct linux_renameat_args *); int linux_linkat(struct thread *, struct linux_linkat_args *); int linux_symlinkat(struct thread *, struct linux_symlinkat_args *); int linux_readlinkat(struct thread *, struct linux_readlinkat_args *); int linux_fchmodat(struct thread *, struct linux_fchmodat_args *); int linux_faccessat(struct thread *, struct linux_faccessat_args *); int linux_pselect6(struct thread *, struct linux_pselect6_args *); int linux_ppoll(struct thread *, struct linux_ppoll_args *); int linux_unshare(struct thread *, struct linux_unshare_args *); int linux_set_robust_list(struct thread *, struct linux_set_robust_list_args *); int linux_get_robust_list(struct thread *, struct linux_get_robust_list_args *); int linux_splice(struct thread *, struct linux_splice_args *); int linux_sync_file_range(struct thread *, struct linux_sync_file_range_args *); int linux_tee(struct thread *, struct linux_tee_args *); int linux_vmsplice(struct thread *, struct linux_vmsplice_args *); int linux_move_pages(struct thread *, struct linux_move_pages_args *); int linux_getcpu(struct thread *, struct linux_getcpu_args *); int linux_epoll_pwait(struct thread *, struct linux_epoll_pwait_args *); int linux_utimensat(struct thread *, struct linux_utimensat_args *); int linux_signalfd(struct thread *, struct linux_signalfd_args *); int linux_timerfd_create(struct thread *, struct linux_timerfd_create_args *); int linux_eventfd(struct thread *, struct linux_eventfd_args *); int linux_fallocate(struct thread *, struct linux_fallocate_args *); int linux_timerfd_settime(struct thread *, struct linux_timerfd_settime_args *); int linux_timerfd_gettime(struct thread *, struct linux_timerfd_gettime_args *); int linux_signalfd4(struct thread *, struct linux_signalfd4_args *); int linux_eventfd2(struct thread *, struct linux_eventfd2_args *); int linux_epoll_create1(struct thread *, struct linux_epoll_create1_args *); int linux_dup3(struct thread *, struct linux_dup3_args *); int linux_pipe2(struct thread *, struct linux_pipe2_args *); int linux_inotify_init1(struct thread *, struct linux_inotify_init1_args *); int linux_preadv(struct thread *, struct linux_preadv_args *); int linux_pwritev(struct thread *, struct linux_pwritev_args *); -int linux_rt_tsigqueueinfo(struct thread *, struct linux_rt_tsigqueueinfo_args *); +int linux_rt_tgsigqueueinfo(struct thread *, struct linux_rt_tgsigqueueinfo_args *); int linux_perf_event_open(struct thread *, struct linux_perf_event_open_args *); int linux_recvmmsg(struct thread *, struct linux_recvmmsg_args *); int linux_fanotify_init(struct thread *, struct linux_fanotify_init_args *); int linux_fanotify_mark(struct thread *, struct linux_fanotify_mark_args *); int linux_prlimit64(struct thread *, struct linux_prlimit64_args *); int linux_name_to_handle_at(struct thread *, struct linux_name_to_handle_at_args *); int linux_open_by_handle_at(struct thread *, struct linux_open_by_handle_at_args *); int linux_clock_adjtime(struct thread *, struct linux_clock_adjtime_args *); int linux_syncfs(struct thread *, struct linux_syncfs_args *); int linux_sendmmsg(struct thread *, struct linux_sendmmsg_args *); int linux_setns(struct thread *, struct linux_setns_args *); int linux_process_vm_readv(struct thread *, struct linux_process_vm_readv_args *); int linux_process_vm_writev(struct thread *, struct linux_process_vm_writev_args *); +int linux_kcmp(struct thread *, struct linux_kcmp_args *); +int linux_finit_module(struct thread *, struct linux_finit_module_args *); +int linux_sched_setattr(struct thread *, struct linux_sched_setattr_args *); +int linux_sched_getattr(struct thread *, struct linux_sched_getattr_args *); +int linux_renameat2(struct thread *, struct linux_renameat2_args *); +int linux_seccomp(struct thread *, struct linux_seccomp_args *); +int linux_getrandom(struct thread *, struct linux_getrandom_args *); +int linux_memfd_create(struct thread *, struct linux_memfd_create_args *); +int linux_bpf(struct thread *, struct linux_bpf_args *); +int linux_execveat(struct thread *, struct linux_execveat_args *); +int linux_socket(struct thread *, struct linux_socket_args *); +int linux_socketpair(struct thread *, struct linux_socketpair_args *); +int linux_bind(struct thread *, struct linux_bind_args *); +int linux_connect(struct thread *, struct linux_connect_args *); +int linux_listen(struct thread *, struct linux_listen_args *); +int linux_accept4(struct thread *, struct linux_accept4_args *); +int linux_getsockopt(struct thread *, struct linux_getsockopt_args *); +int linux_setsockopt(struct thread *, struct linux_setsockopt_args *); +int linux_getsockname(struct thread *, struct linux_getsockname_args *); +int linux_getpeername(struct thread *, struct linux_getpeername_args *); +int linux_sendto(struct thread *, struct linux_sendto_args *); +int linux_sendmsg(struct thread *, struct linux_sendmsg_args *); +int linux_recvfrom(struct thread *, struct linux_recvfrom_args *); +int linux_recvmsg(struct thread *, struct linux_recvmsg_args *); +int linux_shutdown(struct thread *, struct linux_shutdown_args *); +int linux_userfaultfd(struct thread *, struct linux_userfaultfd_args *); +int linux_membarrier(struct thread *, struct linux_membarrier_args *); +int linux_mlock2(struct thread *, struct linux_mlock2_args *); +int linux_copy_file_range(struct thread *, struct linux_copy_file_range_args *); +int linux_preadv2(struct thread *, struct linux_preadv2_args *); +int linux_pwritev2(struct thread *, struct linux_pwritev2_args *); +int linux_pkey_mprotect(struct thread *, struct linux_pkey_mprotect_args *); +int linux_pkey_alloc(struct thread *, struct linux_pkey_alloc_args *); +int linux_pkey_free(struct thread *, struct linux_pkey_free_args *); #ifdef COMPAT_43 #define nosys linux_nosys #endif /* COMPAT_43 */ #ifdef COMPAT_FREEBSD4 #define nosys linux_nosys #endif /* COMPAT_FREEBSD4 */ #ifdef COMPAT_FREEBSD6 #define nosys linux_nosys #endif /* COMPAT_FREEBSD6 */ #ifdef COMPAT_FREEBSD7 #define nosys linux_nosys #endif /* COMPAT_FREEBSD7 */ #ifdef COMPAT_FREEBSD10 #define nosys linux_nosys #endif /* COMPAT_FREEBSD10 */ #define LINUX32_SYS_AUE_linux_exit AUE_EXIT #define LINUX32_SYS_AUE_linux_fork AUE_FORK #define LINUX32_SYS_AUE_linux_open AUE_OPEN_RWTC #define LINUX32_SYS_AUE_linux_waitpid AUE_WAIT4 #define LINUX32_SYS_AUE_linux_creat AUE_CREAT #define LINUX32_SYS_AUE_linux_link AUE_LINK #define LINUX32_SYS_AUE_linux_unlink AUE_UNLINK #define LINUX32_SYS_AUE_linux_execve AUE_EXECVE #define LINUX32_SYS_AUE_linux_chdir AUE_CHDIR #define LINUX32_SYS_AUE_linux_time AUE_NULL #define LINUX32_SYS_AUE_linux_mknod AUE_MKNOD #define LINUX32_SYS_AUE_linux_chmod AUE_CHMOD #define LINUX32_SYS_AUE_linux_lchown16 AUE_LCHOWN #define LINUX32_SYS_AUE_linux_stat AUE_STAT #define LINUX32_SYS_AUE_linux_lseek AUE_LSEEK #define LINUX32_SYS_AUE_linux_getpid AUE_GETPID #define LINUX32_SYS_AUE_linux_mount AUE_MOUNT #define LINUX32_SYS_AUE_linux_oldumount AUE_UMOUNT #define LINUX32_SYS_AUE_linux_setuid16 AUE_SETUID #define LINUX32_SYS_AUE_linux_getuid16 AUE_GETUID #define LINUX32_SYS_AUE_linux_stime AUE_SETTIMEOFDAY #define LINUX32_SYS_AUE_linux_ptrace AUE_PTRACE #define LINUX32_SYS_AUE_linux_alarm AUE_NULL #define LINUX32_SYS_AUE_linux_pause AUE_NULL #define LINUX32_SYS_AUE_linux_utime AUE_UTIME #define LINUX32_SYS_AUE_linux_access AUE_ACCESS #define LINUX32_SYS_AUE_linux_nice AUE_NICE #define LINUX32_SYS_AUE_linux_kill AUE_KILL #define LINUX32_SYS_AUE_linux_rename AUE_RENAME #define LINUX32_SYS_AUE_linux_mkdir AUE_MKDIR #define LINUX32_SYS_AUE_linux_rmdir AUE_RMDIR #define LINUX32_SYS_AUE_linux_pipe AUE_PIPE #define LINUX32_SYS_AUE_linux_times AUE_NULL #define LINUX32_SYS_AUE_linux_brk AUE_NULL #define LINUX32_SYS_AUE_linux_setgid16 AUE_SETGID #define LINUX32_SYS_AUE_linux_getgid16 AUE_GETGID #define LINUX32_SYS_AUE_linux_signal AUE_NULL #define LINUX32_SYS_AUE_linux_geteuid16 AUE_GETEUID #define LINUX32_SYS_AUE_linux_getegid16 AUE_GETEGID #define LINUX32_SYS_AUE_linux_umount AUE_UMOUNT #define LINUX32_SYS_AUE_linux_ioctl AUE_IOCTL #define LINUX32_SYS_AUE_linux_fcntl AUE_FCNTL #define LINUX32_SYS_AUE_linux_olduname AUE_NULL #define LINUX32_SYS_AUE_linux_ustat AUE_NULL #define LINUX32_SYS_AUE_linux_getppid AUE_GETPPID #define LINUX32_SYS_AUE_linux_sigaction AUE_NULL #define LINUX32_SYS_AUE_linux_sgetmask AUE_NULL #define LINUX32_SYS_AUE_linux_ssetmask AUE_NULL #define LINUX32_SYS_AUE_linux_setreuid16 AUE_SETREUID #define LINUX32_SYS_AUE_linux_setregid16 AUE_SETREGID #define LINUX32_SYS_AUE_linux_sigsuspend AUE_NULL #define LINUX32_SYS_AUE_linux_sigpending AUE_NULL #define LINUX32_SYS_AUE_linux_sethostname AUE_SYSCTL #define LINUX32_SYS_AUE_linux_setrlimit AUE_SETRLIMIT #define LINUX32_SYS_AUE_linux_old_getrlimit AUE_GETRLIMIT #define LINUX32_SYS_AUE_linux_getrusage AUE_GETRUSAGE #define LINUX32_SYS_AUE_linux_gettimeofday AUE_NULL #define LINUX32_SYS_AUE_linux_settimeofday AUE_SETTIMEOFDAY #define LINUX32_SYS_AUE_linux_getgroups16 AUE_GETGROUPS #define LINUX32_SYS_AUE_linux_setgroups16 AUE_SETGROUPS #define LINUX32_SYS_AUE_linux_old_select AUE_SELECT #define LINUX32_SYS_AUE_linux_symlink AUE_SYMLINK #define LINUX32_SYS_AUE_linux_lstat AUE_LSTAT #define LINUX32_SYS_AUE_linux_readlink AUE_READLINK #define LINUX32_SYS_AUE_linux_reboot AUE_REBOOT #define LINUX32_SYS_AUE_linux_readdir AUE_GETDIRENTRIES #define LINUX32_SYS_AUE_linux_mmap AUE_MMAP #define LINUX32_SYS_AUE_linux_truncate AUE_TRUNCATE #define LINUX32_SYS_AUE_linux_ftruncate AUE_FTRUNCATE #define LINUX32_SYS_AUE_linux_getpriority AUE_GETPRIORITY #define LINUX32_SYS_AUE_linux_statfs AUE_STATFS #define LINUX32_SYS_AUE_linux_fstatfs AUE_FSTATFS #define LINUX32_SYS_AUE_linux_socketcall AUE_NULL #define LINUX32_SYS_AUE_linux_syslog AUE_NULL #define LINUX32_SYS_AUE_linux_setitimer AUE_SETITIMER #define LINUX32_SYS_AUE_linux_getitimer AUE_GETITIMER #define LINUX32_SYS_AUE_linux_newstat AUE_STAT #define LINUX32_SYS_AUE_linux_newlstat AUE_LSTAT #define LINUX32_SYS_AUE_linux_newfstat AUE_FSTAT #define LINUX32_SYS_AUE_linux_uname AUE_NULL #define LINUX32_SYS_AUE_linux_iopl AUE_NULL #define LINUX32_SYS_AUE_linux_vhangup AUE_NULL #define LINUX32_SYS_AUE_linux_wait4 AUE_WAIT4 #define LINUX32_SYS_AUE_linux_swapoff AUE_SWAPOFF #define LINUX32_SYS_AUE_linux_sysinfo AUE_NULL #define LINUX32_SYS_AUE_linux_ipc AUE_NULL #define LINUX32_SYS_AUE_linux_sigreturn AUE_SIGRETURN #define LINUX32_SYS_AUE_linux_clone AUE_RFORK #define LINUX32_SYS_AUE_linux_setdomainname AUE_SYSCTL #define LINUX32_SYS_AUE_linux_newuname AUE_NULL #define LINUX32_SYS_AUE_linux_adjtimex AUE_ADJTIME #define LINUX32_SYS_AUE_linux_mprotect AUE_MPROTECT #define LINUX32_SYS_AUE_linux_sigprocmask AUE_SIGPROCMASK #define LINUX32_SYS_AUE_linux_create_module AUE_NULL #define LINUX32_SYS_AUE_linux_init_module AUE_NULL #define LINUX32_SYS_AUE_linux_delete_module AUE_NULL #define LINUX32_SYS_AUE_linux_get_kernel_syms AUE_NULL #define LINUX32_SYS_AUE_linux_quotactl AUE_QUOTACTL #define LINUX32_SYS_AUE_linux_bdflush AUE_BDFLUSH #define LINUX32_SYS_AUE_linux_sysfs AUE_NULL #define LINUX32_SYS_AUE_linux_personality AUE_PERSONALITY #define LINUX32_SYS_AUE_linux_setfsuid16 AUE_SETFSUID #define LINUX32_SYS_AUE_linux_setfsgid16 AUE_SETFSGID #define LINUX32_SYS_AUE_linux_llseek AUE_LSEEK #define LINUX32_SYS_AUE_linux_getdents AUE_GETDIRENTRIES #define LINUX32_SYS_AUE_linux_select AUE_SELECT #define LINUX32_SYS_AUE_linux_msync AUE_MSYNC #define LINUX32_SYS_AUE_linux_readv AUE_READV #define LINUX32_SYS_AUE_linux_writev AUE_WRITEV #define LINUX32_SYS_AUE_linux_getsid AUE_GETSID #define LINUX32_SYS_AUE_linux_fdatasync AUE_NULL #define LINUX32_SYS_AUE_linux_sysctl AUE_SYSCTL #define LINUX32_SYS_AUE_linux_sched_setparam AUE_SCHED_SETPARAM #define LINUX32_SYS_AUE_linux_sched_getparam AUE_SCHED_GETPARAM #define LINUX32_SYS_AUE_linux_sched_setscheduler AUE_SCHED_SETSCHEDULER #define LINUX32_SYS_AUE_linux_sched_getscheduler AUE_SCHED_GETSCHEDULER #define LINUX32_SYS_AUE_linux_sched_get_priority_max AUE_SCHED_GET_PRIORITY_MAX #define LINUX32_SYS_AUE_linux_sched_get_priority_min AUE_SCHED_GET_PRIORITY_MIN #define LINUX32_SYS_AUE_linux_sched_rr_get_interval AUE_SCHED_RR_GET_INTERVAL #define LINUX32_SYS_AUE_linux_nanosleep AUE_NULL #define LINUX32_SYS_AUE_linux_mremap AUE_NULL #define LINUX32_SYS_AUE_linux_setresuid16 AUE_SETRESUID #define LINUX32_SYS_AUE_linux_getresuid16 AUE_GETRESUID #define LINUX32_SYS_AUE_linux_query_module AUE_NULL #define LINUX32_SYS_AUE_linux_nfsservctl AUE_NULL #define LINUX32_SYS_AUE_linux_setresgid16 AUE_SETRESGID #define LINUX32_SYS_AUE_linux_getresgid16 AUE_GETRESGID #define LINUX32_SYS_AUE_linux_prctl AUE_PRCTL #define LINUX32_SYS_AUE_linux_rt_sigreturn AUE_NULL #define LINUX32_SYS_AUE_linux_rt_sigaction AUE_NULL #define LINUX32_SYS_AUE_linux_rt_sigprocmask AUE_NULL #define LINUX32_SYS_AUE_linux_rt_sigpending AUE_NULL #define LINUX32_SYS_AUE_linux_rt_sigtimedwait AUE_NULL #define LINUX32_SYS_AUE_linux_rt_sigqueueinfo AUE_NULL #define LINUX32_SYS_AUE_linux_rt_sigsuspend AUE_NULL #define LINUX32_SYS_AUE_linux_pread AUE_PREAD #define LINUX32_SYS_AUE_linux_pwrite AUE_PWRITE #define LINUX32_SYS_AUE_linux_chown16 AUE_CHOWN #define LINUX32_SYS_AUE_linux_getcwd AUE_GETCWD #define LINUX32_SYS_AUE_linux_capget AUE_CAPGET #define LINUX32_SYS_AUE_linux_capset AUE_CAPSET #define LINUX32_SYS_AUE_linux_sigaltstack AUE_NULL #define LINUX32_SYS_AUE_linux_sendfile AUE_SENDFILE #define LINUX32_SYS_AUE_linux_vfork AUE_VFORK #define LINUX32_SYS_AUE_linux_getrlimit AUE_GETRLIMIT #define LINUX32_SYS_AUE_linux_mmap2 AUE_MMAP #define LINUX32_SYS_AUE_linux_truncate64 AUE_TRUNCATE #define LINUX32_SYS_AUE_linux_ftruncate64 AUE_FTRUNCATE #define LINUX32_SYS_AUE_linux_stat64 AUE_STAT #define LINUX32_SYS_AUE_linux_lstat64 AUE_LSTAT #define LINUX32_SYS_AUE_linux_fstat64 AUE_FSTAT #define LINUX32_SYS_AUE_linux_lchown AUE_LCHOWN #define LINUX32_SYS_AUE_linux_getuid AUE_GETUID #define LINUX32_SYS_AUE_linux_getgid AUE_GETGID #define LINUX32_SYS_AUE_linux_getgroups AUE_GETGROUPS #define LINUX32_SYS_AUE_linux_setgroups AUE_SETGROUPS #define LINUX32_SYS_AUE_linux_chown AUE_CHOWN #define LINUX32_SYS_AUE_linux_setfsuid AUE_SETFSUID #define LINUX32_SYS_AUE_linux_setfsgid AUE_SETFSGID #define LINUX32_SYS_AUE_linux_pivot_root AUE_PIVOT_ROOT #define LINUX32_SYS_AUE_linux_mincore AUE_MINCORE #define LINUX32_SYS_AUE_linux_getdents64 AUE_GETDIRENTRIES #define LINUX32_SYS_AUE_linux_fcntl64 AUE_FCNTL #define LINUX32_SYS_AUE_linux_gettid AUE_NULL #define LINUX32_SYS_AUE_linux_setxattr AUE_NULL #define LINUX32_SYS_AUE_linux_lsetxattr AUE_NULL #define LINUX32_SYS_AUE_linux_fsetxattr AUE_NULL #define LINUX32_SYS_AUE_linux_getxattr AUE_NULL #define LINUX32_SYS_AUE_linux_lgetxattr AUE_NULL #define LINUX32_SYS_AUE_linux_fgetxattr AUE_NULL #define LINUX32_SYS_AUE_linux_listxattr AUE_NULL #define LINUX32_SYS_AUE_linux_llistxattr AUE_NULL #define LINUX32_SYS_AUE_linux_flistxattr AUE_NULL #define LINUX32_SYS_AUE_linux_removexattr AUE_NULL #define LINUX32_SYS_AUE_linux_lremovexattr AUE_NULL #define LINUX32_SYS_AUE_linux_fremovexattr AUE_NULL #define LINUX32_SYS_AUE_linux_tkill AUE_NULL #define LINUX32_SYS_AUE_linux_sys_futex AUE_NULL #define LINUX32_SYS_AUE_linux_sched_setaffinity AUE_NULL #define LINUX32_SYS_AUE_linux_sched_getaffinity AUE_NULL #define LINUX32_SYS_AUE_linux_set_thread_area AUE_NULL #define LINUX32_SYS_AUE_linux_fadvise64 AUE_NULL #define LINUX32_SYS_AUE_linux_exit_group AUE_EXIT #define LINUX32_SYS_AUE_linux_lookup_dcookie AUE_NULL #define LINUX32_SYS_AUE_linux_epoll_create AUE_NULL #define LINUX32_SYS_AUE_linux_epoll_ctl AUE_NULL #define LINUX32_SYS_AUE_linux_epoll_wait AUE_NULL #define LINUX32_SYS_AUE_linux_remap_file_pages AUE_NULL #define LINUX32_SYS_AUE_linux_set_tid_address AUE_NULL #define LINUX32_SYS_AUE_linux_timer_create AUE_NULL #define LINUX32_SYS_AUE_linux_timer_settime AUE_NULL #define LINUX32_SYS_AUE_linux_timer_gettime AUE_NULL #define LINUX32_SYS_AUE_linux_timer_getoverrun AUE_NULL #define LINUX32_SYS_AUE_linux_timer_delete AUE_NULL #define LINUX32_SYS_AUE_linux_clock_settime AUE_CLOCK_SETTIME #define LINUX32_SYS_AUE_linux_clock_gettime AUE_NULL #define LINUX32_SYS_AUE_linux_clock_getres AUE_NULL #define LINUX32_SYS_AUE_linux_clock_nanosleep AUE_NULL #define LINUX32_SYS_AUE_linux_statfs64 AUE_STATFS #define LINUX32_SYS_AUE_linux_fstatfs64 AUE_FSTATFS #define LINUX32_SYS_AUE_linux_tgkill AUE_NULL #define LINUX32_SYS_AUE_linux_utimes AUE_UTIMES #define LINUX32_SYS_AUE_linux_fadvise64_64 AUE_NULL #define LINUX32_SYS_AUE_linux_mbind AUE_NULL #define LINUX32_SYS_AUE_linux_get_mempolicy AUE_NULL #define LINUX32_SYS_AUE_linux_set_mempolicy AUE_NULL #define LINUX32_SYS_AUE_linux_mq_open AUE_NULL #define LINUX32_SYS_AUE_linux_mq_unlink AUE_NULL #define LINUX32_SYS_AUE_linux_mq_timedsend AUE_NULL #define LINUX32_SYS_AUE_linux_mq_timedreceive AUE_NULL #define LINUX32_SYS_AUE_linux_mq_notify AUE_NULL #define LINUX32_SYS_AUE_linux_mq_getsetattr AUE_NULL #define LINUX32_SYS_AUE_linux_kexec_load AUE_NULL #define LINUX32_SYS_AUE_linux_waitid AUE_WAIT6 #define LINUX32_SYS_AUE_linux_add_key AUE_NULL #define LINUX32_SYS_AUE_linux_request_key AUE_NULL #define LINUX32_SYS_AUE_linux_keyctl AUE_NULL #define LINUX32_SYS_AUE_linux_ioprio_set AUE_NULL #define LINUX32_SYS_AUE_linux_ioprio_get AUE_NULL #define LINUX32_SYS_AUE_linux_inotify_init AUE_NULL #define LINUX32_SYS_AUE_linux_inotify_add_watch AUE_NULL #define LINUX32_SYS_AUE_linux_inotify_rm_watch AUE_NULL #define LINUX32_SYS_AUE_linux_migrate_pages AUE_NULL #define LINUX32_SYS_AUE_linux_openat AUE_OPEN_RWTC #define LINUX32_SYS_AUE_linux_mkdirat AUE_MKDIRAT #define LINUX32_SYS_AUE_linux_mknodat AUE_MKNODAT #define LINUX32_SYS_AUE_linux_fchownat AUE_FCHOWNAT #define LINUX32_SYS_AUE_linux_futimesat AUE_FUTIMESAT #define LINUX32_SYS_AUE_linux_fstatat64 AUE_FSTATAT #define LINUX32_SYS_AUE_linux_unlinkat AUE_UNLINKAT #define LINUX32_SYS_AUE_linux_renameat AUE_RENAMEAT #define LINUX32_SYS_AUE_linux_linkat AUE_LINKAT #define LINUX32_SYS_AUE_linux_symlinkat AUE_SYMLINKAT #define LINUX32_SYS_AUE_linux_readlinkat AUE_READLINKAT #define LINUX32_SYS_AUE_linux_fchmodat AUE_FCHMODAT #define LINUX32_SYS_AUE_linux_faccessat AUE_FACCESSAT #define LINUX32_SYS_AUE_linux_pselect6 AUE_SELECT #define LINUX32_SYS_AUE_linux_ppoll AUE_POLL #define LINUX32_SYS_AUE_linux_unshare AUE_NULL #define LINUX32_SYS_AUE_linux_set_robust_list AUE_NULL #define LINUX32_SYS_AUE_linux_get_robust_list AUE_NULL #define LINUX32_SYS_AUE_linux_splice AUE_NULL #define LINUX32_SYS_AUE_linux_sync_file_range AUE_NULL #define LINUX32_SYS_AUE_linux_tee AUE_NULL #define LINUX32_SYS_AUE_linux_vmsplice AUE_NULL #define LINUX32_SYS_AUE_linux_move_pages AUE_NULL #define LINUX32_SYS_AUE_linux_getcpu AUE_NULL #define LINUX32_SYS_AUE_linux_epoll_pwait AUE_NULL #define LINUX32_SYS_AUE_linux_utimensat AUE_FUTIMESAT #define LINUX32_SYS_AUE_linux_signalfd AUE_NULL #define LINUX32_SYS_AUE_linux_timerfd_create AUE_NULL #define LINUX32_SYS_AUE_linux_eventfd AUE_NULL #define LINUX32_SYS_AUE_linux_fallocate AUE_NULL #define LINUX32_SYS_AUE_linux_timerfd_settime AUE_NULL #define LINUX32_SYS_AUE_linux_timerfd_gettime AUE_NULL #define LINUX32_SYS_AUE_linux_signalfd4 AUE_NULL #define LINUX32_SYS_AUE_linux_eventfd2 AUE_NULL #define LINUX32_SYS_AUE_linux_epoll_create1 AUE_NULL #define LINUX32_SYS_AUE_linux_dup3 AUE_NULL #define LINUX32_SYS_AUE_linux_pipe2 AUE_NULL #define LINUX32_SYS_AUE_linux_inotify_init1 AUE_NULL #define LINUX32_SYS_AUE_linux_preadv AUE_NULL #define LINUX32_SYS_AUE_linux_pwritev AUE_NULL -#define LINUX32_SYS_AUE_linux_rt_tsigqueueinfo AUE_NULL +#define LINUX32_SYS_AUE_linux_rt_tgsigqueueinfo AUE_NULL #define LINUX32_SYS_AUE_linux_perf_event_open AUE_NULL #define LINUX32_SYS_AUE_linux_recvmmsg AUE_NULL #define LINUX32_SYS_AUE_linux_fanotify_init AUE_NULL #define LINUX32_SYS_AUE_linux_fanotify_mark AUE_NULL #define LINUX32_SYS_AUE_linux_prlimit64 AUE_NULL #define LINUX32_SYS_AUE_linux_name_to_handle_at AUE_NULL #define LINUX32_SYS_AUE_linux_open_by_handle_at AUE_NULL #define LINUX32_SYS_AUE_linux_clock_adjtime AUE_NULL #define LINUX32_SYS_AUE_linux_syncfs AUE_SYNC #define LINUX32_SYS_AUE_linux_sendmmsg AUE_NULL #define LINUX32_SYS_AUE_linux_setns AUE_NULL #define LINUX32_SYS_AUE_linux_process_vm_readv AUE_NULL #define LINUX32_SYS_AUE_linux_process_vm_writev AUE_NULL +#define LINUX32_SYS_AUE_linux_kcmp AUE_NULL +#define LINUX32_SYS_AUE_linux_finit_module AUE_NULL +#define LINUX32_SYS_AUE_linux_sched_setattr AUE_NULL +#define LINUX32_SYS_AUE_linux_sched_getattr AUE_NULL +#define LINUX32_SYS_AUE_linux_renameat2 AUE_NULL +#define LINUX32_SYS_AUE_linux_seccomp AUE_NULL +#define LINUX32_SYS_AUE_linux_getrandom AUE_NULL +#define LINUX32_SYS_AUE_linux_memfd_create AUE_NULL +#define LINUX32_SYS_AUE_linux_bpf AUE_NULL +#define LINUX32_SYS_AUE_linux_execveat AUE_NULL +#define LINUX32_SYS_AUE_linux_socket AUE_SOCKET +#define LINUX32_SYS_AUE_linux_socketpair AUE_SOCKETPAIR +#define LINUX32_SYS_AUE_linux_bind AUE_BIND +#define LINUX32_SYS_AUE_linux_connect AUE_CONNECT +#define LINUX32_SYS_AUE_linux_listen AUE_LISTEN +#define LINUX32_SYS_AUE_linux_accept4 AUE_ACCEPT +#define LINUX32_SYS_AUE_linux_getsockopt AUE_GETSOCKOPT +#define LINUX32_SYS_AUE_linux_setsockopt AUE_SETSOCKOPT +#define LINUX32_SYS_AUE_linux_getsockname AUE_GETSOCKNAME +#define LINUX32_SYS_AUE_linux_getpeername AUE_GETPEERNAME +#define LINUX32_SYS_AUE_linux_sendto AUE_SENDTO +#define LINUX32_SYS_AUE_linux_sendmsg AUE_SENDMSG +#define LINUX32_SYS_AUE_linux_recvfrom AUE_RECVFROM +#define LINUX32_SYS_AUE_linux_recvmsg AUE_RECVMSG +#define LINUX32_SYS_AUE_linux_shutdown AUE_NULL +#define LINUX32_SYS_AUE_linux_userfaultfd AUE_NULL +#define LINUX32_SYS_AUE_linux_membarrier AUE_NULL +#define LINUX32_SYS_AUE_linux_mlock2 AUE_NULL +#define LINUX32_SYS_AUE_linux_copy_file_range AUE_NULL +#define LINUX32_SYS_AUE_linux_preadv2 AUE_NULL +#define LINUX32_SYS_AUE_linux_pwritev2 AUE_NULL +#define LINUX32_SYS_AUE_linux_pkey_mprotect AUE_NULL +#define LINUX32_SYS_AUE_linux_pkey_alloc AUE_NULL +#define LINUX32_SYS_AUE_linux_pkey_free AUE_NULL #undef PAD_ #undef PADL_ #undef PADR_ #endif /* !_LINUX32_SYSPROTO_H_ */ Index: projects/ipsec/sys/amd64/linux32/linux32_syscall.h =================================================================== --- projects/ipsec/sys/amd64/linux32/linux32_syscall.h (revision 313312) +++ projects/ipsec/sys/amd64/linux32/linux32_syscall.h (revision 313313) @@ -1,324 +1,358 @@ /* * System call numbers. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ #define LINUX32_SYS_linux_exit 1 #define LINUX32_SYS_linux_fork 2 #define LINUX32_SYS_read 3 #define LINUX32_SYS_write 4 #define LINUX32_SYS_linux_open 5 #define LINUX32_SYS_close 6 #define LINUX32_SYS_linux_waitpid 7 #define LINUX32_SYS_linux_creat 8 #define LINUX32_SYS_linux_link 9 #define LINUX32_SYS_linux_unlink 10 #define LINUX32_SYS_linux_execve 11 #define LINUX32_SYS_linux_chdir 12 #define LINUX32_SYS_linux_time 13 #define LINUX32_SYS_linux_mknod 14 #define LINUX32_SYS_linux_chmod 15 #define LINUX32_SYS_linux_lchown16 16 #define LINUX32_SYS_linux_stat 18 #define LINUX32_SYS_linux_lseek 19 #define LINUX32_SYS_linux_getpid 20 #define LINUX32_SYS_linux_mount 21 #define LINUX32_SYS_linux_oldumount 22 #define LINUX32_SYS_linux_setuid16 23 #define LINUX32_SYS_linux_getuid16 24 #define LINUX32_SYS_linux_stime 25 #define LINUX32_SYS_linux_ptrace 26 #define LINUX32_SYS_linux_alarm 27 #define LINUX32_SYS_linux_pause 29 #define LINUX32_SYS_linux_utime 30 #define LINUX32_SYS_linux_access 33 #define LINUX32_SYS_linux_nice 34 #define LINUX32_SYS_sync 36 #define LINUX32_SYS_linux_kill 37 #define LINUX32_SYS_linux_rename 38 #define LINUX32_SYS_linux_mkdir 39 #define LINUX32_SYS_linux_rmdir 40 #define LINUX32_SYS_dup 41 #define LINUX32_SYS_linux_pipe 42 #define LINUX32_SYS_linux_times 43 #define LINUX32_SYS_linux_brk 45 #define LINUX32_SYS_linux_setgid16 46 #define LINUX32_SYS_linux_getgid16 47 #define LINUX32_SYS_linux_signal 48 #define LINUX32_SYS_linux_geteuid16 49 #define LINUX32_SYS_linux_getegid16 50 #define LINUX32_SYS_acct 51 #define LINUX32_SYS_linux_umount 52 #define LINUX32_SYS_linux_ioctl 54 #define LINUX32_SYS_linux_fcntl 55 #define LINUX32_SYS_setpgid 57 #define LINUX32_SYS_linux_olduname 59 #define LINUX32_SYS_umask 60 #define LINUX32_SYS_chroot 61 #define LINUX32_SYS_linux_ustat 62 #define LINUX32_SYS_dup2 63 #define LINUX32_SYS_linux_getppid 64 #define LINUX32_SYS_getpgrp 65 #define LINUX32_SYS_setsid 66 #define LINUX32_SYS_linux_sigaction 67 #define LINUX32_SYS_linux_sgetmask 68 #define LINUX32_SYS_linux_ssetmask 69 #define LINUX32_SYS_linux_setreuid16 70 #define LINUX32_SYS_linux_setregid16 71 #define LINUX32_SYS_linux_sigsuspend 72 #define LINUX32_SYS_linux_sigpending 73 #define LINUX32_SYS_linux_sethostname 74 #define LINUX32_SYS_linux_setrlimit 75 #define LINUX32_SYS_linux_old_getrlimit 76 #define LINUX32_SYS_linux_getrusage 77 #define LINUX32_SYS_linux_gettimeofday 78 #define LINUX32_SYS_linux_settimeofday 79 #define LINUX32_SYS_linux_getgroups16 80 #define LINUX32_SYS_linux_setgroups16 81 #define LINUX32_SYS_linux_old_select 82 #define LINUX32_SYS_linux_symlink 83 #define LINUX32_SYS_linux_lstat 84 #define LINUX32_SYS_linux_readlink 85 #define LINUX32_SYS_swapon 87 #define LINUX32_SYS_linux_reboot 88 #define LINUX32_SYS_linux_readdir 89 #define LINUX32_SYS_linux_mmap 90 #define LINUX32_SYS_munmap 91 #define LINUX32_SYS_linux_truncate 92 #define LINUX32_SYS_linux_ftruncate 93 #define LINUX32_SYS_fchmod 94 #define LINUX32_SYS_fchown 95 #define LINUX32_SYS_linux_getpriority 96 #define LINUX32_SYS_setpriority 97 #define LINUX32_SYS_linux_statfs 99 #define LINUX32_SYS_linux_fstatfs 100 #define LINUX32_SYS_linux_socketcall 102 #define LINUX32_SYS_linux_syslog 103 #define LINUX32_SYS_linux_setitimer 104 #define LINUX32_SYS_linux_getitimer 105 #define LINUX32_SYS_linux_newstat 106 #define LINUX32_SYS_linux_newlstat 107 #define LINUX32_SYS_linux_newfstat 108 #define LINUX32_SYS_linux_uname 109 #define LINUX32_SYS_linux_iopl 110 #define LINUX32_SYS_linux_vhangup 111 #define LINUX32_SYS_linux_wait4 114 #define LINUX32_SYS_linux_swapoff 115 #define LINUX32_SYS_linux_sysinfo 116 #define LINUX32_SYS_linux_ipc 117 #define LINUX32_SYS_fsync 118 #define LINUX32_SYS_linux_sigreturn 119 #define LINUX32_SYS_linux_clone 120 #define LINUX32_SYS_linux_setdomainname 121 #define LINUX32_SYS_linux_newuname 122 #define LINUX32_SYS_linux_adjtimex 124 #define LINUX32_SYS_linux_mprotect 125 #define LINUX32_SYS_linux_sigprocmask 126 #define LINUX32_SYS_linux_create_module 127 #define LINUX32_SYS_linux_init_module 128 #define LINUX32_SYS_linux_delete_module 129 #define LINUX32_SYS_linux_get_kernel_syms 130 #define LINUX32_SYS_linux_quotactl 131 #define LINUX32_SYS_getpgid 132 #define LINUX32_SYS_fchdir 133 #define LINUX32_SYS_linux_bdflush 134 #define LINUX32_SYS_linux_sysfs 135 #define LINUX32_SYS_linux_personality 136 #define LINUX32_SYS_linux_setfsuid16 138 #define LINUX32_SYS_linux_setfsgid16 139 #define LINUX32_SYS_linux_llseek 140 #define LINUX32_SYS_linux_getdents 141 #define LINUX32_SYS_linux_select 142 #define LINUX32_SYS_flock 143 #define LINUX32_SYS_linux_msync 144 #define LINUX32_SYS_linux_readv 145 #define LINUX32_SYS_linux_writev 146 #define LINUX32_SYS_linux_getsid 147 #define LINUX32_SYS_linux_fdatasync 148 #define LINUX32_SYS_linux_sysctl 149 #define LINUX32_SYS_mlock 150 #define LINUX32_SYS_munlock 151 #define LINUX32_SYS_mlockall 152 #define LINUX32_SYS_munlockall 153 #define LINUX32_SYS_linux_sched_setparam 154 #define LINUX32_SYS_linux_sched_getparam 155 #define LINUX32_SYS_linux_sched_setscheduler 156 #define LINUX32_SYS_linux_sched_getscheduler 157 #define LINUX32_SYS_sched_yield 158 #define LINUX32_SYS_linux_sched_get_priority_max 159 #define LINUX32_SYS_linux_sched_get_priority_min 160 #define LINUX32_SYS_linux_sched_rr_get_interval 161 #define LINUX32_SYS_linux_nanosleep 162 #define LINUX32_SYS_linux_mremap 163 #define LINUX32_SYS_linux_setresuid16 164 #define LINUX32_SYS_linux_getresuid16 165 #define LINUX32_SYS_linux_query_module 167 #define LINUX32_SYS_poll 168 #define LINUX32_SYS_linux_nfsservctl 169 #define LINUX32_SYS_linux_setresgid16 170 #define LINUX32_SYS_linux_getresgid16 171 #define LINUX32_SYS_linux_prctl 172 #define LINUX32_SYS_linux_rt_sigreturn 173 #define LINUX32_SYS_linux_rt_sigaction 174 #define LINUX32_SYS_linux_rt_sigprocmask 175 #define LINUX32_SYS_linux_rt_sigpending 176 #define LINUX32_SYS_linux_rt_sigtimedwait 177 #define LINUX32_SYS_linux_rt_sigqueueinfo 178 #define LINUX32_SYS_linux_rt_sigsuspend 179 #define LINUX32_SYS_linux_pread 180 #define LINUX32_SYS_linux_pwrite 181 #define LINUX32_SYS_linux_chown16 182 #define LINUX32_SYS_linux_getcwd 183 #define LINUX32_SYS_linux_capget 184 #define LINUX32_SYS_linux_capset 185 #define LINUX32_SYS_linux_sigaltstack 186 #define LINUX32_SYS_linux_sendfile 187 #define LINUX32_SYS_linux_vfork 190 #define LINUX32_SYS_linux_getrlimit 191 #define LINUX32_SYS_linux_mmap2 192 #define LINUX32_SYS_linux_truncate64 193 #define LINUX32_SYS_linux_ftruncate64 194 #define LINUX32_SYS_linux_stat64 195 #define LINUX32_SYS_linux_lstat64 196 #define LINUX32_SYS_linux_fstat64 197 #define LINUX32_SYS_linux_lchown 198 #define LINUX32_SYS_linux_getuid 199 #define LINUX32_SYS_linux_getgid 200 #define LINUX32_SYS_geteuid 201 #define LINUX32_SYS_getegid 202 #define LINUX32_SYS_setreuid 203 #define LINUX32_SYS_setregid 204 #define LINUX32_SYS_linux_getgroups 205 #define LINUX32_SYS_linux_setgroups 206 #define LINUX32_SYS_setresuid 208 #define LINUX32_SYS_getresuid 209 #define LINUX32_SYS_setresgid 210 #define LINUX32_SYS_getresgid 211 #define LINUX32_SYS_linux_chown 212 #define LINUX32_SYS_setuid 213 #define LINUX32_SYS_setgid 214 #define LINUX32_SYS_linux_setfsuid 215 #define LINUX32_SYS_linux_setfsgid 216 #define LINUX32_SYS_linux_pivot_root 217 #define LINUX32_SYS_linux_mincore 218 #define LINUX32_SYS_madvise 219 #define LINUX32_SYS_linux_getdents64 220 #define LINUX32_SYS_linux_fcntl64 221 #define LINUX32_SYS_linux_gettid 224 #define LINUX32_SYS_linux_setxattr 226 #define LINUX32_SYS_linux_lsetxattr 227 #define LINUX32_SYS_linux_fsetxattr 228 #define LINUX32_SYS_linux_getxattr 229 #define LINUX32_SYS_linux_lgetxattr 230 #define LINUX32_SYS_linux_fgetxattr 231 #define LINUX32_SYS_linux_listxattr 232 #define LINUX32_SYS_linux_llistxattr 233 #define LINUX32_SYS_linux_flistxattr 234 #define LINUX32_SYS_linux_removexattr 235 #define LINUX32_SYS_linux_lremovexattr 236 #define LINUX32_SYS_linux_fremovexattr 237 #define LINUX32_SYS_linux_tkill 238 #define LINUX32_SYS_linux_sys_futex 240 #define LINUX32_SYS_linux_sched_setaffinity 241 #define LINUX32_SYS_linux_sched_getaffinity 242 #define LINUX32_SYS_linux_set_thread_area 243 #define LINUX32_SYS_linux_fadvise64 250 #define LINUX32_SYS_linux_exit_group 252 #define LINUX32_SYS_linux_lookup_dcookie 253 #define LINUX32_SYS_linux_epoll_create 254 #define LINUX32_SYS_linux_epoll_ctl 255 #define LINUX32_SYS_linux_epoll_wait 256 #define LINUX32_SYS_linux_remap_file_pages 257 #define LINUX32_SYS_linux_set_tid_address 258 #define LINUX32_SYS_linux_timer_create 259 #define LINUX32_SYS_linux_timer_settime 260 #define LINUX32_SYS_linux_timer_gettime 261 #define LINUX32_SYS_linux_timer_getoverrun 262 #define LINUX32_SYS_linux_timer_delete 263 #define LINUX32_SYS_linux_clock_settime 264 #define LINUX32_SYS_linux_clock_gettime 265 #define LINUX32_SYS_linux_clock_getres 266 #define LINUX32_SYS_linux_clock_nanosleep 267 #define LINUX32_SYS_linux_statfs64 268 #define LINUX32_SYS_linux_fstatfs64 269 #define LINUX32_SYS_linux_tgkill 270 #define LINUX32_SYS_linux_utimes 271 #define LINUX32_SYS_linux_fadvise64_64 272 #define LINUX32_SYS_linux_mbind 274 #define LINUX32_SYS_linux_get_mempolicy 275 #define LINUX32_SYS_linux_set_mempolicy 276 #define LINUX32_SYS_linux_mq_open 277 #define LINUX32_SYS_linux_mq_unlink 278 #define LINUX32_SYS_linux_mq_timedsend 279 #define LINUX32_SYS_linux_mq_timedreceive 280 #define LINUX32_SYS_linux_mq_notify 281 #define LINUX32_SYS_linux_mq_getsetattr 282 #define LINUX32_SYS_linux_kexec_load 283 #define LINUX32_SYS_linux_waitid 284 #define LINUX32_SYS_linux_add_key 286 #define LINUX32_SYS_linux_request_key 287 #define LINUX32_SYS_linux_keyctl 288 #define LINUX32_SYS_linux_ioprio_set 289 #define LINUX32_SYS_linux_ioprio_get 290 #define LINUX32_SYS_linux_inotify_init 291 #define LINUX32_SYS_linux_inotify_add_watch 292 #define LINUX32_SYS_linux_inotify_rm_watch 293 #define LINUX32_SYS_linux_migrate_pages 294 #define LINUX32_SYS_linux_openat 295 #define LINUX32_SYS_linux_mkdirat 296 #define LINUX32_SYS_linux_mknodat 297 #define LINUX32_SYS_linux_fchownat 298 #define LINUX32_SYS_linux_futimesat 299 #define LINUX32_SYS_linux_fstatat64 300 #define LINUX32_SYS_linux_unlinkat 301 #define LINUX32_SYS_linux_renameat 302 #define LINUX32_SYS_linux_linkat 303 #define LINUX32_SYS_linux_symlinkat 304 #define LINUX32_SYS_linux_readlinkat 305 #define LINUX32_SYS_linux_fchmodat 306 #define LINUX32_SYS_linux_faccessat 307 #define LINUX32_SYS_linux_pselect6 308 #define LINUX32_SYS_linux_ppoll 309 #define LINUX32_SYS_linux_unshare 310 #define LINUX32_SYS_linux_set_robust_list 311 #define LINUX32_SYS_linux_get_robust_list 312 #define LINUX32_SYS_linux_splice 313 #define LINUX32_SYS_linux_sync_file_range 314 #define LINUX32_SYS_linux_tee 315 #define LINUX32_SYS_linux_vmsplice 316 #define LINUX32_SYS_linux_move_pages 317 #define LINUX32_SYS_linux_getcpu 318 #define LINUX32_SYS_linux_epoll_pwait 319 #define LINUX32_SYS_linux_utimensat 320 #define LINUX32_SYS_linux_signalfd 321 #define LINUX32_SYS_linux_timerfd_create 322 #define LINUX32_SYS_linux_eventfd 323 #define LINUX32_SYS_linux_fallocate 324 #define LINUX32_SYS_linux_timerfd_settime 325 #define LINUX32_SYS_linux_timerfd_gettime 326 #define LINUX32_SYS_linux_signalfd4 327 #define LINUX32_SYS_linux_eventfd2 328 #define LINUX32_SYS_linux_epoll_create1 329 #define LINUX32_SYS_linux_dup3 330 #define LINUX32_SYS_linux_pipe2 331 #define LINUX32_SYS_linux_inotify_init1 332 #define LINUX32_SYS_linux_preadv 333 #define LINUX32_SYS_linux_pwritev 334 -#define LINUX32_SYS_linux_rt_tsigqueueinfo 335 +#define LINUX32_SYS_linux_rt_tgsigqueueinfo 335 #define LINUX32_SYS_linux_perf_event_open 336 #define LINUX32_SYS_linux_recvmmsg 337 #define LINUX32_SYS_linux_fanotify_init 338 #define LINUX32_SYS_linux_fanotify_mark 339 #define LINUX32_SYS_linux_prlimit64 340 #define LINUX32_SYS_linux_name_to_handle_at 341 #define LINUX32_SYS_linux_open_by_handle_at 342 #define LINUX32_SYS_linux_clock_adjtime 343 #define LINUX32_SYS_linux_syncfs 344 #define LINUX32_SYS_linux_sendmmsg 345 #define LINUX32_SYS_linux_setns 346 #define LINUX32_SYS_linux_process_vm_readv 347 #define LINUX32_SYS_linux_process_vm_writev 348 -#define LINUX32_SYS_MAXSYSCALL 350 +#define LINUX32_SYS_linux_kcmp 349 +#define LINUX32_SYS_linux_finit_module 350 +#define LINUX32_SYS_linux_sched_setattr 351 +#define LINUX32_SYS_linux_sched_getattr 352 +#define LINUX32_SYS_linux_renameat2 353 +#define LINUX32_SYS_linux_seccomp 354 +#define LINUX32_SYS_linux_getrandom 355 +#define LINUX32_SYS_linux_memfd_create 356 +#define LINUX32_SYS_linux_bpf 357 +#define LINUX32_SYS_linux_execveat 358 +#define LINUX32_SYS_linux_socket 359 +#define LINUX32_SYS_linux_socketpair 360 +#define LINUX32_SYS_linux_bind 361 +#define LINUX32_SYS_linux_connect 362 +#define LINUX32_SYS_linux_listen 363 +#define LINUX32_SYS_linux_accept4 364 +#define LINUX32_SYS_linux_getsockopt 365 +#define LINUX32_SYS_linux_setsockopt 366 +#define LINUX32_SYS_linux_getsockname 367 +#define LINUX32_SYS_linux_getpeername 368 +#define LINUX32_SYS_linux_sendto 369 +#define LINUX32_SYS_linux_sendmsg 370 +#define LINUX32_SYS_linux_recvfrom 371 +#define LINUX32_SYS_linux_recvmsg 372 +#define LINUX32_SYS_linux_shutdown 373 +#define LINUX32_SYS_linux_userfaultfd 374 +#define LINUX32_SYS_linux_membarrier 375 +#define LINUX32_SYS_linux_mlock2 376 +#define LINUX32_SYS_linux_copy_file_range 377 +#define LINUX32_SYS_linux_preadv2 378 +#define LINUX32_SYS_linux_pwritev2 379 +#define LINUX32_SYS_linux_pkey_mprotect 380 +#define LINUX32_SYS_linux_pkey_alloc 381 +#define LINUX32_SYS_linux_pkey_free 382 +#define LINUX32_SYS_MAXSYSCALL 384 Index: projects/ipsec/sys/amd64/linux32/linux32_syscalls.c =================================================================== --- projects/ipsec/sys/amd64/linux32/linux32_syscalls.c (revision 313312) +++ projects/ipsec/sys/amd64/linux32/linux32_syscalls.c (revision 313313) @@ -1,361 +1,395 @@ /* * System call names. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ const char *linux32_syscallnames[] = { #define nosys linux_nosys "#0", /* 0 = setup */ "linux_exit", /* 1 = linux_exit */ "linux_fork", /* 2 = linux_fork */ "read", /* 3 = read */ "write", /* 4 = write */ "linux_open", /* 5 = linux_open */ "close", /* 6 = close */ "linux_waitpid", /* 7 = linux_waitpid */ "linux_creat", /* 8 = linux_creat */ "linux_link", /* 9 = linux_link */ "linux_unlink", /* 10 = linux_unlink */ "linux_execve", /* 11 = linux_execve */ "linux_chdir", /* 12 = linux_chdir */ "linux_time", /* 13 = linux_time */ "linux_mknod", /* 14 = linux_mknod */ "linux_chmod", /* 15 = linux_chmod */ "linux_lchown16", /* 16 = linux_lchown16 */ "#17", /* 17 = break */ "linux_stat", /* 18 = linux_stat */ "linux_lseek", /* 19 = linux_lseek */ "linux_getpid", /* 20 = linux_getpid */ "linux_mount", /* 21 = linux_mount */ "linux_oldumount", /* 22 = linux_oldumount */ "linux_setuid16", /* 23 = linux_setuid16 */ "linux_getuid16", /* 24 = linux_getuid16 */ "linux_stime", /* 25 = linux_stime */ "linux_ptrace", /* 26 = linux_ptrace */ "linux_alarm", /* 27 = linux_alarm */ "#28", /* 28 = fstat */ "linux_pause", /* 29 = linux_pause */ "linux_utime", /* 30 = linux_utime */ "#31", /* 31 = stty */ "#32", /* 32 = gtty */ "linux_access", /* 33 = linux_access */ "linux_nice", /* 34 = linux_nice */ "#35", /* 35 = ftime */ "sync", /* 36 = sync */ "linux_kill", /* 37 = linux_kill */ "linux_rename", /* 38 = linux_rename */ "linux_mkdir", /* 39 = linux_mkdir */ "linux_rmdir", /* 40 = linux_rmdir */ "dup", /* 41 = dup */ "linux_pipe", /* 42 = linux_pipe */ "linux_times", /* 43 = linux_times */ "#44", /* 44 = prof */ "linux_brk", /* 45 = linux_brk */ "linux_setgid16", /* 46 = linux_setgid16 */ "linux_getgid16", /* 47 = linux_getgid16 */ "linux_signal", /* 48 = linux_signal */ "linux_geteuid16", /* 49 = linux_geteuid16 */ "linux_getegid16", /* 50 = linux_getegid16 */ "acct", /* 51 = acct */ "linux_umount", /* 52 = linux_umount */ "#53", /* 53 = lock */ "linux_ioctl", /* 54 = linux_ioctl */ "linux_fcntl", /* 55 = linux_fcntl */ "#56", /* 56 = mpx */ "setpgid", /* 57 = setpgid */ "#58", /* 58 = ulimit */ "linux_olduname", /* 59 = linux_olduname */ "umask", /* 60 = umask */ "chroot", /* 61 = chroot */ "linux_ustat", /* 62 = linux_ustat */ "dup2", /* 63 = dup2 */ "linux_getppid", /* 64 = linux_getppid */ "getpgrp", /* 65 = getpgrp */ "setsid", /* 66 = setsid */ "linux_sigaction", /* 67 = linux_sigaction */ "linux_sgetmask", /* 68 = linux_sgetmask */ "linux_ssetmask", /* 69 = linux_ssetmask */ "linux_setreuid16", /* 70 = linux_setreuid16 */ "linux_setregid16", /* 71 = linux_setregid16 */ "linux_sigsuspend", /* 72 = linux_sigsuspend */ "linux_sigpending", /* 73 = linux_sigpending */ "linux_sethostname", /* 74 = linux_sethostname */ "linux_setrlimit", /* 75 = linux_setrlimit */ "linux_old_getrlimit", /* 76 = linux_old_getrlimit */ "linux_getrusage", /* 77 = linux_getrusage */ "linux_gettimeofday", /* 78 = linux_gettimeofday */ "linux_settimeofday", /* 79 = linux_settimeofday */ "linux_getgroups16", /* 80 = linux_getgroups16 */ "linux_setgroups16", /* 81 = linux_setgroups16 */ "linux_old_select", /* 82 = linux_old_select */ "linux_symlink", /* 83 = linux_symlink */ "linux_lstat", /* 84 = linux_lstat */ "linux_readlink", /* 85 = linux_readlink */ "#86", /* 86 = linux_uselib */ "swapon", /* 87 = swapon */ "linux_reboot", /* 88 = linux_reboot */ "linux_readdir", /* 89 = linux_readdir */ "linux_mmap", /* 90 = linux_mmap */ "munmap", /* 91 = munmap */ "linux_truncate", /* 92 = linux_truncate */ "linux_ftruncate", /* 93 = linux_ftruncate */ "fchmod", /* 94 = fchmod */ "fchown", /* 95 = fchown */ "linux_getpriority", /* 96 = linux_getpriority */ "setpriority", /* 97 = setpriority */ "#98", /* 98 = profil */ "linux_statfs", /* 99 = linux_statfs */ "linux_fstatfs", /* 100 = linux_fstatfs */ "#101", /* 101 = ioperm */ "linux_socketcall", /* 102 = linux_socketcall */ "linux_syslog", /* 103 = linux_syslog */ "linux_setitimer", /* 104 = linux_setitimer */ "linux_getitimer", /* 105 = linux_getitimer */ "linux_newstat", /* 106 = linux_newstat */ "linux_newlstat", /* 107 = linux_newlstat */ "linux_newfstat", /* 108 = linux_newfstat */ "linux_uname", /* 109 = linux_uname */ "linux_iopl", /* 110 = linux_iopl */ "linux_vhangup", /* 111 = linux_vhangup */ "#112", /* 112 = idle */ "#113", /* 113 = vm86old */ "linux_wait4", /* 114 = linux_wait4 */ "linux_swapoff", /* 115 = linux_swapoff */ "linux_sysinfo", /* 116 = linux_sysinfo */ "linux_ipc", /* 117 = linux_ipc */ "fsync", /* 118 = fsync */ "linux_sigreturn", /* 119 = linux_sigreturn */ "linux_clone", /* 120 = linux_clone */ "linux_setdomainname", /* 121 = linux_setdomainname */ "linux_newuname", /* 122 = linux_newuname */ "#123", /* 123 = modify_ldt */ "linux_adjtimex", /* 124 = linux_adjtimex */ "linux_mprotect", /* 125 = linux_mprotect */ "linux_sigprocmask", /* 126 = linux_sigprocmask */ "linux_create_module", /* 127 = linux_create_module */ "linux_init_module", /* 128 = linux_init_module */ "linux_delete_module", /* 129 = linux_delete_module */ "linux_get_kernel_syms", /* 130 = linux_get_kernel_syms */ "linux_quotactl", /* 131 = linux_quotactl */ "getpgid", /* 132 = getpgid */ "fchdir", /* 133 = fchdir */ "linux_bdflush", /* 134 = linux_bdflush */ "linux_sysfs", /* 135 = linux_sysfs */ "linux_personality", /* 136 = linux_personality */ "#137", /* 137 = afs_syscall */ "linux_setfsuid16", /* 138 = linux_setfsuid16 */ "linux_setfsgid16", /* 139 = linux_setfsgid16 */ "linux_llseek", /* 140 = linux_llseek */ "linux_getdents", /* 141 = linux_getdents */ "linux_select", /* 142 = linux_select */ "flock", /* 143 = flock */ "linux_msync", /* 144 = linux_msync */ "linux_readv", /* 145 = linux_readv */ "linux_writev", /* 146 = linux_writev */ "linux_getsid", /* 147 = linux_getsid */ "linux_fdatasync", /* 148 = linux_fdatasync */ "linux_sysctl", /* 149 = linux_sysctl */ "mlock", /* 150 = mlock */ "munlock", /* 151 = munlock */ "mlockall", /* 152 = mlockall */ "munlockall", /* 153 = munlockall */ "linux_sched_setparam", /* 154 = linux_sched_setparam */ "linux_sched_getparam", /* 155 = linux_sched_getparam */ "linux_sched_setscheduler", /* 156 = linux_sched_setscheduler */ "linux_sched_getscheduler", /* 157 = linux_sched_getscheduler */ "sched_yield", /* 158 = sched_yield */ "linux_sched_get_priority_max", /* 159 = linux_sched_get_priority_max */ "linux_sched_get_priority_min", /* 160 = linux_sched_get_priority_min */ "linux_sched_rr_get_interval", /* 161 = linux_sched_rr_get_interval */ "linux_nanosleep", /* 162 = linux_nanosleep */ "linux_mremap", /* 163 = linux_mremap */ "linux_setresuid16", /* 164 = linux_setresuid16 */ "linux_getresuid16", /* 165 = linux_getresuid16 */ "#166", /* 166 = vm86 */ "linux_query_module", /* 167 = linux_query_module */ "poll", /* 168 = poll */ "linux_nfsservctl", /* 169 = linux_nfsservctl */ "linux_setresgid16", /* 170 = linux_setresgid16 */ "linux_getresgid16", /* 171 = linux_getresgid16 */ "linux_prctl", /* 172 = linux_prctl */ "linux_rt_sigreturn", /* 173 = linux_rt_sigreturn */ "linux_rt_sigaction", /* 174 = linux_rt_sigaction */ "linux_rt_sigprocmask", /* 175 = linux_rt_sigprocmask */ "linux_rt_sigpending", /* 176 = linux_rt_sigpending */ "linux_rt_sigtimedwait", /* 177 = linux_rt_sigtimedwait */ "linux_rt_sigqueueinfo", /* 178 = linux_rt_sigqueueinfo */ "linux_rt_sigsuspend", /* 179 = linux_rt_sigsuspend */ "linux_pread", /* 180 = linux_pread */ "linux_pwrite", /* 181 = linux_pwrite */ "linux_chown16", /* 182 = linux_chown16 */ "linux_getcwd", /* 183 = linux_getcwd */ "linux_capget", /* 184 = linux_capget */ "linux_capset", /* 185 = linux_capset */ "linux_sigaltstack", /* 186 = linux_sigaltstack */ "linux_sendfile", /* 187 = linux_sendfile */ "#188", /* 188 = getpmsg */ "#189", /* 189 = putpmsg */ "linux_vfork", /* 190 = linux_vfork */ "linux_getrlimit", /* 191 = linux_getrlimit */ "linux_mmap2", /* 192 = linux_mmap2 */ "linux_truncate64", /* 193 = linux_truncate64 */ "linux_ftruncate64", /* 194 = linux_ftruncate64 */ "linux_stat64", /* 195 = linux_stat64 */ "linux_lstat64", /* 196 = linux_lstat64 */ "linux_fstat64", /* 197 = linux_fstat64 */ "linux_lchown", /* 198 = linux_lchown */ "linux_getuid", /* 199 = linux_getuid */ "linux_getgid", /* 200 = linux_getgid */ "geteuid", /* 201 = geteuid */ "getegid", /* 202 = getegid */ "setreuid", /* 203 = setreuid */ "setregid", /* 204 = setregid */ "linux_getgroups", /* 205 = linux_getgroups */ "linux_setgroups", /* 206 = linux_setgroups */ "fchown", /* 207 = fchown */ "setresuid", /* 208 = setresuid */ "getresuid", /* 209 = getresuid */ "setresgid", /* 210 = setresgid */ "getresgid", /* 211 = getresgid */ "linux_chown", /* 212 = linux_chown */ "setuid", /* 213 = setuid */ "setgid", /* 214 = setgid */ "linux_setfsuid", /* 215 = linux_setfsuid */ "linux_setfsgid", /* 216 = linux_setfsgid */ "linux_pivot_root", /* 217 = linux_pivot_root */ "linux_mincore", /* 218 = linux_mincore */ "madvise", /* 219 = madvise */ "linux_getdents64", /* 220 = linux_getdents64 */ "linux_fcntl64", /* 221 = linux_fcntl64 */ "#222", /* 222 = */ "#223", /* 223 = */ "linux_gettid", /* 224 = linux_gettid */ "#225", /* 225 = linux_readahead */ "linux_setxattr", /* 226 = linux_setxattr */ "linux_lsetxattr", /* 227 = linux_lsetxattr */ "linux_fsetxattr", /* 228 = linux_fsetxattr */ "linux_getxattr", /* 229 = linux_getxattr */ "linux_lgetxattr", /* 230 = linux_lgetxattr */ "linux_fgetxattr", /* 231 = linux_fgetxattr */ "linux_listxattr", /* 232 = linux_listxattr */ "linux_llistxattr", /* 233 = linux_llistxattr */ "linux_flistxattr", /* 234 = linux_flistxattr */ "linux_removexattr", /* 235 = linux_removexattr */ "linux_lremovexattr", /* 236 = linux_lremovexattr */ "linux_fremovexattr", /* 237 = linux_fremovexattr */ "linux_tkill", /* 238 = linux_tkill */ "#239", /* 239 = linux_sendfile64 */ "linux_sys_futex", /* 240 = linux_sys_futex */ "linux_sched_setaffinity", /* 241 = linux_sched_setaffinity */ "linux_sched_getaffinity", /* 242 = linux_sched_getaffinity */ "linux_set_thread_area", /* 243 = linux_set_thread_area */ "#244", /* 244 = linux_get_thread_area */ "#245", /* 245 = linux_io_setup */ "#246", /* 246 = linux_io_destroy */ "#247", /* 247 = linux_io_getevents */ "#248", /* 248 = linux_io_submit */ "#249", /* 249 = linux_io_cancel */ "linux_fadvise64", /* 250 = linux_fadvise64 */ "#251", /* 251 = */ "linux_exit_group", /* 252 = linux_exit_group */ "linux_lookup_dcookie", /* 253 = linux_lookup_dcookie */ "linux_epoll_create", /* 254 = linux_epoll_create */ "linux_epoll_ctl", /* 255 = linux_epoll_ctl */ "linux_epoll_wait", /* 256 = linux_epoll_wait */ "linux_remap_file_pages", /* 257 = linux_remap_file_pages */ "linux_set_tid_address", /* 258 = linux_set_tid_address */ "linux_timer_create", /* 259 = linux_timer_create */ "linux_timer_settime", /* 260 = linux_timer_settime */ "linux_timer_gettime", /* 261 = linux_timer_gettime */ "linux_timer_getoverrun", /* 262 = linux_timer_getoverrun */ "linux_timer_delete", /* 263 = linux_timer_delete */ "linux_clock_settime", /* 264 = linux_clock_settime */ "linux_clock_gettime", /* 265 = linux_clock_gettime */ "linux_clock_getres", /* 266 = linux_clock_getres */ "linux_clock_nanosleep", /* 267 = linux_clock_nanosleep */ "linux_statfs64", /* 268 = linux_statfs64 */ "linux_fstatfs64", /* 269 = linux_fstatfs64 */ "linux_tgkill", /* 270 = linux_tgkill */ "linux_utimes", /* 271 = linux_utimes */ "linux_fadvise64_64", /* 272 = linux_fadvise64_64 */ "#273", /* 273 = vserver */ "linux_mbind", /* 274 = linux_mbind */ "linux_get_mempolicy", /* 275 = linux_get_mempolicy */ "linux_set_mempolicy", /* 276 = linux_set_mempolicy */ "linux_mq_open", /* 277 = linux_mq_open */ "linux_mq_unlink", /* 278 = linux_mq_unlink */ "linux_mq_timedsend", /* 279 = linux_mq_timedsend */ "linux_mq_timedreceive", /* 280 = linux_mq_timedreceive */ "linux_mq_notify", /* 281 = linux_mq_notify */ "linux_mq_getsetattr", /* 282 = linux_mq_getsetattr */ "linux_kexec_load", /* 283 = linux_kexec_load */ "linux_waitid", /* 284 = linux_waitid */ "#285", /* 285 = */ "linux_add_key", /* 286 = linux_add_key */ "linux_request_key", /* 287 = linux_request_key */ "linux_keyctl", /* 288 = linux_keyctl */ "linux_ioprio_set", /* 289 = linux_ioprio_set */ "linux_ioprio_get", /* 290 = linux_ioprio_get */ "linux_inotify_init", /* 291 = linux_inotify_init */ "linux_inotify_add_watch", /* 292 = linux_inotify_add_watch */ "linux_inotify_rm_watch", /* 293 = linux_inotify_rm_watch */ "linux_migrate_pages", /* 294 = linux_migrate_pages */ "linux_openat", /* 295 = linux_openat */ "linux_mkdirat", /* 296 = linux_mkdirat */ "linux_mknodat", /* 297 = linux_mknodat */ "linux_fchownat", /* 298 = linux_fchownat */ "linux_futimesat", /* 299 = linux_futimesat */ "linux_fstatat64", /* 300 = linux_fstatat64 */ "linux_unlinkat", /* 301 = linux_unlinkat */ "linux_renameat", /* 302 = linux_renameat */ "linux_linkat", /* 303 = linux_linkat */ "linux_symlinkat", /* 304 = linux_symlinkat */ "linux_readlinkat", /* 305 = linux_readlinkat */ "linux_fchmodat", /* 306 = linux_fchmodat */ "linux_faccessat", /* 307 = linux_faccessat */ "linux_pselect6", /* 308 = linux_pselect6 */ "linux_ppoll", /* 309 = linux_ppoll */ "linux_unshare", /* 310 = linux_unshare */ "linux_set_robust_list", /* 311 = linux_set_robust_list */ "linux_get_robust_list", /* 312 = linux_get_robust_list */ "linux_splice", /* 313 = linux_splice */ "linux_sync_file_range", /* 314 = linux_sync_file_range */ "linux_tee", /* 315 = linux_tee */ "linux_vmsplice", /* 316 = linux_vmsplice */ "linux_move_pages", /* 317 = linux_move_pages */ "linux_getcpu", /* 318 = linux_getcpu */ "linux_epoll_pwait", /* 319 = linux_epoll_pwait */ "linux_utimensat", /* 320 = linux_utimensat */ "linux_signalfd", /* 321 = linux_signalfd */ "linux_timerfd_create", /* 322 = linux_timerfd_create */ "linux_eventfd", /* 323 = linux_eventfd */ "linux_fallocate", /* 324 = linux_fallocate */ "linux_timerfd_settime", /* 325 = linux_timerfd_settime */ "linux_timerfd_gettime", /* 326 = linux_timerfd_gettime */ "linux_signalfd4", /* 327 = linux_signalfd4 */ "linux_eventfd2", /* 328 = linux_eventfd2 */ "linux_epoll_create1", /* 329 = linux_epoll_create1 */ "linux_dup3", /* 330 = linux_dup3 */ "linux_pipe2", /* 331 = linux_pipe2 */ "linux_inotify_init1", /* 332 = linux_inotify_init1 */ "linux_preadv", /* 333 = linux_preadv */ "linux_pwritev", /* 334 = linux_pwritev */ - "linux_rt_tsigqueueinfo", /* 335 = linux_rt_tsigqueueinfo */ + "linux_rt_tgsigqueueinfo", /* 335 = linux_rt_tgsigqueueinfo */ "linux_perf_event_open", /* 336 = linux_perf_event_open */ "linux_recvmmsg", /* 337 = linux_recvmmsg */ "linux_fanotify_init", /* 338 = linux_fanotify_init */ "linux_fanotify_mark", /* 339 = linux_fanotify_mark */ "linux_prlimit64", /* 340 = linux_prlimit64 */ "linux_name_to_handle_at", /* 341 = linux_name_to_handle_at */ "linux_open_by_handle_at", /* 342 = linux_open_by_handle_at */ "linux_clock_adjtime", /* 343 = linux_clock_adjtime */ "linux_syncfs", /* 344 = linux_syncfs */ "linux_sendmmsg", /* 345 = linux_sendmmsg */ "linux_setns", /* 346 = linux_setns */ "linux_process_vm_readv", /* 347 = linux_process_vm_readv */ "linux_process_vm_writev", /* 348 = linux_process_vm_writev */ - "#349", /* 349 = nosys */ + "linux_kcmp", /* 349 = linux_kcmp */ + "linux_finit_module", /* 350 = linux_finit_module */ + "linux_sched_setattr", /* 351 = linux_sched_setattr */ + "linux_sched_getattr", /* 352 = linux_sched_getattr */ + "linux_renameat2", /* 353 = linux_renameat2 */ + "linux_seccomp", /* 354 = linux_seccomp */ + "linux_getrandom", /* 355 = linux_getrandom */ + "linux_memfd_create", /* 356 = linux_memfd_create */ + "linux_bpf", /* 357 = linux_bpf */ + "linux_execveat", /* 358 = linux_execveat */ + "linux_socket", /* 359 = linux_socket */ + "linux_socketpair", /* 360 = linux_socketpair */ + "linux_bind", /* 361 = linux_bind */ + "linux_connect", /* 362 = linux_connect */ + "linux_listen", /* 363 = linux_listen */ + "linux_accept4", /* 364 = linux_accept4 */ + "linux_getsockopt", /* 365 = linux_getsockopt */ + "linux_setsockopt", /* 366 = linux_setsockopt */ + "linux_getsockname", /* 367 = linux_getsockname */ + "linux_getpeername", /* 368 = linux_getpeername */ + "linux_sendto", /* 369 = linux_sendto */ + "linux_sendmsg", /* 370 = linux_sendmsg */ + "linux_recvfrom", /* 371 = linux_recvfrom */ + "linux_recvmsg", /* 372 = linux_recvmsg */ + "linux_shutdown", /* 373 = linux_shutdown */ + "linux_userfaultfd", /* 374 = linux_userfaultfd */ + "linux_membarrier", /* 375 = linux_membarrier */ + "linux_mlock2", /* 376 = linux_mlock2 */ + "linux_copy_file_range", /* 377 = linux_copy_file_range */ + "linux_preadv2", /* 378 = linux_preadv2 */ + "linux_pwritev2", /* 379 = linux_pwritev2 */ + "linux_pkey_mprotect", /* 380 = linux_pkey_mprotect */ + "linux_pkey_alloc", /* 381 = linux_pkey_alloc */ + "linux_pkey_free", /* 382 = linux_pkey_free */ + "#383", /* 383 = nosys */ }; Index: projects/ipsec/sys/amd64/linux32/linux32_sysent.c =================================================================== --- projects/ipsec/sys/amd64/linux32/linux32_sysent.c (revision 313312) +++ projects/ipsec/sys/amd64/linux32/linux32_sysent.c (revision 313313) @@ -1,372 +1,406 @@ /* * System call switch table. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ #include "opt_compat.h" #include #include #include #include #include #include #define AS(name) (sizeof(struct name) / sizeof(register_t)) /* The casts are bogus but will do for now. */ struct sysent linux32_sysent[] = { #define nosys linux_nosys { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 0 = setup */ { AS(linux_exit_args), (sy_call_t *)linux_exit, AUE_EXIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 1 = linux_exit */ { 0, (sy_call_t *)linux_fork, AUE_FORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 2 = linux_fork */ { AS(read_args), (sy_call_t *)sys_read, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 3 = read */ { AS(write_args), (sy_call_t *)sys_write, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 4 = write */ { AS(linux_open_args), (sy_call_t *)linux_open, AUE_OPEN_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 5 = linux_open */ { AS(close_args), (sy_call_t *)sys_close, AUE_CLOSE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 6 = close */ { AS(linux_waitpid_args), (sy_call_t *)linux_waitpid, AUE_WAIT4, NULL, 0, 0, 0, SY_THR_STATIC }, /* 7 = linux_waitpid */ { AS(linux_creat_args), (sy_call_t *)linux_creat, AUE_CREAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 8 = linux_creat */ { AS(linux_link_args), (sy_call_t *)linux_link, AUE_LINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 9 = linux_link */ { AS(linux_unlink_args), (sy_call_t *)linux_unlink, AUE_UNLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 10 = linux_unlink */ { AS(linux_execve_args), (sy_call_t *)linux_execve, AUE_EXECVE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 11 = linux_execve */ { AS(linux_chdir_args), (sy_call_t *)linux_chdir, AUE_CHDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 12 = linux_chdir */ { AS(linux_time_args), (sy_call_t *)linux_time, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 13 = linux_time */ { AS(linux_mknod_args), (sy_call_t *)linux_mknod, AUE_MKNOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 14 = linux_mknod */ { AS(linux_chmod_args), (sy_call_t *)linux_chmod, AUE_CHMOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 15 = linux_chmod */ { AS(linux_lchown16_args), (sy_call_t *)linux_lchown16, AUE_LCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 16 = linux_lchown16 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 17 = break */ { AS(linux_stat_args), (sy_call_t *)linux_stat, AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 18 = linux_stat */ { AS(linux_lseek_args), (sy_call_t *)linux_lseek, AUE_LSEEK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 19 = linux_lseek */ { 0, (sy_call_t *)linux_getpid, AUE_GETPID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 20 = linux_getpid */ { AS(linux_mount_args), (sy_call_t *)linux_mount, AUE_MOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 21 = linux_mount */ { AS(linux_oldumount_args), (sy_call_t *)linux_oldumount, AUE_UMOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 22 = linux_oldumount */ { AS(linux_setuid16_args), (sy_call_t *)linux_setuid16, AUE_SETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 23 = linux_setuid16 */ { 0, (sy_call_t *)linux_getuid16, AUE_GETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 24 = linux_getuid16 */ { 0, (sy_call_t *)linux_stime, AUE_SETTIMEOFDAY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 25 = linux_stime */ { AS(linux_ptrace_args), (sy_call_t *)linux_ptrace, AUE_PTRACE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 26 = linux_ptrace */ { AS(linux_alarm_args), (sy_call_t *)linux_alarm, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 27 = linux_alarm */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 28 = fstat */ { 0, (sy_call_t *)linux_pause, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 29 = linux_pause */ { AS(linux_utime_args), (sy_call_t *)linux_utime, AUE_UTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 30 = linux_utime */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 31 = stty */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 32 = gtty */ { AS(linux_access_args), (sy_call_t *)linux_access, AUE_ACCESS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 33 = linux_access */ { AS(linux_nice_args), (sy_call_t *)linux_nice, AUE_NICE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 34 = linux_nice */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 35 = ftime */ { 0, (sy_call_t *)sys_sync, AUE_SYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 36 = sync */ { AS(linux_kill_args), (sy_call_t *)linux_kill, AUE_KILL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 37 = linux_kill */ { AS(linux_rename_args), (sy_call_t *)linux_rename, AUE_RENAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 38 = linux_rename */ { AS(linux_mkdir_args), (sy_call_t *)linux_mkdir, AUE_MKDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 39 = linux_mkdir */ { AS(linux_rmdir_args), (sy_call_t *)linux_rmdir, AUE_RMDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 40 = linux_rmdir */ { AS(dup_args), (sy_call_t *)sys_dup, AUE_DUP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 41 = dup */ { AS(linux_pipe_args), (sy_call_t *)linux_pipe, AUE_PIPE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 42 = linux_pipe */ { AS(linux_times_args), (sy_call_t *)linux_times, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 43 = linux_times */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 44 = prof */ { AS(linux_brk_args), (sy_call_t *)linux_brk, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 45 = linux_brk */ { AS(linux_setgid16_args), (sy_call_t *)linux_setgid16, AUE_SETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 46 = linux_setgid16 */ { 0, (sy_call_t *)linux_getgid16, AUE_GETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 47 = linux_getgid16 */ { AS(linux_signal_args), (sy_call_t *)linux_signal, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 48 = linux_signal */ { 0, (sy_call_t *)linux_geteuid16, AUE_GETEUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 49 = linux_geteuid16 */ { 0, (sy_call_t *)linux_getegid16, AUE_GETEGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 50 = linux_getegid16 */ { AS(acct_args), (sy_call_t *)sys_acct, AUE_ACCT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 51 = acct */ { AS(linux_umount_args), (sy_call_t *)linux_umount, AUE_UMOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 52 = linux_umount */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 53 = lock */ { AS(linux_ioctl_args), (sy_call_t *)linux_ioctl, AUE_IOCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 54 = linux_ioctl */ { AS(linux_fcntl_args), (sy_call_t *)linux_fcntl, AUE_FCNTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 55 = linux_fcntl */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 56 = mpx */ { AS(setpgid_args), (sy_call_t *)sys_setpgid, AUE_SETPGRP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 57 = setpgid */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 58 = ulimit */ { 0, (sy_call_t *)linux_olduname, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 59 = linux_olduname */ { AS(umask_args), (sy_call_t *)sys_umask, AUE_UMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 60 = umask */ { AS(chroot_args), (sy_call_t *)sys_chroot, AUE_CHROOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 61 = chroot */ { AS(linux_ustat_args), (sy_call_t *)linux_ustat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 62 = linux_ustat */ { AS(dup2_args), (sy_call_t *)sys_dup2, AUE_DUP2, NULL, 0, 0, 0, SY_THR_STATIC }, /* 63 = dup2 */ { 0, (sy_call_t *)linux_getppid, AUE_GETPPID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 64 = linux_getppid */ { 0, (sy_call_t *)sys_getpgrp, AUE_GETPGRP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 65 = getpgrp */ { 0, (sy_call_t *)sys_setsid, AUE_SETSID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 66 = setsid */ { AS(linux_sigaction_args), (sy_call_t *)linux_sigaction, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 67 = linux_sigaction */ { 0, (sy_call_t *)linux_sgetmask, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 68 = linux_sgetmask */ { AS(linux_ssetmask_args), (sy_call_t *)linux_ssetmask, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 69 = linux_ssetmask */ { AS(linux_setreuid16_args), (sy_call_t *)linux_setreuid16, AUE_SETREUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 70 = linux_setreuid16 */ { AS(linux_setregid16_args), (sy_call_t *)linux_setregid16, AUE_SETREGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 71 = linux_setregid16 */ { AS(linux_sigsuspend_args), (sy_call_t *)linux_sigsuspend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 72 = linux_sigsuspend */ { AS(linux_sigpending_args), (sy_call_t *)linux_sigpending, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 73 = linux_sigpending */ { AS(linux_sethostname_args), (sy_call_t *)linux_sethostname, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 74 = linux_sethostname */ { AS(linux_setrlimit_args), (sy_call_t *)linux_setrlimit, AUE_SETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 75 = linux_setrlimit */ { AS(linux_old_getrlimit_args), (sy_call_t *)linux_old_getrlimit, AUE_GETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 76 = linux_old_getrlimit */ { AS(linux_getrusage_args), (sy_call_t *)linux_getrusage, AUE_GETRUSAGE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 77 = linux_getrusage */ { AS(linux_gettimeofday_args), (sy_call_t *)linux_gettimeofday, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 78 = linux_gettimeofday */ { AS(linux_settimeofday_args), (sy_call_t *)linux_settimeofday, AUE_SETTIMEOFDAY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 79 = linux_settimeofday */ { AS(linux_getgroups16_args), (sy_call_t *)linux_getgroups16, AUE_GETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 80 = linux_getgroups16 */ { AS(linux_setgroups16_args), (sy_call_t *)linux_setgroups16, AUE_SETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 81 = linux_setgroups16 */ { AS(linux_old_select_args), (sy_call_t *)linux_old_select, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 82 = linux_old_select */ { AS(linux_symlink_args), (sy_call_t *)linux_symlink, AUE_SYMLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 83 = linux_symlink */ { AS(linux_lstat_args), (sy_call_t *)linux_lstat, AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 84 = linux_lstat */ { AS(linux_readlink_args), (sy_call_t *)linux_readlink, AUE_READLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 85 = linux_readlink */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 86 = linux_uselib */ { AS(swapon_args), (sy_call_t *)sys_swapon, AUE_SWAPON, NULL, 0, 0, 0, SY_THR_STATIC }, /* 87 = swapon */ { AS(linux_reboot_args), (sy_call_t *)linux_reboot, AUE_REBOOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 88 = linux_reboot */ { AS(linux_readdir_args), (sy_call_t *)linux_readdir, AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 89 = linux_readdir */ { AS(linux_mmap_args), (sy_call_t *)linux_mmap, AUE_MMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 90 = linux_mmap */ { AS(munmap_args), (sy_call_t *)sys_munmap, AUE_MUNMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 91 = munmap */ { AS(linux_truncate_args), (sy_call_t *)linux_truncate, AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 92 = linux_truncate */ { AS(linux_ftruncate_args), (sy_call_t *)linux_ftruncate, AUE_FTRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 93 = linux_ftruncate */ { AS(fchmod_args), (sy_call_t *)sys_fchmod, AUE_FCHMOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 94 = fchmod */ { AS(fchown_args), (sy_call_t *)sys_fchown, AUE_FCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 95 = fchown */ { AS(linux_getpriority_args), (sy_call_t *)linux_getpriority, AUE_GETPRIORITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 96 = linux_getpriority */ { AS(setpriority_args), (sy_call_t *)sys_setpriority, AUE_SETPRIORITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 97 = setpriority */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 98 = profil */ { AS(linux_statfs_args), (sy_call_t *)linux_statfs, AUE_STATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 99 = linux_statfs */ { AS(linux_fstatfs_args), (sy_call_t *)linux_fstatfs, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 100 = linux_fstatfs */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 101 = ioperm */ { AS(linux_socketcall_args), (sy_call_t *)linux_socketcall, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 102 = linux_socketcall */ { AS(linux_syslog_args), (sy_call_t *)linux_syslog, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 103 = linux_syslog */ { AS(linux_setitimer_args), (sy_call_t *)linux_setitimer, AUE_SETITIMER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 104 = linux_setitimer */ { AS(linux_getitimer_args), (sy_call_t *)linux_getitimer, AUE_GETITIMER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 105 = linux_getitimer */ { AS(linux_newstat_args), (sy_call_t *)linux_newstat, AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 106 = linux_newstat */ { AS(linux_newlstat_args), (sy_call_t *)linux_newlstat, AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 107 = linux_newlstat */ { AS(linux_newfstat_args), (sy_call_t *)linux_newfstat, AUE_FSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 108 = linux_newfstat */ { 0, (sy_call_t *)linux_uname, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 109 = linux_uname */ { AS(linux_iopl_args), (sy_call_t *)linux_iopl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 110 = linux_iopl */ { 0, (sy_call_t *)linux_vhangup, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 111 = linux_vhangup */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 112 = idle */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 113 = vm86old */ { AS(linux_wait4_args), (sy_call_t *)linux_wait4, AUE_WAIT4, NULL, 0, 0, 0, SY_THR_STATIC }, /* 114 = linux_wait4 */ { 0, (sy_call_t *)linux_swapoff, AUE_SWAPOFF, NULL, 0, 0, 0, SY_THR_STATIC }, /* 115 = linux_swapoff */ { AS(linux_sysinfo_args), (sy_call_t *)linux_sysinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 116 = linux_sysinfo */ { AS(linux_ipc_args), (sy_call_t *)linux_ipc, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 117 = linux_ipc */ { AS(fsync_args), (sy_call_t *)sys_fsync, AUE_FSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 118 = fsync */ { AS(linux_sigreturn_args), (sy_call_t *)linux_sigreturn, AUE_SIGRETURN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 119 = linux_sigreturn */ { AS(linux_clone_args), (sy_call_t *)linux_clone, AUE_RFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 120 = linux_clone */ { AS(linux_setdomainname_args), (sy_call_t *)linux_setdomainname, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 121 = linux_setdomainname */ { AS(linux_newuname_args), (sy_call_t *)linux_newuname, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 122 = linux_newuname */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 123 = modify_ldt */ { 0, (sy_call_t *)linux_adjtimex, AUE_ADJTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 124 = linux_adjtimex */ { AS(linux_mprotect_args), (sy_call_t *)linux_mprotect, AUE_MPROTECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 125 = linux_mprotect */ { AS(linux_sigprocmask_args), (sy_call_t *)linux_sigprocmask, AUE_SIGPROCMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 126 = linux_sigprocmask */ { 0, (sy_call_t *)linux_create_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 127 = linux_create_module */ { 0, (sy_call_t *)linux_init_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 128 = linux_init_module */ { 0, (sy_call_t *)linux_delete_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 129 = linux_delete_module */ { 0, (sy_call_t *)linux_get_kernel_syms, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 130 = linux_get_kernel_syms */ { 0, (sy_call_t *)linux_quotactl, AUE_QUOTACTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 131 = linux_quotactl */ { AS(getpgid_args), (sy_call_t *)sys_getpgid, AUE_GETPGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 132 = getpgid */ { AS(fchdir_args), (sy_call_t *)sys_fchdir, AUE_FCHDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 133 = fchdir */ { 0, (sy_call_t *)linux_bdflush, AUE_BDFLUSH, NULL, 0, 0, 0, SY_THR_STATIC }, /* 134 = linux_bdflush */ { AS(linux_sysfs_args), (sy_call_t *)linux_sysfs, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 135 = linux_sysfs */ { AS(linux_personality_args), (sy_call_t *)linux_personality, AUE_PERSONALITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 136 = linux_personality */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 137 = afs_syscall */ { AS(linux_setfsuid16_args), (sy_call_t *)linux_setfsuid16, AUE_SETFSUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 138 = linux_setfsuid16 */ { AS(linux_setfsgid16_args), (sy_call_t *)linux_setfsgid16, AUE_SETFSGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 139 = linux_setfsgid16 */ { AS(linux_llseek_args), (sy_call_t *)linux_llseek, AUE_LSEEK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 140 = linux_llseek */ { AS(linux_getdents_args), (sy_call_t *)linux_getdents, AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 141 = linux_getdents */ { AS(linux_select_args), (sy_call_t *)linux_select, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 142 = linux_select */ { AS(flock_args), (sy_call_t *)sys_flock, AUE_FLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 143 = flock */ { AS(linux_msync_args), (sy_call_t *)linux_msync, AUE_MSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 144 = linux_msync */ { AS(linux_readv_args), (sy_call_t *)linux_readv, AUE_READV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 145 = linux_readv */ { AS(linux_writev_args), (sy_call_t *)linux_writev, AUE_WRITEV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 146 = linux_writev */ { AS(linux_getsid_args), (sy_call_t *)linux_getsid, AUE_GETSID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 147 = linux_getsid */ { AS(linux_fdatasync_args), (sy_call_t *)linux_fdatasync, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 148 = linux_fdatasync */ { AS(linux_sysctl_args), (sy_call_t *)linux_sysctl, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 149 = linux_sysctl */ { AS(mlock_args), (sy_call_t *)sys_mlock, AUE_MLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 150 = mlock */ { AS(munlock_args), (sy_call_t *)sys_munlock, AUE_MUNLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 151 = munlock */ { AS(mlockall_args), (sy_call_t *)sys_mlockall, AUE_MLOCKALL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 152 = mlockall */ { 0, (sy_call_t *)sys_munlockall, AUE_MUNLOCKALL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 153 = munlockall */ { AS(linux_sched_setparam_args), (sy_call_t *)linux_sched_setparam, AUE_SCHED_SETPARAM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 154 = linux_sched_setparam */ { AS(linux_sched_getparam_args), (sy_call_t *)linux_sched_getparam, AUE_SCHED_GETPARAM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 155 = linux_sched_getparam */ { AS(linux_sched_setscheduler_args), (sy_call_t *)linux_sched_setscheduler, AUE_SCHED_SETSCHEDULER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 156 = linux_sched_setscheduler */ { AS(linux_sched_getscheduler_args), (sy_call_t *)linux_sched_getscheduler, AUE_SCHED_GETSCHEDULER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 157 = linux_sched_getscheduler */ { 0, (sy_call_t *)sys_sched_yield, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 158 = sched_yield */ { AS(linux_sched_get_priority_max_args), (sy_call_t *)linux_sched_get_priority_max, AUE_SCHED_GET_PRIORITY_MAX, NULL, 0, 0, 0, SY_THR_STATIC }, /* 159 = linux_sched_get_priority_max */ { AS(linux_sched_get_priority_min_args), (sy_call_t *)linux_sched_get_priority_min, AUE_SCHED_GET_PRIORITY_MIN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 160 = linux_sched_get_priority_min */ { AS(linux_sched_rr_get_interval_args), (sy_call_t *)linux_sched_rr_get_interval, AUE_SCHED_RR_GET_INTERVAL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 161 = linux_sched_rr_get_interval */ { AS(linux_nanosleep_args), (sy_call_t *)linux_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 162 = linux_nanosleep */ { AS(linux_mremap_args), (sy_call_t *)linux_mremap, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 163 = linux_mremap */ { AS(linux_setresuid16_args), (sy_call_t *)linux_setresuid16, AUE_SETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 164 = linux_setresuid16 */ { AS(linux_getresuid16_args), (sy_call_t *)linux_getresuid16, AUE_GETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 165 = linux_getresuid16 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 166 = vm86 */ { 0, (sy_call_t *)linux_query_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 167 = linux_query_module */ { AS(poll_args), (sy_call_t *)sys_poll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 168 = poll */ { 0, (sy_call_t *)linux_nfsservctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 169 = linux_nfsservctl */ { AS(linux_setresgid16_args), (sy_call_t *)linux_setresgid16, AUE_SETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 170 = linux_setresgid16 */ { AS(linux_getresgid16_args), (sy_call_t *)linux_getresgid16, AUE_GETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 171 = linux_getresgid16 */ { AS(linux_prctl_args), (sy_call_t *)linux_prctl, AUE_PRCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 172 = linux_prctl */ { AS(linux_rt_sigreturn_args), (sy_call_t *)linux_rt_sigreturn, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 173 = linux_rt_sigreturn */ { AS(linux_rt_sigaction_args), (sy_call_t *)linux_rt_sigaction, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 174 = linux_rt_sigaction */ { AS(linux_rt_sigprocmask_args), (sy_call_t *)linux_rt_sigprocmask, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 175 = linux_rt_sigprocmask */ { AS(linux_rt_sigpending_args), (sy_call_t *)linux_rt_sigpending, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 176 = linux_rt_sigpending */ { AS(linux_rt_sigtimedwait_args), (sy_call_t *)linux_rt_sigtimedwait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 177 = linux_rt_sigtimedwait */ { AS(linux_rt_sigqueueinfo_args), (sy_call_t *)linux_rt_sigqueueinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 178 = linux_rt_sigqueueinfo */ { AS(linux_rt_sigsuspend_args), (sy_call_t *)linux_rt_sigsuspend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 179 = linux_rt_sigsuspend */ { AS(linux_pread_args), (sy_call_t *)linux_pread, AUE_PREAD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 180 = linux_pread */ { AS(linux_pwrite_args), (sy_call_t *)linux_pwrite, AUE_PWRITE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 181 = linux_pwrite */ { AS(linux_chown16_args), (sy_call_t *)linux_chown16, AUE_CHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 182 = linux_chown16 */ { AS(linux_getcwd_args), (sy_call_t *)linux_getcwd, AUE_GETCWD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 183 = linux_getcwd */ { AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 184 = linux_capget */ { AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 185 = linux_capset */ { AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 186 = linux_sigaltstack */ { 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 187 = linux_sendfile */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 188 = getpmsg */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 189 = putpmsg */ { 0, (sy_call_t *)linux_vfork, AUE_VFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 190 = linux_vfork */ { AS(linux_getrlimit_args), (sy_call_t *)linux_getrlimit, AUE_GETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 191 = linux_getrlimit */ { AS(linux_mmap2_args), (sy_call_t *)linux_mmap2, AUE_MMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 192 = linux_mmap2 */ { AS(linux_truncate64_args), (sy_call_t *)linux_truncate64, AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 193 = linux_truncate64 */ { AS(linux_ftruncate64_args), (sy_call_t *)linux_ftruncate64, AUE_FTRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 194 = linux_ftruncate64 */ { AS(linux_stat64_args), (sy_call_t *)linux_stat64, AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 195 = linux_stat64 */ { AS(linux_lstat64_args), (sy_call_t *)linux_lstat64, AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 196 = linux_lstat64 */ { AS(linux_fstat64_args), (sy_call_t *)linux_fstat64, AUE_FSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 197 = linux_fstat64 */ { AS(linux_lchown_args), (sy_call_t *)linux_lchown, AUE_LCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 198 = linux_lchown */ { 0, (sy_call_t *)linux_getuid, AUE_GETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 199 = linux_getuid */ { 0, (sy_call_t *)linux_getgid, AUE_GETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 200 = linux_getgid */ { 0, (sy_call_t *)sys_geteuid, AUE_GETEUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 201 = geteuid */ { 0, (sy_call_t *)sys_getegid, AUE_GETEGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 202 = getegid */ { AS(setreuid_args), (sy_call_t *)sys_setreuid, AUE_SETREUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 203 = setreuid */ { AS(setregid_args), (sy_call_t *)sys_setregid, AUE_SETREGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 204 = setregid */ { AS(linux_getgroups_args), (sy_call_t *)linux_getgroups, AUE_GETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 205 = linux_getgroups */ { AS(linux_setgroups_args), (sy_call_t *)linux_setgroups, AUE_SETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 206 = linux_setgroups */ { AS(fchown_args), (sy_call_t *)sys_fchown, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 207 = fchown */ { AS(setresuid_args), (sy_call_t *)sys_setresuid, AUE_SETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 208 = setresuid */ { AS(getresuid_args), (sy_call_t *)sys_getresuid, AUE_GETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 209 = getresuid */ { AS(setresgid_args), (sy_call_t *)sys_setresgid, AUE_SETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 210 = setresgid */ { AS(getresgid_args), (sy_call_t *)sys_getresgid, AUE_GETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 211 = getresgid */ { AS(linux_chown_args), (sy_call_t *)linux_chown, AUE_CHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 212 = linux_chown */ { AS(setuid_args), (sy_call_t *)sys_setuid, AUE_SETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 213 = setuid */ { AS(setgid_args), (sy_call_t *)sys_setgid, AUE_SETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 214 = setgid */ { AS(linux_setfsuid_args), (sy_call_t *)linux_setfsuid, AUE_SETFSUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 215 = linux_setfsuid */ { AS(linux_setfsgid_args), (sy_call_t *)linux_setfsgid, AUE_SETFSGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 216 = linux_setfsgid */ { AS(linux_pivot_root_args), (sy_call_t *)linux_pivot_root, AUE_PIVOT_ROOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 217 = linux_pivot_root */ { AS(linux_mincore_args), (sy_call_t *)linux_mincore, AUE_MINCORE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 218 = linux_mincore */ { AS(madvise_args), (sy_call_t *)sys_madvise, AUE_MADVISE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 219 = madvise */ { AS(linux_getdents64_args), (sy_call_t *)linux_getdents64, AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 220 = linux_getdents64 */ { AS(linux_fcntl64_args), (sy_call_t *)linux_fcntl64, AUE_FCNTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 221 = linux_fcntl64 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 222 = */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 223 = */ { 0, (sy_call_t *)linux_gettid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 224 = linux_gettid */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 225 = linux_readahead */ { 0, (sy_call_t *)linux_setxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 226 = linux_setxattr */ { 0, (sy_call_t *)linux_lsetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 227 = linux_lsetxattr */ { 0, (sy_call_t *)linux_fsetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 228 = linux_fsetxattr */ { 0, (sy_call_t *)linux_getxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 229 = linux_getxattr */ { 0, (sy_call_t *)linux_lgetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 230 = linux_lgetxattr */ { 0, (sy_call_t *)linux_fgetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 231 = linux_fgetxattr */ { 0, (sy_call_t *)linux_listxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 232 = linux_listxattr */ { 0, (sy_call_t *)linux_llistxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 233 = linux_llistxattr */ { 0, (sy_call_t *)linux_flistxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 234 = linux_flistxattr */ { 0, (sy_call_t *)linux_removexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 235 = linux_removexattr */ { 0, (sy_call_t *)linux_lremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 236 = linux_lremovexattr */ { 0, (sy_call_t *)linux_fremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 237 = linux_fremovexattr */ { AS(linux_tkill_args), (sy_call_t *)linux_tkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 238 = linux_tkill */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 239 = linux_sendfile64 */ { AS(linux_sys_futex_args), (sy_call_t *)linux_sys_futex, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 240 = linux_sys_futex */ { AS(linux_sched_setaffinity_args), (sy_call_t *)linux_sched_setaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 241 = linux_sched_setaffinity */ { AS(linux_sched_getaffinity_args), (sy_call_t *)linux_sched_getaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 242 = linux_sched_getaffinity */ { AS(linux_set_thread_area_args), (sy_call_t *)linux_set_thread_area, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 243 = linux_set_thread_area */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 244 = linux_get_thread_area */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 245 = linux_io_setup */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 246 = linux_io_destroy */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 247 = linux_io_getevents */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 248 = linux_io_submit */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 249 = linux_io_cancel */ { AS(linux_fadvise64_args), (sy_call_t *)linux_fadvise64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 250 = linux_fadvise64 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 251 = */ { AS(linux_exit_group_args), (sy_call_t *)linux_exit_group, AUE_EXIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 252 = linux_exit_group */ { 0, (sy_call_t *)linux_lookup_dcookie, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 253 = linux_lookup_dcookie */ { AS(linux_epoll_create_args), (sy_call_t *)linux_epoll_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 254 = linux_epoll_create */ { AS(linux_epoll_ctl_args), (sy_call_t *)linux_epoll_ctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 255 = linux_epoll_ctl */ { AS(linux_epoll_wait_args), (sy_call_t *)linux_epoll_wait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 256 = linux_epoll_wait */ { 0, (sy_call_t *)linux_remap_file_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 257 = linux_remap_file_pages */ { AS(linux_set_tid_address_args), (sy_call_t *)linux_set_tid_address, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 258 = linux_set_tid_address */ { AS(linux_timer_create_args), (sy_call_t *)linux_timer_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 259 = linux_timer_create */ { AS(linux_timer_settime_args), (sy_call_t *)linux_timer_settime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 260 = linux_timer_settime */ { AS(linux_timer_gettime_args), (sy_call_t *)linux_timer_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 261 = linux_timer_gettime */ { AS(linux_timer_getoverrun_args), (sy_call_t *)linux_timer_getoverrun, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 262 = linux_timer_getoverrun */ { AS(linux_timer_delete_args), (sy_call_t *)linux_timer_delete, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 263 = linux_timer_delete */ { AS(linux_clock_settime_args), (sy_call_t *)linux_clock_settime, AUE_CLOCK_SETTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 264 = linux_clock_settime */ { AS(linux_clock_gettime_args), (sy_call_t *)linux_clock_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 265 = linux_clock_gettime */ { AS(linux_clock_getres_args), (sy_call_t *)linux_clock_getres, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 266 = linux_clock_getres */ { AS(linux_clock_nanosleep_args), (sy_call_t *)linux_clock_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 267 = linux_clock_nanosleep */ { AS(linux_statfs64_args), (sy_call_t *)linux_statfs64, AUE_STATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 268 = linux_statfs64 */ { AS(linux_fstatfs64_args), (sy_call_t *)linux_fstatfs64, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 269 = linux_fstatfs64 */ { AS(linux_tgkill_args), (sy_call_t *)linux_tgkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 270 = linux_tgkill */ { AS(linux_utimes_args), (sy_call_t *)linux_utimes, AUE_UTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 271 = linux_utimes */ { AS(linux_fadvise64_64_args), (sy_call_t *)linux_fadvise64_64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 272 = linux_fadvise64_64 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 273 = vserver */ { 0, (sy_call_t *)linux_mbind, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 274 = linux_mbind */ { 0, (sy_call_t *)linux_get_mempolicy, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 275 = linux_get_mempolicy */ { 0, (sy_call_t *)linux_set_mempolicy, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 276 = linux_set_mempolicy */ { 0, (sy_call_t *)linux_mq_open, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 277 = linux_mq_open */ { 0, (sy_call_t *)linux_mq_unlink, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 278 = linux_mq_unlink */ { 0, (sy_call_t *)linux_mq_timedsend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 279 = linux_mq_timedsend */ { 0, (sy_call_t *)linux_mq_timedreceive, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 280 = linux_mq_timedreceive */ { 0, (sy_call_t *)linux_mq_notify, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 281 = linux_mq_notify */ { 0, (sy_call_t *)linux_mq_getsetattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 282 = linux_mq_getsetattr */ { 0, (sy_call_t *)linux_kexec_load, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 283 = linux_kexec_load */ { AS(linux_waitid_args), (sy_call_t *)linux_waitid, AUE_WAIT6, NULL, 0, 0, 0, SY_THR_STATIC }, /* 284 = linux_waitid */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 285 = */ { 0, (sy_call_t *)linux_add_key, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 286 = linux_add_key */ { 0, (sy_call_t *)linux_request_key, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 287 = linux_request_key */ { 0, (sy_call_t *)linux_keyctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 288 = linux_keyctl */ { 0, (sy_call_t *)linux_ioprio_set, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 289 = linux_ioprio_set */ { 0, (sy_call_t *)linux_ioprio_get, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 290 = linux_ioprio_get */ { 0, (sy_call_t *)linux_inotify_init, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 291 = linux_inotify_init */ { 0, (sy_call_t *)linux_inotify_add_watch, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 292 = linux_inotify_add_watch */ { 0, (sy_call_t *)linux_inotify_rm_watch, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 293 = linux_inotify_rm_watch */ { 0, (sy_call_t *)linux_migrate_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 294 = linux_migrate_pages */ { AS(linux_openat_args), (sy_call_t *)linux_openat, AUE_OPEN_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 295 = linux_openat */ { AS(linux_mkdirat_args), (sy_call_t *)linux_mkdirat, AUE_MKDIRAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 296 = linux_mkdirat */ { AS(linux_mknodat_args), (sy_call_t *)linux_mknodat, AUE_MKNODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 297 = linux_mknodat */ { AS(linux_fchownat_args), (sy_call_t *)linux_fchownat, AUE_FCHOWNAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 298 = linux_fchownat */ { AS(linux_futimesat_args), (sy_call_t *)linux_futimesat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 299 = linux_futimesat */ { AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_FSTATAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 300 = linux_fstatat64 */ { AS(linux_unlinkat_args), (sy_call_t *)linux_unlinkat, AUE_UNLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 301 = linux_unlinkat */ { AS(linux_renameat_args), (sy_call_t *)linux_renameat, AUE_RENAMEAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 302 = linux_renameat */ { AS(linux_linkat_args), (sy_call_t *)linux_linkat, AUE_LINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 303 = linux_linkat */ { AS(linux_symlinkat_args), (sy_call_t *)linux_symlinkat, AUE_SYMLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 304 = linux_symlinkat */ { AS(linux_readlinkat_args), (sy_call_t *)linux_readlinkat, AUE_READLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 305 = linux_readlinkat */ { AS(linux_fchmodat_args), (sy_call_t *)linux_fchmodat, AUE_FCHMODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 306 = linux_fchmodat */ { AS(linux_faccessat_args), (sy_call_t *)linux_faccessat, AUE_FACCESSAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 307 = linux_faccessat */ { AS(linux_pselect6_args), (sy_call_t *)linux_pselect6, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 308 = linux_pselect6 */ { AS(linux_ppoll_args), (sy_call_t *)linux_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 309 = linux_ppoll */ { 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 310 = linux_unshare */ { AS(linux_set_robust_list_args), (sy_call_t *)linux_set_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 311 = linux_set_robust_list */ { AS(linux_get_robust_list_args), (sy_call_t *)linux_get_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 312 = linux_get_robust_list */ { 0, (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 313 = linux_splice */ { 0, (sy_call_t *)linux_sync_file_range, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 314 = linux_sync_file_range */ { 0, (sy_call_t *)linux_tee, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 315 = linux_tee */ { 0, (sy_call_t *)linux_vmsplice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 316 = linux_vmsplice */ { 0, (sy_call_t *)linux_move_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 317 = linux_move_pages */ { 0, (sy_call_t *)linux_getcpu, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 318 = linux_getcpu */ { AS(linux_epoll_pwait_args), (sy_call_t *)linux_epoll_pwait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 319 = linux_epoll_pwait */ { AS(linux_utimensat_args), (sy_call_t *)linux_utimensat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 320 = linux_utimensat */ { 0, (sy_call_t *)linux_signalfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 321 = linux_signalfd */ { 0, (sy_call_t *)linux_timerfd_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 322 = linux_timerfd_create */ { AS(linux_eventfd_args), (sy_call_t *)linux_eventfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 323 = linux_eventfd */ { AS(linux_fallocate_args), (sy_call_t *)linux_fallocate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 324 = linux_fallocate */ { 0, (sy_call_t *)linux_timerfd_settime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 325 = linux_timerfd_settime */ { 0, (sy_call_t *)linux_timerfd_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 326 = linux_timerfd_gettime */ { 0, (sy_call_t *)linux_signalfd4, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 327 = linux_signalfd4 */ { AS(linux_eventfd2_args), (sy_call_t *)linux_eventfd2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 328 = linux_eventfd2 */ { AS(linux_epoll_create1_args), (sy_call_t *)linux_epoll_create1, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 329 = linux_epoll_create1 */ { AS(linux_dup3_args), (sy_call_t *)linux_dup3, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 330 = linux_dup3 */ { AS(linux_pipe2_args), (sy_call_t *)linux_pipe2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 331 = linux_pipe2 */ { 0, (sy_call_t *)linux_inotify_init1, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 332 = linux_inotify_init1 */ - { 0, (sy_call_t *)linux_preadv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 333 = linux_preadv */ - { 0, (sy_call_t *)linux_pwritev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 334 = linux_pwritev */ - { 0, (sy_call_t *)linux_rt_tsigqueueinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 335 = linux_rt_tsigqueueinfo */ + { AS(linux_preadv_args), (sy_call_t *)linux_preadv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 333 = linux_preadv */ + { AS(linux_pwritev_args), (sy_call_t *)linux_pwritev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 334 = linux_pwritev */ + { AS(linux_rt_tgsigqueueinfo_args), (sy_call_t *)linux_rt_tgsigqueueinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 335 = linux_rt_tgsigqueueinfo */ { 0, (sy_call_t *)linux_perf_event_open, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 336 = linux_perf_event_open */ { AS(linux_recvmmsg_args), (sy_call_t *)linux_recvmmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 337 = linux_recvmmsg */ { 0, (sy_call_t *)linux_fanotify_init, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 338 = linux_fanotify_init */ { 0, (sy_call_t *)linux_fanotify_mark, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 339 = linux_fanotify_mark */ { AS(linux_prlimit64_args), (sy_call_t *)linux_prlimit64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 340 = linux_prlimit64 */ { 0, (sy_call_t *)linux_name_to_handle_at, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 341 = linux_name_to_handle_at */ { 0, (sy_call_t *)linux_open_by_handle_at, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 342 = linux_open_by_handle_at */ { 0, (sy_call_t *)linux_clock_adjtime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 343 = linux_clock_adjtime */ { AS(linux_syncfs_args), (sy_call_t *)linux_syncfs, AUE_SYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 344 = linux_syncfs */ { AS(linux_sendmmsg_args), (sy_call_t *)linux_sendmmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 345 = linux_sendmmsg */ { 0, (sy_call_t *)linux_setns, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 346 = linux_setns */ - { 0, (sy_call_t *)linux_process_vm_readv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 347 = linux_process_vm_readv */ - { 0, (sy_call_t *)linux_process_vm_writev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 348 = linux_process_vm_writev */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 349 = nosys */ + { AS(linux_process_vm_readv_args), (sy_call_t *)linux_process_vm_readv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 347 = linux_process_vm_readv */ + { AS(linux_process_vm_writev_args), (sy_call_t *)linux_process_vm_writev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 348 = linux_process_vm_writev */ + { AS(linux_kcmp_args), (sy_call_t *)linux_kcmp, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 349 = linux_kcmp */ + { AS(linux_finit_module_args), (sy_call_t *)linux_finit_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 350 = linux_finit_module */ + { AS(linux_sched_setattr_args), (sy_call_t *)linux_sched_setattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 351 = linux_sched_setattr */ + { AS(linux_sched_getattr_args), (sy_call_t *)linux_sched_getattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 352 = linux_sched_getattr */ + { AS(linux_renameat2_args), (sy_call_t *)linux_renameat2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 353 = linux_renameat2 */ + { AS(linux_seccomp_args), (sy_call_t *)linux_seccomp, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 354 = linux_seccomp */ + { AS(linux_getrandom_args), (sy_call_t *)linux_getrandom, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 355 = linux_getrandom */ + { AS(linux_memfd_create_args), (sy_call_t *)linux_memfd_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 356 = linux_memfd_create */ + { AS(linux_bpf_args), (sy_call_t *)linux_bpf, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 357 = linux_bpf */ + { AS(linux_execveat_args), (sy_call_t *)linux_execveat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 358 = linux_execveat */ + { AS(linux_socket_args), (sy_call_t *)linux_socket, AUE_SOCKET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 359 = linux_socket */ + { AS(linux_socketpair_args), (sy_call_t *)linux_socketpair, AUE_SOCKETPAIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 360 = linux_socketpair */ + { AS(linux_bind_args), (sy_call_t *)linux_bind, AUE_BIND, NULL, 0, 0, 0, SY_THR_STATIC }, /* 361 = linux_bind */ + { AS(linux_connect_args), (sy_call_t *)linux_connect, AUE_CONNECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 362 = linux_connect */ + { AS(linux_listen_args), (sy_call_t *)linux_listen, AUE_LISTEN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 363 = linux_listen */ + { AS(linux_accept4_args), (sy_call_t *)linux_accept4, AUE_ACCEPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 364 = linux_accept4 */ + { AS(linux_getsockopt_args), (sy_call_t *)linux_getsockopt, AUE_GETSOCKOPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 365 = linux_getsockopt */ + { AS(linux_setsockopt_args), (sy_call_t *)linux_setsockopt, AUE_SETSOCKOPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 366 = linux_setsockopt */ + { AS(linux_getsockname_args), (sy_call_t *)linux_getsockname, AUE_GETSOCKNAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 367 = linux_getsockname */ + { AS(linux_getpeername_args), (sy_call_t *)linux_getpeername, AUE_GETPEERNAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 368 = linux_getpeername */ + { AS(linux_sendto_args), (sy_call_t *)linux_sendto, AUE_SENDTO, NULL, 0, 0, 0, SY_THR_STATIC }, /* 369 = linux_sendto */ + { AS(linux_sendmsg_args), (sy_call_t *)linux_sendmsg, AUE_SENDMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 370 = linux_sendmsg */ + { AS(linux_recvfrom_args), (sy_call_t *)linux_recvfrom, AUE_RECVFROM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 371 = linux_recvfrom */ + { AS(linux_recvmsg_args), (sy_call_t *)linux_recvmsg, AUE_RECVMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 372 = linux_recvmsg */ + { AS(linux_shutdown_args), (sy_call_t *)linux_shutdown, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 373 = linux_shutdown */ + { AS(linux_userfaultfd_args), (sy_call_t *)linux_userfaultfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 374 = linux_userfaultfd */ + { AS(linux_membarrier_args), (sy_call_t *)linux_membarrier, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 375 = linux_membarrier */ + { AS(linux_mlock2_args), (sy_call_t *)linux_mlock2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 376 = linux_mlock2 */ + { AS(linux_copy_file_range_args), (sy_call_t *)linux_copy_file_range, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 377 = linux_copy_file_range */ + { AS(linux_preadv2_args), (sy_call_t *)linux_preadv2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 378 = linux_preadv2 */ + { AS(linux_pwritev2_args), (sy_call_t *)linux_pwritev2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 379 = linux_pwritev2 */ + { AS(linux_pkey_mprotect_args), (sy_call_t *)linux_pkey_mprotect, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 380 = linux_pkey_mprotect */ + { AS(linux_pkey_alloc_args), (sy_call_t *)linux_pkey_alloc, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 381 = linux_pkey_alloc */ + { AS(linux_pkey_free_args), (sy_call_t *)linux_pkey_free, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 382 = linux_pkey_free */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 383 = nosys */ }; Index: projects/ipsec/sys/amd64/linux32/linux32_systrace_args.c =================================================================== --- projects/ipsec/sys/amd64/linux32/linux32_systrace_args.c (revision 313312) +++ projects/ipsec/sys/amd64/linux32/linux32_systrace_args.c (revision 313313) @@ -1,7159 +1,8403 @@ /* * System call argument to DTrace register array converstion. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ * This file is part of the DTrace syscall provider. */ static void systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) { int64_t *iarg = (int64_t *) uarg; switch (sysnum) { #define nosys linux_nosys /* linux_exit */ case 1: { struct linux_exit_args *p = params; iarg[0] = p->rval; /* int */ *n_args = 1; break; } /* linux_fork */ case 2: { *n_args = 0; break; } /* read */ case 3: { struct read_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->buf; /* char * */ uarg[2] = p->nbyte; /* u_int */ *n_args = 3; break; } /* write */ case 4: { struct write_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->buf; /* char * */ uarg[2] = p->nbyte; /* u_int */ *n_args = 3; break; } /* linux_open */ case 5: { struct linux_open_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->flags; /* l_int */ iarg[2] = p->mode; /* l_int */ *n_args = 3; break; } /* close */ case 6: { struct close_args *p = params; iarg[0] = p->fd; /* int */ *n_args = 1; break; } /* linux_waitpid */ case 7: { struct linux_waitpid_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->status; /* l_int * */ iarg[2] = p->options; /* l_int */ *n_args = 3; break; } /* linux_creat */ case 8: { struct linux_creat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_int */ *n_args = 2; break; } /* linux_link */ case 9: { struct linux_link_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->to; /* char * */ *n_args = 2; break; } /* linux_unlink */ case 10: { struct linux_unlink_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_execve */ case 11: { struct linux_execve_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->argp; /* uint32_t * */ uarg[2] = (intptr_t) p->envp; /* uint32_t * */ *n_args = 3; break; } /* linux_chdir */ case 12: { struct linux_chdir_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_time */ case 13: { struct linux_time_args *p = params; uarg[0] = (intptr_t) p->tm; /* l_time_t * */ *n_args = 1; break; } /* linux_mknod */ case 14: { struct linux_mknod_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_int */ iarg[2] = p->dev; /* l_dev_t */ *n_args = 3; break; } /* linux_chmod */ case 15: { struct linux_chmod_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_mode_t */ *n_args = 2; break; } /* linux_lchown16 */ case 16: { struct linux_lchown16_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid16_t */ iarg[2] = p->gid; /* l_gid16_t */ *n_args = 3; break; } /* linux_stat */ case 18: { struct linux_stat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->up; /* struct linux_stat * */ *n_args = 2; break; } /* linux_lseek */ case 19: { struct linux_lseek_args *p = params; iarg[0] = p->fdes; /* l_uint */ iarg[1] = p->off; /* l_off_t */ iarg[2] = p->whence; /* l_int */ *n_args = 3; break; } /* linux_getpid */ case 20: { *n_args = 0; break; } /* linux_mount */ case 21: { struct linux_mount_args *p = params; uarg[0] = (intptr_t) p->specialfile; /* char * */ uarg[1] = (intptr_t) p->dir; /* char * */ uarg[2] = (intptr_t) p->filesystemtype; /* char * */ iarg[3] = p->rwflag; /* l_ulong */ uarg[4] = (intptr_t) p->data; /* void * */ *n_args = 5; break; } /* linux_oldumount */ case 22: { struct linux_oldumount_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_setuid16 */ case 23: { struct linux_setuid16_args *p = params; iarg[0] = p->uid; /* l_uid16_t */ *n_args = 1; break; } /* linux_getuid16 */ case 24: { *n_args = 0; break; } /* linux_stime */ case 25: { *n_args = 0; break; } /* linux_ptrace */ case 26: { struct linux_ptrace_args *p = params; iarg[0] = p->req; /* l_long */ iarg[1] = p->pid; /* l_long */ iarg[2] = p->addr; /* l_long */ iarg[3] = p->data; /* l_long */ *n_args = 4; break; } /* linux_alarm */ case 27: { struct linux_alarm_args *p = params; iarg[0] = p->secs; /* l_uint */ *n_args = 1; break; } /* linux_pause */ case 29: { *n_args = 0; break; } /* linux_utime */ case 30: { struct linux_utime_args *p = params; uarg[0] = (intptr_t) p->fname; /* char * */ uarg[1] = (intptr_t) p->times; /* struct l_utimbuf * */ *n_args = 2; break; } /* linux_access */ case 33: { struct linux_access_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->amode; /* l_int */ *n_args = 2; break; } /* linux_nice */ case 34: { struct linux_nice_args *p = params; iarg[0] = p->inc; /* l_int */ *n_args = 1; break; } /* sync */ case 36: { *n_args = 0; break; } /* linux_kill */ case 37: { struct linux_kill_args *p = params; iarg[0] = p->pid; /* l_int */ iarg[1] = p->signum; /* l_int */ *n_args = 2; break; } /* linux_rename */ case 38: { struct linux_rename_args *p = params; uarg[0] = (intptr_t) p->from; /* char * */ uarg[1] = (intptr_t) p->to; /* char * */ *n_args = 2; break; } /* linux_mkdir */ case 39: { struct linux_mkdir_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_int */ *n_args = 2; break; } /* linux_rmdir */ case 40: { struct linux_rmdir_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* dup */ case 41: { struct dup_args *p = params; uarg[0] = p->fd; /* u_int */ *n_args = 1; break; } /* linux_pipe */ case 42: { struct linux_pipe_args *p = params; uarg[0] = (intptr_t) p->pipefds; /* l_int * */ *n_args = 1; break; } /* linux_times */ case 43: { struct linux_times_args *p = params; uarg[0] = (intptr_t) p->buf; /* struct l_times_argv * */ *n_args = 1; break; } /* linux_brk */ case 45: { struct linux_brk_args *p = params; iarg[0] = p->dsend; /* l_ulong */ *n_args = 1; break; } /* linux_setgid16 */ case 46: { struct linux_setgid16_args *p = params; iarg[0] = p->gid; /* l_gid16_t */ *n_args = 1; break; } /* linux_getgid16 */ case 47: { *n_args = 0; break; } /* linux_signal */ case 48: { struct linux_signal_args *p = params; iarg[0] = p->sig; /* l_int */ iarg[1] = p->handler; /* l_handler_t */ *n_args = 2; break; } /* linux_geteuid16 */ case 49: { *n_args = 0; break; } /* linux_getegid16 */ case 50: { *n_args = 0; break; } /* acct */ case 51: { struct acct_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_umount */ case 52: { struct linux_umount_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->flags; /* l_int */ *n_args = 2; break; } /* linux_ioctl */ case 54: { struct linux_ioctl_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->cmd; /* l_uint */ uarg[2] = p->arg; /* uintptr_t */ *n_args = 3; break; } /* linux_fcntl */ case 55: { struct linux_fcntl_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->cmd; /* l_uint */ uarg[2] = p->arg; /* uintptr_t */ *n_args = 3; break; } /* setpgid */ case 57: { struct setpgid_args *p = params; iarg[0] = p->pid; /* int */ iarg[1] = p->pgid; /* int */ *n_args = 2; break; } /* linux_olduname */ case 59: { *n_args = 0; break; } /* umask */ case 60: { struct umask_args *p = params; iarg[0] = p->newmask; /* int */ *n_args = 1; break; } /* chroot */ case 61: { struct chroot_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_ustat */ case 62: { struct linux_ustat_args *p = params; iarg[0] = p->dev; /* l_dev_t */ uarg[1] = (intptr_t) p->ubuf; /* struct l_ustat * */ *n_args = 2; break; } /* dup2 */ case 63: { struct dup2_args *p = params; uarg[0] = p->from; /* u_int */ uarg[1] = p->to; /* u_int */ *n_args = 2; break; } /* linux_getppid */ case 64: { *n_args = 0; break; } /* getpgrp */ case 65: { *n_args = 0; break; } /* setsid */ case 66: { *n_args = 0; break; } /* linux_sigaction */ case 67: { struct linux_sigaction_args *p = params; iarg[0] = p->sig; /* l_int */ uarg[1] = (intptr_t) p->nsa; /* l_osigaction_t * */ uarg[2] = (intptr_t) p->osa; /* l_osigaction_t * */ *n_args = 3; break; } /* linux_sgetmask */ case 68: { *n_args = 0; break; } /* linux_ssetmask */ case 69: { struct linux_ssetmask_args *p = params; iarg[0] = p->mask; /* l_osigset_t */ *n_args = 1; break; } /* linux_setreuid16 */ case 70: { struct linux_setreuid16_args *p = params; iarg[0] = p->ruid; /* l_uid16_t */ iarg[1] = p->euid; /* l_uid16_t */ *n_args = 2; break; } /* linux_setregid16 */ case 71: { struct linux_setregid16_args *p = params; iarg[0] = p->rgid; /* l_gid16_t */ iarg[1] = p->egid; /* l_gid16_t */ *n_args = 2; break; } /* linux_sigsuspend */ case 72: { struct linux_sigsuspend_args *p = params; iarg[0] = p->hist0; /* l_int */ iarg[1] = p->hist1; /* l_int */ iarg[2] = p->mask; /* l_osigset_t */ *n_args = 3; break; } /* linux_sigpending */ case 73: { struct linux_sigpending_args *p = params; uarg[0] = (intptr_t) p->mask; /* l_osigset_t * */ *n_args = 1; break; } /* linux_sethostname */ case 74: { struct linux_sethostname_args *p = params; uarg[0] = (intptr_t) p->hostname; /* char * */ uarg[1] = p->len; /* u_int */ *n_args = 2; break; } /* linux_setrlimit */ case 75: { struct linux_setrlimit_args *p = params; iarg[0] = p->resource; /* l_uint */ uarg[1] = (intptr_t) p->rlim; /* struct l_rlimit * */ *n_args = 2; break; } /* linux_old_getrlimit */ case 76: { struct linux_old_getrlimit_args *p = params; iarg[0] = p->resource; /* l_uint */ uarg[1] = (intptr_t) p->rlim; /* struct l_rlimit * */ *n_args = 2; break; } /* linux_getrusage */ case 77: { struct linux_getrusage_args *p = params; iarg[0] = p->who; /* int */ uarg[1] = (intptr_t) p->rusage; /* struct l_rusage * */ *n_args = 2; break; } /* linux_gettimeofday */ case 78: { struct linux_gettimeofday_args *p = params; uarg[0] = (intptr_t) p->tp; /* struct l_timeval * */ uarg[1] = (intptr_t) p->tzp; /* struct timezone * */ *n_args = 2; break; } /* linux_settimeofday */ case 79: { struct linux_settimeofday_args *p = params; uarg[0] = (intptr_t) p->tp; /* struct l_timeval * */ uarg[1] = (intptr_t) p->tzp; /* struct timezone * */ *n_args = 2; break; } /* linux_getgroups16 */ case 80: { struct linux_getgroups16_args *p = params; iarg[0] = p->gidsetsize; /* l_uint */ uarg[1] = (intptr_t) p->gidset; /* l_gid16_t * */ *n_args = 2; break; } /* linux_setgroups16 */ case 81: { struct linux_setgroups16_args *p = params; iarg[0] = p->gidsetsize; /* l_uint */ uarg[1] = (intptr_t) p->gidset; /* l_gid16_t * */ *n_args = 2; break; } /* linux_old_select */ case 82: { struct linux_old_select_args *p = params; uarg[0] = (intptr_t) p->ptr; /* struct l_old_select_argv * */ *n_args = 1; break; } /* linux_symlink */ case 83: { struct linux_symlink_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->to; /* char * */ *n_args = 2; break; } /* linux_lstat */ case 84: { struct linux_lstat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->up; /* struct linux_lstat * */ *n_args = 2; break; } /* linux_readlink */ case 85: { struct linux_readlink_args *p = params; uarg[0] = (intptr_t) p->name; /* char * */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->count; /* l_int */ *n_args = 3; break; } /* swapon */ case 87: { struct swapon_args *p = params; uarg[0] = (intptr_t) p->name; /* char * */ *n_args = 1; break; } /* linux_reboot */ case 88: { struct linux_reboot_args *p = params; iarg[0] = p->magic1; /* l_int */ iarg[1] = p->magic2; /* l_int */ iarg[2] = p->cmd; /* l_uint */ uarg[3] = (intptr_t) p->arg; /* void * */ *n_args = 4; break; } /* linux_readdir */ case 89: { struct linux_readdir_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->dent; /* struct l_dirent * */ iarg[2] = p->count; /* l_uint */ *n_args = 3; break; } /* linux_mmap */ case 90: { struct linux_mmap_args *p = params; uarg[0] = (intptr_t) p->ptr; /* struct l_mmap_argv * */ *n_args = 1; break; } /* munmap */ case 91: { struct munmap_args *p = params; uarg[0] = (intptr_t) p->addr; /* caddr_t */ iarg[1] = p->len; /* int */ *n_args = 2; break; } /* linux_truncate */ case 92: { struct linux_truncate_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->length; /* l_ulong */ *n_args = 2; break; } /* linux_ftruncate */ case 93: { struct linux_ftruncate_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->length; /* long */ *n_args = 2; break; } /* fchmod */ case 94: { struct fchmod_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->mode; /* int */ *n_args = 2; break; } /* fchown */ case 95: { struct fchown_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->uid; /* int */ iarg[2] = p->gid; /* int */ *n_args = 3; break; } /* linux_getpriority */ case 96: { struct linux_getpriority_args *p = params; iarg[0] = p->which; /* int */ iarg[1] = p->who; /* int */ *n_args = 2; break; } /* setpriority */ case 97: { struct setpriority_args *p = params; iarg[0] = p->which; /* int */ iarg[1] = p->who; /* int */ iarg[2] = p->prio; /* int */ *n_args = 3; break; } /* linux_statfs */ case 99: { struct linux_statfs_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->buf; /* struct l_statfs_buf * */ *n_args = 2; break; } /* linux_fstatfs */ case 100: { struct linux_fstatfs_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* struct l_statfs_buf * */ *n_args = 2; break; } /* linux_socketcall */ case 102: { struct linux_socketcall_args *p = params; iarg[0] = p->what; /* l_int */ iarg[1] = p->args; /* l_ulong */ *n_args = 2; break; } /* linux_syslog */ case 103: { struct linux_syslog_args *p = params; iarg[0] = p->type; /* l_int */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->len; /* l_int */ *n_args = 3; break; } /* linux_setitimer */ case 104: { struct linux_setitimer_args *p = params; iarg[0] = p->which; /* l_int */ uarg[1] = (intptr_t) p->itv; /* struct l_itimerval * */ uarg[2] = (intptr_t) p->oitv; /* struct l_itimerval * */ *n_args = 3; break; } /* linux_getitimer */ case 105: { struct linux_getitimer_args *p = params; iarg[0] = p->which; /* l_int */ uarg[1] = (intptr_t) p->itv; /* struct l_itimerval * */ *n_args = 2; break; } /* linux_newstat */ case 106: { struct linux_newstat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->buf; /* struct l_newstat * */ *n_args = 2; break; } /* linux_newlstat */ case 107: { struct linux_newlstat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->buf; /* struct l_newstat * */ *n_args = 2; break; } /* linux_newfstat */ case 108: { struct linux_newfstat_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* struct l_newstat * */ *n_args = 2; break; } /* linux_uname */ case 109: { *n_args = 0; break; } /* linux_iopl */ case 110: { struct linux_iopl_args *p = params; iarg[0] = p->level; /* l_int */ *n_args = 1; break; } /* linux_vhangup */ case 111: { *n_args = 0; break; } /* linux_wait4 */ case 114: { struct linux_wait4_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->status; /* l_int * */ iarg[2] = p->options; /* l_int */ uarg[3] = (intptr_t) p->rusage; /* struct l_rusage * */ *n_args = 4; break; } /* linux_swapoff */ case 115: { *n_args = 0; break; } /* linux_sysinfo */ case 116: { struct linux_sysinfo_args *p = params; uarg[0] = (intptr_t) p->info; /* struct l_sysinfo * */ *n_args = 1; break; } /* linux_ipc */ case 117: { struct linux_ipc_args *p = params; iarg[0] = p->what; /* l_uint */ iarg[1] = p->arg1; /* l_int */ iarg[2] = p->arg2; /* l_int */ iarg[3] = p->arg3; /* l_int */ uarg[4] = (intptr_t) p->ptr; /* void * */ iarg[5] = p->arg5; /* l_long */ *n_args = 6; break; } /* fsync */ case 118: { struct fsync_args *p = params; iarg[0] = p->fd; /* int */ *n_args = 1; break; } /* linux_sigreturn */ case 119: { struct linux_sigreturn_args *p = params; uarg[0] = (intptr_t) p->sfp; /* struct l_sigframe * */ *n_args = 1; break; } /* linux_clone */ case 120: { struct linux_clone_args *p = params; iarg[0] = p->flags; /* l_int */ uarg[1] = (intptr_t) p->stack; /* void * */ uarg[2] = (intptr_t) p->parent_tidptr; /* void * */ uarg[3] = (intptr_t) p->tls; /* void * */ uarg[4] = (intptr_t) p->child_tidptr; /* void * */ *n_args = 5; break; } /* linux_setdomainname */ case 121: { struct linux_setdomainname_args *p = params; uarg[0] = (intptr_t) p->name; /* char * */ iarg[1] = p->len; /* int */ *n_args = 2; break; } /* linux_newuname */ case 122: { struct linux_newuname_args *p = params; uarg[0] = (intptr_t) p->buf; /* struct l_new_utsname * */ *n_args = 1; break; } /* linux_adjtimex */ case 124: { *n_args = 0; break; } /* linux_mprotect */ case 125: { struct linux_mprotect_args *p = params; uarg[0] = (intptr_t) p->addr; /* caddr_t */ iarg[1] = p->len; /* int */ iarg[2] = p->prot; /* int */ *n_args = 3; break; } /* linux_sigprocmask */ case 126: { struct linux_sigprocmask_args *p = params; iarg[0] = p->how; /* l_int */ uarg[1] = (intptr_t) p->mask; /* l_osigset_t * */ uarg[2] = (intptr_t) p->omask; /* l_osigset_t * */ *n_args = 3; break; } /* linux_create_module */ case 127: { *n_args = 0; break; } /* linux_init_module */ case 128: { *n_args = 0; break; } /* linux_delete_module */ case 129: { *n_args = 0; break; } /* linux_get_kernel_syms */ case 130: { *n_args = 0; break; } /* linux_quotactl */ case 131: { *n_args = 0; break; } /* getpgid */ case 132: { struct getpgid_args *p = params; iarg[0] = p->pid; /* int */ *n_args = 1; break; } /* fchdir */ case 133: { struct fchdir_args *p = params; iarg[0] = p->fd; /* int */ *n_args = 1; break; } /* linux_bdflush */ case 134: { *n_args = 0; break; } /* linux_sysfs */ case 135: { struct linux_sysfs_args *p = params; iarg[0] = p->option; /* l_int */ iarg[1] = p->arg1; /* l_ulong */ iarg[2] = p->arg2; /* l_ulong */ *n_args = 3; break; } /* linux_personality */ case 136: { struct linux_personality_args *p = params; iarg[0] = p->per; /* l_uint */ *n_args = 1; break; } /* linux_setfsuid16 */ case 138: { struct linux_setfsuid16_args *p = params; iarg[0] = p->uid; /* l_uid16_t */ *n_args = 1; break; } /* linux_setfsgid16 */ case 139: { struct linux_setfsgid16_args *p = params; iarg[0] = p->gid; /* l_gid16_t */ *n_args = 1; break; } /* linux_llseek */ case 140: { struct linux_llseek_args *p = params; iarg[0] = p->fd; /* l_int */ iarg[1] = p->ohigh; /* l_ulong */ iarg[2] = p->olow; /* l_ulong */ uarg[3] = (intptr_t) p->res; /* l_loff_t * */ iarg[4] = p->whence; /* l_uint */ *n_args = 5; break; } /* linux_getdents */ case 141: { struct linux_getdents_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->dent; /* void * */ iarg[2] = p->count; /* l_uint */ *n_args = 3; break; } /* linux_select */ case 142: { struct linux_select_args *p = params; iarg[0] = p->nfds; /* l_int */ uarg[1] = (intptr_t) p->readfds; /* l_fd_set * */ uarg[2] = (intptr_t) p->writefds; /* l_fd_set * */ uarg[3] = (intptr_t) p->exceptfds; /* l_fd_set * */ uarg[4] = (intptr_t) p->timeout; /* struct l_timeval * */ *n_args = 5; break; } /* flock */ case 143: { struct flock_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->how; /* int */ *n_args = 2; break; } /* linux_msync */ case 144: { struct linux_msync_args *p = params; iarg[0] = p->addr; /* l_ulong */ iarg[1] = p->len; /* l_size_t */ iarg[2] = p->fl; /* l_int */ *n_args = 3; break; } /* linux_readv */ case 145: { struct linux_readv_args *p = params; iarg[0] = p->fd; /* l_ulong */ uarg[1] = (intptr_t) p->iovp; /* struct l_iovec32 * */ iarg[2] = p->iovcnt; /* l_ulong */ *n_args = 3; break; } /* linux_writev */ case 146: { struct linux_writev_args *p = params; iarg[0] = p->fd; /* l_ulong */ uarg[1] = (intptr_t) p->iovp; /* struct l_iovec32 * */ iarg[2] = p->iovcnt; /* l_ulong */ *n_args = 3; break; } /* linux_getsid */ case 147: { struct linux_getsid_args *p = params; iarg[0] = p->pid; /* l_pid_t */ *n_args = 1; break; } /* linux_fdatasync */ case 148: { struct linux_fdatasync_args *p = params; iarg[0] = p->fd; /* l_uint */ *n_args = 1; break; } /* linux_sysctl */ case 149: { struct linux_sysctl_args *p = params; uarg[0] = (intptr_t) p->args; /* struct l___sysctl_args * */ *n_args = 1; break; } /* mlock */ case 150: { struct mlock_args *p = params; uarg[0] = (intptr_t) p->addr; /* const void * */ uarg[1] = p->len; /* size_t */ *n_args = 2; break; } /* munlock */ case 151: { struct munlock_args *p = params; uarg[0] = (intptr_t) p->addr; /* const void * */ uarg[1] = p->len; /* size_t */ *n_args = 2; break; } /* mlockall */ case 152: { struct mlockall_args *p = params; iarg[0] = p->how; /* int */ *n_args = 1; break; } /* munlockall */ case 153: { *n_args = 0; break; } /* linux_sched_setparam */ case 154: { struct linux_sched_setparam_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->param; /* struct sched_param * */ *n_args = 2; break; } /* linux_sched_getparam */ case 155: { struct linux_sched_getparam_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->param; /* struct sched_param * */ *n_args = 2; break; } /* linux_sched_setscheduler */ case 156: { struct linux_sched_setscheduler_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->policy; /* l_int */ uarg[2] = (intptr_t) p->param; /* struct sched_param * */ *n_args = 3; break; } /* linux_sched_getscheduler */ case 157: { struct linux_sched_getscheduler_args *p = params; iarg[0] = p->pid; /* l_pid_t */ *n_args = 1; break; } /* sched_yield */ case 158: { *n_args = 0; break; } /* linux_sched_get_priority_max */ case 159: { struct linux_sched_get_priority_max_args *p = params; iarg[0] = p->policy; /* l_int */ *n_args = 1; break; } /* linux_sched_get_priority_min */ case 160: { struct linux_sched_get_priority_min_args *p = params; iarg[0] = p->policy; /* l_int */ *n_args = 1; break; } /* linux_sched_rr_get_interval */ case 161: { struct linux_sched_rr_get_interval_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->interval; /* struct l_timespec * */ *n_args = 2; break; } /* linux_nanosleep */ case 162: { struct linux_nanosleep_args *p = params; uarg[0] = (intptr_t) p->rqtp; /* const struct l_timespec * */ uarg[1] = (intptr_t) p->rmtp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_mremap */ case 163: { struct linux_mremap_args *p = params; iarg[0] = p->addr; /* l_ulong */ iarg[1] = p->old_len; /* l_ulong */ iarg[2] = p->new_len; /* l_ulong */ iarg[3] = p->flags; /* l_ulong */ iarg[4] = p->new_addr; /* l_ulong */ *n_args = 5; break; } /* linux_setresuid16 */ case 164: { struct linux_setresuid16_args *p = params; iarg[0] = p->ruid; /* l_uid16_t */ iarg[1] = p->euid; /* l_uid16_t */ iarg[2] = p->suid; /* l_uid16_t */ *n_args = 3; break; } /* linux_getresuid16 */ case 165: { struct linux_getresuid16_args *p = params; uarg[0] = (intptr_t) p->ruid; /* l_uid16_t * */ uarg[1] = (intptr_t) p->euid; /* l_uid16_t * */ uarg[2] = (intptr_t) p->suid; /* l_uid16_t * */ *n_args = 3; break; } /* linux_query_module */ case 167: { *n_args = 0; break; } /* poll */ case 168: { struct poll_args *p = params; uarg[0] = (intptr_t) p->fds; /* struct pollfd * */ uarg[1] = p->nfds; /* unsigned int */ iarg[2] = p->timeout; /* int */ *n_args = 3; break; } /* linux_nfsservctl */ case 169: { *n_args = 0; break; } /* linux_setresgid16 */ case 170: { struct linux_setresgid16_args *p = params; iarg[0] = p->rgid; /* l_gid16_t */ iarg[1] = p->egid; /* l_gid16_t */ iarg[2] = p->sgid; /* l_gid16_t */ *n_args = 3; break; } /* linux_getresgid16 */ case 171: { struct linux_getresgid16_args *p = params; uarg[0] = (intptr_t) p->rgid; /* l_gid16_t * */ uarg[1] = (intptr_t) p->egid; /* l_gid16_t * */ uarg[2] = (intptr_t) p->sgid; /* l_gid16_t * */ *n_args = 3; break; } /* linux_prctl */ case 172: { struct linux_prctl_args *p = params; iarg[0] = p->option; /* l_int */ iarg[1] = p->arg2; /* l_int */ iarg[2] = p->arg3; /* l_int */ iarg[3] = p->arg4; /* l_int */ iarg[4] = p->arg5; /* l_int */ *n_args = 5; break; } /* linux_rt_sigreturn */ case 173: { struct linux_rt_sigreturn_args *p = params; uarg[0] = (intptr_t) p->ucp; /* struct l_ucontext * */ *n_args = 1; break; } /* linux_rt_sigaction */ case 174: { struct linux_rt_sigaction_args *p = params; iarg[0] = p->sig; /* l_int */ uarg[1] = (intptr_t) p->act; /* l_sigaction_t * */ uarg[2] = (intptr_t) p->oact; /* l_sigaction_t * */ iarg[3] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; } /* linux_rt_sigprocmask */ case 175: { struct linux_rt_sigprocmask_args *p = params; iarg[0] = p->how; /* l_int */ uarg[1] = (intptr_t) p->mask; /* l_sigset_t * */ uarg[2] = (intptr_t) p->omask; /* l_sigset_t * */ iarg[3] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; } /* linux_rt_sigpending */ case 176: { struct linux_rt_sigpending_args *p = params; uarg[0] = (intptr_t) p->set; /* l_sigset_t * */ iarg[1] = p->sigsetsize; /* l_size_t */ *n_args = 2; break; } /* linux_rt_sigtimedwait */ case 177: { struct linux_rt_sigtimedwait_args *p = params; uarg[0] = (intptr_t) p->mask; /* l_sigset_t * */ uarg[1] = (intptr_t) p->ptr; /* l_siginfo_t * */ uarg[2] = (intptr_t) p->timeout; /* struct l_timeval * */ iarg[3] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; } /* linux_rt_sigqueueinfo */ case 178: { struct linux_rt_sigqueueinfo_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->sig; /* l_int */ uarg[2] = (intptr_t) p->info; /* l_siginfo_t * */ *n_args = 3; break; } /* linux_rt_sigsuspend */ case 179: { struct linux_rt_sigsuspend_args *p = params; uarg[0] = (intptr_t) p->newset; /* l_sigset_t * */ iarg[1] = p->sigsetsize; /* l_size_t */ *n_args = 2; break; } /* linux_pread */ case 180: { struct linux_pread_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->nbyte; /* l_size_t */ iarg[3] = p->offset; /* l_loff_t */ *n_args = 4; break; } /* linux_pwrite */ case 181: { struct linux_pwrite_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->nbyte; /* l_size_t */ iarg[3] = p->offset; /* l_loff_t */ *n_args = 4; break; } /* linux_chown16 */ case 182: { struct linux_chown16_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid16_t */ iarg[2] = p->gid; /* l_gid16_t */ *n_args = 3; break; } /* linux_getcwd */ case 183: { struct linux_getcwd_args *p = params; uarg[0] = (intptr_t) p->buf; /* char * */ iarg[1] = p->bufsize; /* l_ulong */ *n_args = 2; break; } /* linux_capget */ case 184: { struct linux_capget_args *p = params; uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */ uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */ *n_args = 2; break; } /* linux_capset */ case 185: { struct linux_capset_args *p = params; uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */ uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */ *n_args = 2; break; } /* linux_sigaltstack */ case 186: { struct linux_sigaltstack_args *p = params; uarg[0] = (intptr_t) p->uss; /* l_stack_t * */ uarg[1] = (intptr_t) p->uoss; /* l_stack_t * */ *n_args = 2; break; } /* linux_sendfile */ case 187: { *n_args = 0; break; } /* linux_vfork */ case 190: { *n_args = 0; break; } /* linux_getrlimit */ case 191: { struct linux_getrlimit_args *p = params; iarg[0] = p->resource; /* l_uint */ uarg[1] = (intptr_t) p->rlim; /* struct l_rlimit * */ *n_args = 2; break; } /* linux_mmap2 */ case 192: { struct linux_mmap2_args *p = params; iarg[0] = p->addr; /* l_ulong */ iarg[1] = p->len; /* l_ulong */ iarg[2] = p->prot; /* l_ulong */ iarg[3] = p->flags; /* l_ulong */ iarg[4] = p->fd; /* l_ulong */ iarg[5] = p->pgoff; /* l_ulong */ *n_args = 6; break; } /* linux_truncate64 */ case 193: { struct linux_truncate64_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->length; /* l_loff_t */ *n_args = 2; break; } /* linux_ftruncate64 */ case 194: { struct linux_ftruncate64_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->length; /* l_loff_t */ *n_args = 2; break; } /* linux_stat64 */ case 195: { struct linux_stat64_args *p = params; uarg[0] = (intptr_t) p->filename; /* const char * */ uarg[1] = (intptr_t) p->statbuf; /* struct l_stat64 * */ *n_args = 2; break; } /* linux_lstat64 */ case 196: { struct linux_lstat64_args *p = params; uarg[0] = (intptr_t) p->filename; /* const char * */ uarg[1] = (intptr_t) p->statbuf; /* struct l_stat64 * */ *n_args = 2; break; } /* linux_fstat64 */ case 197: { struct linux_fstat64_args *p = params; iarg[0] = p->fd; /* l_int */ uarg[1] = (intptr_t) p->statbuf; /* struct l_stat64 * */ *n_args = 2; break; } /* linux_lchown */ case 198: { struct linux_lchown_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid_t */ iarg[2] = p->gid; /* l_gid_t */ *n_args = 3; break; } /* linux_getuid */ case 199: { *n_args = 0; break; } /* linux_getgid */ case 200: { *n_args = 0; break; } /* geteuid */ case 201: { *n_args = 0; break; } /* getegid */ case 202: { *n_args = 0; break; } /* setreuid */ case 203: { struct setreuid_args *p = params; uarg[0] = p->ruid; /* uid_t */ uarg[1] = p->euid; /* uid_t */ *n_args = 2; break; } /* setregid */ case 204: { struct setregid_args *p = params; iarg[0] = p->rgid; /* gid_t */ iarg[1] = p->egid; /* gid_t */ *n_args = 2; break; } /* linux_getgroups */ case 205: { struct linux_getgroups_args *p = params; iarg[0] = p->gidsetsize; /* l_int */ uarg[1] = (intptr_t) p->grouplist; /* l_gid_t * */ *n_args = 2; break; } /* linux_setgroups */ case 206: { struct linux_setgroups_args *p = params; iarg[0] = p->gidsetsize; /* l_int */ uarg[1] = (intptr_t) p->grouplist; /* l_gid_t * */ *n_args = 2; break; } /* fchown */ case 207: { *n_args = 0; break; } /* setresuid */ case 208: { struct setresuid_args *p = params; uarg[0] = p->ruid; /* uid_t */ uarg[1] = p->euid; /* uid_t */ uarg[2] = p->suid; /* uid_t */ *n_args = 3; break; } /* getresuid */ case 209: { struct getresuid_args *p = params; uarg[0] = (intptr_t) p->ruid; /* uid_t * */ uarg[1] = (intptr_t) p->euid; /* uid_t * */ uarg[2] = (intptr_t) p->suid; /* uid_t * */ *n_args = 3; break; } /* setresgid */ case 210: { struct setresgid_args *p = params; iarg[0] = p->rgid; /* gid_t */ iarg[1] = p->egid; /* gid_t */ iarg[2] = p->sgid; /* gid_t */ *n_args = 3; break; } /* getresgid */ case 211: { struct getresgid_args *p = params; uarg[0] = (intptr_t) p->rgid; /* gid_t * */ uarg[1] = (intptr_t) p->egid; /* gid_t * */ uarg[2] = (intptr_t) p->sgid; /* gid_t * */ *n_args = 3; break; } /* linux_chown */ case 212: { struct linux_chown_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid_t */ iarg[2] = p->gid; /* l_gid_t */ *n_args = 3; break; } /* setuid */ case 213: { struct setuid_args *p = params; uarg[0] = p->uid; /* uid_t */ *n_args = 1; break; } /* setgid */ case 214: { struct setgid_args *p = params; iarg[0] = p->gid; /* gid_t */ *n_args = 1; break; } /* linux_setfsuid */ case 215: { struct linux_setfsuid_args *p = params; iarg[0] = p->uid; /* l_uid_t */ *n_args = 1; break; } /* linux_setfsgid */ case 216: { struct linux_setfsgid_args *p = params; iarg[0] = p->gid; /* l_gid_t */ *n_args = 1; break; } /* linux_pivot_root */ case 217: { struct linux_pivot_root_args *p = params; uarg[0] = (intptr_t) p->new_root; /* char * */ uarg[1] = (intptr_t) p->put_old; /* char * */ *n_args = 2; break; } /* linux_mincore */ case 218: { struct linux_mincore_args *p = params; iarg[0] = p->start; /* l_ulong */ iarg[1] = p->len; /* l_size_t */ uarg[2] = (intptr_t) p->vec; /* u_char * */ *n_args = 3; break; } /* madvise */ case 219: { struct madvise_args *p = params; uarg[0] = (intptr_t) p->addr; /* void * */ uarg[1] = p->len; /* size_t */ iarg[2] = p->behav; /* int */ *n_args = 3; break; } /* linux_getdents64 */ case 220: { struct linux_getdents64_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->dirent; /* void * */ iarg[2] = p->count; /* l_uint */ *n_args = 3; break; } /* linux_fcntl64 */ case 221: { struct linux_fcntl64_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->cmd; /* l_uint */ uarg[2] = p->arg; /* uintptr_t */ *n_args = 3; break; } /* linux_gettid */ case 224: { *n_args = 0; break; } /* linux_setxattr */ case 226: { *n_args = 0; break; } /* linux_lsetxattr */ case 227: { *n_args = 0; break; } /* linux_fsetxattr */ case 228: { *n_args = 0; break; } /* linux_getxattr */ case 229: { *n_args = 0; break; } /* linux_lgetxattr */ case 230: { *n_args = 0; break; } /* linux_fgetxattr */ case 231: { *n_args = 0; break; } /* linux_listxattr */ case 232: { *n_args = 0; break; } /* linux_llistxattr */ case 233: { *n_args = 0; break; } /* linux_flistxattr */ case 234: { *n_args = 0; break; } /* linux_removexattr */ case 235: { *n_args = 0; break; } /* linux_lremovexattr */ case 236: { *n_args = 0; break; } /* linux_fremovexattr */ case 237: { *n_args = 0; break; } /* linux_tkill */ case 238: { struct linux_tkill_args *p = params; iarg[0] = p->tid; /* int */ iarg[1] = p->sig; /* int */ *n_args = 2; break; } /* linux_sys_futex */ case 240: { struct linux_sys_futex_args *p = params; uarg[0] = (intptr_t) p->uaddr; /* void * */ iarg[1] = p->op; /* int */ uarg[2] = p->val; /* uint32_t */ uarg[3] = (intptr_t) p->timeout; /* struct l_timespec * */ uarg[4] = (intptr_t) p->uaddr2; /* uint32_t * */ uarg[5] = p->val3; /* uint32_t */ *n_args = 6; break; } /* linux_sched_setaffinity */ case 241: { struct linux_sched_setaffinity_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->len; /* l_uint */ uarg[2] = (intptr_t) p->user_mask_ptr; /* l_ulong * */ *n_args = 3; break; } /* linux_sched_getaffinity */ case 242: { struct linux_sched_getaffinity_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->len; /* l_uint */ uarg[2] = (intptr_t) p->user_mask_ptr; /* l_ulong * */ *n_args = 3; break; } /* linux_set_thread_area */ case 243: { struct linux_set_thread_area_args *p = params; uarg[0] = (intptr_t) p->desc; /* struct l_user_desc * */ *n_args = 1; break; } /* linux_fadvise64 */ case 250: { struct linux_fadvise64_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->offset; /* l_loff_t */ iarg[2] = p->len; /* l_size_t */ iarg[3] = p->advice; /* int */ *n_args = 4; break; } /* linux_exit_group */ case 252: { struct linux_exit_group_args *p = params; iarg[0] = p->error_code; /* int */ *n_args = 1; break; } /* linux_lookup_dcookie */ case 253: { *n_args = 0; break; } /* linux_epoll_create */ case 254: { struct linux_epoll_create_args *p = params; iarg[0] = p->size; /* l_int */ *n_args = 1; break; } /* linux_epoll_ctl */ case 255: { struct linux_epoll_ctl_args *p = params; iarg[0] = p->epfd; /* l_int */ iarg[1] = p->op; /* l_int */ iarg[2] = p->fd; /* l_int */ uarg[3] = (intptr_t) p->event; /* struct epoll_event * */ *n_args = 4; break; } /* linux_epoll_wait */ case 256: { struct linux_epoll_wait_args *p = params; iarg[0] = p->epfd; /* l_int */ uarg[1] = (intptr_t) p->events; /* struct epoll_event * */ iarg[2] = p->maxevents; /* l_int */ iarg[3] = p->timeout; /* l_int */ *n_args = 4; break; } /* linux_remap_file_pages */ case 257: { *n_args = 0; break; } /* linux_set_tid_address */ case 258: { struct linux_set_tid_address_args *p = params; uarg[0] = (intptr_t) p->tidptr; /* int * */ *n_args = 1; break; } /* linux_timer_create */ case 259: { struct linux_timer_create_args *p = params; iarg[0] = p->clock_id; /* clockid_t */ uarg[1] = (intptr_t) p->evp; /* struct sigevent * */ uarg[2] = (intptr_t) p->timerid; /* l_timer_t * */ *n_args = 3; break; } /* linux_timer_settime */ case 260: { struct linux_timer_settime_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ iarg[1] = p->flags; /* l_int */ uarg[2] = (intptr_t) p->new; /* const struct itimerspec * */ uarg[3] = (intptr_t) p->old; /* struct itimerspec * */ *n_args = 4; break; } /* linux_timer_gettime */ case 261: { struct linux_timer_gettime_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ uarg[1] = (intptr_t) p->setting; /* struct itimerspec * */ *n_args = 2; break; } /* linux_timer_getoverrun */ case 262: { struct linux_timer_getoverrun_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ *n_args = 1; break; } /* linux_timer_delete */ case 263: { struct linux_timer_delete_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ *n_args = 1; break; } /* linux_clock_settime */ case 264: { struct linux_clock_settime_args *p = params; iarg[0] = p->which; /* clockid_t */ uarg[1] = (intptr_t) p->tp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_clock_gettime */ case 265: { struct linux_clock_gettime_args *p = params; iarg[0] = p->which; /* clockid_t */ uarg[1] = (intptr_t) p->tp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_clock_getres */ case 266: { struct linux_clock_getres_args *p = params; iarg[0] = p->which; /* clockid_t */ uarg[1] = (intptr_t) p->tp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_clock_nanosleep */ case 267: { struct linux_clock_nanosleep_args *p = params; iarg[0] = p->which; /* clockid_t */ iarg[1] = p->flags; /* int */ uarg[2] = (intptr_t) p->rqtp; /* struct l_timespec * */ uarg[3] = (intptr_t) p->rmtp; /* struct l_timespec * */ *n_args = 4; break; } /* linux_statfs64 */ case 268: { struct linux_statfs64_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = p->bufsize; /* size_t */ uarg[2] = (intptr_t) p->buf; /* struct l_statfs64_buf * */ *n_args = 3; break; } /* linux_fstatfs64 */ case 269: { struct linux_fstatfs64_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = p->bufsize; /* size_t */ uarg[2] = (intptr_t) p->buf; /* struct l_statfs64_buf * */ *n_args = 3; break; } /* linux_tgkill */ case 270: { struct linux_tgkill_args *p = params; iarg[0] = p->tgid; /* int */ iarg[1] = p->pid; /* int */ iarg[2] = p->sig; /* int */ *n_args = 3; break; } /* linux_utimes */ case 271: { struct linux_utimes_args *p = params; uarg[0] = (intptr_t) p->fname; /* char * */ uarg[1] = (intptr_t) p->tptr; /* struct l_timeval * */ *n_args = 2; break; } /* linux_fadvise64_64 */ case 272: { struct linux_fadvise64_64_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->offset; /* l_loff_t */ iarg[2] = p->len; /* l_loff_t */ iarg[3] = p->advice; /* int */ *n_args = 4; break; } /* linux_mbind */ case 274: { *n_args = 0; break; } /* linux_get_mempolicy */ case 275: { *n_args = 0; break; } /* linux_set_mempolicy */ case 276: { *n_args = 0; break; } /* linux_mq_open */ case 277: { *n_args = 0; break; } /* linux_mq_unlink */ case 278: { *n_args = 0; break; } /* linux_mq_timedsend */ case 279: { *n_args = 0; break; } /* linux_mq_timedreceive */ case 280: { *n_args = 0; break; } /* linux_mq_notify */ case 281: { *n_args = 0; break; } /* linux_mq_getsetattr */ case 282: { *n_args = 0; break; } /* linux_kexec_load */ case 283: { *n_args = 0; break; } /* linux_waitid */ case 284: { struct linux_waitid_args *p = params; iarg[0] = p->idtype; /* int */ iarg[1] = p->id; /* l_pid_t */ uarg[2] = (intptr_t) p->info; /* l_siginfo_t * */ iarg[3] = p->options; /* int */ uarg[4] = (intptr_t) p->rusage; /* struct l_rusage * */ *n_args = 5; break; } /* linux_add_key */ case 286: { *n_args = 0; break; } /* linux_request_key */ case 287: { *n_args = 0; break; } /* linux_keyctl */ case 288: { *n_args = 0; break; } /* linux_ioprio_set */ case 289: { *n_args = 0; break; } /* linux_ioprio_get */ case 290: { *n_args = 0; break; } /* linux_inotify_init */ case 291: { *n_args = 0; break; } /* linux_inotify_add_watch */ case 292: { *n_args = 0; break; } /* linux_inotify_rm_watch */ case 293: { *n_args = 0; break; } /* linux_migrate_pages */ case 294: { *n_args = 0; break; } /* linux_openat */ case 295: { struct linux_openat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->flags; /* l_int */ iarg[3] = p->mode; /* l_int */ *n_args = 4; break; } /* linux_mkdirat */ case 296: { struct linux_mkdirat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* const char * */ iarg[2] = p->mode; /* l_int */ *n_args = 3; break; } /* linux_mknodat */ case 297: { struct linux_mknodat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->mode; /* l_int */ iarg[3] = p->dev; /* l_uint */ *n_args = 4; break; } /* linux_fchownat */ case 298: { struct linux_fchownat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->uid; /* l_uid16_t */ iarg[3] = p->gid; /* l_gid16_t */ iarg[4] = p->flag; /* l_int */ *n_args = 5; break; } /* linux_futimesat */ case 299: { struct linux_futimesat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* char * */ uarg[2] = (intptr_t) p->utimes; /* struct l_timeval * */ *n_args = 3; break; } /* linux_fstatat64 */ case 300: { struct linux_fstatat64_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* char * */ uarg[2] = (intptr_t) p->statbuf; /* struct l_stat64 * */ iarg[3] = p->flag; /* l_int */ *n_args = 4; break; } /* linux_unlinkat */ case 301: { struct linux_unlinkat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* const char * */ iarg[2] = p->flag; /* l_int */ *n_args = 3; break; } /* linux_renameat */ case 302: { struct linux_renameat_args *p = params; iarg[0] = p->olddfd; /* l_int */ uarg[1] = (intptr_t) p->oldname; /* const char * */ iarg[2] = p->newdfd; /* l_int */ uarg[3] = (intptr_t) p->newname; /* const char * */ *n_args = 4; break; } /* linux_linkat */ case 303: { struct linux_linkat_args *p = params; iarg[0] = p->olddfd; /* l_int */ uarg[1] = (intptr_t) p->oldname; /* const char * */ iarg[2] = p->newdfd; /* l_int */ uarg[3] = (intptr_t) p->newname; /* const char * */ iarg[4] = p->flag; /* l_int */ *n_args = 5; break; } /* linux_symlinkat */ case 304: { struct linux_symlinkat_args *p = params; uarg[0] = (intptr_t) p->oldname; /* const char * */ iarg[1] = p->newdfd; /* l_int */ uarg[2] = (intptr_t) p->newname; /* const char * */ *n_args = 3; break; } /* linux_readlinkat */ case 305: { struct linux_readlinkat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->path; /* const char * */ uarg[2] = (intptr_t) p->buf; /* char * */ iarg[3] = p->bufsiz; /* l_int */ *n_args = 4; break; } /* linux_fchmodat */ case 306: { struct linux_fchmodat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->mode; /* l_mode_t */ *n_args = 3; break; } /* linux_faccessat */ case 307: { struct linux_faccessat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->amode; /* l_int */ *n_args = 3; break; } /* linux_pselect6 */ case 308: { struct linux_pselect6_args *p = params; iarg[0] = p->nfds; /* l_int */ uarg[1] = (intptr_t) p->readfds; /* l_fd_set * */ uarg[2] = (intptr_t) p->writefds; /* l_fd_set * */ uarg[3] = (intptr_t) p->exceptfds; /* l_fd_set * */ uarg[4] = (intptr_t) p->tsp; /* struct l_timespec * */ uarg[5] = (intptr_t) p->sig; /* l_uintptr_t * */ *n_args = 6; break; } /* linux_ppoll */ case 309: { struct linux_ppoll_args *p = params; uarg[0] = (intptr_t) p->fds; /* struct pollfd * */ uarg[1] = p->nfds; /* uint32_t */ uarg[2] = (intptr_t) p->tsp; /* struct l_timespec * */ uarg[3] = (intptr_t) p->sset; /* l_sigset_t * */ iarg[4] = p->ssize; /* l_size_t */ *n_args = 5; break; } /* linux_unshare */ case 310: { *n_args = 0; break; } /* linux_set_robust_list */ case 311: { struct linux_set_robust_list_args *p = params; uarg[0] = (intptr_t) p->head; /* struct linux_robust_list_head * */ iarg[1] = p->len; /* l_size_t */ *n_args = 2; break; } /* linux_get_robust_list */ case 312: { struct linux_get_robust_list_args *p = params; iarg[0] = p->pid; /* l_int */ uarg[1] = (intptr_t) p->head; /* struct linux_robust_list_head ** */ uarg[2] = (intptr_t) p->len; /* l_size_t * */ *n_args = 3; break; } /* linux_splice */ case 313: { *n_args = 0; break; } /* linux_sync_file_range */ case 314: { *n_args = 0; break; } /* linux_tee */ case 315: { *n_args = 0; break; } /* linux_vmsplice */ case 316: { *n_args = 0; break; } /* linux_move_pages */ case 317: { *n_args = 0; break; } /* linux_getcpu */ case 318: { *n_args = 0; break; } /* linux_epoll_pwait */ case 319: { struct linux_epoll_pwait_args *p = params; iarg[0] = p->epfd; /* l_int */ uarg[1] = (intptr_t) p->events; /* struct epoll_event * */ iarg[2] = p->maxevents; /* l_int */ iarg[3] = p->timeout; /* l_int */ uarg[4] = (intptr_t) p->mask; /* l_sigset_t * */ *n_args = 5; break; } /* linux_utimensat */ case 320: { struct linux_utimensat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* const char * */ uarg[2] = (intptr_t) p->times; /* const struct l_timespec * */ iarg[3] = p->flags; /* l_int */ *n_args = 4; break; } /* linux_signalfd */ case 321: { *n_args = 0; break; } /* linux_timerfd_create */ case 322: { *n_args = 0; break; } /* linux_eventfd */ case 323: { struct linux_eventfd_args *p = params; iarg[0] = p->initval; /* l_uint */ *n_args = 1; break; } /* linux_fallocate */ case 324: { struct linux_fallocate_args *p = params; iarg[0] = p->fd; /* l_int */ iarg[1] = p->mode; /* l_int */ iarg[2] = p->offset; /* l_loff_t */ iarg[3] = p->len; /* l_loff_t */ *n_args = 4; break; } /* linux_timerfd_settime */ case 325: { *n_args = 0; break; } /* linux_timerfd_gettime */ case 326: { *n_args = 0; break; } /* linux_signalfd4 */ case 327: { *n_args = 0; break; } /* linux_eventfd2 */ case 328: { struct linux_eventfd2_args *p = params; iarg[0] = p->initval; /* l_uint */ iarg[1] = p->flags; /* l_int */ *n_args = 2; break; } /* linux_epoll_create1 */ case 329: { struct linux_epoll_create1_args *p = params; iarg[0] = p->flags; /* l_int */ *n_args = 1; break; } /* linux_dup3 */ case 330: { struct linux_dup3_args *p = params; iarg[0] = p->oldfd; /* l_int */ iarg[1] = p->newfd; /* l_int */ iarg[2] = p->flags; /* l_int */ *n_args = 3; break; } /* linux_pipe2 */ case 331: { struct linux_pipe2_args *p = params; uarg[0] = (intptr_t) p->pipefds; /* l_int * */ iarg[1] = p->flags; /* l_int */ *n_args = 2; break; } /* linux_inotify_init1 */ case 332: { *n_args = 0; break; } /* linux_preadv */ case 333: { - *n_args = 0; + struct linux_preadv_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + *n_args = 5; break; } /* linux_pwritev */ case 334: { - *n_args = 0; + struct linux_pwritev_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + *n_args = 5; break; } - /* linux_rt_tsigqueueinfo */ + /* linux_rt_tgsigqueueinfo */ case 335: { - *n_args = 0; + struct linux_rt_tgsigqueueinfo_args *p = params; + iarg[0] = p->tgid; /* l_pid_t */ + iarg[1] = p->tid; /* l_pid_t */ + iarg[2] = p->sig; /* l_int */ + uarg[3] = (intptr_t) p->uinfo; /* l_siginfo_t * */ + *n_args = 4; break; } /* linux_perf_event_open */ case 336: { *n_args = 0; break; } /* linux_recvmmsg */ case 337: { struct linux_recvmmsg_args *p = params; iarg[0] = p->s; /* l_int */ uarg[1] = (intptr_t) p->msg; /* struct l_mmsghdr * */ iarg[2] = p->vlen; /* l_uint */ iarg[3] = p->flags; /* l_uint */ uarg[4] = (intptr_t) p->timeout; /* struct l_timespec * */ *n_args = 5; break; } /* linux_fanotify_init */ case 338: { *n_args = 0; break; } /* linux_fanotify_mark */ case 339: { *n_args = 0; break; } /* linux_prlimit64 */ case 340: { struct linux_prlimit64_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->resource; /* l_uint */ uarg[2] = (intptr_t) p->new; /* struct rlimit * */ uarg[3] = (intptr_t) p->old; /* struct rlimit * */ *n_args = 4; break; } /* linux_name_to_handle_at */ case 341: { *n_args = 0; break; } /* linux_open_by_handle_at */ case 342: { *n_args = 0; break; } /* linux_clock_adjtime */ case 343: { *n_args = 0; break; } /* linux_syncfs */ case 344: { struct linux_syncfs_args *p = params; iarg[0] = p->fd; /* l_int */ *n_args = 1; break; } /* linux_sendmmsg */ case 345: { struct linux_sendmmsg_args *p = params; iarg[0] = p->s; /* l_int */ uarg[1] = (intptr_t) p->msg; /* struct l_mmsghdr * */ iarg[2] = p->vlen; /* l_uint */ iarg[3] = p->flags; /* l_uint */ *n_args = 4; break; } /* linux_setns */ case 346: { *n_args = 0; break; } /* linux_process_vm_readv */ case 347: { - *n_args = 0; + struct linux_process_vm_readv_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->lvec; /* const struct iovec * */ + iarg[2] = p->liovcnt; /* l_ulong */ + uarg[3] = (intptr_t) p->rvec; /* const struct iovec * */ + iarg[4] = p->riovcnt; /* l_ulong */ + iarg[5] = p->flags; /* l_ulong */ + *n_args = 6; break; } /* linux_process_vm_writev */ case 348: { - *n_args = 0; + struct linux_process_vm_writev_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->lvec; /* const struct iovec * */ + iarg[2] = p->liovcnt; /* l_ulong */ + uarg[3] = (intptr_t) p->rvec; /* const struct iovec * */ + iarg[4] = p->riovcnt; /* l_ulong */ + iarg[5] = p->flags; /* l_ulong */ + *n_args = 6; break; } + /* linux_kcmp */ + case 349: { + struct linux_kcmp_args *p = params; + iarg[0] = p->pid1; /* l_pid_t */ + iarg[1] = p->pid2; /* l_pid_t */ + iarg[2] = p->type; /* l_int */ + iarg[3] = p->idx1; /* l_ulong */ + iarg[4] = p->idx; /* l_ulong */ + *n_args = 5; + break; + } + /* linux_finit_module */ + case 350: { + struct linux_finit_module_args *p = params; + iarg[0] = p->fd; /* l_int */ + uarg[1] = (intptr_t) p->uargs; /* const char * */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_sched_setattr */ + case 351: { + struct linux_sched_setattr_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->attr; /* void * */ + iarg[2] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_sched_getattr */ + case 352: { + struct linux_sched_getattr_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->attr; /* void * */ + iarg[2] = p->size; /* l_uint */ + iarg[3] = p->flags; /* l_uint */ + *n_args = 4; + break; + } + /* linux_renameat2 */ + case 353: { + struct linux_renameat2_args *p = params; + iarg[0] = p->oldfd; /* l_int */ + uarg[1] = (intptr_t) p->oldname; /* const char * */ + iarg[2] = p->newfd; /* l_int */ + uarg[3] = (intptr_t) p->newname; /* const char * */ + uarg[4] = p->flags; /* unsigned int */ + *n_args = 5; + break; + } + /* linux_seccomp */ + case 354: { + struct linux_seccomp_args *p = params; + iarg[0] = p->op; /* l_uint */ + iarg[1] = p->flags; /* l_uint */ + uarg[2] = (intptr_t) p->uargs; /* const char * */ + *n_args = 3; + break; + } + /* linux_getrandom */ + case 355: { + struct linux_getrandom_args *p = params; + uarg[0] = (intptr_t) p->buf; /* char * */ + iarg[1] = p->count; /* l_size_t */ + iarg[2] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_memfd_create */ + case 356: { + struct linux_memfd_create_args *p = params; + uarg[0] = (intptr_t) p->uname_ptr; /* const char * */ + iarg[1] = p->flags; /* l_uint */ + *n_args = 2; + break; + } + /* linux_bpf */ + case 357: { + struct linux_bpf_args *p = params; + iarg[0] = p->cmd; /* l_int */ + uarg[1] = (intptr_t) p->attr; /* void * */ + iarg[2] = p->size; /* l_uint */ + *n_args = 3; + break; + } + /* linux_execveat */ + case 358: { + struct linux_execveat_args *p = params; + iarg[0] = p->dfd; /* l_int */ + uarg[1] = (intptr_t) p->filename; /* const char * */ + uarg[2] = (intptr_t) p->argv; /* const char ** */ + uarg[3] = (intptr_t) p->envp; /* const char ** */ + iarg[4] = p->flags; /* l_int */ + *n_args = 5; + break; + } + /* linux_socket */ + case 359: { + struct linux_socket_args *p = params; + iarg[0] = p->domain; /* l_int */ + iarg[1] = p->type; /* l_int */ + iarg[2] = p->protocol; /* l_int */ + *n_args = 3; + break; + } + /* linux_socketpair */ + case 360: { + struct linux_socketpair_args *p = params; + iarg[0] = p->domain; /* l_int */ + iarg[1] = p->type; /* l_int */ + iarg[2] = p->protocol; /* l_int */ + iarg[3] = p->rsv; /* l_uintptr_t */ + *n_args = 4; + break; + } + /* linux_bind */ + case 361: { + struct linux_bind_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->name; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_int */ + *n_args = 3; + break; + } + /* linux_connect */ + case 362: { + struct linux_connect_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->name; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_int */ + *n_args = 3; + break; + } + /* linux_listen */ + case 363: { + struct linux_listen_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->backlog; /* l_int */ + *n_args = 2; + break; + } + /* linux_accept4 */ + case 364: { + struct linux_accept4_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->addr; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_uintptr_t */ + iarg[3] = p->flags; /* l_int */ + *n_args = 4; + break; + } + /* linux_getsockopt */ + case 365: { + struct linux_getsockopt_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->level; /* l_int */ + iarg[2] = p->optname; /* l_int */ + iarg[3] = p->optval; /* l_uintptr_t */ + iarg[4] = p->optlen; /* l_uintptr_t */ + *n_args = 5; + break; + } + /* linux_setsockopt */ + case 366: { + struct linux_setsockopt_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->level; /* l_int */ + iarg[2] = p->optname; /* l_int */ + iarg[3] = p->optval; /* l_uintptr_t */ + iarg[4] = p->optlen; /* l_int */ + *n_args = 5; + break; + } + /* linux_getsockname */ + case 367: { + struct linux_getsockname_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->addr; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_uintptr_t */ + *n_args = 3; + break; + } + /* linux_getpeername */ + case 368: { + struct linux_getpeername_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->addr; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_uintptr_t */ + *n_args = 3; + break; + } + /* linux_sendto */ + case 369: { + struct linux_sendto_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->msg; /* l_uintptr_t */ + iarg[2] = p->len; /* l_int */ + iarg[3] = p->flags; /* l_int */ + iarg[4] = p->to; /* l_uintptr_t */ + iarg[5] = p->tolen; /* l_int */ + *n_args = 6; + break; + } + /* linux_sendmsg */ + case 370: { + struct linux_sendmsg_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->msg; /* l_uintptr_t */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_recvfrom */ + case 371: { + struct linux_recvfrom_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->buf; /* l_uintptr_t */ + iarg[2] = p->len; /* l_size_t */ + iarg[3] = p->flags; /* l_int */ + iarg[4] = p->from; /* l_uintptr_t */ + iarg[5] = p->fromlen; /* l_uintptr_t */ + *n_args = 6; + break; + } + /* linux_recvmsg */ + case 372: { + struct linux_recvmsg_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->msg; /* l_uintptr_t */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_shutdown */ + case 373: { + struct linux_shutdown_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->how; /* l_int */ + *n_args = 2; + break; + } + /* linux_userfaultfd */ + case 374: { + struct linux_userfaultfd_args *p = params; + iarg[0] = p->flags; /* l_int */ + *n_args = 1; + break; + } + /* linux_membarrier */ + case 375: { + struct linux_membarrier_args *p = params; + iarg[0] = p->cmd; /* l_int */ + iarg[1] = p->flags; /* l_int */ + *n_args = 2; + break; + } + /* linux_mlock2 */ + case 376: { + struct linux_mlock2_args *p = params; + iarg[0] = p->start; /* l_ulong */ + iarg[1] = p->len; /* l_size_t */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_copy_file_range */ + case 377: { + struct linux_copy_file_range_args *p = params; + iarg[0] = p->fd_in; /* l_int */ + uarg[1] = (intptr_t) p->off_in; /* l_loff_t * */ + iarg[2] = p->fd_out; /* l_int */ + uarg[3] = (intptr_t) p->off_out; /* l_loff_t * */ + iarg[4] = p->len; /* l_size_t */ + iarg[5] = p->flags; /* l_uint */ + *n_args = 6; + break; + } + /* linux_preadv2 */ + case 378: { + struct linux_preadv2_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* const struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + iarg[5] = p->flags; /* l_int */ + *n_args = 6; + break; + } + /* linux_pwritev2 */ + case 379: { + struct linux_pwritev2_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* const struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + iarg[5] = p->flags; /* l_int */ + *n_args = 6; + break; + } + /* linux_pkey_mprotect */ + case 380: { + struct linux_pkey_mprotect_args *p = params; + iarg[0] = p->start; /* l_ulong */ + iarg[1] = p->len; /* l_size_t */ + iarg[2] = p->prot; /* l_ulong */ + iarg[3] = p->pkey; /* l_int */ + *n_args = 4; + break; + } + /* linux_pkey_alloc */ + case 381: { + struct linux_pkey_alloc_args *p = params; + iarg[0] = p->flags; /* l_ulong */ + iarg[1] = p->init_val; /* l_ulong */ + *n_args = 2; + break; + } + /* linux_pkey_free */ + case 382: { + struct linux_pkey_free_args *p = params; + iarg[0] = p->pkey; /* l_int */ + *n_args = 1; + break; + } default: *n_args = 0; break; }; } static void systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) { const char *p = NULL; switch (sysnum) { #define nosys linux_nosys /* linux_exit */ case 1: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_fork */ case 2: break; /* read */ case 3: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland char *"; break; case 2: p = "u_int"; break; default: break; }; break; /* write */ case 4: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland char *"; break; case 2: p = "u_int"; break; default: break; }; break; /* linux_open */ case 5: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; default: break; }; break; /* close */ case 6: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_waitpid */ case 7: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland l_int *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_creat */ case 8: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_link */ case 9: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_unlink */ case 10: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_execve */ case 11: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland uint32_t *"; break; case 2: p = "userland uint32_t *"; break; default: break; }; break; /* linux_chdir */ case 12: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_time */ case 13: switch(ndx) { case 0: p = "userland l_time_t *"; break; default: break; }; break; /* linux_mknod */ case 14: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; case 2: p = "l_dev_t"; break; default: break; }; break; /* linux_chmod */ case 15: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_mode_t"; break; default: break; }; break; /* linux_lchown16 */ case 16: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid16_t"; break; case 2: p = "l_gid16_t"; break; default: break; }; break; /* linux_stat */ case 18: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct linux_stat *"; break; default: break; }; break; /* linux_lseek */ case 19: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_off_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_getpid */ case 20: break; /* linux_mount */ case 21: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; case 2: p = "userland char *"; break; case 3: p = "l_ulong"; break; case 4: p = "userland void *"; break; default: break; }; break; /* linux_oldumount */ case 22: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_setuid16 */ case 23: switch(ndx) { case 0: p = "l_uid16_t"; break; default: break; }; break; /* linux_getuid16 */ case 24: break; /* linux_stime */ case 25: break; /* linux_ptrace */ case 26: switch(ndx) { case 0: p = "l_long"; break; case 1: p = "l_long"; break; case 2: p = "l_long"; break; case 3: p = "l_long"; break; default: break; }; break; /* linux_alarm */ case 27: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_pause */ case 29: break; /* linux_utime */ case 30: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_utimbuf *"; break; default: break; }; break; /* linux_access */ case 33: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_nice */ case 34: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* sync */ case 36: break; /* linux_kill */ case 37: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_rename */ case 38: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_mkdir */ case 39: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_rmdir */ case 40: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* dup */ case 41: switch(ndx) { case 0: p = "u_int"; break; default: break; }; break; /* linux_pipe */ case 42: switch(ndx) { case 0: p = "userland l_int *"; break; default: break; }; break; /* linux_times */ case 43: switch(ndx) { case 0: p = "userland struct l_times_argv *"; break; default: break; }; break; /* linux_brk */ case 45: switch(ndx) { case 0: p = "l_ulong"; break; default: break; }; break; /* linux_setgid16 */ case 46: switch(ndx) { case 0: p = "l_gid16_t"; break; default: break; }; break; /* linux_getgid16 */ case 47: break; /* linux_signal */ case 48: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_handler_t"; break; default: break; }; break; /* linux_geteuid16 */ case 49: break; /* linux_getegid16 */ case 50: break; /* acct */ case 51: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_umount */ case 52: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_ioctl */ case 54: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_uint"; break; case 2: p = "uintptr_t"; break; default: break; }; break; /* linux_fcntl */ case 55: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_uint"; break; case 2: p = "uintptr_t"; break; default: break; }; break; /* setpgid */ case 57: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* linux_olduname */ case 59: break; /* umask */ case 60: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* chroot */ case 61: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_ustat */ case 62: switch(ndx) { case 0: p = "l_dev_t"; break; case 1: p = "userland struct l_ustat *"; break; default: break; }; break; /* dup2 */ case 63: switch(ndx) { case 0: p = "u_int"; break; case 1: p = "u_int"; break; default: break; }; break; /* linux_getppid */ case 64: break; /* getpgrp */ case 65: break; /* setsid */ case 66: break; /* linux_sigaction */ case 67: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_osigaction_t *"; break; case 2: p = "userland l_osigaction_t *"; break; default: break; }; break; /* linux_sgetmask */ case 68: break; /* linux_ssetmask */ case 69: switch(ndx) { case 0: p = "l_osigset_t"; break; default: break; }; break; /* linux_setreuid16 */ case 70: switch(ndx) { case 0: p = "l_uid16_t"; break; case 1: p = "l_uid16_t"; break; default: break; }; break; /* linux_setregid16 */ case 71: switch(ndx) { case 0: p = "l_gid16_t"; break; case 1: p = "l_gid16_t"; break; default: break; }; break; /* linux_sigsuspend */ case 72: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_osigset_t"; break; default: break; }; break; /* linux_sigpending */ case 73: switch(ndx) { case 0: p = "userland l_osigset_t *"; break; default: break; }; break; /* linux_sethostname */ case 74: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "u_int"; break; default: break; }; break; /* linux_setrlimit */ case 75: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_rlimit *"; break; default: break; }; break; /* linux_old_getrlimit */ case 76: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_rlimit *"; break; default: break; }; break; /* linux_getrusage */ case 77: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland struct l_rusage *"; break; default: break; }; break; /* linux_gettimeofday */ case 78: switch(ndx) { case 0: p = "userland struct l_timeval *"; break; case 1: p = "userland struct timezone *"; break; default: break; }; break; /* linux_settimeofday */ case 79: switch(ndx) { case 0: p = "userland struct l_timeval *"; break; case 1: p = "userland struct timezone *"; break; default: break; }; break; /* linux_getgroups16 */ case 80: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland l_gid16_t *"; break; default: break; }; break; /* linux_setgroups16 */ case 81: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland l_gid16_t *"; break; default: break; }; break; /* linux_old_select */ case 82: switch(ndx) { case 0: p = "userland struct l_old_select_argv *"; break; default: break; }; break; /* linux_symlink */ case 83: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_lstat */ case 84: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct linux_lstat *"; break; default: break; }; break; /* linux_readlink */ case 85: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* swapon */ case 87: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_reboot */ case 88: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_uint"; break; case 3: p = "userland void *"; break; default: break; }; break; /* linux_readdir */ case 89: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_dirent *"; break; case 2: p = "l_uint"; break; default: break; }; break; /* linux_mmap */ case 90: switch(ndx) { case 0: p = "userland struct l_mmap_argv *"; break; default: break; }; break; /* munmap */ case 91: switch(ndx) { case 0: p = "caddr_t"; break; case 1: p = "int"; break; default: break; }; break; /* linux_truncate */ case 92: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_ulong"; break; default: break; }; break; /* linux_ftruncate */ case 93: switch(ndx) { case 0: p = "int"; break; case 1: p = "long"; break; default: break; }; break; /* fchmod */ case 94: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* fchown */ case 95: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_getpriority */ case 96: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* setpriority */ case 97: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_statfs */ case 99: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_statfs_buf *"; break; default: break; }; break; /* linux_fstatfs */ case 100: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_statfs_buf *"; break; default: break; }; break; /* linux_socketcall */ case 102: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_ulong"; break; default: break; }; break; /* linux_syslog */ case 103: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_setitimer */ case 104: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_itimerval *"; break; case 2: p = "userland struct l_itimerval *"; break; default: break; }; break; /* linux_getitimer */ case 105: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_itimerval *"; break; default: break; }; break; /* linux_newstat */ case 106: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_newstat *"; break; default: break; }; break; /* linux_newlstat */ case 107: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_newstat *"; break; default: break; }; break; /* linux_newfstat */ case 108: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_newstat *"; break; default: break; }; break; /* linux_uname */ case 109: break; /* linux_iopl */ case 110: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_vhangup */ case 111: break; /* linux_wait4 */ case 114: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland l_int *"; break; case 2: p = "l_int"; break; case 3: p = "userland struct l_rusage *"; break; default: break; }; break; /* linux_swapoff */ case 115: break; /* linux_sysinfo */ case 116: switch(ndx) { case 0: p = "userland struct l_sysinfo *"; break; default: break; }; break; /* linux_ipc */ case 117: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; case 4: p = "userland void *"; break; case 5: p = "l_long"; break; default: break; }; break; /* fsync */ case 118: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_sigreturn */ case 119: switch(ndx) { case 0: p = "userland struct l_sigframe *"; break; default: break; }; break; /* linux_clone */ case 120: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland void *"; break; case 2: p = "userland void *"; break; case 3: p = "userland void *"; break; case 4: p = "userland void *"; break; default: break; }; break; /* linux_setdomainname */ case 121: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "int"; break; default: break; }; break; /* linux_newuname */ case 122: switch(ndx) { case 0: p = "userland struct l_new_utsname *"; break; default: break; }; break; /* linux_adjtimex */ case 124: break; /* linux_mprotect */ case 125: switch(ndx) { case 0: p = "caddr_t"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_sigprocmask */ case 126: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_osigset_t *"; break; case 2: p = "userland l_osigset_t *"; break; default: break; }; break; /* linux_create_module */ case 127: break; /* linux_init_module */ case 128: break; /* linux_delete_module */ case 129: break; /* linux_get_kernel_syms */ case 130: break; /* linux_quotactl */ case 131: break; /* getpgid */ case 132: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* fchdir */ case 133: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_bdflush */ case 134: break; /* linux_sysfs */ case 135: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* linux_personality */ case 136: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_setfsuid16 */ case 138: switch(ndx) { case 0: p = "l_uid16_t"; break; default: break; }; break; /* linux_setfsgid16 */ case 139: switch(ndx) { case 0: p = "l_gid16_t"; break; default: break; }; break; /* linux_llseek */ case 140: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; case 3: p = "userland l_loff_t *"; break; case 4: p = "l_uint"; break; default: break; }; break; /* linux_getdents */ case 141: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland void *"; break; case 2: p = "l_uint"; break; default: break; }; break; /* linux_select */ case 142: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_fd_set *"; break; case 2: p = "userland l_fd_set *"; break; case 3: p = "userland l_fd_set *"; break; case 4: p = "userland struct l_timeval *"; break; default: break; }; break; /* flock */ case 143: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* linux_msync */ case 144: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_size_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_readv */ case 145: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "userland struct l_iovec32 *"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* linux_writev */ case 146: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "userland struct l_iovec32 *"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* linux_getsid */ case 147: switch(ndx) { case 0: p = "l_pid_t"; break; default: break; }; break; /* linux_fdatasync */ case 148: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_sysctl */ case 149: switch(ndx) { case 0: p = "userland struct l___sysctl_args *"; break; default: break; }; break; /* mlock */ case 150: switch(ndx) { case 0: p = "userland const void *"; break; case 1: p = "size_t"; break; default: break; }; break; /* munlock */ case 151: switch(ndx) { case 0: p = "userland const void *"; break; case 1: p = "size_t"; break; default: break; }; break; /* mlockall */ case 152: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* munlockall */ case 153: break; /* linux_sched_setparam */ case 154: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland struct sched_param *"; break; default: break; }; break; /* linux_sched_getparam */ case 155: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland struct sched_param *"; break; default: break; }; break; /* linux_sched_setscheduler */ case 156: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_int"; break; case 2: p = "userland struct sched_param *"; break; default: break; }; break; /* linux_sched_getscheduler */ case 157: switch(ndx) { case 0: p = "l_pid_t"; break; default: break; }; break; /* sched_yield */ case 158: break; /* linux_sched_get_priority_max */ case 159: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_sched_get_priority_min */ case 160: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_sched_rr_get_interval */ case 161: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_nanosleep */ case 162: switch(ndx) { case 0: p = "userland const struct l_timespec *"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_mremap */ case 163: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; case 3: p = "l_ulong"; break; case 4: p = "l_ulong"; break; default: break; }; break; /* linux_setresuid16 */ case 164: switch(ndx) { case 0: p = "l_uid16_t"; break; case 1: p = "l_uid16_t"; break; case 2: p = "l_uid16_t"; break; default: break; }; break; /* linux_getresuid16 */ case 165: switch(ndx) { case 0: p = "userland l_uid16_t *"; break; case 1: p = "userland l_uid16_t *"; break; case 2: p = "userland l_uid16_t *"; break; default: break; }; break; /* linux_query_module */ case 167: break; /* poll */ case 168: switch(ndx) { case 0: p = "userland struct pollfd *"; break; case 1: p = "unsigned int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_nfsservctl */ case 169: break; /* linux_setresgid16 */ case 170: switch(ndx) { case 0: p = "l_gid16_t"; break; case 1: p = "l_gid16_t"; break; case 2: p = "l_gid16_t"; break; default: break; }; break; /* linux_getresgid16 */ case 171: switch(ndx) { case 0: p = "userland l_gid16_t *"; break; case 1: p = "userland l_gid16_t *"; break; case 2: p = "userland l_gid16_t *"; break; default: break; }; break; /* linux_prctl */ case 172: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_rt_sigreturn */ case 173: switch(ndx) { case 0: p = "userland struct l_ucontext *"; break; default: break; }; break; /* linux_rt_sigaction */ case 174: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_sigaction_t *"; break; case 2: p = "userland l_sigaction_t *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigprocmask */ case 175: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_sigset_t *"; break; case 2: p = "userland l_sigset_t *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigpending */ case 176: switch(ndx) { case 0: p = "userland l_sigset_t *"; break; case 1: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigtimedwait */ case 177: switch(ndx) { case 0: p = "userland l_sigset_t *"; break; case 1: p = "userland l_siginfo_t *"; break; case 2: p = "userland struct l_timeval *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigqueueinfo */ case 178: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_int"; break; case 2: p = "userland l_siginfo_t *"; break; default: break; }; break; /* linux_rt_sigsuspend */ case 179: switch(ndx) { case 0: p = "userland l_sigset_t *"; break; case 1: p = "l_size_t"; break; default: break; }; break; /* linux_pread */ case 180: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland char *"; break; case 2: p = "l_size_t"; break; case 3: p = "l_loff_t"; break; default: break; }; break; /* linux_pwrite */ case 181: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland char *"; break; case 2: p = "l_size_t"; break; case 3: p = "l_loff_t"; break; default: break; }; break; /* linux_chown16 */ case 182: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid16_t"; break; case 2: p = "l_gid16_t"; break; default: break; }; break; /* linux_getcwd */ case 183: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_ulong"; break; default: break; }; break; /* linux_capget */ case 184: switch(ndx) { case 0: p = "userland struct l_user_cap_header *"; break; case 1: p = "userland struct l_user_cap_data *"; break; default: break; }; break; /* linux_capset */ case 185: switch(ndx) { case 0: p = "userland struct l_user_cap_header *"; break; case 1: p = "userland struct l_user_cap_data *"; break; default: break; }; break; /* linux_sigaltstack */ case 186: switch(ndx) { case 0: p = "userland l_stack_t *"; break; case 1: p = "userland l_stack_t *"; break; default: break; }; break; /* linux_sendfile */ case 187: break; /* linux_vfork */ case 190: break; /* linux_getrlimit */ case 191: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_rlimit *"; break; default: break; }; break; /* linux_mmap2 */ case 192: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; case 3: p = "l_ulong"; break; case 4: p = "l_ulong"; break; case 5: p = "l_ulong"; break; default: break; }; break; /* linux_truncate64 */ case 193: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_loff_t"; break; default: break; }; break; /* linux_ftruncate64 */ case 194: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_loff_t"; break; default: break; }; break; /* linux_stat64 */ case 195: switch(ndx) { case 0: p = "userland const char *"; break; case 1: p = "userland struct l_stat64 *"; break; default: break; }; break; /* linux_lstat64 */ case 196: switch(ndx) { case 0: p = "userland const char *"; break; case 1: p = "userland struct l_stat64 *"; break; default: break; }; break; /* linux_fstat64 */ case 197: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_stat64 *"; break; default: break; }; break; /* linux_lchown */ case 198: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid_t"; break; case 2: p = "l_gid_t"; break; default: break; }; break; /* linux_getuid */ case 199: break; /* linux_getgid */ case 200: break; /* geteuid */ case 201: break; /* getegid */ case 202: break; /* setreuid */ case 203: switch(ndx) { case 0: p = "uid_t"; break; case 1: p = "uid_t"; break; default: break; }; break; /* setregid */ case 204: switch(ndx) { case 0: p = "gid_t"; break; case 1: p = "gid_t"; break; default: break; }; break; /* linux_getgroups */ case 205: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_gid_t *"; break; default: break; }; break; /* linux_setgroups */ case 206: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_gid_t *"; break; default: break; }; break; /* fchown */ case 207: break; /* setresuid */ case 208: switch(ndx) { case 0: p = "uid_t"; break; case 1: p = "uid_t"; break; case 2: p = "uid_t"; break; default: break; }; break; /* getresuid */ case 209: switch(ndx) { case 0: p = "userland uid_t *"; break; case 1: p = "userland uid_t *"; break; case 2: p = "userland uid_t *"; break; default: break; }; break; /* setresgid */ case 210: switch(ndx) { case 0: p = "gid_t"; break; case 1: p = "gid_t"; break; case 2: p = "gid_t"; break; default: break; }; break; /* getresgid */ case 211: switch(ndx) { case 0: p = "userland gid_t *"; break; case 1: p = "userland gid_t *"; break; case 2: p = "userland gid_t *"; break; default: break; }; break; /* linux_chown */ case 212: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid_t"; break; case 2: p = "l_gid_t"; break; default: break; }; break; /* setuid */ case 213: switch(ndx) { case 0: p = "uid_t"; break; default: break; }; break; /* setgid */ case 214: switch(ndx) { case 0: p = "gid_t"; break; default: break; }; break; /* linux_setfsuid */ case 215: switch(ndx) { case 0: p = "l_uid_t"; break; default: break; }; break; /* linux_setfsgid */ case 216: switch(ndx) { case 0: p = "l_gid_t"; break; default: break; }; break; /* linux_pivot_root */ case 217: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_mincore */ case 218: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_size_t"; break; case 2: p = "userland u_char *"; break; default: break; }; break; /* madvise */ case 219: switch(ndx) { case 0: p = "userland void *"; break; case 1: p = "size_t"; break; case 2: p = "int"; break; default: break; }; break; /* linux_getdents64 */ case 220: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland void *"; break; case 2: p = "l_uint"; break; default: break; }; break; /* linux_fcntl64 */ case 221: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_uint"; break; case 2: p = "uintptr_t"; break; default: break; }; break; /* linux_gettid */ case 224: break; /* linux_setxattr */ case 226: break; /* linux_lsetxattr */ case 227: break; /* linux_fsetxattr */ case 228: break; /* linux_getxattr */ case 229: break; /* linux_lgetxattr */ case 230: break; /* linux_fgetxattr */ case 231: break; /* linux_listxattr */ case 232: break; /* linux_llistxattr */ case 233: break; /* linux_flistxattr */ case 234: break; /* linux_removexattr */ case 235: break; /* linux_lremovexattr */ case 236: break; /* linux_fremovexattr */ case 237: break; /* linux_tkill */ case 238: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* linux_sys_futex */ case 240: switch(ndx) { case 0: p = "userland void *"; break; case 1: p = "int"; break; case 2: p = "uint32_t"; break; case 3: p = "userland struct l_timespec *"; break; case 4: p = "userland uint32_t *"; break; case 5: p = "uint32_t"; break; default: break; }; break; /* linux_sched_setaffinity */ case 241: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_uint"; break; case 2: p = "userland l_ulong *"; break; default: break; }; break; /* linux_sched_getaffinity */ case 242: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_uint"; break; case 2: p = "userland l_ulong *"; break; default: break; }; break; /* linux_set_thread_area */ case 243: switch(ndx) { case 0: p = "userland struct l_user_desc *"; break; default: break; }; break; /* linux_fadvise64 */ case 250: switch(ndx) { case 0: p = "int"; break; case 1: p = "l_loff_t"; break; case 2: p = "l_size_t"; break; case 3: p = "int"; break; default: break; }; break; /* linux_exit_group */ case 252: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_lookup_dcookie */ case 253: break; /* linux_epoll_create */ case 254: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_epoll_ctl */ case 255: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "userland struct epoll_event *"; break; default: break; }; break; /* linux_epoll_wait */ case 256: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct epoll_event *"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_remap_file_pages */ case 257: break; /* linux_set_tid_address */ case 258: switch(ndx) { case 0: p = "userland int *"; break; default: break; }; break; /* linux_timer_create */ case 259: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct sigevent *"; break; case 2: p = "userland l_timer_t *"; break; default: break; }; break; /* linux_timer_settime */ case 260: switch(ndx) { case 0: p = "l_timer_t"; break; case 1: p = "l_int"; break; case 2: p = "userland const struct itimerspec *"; break; case 3: p = "userland struct itimerspec *"; break; default: break; }; break; /* linux_timer_gettime */ case 261: switch(ndx) { case 0: p = "l_timer_t"; break; case 1: p = "userland struct itimerspec *"; break; default: break; }; break; /* linux_timer_getoverrun */ case 262: switch(ndx) { case 0: p = "l_timer_t"; break; default: break; }; break; /* linux_timer_delete */ case 263: switch(ndx) { case 0: p = "l_timer_t"; break; default: break; }; break; /* linux_clock_settime */ case 264: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_clock_gettime */ case 265: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_clock_getres */ case 266: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_clock_nanosleep */ case 267: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "int"; break; case 2: p = "userland struct l_timespec *"; break; case 3: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_statfs64 */ case 268: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "size_t"; break; case 2: p = "userland struct l_statfs64_buf *"; break; default: break; }; break; /* linux_fstatfs64 */ case 269: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "size_t"; break; case 2: p = "userland struct l_statfs64_buf *"; break; default: break; }; break; /* linux_tgkill */ case 270: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_utimes */ case 271: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_timeval *"; break; default: break; }; break; /* linux_fadvise64_64 */ case 272: switch(ndx) { case 0: p = "int"; break; case 1: p = "l_loff_t"; break; case 2: p = "l_loff_t"; break; case 3: p = "int"; break; default: break; }; break; /* linux_mbind */ case 274: break; /* linux_get_mempolicy */ case 275: break; /* linux_set_mempolicy */ case 276: break; /* linux_mq_open */ case 277: break; /* linux_mq_unlink */ case 278: break; /* linux_mq_timedsend */ case 279: break; /* linux_mq_timedreceive */ case 280: break; /* linux_mq_notify */ case 281: break; /* linux_mq_getsetattr */ case 282: break; /* linux_kexec_load */ case 283: break; /* linux_waitid */ case 284: switch(ndx) { case 0: p = "int"; break; case 1: p = "l_pid_t"; break; case 2: p = "userland l_siginfo_t *"; break; case 3: p = "int"; break; case 4: p = "userland struct l_rusage *"; break; default: break; }; break; /* linux_add_key */ case 286: break; /* linux_request_key */ case 287: break; /* linux_keyctl */ case 288: break; /* linux_ioprio_set */ case 289: break; /* linux_ioprio_get */ case 290: break; /* linux_inotify_init */ case 291: break; /* linux_inotify_add_watch */ case 292: break; /* linux_inotify_rm_watch */ case 293: break; /* linux_migrate_pages */ case 294: break; /* linux_openat */ case 295: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_mkdirat */ case 296: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_mknodat */ case 297: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "l_uint"; break; default: break; }; break; /* linux_fchownat */ case 298: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_uid16_t"; break; case 3: p = "l_gid16_t"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_futimesat */ case 299: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "userland struct l_timeval *"; break; default: break; }; break; /* linux_fstatat64 */ case 300: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "userland struct l_stat64 *"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_unlinkat */ case 301: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_renameat */ case 302: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "userland const char *"; break; default: break; }; break; /* linux_linkat */ case 303: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "userland const char *"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_symlinkat */ case 304: switch(ndx) { case 0: p = "userland const char *"; break; case 1: p = "l_int"; break; case 2: p = "userland const char *"; break; default: break; }; break; /* linux_readlinkat */ case 305: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "userland char *"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_fchmodat */ case 306: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_mode_t"; break; default: break; }; break; /* linux_faccessat */ case 307: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_pselect6 */ case 308: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_fd_set *"; break; case 2: p = "userland l_fd_set *"; break; case 3: p = "userland l_fd_set *"; break; case 4: p = "userland struct l_timespec *"; break; case 5: p = "userland l_uintptr_t *"; break; default: break; }; break; /* linux_ppoll */ case 309: switch(ndx) { case 0: p = "userland struct pollfd *"; break; case 1: p = "uint32_t"; break; case 2: p = "userland struct l_timespec *"; break; case 3: p = "userland l_sigset_t *"; break; case 4: p = "l_size_t"; break; default: break; }; break; /* linux_unshare */ case 310: break; /* linux_set_robust_list */ case 311: switch(ndx) { case 0: p = "userland struct linux_robust_list_head *"; break; case 1: p = "l_size_t"; break; default: break; }; break; /* linux_get_robust_list */ case 312: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct linux_robust_list_head **"; break; case 2: p = "userland l_size_t *"; break; default: break; }; break; /* linux_splice */ case 313: break; /* linux_sync_file_range */ case 314: break; /* linux_tee */ case 315: break; /* linux_vmsplice */ case 316: break; /* linux_move_pages */ case 317: break; /* linux_getcpu */ case 318: break; /* linux_epoll_pwait */ case 319: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct epoll_event *"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; case 4: p = "userland l_sigset_t *"; break; default: break; }; break; /* linux_utimensat */ case 320: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "userland const struct l_timespec *"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_signalfd */ case 321: break; /* linux_timerfd_create */ case 322: break; /* linux_eventfd */ case 323: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_fallocate */ case 324: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_loff_t"; break; case 3: p = "l_loff_t"; break; default: break; }; break; /* linux_timerfd_settime */ case 325: break; /* linux_timerfd_gettime */ case 326: break; /* linux_signalfd4 */ case 327: break; /* linux_eventfd2 */ case 328: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_epoll_create1 */ case 329: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_dup3 */ case 330: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_pipe2 */ case 331: switch(ndx) { case 0: p = "userland l_int *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_inotify_init1 */ case 332: break; /* linux_preadv */ case 333: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; break; /* linux_pwritev */ case 334: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; break; - /* linux_rt_tsigqueueinfo */ + /* linux_rt_tgsigqueueinfo */ case 335: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland l_siginfo_t *"; + break; + default: + break; + }; break; /* linux_perf_event_open */ case 336: break; /* linux_recvmmsg */ case 337: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_mmsghdr *"; break; case 2: p = "l_uint"; break; case 3: p = "l_uint"; break; case 4: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_fanotify_init */ case 338: break; /* linux_fanotify_mark */ case 339: break; /* linux_prlimit64 */ case 340: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_uint"; break; case 2: p = "userland struct rlimit *"; break; case 3: p = "userland struct rlimit *"; break; default: break; }; break; /* linux_name_to_handle_at */ case 341: break; /* linux_open_by_handle_at */ case 342: break; /* linux_clock_adjtime */ case 343: break; /* linux_syncfs */ case 344: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_sendmmsg */ case 345: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_mmsghdr *"; break; case 2: p = "l_uint"; break; case 3: p = "l_uint"; break; default: break; }; break; /* linux_setns */ case 346: break; /* linux_process_vm_readv */ case 347: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "userland const struct iovec *"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_ulong"; + break; + default: + break; + }; break; /* linux_process_vm_writev */ case 348: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "userland const struct iovec *"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_ulong"; + break; + default: + break; + }; break; + /* linux_kcmp */ + case 349: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_finit_module */ + case 350: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sched_setattr */ + case 351: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_sched_getattr */ + case 352: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + case 3: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_renameat2 */ + case 353: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland const char *"; + break; + case 4: + p = "unsigned int"; + break; + default: + break; + }; + break; + /* linux_seccomp */ + case 354: + switch(ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_getrandom */ + case 355: + switch(ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_memfd_create */ + case 356: + switch(ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_bpf */ + case 357: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_execveat */ + case 358: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland const char **"; + break; + case 3: + p = "userland const char **"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_socket */ + case 359: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_socketpair */ + case 360: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_bind */ + case 361: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_connect */ + case 362: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_listen */ + case 363: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_accept4 */ + case 364: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_getsockopt */ + case 365: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_uintptr_t"; + break; + case 4: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_setsockopt */ + case 366: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_uintptr_t"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_getsockname */ + case 367: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_getpeername */ + case 368: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_sendto */ + case 369: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_int"; + break; + case 4: + p = "l_uintptr_t"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sendmsg */ + case 370: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_recvfrom */ + case 371: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_int"; + break; + case 4: + p = "l_uintptr_t"; + break; + case 5: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_recvmsg */ + case 372: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_shutdown */ + case 373: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_userfaultfd */ + case 374: + switch(ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_membarrier */ + case 375: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_mlock2 */ + case 376: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_copy_file_range */ + case 377: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland l_loff_t *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland l_loff_t *"; + break; + case 4: + p = "l_size_t"; + break; + case 5: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_preadv2 */ + case 378: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pwritev2 */ + case 379: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pkey_mprotect */ + case 380: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pkey_alloc */ + case 381: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_pkey_free */ + case 382: + switch(ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; default: break; }; if (p != NULL) strlcpy(desc, p, descsz); } static void systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) { const char *p = NULL; switch (sysnum) { #define nosys linux_nosys /* linux_exit */ case 1: if (ndx == 0 || ndx == 1) p = "void"; break; /* linux_fork */ case 2: /* read */ case 3: if (ndx == 0 || ndx == 1) p = "int"; break; /* write */ case 4: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_open */ case 5: if (ndx == 0 || ndx == 1) p = "int"; break; /* close */ case 6: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_waitpid */ case 7: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_creat */ case 8: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_link */ case 9: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_unlink */ case 10: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_execve */ case 11: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chdir */ case 12: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_time */ case 13: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mknod */ case 14: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chmod */ case 15: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lchown16 */ case 16: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_stat */ case 18: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lseek */ case 19: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getpid */ case 20: /* linux_mount */ case 21: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_oldumount */ case 22: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setuid16 */ case 23: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getuid16 */ case 24: /* linux_stime */ case 25: /* linux_ptrace */ case 26: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_alarm */ case 27: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pause */ case 29: /* linux_utime */ case 30: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_access */ case 33: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_nice */ case 34: if (ndx == 0 || ndx == 1) p = "int"; break; /* sync */ case 36: /* linux_kill */ case 37: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rename */ case 38: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mkdir */ case 39: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rmdir */ case 40: if (ndx == 0 || ndx == 1) p = "int"; break; /* dup */ case 41: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pipe */ case 42: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_times */ case 43: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_brk */ case 45: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setgid16 */ case 46: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getgid16 */ case 47: /* linux_signal */ case 48: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_geteuid16 */ case 49: /* linux_getegid16 */ case 50: /* acct */ case 51: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_umount */ case 52: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ioctl */ case 54: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fcntl */ case 55: if (ndx == 0 || ndx == 1) p = "int"; break; /* setpgid */ case 57: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_olduname */ case 59: /* umask */ case 60: if (ndx == 0 || ndx == 1) p = "int"; break; /* chroot */ case 61: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ustat */ case 62: if (ndx == 0 || ndx == 1) p = "int"; break; /* dup2 */ case 63: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getppid */ case 64: /* getpgrp */ case 65: /* setsid */ case 66: /* linux_sigaction */ case 67: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sgetmask */ case 68: /* linux_ssetmask */ case 69: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setreuid16 */ case 70: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setregid16 */ case 71: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigsuspend */ case 72: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigpending */ case 73: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sethostname */ case 74: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setrlimit */ case 75: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_old_getrlimit */ case 76: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getrusage */ case 77: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_gettimeofday */ case 78: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_settimeofday */ case 79: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getgroups16 */ case 80: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setgroups16 */ case 81: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_old_select */ case 82: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_symlink */ case 83: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lstat */ case 84: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_readlink */ case 85: if (ndx == 0 || ndx == 1) p = "int"; break; /* swapon */ case 87: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_reboot */ case 88: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_readdir */ case 89: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mmap */ case 90: if (ndx == 0 || ndx == 1) p = "int"; break; /* munmap */ case 91: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_truncate */ case 92: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ftruncate */ case 93: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchmod */ case 94: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchown */ case 95: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getpriority */ case 96: if (ndx == 0 || ndx == 1) p = "int"; break; /* setpriority */ case 97: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_statfs */ case 99: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstatfs */ case 100: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_socketcall */ case 102: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_syslog */ case 103: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setitimer */ case 104: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getitimer */ case 105: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newstat */ case 106: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newlstat */ case 107: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newfstat */ case 108: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_uname */ case 109: /* linux_iopl */ case 110: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_vhangup */ case 111: /* linux_wait4 */ case 114: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_swapoff */ case 115: /* linux_sysinfo */ case 116: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ipc */ case 117: if (ndx == 0 || ndx == 1) p = "int"; break; /* fsync */ case 118: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigreturn */ case 119: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clone */ case 120: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setdomainname */ case 121: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newuname */ case 122: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_adjtimex */ case 124: /* linux_mprotect */ case 125: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigprocmask */ case 126: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_create_module */ case 127: /* linux_init_module */ case 128: /* linux_delete_module */ case 129: /* linux_get_kernel_syms */ case 130: /* linux_quotactl */ case 131: /* getpgid */ case 132: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchdir */ case 133: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_bdflush */ case 134: /* linux_sysfs */ case 135: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_personality */ case 136: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsuid16 */ case 138: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsgid16 */ case 139: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_llseek */ case 140: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getdents */ case 141: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_select */ case 142: if (ndx == 0 || ndx == 1) p = "int"; break; /* flock */ case 143: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_msync */ case 144: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_readv */ case 145: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_writev */ case 146: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getsid */ case 147: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fdatasync */ case 148: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sysctl */ case 149: if (ndx == 0 || ndx == 1) p = "int"; break; /* mlock */ case 150: if (ndx == 0 || ndx == 1) p = "int"; break; /* munlock */ case 151: if (ndx == 0 || ndx == 1) p = "int"; break; /* mlockall */ case 152: if (ndx == 0 || ndx == 1) p = "int"; break; /* munlockall */ case 153: /* linux_sched_setparam */ case 154: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_getparam */ case 155: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_setscheduler */ case 156: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_getscheduler */ case 157: if (ndx == 0 || ndx == 1) p = "int"; break; /* sched_yield */ case 158: /* linux_sched_get_priority_max */ case 159: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_get_priority_min */ case 160: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_rr_get_interval */ case 161: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_nanosleep */ case 162: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mremap */ case 163: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setresuid16 */ case 164: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getresuid16 */ case 165: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_query_module */ case 167: /* poll */ case 168: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_nfsservctl */ case 169: /* linux_setresgid16 */ case 170: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getresgid16 */ case 171: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_prctl */ case 172: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigreturn */ case 173: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigaction */ case 174: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigprocmask */ case 175: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigpending */ case 176: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigtimedwait */ case 177: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigqueueinfo */ case 178: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigsuspend */ case 179: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pread */ case 180: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pwrite */ case 181: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chown16 */ case 182: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getcwd */ case 183: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_capget */ case 184: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_capset */ case 185: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigaltstack */ case 186: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sendfile */ case 187: /* linux_vfork */ case 190: /* linux_getrlimit */ case 191: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mmap2 */ case 192: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_truncate64 */ case 193: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ftruncate64 */ case 194: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_stat64 */ case 195: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lstat64 */ case 196: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstat64 */ case 197: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lchown */ case 198: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getuid */ case 199: /* linux_getgid */ case 200: /* geteuid */ case 201: /* getegid */ case 202: /* setreuid */ case 203: if (ndx == 0 || ndx == 1) p = "int"; break; /* setregid */ case 204: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getgroups */ case 205: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setgroups */ case 206: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchown */ case 207: /* setresuid */ case 208: if (ndx == 0 || ndx == 1) p = "int"; break; /* getresuid */ case 209: if (ndx == 0 || ndx == 1) p = "int"; break; /* setresgid */ case 210: if (ndx == 0 || ndx == 1) p = "int"; break; /* getresgid */ case 211: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chown */ case 212: if (ndx == 0 || ndx == 1) p = "int"; break; /* setuid */ case 213: if (ndx == 0 || ndx == 1) p = "int"; break; /* setgid */ case 214: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsuid */ case 215: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsgid */ case 216: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pivot_root */ case 217: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mincore */ case 218: if (ndx == 0 || ndx == 1) p = "int"; break; /* madvise */ case 219: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getdents64 */ case 220: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fcntl64 */ case 221: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_gettid */ case 224: /* linux_setxattr */ case 226: /* linux_lsetxattr */ case 227: /* linux_fsetxattr */ case 228: /* linux_getxattr */ case 229: /* linux_lgetxattr */ case 230: /* linux_fgetxattr */ case 231: /* linux_listxattr */ case 232: /* linux_llistxattr */ case 233: /* linux_flistxattr */ case 234: /* linux_removexattr */ case 235: /* linux_lremovexattr */ case 236: /* linux_fremovexattr */ case 237: /* linux_tkill */ case 238: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sys_futex */ case 240: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_setaffinity */ case 241: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_getaffinity */ case 242: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_set_thread_area */ case 243: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fadvise64 */ case 250: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_exit_group */ case 252: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lookup_dcookie */ case 253: /* linux_epoll_create */ case 254: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_ctl */ case 255: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_wait */ case 256: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_remap_file_pages */ case 257: /* linux_set_tid_address */ case 258: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_create */ case 259: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_settime */ case 260: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_gettime */ case 261: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_getoverrun */ case 262: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_delete */ case 263: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_settime */ case 264: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_gettime */ case 265: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_getres */ case 266: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_nanosleep */ case 267: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_statfs64 */ case 268: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstatfs64 */ case 269: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_tgkill */ case 270: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_utimes */ case 271: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fadvise64_64 */ case 272: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mbind */ case 274: /* linux_get_mempolicy */ case 275: /* linux_set_mempolicy */ case 276: /* linux_mq_open */ case 277: /* linux_mq_unlink */ case 278: /* linux_mq_timedsend */ case 279: /* linux_mq_timedreceive */ case 280: /* linux_mq_notify */ case 281: /* linux_mq_getsetattr */ case 282: /* linux_kexec_load */ case 283: /* linux_waitid */ case 284: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_add_key */ case 286: /* linux_request_key */ case 287: /* linux_keyctl */ case 288: /* linux_ioprio_set */ case 289: /* linux_ioprio_get */ case 290: /* linux_inotify_init */ case 291: /* linux_inotify_add_watch */ case 292: /* linux_inotify_rm_watch */ case 293: /* linux_migrate_pages */ case 294: /* linux_openat */ case 295: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mkdirat */ case 296: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mknodat */ case 297: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fchownat */ case 298: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_futimesat */ case 299: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstatat64 */ case 300: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_unlinkat */ case 301: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_renameat */ case 302: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_linkat */ case 303: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_symlinkat */ case 304: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_readlinkat */ case 305: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fchmodat */ case 306: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_faccessat */ case 307: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pselect6 */ case 308: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ppoll */ case 309: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_unshare */ case 310: /* linux_set_robust_list */ case 311: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_get_robust_list */ case 312: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_splice */ case 313: /* linux_sync_file_range */ case 314: /* linux_tee */ case 315: /* linux_vmsplice */ case 316: /* linux_move_pages */ case 317: /* linux_getcpu */ case 318: /* linux_epoll_pwait */ case 319: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_utimensat */ case 320: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_signalfd */ case 321: /* linux_timerfd_create */ case 322: /* linux_eventfd */ case 323: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fallocate */ case 324: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timerfd_settime */ case 325: /* linux_timerfd_gettime */ case 326: /* linux_signalfd4 */ case 327: /* linux_eventfd2 */ case 328: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_create1 */ case 329: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_dup3 */ case 330: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pipe2 */ case 331: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_inotify_init1 */ case 332: /* linux_preadv */ case 333: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_pwritev */ case 334: - /* linux_rt_tsigqueueinfo */ + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_tgsigqueueinfo */ case 335: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_perf_event_open */ case 336: /* linux_recvmmsg */ case 337: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fanotify_init */ case 338: /* linux_fanotify_mark */ case 339: /* linux_prlimit64 */ case 340: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_name_to_handle_at */ case 341: /* linux_open_by_handle_at */ case 342: /* linux_clock_adjtime */ case 343: /* linux_syncfs */ case 344: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sendmmsg */ case 345: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setns */ case 346: /* linux_process_vm_readv */ case 347: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_process_vm_writev */ case 348: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_kcmp */ + case 349: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_finit_module */ + case 350: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_setattr */ + case 351: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_getattr */ + case 352: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_renameat2 */ + case 353: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_seccomp */ + case 354: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getrandom */ + case 355: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_memfd_create */ + case 356: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_bpf */ + case 357: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_execveat */ + case 358: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_socket */ + case 359: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_socketpair */ + case 360: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_bind */ + case 361: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_connect */ + case 362: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_listen */ + case 363: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_accept4 */ + case 364: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getsockopt */ + case 365: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setsockopt */ + case 366: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getsockname */ + case 367: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getpeername */ + case 368: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sendto */ + case 369: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sendmsg */ + case 370: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_recvfrom */ + case 371: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_recvmsg */ + case 372: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_shutdown */ + case 373: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_userfaultfd */ + case 374: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_membarrier */ + case 375: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mlock2 */ + case 376: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_copy_file_range */ + case 377: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_preadv2 */ + case 378: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pwritev2 */ + case 379: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_mprotect */ + case 380: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_alloc */ + case 381: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_free */ + case 382: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; if (p != NULL) strlcpy(desc, p, descsz); } Index: projects/ipsec/sys/amd64/linux32/syscalls.master =================================================================== --- projects/ipsec/sys/amd64/linux32/syscalls.master (revision 313312) +++ projects/ipsec/sys/amd64/linux32/syscalls.master (revision 313313) @@ -1,584 +1,688 @@ $FreeBSD$ ; @(#)syscalls.master 8.1 (Berkeley) 7/19/93 ; System call name/number master file (or rather, slave, from LINUX). ; Processed to create linux32_sysent.c, linux32_proto.h and linux32_syscall.h. ; Columns: number audit type nargs name alt{name,tag,rtyp}/comments ; number system call number, must be in order ; audit the audit event associated with the system call ; A value of AUE_NULL means no auditing, but it also means that ; there is no audit event for the call at this time. For the ; case where the event exists, but we don't want auditing, the ; event should be #defined to AUE_NULL in audit_kevents.h. -; type one of STD, OBSOL, UNIMPL +; type one of STD, NOPROTO, UNIMPL ; name psuedo-prototype of syscall routine ; If one of the following alts is different, then all appear: ; altname name of system call if different ; alttag name of args struct tag if different from [o]`name'"_args" ; altrtyp return type if not int (bogus - syscalls always return int) -; for UNIMPL/OBSOL, name continues with comments +; for UNIMPL, name continues with comments ; types: ; STD always included -; OBSOL obsolete, not included in system, only specifies name ; UNIMPL not implemented, placeholder only +; NOPROTO same as STD except do not create structure or +; function prototype in sys/sysproto.h. Does add a +; definition to syscall.h besides adding a sysent. #include "opt_compat.h" #include #include #include #include #include #include ; Isn't pretty, but there seems to be no other way to trap nosys #define nosys linux_nosys ; #ifdef's, etc. may be included, and are copied to the output files. 0 AUE_NULL UNIMPL setup 1 AUE_EXIT STD { void linux_exit(int rval); } 2 AUE_FORK STD { int linux_fork(void); } 3 AUE_NULL NOPROTO { int read(int fd, char *buf, \ u_int nbyte); } 4 AUE_NULL NOPROTO { int write(int fd, char *buf, \ u_int nbyte); } 5 AUE_OPEN_RWTC STD { int linux_open(char *path, l_int flags, \ l_int mode); } 6 AUE_CLOSE NOPROTO { int close(int fd); } 7 AUE_WAIT4 STD { int linux_waitpid(l_pid_t pid, \ l_int *status, l_int options); } 8 AUE_CREAT STD { int linux_creat(char *path, \ l_int mode); } 9 AUE_LINK STD { int linux_link(char *path, char *to); } 10 AUE_UNLINK STD { int linux_unlink(char *path); } 11 AUE_EXECVE STD { int linux_execve(char *path, uint32_t *argp, \ uint32_t *envp); } 12 AUE_CHDIR STD { int linux_chdir(char *path); } 13 AUE_NULL STD { int linux_time(l_time_t *tm); } 14 AUE_MKNOD STD { int linux_mknod(char *path, l_int mode, \ l_dev_t dev); } 15 AUE_CHMOD STD { int linux_chmod(char *path, \ l_mode_t mode); } 16 AUE_LCHOWN STD { int linux_lchown16(char *path, \ l_uid16_t uid, l_gid16_t gid); } 17 AUE_NULL UNIMPL break 18 AUE_STAT STD { int linux_stat(char *path, \ struct linux_stat *up); } 19 AUE_LSEEK STD { int linux_lseek(l_uint fdes, l_off_t off, \ l_int whence); } 20 AUE_GETPID STD { int linux_getpid(void); } 21 AUE_MOUNT STD { int linux_mount(char *specialfile, \ char *dir, char *filesystemtype, \ l_ulong rwflag, void *data); } 22 AUE_UMOUNT STD { int linux_oldumount(char *path); } 23 AUE_SETUID STD { int linux_setuid16(l_uid16_t uid); } 24 AUE_GETUID STD { int linux_getuid16(void); } 25 AUE_SETTIMEOFDAY STD { int linux_stime(void); } 26 AUE_PTRACE STD { int linux_ptrace(l_long req, l_long pid, \ l_long addr, l_long data); } 27 AUE_NULL STD { int linux_alarm(l_uint secs); } 28 AUE_FSTAT UNIMPL fstat 29 AUE_NULL STD { int linux_pause(void); } 30 AUE_UTIME STD { int linux_utime(char *fname, \ struct l_utimbuf *times); } 31 AUE_NULL UNIMPL stty 32 AUE_NULL UNIMPL gtty 33 AUE_ACCESS STD { int linux_access(char *path, l_int amode); } 34 AUE_NICE STD { int linux_nice(l_int inc); } 35 AUE_NULL UNIMPL ftime 36 AUE_SYNC NOPROTO { int sync(void); } 37 AUE_KILL STD { int linux_kill(l_int pid, l_int signum); } 38 AUE_RENAME STD { int linux_rename(char *from, char *to); } 39 AUE_MKDIR STD { int linux_mkdir(char *path, l_int mode); } 40 AUE_RMDIR STD { int linux_rmdir(char *path); } 41 AUE_DUP NOPROTO { int dup(u_int fd); } 42 AUE_PIPE STD { int linux_pipe(l_int *pipefds); } 43 AUE_NULL STD { int linux_times(struct l_times_argv *buf); } 44 AUE_NULL UNIMPL prof 45 AUE_NULL STD { int linux_brk(l_ulong dsend); } 46 AUE_SETGID STD { int linux_setgid16(l_gid16_t gid); } 47 AUE_GETGID STD { int linux_getgid16(void); } 48 AUE_NULL STD { int linux_signal(l_int sig, \ l_handler_t handler); } 49 AUE_GETEUID STD { int linux_geteuid16(void); } 50 AUE_GETEGID STD { int linux_getegid16(void); } 51 AUE_ACCT NOPROTO { int acct(char *path); } 52 AUE_UMOUNT STD { int linux_umount(char *path, l_int flags); } 53 AUE_NULL UNIMPL lock 54 AUE_IOCTL STD { int linux_ioctl(l_uint fd, l_uint cmd, \ uintptr_t arg); } 55 AUE_FCNTL STD { int linux_fcntl(l_uint fd, l_uint cmd, \ uintptr_t arg); } 56 AUE_NULL UNIMPL mpx 57 AUE_SETPGRP NOPROTO { int setpgid(int pid, int pgid); } 58 AUE_NULL UNIMPL ulimit 59 AUE_NULL STD { int linux_olduname(void); } 60 AUE_UMASK NOPROTO { int umask(int newmask); } 61 AUE_CHROOT NOPROTO { int chroot(char *path); } 62 AUE_NULL STD { int linux_ustat(l_dev_t dev, \ struct l_ustat *ubuf); } 63 AUE_DUP2 NOPROTO { int dup2(u_int from, u_int to); } 64 AUE_GETPPID STD { int linux_getppid(void); } 65 AUE_GETPGRP NOPROTO { int getpgrp(void); } 66 AUE_SETSID NOPROTO { int setsid(void); } 67 AUE_NULL STD { int linux_sigaction(l_int sig, \ l_osigaction_t *nsa, \ l_osigaction_t *osa); } 68 AUE_NULL STD { int linux_sgetmask(void); } 69 AUE_NULL STD { int linux_ssetmask(l_osigset_t mask); } 70 AUE_SETREUID STD { int linux_setreuid16(l_uid16_t ruid, \ l_uid16_t euid); } 71 AUE_SETREGID STD { int linux_setregid16(l_gid16_t rgid, \ l_gid16_t egid); } 72 AUE_NULL STD { int linux_sigsuspend(l_int hist0, \ l_int hist1, l_osigset_t mask); } 73 AUE_NULL STD { int linux_sigpending(l_osigset_t *mask); } 74 AUE_SYSCTL STD { int linux_sethostname(char *hostname, \ u_int len); } 75 AUE_SETRLIMIT STD { int linux_setrlimit(l_uint resource, \ struct l_rlimit *rlim); } 76 AUE_GETRLIMIT STD { int linux_old_getrlimit(l_uint resource, \ struct l_rlimit *rlim); } 77 AUE_GETRUSAGE STD { int linux_getrusage(int who, \ struct l_rusage *rusage); } 78 AUE_NULL STD { int linux_gettimeofday( \ struct l_timeval *tp, \ struct timezone *tzp); } 79 AUE_SETTIMEOFDAY STD { int linux_settimeofday( \ struct l_timeval *tp, \ struct timezone *tzp); } 80 AUE_GETGROUPS STD { int linux_getgroups16(l_uint gidsetsize, \ l_gid16_t *gidset); } 81 AUE_SETGROUPS STD { int linux_setgroups16(l_uint gidsetsize, \ l_gid16_t *gidset); } 82 AUE_SELECT STD { int linux_old_select( \ struct l_old_select_argv *ptr); } 83 AUE_SYMLINK STD { int linux_symlink(char *path, char *to); } ; 84: oldlstat 84 AUE_LSTAT STD { int linux_lstat(char *path, struct linux_lstat *up); } 85 AUE_READLINK STD { int linux_readlink(char *name, char *buf, \ l_int count); } 86 AUE_USELIB UNIMPL linux_uselib 87 AUE_SWAPON NOPROTO { int swapon(char *name); } 88 AUE_REBOOT STD { int linux_reboot(l_int magic1, \ l_int magic2, l_uint cmd, void *arg); } ; 89: old_readdir 89 AUE_GETDIRENTRIES STD { int linux_readdir(l_uint fd, \ struct l_dirent *dent, l_uint count); } ; 90: old_mmap 90 AUE_MMAP STD { int linux_mmap(struct l_mmap_argv *ptr); } 91 AUE_MUNMAP NOPROTO { int munmap(caddr_t addr, int len); } 92 AUE_TRUNCATE STD { int linux_truncate(char *path, \ l_ulong length); } 93 AUE_FTRUNCATE STD { int linux_ftruncate(int fd, long length); } 94 AUE_FCHMOD NOPROTO { int fchmod(int fd, int mode); } 95 AUE_FCHOWN NOPROTO { int fchown(int fd, int uid, int gid); } 96 AUE_GETPRIORITY STD { int linux_getpriority(int which, int who); } 97 AUE_SETPRIORITY NOPROTO { int setpriority(int which, int who, \ int prio); } 98 AUE_PROFILE UNIMPL profil 99 AUE_STATFS STD { int linux_statfs(char *path, \ struct l_statfs_buf *buf); } 100 AUE_FSTATFS STD { int linux_fstatfs(l_uint fd, \ struct l_statfs_buf *buf); } 101 AUE_NULL UNIMPL ioperm 102 AUE_NULL STD { int linux_socketcall(l_int what, \ l_ulong args); } 103 AUE_NULL STD { int linux_syslog(l_int type, char *buf, \ l_int len); } 104 AUE_SETITIMER STD { int linux_setitimer(l_int which, \ struct l_itimerval *itv, \ struct l_itimerval *oitv); } 105 AUE_GETITIMER STD { int linux_getitimer(l_int which, \ struct l_itimerval *itv); } 106 AUE_STAT STD { int linux_newstat(char *path, \ struct l_newstat *buf); } 107 AUE_LSTAT STD { int linux_newlstat(char *path, \ struct l_newstat *buf); } 108 AUE_FSTAT STD { int linux_newfstat(l_uint fd, \ struct l_newstat *buf); } ; 109: olduname 109 AUE_NULL STD { int linux_uname(void); } 110 AUE_NULL STD { int linux_iopl(l_int level); } 111 AUE_NULL STD { int linux_vhangup(void); } 112 AUE_NULL UNIMPL idle 113 AUE_NULL UNIMPL vm86old 114 AUE_WAIT4 STD { int linux_wait4(l_pid_t pid, \ l_int *status, l_int options, \ struct l_rusage *rusage); } 115 AUE_SWAPOFF STD { int linux_swapoff(void); } 116 AUE_NULL STD { int linux_sysinfo(struct l_sysinfo *info); } 117 AUE_NULL STD { int linux_ipc(l_uint what, l_int arg1, \ l_int arg2, l_int arg3, void *ptr, \ l_long arg5); } 118 AUE_FSYNC NOPROTO { int fsync(int fd); } 119 AUE_SIGRETURN STD { int linux_sigreturn( \ struct l_sigframe *sfp); } 120 AUE_RFORK STD { int linux_clone(l_int flags, void *stack, \ void *parent_tidptr, void *tls, void * child_tidptr); } 121 AUE_SYSCTL STD { int linux_setdomainname(char *name, \ int len); } 122 AUE_NULL STD { int linux_newuname( \ struct l_new_utsname *buf); } 123 AUE_NULL UNIMPL modify_ldt 124 AUE_ADJTIME STD { int linux_adjtimex(void); } 125 AUE_MPROTECT STD { int linux_mprotect(caddr_t addr, int len, \ int prot); } 126 AUE_SIGPROCMASK STD { int linux_sigprocmask(l_int how, \ l_osigset_t *mask, l_osigset_t *omask); } 127 AUE_NULL STD { int linux_create_module(void); } 128 AUE_NULL STD { int linux_init_module(void); } 129 AUE_NULL STD { int linux_delete_module(void); } 130 AUE_NULL STD { int linux_get_kernel_syms(void); } 131 AUE_QUOTACTL STD { int linux_quotactl(void); } 132 AUE_GETPGID NOPROTO { int getpgid(int pid); } 133 AUE_FCHDIR NOPROTO { int fchdir(int fd); } 134 AUE_BDFLUSH STD { int linux_bdflush(void); } 135 AUE_NULL STD { int linux_sysfs(l_int option, \ l_ulong arg1, l_ulong arg2); } 136 AUE_PERSONALITY STD { int linux_personality(l_uint per); } 137 AUE_NULL UNIMPL afs_syscall 138 AUE_SETFSUID STD { int linux_setfsuid16(l_uid16_t uid); } 139 AUE_SETFSGID STD { int linux_setfsgid16(l_gid16_t gid); } 140 AUE_LSEEK STD { int linux_llseek(l_int fd, l_ulong ohigh, \ l_ulong olow, l_loff_t *res, \ l_uint whence); } 141 AUE_GETDIRENTRIES STD { int linux_getdents(l_uint fd, void *dent, \ l_uint count); } ; 142: newselect 142 AUE_SELECT STD { int linux_select(l_int nfds, \ l_fd_set *readfds, l_fd_set *writefds, \ l_fd_set *exceptfds, \ struct l_timeval *timeout); } 143 AUE_FLOCK NOPROTO { int flock(int fd, int how); } 144 AUE_MSYNC STD { int linux_msync(l_ulong addr, \ l_size_t len, l_int fl); } 145 AUE_READV STD { int linux_readv(l_ulong fd, struct l_iovec32 *iovp, \ l_ulong iovcnt); } 146 AUE_WRITEV STD { int linux_writev(l_ulong fd, struct l_iovec32 *iovp, \ l_ulong iovcnt); } 147 AUE_GETSID STD { int linux_getsid(l_pid_t pid); } 148 AUE_NULL STD { int linux_fdatasync(l_uint fd); } 149 AUE_SYSCTL STD { int linux_sysctl( \ struct l___sysctl_args *args); } 150 AUE_MLOCK NOPROTO { int mlock(const void *addr, size_t len); } 151 AUE_MUNLOCK NOPROTO { int munlock(const void *addr, size_t len); } 152 AUE_MLOCKALL NOPROTO { int mlockall(int how); } 153 AUE_MUNLOCKALL NOPROTO { int munlockall(void); } 154 AUE_SCHED_SETPARAM STD { int linux_sched_setparam(l_pid_t pid, \ struct sched_param *param); } 155 AUE_SCHED_GETPARAM STD { int linux_sched_getparam(l_pid_t pid, \ struct sched_param *param); } 156 AUE_SCHED_SETSCHEDULER STD { int linux_sched_setscheduler( \ l_pid_t pid, l_int policy, \ struct sched_param *param); } 157 AUE_SCHED_GETSCHEDULER STD { int linux_sched_getscheduler( \ l_pid_t pid); } 158 AUE_NULL NOPROTO { int sched_yield(void); } 159 AUE_SCHED_GET_PRIORITY_MAX STD { int linux_sched_get_priority_max( \ l_int policy); } 160 AUE_SCHED_GET_PRIORITY_MIN STD { int linux_sched_get_priority_min( \ l_int policy); } 161 AUE_SCHED_RR_GET_INTERVAL STD { int linux_sched_rr_get_interval(l_pid_t pid, \ struct l_timespec *interval); } 162 AUE_NULL STD { int linux_nanosleep( \ const struct l_timespec *rqtp, \ struct l_timespec *rmtp); } 163 AUE_NULL STD { int linux_mremap(l_ulong addr, \ l_ulong old_len, l_ulong new_len, \ l_ulong flags, l_ulong new_addr); } 164 AUE_SETRESUID STD { int linux_setresuid16(l_uid16_t ruid, \ l_uid16_t euid, l_uid16_t suid); } 165 AUE_GETRESUID STD { int linux_getresuid16(l_uid16_t *ruid, \ l_uid16_t *euid, l_uid16_t *suid); } 166 AUE_NULL UNIMPL vm86 167 AUE_NULL STD { int linux_query_module(void); } 168 AUE_POLL NOPROTO { int poll(struct pollfd *fds, \ unsigned int nfds, int timeout); } 169 AUE_NULL STD { int linux_nfsservctl(void); } 170 AUE_SETRESGID STD { int linux_setresgid16(l_gid16_t rgid, \ l_gid16_t egid, l_gid16_t sgid); } 171 AUE_GETRESGID STD { int linux_getresgid16(l_gid16_t *rgid, \ l_gid16_t *egid, l_gid16_t *sgid); } 172 AUE_PRCTL STD { int linux_prctl(l_int option, l_int arg2, l_int arg3, \ l_int arg4, l_int arg5); } 173 AUE_NULL STD { int linux_rt_sigreturn( \ struct l_ucontext *ucp); } 174 AUE_NULL STD { int linux_rt_sigaction(l_int sig, \ l_sigaction_t *act, l_sigaction_t *oact, \ l_size_t sigsetsize); } 175 AUE_NULL STD { int linux_rt_sigprocmask(l_int how, \ l_sigset_t *mask, l_sigset_t *omask, \ l_size_t sigsetsize); } 176 AUE_NULL STD { int linux_rt_sigpending(l_sigset_t *set, \ l_size_t sigsetsize); } 177 AUE_NULL STD { int linux_rt_sigtimedwait(l_sigset_t *mask, \ l_siginfo_t *ptr, \ struct l_timeval *timeout, \ l_size_t sigsetsize); } 178 AUE_NULL STD { int linux_rt_sigqueueinfo(l_pid_t pid, l_int sig, \ l_siginfo_t *info); } 179 AUE_NULL STD { int linux_rt_sigsuspend( \ l_sigset_t *newset, \ l_size_t sigsetsize); } 180 AUE_PREAD STD { int linux_pread(l_uint fd, char *buf, \ l_size_t nbyte, l_loff_t offset); } 181 AUE_PWRITE STD { int linux_pwrite(l_uint fd, char *buf, \ l_size_t nbyte, l_loff_t offset); } 182 AUE_CHOWN STD { int linux_chown16(char *path, \ l_uid16_t uid, l_gid16_t gid); } 183 AUE_GETCWD STD { int linux_getcwd(char *buf, \ l_ulong bufsize); } 184 AUE_CAPGET STD { int linux_capget(struct l_user_cap_header *hdrp, \ struct l_user_cap_data *datap); } 185 AUE_CAPSET STD { int linux_capset(struct l_user_cap_header *hdrp, \ struct l_user_cap_data *datap); } 186 AUE_NULL STD { int linux_sigaltstack(l_stack_t *uss, \ l_stack_t *uoss); } 187 AUE_SENDFILE STD { int linux_sendfile(void); } 188 AUE_GETPMSG UNIMPL getpmsg 189 AUE_PUTPMSG UNIMPL putpmsg 190 AUE_VFORK STD { int linux_vfork(void); } ; 191: ugetrlimit 191 AUE_GETRLIMIT STD { int linux_getrlimit(l_uint resource, \ struct l_rlimit *rlim); } 192 AUE_MMAP STD { int linux_mmap2(l_ulong addr, l_ulong len, \ l_ulong prot, l_ulong flags, l_ulong fd, \ l_ulong pgoff); } 193 AUE_TRUNCATE STD { int linux_truncate64(char *path, \ l_loff_t length); } 194 AUE_FTRUNCATE STD { int linux_ftruncate64(l_uint fd, \ l_loff_t length); } 195 AUE_STAT STD { int linux_stat64(const char *filename, \ struct l_stat64 *statbuf); } 196 AUE_LSTAT STD { int linux_lstat64(const char *filename, \ struct l_stat64 *statbuf); } 197 AUE_FSTAT STD { int linux_fstat64(l_int fd, \ struct l_stat64 *statbuf); } 198 AUE_LCHOWN STD { int linux_lchown(char *path, l_uid_t uid, \ l_gid_t gid); } 199 AUE_GETUID STD { int linux_getuid(void); } 200 AUE_GETGID STD { int linux_getgid(void); } 201 AUE_GETEUID NOPROTO { int geteuid(void); } 202 AUE_GETEGID NOPROTO { int getegid(void); } 203 AUE_SETREUID NOPROTO { int setreuid(uid_t ruid, uid_t euid); } 204 AUE_SETREGID NOPROTO { int setregid(gid_t rgid, gid_t egid); } 205 AUE_GETGROUPS STD { int linux_getgroups(l_int gidsetsize, \ l_gid_t *grouplist); } 206 AUE_SETGROUPS STD { int linux_setgroups(l_int gidsetsize, \ l_gid_t *grouplist); } 207 AUE_FCHOWN NODEF fchown fchown fchown_args int 208 AUE_SETRESUID NOPROTO { int setresuid(uid_t ruid, uid_t euid, \ uid_t suid); } 209 AUE_GETRESUID NOPROTO { int getresuid(uid_t *ruid, uid_t *euid, \ uid_t *suid); } 210 AUE_SETRESGID NOPROTO { int setresgid(gid_t rgid, gid_t egid, \ gid_t sgid); } 211 AUE_GETRESGID NOPROTO { int getresgid(gid_t *rgid, gid_t *egid, \ gid_t *sgid); } 212 AUE_CHOWN STD { int linux_chown(char *path, l_uid_t uid, \ l_gid_t gid); } 213 AUE_SETUID NOPROTO { int setuid(uid_t uid); } 214 AUE_SETGID NOPROTO { int setgid(gid_t gid); } 215 AUE_SETFSUID STD { int linux_setfsuid(l_uid_t uid); } 216 AUE_SETFSGID STD { int linux_setfsgid(l_gid_t gid); } 217 AUE_PIVOT_ROOT STD { int linux_pivot_root(char *new_root, \ char *put_old); } 218 AUE_MINCORE STD { int linux_mincore(l_ulong start, \ l_size_t len, u_char *vec); } 219 AUE_MADVISE NOPROTO { int madvise(void *addr, size_t len, \ int behav); } 220 AUE_GETDIRENTRIES STD { int linux_getdents64(l_uint fd, \ void *dirent, l_uint count); } 221 AUE_FCNTL STD { int linux_fcntl64(l_uint fd, l_uint cmd, \ uintptr_t arg); } 222 AUE_NULL UNIMPL 223 AUE_NULL UNIMPL 224 AUE_NULL STD { long linux_gettid(void); } 225 AUE_NULL UNIMPL linux_readahead 226 AUE_NULL STD { int linux_setxattr(void); } 227 AUE_NULL STD { int linux_lsetxattr(void); } 228 AUE_NULL STD { int linux_fsetxattr(void); } 229 AUE_NULL STD { int linux_getxattr(void); } 230 AUE_NULL STD { int linux_lgetxattr(void); } 231 AUE_NULL STD { int linux_fgetxattr(void); } 232 AUE_NULL STD { int linux_listxattr(void); } 233 AUE_NULL STD { int linux_llistxattr(void); } 234 AUE_NULL STD { int linux_flistxattr(void); } 235 AUE_NULL STD { int linux_removexattr(void); } 236 AUE_NULL STD { int linux_lremovexattr(void); } 237 AUE_NULL STD { int linux_fremovexattr(void); } 238 AUE_NULL STD { int linux_tkill(int tid, int sig); } 239 AUE_SENDFILE UNIMPL linux_sendfile64 240 AUE_NULL STD { int linux_sys_futex(void *uaddr, int op, uint32_t val, \ struct l_timespec *timeout, uint32_t *uaddr2, uint32_t val3); } 241 AUE_NULL STD { int linux_sched_setaffinity(l_pid_t pid, l_uint len, \ l_ulong *user_mask_ptr); } 242 AUE_NULL STD { int linux_sched_getaffinity(l_pid_t pid, l_uint len, \ l_ulong *user_mask_ptr); } 243 AUE_NULL STD { int linux_set_thread_area(struct l_user_desc *desc); } 244 AUE_NULL UNIMPL linux_get_thread_area 245 AUE_NULL UNIMPL linux_io_setup 246 AUE_NULL UNIMPL linux_io_destroy 247 AUE_NULL UNIMPL linux_io_getevents 248 AUE_NULL UNIMPL linux_io_submit 249 AUE_NULL UNIMPL linux_io_cancel 250 AUE_NULL STD { int linux_fadvise64(int fd, l_loff_t offset, \ l_size_t len, int advice); } 251 AUE_NULL UNIMPL 252 AUE_EXIT STD { int linux_exit_group(int error_code); } 253 AUE_NULL STD { int linux_lookup_dcookie(void); } 254 AUE_NULL STD { int linux_epoll_create(l_int size); } 255 AUE_NULL STD { int linux_epoll_ctl(l_int epfd, l_int op, l_int fd, \ struct epoll_event *event); } 256 AUE_NULL STD { int linux_epoll_wait(l_int epfd, struct epoll_event *events, \ l_int maxevents, l_int timeout); } 257 AUE_NULL STD { int linux_remap_file_pages(void); } 258 AUE_NULL STD { int linux_set_tid_address(int *tidptr); } 259 AUE_NULL STD { int linux_timer_create(clockid_t clock_id, \ struct sigevent *evp, l_timer_t *timerid); } 260 AUE_NULL STD { int linux_timer_settime(l_timer_t timerid, l_int flags, \ const struct itimerspec *new, struct itimerspec *old); } 261 AUE_NULL STD { int linux_timer_gettime(l_timer_t timerid, struct itimerspec *setting); } 262 AUE_NULL STD { int linux_timer_getoverrun(l_timer_t timerid); } 263 AUE_NULL STD { int linux_timer_delete(l_timer_t timerid); } 264 AUE_CLOCK_SETTIME STD { int linux_clock_settime(clockid_t which, struct l_timespec *tp); } 265 AUE_NULL STD { int linux_clock_gettime(clockid_t which, struct l_timespec *tp); } 266 AUE_NULL STD { int linux_clock_getres(clockid_t which, struct l_timespec *tp); } 267 AUE_NULL STD { int linux_clock_nanosleep(clockid_t which, int flags, \ struct l_timespec *rqtp, struct l_timespec *rmtp); } 268 AUE_STATFS STD { int linux_statfs64(char *path, size_t bufsize, struct l_statfs64_buf *buf); } 269 AUE_FSTATFS STD { int linux_fstatfs64(l_uint fd, size_t bufsize, struct l_statfs64_buf *buf); } 270 AUE_NULL STD { int linux_tgkill(int tgid, int pid, int sig); } 271 AUE_UTIMES STD { int linux_utimes(char *fname, \ struct l_timeval *tptr); } 272 AUE_NULL STD { int linux_fadvise64_64(int fd, \ l_loff_t offset, l_loff_t len, \ int advice); } 273 AUE_NULL UNIMPL vserver 274 AUE_NULL STD { int linux_mbind(void); } 275 AUE_NULL STD { int linux_get_mempolicy(void); } 276 AUE_NULL STD { int linux_set_mempolicy(void); } ; linux 2.6.6: 277 AUE_NULL STD { int linux_mq_open(void); } 278 AUE_NULL STD { int linux_mq_unlink(void); } 279 AUE_NULL STD { int linux_mq_timedsend(void); } 280 AUE_NULL STD { int linux_mq_timedreceive(void); } 281 AUE_NULL STD { int linux_mq_notify(void); } 282 AUE_NULL STD { int linux_mq_getsetattr(void); } 283 AUE_NULL STD { int linux_kexec_load(void); } 284 AUE_WAIT6 STD { int linux_waitid(int idtype, l_pid_t id, \ l_siginfo_t *info, int options, \ struct l_rusage *rusage); } 285 AUE_NULL UNIMPL ; linux 2.6.11: 286 AUE_NULL STD { int linux_add_key(void); } 287 AUE_NULL STD { int linux_request_key(void); } 288 AUE_NULL STD { int linux_keyctl(void); } ; linux 2.6.13: 289 AUE_NULL STD { int linux_ioprio_set(void); } 290 AUE_NULL STD { int linux_ioprio_get(void); } 291 AUE_NULL STD { int linux_inotify_init(void); } 292 AUE_NULL STD { int linux_inotify_add_watch(void); } 293 AUE_NULL STD { int linux_inotify_rm_watch(void); } ; linux 2.6.16: 294 AUE_NULL STD { int linux_migrate_pages(void); } 295 AUE_OPEN_RWTC STD { int linux_openat(l_int dfd, const char *filename, \ l_int flags, l_int mode); } 296 AUE_MKDIRAT STD { int linux_mkdirat(l_int dfd, const char *pathname, \ l_int mode); } 297 AUE_MKNODAT STD { int linux_mknodat(l_int dfd, const char *filename, \ l_int mode, l_uint dev); } 298 AUE_FCHOWNAT STD { int linux_fchownat(l_int dfd, const char *filename, \ l_uid16_t uid, l_gid16_t gid, l_int flag); } 299 AUE_FUTIMESAT STD { int linux_futimesat(l_int dfd, char *filename, \ struct l_timeval *utimes); } 300 AUE_FSTATAT STD { int linux_fstatat64(l_int dfd, char *pathname, \ struct l_stat64 *statbuf, l_int flag); } 301 AUE_UNLINKAT STD { int linux_unlinkat(l_int dfd, const char *pathname, \ l_int flag); } 302 AUE_RENAMEAT STD { int linux_renameat(l_int olddfd, const char *oldname, \ l_int newdfd, const char *newname); } 303 AUE_LINKAT STD { int linux_linkat(l_int olddfd, const char *oldname, \ l_int newdfd, const char *newname, l_int flag); } 304 AUE_SYMLINKAT STD { int linux_symlinkat(const char *oldname, l_int newdfd, \ const char *newname); } 305 AUE_READLINKAT STD { int linux_readlinkat(l_int dfd, const char *path, \ char *buf, l_int bufsiz); } 306 AUE_FCHMODAT STD { int linux_fchmodat(l_int dfd, const char *filename, \ l_mode_t mode); } 307 AUE_FACCESSAT STD { int linux_faccessat(l_int dfd, const char *filename, \ l_int amode); } 308 AUE_SELECT STD { int linux_pselect6(l_int nfds, l_fd_set *readfds, \ l_fd_set *writefds, l_fd_set *exceptfds, \ struct l_timespec *tsp, l_uintptr_t *sig); } 309 AUE_POLL STD { int linux_ppoll(struct pollfd *fds, uint32_t nfds, \ struct l_timespec *tsp, l_sigset_t *sset, l_size_t ssize); } 310 AUE_NULL STD { int linux_unshare(void); } ; linux 2.6.17: 311 AUE_NULL STD { int linux_set_robust_list(struct linux_robust_list_head *head, \ l_size_t len); } 312 AUE_NULL STD { int linux_get_robust_list(l_int pid, \ struct linux_robust_list_head **head, l_size_t *len); } 313 AUE_NULL STD { int linux_splice(void); } 314 AUE_NULL STD { int linux_sync_file_range(void); } 315 AUE_NULL STD { int linux_tee(void); } 316 AUE_NULL STD { int linux_vmsplice(void); } ; linux 2.6.18: 317 AUE_NULL STD { int linux_move_pages(void); } ; linux 2.6.19: 318 AUE_NULL STD { int linux_getcpu(void); } 319 AUE_NULL STD { int linux_epoll_pwait(l_int epfd, struct epoll_event *events, \ l_int maxevents, l_int timeout, l_sigset_t *mask); } ; linux 2.6.22: 320 AUE_FUTIMESAT STD { int linux_utimensat(l_int dfd, const char *pathname, \ const struct l_timespec *times, l_int flags); } 321 AUE_NULL STD { int linux_signalfd(void); } 322 AUE_NULL STD { int linux_timerfd_create(void); } 323 AUE_NULL STD { int linux_eventfd(l_uint initval); } ; linux 2.6.23: 324 AUE_NULL STD { int linux_fallocate(l_int fd, l_int mode, \ l_loff_t offset, l_loff_t len); } ; linux 2.6.25: 325 AUE_NULL STD { int linux_timerfd_settime(void); } 326 AUE_NULL STD { int linux_timerfd_gettime(void); } ; linux 2.6.27: 327 AUE_NULL STD { int linux_signalfd4(void); } 328 AUE_NULL STD { int linux_eventfd2(l_uint initval, l_int flags); } 329 AUE_NULL STD { int linux_epoll_create1(l_int flags); } 330 AUE_NULL STD { int linux_dup3(l_int oldfd, \ l_int newfd, l_int flags); } 331 AUE_NULL STD { int linux_pipe2(l_int *pipefds, l_int flags); } 332 AUE_NULL STD { int linux_inotify_init1(void); } ; linux 2.6.30: -333 AUE_NULL STD { int linux_preadv(void); } -334 AUE_NULL STD { int linux_pwritev(void); } +333 AUE_NULL STD { int linux_preadv(l_ulong fd, \ + struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h); } +334 AUE_NULL STD { int linux_pwritev(l_ulong fd, \ + struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h); } ; linux 2.6.31: -335 AUE_NULL STD { int linux_rt_tsigqueueinfo(void); } +335 AUE_NULL STD { int linux_rt_tgsigqueueinfo(l_pid_t tgid, \ + l_pid_t tid, l_int sig, l_siginfo_t *uinfo); } 336 AUE_NULL STD { int linux_perf_event_open(void); } ; linux 2.6.33: 337 AUE_NULL STD { int linux_recvmmsg(l_int s, \ struct l_mmsghdr *msg, l_uint vlen, \ l_uint flags, struct l_timespec *timeout); } 338 AUE_NULL STD { int linux_fanotify_init(void); } 339 AUE_NULL STD { int linux_fanotify_mark(void); } ; linux 2.6.36: 340 AUE_NULL STD { int linux_prlimit64(l_pid_t pid, \ l_uint resource, \ struct rlimit *new, \ struct rlimit *old); } -; later: +; linux 2.6.39: 341 AUE_NULL STD { int linux_name_to_handle_at(void); } 342 AUE_NULL STD { int linux_open_by_handle_at(void); } 343 AUE_NULL STD { int linux_clock_adjtime(void); } 344 AUE_SYNC STD { int linux_syncfs(l_int fd); } +; linux 3.0: 345 AUE_NULL STD { int linux_sendmmsg(l_int s, \ struct l_mmsghdr *msg, l_uint vlen, \ l_uint flags); } 346 AUE_NULL STD { int linux_setns(void); } -347 AUE_NULL STD { int linux_process_vm_readv(void); } -348 AUE_NULL STD { int linux_process_vm_writev(void); } +; linux 3.2 (glibc 2.15): +347 AUE_NULL STD { int linux_process_vm_readv(l_pid_t pid, \ + const struct iovec *lvec, l_ulong liovcnt, \ + const struct iovec *rvec, l_ulong riovcnt, \ + l_ulong flags); } +348 AUE_NULL STD { int linux_process_vm_writev(l_pid_t pid, \ + const struct iovec *lvec, l_ulong liovcnt, \ + const struct iovec *rvec, l_ulong riovcnt, \ + l_ulong flags); } +; linux 3.5 (no glibc wrapper): +349 AUE_NULL STD { int linux_kcmp(l_pid_t pid1, l_pid_t pid2, \ + l_int type, l_ulong idx1, l_ulong idx); } +; linux 3.8 (no glibc wrapper): +350 AUE_NULL STD { int linux_finit_module(l_int fd, \ + const char *uargs, l_int flags); } +; linux 3.14: +351 AUE_NULL STD { int linux_sched_setattr(l_pid_t pid, \ + void *attr, l_uint flags); } +352 AUE_NULL STD { int linux_sched_getattr(l_pid_t pid, \ + void *attr, l_uint size, l_uint flags); } +; linux 3.15: +353 AUE_NULL STD { int linux_renameat2(l_int oldfd, \ + const char *oldname, l_int newfd, \ + const char *newname, unsigned int flags); } +; linux 3.17: +354 AUE_NULL STD { int linux_seccomp(l_uint op, l_uint flags, \ + const char *uargs); } +355 AUE_NULL STD { int linux_getrandom(char *buf, \ + l_size_t count, l_uint flags); } +356 AUE_NULL STD { int linux_memfd_create(const char *uname_ptr, \ + l_uint flags); } +; linux 3.18: +357 AUE_NULL STD { int linux_bpf(l_int cmd, void *attr, \ + l_uint size); } +; linux 3.19: +358 AUE_NULL STD { int linux_execveat(l_int dfd, \ + const char *filename, const char **argv, \ + const char **envp, l_int flags); } +; linux 4.3: sockets now direct system calls: +359 AUE_SOCKET STD { int linux_socket(l_int domain, l_int type, \ + l_int protocol); } +360 AUE_SOCKETPAIR STD { int linux_socketpair(l_int domain, \ + l_int type, l_int protocol, l_uintptr_t rsv); } +361 AUE_BIND STD { int linux_bind(l_int s, l_uintptr_t name, \ + l_int namelen); } +362 AUE_CONNECT STD { int linux_connect(l_int s, l_uintptr_t name, \ + l_int namelen); } +363 AUE_LISTEN STD { int linux_listen(l_int s, l_int backlog); } +364 AUE_ACCEPT STD { int linux_accept4(l_int s, l_uintptr_t addr, \ + l_uintptr_t namelen, l_int flags); } +365 AUE_GETSOCKOPT STD { int linux_getsockopt(l_int s, l_int level, \ + l_int optname, l_uintptr_t optval, \ + l_uintptr_t optlen); } +366 AUE_SETSOCKOPT STD { int linux_setsockopt(l_int s, l_int level, \ + l_int optname, l_uintptr_t optval, \ + l_int optlen); } +367 AUE_GETSOCKNAME STD { int linux_getsockname(l_int s, \ + l_uintptr_t addr, l_uintptr_t namelen); } +368 AUE_GETPEERNAME STD { int linux_getpeername(l_int s, \ + l_uintptr_t addr, l_uintptr_t namelen); } +369 AUE_SENDTO STD { int linux_sendto(l_int s, l_uintptr_t msg, \ + l_int len, l_int flags, l_uintptr_t to, \ + l_int tolen); } +370 AUE_SENDMSG STD { int linux_sendmsg(l_int s, l_uintptr_t msg, \ + l_int flags); } +371 AUE_RECVFROM STD { int linux_recvfrom(l_int s, l_uintptr_t buf, \ + l_size_t len, l_int flags, l_uintptr_t from, \ + l_uintptr_t fromlen); } +372 AUE_RECVMSG STD { int linux_recvmsg(l_int s, l_uintptr_t msg, \ + l_int flags); } +373 AUE_NULL STD { int linux_shutdown(l_int s, l_int how); } +; +; linux 4.2: +374 AUE_NULL STD { int linux_userfaultfd(l_int flags); } +; linux 4.3: +375 AUE_NULL STD { int linux_membarrier(l_int cmd, l_int flags); } +; linux 4.4: +376 AUE_NULL STD { int linux_mlock2(l_ulong start, l_size_t len, \ + l_int flags); } +; linux 4.5: +377 AUE_NULL STD { int linux_copy_file_range(l_int fd_in, \ + l_loff_t *off_in, l_int fd_out, \ + l_loff_t *off_out, l_size_t len, \ + l_uint flags); } +; linux 4.6: +378 AUE_NULL STD { int linux_preadv2(l_ulong fd, \ + const struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h, l_int flags); } +379 AUE_NULL STD { int linux_pwritev2(l_ulong fd, \ + const struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h, l_int flags); } +; linux 4.8: +380 AUE_NULL STD { int linux_pkey_mprotect(l_ulong start, \ + l_size_t len, l_ulong prot, l_int pkey); } +381 AUE_NULL STD { int linux_pkey_alloc(l_ulong flags, \ + l_ulong init_val); } +382 AUE_NULL STD { int linux_pkey_free(l_int pkey); } + ; please, keep this line at the end. -349 AUE_NULL UNIMPL nosys +383 AUE_NULL UNIMPL nosys Index: projects/ipsec/sys/arm/include/_types.h =================================================================== --- projects/ipsec/sys/arm/include/_types.h (revision 313312) +++ projects/ipsec/sys/arm/include/_types.h (revision 313313) @@ -1,126 +1,124 @@ /*- * Copyright (c) 2002 Mike Barcroft * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From: @(#)ansi.h 8.2 (Berkeley) 1/4/94 * From: @(#)types.h 8.3 (Berkeley) 1/5/94 * $FreeBSD$ */ #ifndef _MACHINE__TYPES_H_ #define _MACHINE__TYPES_H_ #ifndef _SYS_CDEFS_H_ #error this file needs sys/cdefs.h as a prerequisite #endif /* * Basic types upon which most other types are built. */ typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; typedef unsigned short __uint16_t; typedef int __int32_t; typedef unsigned int __uint32_t; #ifndef lint __extension__ #endif /* LONGLONG */ typedef long long __int64_t; #ifndef lint __extension__ #endif /* LONGLONG */ typedef unsigned long long __uint64_t; /* * Standard type definitions. */ typedef __uint32_t __clock_t; /* clock()... */ typedef __int32_t __critical_t; typedef double __double_t; typedef float __float_t; typedef __int32_t __intfptr_t; typedef __int64_t __intmax_t; typedef __int32_t __intptr_t; typedef __int32_t __int_fast8_t; typedef __int32_t __int_fast16_t; typedef __int32_t __int_fast32_t; typedef __int64_t __int_fast64_t; typedef __int8_t __int_least8_t; typedef __int16_t __int_least16_t; typedef __int32_t __int_least32_t; typedef __int64_t __int_least64_t; typedef __int32_t __ptrdiff_t; /* ptr1 - ptr2 */ typedef __int32_t __register_t; typedef __int32_t __segsz_t; /* segment size (in pages) */ typedef __uint32_t __size_t; /* sizeof() */ typedef __int32_t __ssize_t; /* byte count or error */ typedef __int64_t __time_t; /* time()... */ typedef __uint32_t __uintfptr_t; typedef __uint64_t __uintmax_t; typedef __uint32_t __uintptr_t; typedef __uint32_t __uint_fast8_t; typedef __uint32_t __uint_fast16_t; typedef __uint32_t __uint_fast32_t; typedef __uint64_t __uint_fast64_t; typedef __uint8_t __uint_least8_t; typedef __uint16_t __uint_least16_t; typedef __uint32_t __uint_least32_t; typedef __uint64_t __uint_least64_t; typedef __uint32_t __u_register_t; typedef __uint32_t __vm_offset_t; -typedef __int64_t __vm_ooffset_t; typedef __uint32_t __vm_paddr_t; -typedef __uint64_t __vm_pindex_t; typedef __uint32_t __vm_size_t; typedef unsigned int ___wchar_t; #define __WCHAR_MIN 0 /* min value for a wchar_t */ #define __WCHAR_MAX __UINT_MAX /* max value for a wchar_t */ /* * Unusual type definitions. */ #ifdef __GNUCLIKE_BUILTIN_VARARGS typedef __builtin_va_list __va_list; /* internally known to gcc */ #else typedef char * __va_list; #endif /* __GNUCLIKE_BUILTIN_VARARGS */ #if defined(__GNUCLIKE_BUILTIN_VAALIST) && !defined(__GNUC_VA_LIST) \ && !defined(__NO_GNUC_VA_LIST) #define __GNUC_VA_LIST typedef __va_list __gnuc_va_list; /* compatibility w/GNU headers*/ #endif #endif /* !_MACHINE__TYPES_H_ */ Index: projects/ipsec/sys/arm64/include/_types.h =================================================================== --- projects/ipsec/sys/arm64/include/_types.h (revision 313312) +++ projects/ipsec/sys/arm64/include/_types.h (revision 313313) @@ -1,114 +1,112 @@ /*- * Copyright (c) 2002 Mike Barcroft * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From: @(#)ansi.h 8.2 (Berkeley) 1/4/94 * From: @(#)types.h 8.3 (Berkeley) 1/5/94 * $FreeBSD$ */ #ifndef _MACHINE__TYPES_H_ #define _MACHINE__TYPES_H_ #ifndef _SYS_CDEFS_H_ #error this file needs sys/cdefs.h as a prerequisite #endif /* * Basic types upon which most other types are built. */ typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; typedef unsigned short __uint16_t; typedef int __int32_t; typedef unsigned int __uint32_t; typedef long __int64_t; typedef unsigned long __uint64_t; /* * Standard type definitions. */ typedef __int32_t __clock_t; /* clock()... */ typedef __int64_t __critical_t; typedef double __double_t; typedef float __float_t; typedef __int64_t __intfptr_t; typedef __int64_t __intmax_t; typedef __int64_t __intptr_t; typedef __int32_t __int_fast8_t; typedef __int32_t __int_fast16_t; typedef __int32_t __int_fast32_t; typedef __int64_t __int_fast64_t; typedef __int8_t __int_least8_t; typedef __int16_t __int_least16_t; typedef __int32_t __int_least32_t; typedef __int64_t __int_least64_t; typedef __int64_t __ptrdiff_t; /* ptr1 - ptr2 */ typedef __int64_t __register_t; typedef __int64_t __segsz_t; /* segment size (in pages) */ typedef __uint64_t __size_t; /* sizeof() */ typedef __int64_t __ssize_t; /* byte count or error */ typedef __int64_t __time_t; /* time()... */ typedef __uint64_t __uintfptr_t; typedef __uint64_t __uintmax_t; typedef __uint64_t __uintptr_t; typedef __uint32_t __uint_fast8_t; typedef __uint32_t __uint_fast16_t; typedef __uint32_t __uint_fast32_t; typedef __uint64_t __uint_fast64_t; typedef __uint8_t __uint_least8_t; typedef __uint16_t __uint_least16_t; typedef __uint32_t __uint_least32_t; typedef __uint64_t __uint_least64_t; typedef __uint64_t __u_register_t; typedef __uint64_t __vm_offset_t; -typedef __int64_t __vm_ooffset_t; typedef __uint64_t __vm_paddr_t; -typedef __uint64_t __vm_pindex_t; typedef __uint64_t __vm_size_t; typedef unsigned int ___wchar_t; #define __WCHAR_MIN 0 /* min value for a wchar_t */ #define __WCHAR_MAX __UINT_MAX /* max value for a wchar_t */ /* * Unusual type definitions. */ #ifdef __GNUCLIKE_BUILTIN_VARARGS typedef __builtin_va_list __va_list; /* internally known to gcc */ #else typedef char * __va_list; #endif /* __GNUCLIKE_BUILTIN_VARARGS */ #if defined(__GNUCLIKE_BUILTIN_VAALIST) && !defined(__GNUC_VA_LIST) \ && !defined(__NO_GNUC_VA_LIST) #define __GNUC_VA_LIST typedef __va_list __gnuc_va_list; /* compatibility w/GNU headers*/ #endif #endif /* !_MACHINE__TYPES_H_ */ Index: projects/ipsec/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c =================================================================== --- projects/ipsec/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c (revision 313312) +++ projects/ipsec/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c (revision 313313) @@ -1,18352 +1,18361 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * $FreeBSD$ */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, Joyent, Inc. All rights reserved. * Copyright (c) 2012, 2014 by Delphix. All rights reserved. */ /* * DTrace - Dynamic Tracing for Solaris * * This is the implementation of the Solaris Dynamic Tracing framework * (DTrace). The user-visible interface to DTrace is described at length in * the "Solaris Dynamic Tracing Guide". The interfaces between the libdtrace * library, the in-kernel DTrace framework, and the DTrace providers are * described in the block comments in the header file. The * internal architecture of DTrace is described in the block comments in the * header file. The comments contained within the DTrace * implementation very much assume mastery of all of these sources; if one has * an unanswered question about the implementation, one should consult them * first. * * The functions here are ordered roughly as follows: * * - Probe context functions * - Probe hashing functions * - Non-probe context utility functions * - Matching functions * - Provider-to-Framework API functions * - Probe management functions * - DIF object functions * - Format functions * - Predicate functions * - ECB functions * - Buffer functions * - Enabling functions * - DOF functions * - Anonymous enabling functions * - Consumer state functions * - Helper functions * - Hook functions * - Driver cookbook functions * * Each group of functions begins with a block comment labelled the "DTrace * [Group] Functions", allowing one to find each block by searching forward * on capital-f functions. */ #include #ifndef illumos #include #endif #include #include #include #include #ifdef illumos #include #include #endif #include #include #ifdef illumos #include #endif #include #include #include #include #ifdef illumos #include #include #endif #include #ifdef illumos #include #include #endif #include #ifdef illumos #include #include #endif #include #ifdef illumos #include #include #endif #include #include #include #include "strtolctype.h" /* FreeBSD includes: */ #ifndef illumos #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dtrace_cddl.h" #include "dtrace_debug.c" #endif #include "dtrace_xoroshiro128_plus.h" /* * DTrace Tunable Variables * * The following variables may be tuned by adding a line to /etc/system that * includes both the name of the DTrace module ("dtrace") and the name of the * variable. For example: * * set dtrace:dtrace_destructive_disallow = 1 * * In general, the only variables that one should be tuning this way are those * that affect system-wide DTrace behavior, and for which the default behavior * is undesirable. Most of these variables are tunable on a per-consumer * basis using DTrace options, and need not be tuned on a system-wide basis. * When tuning these variables, avoid pathological values; while some attempt * is made to verify the integrity of these variables, they are not considered * part of the supported interface to DTrace, and they are therefore not * checked comprehensively. Further, these variables should not be tuned * dynamically via "mdb -kw" or other means; they should only be tuned via * /etc/system. */ int dtrace_destructive_disallow = 0; #ifndef illumos /* Positive logic version of dtrace_destructive_disallow for loader tunable */ int dtrace_allow_destructive = 1; #endif dtrace_optval_t dtrace_nonroot_maxsize = (16 * 1024 * 1024); size_t dtrace_difo_maxsize = (256 * 1024); dtrace_optval_t dtrace_dof_maxsize = (8 * 1024 * 1024); size_t dtrace_statvar_maxsize = (16 * 1024); size_t dtrace_actions_max = (16 * 1024); size_t dtrace_retain_max = 1024; dtrace_optval_t dtrace_helper_actions_max = 128; dtrace_optval_t dtrace_helper_providers_max = 32; dtrace_optval_t dtrace_dstate_defsize = (1 * 1024 * 1024); size_t dtrace_strsize_default = 256; dtrace_optval_t dtrace_cleanrate_default = 9900990; /* 101 hz */ dtrace_optval_t dtrace_cleanrate_min = 200000; /* 5000 hz */ dtrace_optval_t dtrace_cleanrate_max = (uint64_t)60 * NANOSEC; /* 1/minute */ dtrace_optval_t dtrace_aggrate_default = NANOSEC; /* 1 hz */ dtrace_optval_t dtrace_statusrate_default = NANOSEC; /* 1 hz */ dtrace_optval_t dtrace_statusrate_max = (hrtime_t)10 * NANOSEC; /* 6/minute */ dtrace_optval_t dtrace_switchrate_default = NANOSEC; /* 1 hz */ dtrace_optval_t dtrace_nspec_default = 1; dtrace_optval_t dtrace_specsize_default = 32 * 1024; dtrace_optval_t dtrace_stackframes_default = 20; dtrace_optval_t dtrace_ustackframes_default = 20; dtrace_optval_t dtrace_jstackframes_default = 50; dtrace_optval_t dtrace_jstackstrsize_default = 512; int dtrace_msgdsize_max = 128; hrtime_t dtrace_chill_max = MSEC2NSEC(500); /* 500 ms */ hrtime_t dtrace_chill_interval = NANOSEC; /* 1000 ms */ int dtrace_devdepth_max = 32; int dtrace_err_verbose; hrtime_t dtrace_deadman_interval = NANOSEC; hrtime_t dtrace_deadman_timeout = (hrtime_t)10 * NANOSEC; hrtime_t dtrace_deadman_user = (hrtime_t)30 * NANOSEC; hrtime_t dtrace_unregister_defunct_reap = (hrtime_t)60 * NANOSEC; #ifndef illumos int dtrace_memstr_max = 4096; #endif /* * DTrace External Variables * * As dtrace(7D) is a kernel module, any DTrace variables are obviously * available to DTrace consumers via the backtick (`) syntax. One of these, * dtrace_zero, is made deliberately so: it is provided as a source of * well-known, zero-filled memory. While this variable is not documented, * it is used by some translators as an implementation detail. */ const char dtrace_zero[256] = { 0 }; /* zero-filled memory */ /* * DTrace Internal Variables */ #ifdef illumos static dev_info_t *dtrace_devi; /* device info */ #endif #ifdef illumos static vmem_t *dtrace_arena; /* probe ID arena */ static vmem_t *dtrace_minor; /* minor number arena */ #else static taskq_t *dtrace_taskq; /* task queue */ static struct unrhdr *dtrace_arena; /* Probe ID number. */ #endif static dtrace_probe_t **dtrace_probes; /* array of all probes */ static int dtrace_nprobes; /* number of probes */ static dtrace_provider_t *dtrace_provider; /* provider list */ static dtrace_meta_t *dtrace_meta_pid; /* user-land meta provider */ static int dtrace_opens; /* number of opens */ static int dtrace_helpers; /* number of helpers */ static int dtrace_getf; /* number of unpriv getf()s */ #ifdef illumos static void *dtrace_softstate; /* softstate pointer */ #endif static dtrace_hash_t *dtrace_bymod; /* probes hashed by module */ static dtrace_hash_t *dtrace_byfunc; /* probes hashed by function */ static dtrace_hash_t *dtrace_byname; /* probes hashed by name */ static dtrace_toxrange_t *dtrace_toxrange; /* toxic range array */ static int dtrace_toxranges; /* number of toxic ranges */ static int dtrace_toxranges_max; /* size of toxic range array */ static dtrace_anon_t dtrace_anon; /* anonymous enabling */ static kmem_cache_t *dtrace_state_cache; /* cache for dynamic state */ static uint64_t dtrace_vtime_references; /* number of vtimestamp refs */ static kthread_t *dtrace_panicked; /* panicking thread */ static dtrace_ecb_t *dtrace_ecb_create_cache; /* cached created ECB */ static dtrace_genid_t dtrace_probegen; /* current probe generation */ static dtrace_helpers_t *dtrace_deferred_pid; /* deferred helper list */ static dtrace_enabling_t *dtrace_retained; /* list of retained enablings */ static dtrace_genid_t dtrace_retained_gen; /* current retained enab gen */ static dtrace_dynvar_t dtrace_dynhash_sink; /* end of dynamic hash chains */ static int dtrace_dynvar_failclean; /* dynvars failed to clean */ #ifndef illumos static struct mtx dtrace_unr_mtx; MTX_SYSINIT(dtrace_unr_mtx, &dtrace_unr_mtx, "Unique resource identifier", MTX_DEF); static eventhandler_tag dtrace_kld_load_tag; static eventhandler_tag dtrace_kld_unload_try_tag; #endif /* * DTrace Locking * DTrace is protected by three (relatively coarse-grained) locks: * * (1) dtrace_lock is required to manipulate essentially any DTrace state, * including enabling state, probes, ECBs, consumer state, helper state, * etc. Importantly, dtrace_lock is _not_ required when in probe context; * probe context is lock-free -- synchronization is handled via the * dtrace_sync() cross call mechanism. * * (2) dtrace_provider_lock is required when manipulating provider state, or * when provider state must be held constant. * * (3) dtrace_meta_lock is required when manipulating meta provider state, or * when meta provider state must be held constant. * * The lock ordering between these three locks is dtrace_meta_lock before * dtrace_provider_lock before dtrace_lock. (In particular, there are * several places where dtrace_provider_lock is held by the framework as it * calls into the providers -- which then call back into the framework, * grabbing dtrace_lock.) * * There are two other locks in the mix: mod_lock and cpu_lock. With respect * to dtrace_provider_lock and dtrace_lock, cpu_lock continues its historical * role as a coarse-grained lock; it is acquired before both of these locks. * With respect to dtrace_meta_lock, its behavior is stranger: cpu_lock must * be acquired _between_ dtrace_meta_lock and any other DTrace locks. * mod_lock is similar with respect to dtrace_provider_lock in that it must be * acquired _between_ dtrace_provider_lock and dtrace_lock. */ static kmutex_t dtrace_lock; /* probe state lock */ static kmutex_t dtrace_provider_lock; /* provider state lock */ static kmutex_t dtrace_meta_lock; /* meta-provider state lock */ #ifndef illumos /* XXX FreeBSD hacks. */ #define cr_suid cr_svuid #define cr_sgid cr_svgid #define ipaddr_t in_addr_t #define mod_modname pathname #define vuprintf vprintf #define ttoproc(_a) ((_a)->td_proc) #define crgetzoneid(_a) 0 #define SNOCD 0 #define CPU_ON_INTR(_a) 0 #define PRIV_EFFECTIVE (1 << 0) #define PRIV_DTRACE_KERNEL (1 << 1) #define PRIV_DTRACE_PROC (1 << 2) #define PRIV_DTRACE_USER (1 << 3) #define PRIV_PROC_OWNER (1 << 4) #define PRIV_PROC_ZONE (1 << 5) #define PRIV_ALL ~0 SYSCTL_DECL(_debug_dtrace); SYSCTL_DECL(_kern_dtrace); #endif #ifdef illumos #define curcpu CPU->cpu_id #endif /* * DTrace Provider Variables * * These are the variables relating to DTrace as a provider (that is, the * provider of the BEGIN, END, and ERROR probes). */ static dtrace_pattr_t dtrace_provider_attr = { { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, }; static void dtrace_nullop(void) {} static dtrace_pops_t dtrace_provider_ops = { (void (*)(void *, dtrace_probedesc_t *))dtrace_nullop, (void (*)(void *, modctl_t *))dtrace_nullop, (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, NULL, NULL, NULL, (void (*)(void *, dtrace_id_t, void *))dtrace_nullop }; static dtrace_id_t dtrace_probeid_begin; /* special BEGIN probe */ static dtrace_id_t dtrace_probeid_end; /* special END probe */ dtrace_id_t dtrace_probeid_error; /* special ERROR probe */ /* * DTrace Helper Tracing Variables * * These variables should be set dynamically to enable helper tracing. The * only variables that should be set are dtrace_helptrace_enable (which should * be set to a non-zero value to allocate helper tracing buffers on the next * open of /dev/dtrace) and dtrace_helptrace_disable (which should be set to a * non-zero value to deallocate helper tracing buffers on the next close of * /dev/dtrace). When (and only when) helper tracing is disabled, the * buffer size may also be set via dtrace_helptrace_bufsize. */ int dtrace_helptrace_enable = 0; int dtrace_helptrace_disable = 0; int dtrace_helptrace_bufsize = 16 * 1024 * 1024; uint32_t dtrace_helptrace_nlocals; static dtrace_helptrace_t *dtrace_helptrace_buffer; static uint32_t dtrace_helptrace_next = 0; static int dtrace_helptrace_wrapped = 0; /* * DTrace Error Hashing * * On DEBUG kernels, DTrace will track the errors that has seen in a hash * table. This is very useful for checking coverage of tests that are * expected to induce DIF or DOF processing errors, and may be useful for * debugging problems in the DIF code generator or in DOF generation . The * error hash may be examined with the ::dtrace_errhash MDB dcmd. */ #ifdef DEBUG static dtrace_errhash_t dtrace_errhash[DTRACE_ERRHASHSZ]; static const char *dtrace_errlast; static kthread_t *dtrace_errthread; static kmutex_t dtrace_errlock; #endif /* * DTrace Macros and Constants * * These are various macros that are useful in various spots in the * implementation, along with a few random constants that have no meaning * outside of the implementation. There is no real structure to this cpp * mishmash -- but is there ever? */ #define DTRACE_HASHSTR(hash, probe) \ dtrace_hash_str(*((char **)((uintptr_t)(probe) + (hash)->dth_stroffs))) #define DTRACE_HASHNEXT(hash, probe) \ (dtrace_probe_t **)((uintptr_t)(probe) + (hash)->dth_nextoffs) #define DTRACE_HASHPREV(hash, probe) \ (dtrace_probe_t **)((uintptr_t)(probe) + (hash)->dth_prevoffs) #define DTRACE_HASHEQ(hash, lhs, rhs) \ (strcmp(*((char **)((uintptr_t)(lhs) + (hash)->dth_stroffs)), \ *((char **)((uintptr_t)(rhs) + (hash)->dth_stroffs))) == 0) #define DTRACE_AGGHASHSIZE_SLEW 17 #define DTRACE_V4MAPPED_OFFSET (sizeof (uint32_t) * 3) /* * The key for a thread-local variable consists of the lower 61 bits of the * t_did, plus the 3 bits of the highest active interrupt above LOCK_LEVEL. * We add DIF_VARIABLE_MAX to t_did to assure that the thread key is never * equal to a variable identifier. This is necessary (but not sufficient) to * assure that global associative arrays never collide with thread-local * variables. To guarantee that they cannot collide, we must also define the * order for keying dynamic variables. That order is: * * [ key0 ] ... [ keyn ] [ variable-key ] [ tls-key ] * * Because the variable-key and the tls-key are in orthogonal spaces, there is * no way for a global variable key signature to match a thread-local key * signature. */ #ifdef illumos #define DTRACE_TLS_THRKEY(where) { \ uint_t intr = 0; \ uint_t actv = CPU->cpu_intr_actv >> (LOCK_LEVEL + 1); \ for (; actv; actv >>= 1) \ intr++; \ ASSERT(intr < (1 << 3)); \ (where) = ((curthread->t_did + DIF_VARIABLE_MAX) & \ (((uint64_t)1 << 61) - 1)) | ((uint64_t)intr << 61); \ } #else #define DTRACE_TLS_THRKEY(where) { \ solaris_cpu_t *_c = &solaris_cpu[curcpu]; \ uint_t intr = 0; \ uint_t actv = _c->cpu_intr_actv; \ for (; actv; actv >>= 1) \ intr++; \ ASSERT(intr < (1 << 3)); \ (where) = ((curthread->td_tid + DIF_VARIABLE_MAX) & \ (((uint64_t)1 << 61) - 1)) | ((uint64_t)intr << 61); \ } #endif #define DT_BSWAP_8(x) ((x) & 0xff) #define DT_BSWAP_16(x) ((DT_BSWAP_8(x) << 8) | DT_BSWAP_8((x) >> 8)) #define DT_BSWAP_32(x) ((DT_BSWAP_16(x) << 16) | DT_BSWAP_16((x) >> 16)) #define DT_BSWAP_64(x) ((DT_BSWAP_32(x) << 32) | DT_BSWAP_32((x) >> 32)) #define DT_MASK_LO 0x00000000FFFFFFFFULL #define DTRACE_STORE(type, tomax, offset, what) \ *((type *)((uintptr_t)(tomax) + (uintptr_t)offset)) = (type)(what); #ifndef __x86 #define DTRACE_ALIGNCHECK(addr, size, flags) \ if (addr & (size - 1)) { \ *flags |= CPU_DTRACE_BADALIGN; \ cpu_core[curcpu].cpuc_dtrace_illval = addr; \ return (0); \ } #else #define DTRACE_ALIGNCHECK(addr, size, flags) #endif /* * Test whether a range of memory starting at testaddr of size testsz falls * within the range of memory described by addr, sz. We take care to avoid * problems with overflow and underflow of the unsigned quantities, and * disallow all negative sizes. Ranges of size 0 are allowed. */ #define DTRACE_INRANGE(testaddr, testsz, baseaddr, basesz) \ ((testaddr) - (uintptr_t)(baseaddr) < (basesz) && \ (testaddr) + (testsz) - (uintptr_t)(baseaddr) <= (basesz) && \ (testaddr) + (testsz) >= (testaddr)) #define DTRACE_RANGE_REMAIN(remp, addr, baseaddr, basesz) \ do { \ if ((remp) != NULL) { \ *(remp) = (uintptr_t)(baseaddr) + (basesz) - (addr); \ } \ _NOTE(CONSTCOND) } while (0) /* * Test whether alloc_sz bytes will fit in the scratch region. We isolate * alloc_sz on the righthand side of the comparison in order to avoid overflow * or underflow in the comparison with it. This is simpler than the INRANGE * check above, because we know that the dtms_scratch_ptr is valid in the * range. Allocations of size zero are allowed. */ #define DTRACE_INSCRATCH(mstate, alloc_sz) \ ((mstate)->dtms_scratch_base + (mstate)->dtms_scratch_size - \ (mstate)->dtms_scratch_ptr >= (alloc_sz)) #define DTRACE_LOADFUNC(bits) \ /*CSTYLED*/ \ uint##bits##_t \ dtrace_load##bits(uintptr_t addr) \ { \ size_t size = bits / NBBY; \ /*CSTYLED*/ \ uint##bits##_t rval; \ int i; \ volatile uint16_t *flags = (volatile uint16_t *) \ &cpu_core[curcpu].cpuc_dtrace_flags; \ \ DTRACE_ALIGNCHECK(addr, size, flags); \ \ for (i = 0; i < dtrace_toxranges; i++) { \ if (addr >= dtrace_toxrange[i].dtt_limit) \ continue; \ \ if (addr + size <= dtrace_toxrange[i].dtt_base) \ continue; \ \ /* \ * This address falls within a toxic region; return 0. \ */ \ *flags |= CPU_DTRACE_BADADDR; \ cpu_core[curcpu].cpuc_dtrace_illval = addr; \ return (0); \ } \ \ *flags |= CPU_DTRACE_NOFAULT; \ /*CSTYLED*/ \ rval = *((volatile uint##bits##_t *)addr); \ *flags &= ~CPU_DTRACE_NOFAULT; \ \ return (!(*flags & CPU_DTRACE_FAULT) ? rval : 0); \ } #ifdef _LP64 #define dtrace_loadptr dtrace_load64 #else #define dtrace_loadptr dtrace_load32 #endif #define DTRACE_DYNHASH_FREE 0 #define DTRACE_DYNHASH_SINK 1 #define DTRACE_DYNHASH_VALID 2 #define DTRACE_MATCH_NEXT 0 #define DTRACE_MATCH_DONE 1 #define DTRACE_ANCHORED(probe) ((probe)->dtpr_func[0] != '\0') #define DTRACE_STATE_ALIGN 64 #define DTRACE_FLAGS2FLT(flags) \ (((flags) & CPU_DTRACE_BADADDR) ? DTRACEFLT_BADADDR : \ ((flags) & CPU_DTRACE_ILLOP) ? DTRACEFLT_ILLOP : \ ((flags) & CPU_DTRACE_DIVZERO) ? DTRACEFLT_DIVZERO : \ ((flags) & CPU_DTRACE_KPRIV) ? DTRACEFLT_KPRIV : \ ((flags) & CPU_DTRACE_UPRIV) ? DTRACEFLT_UPRIV : \ ((flags) & CPU_DTRACE_TUPOFLOW) ? DTRACEFLT_TUPOFLOW : \ ((flags) & CPU_DTRACE_BADALIGN) ? DTRACEFLT_BADALIGN : \ ((flags) & CPU_DTRACE_NOSCRATCH) ? DTRACEFLT_NOSCRATCH : \ ((flags) & CPU_DTRACE_BADSTACK) ? DTRACEFLT_BADSTACK : \ DTRACEFLT_UNKNOWN) #define DTRACEACT_ISSTRING(act) \ ((act)->dta_kind == DTRACEACT_DIFEXPR && \ (act)->dta_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_STRING) /* Function prototype definitions: */ static size_t dtrace_strlen(const char *, size_t); static dtrace_probe_t *dtrace_probe_lookup_id(dtrace_id_t id); static void dtrace_enabling_provide(dtrace_provider_t *); static int dtrace_enabling_match(dtrace_enabling_t *, int *); static void dtrace_enabling_matchall(void); static void dtrace_enabling_reap(void); static dtrace_state_t *dtrace_anon_grab(void); static uint64_t dtrace_helper(int, dtrace_mstate_t *, dtrace_state_t *, uint64_t, uint64_t); static dtrace_helpers_t *dtrace_helpers_create(proc_t *); static void dtrace_buffer_drop(dtrace_buffer_t *); static int dtrace_buffer_consumed(dtrace_buffer_t *, hrtime_t when); static intptr_t dtrace_buffer_reserve(dtrace_buffer_t *, size_t, size_t, dtrace_state_t *, dtrace_mstate_t *); static int dtrace_state_option(dtrace_state_t *, dtrace_optid_t, dtrace_optval_t); static int dtrace_ecb_create_enable(dtrace_probe_t *, void *); static void dtrace_helper_provider_destroy(dtrace_helper_provider_t *); uint16_t dtrace_load16(uintptr_t); uint32_t dtrace_load32(uintptr_t); uint64_t dtrace_load64(uintptr_t); uint8_t dtrace_load8(uintptr_t); void dtrace_dynvar_clean(dtrace_dstate_t *); dtrace_dynvar_t *dtrace_dynvar(dtrace_dstate_t *, uint_t, dtrace_key_t *, size_t, dtrace_dynvar_op_t, dtrace_mstate_t *, dtrace_vstate_t *); uintptr_t dtrace_dif_varstr(uintptr_t, dtrace_state_t *, dtrace_mstate_t *); static int dtrace_priv_proc(dtrace_state_t *); static void dtrace_getf_barrier(void); static int dtrace_canload_remains(uint64_t, size_t, size_t *, dtrace_mstate_t *, dtrace_vstate_t *); static int dtrace_canstore_remains(uint64_t, size_t, size_t *, dtrace_mstate_t *, dtrace_vstate_t *); /* * DTrace Probe Context Functions * * These functions are called from probe context. Because probe context is * any context in which C may be called, arbitrarily locks may be held, * interrupts may be disabled, we may be in arbitrary dispatched state, etc. * As a result, functions called from probe context may only call other DTrace * support functions -- they may not interact at all with the system at large. * (Note that the ASSERT macro is made probe-context safe by redefining it in * terms of dtrace_assfail(), a probe-context safe function.) If arbitrary * loads are to be performed from probe context, they _must_ be in terms of * the safe dtrace_load*() variants. * * Some functions in this block are not actually called from probe context; * for these functions, there will be a comment above the function reading * "Note: not called from probe context." */ void dtrace_panic(const char *format, ...) { va_list alist; va_start(alist, format); #ifdef __FreeBSD__ vpanic(format, alist); #else dtrace_vpanic(format, alist); #endif va_end(alist); } int dtrace_assfail(const char *a, const char *f, int l) { dtrace_panic("assertion failed: %s, file: %s, line: %d", a, f, l); /* * We just need something here that even the most clever compiler * cannot optimize away. */ return (a[(uintptr_t)f]); } /* * Atomically increment a specified error counter from probe context. */ static void dtrace_error(uint32_t *counter) { /* * Most counters stored to in probe context are per-CPU counters. * However, there are some error conditions that are sufficiently * arcane that they don't merit per-CPU storage. If these counters * are incremented concurrently on different CPUs, scalability will be * adversely affected -- but we don't expect them to be white-hot in a * correctly constructed enabling... */ uint32_t oval, nval; do { oval = *counter; if ((nval = oval + 1) == 0) { /* * If the counter would wrap, set it to 1 -- assuring * that the counter is never zero when we have seen * errors. (The counter must be 32-bits because we * aren't guaranteed a 64-bit compare&swap operation.) * To save this code both the infamy of being fingered * by a priggish news story and the indignity of being * the target of a neo-puritan witch trial, we're * carefully avoiding any colorful description of the * likelihood of this condition -- but suffice it to * say that it is only slightly more likely than the * overflow of predicate cache IDs, as discussed in * dtrace_predicate_create(). */ nval = 1; } } while (dtrace_cas32(counter, oval, nval) != oval); } /* * Use the DTRACE_LOADFUNC macro to define functions for each of loading a * uint8_t, a uint16_t, a uint32_t and a uint64_t. */ /* BEGIN CSTYLED */ DTRACE_LOADFUNC(8) DTRACE_LOADFUNC(16) DTRACE_LOADFUNC(32) DTRACE_LOADFUNC(64) /* END CSTYLED */ static int dtrace_inscratch(uintptr_t dest, size_t size, dtrace_mstate_t *mstate) { if (dest < mstate->dtms_scratch_base) return (0); if (dest + size < dest) return (0); if (dest + size > mstate->dtms_scratch_ptr) return (0); return (1); } static int dtrace_canstore_statvar(uint64_t addr, size_t sz, size_t *remain, dtrace_statvar_t **svars, int nsvars) { int i; size_t maxglobalsize, maxlocalsize; if (nsvars == 0) return (0); maxglobalsize = dtrace_statvar_maxsize + sizeof (uint64_t); maxlocalsize = maxglobalsize * NCPU; for (i = 0; i < nsvars; i++) { dtrace_statvar_t *svar = svars[i]; uint8_t scope; size_t size; if (svar == NULL || (size = svar->dtsv_size) == 0) continue; scope = svar->dtsv_var.dtdv_scope; /* * We verify that our size is valid in the spirit of providing * defense in depth: we want to prevent attackers from using * DTrace to escalate an orthogonal kernel heap corruption bug * into the ability to store to arbitrary locations in memory. */ VERIFY((scope == DIFV_SCOPE_GLOBAL && size <= maxglobalsize) || (scope == DIFV_SCOPE_LOCAL && size <= maxlocalsize)); if (DTRACE_INRANGE(addr, sz, svar->dtsv_data, svar->dtsv_size)) { DTRACE_RANGE_REMAIN(remain, addr, svar->dtsv_data, svar->dtsv_size); return (1); } } return (0); } /* * Check to see if the address is within a memory region to which a store may * be issued. This includes the DTrace scratch areas, and any DTrace variable * region. The caller of dtrace_canstore() is responsible for performing any * alignment checks that are needed before stores are actually executed. */ static int dtrace_canstore(uint64_t addr, size_t sz, dtrace_mstate_t *mstate, dtrace_vstate_t *vstate) { return (dtrace_canstore_remains(addr, sz, NULL, mstate, vstate)); } /* * Implementation of dtrace_canstore which communicates the upper bound of the * allowed memory region. */ static int dtrace_canstore_remains(uint64_t addr, size_t sz, size_t *remain, dtrace_mstate_t *mstate, dtrace_vstate_t *vstate) { /* * First, check to see if the address is in scratch space... */ if (DTRACE_INRANGE(addr, sz, mstate->dtms_scratch_base, mstate->dtms_scratch_size)) { DTRACE_RANGE_REMAIN(remain, addr, mstate->dtms_scratch_base, mstate->dtms_scratch_size); return (1); } /* * Now check to see if it's a dynamic variable. This check will pick * up both thread-local variables and any global dynamically-allocated * variables. */ if (DTRACE_INRANGE(addr, sz, vstate->dtvs_dynvars.dtds_base, vstate->dtvs_dynvars.dtds_size)) { dtrace_dstate_t *dstate = &vstate->dtvs_dynvars; uintptr_t base = (uintptr_t)dstate->dtds_base + (dstate->dtds_hashsize * sizeof (dtrace_dynhash_t)); uintptr_t chunkoffs; dtrace_dynvar_t *dvar; /* * Before we assume that we can store here, we need to make * sure that it isn't in our metadata -- storing to our * dynamic variable metadata would corrupt our state. For * the range to not include any dynamic variable metadata, * it must: * * (1) Start above the hash table that is at the base of * the dynamic variable space * * (2) Have a starting chunk offset that is beyond the * dtrace_dynvar_t that is at the base of every chunk * * (3) Not span a chunk boundary * * (4) Not be in the tuple space of a dynamic variable * */ if (addr < base) return (0); chunkoffs = (addr - base) % dstate->dtds_chunksize; if (chunkoffs < sizeof (dtrace_dynvar_t)) return (0); if (chunkoffs + sz > dstate->dtds_chunksize) return (0); dvar = (dtrace_dynvar_t *)((uintptr_t)addr - chunkoffs); if (dvar->dtdv_hashval == DTRACE_DYNHASH_FREE) return (0); if (chunkoffs < sizeof (dtrace_dynvar_t) + ((dvar->dtdv_tuple.dtt_nkeys - 1) * sizeof (dtrace_key_t))) return (0); DTRACE_RANGE_REMAIN(remain, addr, dvar, dstate->dtds_chunksize); return (1); } /* * Finally, check the static local and global variables. These checks * take the longest, so we perform them last. */ if (dtrace_canstore_statvar(addr, sz, remain, vstate->dtvs_locals, vstate->dtvs_nlocals)) return (1); if (dtrace_canstore_statvar(addr, sz, remain, vstate->dtvs_globals, vstate->dtvs_nglobals)) return (1); return (0); } /* * Convenience routine to check to see if the address is within a memory * region in which a load may be issued given the user's privilege level; * if not, it sets the appropriate error flags and loads 'addr' into the * illegal value slot. * * DTrace subroutines (DIF_SUBR_*) should use this helper to implement * appropriate memory access protection. */ static int dtrace_canload(uint64_t addr, size_t sz, dtrace_mstate_t *mstate, dtrace_vstate_t *vstate) { return (dtrace_canload_remains(addr, sz, NULL, mstate, vstate)); } /* * Implementation of dtrace_canload which communicates the uppoer bound of the * allowed memory region. */ static int dtrace_canload_remains(uint64_t addr, size_t sz, size_t *remain, dtrace_mstate_t *mstate, dtrace_vstate_t *vstate) { volatile uintptr_t *illval = &cpu_core[curcpu].cpuc_dtrace_illval; file_t *fp; /* * If we hold the privilege to read from kernel memory, then * everything is readable. */ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) { DTRACE_RANGE_REMAIN(remain, addr, addr, sz); return (1); } /* * You can obviously read that which you can store. */ if (dtrace_canstore_remains(addr, sz, remain, mstate, vstate)) return (1); /* * We're allowed to read from our own string table. */ if (DTRACE_INRANGE(addr, sz, mstate->dtms_difo->dtdo_strtab, mstate->dtms_difo->dtdo_strlen)) { DTRACE_RANGE_REMAIN(remain, addr, mstate->dtms_difo->dtdo_strtab, mstate->dtms_difo->dtdo_strlen); return (1); } if (vstate->dtvs_state != NULL && dtrace_priv_proc(vstate->dtvs_state)) { proc_t *p; /* * When we have privileges to the current process, there are * several context-related kernel structures that are safe to * read, even absent the privilege to read from kernel memory. * These reads are safe because these structures contain only * state that (1) we're permitted to read, (2) is harmless or * (3) contains pointers to additional kernel state that we're * not permitted to read (and as such, do not present an * opportunity for privilege escalation). Finally (and * critically), because of the nature of their relation with * the current thread context, the memory associated with these * structures cannot change over the duration of probe context, * and it is therefore impossible for this memory to be * deallocated and reallocated as something else while it's * being operated upon. */ if (DTRACE_INRANGE(addr, sz, curthread, sizeof (kthread_t))) { DTRACE_RANGE_REMAIN(remain, addr, curthread, sizeof (kthread_t)); return (1); } if ((p = curthread->t_procp) != NULL && DTRACE_INRANGE(addr, sz, curthread->t_procp, sizeof (proc_t))) { DTRACE_RANGE_REMAIN(remain, addr, curthread->t_procp, sizeof (proc_t)); return (1); } if (curthread->t_cred != NULL && DTRACE_INRANGE(addr, sz, curthread->t_cred, sizeof (cred_t))) { DTRACE_RANGE_REMAIN(remain, addr, curthread->t_cred, sizeof (cred_t)); return (1); } #ifdef illumos if (p != NULL && p->p_pidp != NULL && DTRACE_INRANGE(addr, sz, &(p->p_pidp->pid_id), sizeof (pid_t))) { DTRACE_RANGE_REMAIN(remain, addr, &(p->p_pidp->pid_id), sizeof (pid_t)); return (1); } if (curthread->t_cpu != NULL && DTRACE_INRANGE(addr, sz, curthread->t_cpu, offsetof(cpu_t, cpu_pause_thread))) { DTRACE_RANGE_REMAIN(remain, addr, curthread->t_cpu, offsetof(cpu_t, cpu_pause_thread)); return (1); } #endif } if ((fp = mstate->dtms_getf) != NULL) { uintptr_t psz = sizeof (void *); vnode_t *vp; vnodeops_t *op; /* * When getf() returns a file_t, the enabling is implicitly * granted the (transient) right to read the returned file_t * as well as the v_path and v_op->vnop_name of the underlying * vnode. These accesses are allowed after a successful * getf() because the members that they refer to cannot change * once set -- and the barrier logic in the kernel's closef() * path assures that the file_t and its referenced vode_t * cannot themselves be stale (that is, it impossible for * either dtms_getf itself or its f_vnode member to reference * freed memory). */ if (DTRACE_INRANGE(addr, sz, fp, sizeof (file_t))) { DTRACE_RANGE_REMAIN(remain, addr, fp, sizeof (file_t)); return (1); } if ((vp = fp->f_vnode) != NULL) { size_t slen; #ifdef illumos if (DTRACE_INRANGE(addr, sz, &vp->v_path, psz)) { DTRACE_RANGE_REMAIN(remain, addr, &vp->v_path, psz); return (1); } slen = strlen(vp->v_path) + 1; if (DTRACE_INRANGE(addr, sz, vp->v_path, slen)) { DTRACE_RANGE_REMAIN(remain, addr, vp->v_path, slen); return (1); } #endif if (DTRACE_INRANGE(addr, sz, &vp->v_op, psz)) { DTRACE_RANGE_REMAIN(remain, addr, &vp->v_op, psz); return (1); } #ifdef illumos if ((op = vp->v_op) != NULL && DTRACE_INRANGE(addr, sz, &op->vnop_name, psz)) { DTRACE_RANGE_REMAIN(remain, addr, &op->vnop_name, psz); return (1); } if (op != NULL && op->vnop_name != NULL && DTRACE_INRANGE(addr, sz, op->vnop_name, (slen = strlen(op->vnop_name) + 1))) { DTRACE_RANGE_REMAIN(remain, addr, op->vnop_name, slen); return (1); } #endif } } DTRACE_CPUFLAG_SET(CPU_DTRACE_KPRIV); *illval = addr; return (0); } /* * Convenience routine to check to see if a given string is within a memory * region in which a load may be issued given the user's privilege level; * this exists so that we don't need to issue unnecessary dtrace_strlen() * calls in the event that the user has all privileges. */ static int dtrace_strcanload(uint64_t addr, size_t sz, size_t *remain, dtrace_mstate_t *mstate, dtrace_vstate_t *vstate) { size_t rsize; /* * If we hold the privilege to read from kernel memory, then * everything is readable. */ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) { DTRACE_RANGE_REMAIN(remain, addr, addr, sz); return (1); } /* * Even if the caller is uninterested in querying the remaining valid * range, it is required to ensure that the access is allowed. */ if (remain == NULL) { remain = &rsize; } if (dtrace_canload_remains(addr, 0, remain, mstate, vstate)) { size_t strsz; /* * Perform the strlen after determining the length of the * memory region which is accessible. This prevents timing * information from being used to find NULs in memory which is * not accessible to the caller. */ strsz = 1 + dtrace_strlen((char *)(uintptr_t)addr, MIN(sz, *remain)); if (strsz <= *remain) { return (1); } } return (0); } /* * Convenience routine to check to see if a given variable is within a memory * region in which a load may be issued given the user's privilege level. */ static int dtrace_vcanload(void *src, dtrace_diftype_t *type, size_t *remain, dtrace_mstate_t *mstate, dtrace_vstate_t *vstate) { size_t sz; ASSERT(type->dtdt_flags & DIF_TF_BYREF); /* * Calculate the max size before performing any checks since even * DTRACE_ACCESS_KERNEL-credentialed callers expect that this function * return the max length via 'remain'. */ if (type->dtdt_kind == DIF_TYPE_STRING) { dtrace_state_t *state = vstate->dtvs_state; if (state != NULL) { sz = state->dts_options[DTRACEOPT_STRSIZE]; } else { /* * In helper context, we have a NULL state; fall back * to using the system-wide default for the string size * in this case. */ sz = dtrace_strsize_default; } } else { sz = type->dtdt_size; } /* * If we hold the privilege to read from kernel memory, then * everything is readable. */ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) { DTRACE_RANGE_REMAIN(remain, (uintptr_t)src, src, sz); return (1); } if (type->dtdt_kind == DIF_TYPE_STRING) { return (dtrace_strcanload((uintptr_t)src, sz, remain, mstate, vstate)); } return (dtrace_canload_remains((uintptr_t)src, sz, remain, mstate, vstate)); } /* * Convert a string to a signed integer using safe loads. * * NOTE: This function uses various macros from strtolctype.h to manipulate * digit values, etc -- these have all been checked to ensure they make * no additional function calls. */ static int64_t dtrace_strtoll(char *input, int base, size_t limit) { uintptr_t pos = (uintptr_t)input; int64_t val = 0; int x; boolean_t neg = B_FALSE; char c, cc, ccc; uintptr_t end = pos + limit; /* * Consume any whitespace preceding digits. */ while ((c = dtrace_load8(pos)) == ' ' || c == '\t') pos++; /* * Handle an explicit sign if one is present. */ if (c == '-' || c == '+') { if (c == '-') neg = B_TRUE; c = dtrace_load8(++pos); } /* * Check for an explicit hexadecimal prefix ("0x" or "0X") and skip it * if present. */ if (base == 16 && c == '0' && ((cc = dtrace_load8(pos + 1)) == 'x' || cc == 'X') && isxdigit(ccc = dtrace_load8(pos + 2))) { pos += 2; c = ccc; } /* * Read in contiguous digits until the first non-digit character. */ for (; pos < end && c != '\0' && lisalnum(c) && (x = DIGIT(c)) < base; c = dtrace_load8(++pos)) val = val * base + x; return (neg ? -val : val); } /* * Compare two strings using safe loads. */ static int dtrace_strncmp(char *s1, char *s2, size_t limit) { uint8_t c1, c2; volatile uint16_t *flags; if (s1 == s2 || limit == 0) return (0); flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; do { if (s1 == NULL) { c1 = '\0'; } else { c1 = dtrace_load8((uintptr_t)s1++); } if (s2 == NULL) { c2 = '\0'; } else { c2 = dtrace_load8((uintptr_t)s2++); } if (c1 != c2) return (c1 - c2); } while (--limit && c1 != '\0' && !(*flags & CPU_DTRACE_FAULT)); return (0); } /* * Compute strlen(s) for a string using safe memory accesses. The additional * len parameter is used to specify a maximum length to ensure completion. */ static size_t dtrace_strlen(const char *s, size_t lim) { uint_t len; for (len = 0; len != lim; len++) { if (dtrace_load8((uintptr_t)s++) == '\0') break; } return (len); } /* * Check if an address falls within a toxic region. */ static int dtrace_istoxic(uintptr_t kaddr, size_t size) { uintptr_t taddr, tsize; int i; for (i = 0; i < dtrace_toxranges; i++) { taddr = dtrace_toxrange[i].dtt_base; tsize = dtrace_toxrange[i].dtt_limit - taddr; if (kaddr - taddr < tsize) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = kaddr; return (1); } if (taddr - kaddr < size) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = taddr; return (1); } } return (0); } /* * Copy src to dst using safe memory accesses. The src is assumed to be unsafe * memory specified by the DIF program. The dst is assumed to be safe memory * that we can store to directly because it is managed by DTrace. As with * standard bcopy, overlapping copies are handled properly. */ static void dtrace_bcopy(const void *src, void *dst, size_t len) { if (len != 0) { uint8_t *s1 = dst; const uint8_t *s2 = src; if (s1 <= s2) { do { *s1++ = dtrace_load8((uintptr_t)s2++); } while (--len != 0); } else { s2 += len; s1 += len; do { *--s1 = dtrace_load8((uintptr_t)--s2); } while (--len != 0); } } } /* * Copy src to dst using safe memory accesses, up to either the specified * length, or the point that a nul byte is encountered. The src is assumed to * be unsafe memory specified by the DIF program. The dst is assumed to be * safe memory that we can store to directly because it is managed by DTrace. * Unlike dtrace_bcopy(), overlapping regions are not handled. */ static void dtrace_strcpy(const void *src, void *dst, size_t len) { if (len != 0) { uint8_t *s1 = dst, c; const uint8_t *s2 = src; do { *s1++ = c = dtrace_load8((uintptr_t)s2++); } while (--len != 0 && c != '\0'); } } /* * Copy src to dst, deriving the size and type from the specified (BYREF) * variable type. The src is assumed to be unsafe memory specified by the DIF * program. The dst is assumed to be DTrace variable memory that is of the * specified type; we assume that we can store to directly. */ static void dtrace_vcopy(void *src, void *dst, dtrace_diftype_t *type, size_t limit) { ASSERT(type->dtdt_flags & DIF_TF_BYREF); if (type->dtdt_kind == DIF_TYPE_STRING) { dtrace_strcpy(src, dst, MIN(type->dtdt_size, limit)); } else { dtrace_bcopy(src, dst, MIN(type->dtdt_size, limit)); } } /* * Compare s1 to s2 using safe memory accesses. The s1 data is assumed to be * unsafe memory specified by the DIF program. The s2 data is assumed to be * safe memory that we can access directly because it is managed by DTrace. */ static int dtrace_bcmp(const void *s1, const void *s2, size_t len) { volatile uint16_t *flags; flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; if (s1 == s2) return (0); if (s1 == NULL || s2 == NULL) return (1); if (s1 != s2 && len != 0) { const uint8_t *ps1 = s1; const uint8_t *ps2 = s2; do { if (dtrace_load8((uintptr_t)ps1++) != *ps2++) return (1); } while (--len != 0 && !(*flags & CPU_DTRACE_FAULT)); } return (0); } /* * Zero the specified region using a simple byte-by-byte loop. Note that this * is for safe DTrace-managed memory only. */ static void dtrace_bzero(void *dst, size_t len) { uchar_t *cp; for (cp = dst; len != 0; len--) *cp++ = 0; } static void dtrace_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum) { uint64_t result[2]; result[0] = addend1[0] + addend2[0]; result[1] = addend1[1] + addend2[1] + (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0); sum[0] = result[0]; sum[1] = result[1]; } /* * Shift the 128-bit value in a by b. If b is positive, shift left. * If b is negative, shift right. */ static void dtrace_shift_128(uint64_t *a, int b) { uint64_t mask; if (b == 0) return; if (b < 0) { b = -b; if (b >= 64) { a[0] = a[1] >> (b - 64); a[1] = 0; } else { a[0] >>= b; mask = 1LL << (64 - b); mask -= 1; a[0] |= ((a[1] & mask) << (64 - b)); a[1] >>= b; } } else { if (b >= 64) { a[1] = a[0] << (b - 64); a[0] = 0; } else { a[1] <<= b; mask = a[0] >> (64 - b); a[1] |= mask; a[0] <<= b; } } } /* * The basic idea is to break the 2 64-bit values into 4 32-bit values, * use native multiplication on those, and then re-combine into the * resulting 128-bit value. * * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) = * hi1 * hi2 << 64 + * hi1 * lo2 << 32 + * hi2 * lo1 << 32 + * lo1 * lo2 */ static void dtrace_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product) { uint64_t hi1, hi2, lo1, lo2; uint64_t tmp[2]; hi1 = factor1 >> 32; hi2 = factor2 >> 32; lo1 = factor1 & DT_MASK_LO; lo2 = factor2 & DT_MASK_LO; product[0] = lo1 * lo2; product[1] = hi1 * hi2; tmp[0] = hi1 * lo2; tmp[1] = 0; dtrace_shift_128(tmp, 32); dtrace_add_128(product, tmp, product); tmp[0] = hi2 * lo1; tmp[1] = 0; dtrace_shift_128(tmp, 32); dtrace_add_128(product, tmp, product); } /* * This privilege check should be used by actions and subroutines to * verify that the user credentials of the process that enabled the * invoking ECB match the target credentials */ static int dtrace_priv_proc_common_user(dtrace_state_t *state) { cred_t *cr, *s_cr = state->dts_cred.dcr_cred; /* * We should always have a non-NULL state cred here, since if cred * is null (anonymous tracing), we fast-path bypass this routine. */ ASSERT(s_cr != NULL); if ((cr = CRED()) != NULL && s_cr->cr_uid == cr->cr_uid && s_cr->cr_uid == cr->cr_ruid && s_cr->cr_uid == cr->cr_suid && s_cr->cr_gid == cr->cr_gid && s_cr->cr_gid == cr->cr_rgid && s_cr->cr_gid == cr->cr_sgid) return (1); return (0); } /* * This privilege check should be used by actions and subroutines to * verify that the zone of the process that enabled the invoking ECB * matches the target credentials */ static int dtrace_priv_proc_common_zone(dtrace_state_t *state) { #ifdef illumos cred_t *cr, *s_cr = state->dts_cred.dcr_cred; /* * We should always have a non-NULL state cred here, since if cred * is null (anonymous tracing), we fast-path bypass this routine. */ ASSERT(s_cr != NULL); if ((cr = CRED()) != NULL && s_cr->cr_zone == cr->cr_zone) return (1); return (0); #else return (1); #endif } /* * This privilege check should be used by actions and subroutines to * verify that the process has not setuid or changed credentials. */ static int dtrace_priv_proc_common_nocd(void) { proc_t *proc; if ((proc = ttoproc(curthread)) != NULL && !(proc->p_flag & SNOCD)) return (1); return (0); } static int dtrace_priv_proc_destructive(dtrace_state_t *state) { int action = state->dts_cred.dcr_action; if (((action & DTRACE_CRA_PROC_DESTRUCTIVE_ALLZONE) == 0) && dtrace_priv_proc_common_zone(state) == 0) goto bad; if (((action & DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER) == 0) && dtrace_priv_proc_common_user(state) == 0) goto bad; if (((action & DTRACE_CRA_PROC_DESTRUCTIVE_CREDCHG) == 0) && dtrace_priv_proc_common_nocd() == 0) goto bad; return (1); bad: cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_UPRIV; return (0); } static int dtrace_priv_proc_control(dtrace_state_t *state) { if (state->dts_cred.dcr_action & DTRACE_CRA_PROC_CONTROL) return (1); if (dtrace_priv_proc_common_zone(state) && dtrace_priv_proc_common_user(state) && dtrace_priv_proc_common_nocd()) return (1); cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_UPRIV; return (0); } static int dtrace_priv_proc(dtrace_state_t *state) { if (state->dts_cred.dcr_action & DTRACE_CRA_PROC) return (1); cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_UPRIV; return (0); } static int dtrace_priv_kernel(dtrace_state_t *state) { if (state->dts_cred.dcr_action & DTRACE_CRA_KERNEL) return (1); cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_KPRIV; return (0); } static int dtrace_priv_kernel_destructive(dtrace_state_t *state) { if (state->dts_cred.dcr_action & DTRACE_CRA_KERNEL_DESTRUCTIVE) return (1); cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_KPRIV; return (0); } /* * Determine if the dte_cond of the specified ECB allows for processing of * the current probe to continue. Note that this routine may allow continued * processing, but with access(es) stripped from the mstate's dtms_access * field. */ static int dtrace_priv_probe(dtrace_state_t *state, dtrace_mstate_t *mstate, dtrace_ecb_t *ecb) { dtrace_probe_t *probe = ecb->dte_probe; dtrace_provider_t *prov = probe->dtpr_provider; dtrace_pops_t *pops = &prov->dtpv_pops; int mode = DTRACE_MODE_NOPRIV_DROP; ASSERT(ecb->dte_cond); #ifdef illumos if (pops->dtps_mode != NULL) { mode = pops->dtps_mode(prov->dtpv_arg, probe->dtpr_id, probe->dtpr_arg); ASSERT((mode & DTRACE_MODE_USER) || (mode & DTRACE_MODE_KERNEL)); ASSERT((mode & DTRACE_MODE_NOPRIV_RESTRICT) || (mode & DTRACE_MODE_NOPRIV_DROP)); } /* * If the dte_cond bits indicate that this consumer is only allowed to * see user-mode firings of this probe, call the provider's dtps_mode() * entry point to check that the probe was fired while in a user * context. If that's not the case, use the policy specified by the * provider to determine if we drop the probe or merely restrict * operation. */ if (ecb->dte_cond & DTRACE_COND_USERMODE) { ASSERT(mode != DTRACE_MODE_NOPRIV_DROP); if (!(mode & DTRACE_MODE_USER)) { if (mode & DTRACE_MODE_NOPRIV_DROP) return (0); mstate->dtms_access &= ~DTRACE_ACCESS_ARGS; } } #endif /* * This is more subtle than it looks. We have to be absolutely certain * that CRED() isn't going to change out from under us so it's only * legit to examine that structure if we're in constrained situations. * Currently, the only times we'll this check is if a non-super-user * has enabled the profile or syscall providers -- providers that * allow visibility of all processes. For the profile case, the check * above will ensure that we're examining a user context. */ if (ecb->dte_cond & DTRACE_COND_OWNER) { cred_t *cr; cred_t *s_cr = state->dts_cred.dcr_cred; proc_t *proc; ASSERT(s_cr != NULL); if ((cr = CRED()) == NULL || s_cr->cr_uid != cr->cr_uid || s_cr->cr_uid != cr->cr_ruid || s_cr->cr_uid != cr->cr_suid || s_cr->cr_gid != cr->cr_gid || s_cr->cr_gid != cr->cr_rgid || s_cr->cr_gid != cr->cr_sgid || (proc = ttoproc(curthread)) == NULL || (proc->p_flag & SNOCD)) { if (mode & DTRACE_MODE_NOPRIV_DROP) return (0); #ifdef illumos mstate->dtms_access &= ~DTRACE_ACCESS_PROC; #endif } } #ifdef illumos /* * If our dte_cond is set to DTRACE_COND_ZONEOWNER and we are not * in our zone, check to see if our mode policy is to restrict rather * than to drop; if to restrict, strip away both DTRACE_ACCESS_PROC * and DTRACE_ACCESS_ARGS */ if (ecb->dte_cond & DTRACE_COND_ZONEOWNER) { cred_t *cr; cred_t *s_cr = state->dts_cred.dcr_cred; ASSERT(s_cr != NULL); if ((cr = CRED()) == NULL || s_cr->cr_zone->zone_id != cr->cr_zone->zone_id) { if (mode & DTRACE_MODE_NOPRIV_DROP) return (0); mstate->dtms_access &= ~(DTRACE_ACCESS_PROC | DTRACE_ACCESS_ARGS); } } #endif return (1); } /* * Note: not called from probe context. This function is called * asynchronously (and at a regular interval) from outside of probe context to * clean the dirty dynamic variable lists on all CPUs. Dynamic variable * cleaning is explained in detail in . */ void dtrace_dynvar_clean(dtrace_dstate_t *dstate) { dtrace_dynvar_t *dirty; dtrace_dstate_percpu_t *dcpu; dtrace_dynvar_t **rinsep; int i, j, work = 0; for (i = 0; i < NCPU; i++) { dcpu = &dstate->dtds_percpu[i]; rinsep = &dcpu->dtdsc_rinsing; /* * If the dirty list is NULL, there is no dirty work to do. */ if (dcpu->dtdsc_dirty == NULL) continue; if (dcpu->dtdsc_rinsing != NULL) { /* * If the rinsing list is non-NULL, then it is because * this CPU was selected to accept another CPU's * dirty list -- and since that time, dirty buffers * have accumulated. This is a highly unlikely * condition, but we choose to ignore the dirty * buffers -- they'll be picked up a future cleanse. */ continue; } if (dcpu->dtdsc_clean != NULL) { /* * If the clean list is non-NULL, then we're in a * situation where a CPU has done deallocations (we * have a non-NULL dirty list) but no allocations (we * also have a non-NULL clean list). We can't simply * move the dirty list into the clean list on this * CPU, yet we also don't want to allow this condition * to persist, lest a short clean list prevent a * massive dirty list from being cleaned (which in * turn could lead to otherwise avoidable dynamic * drops). To deal with this, we look for some CPU * with a NULL clean list, NULL dirty list, and NULL * rinsing list -- and then we borrow this CPU to * rinse our dirty list. */ for (j = 0; j < NCPU; j++) { dtrace_dstate_percpu_t *rinser; rinser = &dstate->dtds_percpu[j]; if (rinser->dtdsc_rinsing != NULL) continue; if (rinser->dtdsc_dirty != NULL) continue; if (rinser->dtdsc_clean != NULL) continue; rinsep = &rinser->dtdsc_rinsing; break; } if (j == NCPU) { /* * We were unable to find another CPU that * could accept this dirty list -- we are * therefore unable to clean it now. */ dtrace_dynvar_failclean++; continue; } } work = 1; /* * Atomically move the dirty list aside. */ do { dirty = dcpu->dtdsc_dirty; /* * Before we zap the dirty list, set the rinsing list. * (This allows for a potential assertion in * dtrace_dynvar(): if a free dynamic variable appears * on a hash chain, either the dirty list or the * rinsing list for some CPU must be non-NULL.) */ *rinsep = dirty; dtrace_membar_producer(); } while (dtrace_casptr(&dcpu->dtdsc_dirty, dirty, NULL) != dirty); } if (!work) { /* * We have no work to do; we can simply return. */ return; } dtrace_sync(); for (i = 0; i < NCPU; i++) { dcpu = &dstate->dtds_percpu[i]; if (dcpu->dtdsc_rinsing == NULL) continue; /* * We are now guaranteed that no hash chain contains a pointer * into this dirty list; we can make it clean. */ ASSERT(dcpu->dtdsc_clean == NULL); dcpu->dtdsc_clean = dcpu->dtdsc_rinsing; dcpu->dtdsc_rinsing = NULL; } /* * Before we actually set the state to be DTRACE_DSTATE_CLEAN, make * sure that all CPUs have seen all of the dtdsc_clean pointers. * This prevents a race whereby a CPU incorrectly decides that * the state should be something other than DTRACE_DSTATE_CLEAN * after dtrace_dynvar_clean() has completed. */ dtrace_sync(); dstate->dtds_state = DTRACE_DSTATE_CLEAN; } /* * Depending on the value of the op parameter, this function looks-up, * allocates or deallocates an arbitrarily-keyed dynamic variable. If an * allocation is requested, this function will return a pointer to a * dtrace_dynvar_t corresponding to the allocated variable -- or NULL if no * variable can be allocated. If NULL is returned, the appropriate counter * will be incremented. */ dtrace_dynvar_t * dtrace_dynvar(dtrace_dstate_t *dstate, uint_t nkeys, dtrace_key_t *key, size_t dsize, dtrace_dynvar_op_t op, dtrace_mstate_t *mstate, dtrace_vstate_t *vstate) { uint64_t hashval = DTRACE_DYNHASH_VALID; dtrace_dynhash_t *hash = dstate->dtds_hash; dtrace_dynvar_t *free, *new_free, *next, *dvar, *start, *prev = NULL; processorid_t me = curcpu, cpu = me; dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[me]; size_t bucket, ksize; size_t chunksize = dstate->dtds_chunksize; uintptr_t kdata, lock, nstate; uint_t i; ASSERT(nkeys != 0); /* * Hash the key. As with aggregations, we use Jenkins' "One-at-a-time" * algorithm. For the by-value portions, we perform the algorithm in * 16-bit chunks (as opposed to 8-bit chunks). This speeds things up a * bit, and seems to have only a minute effect on distribution. For * the by-reference data, we perform "One-at-a-time" iterating (safely) * over each referenced byte. It's painful to do this, but it's much * better than pathological hash distribution. The efficacy of the * hashing algorithm (and a comparison with other algorithms) may be * found by running the ::dtrace_dynstat MDB dcmd. */ for (i = 0; i < nkeys; i++) { if (key[i].dttk_size == 0) { uint64_t val = key[i].dttk_value; hashval += (val >> 48) & 0xffff; hashval += (hashval << 10); hashval ^= (hashval >> 6); hashval += (val >> 32) & 0xffff; hashval += (hashval << 10); hashval ^= (hashval >> 6); hashval += (val >> 16) & 0xffff; hashval += (hashval << 10); hashval ^= (hashval >> 6); hashval += val & 0xffff; hashval += (hashval << 10); hashval ^= (hashval >> 6); } else { /* * This is incredibly painful, but it beats the hell * out of the alternative. */ uint64_t j, size = key[i].dttk_size; uintptr_t base = (uintptr_t)key[i].dttk_value; if (!dtrace_canload(base, size, mstate, vstate)) break; for (j = 0; j < size; j++) { hashval += dtrace_load8(base + j); hashval += (hashval << 10); hashval ^= (hashval >> 6); } } } if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) return (NULL); hashval += (hashval << 3); hashval ^= (hashval >> 11); hashval += (hashval << 15); /* * There is a remote chance (ideally, 1 in 2^31) that our hashval * comes out to be one of our two sentinel hash values. If this * actually happens, we set the hashval to be a value known to be a * non-sentinel value. */ if (hashval == DTRACE_DYNHASH_FREE || hashval == DTRACE_DYNHASH_SINK) hashval = DTRACE_DYNHASH_VALID; /* * Yes, it's painful to do a divide here. If the cycle count becomes * important here, tricks can be pulled to reduce it. (However, it's * critical that hash collisions be kept to an absolute minimum; * they're much more painful than a divide.) It's better to have a * solution that generates few collisions and still keeps things * relatively simple. */ bucket = hashval % dstate->dtds_hashsize; if (op == DTRACE_DYNVAR_DEALLOC) { volatile uintptr_t *lockp = &hash[bucket].dtdh_lock; for (;;) { while ((lock = *lockp) & 1) continue; if (dtrace_casptr((volatile void *)lockp, (volatile void *)lock, (volatile void *)(lock + 1)) == (void *)lock) break; } dtrace_membar_producer(); } top: prev = NULL; lock = hash[bucket].dtdh_lock; dtrace_membar_consumer(); start = hash[bucket].dtdh_chain; ASSERT(start != NULL && (start->dtdv_hashval == DTRACE_DYNHASH_SINK || start->dtdv_hashval != DTRACE_DYNHASH_FREE || op != DTRACE_DYNVAR_DEALLOC)); for (dvar = start; dvar != NULL; dvar = dvar->dtdv_next) { dtrace_tuple_t *dtuple = &dvar->dtdv_tuple; dtrace_key_t *dkey = &dtuple->dtt_key[0]; if (dvar->dtdv_hashval != hashval) { if (dvar->dtdv_hashval == DTRACE_DYNHASH_SINK) { /* * We've reached the sink, and therefore the * end of the hash chain; we can kick out of * the loop knowing that we have seen a valid * snapshot of state. */ ASSERT(dvar->dtdv_next == NULL); ASSERT(dvar == &dtrace_dynhash_sink); break; } if (dvar->dtdv_hashval == DTRACE_DYNHASH_FREE) { /* * We've gone off the rails: somewhere along * the line, one of the members of this hash * chain was deleted. Note that we could also * detect this by simply letting this loop run * to completion, as we would eventually hit * the end of the dirty list. However, we * want to avoid running the length of the * dirty list unnecessarily (it might be quite * long), so we catch this as early as * possible by detecting the hash marker. In * this case, we simply set dvar to NULL and * break; the conditional after the loop will * send us back to top. */ dvar = NULL; break; } goto next; } if (dtuple->dtt_nkeys != nkeys) goto next; for (i = 0; i < nkeys; i++, dkey++) { if (dkey->dttk_size != key[i].dttk_size) goto next; /* size or type mismatch */ if (dkey->dttk_size != 0) { if (dtrace_bcmp( (void *)(uintptr_t)key[i].dttk_value, (void *)(uintptr_t)dkey->dttk_value, dkey->dttk_size)) goto next; } else { if (dkey->dttk_value != key[i].dttk_value) goto next; } } if (op != DTRACE_DYNVAR_DEALLOC) return (dvar); ASSERT(dvar->dtdv_next == NULL || dvar->dtdv_next->dtdv_hashval != DTRACE_DYNHASH_FREE); if (prev != NULL) { ASSERT(hash[bucket].dtdh_chain != dvar); ASSERT(start != dvar); ASSERT(prev->dtdv_next == dvar); prev->dtdv_next = dvar->dtdv_next; } else { if (dtrace_casptr(&hash[bucket].dtdh_chain, start, dvar->dtdv_next) != start) { /* * We have failed to atomically swing the * hash table head pointer, presumably because * of a conflicting allocation on another CPU. * We need to reread the hash chain and try * again. */ goto top; } } dtrace_membar_producer(); /* * Now set the hash value to indicate that it's free. */ ASSERT(hash[bucket].dtdh_chain != dvar); dvar->dtdv_hashval = DTRACE_DYNHASH_FREE; dtrace_membar_producer(); /* * Set the next pointer to point at the dirty list, and * atomically swing the dirty pointer to the newly freed dvar. */ do { next = dcpu->dtdsc_dirty; dvar->dtdv_next = next; } while (dtrace_casptr(&dcpu->dtdsc_dirty, next, dvar) != next); /* * Finally, unlock this hash bucket. */ ASSERT(hash[bucket].dtdh_lock == lock); ASSERT(lock & 1); hash[bucket].dtdh_lock++; return (NULL); next: prev = dvar; continue; } if (dvar == NULL) { /* * If dvar is NULL, it is because we went off the rails: * one of the elements that we traversed in the hash chain * was deleted while we were traversing it. In this case, * we assert that we aren't doing a dealloc (deallocs lock * the hash bucket to prevent themselves from racing with * one another), and retry the hash chain traversal. */ ASSERT(op != DTRACE_DYNVAR_DEALLOC); goto top; } if (op != DTRACE_DYNVAR_ALLOC) { /* * If we are not to allocate a new variable, we want to * return NULL now. Before we return, check that the value * of the lock word hasn't changed. If it has, we may have * seen an inconsistent snapshot. */ if (op == DTRACE_DYNVAR_NOALLOC) { if (hash[bucket].dtdh_lock != lock) goto top; } else { ASSERT(op == DTRACE_DYNVAR_DEALLOC); ASSERT(hash[bucket].dtdh_lock == lock); ASSERT(lock & 1); hash[bucket].dtdh_lock++; } return (NULL); } /* * We need to allocate a new dynamic variable. The size we need is the * size of dtrace_dynvar plus the size of nkeys dtrace_key_t's plus the * size of any auxiliary key data (rounded up to 8-byte alignment) plus * the size of any referred-to data (dsize). We then round the final * size up to the chunksize for allocation. */ for (ksize = 0, i = 0; i < nkeys; i++) ksize += P2ROUNDUP(key[i].dttk_size, sizeof (uint64_t)); /* * This should be pretty much impossible, but could happen if, say, * strange DIF specified the tuple. Ideally, this should be an * assertion and not an error condition -- but that requires that the * chunksize calculation in dtrace_difo_chunksize() be absolutely * bullet-proof. (That is, it must not be able to be fooled by * malicious DIF.) Given the lack of backwards branches in DIF, * solving this would presumably not amount to solving the Halting * Problem -- but it still seems awfully hard. */ if (sizeof (dtrace_dynvar_t) + sizeof (dtrace_key_t) * (nkeys - 1) + ksize + dsize > chunksize) { dcpu->dtdsc_drops++; return (NULL); } nstate = DTRACE_DSTATE_EMPTY; do { retry: free = dcpu->dtdsc_free; if (free == NULL) { dtrace_dynvar_t *clean = dcpu->dtdsc_clean; void *rval; if (clean == NULL) { /* * We're out of dynamic variable space on * this CPU. Unless we have tried all CPUs, * we'll try to allocate from a different * CPU. */ switch (dstate->dtds_state) { case DTRACE_DSTATE_CLEAN: { void *sp = &dstate->dtds_state; if (++cpu >= NCPU) cpu = 0; if (dcpu->dtdsc_dirty != NULL && nstate == DTRACE_DSTATE_EMPTY) nstate = DTRACE_DSTATE_DIRTY; if (dcpu->dtdsc_rinsing != NULL) nstate = DTRACE_DSTATE_RINSING; dcpu = &dstate->dtds_percpu[cpu]; if (cpu != me) goto retry; (void) dtrace_cas32(sp, DTRACE_DSTATE_CLEAN, nstate); /* * To increment the correct bean * counter, take another lap. */ goto retry; } case DTRACE_DSTATE_DIRTY: dcpu->dtdsc_dirty_drops++; break; case DTRACE_DSTATE_RINSING: dcpu->dtdsc_rinsing_drops++; break; case DTRACE_DSTATE_EMPTY: dcpu->dtdsc_drops++; break; } DTRACE_CPUFLAG_SET(CPU_DTRACE_DROP); return (NULL); } /* * The clean list appears to be non-empty. We want to * move the clean list to the free list; we start by * moving the clean pointer aside. */ if (dtrace_casptr(&dcpu->dtdsc_clean, clean, NULL) != clean) { /* * We are in one of two situations: * * (a) The clean list was switched to the * free list by another CPU. * * (b) The clean list was added to by the * cleansing cyclic. * * In either of these situations, we can * just reattempt the free list allocation. */ goto retry; } ASSERT(clean->dtdv_hashval == DTRACE_DYNHASH_FREE); /* * Now we'll move the clean list to our free list. * It's impossible for this to fail: the only way * the free list can be updated is through this * code path, and only one CPU can own the clean list. * Thus, it would only be possible for this to fail if * this code were racing with dtrace_dynvar_clean(). * (That is, if dtrace_dynvar_clean() updated the clean * list, and we ended up racing to update the free * list.) This race is prevented by the dtrace_sync() * in dtrace_dynvar_clean() -- which flushes the * owners of the clean lists out before resetting * the clean lists. */ dcpu = &dstate->dtds_percpu[me]; rval = dtrace_casptr(&dcpu->dtdsc_free, NULL, clean); ASSERT(rval == NULL); goto retry; } dvar = free; new_free = dvar->dtdv_next; } while (dtrace_casptr(&dcpu->dtdsc_free, free, new_free) != free); /* * We have now allocated a new chunk. We copy the tuple keys into the * tuple array and copy any referenced key data into the data space * following the tuple array. As we do this, we relocate dttk_value * in the final tuple to point to the key data address in the chunk. */ kdata = (uintptr_t)&dvar->dtdv_tuple.dtt_key[nkeys]; dvar->dtdv_data = (void *)(kdata + ksize); dvar->dtdv_tuple.dtt_nkeys = nkeys; for (i = 0; i < nkeys; i++) { dtrace_key_t *dkey = &dvar->dtdv_tuple.dtt_key[i]; size_t kesize = key[i].dttk_size; if (kesize != 0) { dtrace_bcopy( (const void *)(uintptr_t)key[i].dttk_value, (void *)kdata, kesize); dkey->dttk_value = kdata; kdata += P2ROUNDUP(kesize, sizeof (uint64_t)); } else { dkey->dttk_value = key[i].dttk_value; } dkey->dttk_size = kesize; } ASSERT(dvar->dtdv_hashval == DTRACE_DYNHASH_FREE); dvar->dtdv_hashval = hashval; dvar->dtdv_next = start; if (dtrace_casptr(&hash[bucket].dtdh_chain, start, dvar) == start) return (dvar); /* * The cas has failed. Either another CPU is adding an element to * this hash chain, or another CPU is deleting an element from this * hash chain. The simplest way to deal with both of these cases * (though not necessarily the most efficient) is to free our * allocated block and re-attempt it all. Note that the free is * to the dirty list and _not_ to the free list. This is to prevent * races with allocators, above. */ dvar->dtdv_hashval = DTRACE_DYNHASH_FREE; dtrace_membar_producer(); do { free = dcpu->dtdsc_dirty; dvar->dtdv_next = free; } while (dtrace_casptr(&dcpu->dtdsc_dirty, free, dvar) != free); goto top; } /*ARGSUSED*/ static void dtrace_aggregate_min(uint64_t *oval, uint64_t nval, uint64_t arg) { if ((int64_t)nval < (int64_t)*oval) *oval = nval; } /*ARGSUSED*/ static void dtrace_aggregate_max(uint64_t *oval, uint64_t nval, uint64_t arg) { if ((int64_t)nval > (int64_t)*oval) *oval = nval; } static void dtrace_aggregate_quantize(uint64_t *quanta, uint64_t nval, uint64_t incr) { int i, zero = DTRACE_QUANTIZE_ZEROBUCKET; int64_t val = (int64_t)nval; if (val < 0) { for (i = 0; i < zero; i++) { if (val <= DTRACE_QUANTIZE_BUCKETVAL(i)) { quanta[i] += incr; return; } } } else { for (i = zero + 1; i < DTRACE_QUANTIZE_NBUCKETS; i++) { if (val < DTRACE_QUANTIZE_BUCKETVAL(i)) { quanta[i - 1] += incr; return; } } quanta[DTRACE_QUANTIZE_NBUCKETS - 1] += incr; return; } ASSERT(0); } static void dtrace_aggregate_lquantize(uint64_t *lquanta, uint64_t nval, uint64_t incr) { uint64_t arg = *lquanta++; int32_t base = DTRACE_LQUANTIZE_BASE(arg); uint16_t step = DTRACE_LQUANTIZE_STEP(arg); uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg); int32_t val = (int32_t)nval, level; ASSERT(step != 0); ASSERT(levels != 0); if (val < base) { /* * This is an underflow. */ lquanta[0] += incr; return; } level = (val - base) / step; if (level < levels) { lquanta[level + 1] += incr; return; } /* * This is an overflow. */ lquanta[levels + 1] += incr; } static int dtrace_aggregate_llquantize_bucket(uint16_t factor, uint16_t low, uint16_t high, uint16_t nsteps, int64_t value) { int64_t this = 1, last, next; int base = 1, order; ASSERT(factor <= nsteps); ASSERT(nsteps % factor == 0); for (order = 0; order < low; order++) this *= factor; /* * If our value is less than our factor taken to the power of the * low order of magnitude, it goes into the zeroth bucket. */ if (value < (last = this)) return (0); for (this *= factor; order <= high; order++) { int nbuckets = this > nsteps ? nsteps : this; if ((next = this * factor) < this) { /* * We should not generally get log/linear quantizations * with a high magnitude that allows 64-bits to * overflow, but we nonetheless protect against this * by explicitly checking for overflow, and clamping * our value accordingly. */ value = this - 1; } if (value < this) { /* * If our value lies within this order of magnitude, * determine its position by taking the offset within * the order of magnitude, dividing by the bucket * width, and adding to our (accumulated) base. */ return (base + (value - last) / (this / nbuckets)); } base += nbuckets - (nbuckets / factor); last = this; this = next; } /* * Our value is greater than or equal to our factor taken to the * power of one plus the high magnitude -- return the top bucket. */ return (base); } static void dtrace_aggregate_llquantize(uint64_t *llquanta, uint64_t nval, uint64_t incr) { uint64_t arg = *llquanta++; uint16_t factor = DTRACE_LLQUANTIZE_FACTOR(arg); uint16_t low = DTRACE_LLQUANTIZE_LOW(arg); uint16_t high = DTRACE_LLQUANTIZE_HIGH(arg); uint16_t nsteps = DTRACE_LLQUANTIZE_NSTEP(arg); llquanta[dtrace_aggregate_llquantize_bucket(factor, low, high, nsteps, nval)] += incr; } /*ARGSUSED*/ static void dtrace_aggregate_avg(uint64_t *data, uint64_t nval, uint64_t arg) { data[0]++; data[1] += nval; } /*ARGSUSED*/ static void dtrace_aggregate_stddev(uint64_t *data, uint64_t nval, uint64_t arg) { int64_t snval = (int64_t)nval; uint64_t tmp[2]; data[0]++; data[1] += nval; /* * What we want to say here is: * * data[2] += nval * nval; * * But given that nval is 64-bit, we could easily overflow, so * we do this as 128-bit arithmetic. */ if (snval < 0) snval = -snval; dtrace_multiply_128((uint64_t)snval, (uint64_t)snval, tmp); dtrace_add_128(data + 2, tmp, data + 2); } /*ARGSUSED*/ static void dtrace_aggregate_count(uint64_t *oval, uint64_t nval, uint64_t arg) { *oval = *oval + 1; } /*ARGSUSED*/ static void dtrace_aggregate_sum(uint64_t *oval, uint64_t nval, uint64_t arg) { *oval += nval; } /* * Aggregate given the tuple in the principal data buffer, and the aggregating * action denoted by the specified dtrace_aggregation_t. The aggregation * buffer is specified as the buf parameter. This routine does not return * failure; if there is no space in the aggregation buffer, the data will be * dropped, and a corresponding counter incremented. */ static void dtrace_aggregate(dtrace_aggregation_t *agg, dtrace_buffer_t *dbuf, intptr_t offset, dtrace_buffer_t *buf, uint64_t expr, uint64_t arg) { dtrace_recdesc_t *rec = &agg->dtag_action.dta_rec; uint32_t i, ndx, size, fsize; uint32_t align = sizeof (uint64_t) - 1; dtrace_aggbuffer_t *agb; dtrace_aggkey_t *key; uint32_t hashval = 0, limit, isstr; caddr_t tomax, data, kdata; dtrace_actkind_t action; dtrace_action_t *act; uintptr_t offs; if (buf == NULL) return; if (!agg->dtag_hasarg) { /* * Currently, only quantize() and lquantize() take additional * arguments, and they have the same semantics: an increment * value that defaults to 1 when not present. If additional * aggregating actions take arguments, the setting of the * default argument value will presumably have to become more * sophisticated... */ arg = 1; } action = agg->dtag_action.dta_kind - DTRACEACT_AGGREGATION; size = rec->dtrd_offset - agg->dtag_base; fsize = size + rec->dtrd_size; ASSERT(dbuf->dtb_tomax != NULL); data = dbuf->dtb_tomax + offset + agg->dtag_base; if ((tomax = buf->dtb_tomax) == NULL) { dtrace_buffer_drop(buf); return; } /* * The metastructure is always at the bottom of the buffer. */ agb = (dtrace_aggbuffer_t *)(tomax + buf->dtb_size - sizeof (dtrace_aggbuffer_t)); if (buf->dtb_offset == 0) { /* * We just kludge up approximately 1/8th of the size to be * buckets. If this guess ends up being routinely * off-the-mark, we may need to dynamically readjust this * based on past performance. */ uintptr_t hashsize = (buf->dtb_size >> 3) / sizeof (uintptr_t); if ((uintptr_t)agb - hashsize * sizeof (dtrace_aggkey_t *) < (uintptr_t)tomax || hashsize == 0) { /* * We've been given a ludicrously small buffer; * increment our drop count and leave. */ dtrace_buffer_drop(buf); return; } /* * And now, a pathetic attempt to try to get a an odd (or * perchance, a prime) hash size for better hash distribution. */ if (hashsize > (DTRACE_AGGHASHSIZE_SLEW << 3)) hashsize -= DTRACE_AGGHASHSIZE_SLEW; agb->dtagb_hashsize = hashsize; agb->dtagb_hash = (dtrace_aggkey_t **)((uintptr_t)agb - agb->dtagb_hashsize * sizeof (dtrace_aggkey_t *)); agb->dtagb_free = (uintptr_t)agb->dtagb_hash; for (i = 0; i < agb->dtagb_hashsize; i++) agb->dtagb_hash[i] = NULL; } ASSERT(agg->dtag_first != NULL); ASSERT(agg->dtag_first->dta_intuple); /* * Calculate the hash value based on the key. Note that we _don't_ * include the aggid in the hashing (but we will store it as part of * the key). The hashing algorithm is Bob Jenkins' "One-at-a-time" * algorithm: a simple, quick algorithm that has no known funnels, and * gets good distribution in practice. The efficacy of the hashing * algorithm (and a comparison with other algorithms) may be found by * running the ::dtrace_aggstat MDB dcmd. */ for (act = agg->dtag_first; act->dta_intuple; act = act->dta_next) { i = act->dta_rec.dtrd_offset - agg->dtag_base; limit = i + act->dta_rec.dtrd_size; ASSERT(limit <= size); isstr = DTRACEACT_ISSTRING(act); for (; i < limit; i++) { hashval += data[i]; hashval += (hashval << 10); hashval ^= (hashval >> 6); if (isstr && data[i] == '\0') break; } } hashval += (hashval << 3); hashval ^= (hashval >> 11); hashval += (hashval << 15); /* * Yes, the divide here is expensive -- but it's generally the least * of the performance issues given the amount of data that we iterate * over to compute hash values, compare data, etc. */ ndx = hashval % agb->dtagb_hashsize; for (key = agb->dtagb_hash[ndx]; key != NULL; key = key->dtak_next) { ASSERT((caddr_t)key >= tomax); ASSERT((caddr_t)key < tomax + buf->dtb_size); if (hashval != key->dtak_hashval || key->dtak_size != size) continue; kdata = key->dtak_data; ASSERT(kdata >= tomax && kdata < tomax + buf->dtb_size); for (act = agg->dtag_first; act->dta_intuple; act = act->dta_next) { i = act->dta_rec.dtrd_offset - agg->dtag_base; limit = i + act->dta_rec.dtrd_size; ASSERT(limit <= size); isstr = DTRACEACT_ISSTRING(act); for (; i < limit; i++) { if (kdata[i] != data[i]) goto next; if (isstr && data[i] == '\0') break; } } if (action != key->dtak_action) { /* * We are aggregating on the same value in the same * aggregation with two different aggregating actions. * (This should have been picked up in the compiler, * so we may be dealing with errant or devious DIF.) * This is an error condition; we indicate as much, * and return. */ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return; } /* * This is a hit: we need to apply the aggregator to * the value at this key. */ agg->dtag_aggregate((uint64_t *)(kdata + size), expr, arg); return; next: continue; } /* * We didn't find it. We need to allocate some zero-filled space, * link it into the hash table appropriately, and apply the aggregator * to the (zero-filled) value. */ offs = buf->dtb_offset; while (offs & (align - 1)) offs += sizeof (uint32_t); /* * If we don't have enough room to both allocate a new key _and_ * its associated data, increment the drop count and return. */ if ((uintptr_t)tomax + offs + fsize > agb->dtagb_free - sizeof (dtrace_aggkey_t)) { dtrace_buffer_drop(buf); return; } /*CONSTCOND*/ ASSERT(!(sizeof (dtrace_aggkey_t) & (sizeof (uintptr_t) - 1))); key = (dtrace_aggkey_t *)(agb->dtagb_free - sizeof (dtrace_aggkey_t)); agb->dtagb_free -= sizeof (dtrace_aggkey_t); key->dtak_data = kdata = tomax + offs; buf->dtb_offset = offs + fsize; /* * Now copy the data across. */ *((dtrace_aggid_t *)kdata) = agg->dtag_id; for (i = sizeof (dtrace_aggid_t); i < size; i++) kdata[i] = data[i]; /* * Because strings are not zeroed out by default, we need to iterate * looking for actions that store strings, and we need to explicitly * pad these strings out with zeroes. */ for (act = agg->dtag_first; act->dta_intuple; act = act->dta_next) { int nul; if (!DTRACEACT_ISSTRING(act)) continue; i = act->dta_rec.dtrd_offset - agg->dtag_base; limit = i + act->dta_rec.dtrd_size; ASSERT(limit <= size); for (nul = 0; i < limit; i++) { if (nul) { kdata[i] = '\0'; continue; } if (data[i] != '\0') continue; nul = 1; } } for (i = size; i < fsize; i++) kdata[i] = 0; key->dtak_hashval = hashval; key->dtak_size = size; key->dtak_action = action; key->dtak_next = agb->dtagb_hash[ndx]; agb->dtagb_hash[ndx] = key; /* * Finally, apply the aggregator. */ *((uint64_t *)(key->dtak_data + size)) = agg->dtag_initial; agg->dtag_aggregate((uint64_t *)(key->dtak_data + size), expr, arg); } /* * Given consumer state, this routine finds a speculation in the INACTIVE * state and transitions it into the ACTIVE state. If there is no speculation * in the INACTIVE state, 0 is returned. In this case, no error counter is * incremented -- it is up to the caller to take appropriate action. */ static int dtrace_speculation(dtrace_state_t *state) { int i = 0; dtrace_speculation_state_t current; uint32_t *stat = &state->dts_speculations_unavail, count; while (i < state->dts_nspeculations) { dtrace_speculation_t *spec = &state->dts_speculations[i]; current = spec->dtsp_state; if (current != DTRACESPEC_INACTIVE) { if (current == DTRACESPEC_COMMITTINGMANY || current == DTRACESPEC_COMMITTING || current == DTRACESPEC_DISCARDING) stat = &state->dts_speculations_busy; i++; continue; } if (dtrace_cas32((uint32_t *)&spec->dtsp_state, current, DTRACESPEC_ACTIVE) == current) return (i + 1); } /* * We couldn't find a speculation. If we found as much as a single * busy speculation buffer, we'll attribute this failure as "busy" * instead of "unavail". */ do { count = *stat; } while (dtrace_cas32(stat, count, count + 1) != count); return (0); } /* * This routine commits an active speculation. If the specified speculation * is not in a valid state to perform a commit(), this routine will silently do * nothing. The state of the specified speculation is transitioned according * to the state transition diagram outlined in */ static void dtrace_speculation_commit(dtrace_state_t *state, processorid_t cpu, dtrace_specid_t which) { dtrace_speculation_t *spec; dtrace_buffer_t *src, *dest; uintptr_t daddr, saddr, dlimit, slimit; dtrace_speculation_state_t current, new = 0; intptr_t offs; uint64_t timestamp; if (which == 0) return; if (which > state->dts_nspeculations) { cpu_core[cpu].cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; return; } spec = &state->dts_speculations[which - 1]; src = &spec->dtsp_buffer[cpu]; dest = &state->dts_buffer[cpu]; do { current = spec->dtsp_state; if (current == DTRACESPEC_COMMITTINGMANY) break; switch (current) { case DTRACESPEC_INACTIVE: case DTRACESPEC_DISCARDING: return; case DTRACESPEC_COMMITTING: /* * This is only possible if we are (a) commit()'ing * without having done a prior speculate() on this CPU * and (b) racing with another commit() on a different * CPU. There's nothing to do -- we just assert that * our offset is 0. */ ASSERT(src->dtb_offset == 0); return; case DTRACESPEC_ACTIVE: new = DTRACESPEC_COMMITTING; break; case DTRACESPEC_ACTIVEONE: /* * This speculation is active on one CPU. If our * buffer offset is non-zero, we know that the one CPU * must be us. Otherwise, we are committing on a * different CPU from the speculate(), and we must * rely on being asynchronously cleaned. */ if (src->dtb_offset != 0) { new = DTRACESPEC_COMMITTING; break; } /*FALLTHROUGH*/ case DTRACESPEC_ACTIVEMANY: new = DTRACESPEC_COMMITTINGMANY; break; default: ASSERT(0); } } while (dtrace_cas32((uint32_t *)&spec->dtsp_state, current, new) != current); /* * We have set the state to indicate that we are committing this * speculation. Now reserve the necessary space in the destination * buffer. */ if ((offs = dtrace_buffer_reserve(dest, src->dtb_offset, sizeof (uint64_t), state, NULL)) < 0) { dtrace_buffer_drop(dest); goto out; } /* * We have sufficient space to copy the speculative buffer into the * primary buffer. First, modify the speculative buffer, filling * in the timestamp of all entries with the current time. The data * must have the commit() time rather than the time it was traced, * so that all entries in the primary buffer are in timestamp order. */ timestamp = dtrace_gethrtime(); saddr = (uintptr_t)src->dtb_tomax; slimit = saddr + src->dtb_offset; while (saddr < slimit) { size_t size; dtrace_rechdr_t *dtrh = (dtrace_rechdr_t *)saddr; if (dtrh->dtrh_epid == DTRACE_EPIDNONE) { saddr += sizeof (dtrace_epid_t); continue; } ASSERT3U(dtrh->dtrh_epid, <=, state->dts_necbs); size = state->dts_ecbs[dtrh->dtrh_epid - 1]->dte_size; ASSERT3U(saddr + size, <=, slimit); ASSERT3U(size, >=, sizeof (dtrace_rechdr_t)); ASSERT3U(DTRACE_RECORD_LOAD_TIMESTAMP(dtrh), ==, UINT64_MAX); DTRACE_RECORD_STORE_TIMESTAMP(dtrh, timestamp); saddr += size; } /* * Copy the buffer across. (Note that this is a * highly subobtimal bcopy(); in the unlikely event that this becomes * a serious performance issue, a high-performance DTrace-specific * bcopy() should obviously be invented.) */ daddr = (uintptr_t)dest->dtb_tomax + offs; dlimit = daddr + src->dtb_offset; saddr = (uintptr_t)src->dtb_tomax; /* * First, the aligned portion. */ while (dlimit - daddr >= sizeof (uint64_t)) { *((uint64_t *)daddr) = *((uint64_t *)saddr); daddr += sizeof (uint64_t); saddr += sizeof (uint64_t); } /* * Now any left-over bit... */ while (dlimit - daddr) *((uint8_t *)daddr++) = *((uint8_t *)saddr++); /* * Finally, commit the reserved space in the destination buffer. */ dest->dtb_offset = offs + src->dtb_offset; out: /* * If we're lucky enough to be the only active CPU on this speculation * buffer, we can just set the state back to DTRACESPEC_INACTIVE. */ if (current == DTRACESPEC_ACTIVE || (current == DTRACESPEC_ACTIVEONE && new == DTRACESPEC_COMMITTING)) { uint32_t rval = dtrace_cas32((uint32_t *)&spec->dtsp_state, DTRACESPEC_COMMITTING, DTRACESPEC_INACTIVE); ASSERT(rval == DTRACESPEC_COMMITTING); } src->dtb_offset = 0; src->dtb_xamot_drops += src->dtb_drops; src->dtb_drops = 0; } /* * This routine discards an active speculation. If the specified speculation * is not in a valid state to perform a discard(), this routine will silently * do nothing. The state of the specified speculation is transitioned * according to the state transition diagram outlined in */ static void dtrace_speculation_discard(dtrace_state_t *state, processorid_t cpu, dtrace_specid_t which) { dtrace_speculation_t *spec; dtrace_speculation_state_t current, new = 0; dtrace_buffer_t *buf; if (which == 0) return; if (which > state->dts_nspeculations) { cpu_core[cpu].cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; return; } spec = &state->dts_speculations[which - 1]; buf = &spec->dtsp_buffer[cpu]; do { current = spec->dtsp_state; switch (current) { case DTRACESPEC_INACTIVE: case DTRACESPEC_COMMITTINGMANY: case DTRACESPEC_COMMITTING: case DTRACESPEC_DISCARDING: return; case DTRACESPEC_ACTIVE: case DTRACESPEC_ACTIVEMANY: new = DTRACESPEC_DISCARDING; break; case DTRACESPEC_ACTIVEONE: if (buf->dtb_offset != 0) { new = DTRACESPEC_INACTIVE; } else { new = DTRACESPEC_DISCARDING; } break; default: ASSERT(0); } } while (dtrace_cas32((uint32_t *)&spec->dtsp_state, current, new) != current); buf->dtb_offset = 0; buf->dtb_drops = 0; } /* * Note: not called from probe context. This function is called * asynchronously from cross call context to clean any speculations that are * in the COMMITTINGMANY or DISCARDING states. These speculations may not be * transitioned back to the INACTIVE state until all CPUs have cleaned the * speculation. */ static void dtrace_speculation_clean_here(dtrace_state_t *state) { dtrace_icookie_t cookie; processorid_t cpu = curcpu; dtrace_buffer_t *dest = &state->dts_buffer[cpu]; dtrace_specid_t i; cookie = dtrace_interrupt_disable(); if (dest->dtb_tomax == NULL) { dtrace_interrupt_enable(cookie); return; } for (i = 0; i < state->dts_nspeculations; i++) { dtrace_speculation_t *spec = &state->dts_speculations[i]; dtrace_buffer_t *src = &spec->dtsp_buffer[cpu]; if (src->dtb_tomax == NULL) continue; if (spec->dtsp_state == DTRACESPEC_DISCARDING) { src->dtb_offset = 0; continue; } if (spec->dtsp_state != DTRACESPEC_COMMITTINGMANY) continue; if (src->dtb_offset == 0) continue; dtrace_speculation_commit(state, cpu, i + 1); } dtrace_interrupt_enable(cookie); } /* * Note: not called from probe context. This function is called * asynchronously (and at a regular interval) to clean any speculations that * are in the COMMITTINGMANY or DISCARDING states. If it discovers that there * is work to be done, it cross calls all CPUs to perform that work; * COMMITMANY and DISCARDING speculations may not be transitioned back to the * INACTIVE state until they have been cleaned by all CPUs. */ static void dtrace_speculation_clean(dtrace_state_t *state) { int work = 0, rv; dtrace_specid_t i; for (i = 0; i < state->dts_nspeculations; i++) { dtrace_speculation_t *spec = &state->dts_speculations[i]; ASSERT(!spec->dtsp_cleaning); if (spec->dtsp_state != DTRACESPEC_DISCARDING && spec->dtsp_state != DTRACESPEC_COMMITTINGMANY) continue; work++; spec->dtsp_cleaning = 1; } if (!work) return; dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_speculation_clean_here, state); /* * We now know that all CPUs have committed or discarded their * speculation buffers, as appropriate. We can now set the state * to inactive. */ for (i = 0; i < state->dts_nspeculations; i++) { dtrace_speculation_t *spec = &state->dts_speculations[i]; dtrace_speculation_state_t current, new; if (!spec->dtsp_cleaning) continue; current = spec->dtsp_state; ASSERT(current == DTRACESPEC_DISCARDING || current == DTRACESPEC_COMMITTINGMANY); new = DTRACESPEC_INACTIVE; rv = dtrace_cas32((uint32_t *)&spec->dtsp_state, current, new); ASSERT(rv == current); spec->dtsp_cleaning = 0; } } /* * Called as part of a speculate() to get the speculative buffer associated * with a given speculation. Returns NULL if the specified speculation is not * in an ACTIVE state. If the speculation is in the ACTIVEONE state -- and * the active CPU is not the specified CPU -- the speculation will be * atomically transitioned into the ACTIVEMANY state. */ static dtrace_buffer_t * dtrace_speculation_buffer(dtrace_state_t *state, processorid_t cpuid, dtrace_specid_t which) { dtrace_speculation_t *spec; dtrace_speculation_state_t current, new = 0; dtrace_buffer_t *buf; if (which == 0) return (NULL); if (which > state->dts_nspeculations) { cpu_core[cpuid].cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; return (NULL); } spec = &state->dts_speculations[which - 1]; buf = &spec->dtsp_buffer[cpuid]; do { current = spec->dtsp_state; switch (current) { case DTRACESPEC_INACTIVE: case DTRACESPEC_COMMITTINGMANY: case DTRACESPEC_DISCARDING: return (NULL); case DTRACESPEC_COMMITTING: ASSERT(buf->dtb_offset == 0); return (NULL); case DTRACESPEC_ACTIVEONE: /* * This speculation is currently active on one CPU. * Check the offset in the buffer; if it's non-zero, * that CPU must be us (and we leave the state alone). * If it's zero, assume that we're starting on a new * CPU -- and change the state to indicate that the * speculation is active on more than one CPU. */ if (buf->dtb_offset != 0) return (buf); new = DTRACESPEC_ACTIVEMANY; break; case DTRACESPEC_ACTIVEMANY: return (buf); case DTRACESPEC_ACTIVE: new = DTRACESPEC_ACTIVEONE; break; default: ASSERT(0); } } while (dtrace_cas32((uint32_t *)&spec->dtsp_state, current, new) != current); ASSERT(new == DTRACESPEC_ACTIVEONE || new == DTRACESPEC_ACTIVEMANY); return (buf); } /* * Return a string. In the event that the user lacks the privilege to access * arbitrary kernel memory, we copy the string out to scratch memory so that we * don't fail access checking. * * dtrace_dif_variable() uses this routine as a helper for various * builtin values such as 'execname' and 'probefunc.' */ uintptr_t dtrace_dif_varstr(uintptr_t addr, dtrace_state_t *state, dtrace_mstate_t *mstate) { uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; uintptr_t ret; size_t strsz; /* * The easy case: this probe is allowed to read all of memory, so * we can just return this as a vanilla pointer. */ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) return (addr); /* * This is the tougher case: we copy the string in question from * kernel memory into scratch memory and return it that way: this * ensures that we won't trip up when access checking tests the * BYREF return value. */ strsz = dtrace_strlen((char *)addr, size) + 1; if (mstate->dtms_scratch_ptr + strsz > mstate->dtms_scratch_base + mstate->dtms_scratch_size) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); return (0); } dtrace_strcpy((const void *)addr, (void *)mstate->dtms_scratch_ptr, strsz); ret = mstate->dtms_scratch_ptr; mstate->dtms_scratch_ptr += strsz; return (ret); } /* * Return a string from a memoy address which is known to have one or * more concatenated, individually zero terminated, sub-strings. * In the event that the user lacks the privilege to access * arbitrary kernel memory, we copy the string out to scratch memory so that we * don't fail access checking. * * dtrace_dif_variable() uses this routine as a helper for various * builtin values such as 'execargs'. */ static uintptr_t dtrace_dif_varstrz(uintptr_t addr, size_t strsz, dtrace_state_t *state, dtrace_mstate_t *mstate) { char *p; size_t i; uintptr_t ret; if (mstate->dtms_scratch_ptr + strsz > mstate->dtms_scratch_base + mstate->dtms_scratch_size) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); return (0); } dtrace_bcopy((const void *)addr, (void *)mstate->dtms_scratch_ptr, strsz); /* Replace sub-string termination characters with a space. */ for (p = (char *) mstate->dtms_scratch_ptr, i = 0; i < strsz - 1; p++, i++) if (*p == '\0') *p = ' '; ret = mstate->dtms_scratch_ptr; mstate->dtms_scratch_ptr += strsz; return (ret); } /* * This function implements the DIF emulator's variable lookups. The emulator * passes a reserved variable identifier and optional built-in array index. */ static uint64_t dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, uint64_t ndx) { /* * If we're accessing one of the uncached arguments, we'll turn this * into a reference in the args array. */ if (v >= DIF_VAR_ARG0 && v <= DIF_VAR_ARG9) { ndx = v - DIF_VAR_ARG0; v = DIF_VAR_ARGS; } switch (v) { case DIF_VAR_ARGS: ASSERT(mstate->dtms_present & DTRACE_MSTATE_ARGS); if (ndx >= sizeof (mstate->dtms_arg) / sizeof (mstate->dtms_arg[0])) { int aframes = mstate->dtms_probe->dtpr_aframes + 2; dtrace_provider_t *pv; uint64_t val; pv = mstate->dtms_probe->dtpr_provider; if (pv->dtpv_pops.dtps_getargval != NULL) val = pv->dtpv_pops.dtps_getargval(pv->dtpv_arg, mstate->dtms_probe->dtpr_id, mstate->dtms_probe->dtpr_arg, ndx, aframes); else val = dtrace_getarg(ndx, aframes); /* * This is regrettably required to keep the compiler * from tail-optimizing the call to dtrace_getarg(). * The condition always evaluates to true, but the * compiler has no way of figuring that out a priori. * (None of this would be necessary if the compiler * could be relied upon to _always_ tail-optimize * the call to dtrace_getarg() -- but it can't.) */ if (mstate->dtms_probe != NULL) return (val); ASSERT(0); } return (mstate->dtms_arg[ndx]); #ifdef illumos case DIF_VAR_UREGS: { klwp_t *lwp; if (!dtrace_priv_proc(state)) return (0); if ((lwp = curthread->t_lwp) == NULL) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = NULL; return (0); } return (dtrace_getreg(lwp->lwp_regs, ndx)); return (0); } #else case DIF_VAR_UREGS: { struct trapframe *tframe; if (!dtrace_priv_proc(state)) return (0); if ((tframe = curthread->td_frame) == NULL) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = 0; return (0); } return (dtrace_getreg(tframe, ndx)); } #endif case DIF_VAR_CURTHREAD: if (!dtrace_priv_proc(state)) return (0); return ((uint64_t)(uintptr_t)curthread); case DIF_VAR_TIMESTAMP: if (!(mstate->dtms_present & DTRACE_MSTATE_TIMESTAMP)) { mstate->dtms_timestamp = dtrace_gethrtime(); mstate->dtms_present |= DTRACE_MSTATE_TIMESTAMP; } return (mstate->dtms_timestamp); case DIF_VAR_VTIMESTAMP: ASSERT(dtrace_vtime_references != 0); return (curthread->t_dtrace_vtime); case DIF_VAR_WALLTIMESTAMP: if (!(mstate->dtms_present & DTRACE_MSTATE_WALLTIMESTAMP)) { mstate->dtms_walltimestamp = dtrace_gethrestime(); mstate->dtms_present |= DTRACE_MSTATE_WALLTIMESTAMP; } return (mstate->dtms_walltimestamp); #ifdef illumos case DIF_VAR_IPL: if (!dtrace_priv_kernel(state)) return (0); if (!(mstate->dtms_present & DTRACE_MSTATE_IPL)) { mstate->dtms_ipl = dtrace_getipl(); mstate->dtms_present |= DTRACE_MSTATE_IPL; } return (mstate->dtms_ipl); #endif case DIF_VAR_EPID: ASSERT(mstate->dtms_present & DTRACE_MSTATE_EPID); return (mstate->dtms_epid); case DIF_VAR_ID: ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); return (mstate->dtms_probe->dtpr_id); case DIF_VAR_STACKDEPTH: if (!dtrace_priv_kernel(state)) return (0); if (!(mstate->dtms_present & DTRACE_MSTATE_STACKDEPTH)) { int aframes = mstate->dtms_probe->dtpr_aframes + 2; mstate->dtms_stackdepth = dtrace_getstackdepth(aframes); mstate->dtms_present |= DTRACE_MSTATE_STACKDEPTH; } return (mstate->dtms_stackdepth); case DIF_VAR_USTACKDEPTH: if (!dtrace_priv_proc(state)) return (0); if (!(mstate->dtms_present & DTRACE_MSTATE_USTACKDEPTH)) { /* * See comment in DIF_VAR_PID. */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) { mstate->dtms_ustackdepth = 0; } else { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); mstate->dtms_ustackdepth = dtrace_getustackdepth(); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); } mstate->dtms_present |= DTRACE_MSTATE_USTACKDEPTH; } return (mstate->dtms_ustackdepth); case DIF_VAR_CALLER: if (!dtrace_priv_kernel(state)) return (0); if (!(mstate->dtms_present & DTRACE_MSTATE_CALLER)) { int aframes = mstate->dtms_probe->dtpr_aframes + 2; if (!DTRACE_ANCHORED(mstate->dtms_probe)) { /* * If this is an unanchored probe, we are * required to go through the slow path: * dtrace_caller() only guarantees correct * results for anchored probes. */ pc_t caller[2] = {0, 0}; dtrace_getpcstack(caller, 2, aframes, (uint32_t *)(uintptr_t)mstate->dtms_arg[0]); mstate->dtms_caller = caller[1]; } else if ((mstate->dtms_caller = dtrace_caller(aframes)) == -1) { /* * We have failed to do this the quick way; * we must resort to the slower approach of * calling dtrace_getpcstack(). */ pc_t caller = 0; dtrace_getpcstack(&caller, 1, aframes, NULL); mstate->dtms_caller = caller; } mstate->dtms_present |= DTRACE_MSTATE_CALLER; } return (mstate->dtms_caller); case DIF_VAR_UCALLER: if (!dtrace_priv_proc(state)) return (0); if (!(mstate->dtms_present & DTRACE_MSTATE_UCALLER)) { uint64_t ustack[3]; /* * dtrace_getupcstack() fills in the first uint64_t * with the current PID. The second uint64_t will * be the program counter at user-level. The third * uint64_t will contain the caller, which is what * we're after. */ ustack[2] = 0; DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_getupcstack(ustack, 3); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); mstate->dtms_ucaller = ustack[2]; mstate->dtms_present |= DTRACE_MSTATE_UCALLER; } return (mstate->dtms_ucaller); case DIF_VAR_PROBEPROV: ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); return (dtrace_dif_varstr( (uintptr_t)mstate->dtms_probe->dtpr_provider->dtpv_name, state, mstate)); case DIF_VAR_PROBEMOD: ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); return (dtrace_dif_varstr( (uintptr_t)mstate->dtms_probe->dtpr_mod, state, mstate)); case DIF_VAR_PROBEFUNC: ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); return (dtrace_dif_varstr( (uintptr_t)mstate->dtms_probe->dtpr_func, state, mstate)); case DIF_VAR_PROBENAME: ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); return (dtrace_dif_varstr( (uintptr_t)mstate->dtms_probe->dtpr_name, state, mstate)); case DIF_VAR_PID: if (!dtrace_priv_proc(state)) return (0); #ifdef illumos /* * Note that we are assuming that an unanchored probe is * always due to a high-level interrupt. (And we're assuming * that there is only a single high level interrupt.) */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return (pid0.pid_id); /* * It is always safe to dereference one's own t_procp pointer: * it always points to a valid, allocated proc structure. * Further, it is always safe to dereference the p_pidp member * of one's own proc structure. (These are truisms becuase * threads and processes don't clean up their own state -- * they leave that task to whomever reaps them.) */ return ((uint64_t)curthread->t_procp->p_pidp->pid_id); #else return ((uint64_t)curproc->p_pid); #endif case DIF_VAR_PPID: if (!dtrace_priv_proc(state)) return (0); #ifdef illumos /* * See comment in DIF_VAR_PID. */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return (pid0.pid_id); /* * It is always safe to dereference one's own t_procp pointer: * it always points to a valid, allocated proc structure. * (This is true because threads don't clean up their own * state -- they leave that task to whomever reaps them.) */ return ((uint64_t)curthread->t_procp->p_ppid); #else if (curproc->p_pid == proc0.p_pid) return (curproc->p_pid); else return (curproc->p_pptr->p_pid); #endif case DIF_VAR_TID: #ifdef illumos /* * See comment in DIF_VAR_PID. */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return (0); #endif return ((uint64_t)curthread->t_tid); case DIF_VAR_EXECARGS: { struct pargs *p_args = curthread->td_proc->p_args; if (p_args == NULL) return(0); return (dtrace_dif_varstrz( (uintptr_t) p_args->ar_args, p_args->ar_length, state, mstate)); } case DIF_VAR_EXECNAME: #ifdef illumos if (!dtrace_priv_proc(state)) return (0); /* * See comment in DIF_VAR_PID. */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return ((uint64_t)(uintptr_t)p0.p_user.u_comm); /* * It is always safe to dereference one's own t_procp pointer: * it always points to a valid, allocated proc structure. * (This is true because threads don't clean up their own * state -- they leave that task to whomever reaps them.) */ return (dtrace_dif_varstr( (uintptr_t)curthread->t_procp->p_user.u_comm, state, mstate)); #else return (dtrace_dif_varstr( (uintptr_t) curthread->td_proc->p_comm, state, mstate)); #endif case DIF_VAR_ZONENAME: #ifdef illumos if (!dtrace_priv_proc(state)) return (0); /* * See comment in DIF_VAR_PID. */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return ((uint64_t)(uintptr_t)p0.p_zone->zone_name); /* * It is always safe to dereference one's own t_procp pointer: * it always points to a valid, allocated proc structure. * (This is true because threads don't clean up their own * state -- they leave that task to whomever reaps them.) */ return (dtrace_dif_varstr( (uintptr_t)curthread->t_procp->p_zone->zone_name, state, mstate)); #else return (0); #endif case DIF_VAR_UID: if (!dtrace_priv_proc(state)) return (0); #ifdef illumos /* * See comment in DIF_VAR_PID. */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return ((uint64_t)p0.p_cred->cr_uid); /* * It is always safe to dereference one's own t_procp pointer: * it always points to a valid, allocated proc structure. * (This is true because threads don't clean up their own * state -- they leave that task to whomever reaps them.) * * Additionally, it is safe to dereference one's own process * credential, since this is never NULL after process birth. */ return ((uint64_t)curthread->t_procp->p_cred->cr_uid); #else return ((uint64_t)curthread->td_ucred->cr_uid); #endif case DIF_VAR_GID: if (!dtrace_priv_proc(state)) return (0); #ifdef illumos /* * See comment in DIF_VAR_PID. */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return ((uint64_t)p0.p_cred->cr_gid); /* * It is always safe to dereference one's own t_procp pointer: * it always points to a valid, allocated proc structure. * (This is true because threads don't clean up their own * state -- they leave that task to whomever reaps them.) * * Additionally, it is safe to dereference one's own process * credential, since this is never NULL after process birth. */ return ((uint64_t)curthread->t_procp->p_cred->cr_gid); #else return ((uint64_t)curthread->td_ucred->cr_gid); #endif case DIF_VAR_ERRNO: { #ifdef illumos klwp_t *lwp; if (!dtrace_priv_proc(state)) return (0); /* * See comment in DIF_VAR_PID. */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return (0); /* * It is always safe to dereference one's own t_lwp pointer in * the event that this pointer is non-NULL. (This is true * because threads and lwps don't clean up their own state -- * they leave that task to whomever reaps them.) */ if ((lwp = curthread->t_lwp) == NULL) return (0); return ((uint64_t)lwp->lwp_errno); #else return (curthread->td_errno); #endif } #ifndef illumos case DIF_VAR_CPU: { return curcpu; } #endif default: DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } } typedef enum dtrace_json_state { DTRACE_JSON_REST = 1, DTRACE_JSON_OBJECT, DTRACE_JSON_STRING, DTRACE_JSON_STRING_ESCAPE, DTRACE_JSON_STRING_ESCAPE_UNICODE, DTRACE_JSON_COLON, DTRACE_JSON_COMMA, DTRACE_JSON_VALUE, DTRACE_JSON_IDENTIFIER, DTRACE_JSON_NUMBER, DTRACE_JSON_NUMBER_FRAC, DTRACE_JSON_NUMBER_EXP, DTRACE_JSON_COLLECT_OBJECT } dtrace_json_state_t; /* * This function possesses just enough knowledge about JSON to extract a single * value from a JSON string and store it in the scratch buffer. It is able * to extract nested object values, and members of arrays by index. * * elemlist is a list of JSON keys, stored as packed NUL-terminated strings, to * be looked up as we descend into the object tree. e.g. * * foo[0].bar.baz[32] --> "foo" NUL "0" NUL "bar" NUL "baz" NUL "32" NUL * with nelems = 5. * * The run time of this function must be bounded above by strsize to limit the * amount of work done in probe context. As such, it is implemented as a * simple state machine, reading one character at a time using safe loads * until we find the requested element, hit a parsing error or run off the * end of the object or string. * * As there is no way for a subroutine to return an error without interrupting * clause execution, we simply return NULL in the event of a missing key or any * other error condition. Each NULL return in this function is commented with * the error condition it represents -- parsing or otherwise. * * The set of states for the state machine closely matches the JSON * specification (http://json.org/). Briefly: * * DTRACE_JSON_REST: * Skip whitespace until we find either a top-level Object, moving * to DTRACE_JSON_OBJECT; or an Array, moving to DTRACE_JSON_VALUE. * * DTRACE_JSON_OBJECT: * Locate the next key String in an Object. Sets a flag to denote * the next String as a key string and moves to DTRACE_JSON_STRING. * * DTRACE_JSON_COLON: * Skip whitespace until we find the colon that separates key Strings * from their values. Once found, move to DTRACE_JSON_VALUE. * * DTRACE_JSON_VALUE: * Detects the type of the next value (String, Number, Identifier, Object * or Array) and routes to the states that process that type. Here we also * deal with the element selector list if we are requested to traverse down * into the object tree. * * DTRACE_JSON_COMMA: * Skip whitespace until we find the comma that separates key-value pairs * in Objects (returning to DTRACE_JSON_OBJECT) or values in Arrays * (similarly DTRACE_JSON_VALUE). All following literal value processing * states return to this state at the end of their value, unless otherwise * noted. * * DTRACE_JSON_NUMBER, DTRACE_JSON_NUMBER_FRAC, DTRACE_JSON_NUMBER_EXP: * Processes a Number literal from the JSON, including any exponent * component that may be present. Numbers are returned as strings, which * may be passed to strtoll() if an integer is required. * * DTRACE_JSON_IDENTIFIER: * Processes a "true", "false" or "null" literal in the JSON. * * DTRACE_JSON_STRING, DTRACE_JSON_STRING_ESCAPE, * DTRACE_JSON_STRING_ESCAPE_UNICODE: * Processes a String literal from the JSON, whether the String denotes * a key, a value or part of a larger Object. Handles all escape sequences * present in the specification, including four-digit unicode characters, * but merely includes the escape sequence without converting it to the * actual escaped character. If the String is flagged as a key, we * move to DTRACE_JSON_COLON rather than DTRACE_JSON_COMMA. * * DTRACE_JSON_COLLECT_OBJECT: * This state collects an entire Object (or Array), correctly handling * embedded strings. If the full element selector list matches this nested * object, we return the Object in full as a string. If not, we use this * state to skip to the next value at this level and continue processing. * * NOTE: This function uses various macros from strtolctype.h to manipulate * digit values, etc -- these have all been checked to ensure they make * no additional function calls. */ static char * dtrace_json(uint64_t size, uintptr_t json, char *elemlist, int nelems, char *dest) { dtrace_json_state_t state = DTRACE_JSON_REST; int64_t array_elem = INT64_MIN; int64_t array_pos = 0; uint8_t escape_unicount = 0; boolean_t string_is_key = B_FALSE; boolean_t collect_object = B_FALSE; boolean_t found_key = B_FALSE; boolean_t in_array = B_FALSE; uint32_t braces = 0, brackets = 0; char *elem = elemlist; char *dd = dest; uintptr_t cur; for (cur = json; cur < json + size; cur++) { char cc = dtrace_load8(cur); if (cc == '\0') return (NULL); switch (state) { case DTRACE_JSON_REST: if (isspace(cc)) break; if (cc == '{') { state = DTRACE_JSON_OBJECT; break; } if (cc == '[') { in_array = B_TRUE; array_pos = 0; array_elem = dtrace_strtoll(elem, 10, size); found_key = array_elem == 0 ? B_TRUE : B_FALSE; state = DTRACE_JSON_VALUE; break; } /* * ERROR: expected to find a top-level object or array. */ return (NULL); case DTRACE_JSON_OBJECT: if (isspace(cc)) break; if (cc == '"') { state = DTRACE_JSON_STRING; string_is_key = B_TRUE; break; } /* * ERROR: either the object did not start with a key * string, or we've run off the end of the object * without finding the requested key. */ return (NULL); case DTRACE_JSON_STRING: if (cc == '\\') { *dd++ = '\\'; state = DTRACE_JSON_STRING_ESCAPE; break; } if (cc == '"') { if (collect_object) { /* * We don't reset the dest here, as * the string is part of a larger * object being collected. */ *dd++ = cc; collect_object = B_FALSE; state = DTRACE_JSON_COLLECT_OBJECT; break; } *dd = '\0'; dd = dest; /* reset string buffer */ if (string_is_key) { if (dtrace_strncmp(dest, elem, size) == 0) found_key = B_TRUE; } else if (found_key) { if (nelems > 1) { /* * We expected an object, not * this string. */ return (NULL); } return (dest); } state = string_is_key ? DTRACE_JSON_COLON : DTRACE_JSON_COMMA; string_is_key = B_FALSE; break; } *dd++ = cc; break; case DTRACE_JSON_STRING_ESCAPE: *dd++ = cc; if (cc == 'u') { escape_unicount = 0; state = DTRACE_JSON_STRING_ESCAPE_UNICODE; } else { state = DTRACE_JSON_STRING; } break; case DTRACE_JSON_STRING_ESCAPE_UNICODE: if (!isxdigit(cc)) { /* * ERROR: invalid unicode escape, expected * four valid hexidecimal digits. */ return (NULL); } *dd++ = cc; if (++escape_unicount == 4) state = DTRACE_JSON_STRING; break; case DTRACE_JSON_COLON: if (isspace(cc)) break; if (cc == ':') { state = DTRACE_JSON_VALUE; break; } /* * ERROR: expected a colon. */ return (NULL); case DTRACE_JSON_COMMA: if (isspace(cc)) break; if (cc == ',') { if (in_array) { state = DTRACE_JSON_VALUE; if (++array_pos == array_elem) found_key = B_TRUE; } else { state = DTRACE_JSON_OBJECT; } break; } /* * ERROR: either we hit an unexpected character, or * we reached the end of the object or array without * finding the requested key. */ return (NULL); case DTRACE_JSON_IDENTIFIER: if (islower(cc)) { *dd++ = cc; break; } *dd = '\0'; dd = dest; /* reset string buffer */ if (dtrace_strncmp(dest, "true", 5) == 0 || dtrace_strncmp(dest, "false", 6) == 0 || dtrace_strncmp(dest, "null", 5) == 0) { if (found_key) { if (nelems > 1) { /* * ERROR: We expected an object, * not this identifier. */ return (NULL); } return (dest); } else { cur--; state = DTRACE_JSON_COMMA; break; } } /* * ERROR: we did not recognise the identifier as one * of those in the JSON specification. */ return (NULL); case DTRACE_JSON_NUMBER: if (cc == '.') { *dd++ = cc; state = DTRACE_JSON_NUMBER_FRAC; break; } if (cc == 'x' || cc == 'X') { /* * ERROR: specification explicitly excludes * hexidecimal or octal numbers. */ return (NULL); } /* FALLTHRU */ case DTRACE_JSON_NUMBER_FRAC: if (cc == 'e' || cc == 'E') { *dd++ = cc; state = DTRACE_JSON_NUMBER_EXP; break; } if (cc == '+' || cc == '-') { /* * ERROR: expect sign as part of exponent only. */ return (NULL); } /* FALLTHRU */ case DTRACE_JSON_NUMBER_EXP: if (isdigit(cc) || cc == '+' || cc == '-') { *dd++ = cc; break; } *dd = '\0'; dd = dest; /* reset string buffer */ if (found_key) { if (nelems > 1) { /* * ERROR: We expected an object, not * this number. */ return (NULL); } return (dest); } cur--; state = DTRACE_JSON_COMMA; break; case DTRACE_JSON_VALUE: if (isspace(cc)) break; if (cc == '{' || cc == '[') { if (nelems > 1 && found_key) { in_array = cc == '[' ? B_TRUE : B_FALSE; /* * If our element selector directs us * to descend into this nested object, * then move to the next selector * element in the list and restart the * state machine. */ while (*elem != '\0') elem++; elem++; /* skip the inter-element NUL */ nelems--; dd = dest; if (in_array) { state = DTRACE_JSON_VALUE; array_pos = 0; array_elem = dtrace_strtoll( elem, 10, size); found_key = array_elem == 0 ? B_TRUE : B_FALSE; } else { found_key = B_FALSE; state = DTRACE_JSON_OBJECT; } break; } /* * Otherwise, we wish to either skip this * nested object or return it in full. */ if (cc == '[') brackets = 1; else braces = 1; *dd++ = cc; state = DTRACE_JSON_COLLECT_OBJECT; break; } if (cc == '"') { state = DTRACE_JSON_STRING; break; } if (islower(cc)) { /* * Here we deal with true, false and null. */ *dd++ = cc; state = DTRACE_JSON_IDENTIFIER; break; } if (cc == '-' || isdigit(cc)) { *dd++ = cc; state = DTRACE_JSON_NUMBER; break; } /* * ERROR: unexpected character at start of value. */ return (NULL); case DTRACE_JSON_COLLECT_OBJECT: if (cc == '\0') /* * ERROR: unexpected end of input. */ return (NULL); *dd++ = cc; if (cc == '"') { collect_object = B_TRUE; state = DTRACE_JSON_STRING; break; } if (cc == ']') { if (brackets-- == 0) { /* * ERROR: unbalanced brackets. */ return (NULL); } } else if (cc == '}') { if (braces-- == 0) { /* * ERROR: unbalanced braces. */ return (NULL); } } else if (cc == '{') { braces++; } else if (cc == '[') { brackets++; } if (brackets == 0 && braces == 0) { if (found_key) { *dd = '\0'; return (dest); } dd = dest; /* reset string buffer */ state = DTRACE_JSON_COMMA; } break; } } return (NULL); } /* * Emulate the execution of DTrace ID subroutines invoked by the call opcode. * Notice that we don't bother validating the proper number of arguments or * their types in the tuple stack. This isn't needed because all argument * interpretation is safe because of our load safety -- the worst that can * happen is that a bogus program can obtain bogus results. */ static void dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, dtrace_key_t *tupregs, int nargs, dtrace_mstate_t *mstate, dtrace_state_t *state) { volatile uint16_t *flags = &cpu_core[curcpu].cpuc_dtrace_flags; volatile uintptr_t *illval = &cpu_core[curcpu].cpuc_dtrace_illval; dtrace_vstate_t *vstate = &state->dts_vstate; #ifdef illumos union { mutex_impl_t mi; uint64_t mx; } m; union { krwlock_t ri; uintptr_t rw; } r; #else struct thread *lowner; union { struct lock_object *li; uintptr_t lx; } l; #endif switch (subr) { case DIF_SUBR_RAND: regs[rd] = dtrace_xoroshiro128_plus_next( state->dts_rstate[curcpu]); break; #ifdef illumos case DIF_SUBR_MUTEX_OWNED: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (kmutex_t), mstate, vstate)) { regs[rd] = 0; break; } m.mx = dtrace_load64(tupregs[0].dttk_value); if (MUTEX_TYPE_ADAPTIVE(&m.mi)) regs[rd] = MUTEX_OWNER(&m.mi) != MUTEX_NO_OWNER; else regs[rd] = LOCK_HELD(&m.mi.m_spin.m_spinlock); break; case DIF_SUBR_MUTEX_OWNER: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (kmutex_t), mstate, vstate)) { regs[rd] = 0; break; } m.mx = dtrace_load64(tupregs[0].dttk_value); if (MUTEX_TYPE_ADAPTIVE(&m.mi) && MUTEX_OWNER(&m.mi) != MUTEX_NO_OWNER) regs[rd] = (uintptr_t)MUTEX_OWNER(&m.mi); else regs[rd] = 0; break; case DIF_SUBR_MUTEX_TYPE_ADAPTIVE: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (kmutex_t), mstate, vstate)) { regs[rd] = 0; break; } m.mx = dtrace_load64(tupregs[0].dttk_value); regs[rd] = MUTEX_TYPE_ADAPTIVE(&m.mi); break; case DIF_SUBR_MUTEX_TYPE_SPIN: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (kmutex_t), mstate, vstate)) { regs[rd] = 0; break; } m.mx = dtrace_load64(tupregs[0].dttk_value); regs[rd] = MUTEX_TYPE_SPIN(&m.mi); break; case DIF_SUBR_RW_READ_HELD: { uintptr_t tmp; if (!dtrace_canload(tupregs[0].dttk_value, sizeof (uintptr_t), mstate, vstate)) { regs[rd] = 0; break; } r.rw = dtrace_loadptr(tupregs[0].dttk_value); regs[rd] = _RW_READ_HELD(&r.ri, tmp); break; } case DIF_SUBR_RW_WRITE_HELD: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (krwlock_t), mstate, vstate)) { regs[rd] = 0; break; } r.rw = dtrace_loadptr(tupregs[0].dttk_value); regs[rd] = _RW_WRITE_HELD(&r.ri); break; case DIF_SUBR_RW_ISWRITER: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (krwlock_t), mstate, vstate)) { regs[rd] = 0; break; } r.rw = dtrace_loadptr(tupregs[0].dttk_value); regs[rd] = _RW_ISWRITER(&r.ri); break; #else /* !illumos */ case DIF_SUBR_MUTEX_OWNED: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (struct lock_object), mstate, vstate)) { regs[rd] = 0; break; } l.lx = dtrace_loadptr((uintptr_t)&tupregs[0].dttk_value); DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = LOCK_CLASS(l.li)->lc_owner(l.li, &lowner); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_SUBR_MUTEX_OWNER: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (struct lock_object), mstate, vstate)) { regs[rd] = 0; break; } l.lx = dtrace_loadptr((uintptr_t)&tupregs[0].dttk_value); DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); LOCK_CLASS(l.li)->lc_owner(l.li, &lowner); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); regs[rd] = (uintptr_t)lowner; break; case DIF_SUBR_MUTEX_TYPE_ADAPTIVE: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (struct mtx), mstate, vstate)) { regs[rd] = 0; break; } l.lx = dtrace_loadptr((uintptr_t)&tupregs[0].dttk_value); DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = (LOCK_CLASS(l.li)->lc_flags & LC_SLEEPLOCK) != 0; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_SUBR_MUTEX_TYPE_SPIN: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (struct mtx), mstate, vstate)) { regs[rd] = 0; break; } l.lx = dtrace_loadptr((uintptr_t)&tupregs[0].dttk_value); DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = (LOCK_CLASS(l.li)->lc_flags & LC_SPINLOCK) != 0; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_SUBR_RW_READ_HELD: case DIF_SUBR_SX_SHARED_HELD: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (uintptr_t), mstate, vstate)) { regs[rd] = 0; break; } l.lx = dtrace_loadptr((uintptr_t)&tupregs[0].dttk_value); DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = LOCK_CLASS(l.li)->lc_owner(l.li, &lowner) && lowner == NULL; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_SUBR_RW_WRITE_HELD: case DIF_SUBR_SX_EXCLUSIVE_HELD: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (uintptr_t), mstate, vstate)) { regs[rd] = 0; break; } l.lx = dtrace_loadptr(tupregs[0].dttk_value); DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = LOCK_CLASS(l.li)->lc_owner(l.li, &lowner) && lowner != NULL; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_SUBR_RW_ISWRITER: case DIF_SUBR_SX_ISEXCLUSIVE: if (!dtrace_canload(tupregs[0].dttk_value, sizeof (uintptr_t), mstate, vstate)) { regs[rd] = 0; break; } l.lx = dtrace_loadptr(tupregs[0].dttk_value); DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); LOCK_CLASS(l.li)->lc_owner(l.li, &lowner); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); regs[rd] = (lowner == curthread); break; #endif /* illumos */ case DIF_SUBR_BCOPY: { /* * We need to be sure that the destination is in the scratch * region -- no other region is allowed. */ uintptr_t src = tupregs[0].dttk_value; uintptr_t dest = tupregs[1].dttk_value; size_t size = tupregs[2].dttk_value; if (!dtrace_inscratch(dest, size, mstate)) { *flags |= CPU_DTRACE_BADADDR; *illval = regs[rd]; break; } if (!dtrace_canload(src, size, mstate, vstate)) { regs[rd] = 0; break; } dtrace_bcopy((void *)src, (void *)dest, size); break; } case DIF_SUBR_ALLOCA: case DIF_SUBR_COPYIN: { uintptr_t dest = P2ROUNDUP(mstate->dtms_scratch_ptr, 8); uint64_t size = tupregs[subr == DIF_SUBR_ALLOCA ? 0 : 1].dttk_value; size_t scratch_size = (dest - mstate->dtms_scratch_ptr) + size; /* * This action doesn't require any credential checks since * probes will not activate in user contexts to which the * enabling user does not have permissions. */ /* * Rounding up the user allocation size could have overflowed * a large, bogus allocation (like -1ULL) to 0. */ if (scratch_size < size || !DTRACE_INSCRATCH(mstate, scratch_size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } if (subr == DIF_SUBR_COPYIN) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_copyin(tupregs[0].dttk_value, dest, size, flags); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); } mstate->dtms_scratch_ptr += scratch_size; regs[rd] = dest; break; } case DIF_SUBR_COPYINTO: { uint64_t size = tupregs[1].dttk_value; uintptr_t dest = tupregs[2].dttk_value; /* * This action doesn't require any credential checks since * probes will not activate in user contexts to which the * enabling user does not have permissions. */ if (!dtrace_inscratch(dest, size, mstate)) { *flags |= CPU_DTRACE_BADADDR; *illval = regs[rd]; break; } DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_copyin(tupregs[0].dttk_value, dest, size, flags); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; } case DIF_SUBR_COPYINSTR: { uintptr_t dest = mstate->dtms_scratch_ptr; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; if (nargs > 1 && tupregs[1].dttk_value < size) size = tupregs[1].dttk_value + 1; /* * This action doesn't require any credential checks since * probes will not activate in user contexts to which the * enabling user does not have permissions. */ if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_copyinstr(tupregs[0].dttk_value, dest, size, flags); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); ((char *)dest)[size - 1] = '\0'; mstate->dtms_scratch_ptr += size; regs[rd] = dest; break; } #ifdef illumos case DIF_SUBR_MSGSIZE: case DIF_SUBR_MSGDSIZE: { uintptr_t baddr = tupregs[0].dttk_value, daddr; uintptr_t wptr, rptr; size_t count = 0; int cont = 0; while (baddr != 0 && !(*flags & CPU_DTRACE_FAULT)) { if (!dtrace_canload(baddr, sizeof (mblk_t), mstate, vstate)) { regs[rd] = 0; break; } wptr = dtrace_loadptr(baddr + offsetof(mblk_t, b_wptr)); rptr = dtrace_loadptr(baddr + offsetof(mblk_t, b_rptr)); if (wptr < rptr) { *flags |= CPU_DTRACE_BADADDR; *illval = tupregs[0].dttk_value; break; } daddr = dtrace_loadptr(baddr + offsetof(mblk_t, b_datap)); baddr = dtrace_loadptr(baddr + offsetof(mblk_t, b_cont)); /* * We want to prevent against denial-of-service here, * so we're only going to search the list for * dtrace_msgdsize_max mblks. */ if (cont++ > dtrace_msgdsize_max) { *flags |= CPU_DTRACE_ILLOP; break; } if (subr == DIF_SUBR_MSGDSIZE) { if (dtrace_load8(daddr + offsetof(dblk_t, db_type)) != M_DATA) continue; } count += wptr - rptr; } if (!(*flags & CPU_DTRACE_FAULT)) regs[rd] = count; break; } #endif case DIF_SUBR_PROGENYOF: { pid_t pid = tupregs[0].dttk_value; proc_t *p; int rval = 0; DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); for (p = curthread->t_procp; p != NULL; p = p->p_parent) { #ifdef illumos if (p->p_pidp->pid_id == pid) { #else if (p->p_pid == pid) { #endif rval = 1; break; } } DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); regs[rd] = rval; break; } case DIF_SUBR_SPECULATION: regs[rd] = dtrace_speculation(state); break; case DIF_SUBR_COPYOUT: { uintptr_t kaddr = tupregs[0].dttk_value; uintptr_t uaddr = tupregs[1].dttk_value; uint64_t size = tupregs[2].dttk_value; if (!dtrace_destructive_disallow && dtrace_priv_proc_control(state) && !dtrace_istoxic(kaddr, size) && dtrace_canload(kaddr, size, mstate, vstate)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_copyout(kaddr, uaddr, size, flags); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); } break; } case DIF_SUBR_COPYOUTSTR: { uintptr_t kaddr = tupregs[0].dttk_value; uintptr_t uaddr = tupregs[1].dttk_value; uint64_t size = tupregs[2].dttk_value; size_t lim; if (!dtrace_destructive_disallow && dtrace_priv_proc_control(state) && !dtrace_istoxic(kaddr, size) && dtrace_strcanload(kaddr, size, &lim, mstate, vstate)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_copyoutstr(kaddr, uaddr, lim, flags); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); } break; } case DIF_SUBR_STRLEN: { size_t size = state->dts_options[DTRACEOPT_STRSIZE]; uintptr_t addr = (uintptr_t)tupregs[0].dttk_value; size_t lim; if (!dtrace_strcanload(addr, size, &lim, mstate, vstate)) { regs[rd] = 0; break; } regs[rd] = dtrace_strlen((char *)addr, lim); break; } case DIF_SUBR_STRCHR: case DIF_SUBR_STRRCHR: { /* * We're going to iterate over the string looking for the * specified character. We will iterate until we have reached * the string length or we have found the character. If this * is DIF_SUBR_STRRCHR, we will look for the last occurrence * of the specified character instead of the first. */ uintptr_t addr = tupregs[0].dttk_value; uintptr_t addr_limit; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; size_t lim; char c, target = (char)tupregs[1].dttk_value; if (!dtrace_strcanload(addr, size, &lim, mstate, vstate)) { regs[rd] = 0; break; } addr_limit = addr + lim; for (regs[rd] = 0; addr < addr_limit; addr++) { if ((c = dtrace_load8(addr)) == target) { regs[rd] = addr; if (subr == DIF_SUBR_STRCHR) break; } if (c == '\0') break; } break; } case DIF_SUBR_STRSTR: case DIF_SUBR_INDEX: case DIF_SUBR_RINDEX: { /* * We're going to iterate over the string looking for the * specified string. We will iterate until we have reached * the string length or we have found the string. (Yes, this * is done in the most naive way possible -- but considering * that the string we're searching for is likely to be * relatively short, the complexity of Rabin-Karp or similar * hardly seems merited.) */ char *addr = (char *)(uintptr_t)tupregs[0].dttk_value; char *substr = (char *)(uintptr_t)tupregs[1].dttk_value; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; size_t len = dtrace_strlen(addr, size); size_t sublen = dtrace_strlen(substr, size); char *limit = addr + len, *orig = addr; int notfound = subr == DIF_SUBR_STRSTR ? 0 : -1; int inc = 1; regs[rd] = notfound; if (!dtrace_canload((uintptr_t)addr, len + 1, mstate, vstate)) { regs[rd] = 0; break; } if (!dtrace_canload((uintptr_t)substr, sublen + 1, mstate, vstate)) { regs[rd] = 0; break; } /* * strstr() and index()/rindex() have similar semantics if * both strings are the empty string: strstr() returns a * pointer to the (empty) string, and index() and rindex() * both return index 0 (regardless of any position argument). */ if (sublen == 0 && len == 0) { if (subr == DIF_SUBR_STRSTR) regs[rd] = (uintptr_t)addr; else regs[rd] = 0; break; } if (subr != DIF_SUBR_STRSTR) { if (subr == DIF_SUBR_RINDEX) { limit = orig - 1; addr += len; inc = -1; } /* * Both index() and rindex() take an optional position * argument that denotes the starting position. */ if (nargs == 3) { int64_t pos = (int64_t)tupregs[2].dttk_value; /* * If the position argument to index() is * negative, Perl implicitly clamps it at * zero. This semantic is a little surprising * given the special meaning of negative * positions to similar Perl functions like * substr(), but it appears to reflect a * notion that index() can start from a * negative index and increment its way up to * the string. Given this notion, Perl's * rindex() is at least self-consistent in * that it implicitly clamps positions greater * than the string length to be the string * length. Where Perl completely loses * coherence, however, is when the specified * substring is the empty string (""). In * this case, even if the position is * negative, rindex() returns 0 -- and even if * the position is greater than the length, * index() returns the string length. These * semantics violate the notion that index() * should never return a value less than the * specified position and that rindex() should * never return a value greater than the * specified position. (One assumes that * these semantics are artifacts of Perl's * implementation and not the results of * deliberate design -- it beggars belief that * even Larry Wall could desire such oddness.) * While in the abstract one would wish for * consistent position semantics across * substr(), index() and rindex() -- or at the * very least self-consistent position * semantics for index() and rindex() -- we * instead opt to keep with the extant Perl * semantics, in all their broken glory. (Do * we have more desire to maintain Perl's * semantics than Perl does? Probably.) */ if (subr == DIF_SUBR_RINDEX) { if (pos < 0) { if (sublen == 0) regs[rd] = 0; break; } if (pos > len) pos = len; } else { if (pos < 0) pos = 0; if (pos >= len) { if (sublen == 0) regs[rd] = len; break; } } addr = orig + pos; } } for (regs[rd] = notfound; addr != limit; addr += inc) { if (dtrace_strncmp(addr, substr, sublen) == 0) { if (subr != DIF_SUBR_STRSTR) { /* * As D index() and rindex() are * modeled on Perl (and not on awk), * we return a zero-based (and not a * one-based) index. (For you Perl * weenies: no, we're not going to add * $[ -- and shouldn't you be at a con * or something?) */ regs[rd] = (uintptr_t)(addr - orig); break; } ASSERT(subr == DIF_SUBR_STRSTR); regs[rd] = (uintptr_t)addr; break; } } break; } case DIF_SUBR_STRTOK: { uintptr_t addr = tupregs[0].dttk_value; uintptr_t tokaddr = tupregs[1].dttk_value; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; uintptr_t limit, toklimit; size_t clim; uint8_t c = 0, tokmap[32]; /* 256 / 8 */ char *dest = (char *)mstate->dtms_scratch_ptr; int i; /* * Check both the token buffer and (later) the input buffer, * since both could be non-scratch addresses. */ if (!dtrace_strcanload(tokaddr, size, &clim, mstate, vstate)) { regs[rd] = 0; break; } toklimit = tokaddr + clim; if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } if (addr == 0) { /* * If the address specified is NULL, we use our saved * strtok pointer from the mstate. Note that this * means that the saved strtok pointer is _only_ * valid within multiple enablings of the same probe -- * it behaves like an implicit clause-local variable. */ addr = mstate->dtms_strtok; limit = mstate->dtms_strtok_limit; } else { /* * If the user-specified address is non-NULL we must * access check it. This is the only time we have * a chance to do so, since this address may reside * in the string table of this clause-- future calls * (when we fetch addr from mstate->dtms_strtok) * would fail this access check. */ if (!dtrace_strcanload(addr, size, &clim, mstate, vstate)) { regs[rd] = 0; break; } limit = addr + clim; } /* * First, zero the token map, and then process the token * string -- setting a bit in the map for every character * found in the token string. */ for (i = 0; i < sizeof (tokmap); i++) tokmap[i] = 0; for (; tokaddr < toklimit; tokaddr++) { if ((c = dtrace_load8(tokaddr)) == '\0') break; ASSERT((c >> 3) < sizeof (tokmap)); tokmap[c >> 3] |= (1 << (c & 0x7)); } for (; addr < limit; addr++) { /* * We're looking for a character that is _not_ * contained in the token string. */ if ((c = dtrace_load8(addr)) == '\0') break; if (!(tokmap[c >> 3] & (1 << (c & 0x7)))) break; } if (c == '\0') { /* * We reached the end of the string without finding * any character that was not in the token string. * We return NULL in this case, and we set the saved * address to NULL as well. */ regs[rd] = 0; mstate->dtms_strtok = 0; mstate->dtms_strtok_limit = 0; break; } /* * From here on, we're copying into the destination string. */ for (i = 0; addr < limit && i < size - 1; addr++) { if ((c = dtrace_load8(addr)) == '\0') break; if (tokmap[c >> 3] & (1 << (c & 0x7))) break; ASSERT(i < size); dest[i++] = c; } ASSERT(i < size); dest[i] = '\0'; regs[rd] = (uintptr_t)dest; mstate->dtms_scratch_ptr += size; mstate->dtms_strtok = addr; mstate->dtms_strtok_limit = limit; break; } case DIF_SUBR_SUBSTR: { uintptr_t s = tupregs[0].dttk_value; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; char *d = (char *)mstate->dtms_scratch_ptr; int64_t index = (int64_t)tupregs[1].dttk_value; int64_t remaining = (int64_t)tupregs[2].dttk_value; size_t len = dtrace_strlen((char *)s, size); int64_t i; if (!dtrace_canload(s, len + 1, mstate, vstate)) { regs[rd] = 0; break; } if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } if (nargs <= 2) remaining = (int64_t)size; if (index < 0) { index += len; if (index < 0 && index + remaining > 0) { remaining += index; index = 0; } } if (index >= len || index < 0) { remaining = 0; } else if (remaining < 0) { remaining += len - index; } else if (index + remaining > size) { remaining = size - index; } for (i = 0; i < remaining; i++) { if ((d[i] = dtrace_load8(s + index + i)) == '\0') break; } d[i] = '\0'; mstate->dtms_scratch_ptr += size; regs[rd] = (uintptr_t)d; break; } case DIF_SUBR_JSON: { uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; uintptr_t json = tupregs[0].dttk_value; size_t jsonlen = dtrace_strlen((char *)json, size); uintptr_t elem = tupregs[1].dttk_value; size_t elemlen = dtrace_strlen((char *)elem, size); char *dest = (char *)mstate->dtms_scratch_ptr; char *elemlist = (char *)mstate->dtms_scratch_ptr + jsonlen + 1; char *ee = elemlist; int nelems = 1; uintptr_t cur; if (!dtrace_canload(json, jsonlen + 1, mstate, vstate) || !dtrace_canload(elem, elemlen + 1, mstate, vstate)) { regs[rd] = 0; break; } if (!DTRACE_INSCRATCH(mstate, jsonlen + 1 + elemlen + 1)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } /* * Read the element selector and split it up into a packed list * of strings. */ for (cur = elem; cur < elem + elemlen; cur++) { char cc = dtrace_load8(cur); if (cur == elem && cc == '[') { /* * If the first element selector key is * actually an array index then ignore the * bracket. */ continue; } if (cc == ']') continue; if (cc == '.' || cc == '[') { nelems++; cc = '\0'; } *ee++ = cc; } *ee++ = '\0'; if ((regs[rd] = (uintptr_t)dtrace_json(size, json, elemlist, nelems, dest)) != 0) mstate->dtms_scratch_ptr += jsonlen + 1; break; } case DIF_SUBR_TOUPPER: case DIF_SUBR_TOLOWER: { uintptr_t s = tupregs[0].dttk_value; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; char *dest = (char *)mstate->dtms_scratch_ptr, c; size_t len = dtrace_strlen((char *)s, size); char lower, upper, convert; int64_t i; if (subr == DIF_SUBR_TOUPPER) { lower = 'a'; upper = 'z'; convert = 'A'; } else { lower = 'A'; upper = 'Z'; convert = 'a'; } if (!dtrace_canload(s, len + 1, mstate, vstate)) { regs[rd] = 0; break; } if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } for (i = 0; i < size - 1; i++) { if ((c = dtrace_load8(s + i)) == '\0') break; if (c >= lower && c <= upper) c = convert + (c - lower); dest[i] = c; } ASSERT(i < size); dest[i] = '\0'; regs[rd] = (uintptr_t)dest; mstate->dtms_scratch_ptr += size; break; } #ifdef illumos case DIF_SUBR_GETMAJOR: #ifdef _LP64 regs[rd] = (tupregs[0].dttk_value >> NBITSMINOR64) & MAXMAJ64; #else regs[rd] = (tupregs[0].dttk_value >> NBITSMINOR) & MAXMAJ; #endif break; case DIF_SUBR_GETMINOR: #ifdef _LP64 regs[rd] = tupregs[0].dttk_value & MAXMIN64; #else regs[rd] = tupregs[0].dttk_value & MAXMIN; #endif break; case DIF_SUBR_DDI_PATHNAME: { /* * This one is a galactic mess. We are going to roughly * emulate ddi_pathname(), but it's made more complicated * by the fact that we (a) want to include the minor name and * (b) must proceed iteratively instead of recursively. */ uintptr_t dest = mstate->dtms_scratch_ptr; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; char *start = (char *)dest, *end = start + size - 1; uintptr_t daddr = tupregs[0].dttk_value; int64_t minor = (int64_t)tupregs[1].dttk_value; char *s; int i, len, depth = 0; /* * Due to all the pointer jumping we do and context we must * rely upon, we just mandate that the user must have kernel * read privileges to use this routine. */ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) == 0) { *flags |= CPU_DTRACE_KPRIV; *illval = daddr; regs[rd] = 0; } if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } *end = '\0'; /* * We want to have a name for the minor. In order to do this, * we need to walk the minor list from the devinfo. We want * to be sure that we don't infinitely walk a circular list, * so we check for circularity by sending a scout pointer * ahead two elements for every element that we iterate over; * if the list is circular, these will ultimately point to the * same element. You may recognize this little trick as the * answer to a stupid interview question -- one that always * seems to be asked by those who had to have it laboriously * explained to them, and who can't even concisely describe * the conditions under which one would be forced to resort to * this technique. Needless to say, those conditions are * found here -- and probably only here. Is this the only use * of this infamous trick in shipping, production code? If it * isn't, it probably should be... */ if (minor != -1) { uintptr_t maddr = dtrace_loadptr(daddr + offsetof(struct dev_info, devi_minor)); uintptr_t next = offsetof(struct ddi_minor_data, next); uintptr_t name = offsetof(struct ddi_minor_data, d_minor) + offsetof(struct ddi_minor, name); uintptr_t dev = offsetof(struct ddi_minor_data, d_minor) + offsetof(struct ddi_minor, dev); uintptr_t scout; if (maddr != NULL) scout = dtrace_loadptr(maddr + next); while (maddr != NULL && !(*flags & CPU_DTRACE_FAULT)) { uint64_t m; #ifdef _LP64 m = dtrace_load64(maddr + dev) & MAXMIN64; #else m = dtrace_load32(maddr + dev) & MAXMIN; #endif if (m != minor) { maddr = dtrace_loadptr(maddr + next); if (scout == NULL) continue; scout = dtrace_loadptr(scout + next); if (scout == NULL) continue; scout = dtrace_loadptr(scout + next); if (scout == NULL) continue; if (scout == maddr) { *flags |= CPU_DTRACE_ILLOP; break; } continue; } /* * We have the minor data. Now we need to * copy the minor's name into the end of the * pathname. */ s = (char *)dtrace_loadptr(maddr + name); len = dtrace_strlen(s, size); if (*flags & CPU_DTRACE_FAULT) break; if (len != 0) { if ((end -= (len + 1)) < start) break; *end = ':'; } for (i = 1; i <= len; i++) end[i] = dtrace_load8((uintptr_t)s++); break; } } while (daddr != NULL && !(*flags & CPU_DTRACE_FAULT)) { ddi_node_state_t devi_state; devi_state = dtrace_load32(daddr + offsetof(struct dev_info, devi_node_state)); if (*flags & CPU_DTRACE_FAULT) break; if (devi_state >= DS_INITIALIZED) { s = (char *)dtrace_loadptr(daddr + offsetof(struct dev_info, devi_addr)); len = dtrace_strlen(s, size); if (*flags & CPU_DTRACE_FAULT) break; if (len != 0) { if ((end -= (len + 1)) < start) break; *end = '@'; } for (i = 1; i <= len; i++) end[i] = dtrace_load8((uintptr_t)s++); } /* * Now for the node name... */ s = (char *)dtrace_loadptr(daddr + offsetof(struct dev_info, devi_node_name)); daddr = dtrace_loadptr(daddr + offsetof(struct dev_info, devi_parent)); /* * If our parent is NULL (that is, if we're the root * node), we're going to use the special path * "devices". */ if (daddr == 0) s = "devices"; len = dtrace_strlen(s, size); if (*flags & CPU_DTRACE_FAULT) break; if ((end -= (len + 1)) < start) break; for (i = 1; i <= len; i++) end[i] = dtrace_load8((uintptr_t)s++); *end = '/'; if (depth++ > dtrace_devdepth_max) { *flags |= CPU_DTRACE_ILLOP; break; } } if (end < start) DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); if (daddr == 0) { regs[rd] = (uintptr_t)end; mstate->dtms_scratch_ptr += size; } break; } #endif case DIF_SUBR_STRJOIN: { char *d = (char *)mstate->dtms_scratch_ptr; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; uintptr_t s1 = tupregs[0].dttk_value; uintptr_t s2 = tupregs[1].dttk_value; int i = 0, j = 0; size_t lim1, lim2; char c; if (!dtrace_strcanload(s1, size, &lim1, mstate, vstate) || !dtrace_strcanload(s2, size, &lim2, mstate, vstate)) { regs[rd] = 0; break; } if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } for (;;) { if (i >= size) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } c = (i >= lim1) ? '\0' : dtrace_load8(s1++); if ((d[i++] = c) == '\0') { i--; break; } } for (;;) { if (i >= size) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } c = (j++ >= lim2) ? '\0' : dtrace_load8(s2++); if ((d[i++] = c) == '\0') break; } if (i < size) { mstate->dtms_scratch_ptr += i; regs[rd] = (uintptr_t)d; } break; } case DIF_SUBR_STRTOLL: { uintptr_t s = tupregs[0].dttk_value; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; size_t lim; int base = 10; if (nargs > 1) { if ((base = tupregs[1].dttk_value) <= 1 || base > ('z' - 'a' + 1) + ('9' - '0' + 1)) { *flags |= CPU_DTRACE_ILLOP; break; } } if (!dtrace_strcanload(s, size, &lim, mstate, vstate)) { regs[rd] = INT64_MIN; break; } regs[rd] = dtrace_strtoll((char *)s, base, lim); break; } case DIF_SUBR_LLTOSTR: { int64_t i = (int64_t)tupregs[0].dttk_value; uint64_t val, digit; uint64_t size = 65; /* enough room for 2^64 in binary */ char *end = (char *)mstate->dtms_scratch_ptr + size - 1; int base = 10; if (nargs > 1) { if ((base = tupregs[1].dttk_value) <= 1 || base > ('z' - 'a' + 1) + ('9' - '0' + 1)) { *flags |= CPU_DTRACE_ILLOP; break; } } val = (base == 10 && i < 0) ? i * -1 : i; if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } for (*end-- = '\0'; val; val /= base) { if ((digit = val % base) <= '9' - '0') { *end-- = '0' + digit; } else { *end-- = 'a' + (digit - ('9' - '0') - 1); } } if (i == 0 && base == 16) *end-- = '0'; if (base == 16) *end-- = 'x'; if (i == 0 || base == 8 || base == 16) *end-- = '0'; if (i < 0 && base == 10) *end-- = '-'; regs[rd] = (uintptr_t)end + 1; mstate->dtms_scratch_ptr += size; break; } case DIF_SUBR_HTONS: case DIF_SUBR_NTOHS: #if BYTE_ORDER == BIG_ENDIAN regs[rd] = (uint16_t)tupregs[0].dttk_value; #else regs[rd] = DT_BSWAP_16((uint16_t)tupregs[0].dttk_value); #endif break; case DIF_SUBR_HTONL: case DIF_SUBR_NTOHL: #if BYTE_ORDER == BIG_ENDIAN regs[rd] = (uint32_t)tupregs[0].dttk_value; #else regs[rd] = DT_BSWAP_32((uint32_t)tupregs[0].dttk_value); #endif break; case DIF_SUBR_HTONLL: case DIF_SUBR_NTOHLL: #if BYTE_ORDER == BIG_ENDIAN regs[rd] = (uint64_t)tupregs[0].dttk_value; #else regs[rd] = DT_BSWAP_64((uint64_t)tupregs[0].dttk_value); #endif break; case DIF_SUBR_DIRNAME: case DIF_SUBR_BASENAME: { char *dest = (char *)mstate->dtms_scratch_ptr; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; uintptr_t src = tupregs[0].dttk_value; int i, j, len = dtrace_strlen((char *)src, size); int lastbase = -1, firstbase = -1, lastdir = -1; int start, end; if (!dtrace_canload(src, len + 1, mstate, vstate)) { regs[rd] = 0; break; } if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } /* * The basename and dirname for a zero-length string is * defined to be "." */ if (len == 0) { len = 1; src = (uintptr_t)"."; } /* * Start from the back of the string, moving back toward the * front until we see a character that isn't a slash. That * character is the last character in the basename. */ for (i = len - 1; i >= 0; i--) { if (dtrace_load8(src + i) != '/') break; } if (i >= 0) lastbase = i; /* * Starting from the last character in the basename, move * towards the front until we find a slash. The character * that we processed immediately before that is the first * character in the basename. */ for (; i >= 0; i--) { if (dtrace_load8(src + i) == '/') break; } if (i >= 0) firstbase = i + 1; /* * Now keep going until we find a non-slash character. That * character is the last character in the dirname. */ for (; i >= 0; i--) { if (dtrace_load8(src + i) != '/') break; } if (i >= 0) lastdir = i; ASSERT(!(lastbase == -1 && firstbase != -1)); ASSERT(!(firstbase == -1 && lastdir != -1)); if (lastbase == -1) { /* * We didn't find a non-slash character. We know that * the length is non-zero, so the whole string must be * slashes. In either the dirname or the basename * case, we return '/'. */ ASSERT(firstbase == -1); firstbase = lastbase = lastdir = 0; } if (firstbase == -1) { /* * The entire string consists only of a basename * component. If we're looking for dirname, we need * to change our string to be just "."; if we're * looking for a basename, we'll just set the first * character of the basename to be 0. */ if (subr == DIF_SUBR_DIRNAME) { ASSERT(lastdir == -1); src = (uintptr_t)"."; lastdir = 0; } else { firstbase = 0; } } if (subr == DIF_SUBR_DIRNAME) { if (lastdir == -1) { /* * We know that we have a slash in the name -- * or lastdir would be set to 0, above. And * because lastdir is -1, we know that this * slash must be the first character. (That * is, the full string must be of the form * "/basename".) In this case, the last * character of the directory name is 0. */ lastdir = 0; } start = 0; end = lastdir; } else { ASSERT(subr == DIF_SUBR_BASENAME); ASSERT(firstbase != -1 && lastbase != -1); start = firstbase; end = lastbase; } for (i = start, j = 0; i <= end && j < size - 1; i++, j++) dest[j] = dtrace_load8(src + i); dest[j] = '\0'; regs[rd] = (uintptr_t)dest; mstate->dtms_scratch_ptr += size; break; } case DIF_SUBR_GETF: { uintptr_t fd = tupregs[0].dttk_value; struct filedesc *fdp; file_t *fp; if (!dtrace_priv_proc(state)) { regs[rd] = 0; break; } fdp = curproc->p_fd; FILEDESC_SLOCK(fdp); fp = fget_locked(fdp, fd); mstate->dtms_getf = fp; regs[rd] = (uintptr_t)fp; FILEDESC_SUNLOCK(fdp); break; } case DIF_SUBR_CLEANPATH: { char *dest = (char *)mstate->dtms_scratch_ptr, c; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; uintptr_t src = tupregs[0].dttk_value; size_t lim; int i = 0, j = 0; #ifdef illumos zone_t *z; #endif if (!dtrace_strcanload(src, size, &lim, mstate, vstate)) { regs[rd] = 0; break; } if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } /* * Move forward, loading each character. */ do { c = (i >= lim) ? '\0' : dtrace_load8(src + i++); next: if (j + 5 >= size) /* 5 = strlen("/..c\0") */ break; if (c != '/') { dest[j++] = c; continue; } c = (i >= lim) ? '\0' : dtrace_load8(src + i++); if (c == '/') { /* * We have two slashes -- we can just advance * to the next character. */ goto next; } if (c != '.') { /* * This is not "." and it's not ".." -- we can * just store the "/" and this character and * drive on. */ dest[j++] = '/'; dest[j++] = c; continue; } c = (i >= lim) ? '\0' : dtrace_load8(src + i++); if (c == '/') { /* * This is a "/./" component. We're not going * to store anything in the destination buffer; * we're just going to go to the next component. */ goto next; } if (c != '.') { /* * This is not ".." -- we can just store the * "/." and this character and continue * processing. */ dest[j++] = '/'; dest[j++] = '.'; dest[j++] = c; continue; } c = (i >= lim) ? '\0' : dtrace_load8(src + i++); if (c != '/' && c != '\0') { /* * This is not ".." -- it's "..[mumble]". * We'll store the "/.." and this character * and continue processing. */ dest[j++] = '/'; dest[j++] = '.'; dest[j++] = '.'; dest[j++] = c; continue; } /* * This is "/../" or "/..\0". We need to back up * our destination pointer until we find a "/". */ i--; while (j != 0 && dest[--j] != '/') continue; if (c == '\0') dest[++j] = '/'; } while (c != '\0'); dest[j] = '\0'; #ifdef illumos if (mstate->dtms_getf != NULL && !(mstate->dtms_access & DTRACE_ACCESS_KERNEL) && (z = state->dts_cred.dcr_cred->cr_zone) != kcred->cr_zone) { /* * If we've done a getf() as a part of this ECB and we * don't have kernel access (and we're not in the global * zone), check if the path we cleaned up begins with * the zone's root path, and trim it off if so. Note * that this is an output cleanliness issue, not a * security issue: knowing one's zone root path does * not enable privilege escalation. */ if (strstr(dest, z->zone_rootpath) == dest) dest += strlen(z->zone_rootpath) - 1; } #endif regs[rd] = (uintptr_t)dest; mstate->dtms_scratch_ptr += size; break; } case DIF_SUBR_INET_NTOA: case DIF_SUBR_INET_NTOA6: case DIF_SUBR_INET_NTOP: { size_t size; int af, argi, i; char *base, *end; if (subr == DIF_SUBR_INET_NTOP) { af = (int)tupregs[0].dttk_value; argi = 1; } else { af = subr == DIF_SUBR_INET_NTOA ? AF_INET: AF_INET6; argi = 0; } if (af == AF_INET) { ipaddr_t ip4; uint8_t *ptr8, val; if (!dtrace_canload(tupregs[argi].dttk_value, sizeof (ipaddr_t), mstate, vstate)) { regs[rd] = 0; break; } /* * Safely load the IPv4 address. */ ip4 = dtrace_load32(tupregs[argi].dttk_value); /* * Check an IPv4 string will fit in scratch. */ size = INET_ADDRSTRLEN; if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } base = (char *)mstate->dtms_scratch_ptr; end = (char *)mstate->dtms_scratch_ptr + size - 1; /* * Stringify as a dotted decimal quad. */ *end-- = '\0'; ptr8 = (uint8_t *)&ip4; for (i = 3; i >= 0; i--) { val = ptr8[i]; if (val == 0) { *end-- = '0'; } else { for (; val; val /= 10) { *end-- = '0' + (val % 10); } } if (i > 0) *end-- = '.'; } ASSERT(end + 1 >= base); } else if (af == AF_INET6) { struct in6_addr ip6; int firstzero, tryzero, numzero, v6end; uint16_t val; const char digits[] = "0123456789abcdef"; /* * Stringify using RFC 1884 convention 2 - 16 bit * hexadecimal values with a zero-run compression. * Lower case hexadecimal digits are used. * eg, fe80::214:4fff:fe0b:76c8. * The IPv4 embedded form is returned for inet_ntop, * just the IPv4 string is returned for inet_ntoa6. */ if (!dtrace_canload(tupregs[argi].dttk_value, sizeof (struct in6_addr), mstate, vstate)) { regs[rd] = 0; break; } /* * Safely load the IPv6 address. */ dtrace_bcopy( (void *)(uintptr_t)tupregs[argi].dttk_value, (void *)(uintptr_t)&ip6, sizeof (struct in6_addr)); /* * Check an IPv6 string will fit in scratch. */ size = INET6_ADDRSTRLEN; if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } base = (char *)mstate->dtms_scratch_ptr; end = (char *)mstate->dtms_scratch_ptr + size - 1; *end-- = '\0'; /* * Find the longest run of 16 bit zero values * for the single allowed zero compression - "::". */ firstzero = -1; tryzero = -1; numzero = 1; for (i = 0; i < sizeof (struct in6_addr); i++) { #ifdef illumos if (ip6._S6_un._S6_u8[i] == 0 && #else if (ip6.__u6_addr.__u6_addr8[i] == 0 && #endif tryzero == -1 && i % 2 == 0) { tryzero = i; continue; } if (tryzero != -1 && #ifdef illumos (ip6._S6_un._S6_u8[i] != 0 || #else (ip6.__u6_addr.__u6_addr8[i] != 0 || #endif i == sizeof (struct in6_addr) - 1)) { if (i - tryzero <= numzero) { tryzero = -1; continue; } firstzero = tryzero; numzero = i - i % 2 - tryzero; tryzero = -1; #ifdef illumos if (ip6._S6_un._S6_u8[i] == 0 && #else if (ip6.__u6_addr.__u6_addr8[i] == 0 && #endif i == sizeof (struct in6_addr) - 1) numzero += 2; } } ASSERT(firstzero + numzero <= sizeof (struct in6_addr)); /* * Check for an IPv4 embedded address. */ v6end = sizeof (struct in6_addr) - 2; if (IN6_IS_ADDR_V4MAPPED(&ip6) || IN6_IS_ADDR_V4COMPAT(&ip6)) { for (i = sizeof (struct in6_addr) - 1; i >= DTRACE_V4MAPPED_OFFSET; i--) { ASSERT(end >= base); #ifdef illumos val = ip6._S6_un._S6_u8[i]; #else val = ip6.__u6_addr.__u6_addr8[i]; #endif if (val == 0) { *end-- = '0'; } else { for (; val; val /= 10) { *end-- = '0' + val % 10; } } if (i > DTRACE_V4MAPPED_OFFSET) *end-- = '.'; } if (subr == DIF_SUBR_INET_NTOA6) goto inetout; /* * Set v6end to skip the IPv4 address that * we have already stringified. */ v6end = 10; } /* * Build the IPv6 string by working through the * address in reverse. */ for (i = v6end; i >= 0; i -= 2) { ASSERT(end >= base); if (i == firstzero + numzero - 2) { *end-- = ':'; *end-- = ':'; i -= numzero - 2; continue; } if (i < 14 && i != firstzero - 2) *end-- = ':'; #ifdef illumos val = (ip6._S6_un._S6_u8[i] << 8) + ip6._S6_un._S6_u8[i + 1]; #else val = (ip6.__u6_addr.__u6_addr8[i] << 8) + ip6.__u6_addr.__u6_addr8[i + 1]; #endif if (val == 0) { *end-- = '0'; } else { for (; val; val /= 16) { *end-- = digits[val % 16]; } } } ASSERT(end + 1 >= base); } else { /* * The user didn't use AH_INET or AH_INET6. */ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); regs[rd] = 0; break; } inetout: regs[rd] = (uintptr_t)end + 1; mstate->dtms_scratch_ptr += size; break; } case DIF_SUBR_MEMREF: { uintptr_t size = 2 * sizeof(uintptr_t); uintptr_t *memref = (uintptr_t *) P2ROUNDUP(mstate->dtms_scratch_ptr, sizeof(uintptr_t)); size_t scratch_size = ((uintptr_t) memref - mstate->dtms_scratch_ptr) + size; /* address and length */ memref[0] = tupregs[0].dttk_value; memref[1] = tupregs[1].dttk_value; regs[rd] = (uintptr_t) memref; mstate->dtms_scratch_ptr += scratch_size; break; } #ifndef illumos case DIF_SUBR_MEMSTR: { char *str = (char *)mstate->dtms_scratch_ptr; uintptr_t mem = tupregs[0].dttk_value; char c = tupregs[1].dttk_value; size_t size = tupregs[2].dttk_value; uint8_t n; int i; regs[rd] = 0; if (size == 0) break; if (!dtrace_canload(mem, size - 1, mstate, vstate)) break; if (!DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); break; } if (dtrace_memstr_max != 0 && size > dtrace_memstr_max) { *flags |= CPU_DTRACE_ILLOP; break; } for (i = 0; i < size - 1; i++) { n = dtrace_load8(mem++); str[i] = (n == 0) ? c : n; } str[size - 1] = 0; regs[rd] = (uintptr_t)str; mstate->dtms_scratch_ptr += size; break; } #endif } } /* * Emulate the execution of DTrace IR instructions specified by the given * DIF object. This function is deliberately void of assertions as all of * the necessary checks are handled by a call to dtrace_difo_validate(). */ static uint64_t dtrace_dif_emulate(dtrace_difo_t *difo, dtrace_mstate_t *mstate, dtrace_vstate_t *vstate, dtrace_state_t *state) { const dif_instr_t *text = difo->dtdo_buf; const uint_t textlen = difo->dtdo_len; const char *strtab = difo->dtdo_strtab; const uint64_t *inttab = difo->dtdo_inttab; uint64_t rval = 0; dtrace_statvar_t *svar; dtrace_dstate_t *dstate = &vstate->dtvs_dynvars; dtrace_difv_t *v; volatile uint16_t *flags = &cpu_core[curcpu].cpuc_dtrace_flags; volatile uintptr_t *illval = &cpu_core[curcpu].cpuc_dtrace_illval; dtrace_key_t tupregs[DIF_DTR_NREGS + 2]; /* +2 for thread and id */ uint64_t regs[DIF_DIR_NREGS]; uint64_t *tmp; uint8_t cc_n = 0, cc_z = 0, cc_v = 0, cc_c = 0; int64_t cc_r; uint_t pc = 0, id, opc = 0; uint8_t ttop = 0; dif_instr_t instr; uint_t r1, r2, rd; /* * We stash the current DIF object into the machine state: we need it * for subsequent access checking. */ mstate->dtms_difo = difo; regs[DIF_REG_R0] = 0; /* %r0 is fixed at zero */ while (pc < textlen && !(*flags & CPU_DTRACE_FAULT)) { opc = pc; instr = text[pc++]; r1 = DIF_INSTR_R1(instr); r2 = DIF_INSTR_R2(instr); rd = DIF_INSTR_RD(instr); switch (DIF_INSTR_OP(instr)) { case DIF_OP_OR: regs[rd] = regs[r1] | regs[r2]; break; case DIF_OP_XOR: regs[rd] = regs[r1] ^ regs[r2]; break; case DIF_OP_AND: regs[rd] = regs[r1] & regs[r2]; break; case DIF_OP_SLL: regs[rd] = regs[r1] << regs[r2]; break; case DIF_OP_SRL: regs[rd] = regs[r1] >> regs[r2]; break; case DIF_OP_SUB: regs[rd] = regs[r1] - regs[r2]; break; case DIF_OP_ADD: regs[rd] = regs[r1] + regs[r2]; break; case DIF_OP_MUL: regs[rd] = regs[r1] * regs[r2]; break; case DIF_OP_SDIV: if (regs[r2] == 0) { regs[rd] = 0; *flags |= CPU_DTRACE_DIVZERO; } else { regs[rd] = (int64_t)regs[r1] / (int64_t)regs[r2]; } break; case DIF_OP_UDIV: if (regs[r2] == 0) { regs[rd] = 0; *flags |= CPU_DTRACE_DIVZERO; } else { regs[rd] = regs[r1] / regs[r2]; } break; case DIF_OP_SREM: if (regs[r2] == 0) { regs[rd] = 0; *flags |= CPU_DTRACE_DIVZERO; } else { regs[rd] = (int64_t)regs[r1] % (int64_t)regs[r2]; } break; case DIF_OP_UREM: if (regs[r2] == 0) { regs[rd] = 0; *flags |= CPU_DTRACE_DIVZERO; } else { regs[rd] = regs[r1] % regs[r2]; } break; case DIF_OP_NOT: regs[rd] = ~regs[r1]; break; case DIF_OP_MOV: regs[rd] = regs[r1]; break; case DIF_OP_CMP: cc_r = regs[r1] - regs[r2]; cc_n = cc_r < 0; cc_z = cc_r == 0; cc_v = 0; cc_c = regs[r1] < regs[r2]; break; case DIF_OP_TST: cc_n = cc_v = cc_c = 0; cc_z = regs[r1] == 0; break; case DIF_OP_BA: pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BE: if (cc_z) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BNE: if (cc_z == 0) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BG: if ((cc_z | (cc_n ^ cc_v)) == 0) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BGU: if ((cc_c | cc_z) == 0) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BGE: if ((cc_n ^ cc_v) == 0) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BGEU: if (cc_c == 0) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BL: if (cc_n ^ cc_v) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BLU: if (cc_c) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BLE: if (cc_z | (cc_n ^ cc_v)) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_BLEU: if (cc_c | cc_z) pc = DIF_INSTR_LABEL(instr); break; case DIF_OP_RLDSB: if (!dtrace_canload(regs[r1], 1, mstate, vstate)) break; /*FALLTHROUGH*/ case DIF_OP_LDSB: regs[rd] = (int8_t)dtrace_load8(regs[r1]); break; case DIF_OP_RLDSH: if (!dtrace_canload(regs[r1], 2, mstate, vstate)) break; /*FALLTHROUGH*/ case DIF_OP_LDSH: regs[rd] = (int16_t)dtrace_load16(regs[r1]); break; case DIF_OP_RLDSW: if (!dtrace_canload(regs[r1], 4, mstate, vstate)) break; /*FALLTHROUGH*/ case DIF_OP_LDSW: regs[rd] = (int32_t)dtrace_load32(regs[r1]); break; case DIF_OP_RLDUB: if (!dtrace_canload(regs[r1], 1, mstate, vstate)) break; /*FALLTHROUGH*/ case DIF_OP_LDUB: regs[rd] = dtrace_load8(regs[r1]); break; case DIF_OP_RLDUH: if (!dtrace_canload(regs[r1], 2, mstate, vstate)) break; /*FALLTHROUGH*/ case DIF_OP_LDUH: regs[rd] = dtrace_load16(regs[r1]); break; case DIF_OP_RLDUW: if (!dtrace_canload(regs[r1], 4, mstate, vstate)) break; /*FALLTHROUGH*/ case DIF_OP_LDUW: regs[rd] = dtrace_load32(regs[r1]); break; case DIF_OP_RLDX: if (!dtrace_canload(regs[r1], 8, mstate, vstate)) break; /*FALLTHROUGH*/ case DIF_OP_LDX: regs[rd] = dtrace_load64(regs[r1]); break; case DIF_OP_ULDSB: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = (int8_t) dtrace_fuword8((void *)(uintptr_t)regs[r1]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_OP_ULDSH: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = (int16_t) dtrace_fuword16((void *)(uintptr_t)regs[r1]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_OP_ULDSW: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = (int32_t) dtrace_fuword32((void *)(uintptr_t)regs[r1]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_OP_ULDUB: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = dtrace_fuword8((void *)(uintptr_t)regs[r1]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_OP_ULDUH: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = dtrace_fuword16((void *)(uintptr_t)regs[r1]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_OP_ULDUW: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = dtrace_fuword32((void *)(uintptr_t)regs[r1]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_OP_ULDX: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); regs[rd] = dtrace_fuword64((void *)(uintptr_t)regs[r1]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); break; case DIF_OP_RET: rval = regs[rd]; pc = textlen; break; case DIF_OP_NOP: break; case DIF_OP_SETX: regs[rd] = inttab[DIF_INSTR_INTEGER(instr)]; break; case DIF_OP_SETS: regs[rd] = (uint64_t)(uintptr_t) (strtab + DIF_INSTR_STRING(instr)); break; case DIF_OP_SCMP: { size_t sz = state->dts_options[DTRACEOPT_STRSIZE]; uintptr_t s1 = regs[r1]; uintptr_t s2 = regs[r2]; size_t lim1, lim2; if (s1 != 0 && !dtrace_strcanload(s1, sz, &lim1, mstate, vstate)) break; if (s2 != 0 && !dtrace_strcanload(s2, sz, &lim2, mstate, vstate)) break; cc_r = dtrace_strncmp((char *)s1, (char *)s2, MIN(lim1, lim2)); cc_n = cc_r < 0; cc_z = cc_r == 0; cc_v = cc_c = 0; break; } case DIF_OP_LDGA: regs[rd] = dtrace_dif_variable(mstate, state, r1, regs[r2]); break; case DIF_OP_LDGS: id = DIF_INSTR_VAR(instr); if (id >= DIF_VAR_OTHER_UBASE) { uintptr_t a; id -= DIF_VAR_OTHER_UBASE; svar = vstate->dtvs_globals[id]; ASSERT(svar != NULL); v = &svar->dtsv_var; if (!(v->dtdv_type.dtdt_flags & DIF_TF_BYREF)) { regs[rd] = svar->dtsv_data; break; } a = (uintptr_t)svar->dtsv_data; if (*(uint8_t *)a == UINT8_MAX) { /* * If the 0th byte is set to UINT8_MAX * then this is to be treated as a * reference to a NULL variable. */ regs[rd] = 0; } else { regs[rd] = a + sizeof (uint64_t); } break; } regs[rd] = dtrace_dif_variable(mstate, state, id, 0); break; case DIF_OP_STGS: id = DIF_INSTR_VAR(instr); ASSERT(id >= DIF_VAR_OTHER_UBASE); id -= DIF_VAR_OTHER_UBASE; VERIFY(id < vstate->dtvs_nglobals); svar = vstate->dtvs_globals[id]; ASSERT(svar != NULL); v = &svar->dtsv_var; if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { uintptr_t a = (uintptr_t)svar->dtsv_data; size_t lim; ASSERT(a != 0); ASSERT(svar->dtsv_size != 0); if (regs[rd] == 0) { *(uint8_t *)a = UINT8_MAX; break; } else { *(uint8_t *)a = 0; a += sizeof (uint64_t); } if (!dtrace_vcanload( (void *)(uintptr_t)regs[rd], &v->dtdv_type, &lim, mstate, vstate)) break; dtrace_vcopy((void *)(uintptr_t)regs[rd], (void *)a, &v->dtdv_type, lim); break; } svar->dtsv_data = regs[rd]; break; case DIF_OP_LDTA: /* * There are no DTrace built-in thread-local arrays at * present. This opcode is saved for future work. */ *flags |= CPU_DTRACE_ILLOP; regs[rd] = 0; break; case DIF_OP_LDLS: id = DIF_INSTR_VAR(instr); if (id < DIF_VAR_OTHER_UBASE) { /* * For now, this has no meaning. */ regs[rd] = 0; break; } id -= DIF_VAR_OTHER_UBASE; ASSERT(id < vstate->dtvs_nlocals); ASSERT(vstate->dtvs_locals != NULL); svar = vstate->dtvs_locals[id]; ASSERT(svar != NULL); v = &svar->dtsv_var; if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { uintptr_t a = (uintptr_t)svar->dtsv_data; size_t sz = v->dtdv_type.dtdt_size; size_t lim; sz += sizeof (uint64_t); ASSERT(svar->dtsv_size == NCPU * sz); a += curcpu * sz; if (*(uint8_t *)a == UINT8_MAX) { /* * If the 0th byte is set to UINT8_MAX * then this is to be treated as a * reference to a NULL variable. */ regs[rd] = 0; } else { regs[rd] = a + sizeof (uint64_t); } break; } ASSERT(svar->dtsv_size == NCPU * sizeof (uint64_t)); tmp = (uint64_t *)(uintptr_t)svar->dtsv_data; regs[rd] = tmp[curcpu]; break; case DIF_OP_STLS: id = DIF_INSTR_VAR(instr); ASSERT(id >= DIF_VAR_OTHER_UBASE); id -= DIF_VAR_OTHER_UBASE; VERIFY(id < vstate->dtvs_nlocals); ASSERT(vstate->dtvs_locals != NULL); svar = vstate->dtvs_locals[id]; ASSERT(svar != NULL); v = &svar->dtsv_var; if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { uintptr_t a = (uintptr_t)svar->dtsv_data; size_t sz = v->dtdv_type.dtdt_size; size_t lim; sz += sizeof (uint64_t); ASSERT(svar->dtsv_size == NCPU * sz); a += curcpu * sz; if (regs[rd] == 0) { *(uint8_t *)a = UINT8_MAX; break; } else { *(uint8_t *)a = 0; a += sizeof (uint64_t); } if (!dtrace_vcanload( (void *)(uintptr_t)regs[rd], &v->dtdv_type, &lim, mstate, vstate)) break; dtrace_vcopy((void *)(uintptr_t)regs[rd], (void *)a, &v->dtdv_type, lim); break; } ASSERT(svar->dtsv_size == NCPU * sizeof (uint64_t)); tmp = (uint64_t *)(uintptr_t)svar->dtsv_data; tmp[curcpu] = regs[rd]; break; case DIF_OP_LDTS: { dtrace_dynvar_t *dvar; dtrace_key_t *key; id = DIF_INSTR_VAR(instr); ASSERT(id >= DIF_VAR_OTHER_UBASE); id -= DIF_VAR_OTHER_UBASE; v = &vstate->dtvs_tlocals[id]; key = &tupregs[DIF_DTR_NREGS]; key[0].dttk_value = (uint64_t)id; key[0].dttk_size = 0; DTRACE_TLS_THRKEY(key[1].dttk_value); key[1].dttk_size = 0; dvar = dtrace_dynvar(dstate, 2, key, sizeof (uint64_t), DTRACE_DYNVAR_NOALLOC, mstate, vstate); if (dvar == NULL) { regs[rd] = 0; break; } if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { regs[rd] = (uint64_t)(uintptr_t)dvar->dtdv_data; } else { regs[rd] = *((uint64_t *)dvar->dtdv_data); } break; } case DIF_OP_STTS: { dtrace_dynvar_t *dvar; dtrace_key_t *key; id = DIF_INSTR_VAR(instr); ASSERT(id >= DIF_VAR_OTHER_UBASE); id -= DIF_VAR_OTHER_UBASE; VERIFY(id < vstate->dtvs_ntlocals); key = &tupregs[DIF_DTR_NREGS]; key[0].dttk_value = (uint64_t)id; key[0].dttk_size = 0; DTRACE_TLS_THRKEY(key[1].dttk_value); key[1].dttk_size = 0; v = &vstate->dtvs_tlocals[id]; dvar = dtrace_dynvar(dstate, 2, key, v->dtdv_type.dtdt_size > sizeof (uint64_t) ? v->dtdv_type.dtdt_size : sizeof (uint64_t), regs[rd] ? DTRACE_DYNVAR_ALLOC : DTRACE_DYNVAR_DEALLOC, mstate, vstate); /* * Given that we're storing to thread-local data, * we need to flush our predicate cache. */ curthread->t_predcache = 0; if (dvar == NULL) break; if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { size_t lim; if (!dtrace_vcanload( (void *)(uintptr_t)regs[rd], &v->dtdv_type, &lim, mstate, vstate)) break; dtrace_vcopy((void *)(uintptr_t)regs[rd], dvar->dtdv_data, &v->dtdv_type, lim); } else { *((uint64_t *)dvar->dtdv_data) = regs[rd]; } break; } case DIF_OP_SRA: regs[rd] = (int64_t)regs[r1] >> regs[r2]; break; case DIF_OP_CALL: dtrace_dif_subr(DIF_INSTR_SUBR(instr), rd, regs, tupregs, ttop, mstate, state); break; case DIF_OP_PUSHTR: if (ttop == DIF_DTR_NREGS) { *flags |= CPU_DTRACE_TUPOFLOW; break; } if (r1 == DIF_TYPE_STRING) { /* * If this is a string type and the size is 0, * we'll use the system-wide default string * size. Note that we are _not_ looking at * the value of the DTRACEOPT_STRSIZE option; * had this been set, we would expect to have * a non-zero size value in the "pushtr". */ tupregs[ttop].dttk_size = dtrace_strlen((char *)(uintptr_t)regs[rd], regs[r2] ? regs[r2] : dtrace_strsize_default) + 1; } else { if (regs[r2] > LONG_MAX) { *flags |= CPU_DTRACE_ILLOP; break; } tupregs[ttop].dttk_size = regs[r2]; } tupregs[ttop++].dttk_value = regs[rd]; break; case DIF_OP_PUSHTV: if (ttop == DIF_DTR_NREGS) { *flags |= CPU_DTRACE_TUPOFLOW; break; } tupregs[ttop].dttk_value = regs[rd]; tupregs[ttop++].dttk_size = 0; break; case DIF_OP_POPTS: if (ttop != 0) ttop--; break; case DIF_OP_FLUSHTS: ttop = 0; break; case DIF_OP_LDGAA: case DIF_OP_LDTAA: { dtrace_dynvar_t *dvar; dtrace_key_t *key = tupregs; uint_t nkeys = ttop; id = DIF_INSTR_VAR(instr); ASSERT(id >= DIF_VAR_OTHER_UBASE); id -= DIF_VAR_OTHER_UBASE; key[nkeys].dttk_value = (uint64_t)id; key[nkeys++].dttk_size = 0; if (DIF_INSTR_OP(instr) == DIF_OP_LDTAA) { DTRACE_TLS_THRKEY(key[nkeys].dttk_value); key[nkeys++].dttk_size = 0; VERIFY(id < vstate->dtvs_ntlocals); v = &vstate->dtvs_tlocals[id]; } else { VERIFY(id < vstate->dtvs_nglobals); v = &vstate->dtvs_globals[id]->dtsv_var; } dvar = dtrace_dynvar(dstate, nkeys, key, v->dtdv_type.dtdt_size > sizeof (uint64_t) ? v->dtdv_type.dtdt_size : sizeof (uint64_t), DTRACE_DYNVAR_NOALLOC, mstate, vstate); if (dvar == NULL) { regs[rd] = 0; break; } if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { regs[rd] = (uint64_t)(uintptr_t)dvar->dtdv_data; } else { regs[rd] = *((uint64_t *)dvar->dtdv_data); } break; } case DIF_OP_STGAA: case DIF_OP_STTAA: { dtrace_dynvar_t *dvar; dtrace_key_t *key = tupregs; uint_t nkeys = ttop; id = DIF_INSTR_VAR(instr); ASSERT(id >= DIF_VAR_OTHER_UBASE); id -= DIF_VAR_OTHER_UBASE; key[nkeys].dttk_value = (uint64_t)id; key[nkeys++].dttk_size = 0; if (DIF_INSTR_OP(instr) == DIF_OP_STTAA) { DTRACE_TLS_THRKEY(key[nkeys].dttk_value); key[nkeys++].dttk_size = 0; VERIFY(id < vstate->dtvs_ntlocals); v = &vstate->dtvs_tlocals[id]; } else { VERIFY(id < vstate->dtvs_nglobals); v = &vstate->dtvs_globals[id]->dtsv_var; } dvar = dtrace_dynvar(dstate, nkeys, key, v->dtdv_type.dtdt_size > sizeof (uint64_t) ? v->dtdv_type.dtdt_size : sizeof (uint64_t), regs[rd] ? DTRACE_DYNVAR_ALLOC : DTRACE_DYNVAR_DEALLOC, mstate, vstate); if (dvar == NULL) break; if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { size_t lim; if (!dtrace_vcanload( (void *)(uintptr_t)regs[rd], &v->dtdv_type, &lim, mstate, vstate)) break; dtrace_vcopy((void *)(uintptr_t)regs[rd], dvar->dtdv_data, &v->dtdv_type, lim); } else { *((uint64_t *)dvar->dtdv_data) = regs[rd]; } break; } case DIF_OP_ALLOCS: { uintptr_t ptr = P2ROUNDUP(mstate->dtms_scratch_ptr, 8); size_t size = ptr - mstate->dtms_scratch_ptr + regs[r1]; /* * Rounding up the user allocation size could have * overflowed large, bogus allocations (like -1ULL) to * 0. */ if (size < regs[r1] || !DTRACE_INSCRATCH(mstate, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); regs[rd] = 0; break; } dtrace_bzero((void *) mstate->dtms_scratch_ptr, size); mstate->dtms_scratch_ptr += size; regs[rd] = ptr; break; } case DIF_OP_COPYS: if (!dtrace_canstore(regs[rd], regs[r2], mstate, vstate)) { *flags |= CPU_DTRACE_BADADDR; *illval = regs[rd]; break; } if (!dtrace_canload(regs[r1], regs[r2], mstate, vstate)) break; dtrace_bcopy((void *)(uintptr_t)regs[r1], (void *)(uintptr_t)regs[rd], (size_t)regs[r2]); break; case DIF_OP_STB: if (!dtrace_canstore(regs[rd], 1, mstate, vstate)) { *flags |= CPU_DTRACE_BADADDR; *illval = regs[rd]; break; } *((uint8_t *)(uintptr_t)regs[rd]) = (uint8_t)regs[r1]; break; case DIF_OP_STH: if (!dtrace_canstore(regs[rd], 2, mstate, vstate)) { *flags |= CPU_DTRACE_BADADDR; *illval = regs[rd]; break; } if (regs[rd] & 1) { *flags |= CPU_DTRACE_BADALIGN; *illval = regs[rd]; break; } *((uint16_t *)(uintptr_t)regs[rd]) = (uint16_t)regs[r1]; break; case DIF_OP_STW: if (!dtrace_canstore(regs[rd], 4, mstate, vstate)) { *flags |= CPU_DTRACE_BADADDR; *illval = regs[rd]; break; } if (regs[rd] & 3) { *flags |= CPU_DTRACE_BADALIGN; *illval = regs[rd]; break; } *((uint32_t *)(uintptr_t)regs[rd]) = (uint32_t)regs[r1]; break; case DIF_OP_STX: if (!dtrace_canstore(regs[rd], 8, mstate, vstate)) { *flags |= CPU_DTRACE_BADADDR; *illval = regs[rd]; break; } if (regs[rd] & 7) { *flags |= CPU_DTRACE_BADALIGN; *illval = regs[rd]; break; } *((uint64_t *)(uintptr_t)regs[rd]) = regs[r1]; break; } } if (!(*flags & CPU_DTRACE_FAULT)) return (rval); mstate->dtms_fltoffs = opc * sizeof (dif_instr_t); mstate->dtms_present |= DTRACE_MSTATE_FLTOFFS; return (0); } static void dtrace_action_breakpoint(dtrace_ecb_t *ecb) { dtrace_probe_t *probe = ecb->dte_probe; dtrace_provider_t *prov = probe->dtpr_provider; char c[DTRACE_FULLNAMELEN + 80], *str; char *msg = "dtrace: breakpoint action at probe "; char *ecbmsg = " (ecb "; uintptr_t mask = (0xf << (sizeof (uintptr_t) * NBBY / 4)); uintptr_t val = (uintptr_t)ecb; int shift = (sizeof (uintptr_t) * NBBY) - 4, i = 0; if (dtrace_destructive_disallow) return; /* * It's impossible to be taking action on the NULL probe. */ ASSERT(probe != NULL); /* * This is a poor man's (destitute man's?) sprintf(): we want to * print the provider name, module name, function name and name of * the probe, along with the hex address of the ECB with the breakpoint * action -- all of which we must place in the character buffer by * hand. */ while (*msg != '\0') c[i++] = *msg++; for (str = prov->dtpv_name; *str != '\0'; str++) c[i++] = *str; c[i++] = ':'; for (str = probe->dtpr_mod; *str != '\0'; str++) c[i++] = *str; c[i++] = ':'; for (str = probe->dtpr_func; *str != '\0'; str++) c[i++] = *str; c[i++] = ':'; for (str = probe->dtpr_name; *str != '\0'; str++) c[i++] = *str; while (*ecbmsg != '\0') c[i++] = *ecbmsg++; while (shift >= 0) { mask = (uintptr_t)0xf << shift; if (val >= ((uintptr_t)1 << shift)) c[i++] = "0123456789abcdef"[(val & mask) >> shift]; shift -= 4; } c[i++] = ')'; c[i] = '\0'; #ifdef illumos debug_enter(c); #else kdb_enter(KDB_WHY_DTRACE, "breakpoint action"); #endif } static void dtrace_action_panic(dtrace_ecb_t *ecb) { dtrace_probe_t *probe = ecb->dte_probe; /* * It's impossible to be taking action on the NULL probe. */ ASSERT(probe != NULL); if (dtrace_destructive_disallow) return; if (dtrace_panicked != NULL) return; if (dtrace_casptr(&dtrace_panicked, NULL, curthread) != NULL) return; /* * We won the right to panic. (We want to be sure that only one * thread calls panic() from dtrace_probe(), and that panic() is * called exactly once.) */ dtrace_panic("dtrace: panic action at probe %s:%s:%s:%s (ecb %p)", probe->dtpr_provider->dtpv_name, probe->dtpr_mod, probe->dtpr_func, probe->dtpr_name, (void *)ecb); } static void dtrace_action_raise(uint64_t sig) { if (dtrace_destructive_disallow) return; if (sig >= NSIG) { DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return; } #ifdef illumos /* * raise() has a queue depth of 1 -- we ignore all subsequent * invocations of the raise() action. */ if (curthread->t_dtrace_sig == 0) curthread->t_dtrace_sig = (uint8_t)sig; curthread->t_sig_check = 1; aston(curthread); #else struct proc *p = curproc; PROC_LOCK(p); kern_psignal(p, sig); PROC_UNLOCK(p); #endif } static void dtrace_action_stop(void) { if (dtrace_destructive_disallow) return; #ifdef illumos if (!curthread->t_dtrace_stop) { curthread->t_dtrace_stop = 1; curthread->t_sig_check = 1; aston(curthread); } #else struct proc *p = curproc; PROC_LOCK(p); kern_psignal(p, SIGSTOP); PROC_UNLOCK(p); #endif } static void dtrace_action_chill(dtrace_mstate_t *mstate, hrtime_t val) { hrtime_t now; volatile uint16_t *flags; #ifdef illumos cpu_t *cpu = CPU; #else cpu_t *cpu = &solaris_cpu[curcpu]; #endif if (dtrace_destructive_disallow) return; flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; now = dtrace_gethrtime(); if (now - cpu->cpu_dtrace_chillmark > dtrace_chill_interval) { /* * We need to advance the mark to the current time. */ cpu->cpu_dtrace_chillmark = now; cpu->cpu_dtrace_chilled = 0; } /* * Now check to see if the requested chill time would take us over * the maximum amount of time allowed in the chill interval. (Or * worse, if the calculation itself induces overflow.) */ if (cpu->cpu_dtrace_chilled + val > dtrace_chill_max || cpu->cpu_dtrace_chilled + val < cpu->cpu_dtrace_chilled) { *flags |= CPU_DTRACE_ILLOP; return; } while (dtrace_gethrtime() - now < val) continue; /* * Normally, we assure that the value of the variable "timestamp" does * not change within an ECB. The presence of chill() represents an * exception to this rule, however. */ mstate->dtms_present &= ~DTRACE_MSTATE_TIMESTAMP; cpu->cpu_dtrace_chilled += val; } static void dtrace_action_ustack(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t *buf, uint64_t arg) { int nframes = DTRACE_USTACK_NFRAMES(arg); int strsize = DTRACE_USTACK_STRSIZE(arg); uint64_t *pcs = &buf[1], *fps; char *str = (char *)&pcs[nframes]; int size, offs = 0, i, j; size_t rem; uintptr_t old = mstate->dtms_scratch_ptr, saved; uint16_t *flags = &cpu_core[curcpu].cpuc_dtrace_flags; char *sym; /* * Should be taking a faster path if string space has not been * allocated. */ ASSERT(strsize != 0); /* * We will first allocate some temporary space for the frame pointers. */ fps = (uint64_t *)P2ROUNDUP(mstate->dtms_scratch_ptr, 8); size = (uintptr_t)fps - mstate->dtms_scratch_ptr + (nframes * sizeof (uint64_t)); if (!DTRACE_INSCRATCH(mstate, size)) { /* * Not enough room for our frame pointers -- need to indicate * that we ran out of scratch space. */ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); return; } mstate->dtms_scratch_ptr += size; saved = mstate->dtms_scratch_ptr; /* * Now get a stack with both program counters and frame pointers. */ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_getufpstack(buf, fps, nframes + 1); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); /* * If that faulted, we're cooked. */ if (*flags & CPU_DTRACE_FAULT) goto out; /* * Now we want to walk up the stack, calling the USTACK helper. For * each iteration, we restore the scratch pointer. */ for (i = 0; i < nframes; i++) { mstate->dtms_scratch_ptr = saved; if (offs >= strsize) break; sym = (char *)(uintptr_t)dtrace_helper( DTRACE_HELPER_ACTION_USTACK, mstate, state, pcs[i], fps[i]); /* * If we faulted while running the helper, we're going to * clear the fault and null out the corresponding string. */ if (*flags & CPU_DTRACE_FAULT) { *flags &= ~CPU_DTRACE_FAULT; str[offs++] = '\0'; continue; } if (sym == NULL) { str[offs++] = '\0'; continue; } if (!dtrace_strcanload((uintptr_t)sym, strsize, &rem, mstate, &(state->dts_vstate))) { str[offs++] = '\0'; continue; } DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); /* * Now copy in the string that the helper returned to us. */ for (j = 0; offs + j < strsize && j < rem; j++) { if ((str[offs + j] = sym[j]) == '\0') break; } DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); offs += j + 1; } if (offs >= strsize) { /* * If we didn't have room for all of the strings, we don't * abort processing -- this needn't be a fatal error -- but we * still want to increment a counter (dts_stkstroverflows) to * allow this condition to be warned about. (If this is from * a jstack() action, it is easily tuned via jstackstrsize.) */ dtrace_error(&state->dts_stkstroverflows); } while (offs < strsize) str[offs++] = '\0'; out: mstate->dtms_scratch_ptr = old; } static void dtrace_store_by_ref(dtrace_difo_t *dp, caddr_t tomax, size_t size, size_t *valoffsp, uint64_t *valp, uint64_t end, int intuple, int dtkind) { volatile uint16_t *flags; uint64_t val = *valp; size_t valoffs = *valoffsp; flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; ASSERT(dtkind == DIF_TF_BYREF || dtkind == DIF_TF_BYUREF); /* * If this is a string, we're going to only load until we find the zero * byte -- after which we'll store zero bytes. */ if (dp->dtdo_rtype.dtdt_kind == DIF_TYPE_STRING) { char c = '\0' + 1; size_t s; for (s = 0; s < size; s++) { if (c != '\0' && dtkind == DIF_TF_BYREF) { c = dtrace_load8(val++); } else if (c != '\0' && dtkind == DIF_TF_BYUREF) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); c = dtrace_fuword8((void *)(uintptr_t)val++); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); if (*flags & CPU_DTRACE_FAULT) break; } DTRACE_STORE(uint8_t, tomax, valoffs++, c); if (c == '\0' && intuple) break; } } else { uint8_t c; while (valoffs < end) { if (dtkind == DIF_TF_BYREF) { c = dtrace_load8(val++); } else if (dtkind == DIF_TF_BYUREF) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); c = dtrace_fuword8((void *)(uintptr_t)val++); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); if (*flags & CPU_DTRACE_FAULT) break; } DTRACE_STORE(uint8_t, tomax, valoffs++, c); } } *valp = val; *valoffsp = valoffs; } /* * If you're looking for the epicenter of DTrace, you just found it. This * is the function called by the provider to fire a probe -- from which all * subsequent probe-context DTrace activity emanates. */ void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) { processorid_t cpuid; dtrace_icookie_t cookie; dtrace_probe_t *probe; dtrace_mstate_t mstate; dtrace_ecb_t *ecb; dtrace_action_t *act; intptr_t offs; size_t size; int vtime, onintr; volatile uint16_t *flags; hrtime_t now; if (panicstr != NULL) return; #ifdef illumos /* * Kick out immediately if this CPU is still being born (in which case * curthread will be set to -1) or the current thread can't allow * probes in its current context. */ if (((uintptr_t)curthread & 1) || (curthread->t_flag & T_DONTDTRACE)) return; #endif cookie = dtrace_interrupt_disable(); probe = dtrace_probes[id - 1]; cpuid = curcpu; onintr = CPU_ON_INTR(CPU); if (!onintr && probe->dtpr_predcache != DTRACE_CACHEIDNONE && probe->dtpr_predcache == curthread->t_predcache) { /* * We have hit in the predicate cache; we know that * this predicate would evaluate to be false. */ dtrace_interrupt_enable(cookie); return; } #ifdef illumos if (panic_quiesce) { #else if (panicstr != NULL) { #endif /* * We don't trace anything if we're panicking. */ dtrace_interrupt_enable(cookie); return; } now = mstate.dtms_timestamp = dtrace_gethrtime(); mstate.dtms_present |= DTRACE_MSTATE_TIMESTAMP; vtime = dtrace_vtime_references != 0; if (vtime && curthread->t_dtrace_start) curthread->t_dtrace_vtime += now - curthread->t_dtrace_start; mstate.dtms_difo = NULL; mstate.dtms_probe = probe; mstate.dtms_strtok = 0; mstate.dtms_arg[0] = arg0; mstate.dtms_arg[1] = arg1; mstate.dtms_arg[2] = arg2; mstate.dtms_arg[3] = arg3; mstate.dtms_arg[4] = arg4; flags = (volatile uint16_t *)&cpu_core[cpuid].cpuc_dtrace_flags; for (ecb = probe->dtpr_ecb; ecb != NULL; ecb = ecb->dte_next) { dtrace_predicate_t *pred = ecb->dte_predicate; dtrace_state_t *state = ecb->dte_state; dtrace_buffer_t *buf = &state->dts_buffer[cpuid]; dtrace_buffer_t *aggbuf = &state->dts_aggbuffer[cpuid]; dtrace_vstate_t *vstate = &state->dts_vstate; dtrace_provider_t *prov = probe->dtpr_provider; uint64_t tracememsize = 0; int committed = 0; caddr_t tomax; /* * A little subtlety with the following (seemingly innocuous) * declaration of the automatic 'val': by looking at the * code, you might think that it could be declared in the * action processing loop, below. (That is, it's only used in * the action processing loop.) However, it must be declared * out of that scope because in the case of DIF expression * arguments to aggregating actions, one iteration of the * action loop will use the last iteration's value. */ uint64_t val = 0; mstate.dtms_present = DTRACE_MSTATE_ARGS | DTRACE_MSTATE_PROBE; mstate.dtms_getf = NULL; *flags &= ~CPU_DTRACE_ERROR; if (prov == dtrace_provider) { /* * If dtrace itself is the provider of this probe, * we're only going to continue processing the ECB if * arg0 (the dtrace_state_t) is equal to the ECB's * creating state. (This prevents disjoint consumers * from seeing one another's metaprobes.) */ if (arg0 != (uint64_t)(uintptr_t)state) continue; } if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE) { /* * We're not currently active. If our provider isn't * the dtrace pseudo provider, we're not interested. */ if (prov != dtrace_provider) continue; /* * Now we must further check if we are in the BEGIN * probe. If we are, we will only continue processing * if we're still in WARMUP -- if one BEGIN enabling * has invoked the exit() action, we don't want to * evaluate subsequent BEGIN enablings. */ if (probe->dtpr_id == dtrace_probeid_begin && state->dts_activity != DTRACE_ACTIVITY_WARMUP) { ASSERT(state->dts_activity == DTRACE_ACTIVITY_DRAINING); continue; } } if (ecb->dte_cond) { /* * If the dte_cond bits indicate that this * consumer is only allowed to see user-mode firings * of this probe, call the provider's dtps_usermode() * entry point to check that the probe was fired * while in a user context. Skip this ECB if that's * not the case. */ if ((ecb->dte_cond & DTRACE_COND_USERMODE) && prov->dtpv_pops.dtps_usermode(prov->dtpv_arg, probe->dtpr_id, probe->dtpr_arg) == 0) continue; #ifdef illumos /* * This is more subtle than it looks. We have to be * absolutely certain that CRED() isn't going to * change out from under us so it's only legit to * examine that structure if we're in constrained * situations. Currently, the only times we'll this * check is if a non-super-user has enabled the * profile or syscall providers -- providers that * allow visibility of all processes. For the * profile case, the check above will ensure that * we're examining a user context. */ if (ecb->dte_cond & DTRACE_COND_OWNER) { cred_t *cr; cred_t *s_cr = ecb->dte_state->dts_cred.dcr_cred; proc_t *proc; ASSERT(s_cr != NULL); if ((cr = CRED()) == NULL || s_cr->cr_uid != cr->cr_uid || s_cr->cr_uid != cr->cr_ruid || s_cr->cr_uid != cr->cr_suid || s_cr->cr_gid != cr->cr_gid || s_cr->cr_gid != cr->cr_rgid || s_cr->cr_gid != cr->cr_sgid || (proc = ttoproc(curthread)) == NULL || (proc->p_flag & SNOCD)) continue; } if (ecb->dte_cond & DTRACE_COND_ZONEOWNER) { cred_t *cr; cred_t *s_cr = ecb->dte_state->dts_cred.dcr_cred; ASSERT(s_cr != NULL); if ((cr = CRED()) == NULL || s_cr->cr_zone->zone_id != cr->cr_zone->zone_id) continue; } #endif } if (now - state->dts_alive > dtrace_deadman_timeout) { /* * We seem to be dead. Unless we (a) have kernel * destructive permissions (b) have explicitly enabled * destructive actions and (c) destructive actions have * not been disabled, we're going to transition into * the KILLED state, from which no further processing * on this state will be performed. */ if (!dtrace_priv_kernel_destructive(state) || !state->dts_cred.dcr_destructive || dtrace_destructive_disallow) { void *activity = &state->dts_activity; dtrace_activity_t current; do { current = state->dts_activity; } while (dtrace_cas32(activity, current, DTRACE_ACTIVITY_KILLED) != current); continue; } } if ((offs = dtrace_buffer_reserve(buf, ecb->dte_needed, ecb->dte_alignment, state, &mstate)) < 0) continue; tomax = buf->dtb_tomax; ASSERT(tomax != NULL); if (ecb->dte_size != 0) { dtrace_rechdr_t dtrh; if (!(mstate.dtms_present & DTRACE_MSTATE_TIMESTAMP)) { mstate.dtms_timestamp = dtrace_gethrtime(); mstate.dtms_present |= DTRACE_MSTATE_TIMESTAMP; } ASSERT3U(ecb->dte_size, >=, sizeof (dtrace_rechdr_t)); dtrh.dtrh_epid = ecb->dte_epid; DTRACE_RECORD_STORE_TIMESTAMP(&dtrh, mstate.dtms_timestamp); *((dtrace_rechdr_t *)(tomax + offs)) = dtrh; } mstate.dtms_epid = ecb->dte_epid; mstate.dtms_present |= DTRACE_MSTATE_EPID; if (state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL) mstate.dtms_access = DTRACE_ACCESS_KERNEL; else mstate.dtms_access = 0; if (pred != NULL) { dtrace_difo_t *dp = pred->dtp_difo; uint64_t rval; rval = dtrace_dif_emulate(dp, &mstate, vstate, state); if (!(*flags & CPU_DTRACE_ERROR) && !rval) { dtrace_cacheid_t cid = probe->dtpr_predcache; if (cid != DTRACE_CACHEIDNONE && !onintr) { /* * Update the predicate cache... */ ASSERT(cid == pred->dtp_cacheid); curthread->t_predcache = cid; } continue; } } for (act = ecb->dte_action; !(*flags & CPU_DTRACE_ERROR) && act != NULL; act = act->dta_next) { size_t valoffs; dtrace_difo_t *dp; dtrace_recdesc_t *rec = &act->dta_rec; size = rec->dtrd_size; valoffs = offs + rec->dtrd_offset; if (DTRACEACT_ISAGG(act->dta_kind)) { uint64_t v = 0xbad; dtrace_aggregation_t *agg; agg = (dtrace_aggregation_t *)act; if ((dp = act->dta_difo) != NULL) v = dtrace_dif_emulate(dp, &mstate, vstate, state); if (*flags & CPU_DTRACE_ERROR) continue; /* * Note that we always pass the expression * value from the previous iteration of the * action loop. This value will only be used * if there is an expression argument to the * aggregating action, denoted by the * dtag_hasarg field. */ dtrace_aggregate(agg, buf, offs, aggbuf, v, val); continue; } switch (act->dta_kind) { case DTRACEACT_STOP: if (dtrace_priv_proc_destructive(state)) dtrace_action_stop(); continue; case DTRACEACT_BREAKPOINT: if (dtrace_priv_kernel_destructive(state)) dtrace_action_breakpoint(ecb); continue; case DTRACEACT_PANIC: if (dtrace_priv_kernel_destructive(state)) dtrace_action_panic(ecb); continue; case DTRACEACT_STACK: if (!dtrace_priv_kernel(state)) continue; dtrace_getpcstack((pc_t *)(tomax + valoffs), size / sizeof (pc_t), probe->dtpr_aframes, DTRACE_ANCHORED(probe) ? NULL : (uint32_t *)arg0); continue; case DTRACEACT_JSTACK: case DTRACEACT_USTACK: if (!dtrace_priv_proc(state)) continue; /* * See comment in DIF_VAR_PID. */ if (DTRACE_ANCHORED(mstate.dtms_probe) && CPU_ON_INTR(CPU)) { int depth = DTRACE_USTACK_NFRAMES( rec->dtrd_arg) + 1; dtrace_bzero((void *)(tomax + valoffs), DTRACE_USTACK_STRSIZE(rec->dtrd_arg) + depth * sizeof (uint64_t)); continue; } if (DTRACE_USTACK_STRSIZE(rec->dtrd_arg) != 0 && curproc->p_dtrace_helpers != NULL) { /* * This is the slow path -- we have * allocated string space, and we're * getting the stack of a process that * has helpers. Call into a separate * routine to perform this processing. */ dtrace_action_ustack(&mstate, state, (uint64_t *)(tomax + valoffs), rec->dtrd_arg); continue; } DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_getupcstack((uint64_t *) (tomax + valoffs), DTRACE_USTACK_NFRAMES(rec->dtrd_arg) + 1); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); continue; default: break; } dp = act->dta_difo; ASSERT(dp != NULL); val = dtrace_dif_emulate(dp, &mstate, vstate, state); if (*flags & CPU_DTRACE_ERROR) continue; switch (act->dta_kind) { case DTRACEACT_SPECULATE: { dtrace_rechdr_t *dtrh; ASSERT(buf == &state->dts_buffer[cpuid]); buf = dtrace_speculation_buffer(state, cpuid, val); if (buf == NULL) { *flags |= CPU_DTRACE_DROP; continue; } offs = dtrace_buffer_reserve(buf, ecb->dte_needed, ecb->dte_alignment, state, NULL); if (offs < 0) { *flags |= CPU_DTRACE_DROP; continue; } tomax = buf->dtb_tomax; ASSERT(tomax != NULL); if (ecb->dte_size == 0) continue; ASSERT3U(ecb->dte_size, >=, sizeof (dtrace_rechdr_t)); dtrh = ((void *)(tomax + offs)); dtrh->dtrh_epid = ecb->dte_epid; /* * When the speculation is committed, all of * the records in the speculative buffer will * have their timestamps set to the commit * time. Until then, it is set to a sentinel * value, for debugability. */ DTRACE_RECORD_STORE_TIMESTAMP(dtrh, UINT64_MAX); continue; } case DTRACEACT_PRINTM: { /* The DIF returns a 'memref'. */ uintptr_t *memref = (uintptr_t *)(uintptr_t) val; /* Get the size from the memref. */ size = memref[1]; /* * Check if the size exceeds the allocated * buffer size. */ if (size + sizeof(uintptr_t) > dp->dtdo_rtype.dtdt_size) { /* Flag a drop! */ *flags |= CPU_DTRACE_DROP; continue; } /* Store the size in the buffer first. */ DTRACE_STORE(uintptr_t, tomax, valoffs, size); /* * Offset the buffer address to the start * of the data. */ valoffs += sizeof(uintptr_t); /* * Reset to the memory address rather than * the memref array, then let the BYREF * code below do the work to store the * memory data in the buffer. */ val = memref[0]; break; } case DTRACEACT_CHILL: if (dtrace_priv_kernel_destructive(state)) dtrace_action_chill(&mstate, val); continue; case DTRACEACT_RAISE: if (dtrace_priv_proc_destructive(state)) dtrace_action_raise(val); continue; case DTRACEACT_COMMIT: ASSERT(!committed); /* * We need to commit our buffer state. */ if (ecb->dte_size) buf->dtb_offset = offs + ecb->dte_size; buf = &state->dts_buffer[cpuid]; dtrace_speculation_commit(state, cpuid, val); committed = 1; continue; case DTRACEACT_DISCARD: dtrace_speculation_discard(state, cpuid, val); continue; case DTRACEACT_DIFEXPR: case DTRACEACT_LIBACT: case DTRACEACT_PRINTF: case DTRACEACT_PRINTA: case DTRACEACT_SYSTEM: case DTRACEACT_FREOPEN: case DTRACEACT_TRACEMEM: break; case DTRACEACT_TRACEMEM_DYNSIZE: tracememsize = val; break; case DTRACEACT_SYM: case DTRACEACT_MOD: if (!dtrace_priv_kernel(state)) continue; break; case DTRACEACT_USYM: case DTRACEACT_UMOD: case DTRACEACT_UADDR: { #ifdef illumos struct pid *pid = curthread->t_procp->p_pidp; #endif if (!dtrace_priv_proc(state)) continue; DTRACE_STORE(uint64_t, tomax, #ifdef illumos valoffs, (uint64_t)pid->pid_id); #else valoffs, (uint64_t) curproc->p_pid); #endif DTRACE_STORE(uint64_t, tomax, valoffs + sizeof (uint64_t), val); continue; } case DTRACEACT_EXIT: { /* * For the exit action, we are going to attempt * to atomically set our activity to be * draining. If this fails (either because * another CPU has beat us to the exit action, * or because our current activity is something * other than ACTIVE or WARMUP), we will * continue. This assures that the exit action * can be successfully recorded at most once * when we're in the ACTIVE state. If we're * encountering the exit() action while in * COOLDOWN, however, we want to honor the new * status code. (We know that we're the only * thread in COOLDOWN, so there is no race.) */ void *activity = &state->dts_activity; dtrace_activity_t current = state->dts_activity; if (current == DTRACE_ACTIVITY_COOLDOWN) break; if (current != DTRACE_ACTIVITY_WARMUP) current = DTRACE_ACTIVITY_ACTIVE; if (dtrace_cas32(activity, current, DTRACE_ACTIVITY_DRAINING) != current) { *flags |= CPU_DTRACE_DROP; continue; } break; } default: ASSERT(0); } if (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF || dp->dtdo_rtype.dtdt_flags & DIF_TF_BYUREF) { uintptr_t end = valoffs + size; if (tracememsize != 0 && valoffs + tracememsize < end) { end = valoffs + tracememsize; tracememsize = 0; } if (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF && !dtrace_vcanload((void *)(uintptr_t)val, &dp->dtdo_rtype, NULL, &mstate, vstate)) continue; dtrace_store_by_ref(dp, tomax, size, &valoffs, &val, end, act->dta_intuple, dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF ? DIF_TF_BYREF: DIF_TF_BYUREF); continue; } switch (size) { case 0: break; case sizeof (uint8_t): DTRACE_STORE(uint8_t, tomax, valoffs, val); break; case sizeof (uint16_t): DTRACE_STORE(uint16_t, tomax, valoffs, val); break; case sizeof (uint32_t): DTRACE_STORE(uint32_t, tomax, valoffs, val); break; case sizeof (uint64_t): DTRACE_STORE(uint64_t, tomax, valoffs, val); break; default: /* * Any other size should have been returned by * reference, not by value. */ ASSERT(0); break; } } if (*flags & CPU_DTRACE_DROP) continue; if (*flags & CPU_DTRACE_FAULT) { int ndx; dtrace_action_t *err; buf->dtb_errors++; if (probe->dtpr_id == dtrace_probeid_error) { /* * There's nothing we can do -- we had an * error on the error probe. We bump an * error counter to at least indicate that * this condition happened. */ dtrace_error(&state->dts_dblerrors); continue; } if (vtime) { /* * Before recursing on dtrace_probe(), we * need to explicitly clear out our start * time to prevent it from being accumulated * into t_dtrace_vtime. */ curthread->t_dtrace_start = 0; } /* * Iterate over the actions to figure out which action * we were processing when we experienced the error. * Note that act points _past_ the faulting action; if * act is ecb->dte_action, the fault was in the * predicate, if it's ecb->dte_action->dta_next it's * in action #1, and so on. */ for (err = ecb->dte_action, ndx = 0; err != act; err = err->dta_next, ndx++) continue; dtrace_probe_error(state, ecb->dte_epid, ndx, (mstate.dtms_present & DTRACE_MSTATE_FLTOFFS) ? mstate.dtms_fltoffs : -1, DTRACE_FLAGS2FLT(*flags), cpu_core[cpuid].cpuc_dtrace_illval); continue; } if (!committed) buf->dtb_offset = offs + ecb->dte_size; } if (vtime) curthread->t_dtrace_start = dtrace_gethrtime(); dtrace_interrupt_enable(cookie); } /* * DTrace Probe Hashing Functions * * The functions in this section (and indeed, the functions in remaining * sections) are not _called_ from probe context. (Any exceptions to this are * marked with a "Note:".) Rather, they are called from elsewhere in the * DTrace framework to look-up probes in, add probes to and remove probes from * the DTrace probe hashes. (Each probe is hashed by each element of the * probe tuple -- allowing for fast lookups, regardless of what was * specified.) */ static uint_t dtrace_hash_str(const char *p) { unsigned int g; uint_t hval = 0; while (*p) { hval = (hval << 4) + *p++; if ((g = (hval & 0xf0000000)) != 0) hval ^= g >> 24; hval &= ~g; } return (hval); } static dtrace_hash_t * dtrace_hash_create(uintptr_t stroffs, uintptr_t nextoffs, uintptr_t prevoffs) { dtrace_hash_t *hash = kmem_zalloc(sizeof (dtrace_hash_t), KM_SLEEP); hash->dth_stroffs = stroffs; hash->dth_nextoffs = nextoffs; hash->dth_prevoffs = prevoffs; hash->dth_size = 1; hash->dth_mask = hash->dth_size - 1; hash->dth_tab = kmem_zalloc(hash->dth_size * sizeof (dtrace_hashbucket_t *), KM_SLEEP); return (hash); } static void dtrace_hash_destroy(dtrace_hash_t *hash) { #ifdef DEBUG int i; for (i = 0; i < hash->dth_size; i++) ASSERT(hash->dth_tab[i] == NULL); #endif kmem_free(hash->dth_tab, hash->dth_size * sizeof (dtrace_hashbucket_t *)); kmem_free(hash, sizeof (dtrace_hash_t)); } static void dtrace_hash_resize(dtrace_hash_t *hash) { int size = hash->dth_size, i, ndx; int new_size = hash->dth_size << 1; int new_mask = new_size - 1; dtrace_hashbucket_t **new_tab, *bucket, *next; ASSERT((new_size & new_mask) == 0); new_tab = kmem_zalloc(new_size * sizeof (void *), KM_SLEEP); for (i = 0; i < size; i++) { for (bucket = hash->dth_tab[i]; bucket != NULL; bucket = next) { dtrace_probe_t *probe = bucket->dthb_chain; ASSERT(probe != NULL); ndx = DTRACE_HASHSTR(hash, probe) & new_mask; next = bucket->dthb_next; bucket->dthb_next = new_tab[ndx]; new_tab[ndx] = bucket; } } kmem_free(hash->dth_tab, hash->dth_size * sizeof (void *)); hash->dth_tab = new_tab; hash->dth_size = new_size; hash->dth_mask = new_mask; } static void dtrace_hash_add(dtrace_hash_t *hash, dtrace_probe_t *new) { int hashval = DTRACE_HASHSTR(hash, new); int ndx = hashval & hash->dth_mask; dtrace_hashbucket_t *bucket = hash->dth_tab[ndx]; dtrace_probe_t **nextp, **prevp; for (; bucket != NULL; bucket = bucket->dthb_next) { if (DTRACE_HASHEQ(hash, bucket->dthb_chain, new)) goto add; } if ((hash->dth_nbuckets >> 1) > hash->dth_size) { dtrace_hash_resize(hash); dtrace_hash_add(hash, new); return; } bucket = kmem_zalloc(sizeof (dtrace_hashbucket_t), KM_SLEEP); bucket->dthb_next = hash->dth_tab[ndx]; hash->dth_tab[ndx] = bucket; hash->dth_nbuckets++; add: nextp = DTRACE_HASHNEXT(hash, new); ASSERT(*nextp == NULL && *(DTRACE_HASHPREV(hash, new)) == NULL); *nextp = bucket->dthb_chain; if (bucket->dthb_chain != NULL) { prevp = DTRACE_HASHPREV(hash, bucket->dthb_chain); ASSERT(*prevp == NULL); *prevp = new; } bucket->dthb_chain = new; bucket->dthb_len++; } static dtrace_probe_t * dtrace_hash_lookup(dtrace_hash_t *hash, dtrace_probe_t *template) { int hashval = DTRACE_HASHSTR(hash, template); int ndx = hashval & hash->dth_mask; dtrace_hashbucket_t *bucket = hash->dth_tab[ndx]; for (; bucket != NULL; bucket = bucket->dthb_next) { if (DTRACE_HASHEQ(hash, bucket->dthb_chain, template)) return (bucket->dthb_chain); } return (NULL); } static int dtrace_hash_collisions(dtrace_hash_t *hash, dtrace_probe_t *template) { int hashval = DTRACE_HASHSTR(hash, template); int ndx = hashval & hash->dth_mask; dtrace_hashbucket_t *bucket = hash->dth_tab[ndx]; for (; bucket != NULL; bucket = bucket->dthb_next) { if (DTRACE_HASHEQ(hash, bucket->dthb_chain, template)) return (bucket->dthb_len); } return (0); } static void dtrace_hash_remove(dtrace_hash_t *hash, dtrace_probe_t *probe) { int ndx = DTRACE_HASHSTR(hash, probe) & hash->dth_mask; dtrace_hashbucket_t *bucket = hash->dth_tab[ndx]; dtrace_probe_t **prevp = DTRACE_HASHPREV(hash, probe); dtrace_probe_t **nextp = DTRACE_HASHNEXT(hash, probe); /* * Find the bucket that we're removing this probe from. */ for (; bucket != NULL; bucket = bucket->dthb_next) { if (DTRACE_HASHEQ(hash, bucket->dthb_chain, probe)) break; } ASSERT(bucket != NULL); if (*prevp == NULL) { if (*nextp == NULL) { /* * The removed probe was the only probe on this * bucket; we need to remove the bucket. */ dtrace_hashbucket_t *b = hash->dth_tab[ndx]; ASSERT(bucket->dthb_chain == probe); ASSERT(b != NULL); if (b == bucket) { hash->dth_tab[ndx] = bucket->dthb_next; } else { while (b->dthb_next != bucket) b = b->dthb_next; b->dthb_next = bucket->dthb_next; } ASSERT(hash->dth_nbuckets > 0); hash->dth_nbuckets--; kmem_free(bucket, sizeof (dtrace_hashbucket_t)); return; } bucket->dthb_chain = *nextp; } else { *(DTRACE_HASHNEXT(hash, *prevp)) = *nextp; } if (*nextp != NULL) *(DTRACE_HASHPREV(hash, *nextp)) = *prevp; } /* * DTrace Utility Functions * * These are random utility functions that are _not_ called from probe context. */ static int dtrace_badattr(const dtrace_attribute_t *a) { return (a->dtat_name > DTRACE_STABILITY_MAX || a->dtat_data > DTRACE_STABILITY_MAX || a->dtat_class > DTRACE_CLASS_MAX); } /* * Return a duplicate copy of a string. If the specified string is NULL, * this function returns a zero-length string. */ static char * dtrace_strdup(const char *str) { char *new = kmem_zalloc((str != NULL ? strlen(str) : 0) + 1, KM_SLEEP); if (str != NULL) (void) strcpy(new, str); return (new); } #define DTRACE_ISALPHA(c) \ (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) static int dtrace_badname(const char *s) { char c; if (s == NULL || (c = *s++) == '\0') return (0); if (!DTRACE_ISALPHA(c) && c != '-' && c != '_' && c != '.') return (1); while ((c = *s++) != '\0') { if (!DTRACE_ISALPHA(c) && (c < '0' || c > '9') && c != '-' && c != '_' && c != '.' && c != '`') return (1); } return (0); } static void dtrace_cred2priv(cred_t *cr, uint32_t *privp, uid_t *uidp, zoneid_t *zoneidp) { uint32_t priv; #ifdef illumos if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) { /* * For DTRACE_PRIV_ALL, the uid and zoneid don't matter. */ priv = DTRACE_PRIV_ALL; } else { *uidp = crgetuid(cr); *zoneidp = crgetzoneid(cr); priv = 0; if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_KERNEL, B_FALSE)) priv |= DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER; else if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_USER, B_FALSE)) priv |= DTRACE_PRIV_USER; if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_PROC, B_FALSE)) priv |= DTRACE_PRIV_PROC; if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, B_FALSE)) priv |= DTRACE_PRIV_OWNER; if (PRIV_POLICY_ONLY(cr, PRIV_PROC_ZONE, B_FALSE)) priv |= DTRACE_PRIV_ZONEOWNER; } #else priv = DTRACE_PRIV_ALL; #endif *privp = priv; } #ifdef DTRACE_ERRDEBUG static void dtrace_errdebug(const char *str) { int hval = dtrace_hash_str(str) % DTRACE_ERRHASHSZ; int occupied = 0; mutex_enter(&dtrace_errlock); dtrace_errlast = str; dtrace_errthread = curthread; while (occupied++ < DTRACE_ERRHASHSZ) { if (dtrace_errhash[hval].dter_msg == str) { dtrace_errhash[hval].dter_count++; goto out; } if (dtrace_errhash[hval].dter_msg != NULL) { hval = (hval + 1) % DTRACE_ERRHASHSZ; continue; } dtrace_errhash[hval].dter_msg = str; dtrace_errhash[hval].dter_count = 1; goto out; } panic("dtrace: undersized error hash"); out: mutex_exit(&dtrace_errlock); } #endif /* * DTrace Matching Functions * * These functions are used to match groups of probes, given some elements of * a probe tuple, or some globbed expressions for elements of a probe tuple. */ static int dtrace_match_priv(const dtrace_probe_t *prp, uint32_t priv, uid_t uid, zoneid_t zoneid) { if (priv != DTRACE_PRIV_ALL) { uint32_t ppriv = prp->dtpr_provider->dtpv_priv.dtpp_flags; uint32_t match = priv & ppriv; /* * No PRIV_DTRACE_* privileges... */ if ((priv & (DTRACE_PRIV_PROC | DTRACE_PRIV_USER | DTRACE_PRIV_KERNEL)) == 0) return (0); /* * No matching bits, but there were bits to match... */ if (match == 0 && ppriv != 0) return (0); /* * Need to have permissions to the process, but don't... */ if (((ppriv & ~match) & DTRACE_PRIV_OWNER) != 0 && uid != prp->dtpr_provider->dtpv_priv.dtpp_uid) { return (0); } /* * Need to be in the same zone unless we possess the * privilege to examine all zones. */ if (((ppriv & ~match) & DTRACE_PRIV_ZONEOWNER) != 0 && zoneid != prp->dtpr_provider->dtpv_priv.dtpp_zoneid) { return (0); } } return (1); } /* * dtrace_match_probe compares a dtrace_probe_t to a pre-compiled key, which * consists of input pattern strings and an ops-vector to evaluate them. * This function returns >0 for match, 0 for no match, and <0 for error. */ static int dtrace_match_probe(const dtrace_probe_t *prp, const dtrace_probekey_t *pkp, uint32_t priv, uid_t uid, zoneid_t zoneid) { dtrace_provider_t *pvp = prp->dtpr_provider; int rv; if (pvp->dtpv_defunct) return (0); if ((rv = pkp->dtpk_pmatch(pvp->dtpv_name, pkp->dtpk_prov, 0)) <= 0) return (rv); if ((rv = pkp->dtpk_mmatch(prp->dtpr_mod, pkp->dtpk_mod, 0)) <= 0) return (rv); if ((rv = pkp->dtpk_fmatch(prp->dtpr_func, pkp->dtpk_func, 0)) <= 0) return (rv); if ((rv = pkp->dtpk_nmatch(prp->dtpr_name, pkp->dtpk_name, 0)) <= 0) return (rv); if (dtrace_match_priv(prp, priv, uid, zoneid) == 0) return (0); return (rv); } /* * dtrace_match_glob() is a safe kernel implementation of the gmatch(3GEN) * interface for matching a glob pattern 'p' to an input string 's'. Unlike * libc's version, the kernel version only applies to 8-bit ASCII strings. * In addition, all of the recursion cases except for '*' matching have been * unwound. For '*', we still implement recursive evaluation, but a depth * counter is maintained and matching is aborted if we recurse too deep. * The function returns 0 if no match, >0 if match, and <0 if recursion error. */ static int dtrace_match_glob(const char *s, const char *p, int depth) { const char *olds; char s1, c; int gs; if (depth > DTRACE_PROBEKEY_MAXDEPTH) return (-1); if (s == NULL) s = ""; /* treat NULL as empty string */ top: olds = s; s1 = *s++; if (p == NULL) return (0); if ((c = *p++) == '\0') return (s1 == '\0'); switch (c) { case '[': { int ok = 0, notflag = 0; char lc = '\0'; if (s1 == '\0') return (0); if (*p == '!') { notflag = 1; p++; } if ((c = *p++) == '\0') return (0); do { if (c == '-' && lc != '\0' && *p != ']') { if ((c = *p++) == '\0') return (0); if (c == '\\' && (c = *p++) == '\0') return (0); if (notflag) { if (s1 < lc || s1 > c) ok++; else return (0); } else if (lc <= s1 && s1 <= c) ok++; } else if (c == '\\' && (c = *p++) == '\0') return (0); lc = c; /* save left-hand 'c' for next iteration */ if (notflag) { if (s1 != c) ok++; else return (0); } else if (s1 == c) ok++; if ((c = *p++) == '\0') return (0); } while (c != ']'); if (ok) goto top; return (0); } case '\\': if ((c = *p++) == '\0') return (0); /*FALLTHRU*/ default: if (c != s1) return (0); /*FALLTHRU*/ case '?': if (s1 != '\0') goto top; return (0); case '*': while (*p == '*') p++; /* consecutive *'s are identical to a single one */ if (*p == '\0') return (1); for (s = olds; *s != '\0'; s++) { if ((gs = dtrace_match_glob(s, p, depth + 1)) != 0) return (gs); } return (0); } } /*ARGSUSED*/ static int dtrace_match_string(const char *s, const char *p, int depth) { return (s != NULL && strcmp(s, p) == 0); } /*ARGSUSED*/ static int dtrace_match_nul(const char *s, const char *p, int depth) { return (1); /* always match the empty pattern */ } /*ARGSUSED*/ static int dtrace_match_nonzero(const char *s, const char *p, int depth) { return (s != NULL && s[0] != '\0'); } static int dtrace_match(const dtrace_probekey_t *pkp, uint32_t priv, uid_t uid, zoneid_t zoneid, int (*matched)(dtrace_probe_t *, void *), void *arg) { dtrace_probe_t template, *probe; dtrace_hash_t *hash = NULL; int len, best = INT_MAX, nmatched = 0; dtrace_id_t i; ASSERT(MUTEX_HELD(&dtrace_lock)); /* * If the probe ID is specified in the key, just lookup by ID and * invoke the match callback once if a matching probe is found. */ if (pkp->dtpk_id != DTRACE_IDNONE) { if ((probe = dtrace_probe_lookup_id(pkp->dtpk_id)) != NULL && dtrace_match_probe(probe, pkp, priv, uid, zoneid) > 0) { (void) (*matched)(probe, arg); nmatched++; } return (nmatched); } template.dtpr_mod = (char *)pkp->dtpk_mod; template.dtpr_func = (char *)pkp->dtpk_func; template.dtpr_name = (char *)pkp->dtpk_name; /* * We want to find the most distinct of the module name, function * name, and name. So for each one that is not a glob pattern or * empty string, we perform a lookup in the corresponding hash and * use the hash table with the fewest collisions to do our search. */ if (pkp->dtpk_mmatch == &dtrace_match_string && (len = dtrace_hash_collisions(dtrace_bymod, &template)) < best) { best = len; hash = dtrace_bymod; } if (pkp->dtpk_fmatch == &dtrace_match_string && (len = dtrace_hash_collisions(dtrace_byfunc, &template)) < best) { best = len; hash = dtrace_byfunc; } if (pkp->dtpk_nmatch == &dtrace_match_string && (len = dtrace_hash_collisions(dtrace_byname, &template)) < best) { best = len; hash = dtrace_byname; } /* * If we did not select a hash table, iterate over every probe and * invoke our callback for each one that matches our input probe key. */ if (hash == NULL) { for (i = 0; i < dtrace_nprobes; i++) { if ((probe = dtrace_probes[i]) == NULL || dtrace_match_probe(probe, pkp, priv, uid, zoneid) <= 0) continue; nmatched++; if ((*matched)(probe, arg) != DTRACE_MATCH_NEXT) break; } return (nmatched); } /* * If we selected a hash table, iterate over each probe of the same key * name and invoke the callback for every probe that matches the other * attributes of our input probe key. */ for (probe = dtrace_hash_lookup(hash, &template); probe != NULL; probe = *(DTRACE_HASHNEXT(hash, probe))) { if (dtrace_match_probe(probe, pkp, priv, uid, zoneid) <= 0) continue; nmatched++; if ((*matched)(probe, arg) != DTRACE_MATCH_NEXT) break; } return (nmatched); } /* * Return the function pointer dtrace_probecmp() should use to compare the * specified pattern with a string. For NULL or empty patterns, we select * dtrace_match_nul(). For glob pattern strings, we use dtrace_match_glob(). * For non-empty non-glob strings, we use dtrace_match_string(). */ static dtrace_probekey_f * dtrace_probekey_func(const char *p) { char c; if (p == NULL || *p == '\0') return (&dtrace_match_nul); while ((c = *p++) != '\0') { if (c == '[' || c == '?' || c == '*' || c == '\\') return (&dtrace_match_glob); } return (&dtrace_match_string); } /* * Build a probe comparison key for use with dtrace_match_probe() from the * given probe description. By convention, a null key only matches anchored * probes: if each field is the empty string, reset dtpk_fmatch to * dtrace_match_nonzero(). */ static void dtrace_probekey(dtrace_probedesc_t *pdp, dtrace_probekey_t *pkp) { pkp->dtpk_prov = pdp->dtpd_provider; pkp->dtpk_pmatch = dtrace_probekey_func(pdp->dtpd_provider); pkp->dtpk_mod = pdp->dtpd_mod; pkp->dtpk_mmatch = dtrace_probekey_func(pdp->dtpd_mod); pkp->dtpk_func = pdp->dtpd_func; pkp->dtpk_fmatch = dtrace_probekey_func(pdp->dtpd_func); pkp->dtpk_name = pdp->dtpd_name; pkp->dtpk_nmatch = dtrace_probekey_func(pdp->dtpd_name); pkp->dtpk_id = pdp->dtpd_id; if (pkp->dtpk_id == DTRACE_IDNONE && pkp->dtpk_pmatch == &dtrace_match_nul && pkp->dtpk_mmatch == &dtrace_match_nul && pkp->dtpk_fmatch == &dtrace_match_nul && pkp->dtpk_nmatch == &dtrace_match_nul) pkp->dtpk_fmatch = &dtrace_match_nonzero; } /* * DTrace Provider-to-Framework API Functions * * These functions implement much of the Provider-to-Framework API, as * described in . The parts of the API not in this section are * the functions in the API for probe management (found below), and * dtrace_probe() itself (found above). */ /* * Register the calling provider with the DTrace framework. This should * generally be called by DTrace providers in their attach(9E) entry point. */ int dtrace_register(const char *name, const dtrace_pattr_t *pap, uint32_t priv, cred_t *cr, const dtrace_pops_t *pops, void *arg, dtrace_provider_id_t *idp) { dtrace_provider_t *provider; if (name == NULL || pap == NULL || pops == NULL || idp == NULL) { cmn_err(CE_WARN, "failed to register provider '%s': invalid " "arguments", name ? name : ""); return (EINVAL); } if (name[0] == '\0' || dtrace_badname(name)) { cmn_err(CE_WARN, "failed to register provider '%s': invalid " "provider name", name); return (EINVAL); } if ((pops->dtps_provide == NULL && pops->dtps_provide_module == NULL) || pops->dtps_enable == NULL || pops->dtps_disable == NULL || pops->dtps_destroy == NULL || ((pops->dtps_resume == NULL) != (pops->dtps_suspend == NULL))) { cmn_err(CE_WARN, "failed to register provider '%s': invalid " "provider ops", name); return (EINVAL); } if (dtrace_badattr(&pap->dtpa_provider) || dtrace_badattr(&pap->dtpa_mod) || dtrace_badattr(&pap->dtpa_func) || dtrace_badattr(&pap->dtpa_name) || dtrace_badattr(&pap->dtpa_args)) { cmn_err(CE_WARN, "failed to register provider '%s': invalid " "provider attributes", name); return (EINVAL); } if (priv & ~DTRACE_PRIV_ALL) { cmn_err(CE_WARN, "failed to register provider '%s': invalid " "privilege attributes", name); return (EINVAL); } if ((priv & DTRACE_PRIV_KERNEL) && (priv & (DTRACE_PRIV_USER | DTRACE_PRIV_OWNER)) && pops->dtps_usermode == NULL) { cmn_err(CE_WARN, "failed to register provider '%s': need " "dtps_usermode() op for given privilege attributes", name); return (EINVAL); } provider = kmem_zalloc(sizeof (dtrace_provider_t), KM_SLEEP); provider->dtpv_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); (void) strcpy(provider->dtpv_name, name); provider->dtpv_attr = *pap; provider->dtpv_priv.dtpp_flags = priv; if (cr != NULL) { provider->dtpv_priv.dtpp_uid = crgetuid(cr); provider->dtpv_priv.dtpp_zoneid = crgetzoneid(cr); } provider->dtpv_pops = *pops; if (pops->dtps_provide == NULL) { ASSERT(pops->dtps_provide_module != NULL); provider->dtpv_pops.dtps_provide = (void (*)(void *, dtrace_probedesc_t *))dtrace_nullop; } if (pops->dtps_provide_module == NULL) { ASSERT(pops->dtps_provide != NULL); provider->dtpv_pops.dtps_provide_module = (void (*)(void *, modctl_t *))dtrace_nullop; } if (pops->dtps_suspend == NULL) { ASSERT(pops->dtps_resume == NULL); provider->dtpv_pops.dtps_suspend = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop; provider->dtpv_pops.dtps_resume = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop; } provider->dtpv_arg = arg; *idp = (dtrace_provider_id_t)provider; if (pops == &dtrace_provider_ops) { ASSERT(MUTEX_HELD(&dtrace_provider_lock)); ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(dtrace_anon.dta_enabling == NULL); /* * We make sure that the DTrace provider is at the head of * the provider chain. */ provider->dtpv_next = dtrace_provider; dtrace_provider = provider; return (0); } mutex_enter(&dtrace_provider_lock); mutex_enter(&dtrace_lock); /* * If there is at least one provider registered, we'll add this * provider after the first provider. */ if (dtrace_provider != NULL) { provider->dtpv_next = dtrace_provider->dtpv_next; dtrace_provider->dtpv_next = provider; } else { dtrace_provider = provider; } if (dtrace_retained != NULL) { dtrace_enabling_provide(provider); /* * Now we need to call dtrace_enabling_matchall() -- which * will acquire cpu_lock and dtrace_lock. We therefore need * to drop all of our locks before calling into it... */ mutex_exit(&dtrace_lock); mutex_exit(&dtrace_provider_lock); dtrace_enabling_matchall(); return (0); } mutex_exit(&dtrace_lock); mutex_exit(&dtrace_provider_lock); return (0); } /* * Unregister the specified provider from the DTrace framework. This should * generally be called by DTrace providers in their detach(9E) entry point. */ int dtrace_unregister(dtrace_provider_id_t id) { dtrace_provider_t *old = (dtrace_provider_t *)id; dtrace_provider_t *prev = NULL; int i, self = 0, noreap = 0; dtrace_probe_t *probe, *first = NULL; if (old->dtpv_pops.dtps_enable == (void (*)(void *, dtrace_id_t, void *))dtrace_nullop) { /* * If DTrace itself is the provider, we're called with locks * already held. */ ASSERT(old == dtrace_provider); #ifdef illumos ASSERT(dtrace_devi != NULL); #endif ASSERT(MUTEX_HELD(&dtrace_provider_lock)); ASSERT(MUTEX_HELD(&dtrace_lock)); self = 1; if (dtrace_provider->dtpv_next != NULL) { /* * There's another provider here; return failure. */ return (EBUSY); } } else { mutex_enter(&dtrace_provider_lock); #ifdef illumos mutex_enter(&mod_lock); #endif mutex_enter(&dtrace_lock); } /* * If anyone has /dev/dtrace open, or if there are anonymous enabled * probes, we refuse to let providers slither away, unless this * provider has already been explicitly invalidated. */ if (!old->dtpv_defunct && (dtrace_opens || (dtrace_anon.dta_state != NULL && dtrace_anon.dta_state->dts_necbs > 0))) { if (!self) { mutex_exit(&dtrace_lock); #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_provider_lock); } return (EBUSY); } /* * Attempt to destroy the probes associated with this provider. */ for (i = 0; i < dtrace_nprobes; i++) { if ((probe = dtrace_probes[i]) == NULL) continue; if (probe->dtpr_provider != old) continue; if (probe->dtpr_ecb == NULL) continue; /* * If we are trying to unregister a defunct provider, and the * provider was made defunct within the interval dictated by * dtrace_unregister_defunct_reap, we'll (asynchronously) * attempt to reap our enablings. To denote that the provider * should reattempt to unregister itself at some point in the * future, we will return a differentiable error code (EAGAIN * instead of EBUSY) in this case. */ if (dtrace_gethrtime() - old->dtpv_defunct > dtrace_unregister_defunct_reap) noreap = 1; if (!self) { mutex_exit(&dtrace_lock); #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_provider_lock); } if (noreap) return (EBUSY); (void) taskq_dispatch(dtrace_taskq, (task_func_t *)dtrace_enabling_reap, NULL, TQ_SLEEP); return (EAGAIN); } /* * All of the probes for this provider are disabled; we can safely * remove all of them from their hash chains and from the probe array. */ for (i = 0; i < dtrace_nprobes; i++) { if ((probe = dtrace_probes[i]) == NULL) continue; if (probe->dtpr_provider != old) continue; dtrace_probes[i] = NULL; dtrace_hash_remove(dtrace_bymod, probe); dtrace_hash_remove(dtrace_byfunc, probe); dtrace_hash_remove(dtrace_byname, probe); if (first == NULL) { first = probe; probe->dtpr_nextmod = NULL; } else { probe->dtpr_nextmod = first; first = probe; } } /* * The provider's probes have been removed from the hash chains and * from the probe array. Now issue a dtrace_sync() to be sure that * everyone has cleared out from any probe array processing. */ dtrace_sync(); for (probe = first; probe != NULL; probe = first) { first = probe->dtpr_nextmod; old->dtpv_pops.dtps_destroy(old->dtpv_arg, probe->dtpr_id, probe->dtpr_arg); kmem_free(probe->dtpr_mod, strlen(probe->dtpr_mod) + 1); kmem_free(probe->dtpr_func, strlen(probe->dtpr_func) + 1); kmem_free(probe->dtpr_name, strlen(probe->dtpr_name) + 1); #ifdef illumos vmem_free(dtrace_arena, (void *)(uintptr_t)(probe->dtpr_id), 1); #else free_unr(dtrace_arena, probe->dtpr_id); #endif kmem_free(probe, sizeof (dtrace_probe_t)); } if ((prev = dtrace_provider) == old) { #ifdef illumos ASSERT(self || dtrace_devi == NULL); ASSERT(old->dtpv_next == NULL || dtrace_devi == NULL); #endif dtrace_provider = old->dtpv_next; } else { while (prev != NULL && prev->dtpv_next != old) prev = prev->dtpv_next; if (prev == NULL) { panic("attempt to unregister non-existent " "dtrace provider %p\n", (void *)id); } prev->dtpv_next = old->dtpv_next; } if (!self) { mutex_exit(&dtrace_lock); #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_provider_lock); } kmem_free(old->dtpv_name, strlen(old->dtpv_name) + 1); kmem_free(old, sizeof (dtrace_provider_t)); return (0); } /* * Invalidate the specified provider. All subsequent probe lookups for the * specified provider will fail, but its probes will not be removed. */ void dtrace_invalidate(dtrace_provider_id_t id) { dtrace_provider_t *pvp = (dtrace_provider_t *)id; ASSERT(pvp->dtpv_pops.dtps_enable != (void (*)(void *, dtrace_id_t, void *))dtrace_nullop); mutex_enter(&dtrace_provider_lock); mutex_enter(&dtrace_lock); pvp->dtpv_defunct = dtrace_gethrtime(); mutex_exit(&dtrace_lock); mutex_exit(&dtrace_provider_lock); } /* * Indicate whether or not DTrace has attached. */ int dtrace_attached(void) { /* * dtrace_provider will be non-NULL iff the DTrace driver has * attached. (It's non-NULL because DTrace is always itself a * provider.) */ return (dtrace_provider != NULL); } /* * Remove all the unenabled probes for the given provider. This function is * not unlike dtrace_unregister(), except that it doesn't remove the provider * -- just as many of its associated probes as it can. */ int dtrace_condense(dtrace_provider_id_t id) { dtrace_provider_t *prov = (dtrace_provider_t *)id; int i; dtrace_probe_t *probe; /* * Make sure this isn't the dtrace provider itself. */ ASSERT(prov->dtpv_pops.dtps_enable != (void (*)(void *, dtrace_id_t, void *))dtrace_nullop); mutex_enter(&dtrace_provider_lock); mutex_enter(&dtrace_lock); /* * Attempt to destroy the probes associated with this provider. */ for (i = 0; i < dtrace_nprobes; i++) { if ((probe = dtrace_probes[i]) == NULL) continue; if (probe->dtpr_provider != prov) continue; if (probe->dtpr_ecb != NULL) continue; dtrace_probes[i] = NULL; dtrace_hash_remove(dtrace_bymod, probe); dtrace_hash_remove(dtrace_byfunc, probe); dtrace_hash_remove(dtrace_byname, probe); prov->dtpv_pops.dtps_destroy(prov->dtpv_arg, i + 1, probe->dtpr_arg); kmem_free(probe->dtpr_mod, strlen(probe->dtpr_mod) + 1); kmem_free(probe->dtpr_func, strlen(probe->dtpr_func) + 1); kmem_free(probe->dtpr_name, strlen(probe->dtpr_name) + 1); kmem_free(probe, sizeof (dtrace_probe_t)); #ifdef illumos vmem_free(dtrace_arena, (void *)((uintptr_t)i + 1), 1); #else free_unr(dtrace_arena, i + 1); #endif } mutex_exit(&dtrace_lock); mutex_exit(&dtrace_provider_lock); return (0); } /* * DTrace Probe Management Functions * * The functions in this section perform the DTrace probe management, * including functions to create probes, look-up probes, and call into the * providers to request that probes be provided. Some of these functions are * in the Provider-to-Framework API; these functions can be identified by the * fact that they are not declared "static". */ /* * Create a probe with the specified module name, function name, and name. */ dtrace_id_t dtrace_probe_create(dtrace_provider_id_t prov, const char *mod, const char *func, const char *name, int aframes, void *arg) { dtrace_probe_t *probe, **probes; dtrace_provider_t *provider = (dtrace_provider_t *)prov; dtrace_id_t id; if (provider == dtrace_provider) { ASSERT(MUTEX_HELD(&dtrace_lock)); } else { mutex_enter(&dtrace_lock); } #ifdef illumos id = (dtrace_id_t)(uintptr_t)vmem_alloc(dtrace_arena, 1, VM_BESTFIT | VM_SLEEP); #else id = alloc_unr(dtrace_arena); #endif probe = kmem_zalloc(sizeof (dtrace_probe_t), KM_SLEEP); probe->dtpr_id = id; probe->dtpr_gen = dtrace_probegen++; probe->dtpr_mod = dtrace_strdup(mod); probe->dtpr_func = dtrace_strdup(func); probe->dtpr_name = dtrace_strdup(name); probe->dtpr_arg = arg; probe->dtpr_aframes = aframes; probe->dtpr_provider = provider; dtrace_hash_add(dtrace_bymod, probe); dtrace_hash_add(dtrace_byfunc, probe); dtrace_hash_add(dtrace_byname, probe); if (id - 1 >= dtrace_nprobes) { size_t osize = dtrace_nprobes * sizeof (dtrace_probe_t *); size_t nsize = osize << 1; if (nsize == 0) { ASSERT(osize == 0); ASSERT(dtrace_probes == NULL); nsize = sizeof (dtrace_probe_t *); } probes = kmem_zalloc(nsize, KM_SLEEP); if (dtrace_probes == NULL) { ASSERT(osize == 0); dtrace_probes = probes; dtrace_nprobes = 1; } else { dtrace_probe_t **oprobes = dtrace_probes; bcopy(oprobes, probes, osize); dtrace_membar_producer(); dtrace_probes = probes; dtrace_sync(); /* * All CPUs are now seeing the new probes array; we can * safely free the old array. */ kmem_free(oprobes, osize); dtrace_nprobes <<= 1; } ASSERT(id - 1 < dtrace_nprobes); } ASSERT(dtrace_probes[id - 1] == NULL); dtrace_probes[id - 1] = probe; if (provider != dtrace_provider) mutex_exit(&dtrace_lock); return (id); } static dtrace_probe_t * dtrace_probe_lookup_id(dtrace_id_t id) { ASSERT(MUTEX_HELD(&dtrace_lock)); if (id == 0 || id > dtrace_nprobes) return (NULL); return (dtrace_probes[id - 1]); } static int dtrace_probe_lookup_match(dtrace_probe_t *probe, void *arg) { *((dtrace_id_t *)arg) = probe->dtpr_id; return (DTRACE_MATCH_DONE); } /* * Look up a probe based on provider and one or more of module name, function * name and probe name. */ dtrace_id_t dtrace_probe_lookup(dtrace_provider_id_t prid, char *mod, char *func, char *name) { dtrace_probekey_t pkey; dtrace_id_t id; int match; pkey.dtpk_prov = ((dtrace_provider_t *)prid)->dtpv_name; pkey.dtpk_pmatch = &dtrace_match_string; pkey.dtpk_mod = mod; pkey.dtpk_mmatch = mod ? &dtrace_match_string : &dtrace_match_nul; pkey.dtpk_func = func; pkey.dtpk_fmatch = func ? &dtrace_match_string : &dtrace_match_nul; pkey.dtpk_name = name; pkey.dtpk_nmatch = name ? &dtrace_match_string : &dtrace_match_nul; pkey.dtpk_id = DTRACE_IDNONE; mutex_enter(&dtrace_lock); match = dtrace_match(&pkey, DTRACE_PRIV_ALL, 0, 0, dtrace_probe_lookup_match, &id); mutex_exit(&dtrace_lock); ASSERT(match == 1 || match == 0); return (match ? id : 0); } /* * Returns the probe argument associated with the specified probe. */ void * dtrace_probe_arg(dtrace_provider_id_t id, dtrace_id_t pid) { dtrace_probe_t *probe; void *rval = NULL; mutex_enter(&dtrace_lock); if ((probe = dtrace_probe_lookup_id(pid)) != NULL && probe->dtpr_provider == (dtrace_provider_t *)id) rval = probe->dtpr_arg; mutex_exit(&dtrace_lock); return (rval); } /* * Copy a probe into a probe description. */ static void dtrace_probe_description(const dtrace_probe_t *prp, dtrace_probedesc_t *pdp) { bzero(pdp, sizeof (dtrace_probedesc_t)); pdp->dtpd_id = prp->dtpr_id; (void) strncpy(pdp->dtpd_provider, prp->dtpr_provider->dtpv_name, DTRACE_PROVNAMELEN - 1); (void) strncpy(pdp->dtpd_mod, prp->dtpr_mod, DTRACE_MODNAMELEN - 1); (void) strncpy(pdp->dtpd_func, prp->dtpr_func, DTRACE_FUNCNAMELEN - 1); (void) strncpy(pdp->dtpd_name, prp->dtpr_name, DTRACE_NAMELEN - 1); } /* * Called to indicate that a probe -- or probes -- should be provided by a * specfied provider. If the specified description is NULL, the provider will * be told to provide all of its probes. (This is done whenever a new * consumer comes along, or whenever a retained enabling is to be matched.) If * the specified description is non-NULL, the provider is given the * opportunity to dynamically provide the specified probe, allowing providers * to support the creation of probes on-the-fly. (So-called _autocreated_ * probes.) If the provider is NULL, the operations will be applied to all * providers; if the provider is non-NULL the operations will only be applied * to the specified provider. The dtrace_provider_lock must be held, and the * dtrace_lock must _not_ be held -- the provider's dtps_provide() operation * will need to grab the dtrace_lock when it reenters the framework through * dtrace_probe_lookup(), dtrace_probe_create(), etc. */ static void dtrace_probe_provide(dtrace_probedesc_t *desc, dtrace_provider_t *prv) { #ifdef illumos modctl_t *ctl; #endif int all = 0; ASSERT(MUTEX_HELD(&dtrace_provider_lock)); if (prv == NULL) { all = 1; prv = dtrace_provider; } do { /* * First, call the blanket provide operation. */ prv->dtpv_pops.dtps_provide(prv->dtpv_arg, desc); #ifdef illumos /* * Now call the per-module provide operation. We will grab * mod_lock to prevent the list from being modified. Note * that this also prevents the mod_busy bits from changing. * (mod_busy can only be changed with mod_lock held.) */ mutex_enter(&mod_lock); ctl = &modules; do { if (ctl->mod_busy || ctl->mod_mp == NULL) continue; prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, ctl); } while ((ctl = ctl->mod_next) != &modules); mutex_exit(&mod_lock); #endif } while (all && (prv = prv->dtpv_next) != NULL); } #ifdef illumos /* * Iterate over each probe, and call the Framework-to-Provider API function * denoted by offs. */ static void dtrace_probe_foreach(uintptr_t offs) { dtrace_provider_t *prov; void (*func)(void *, dtrace_id_t, void *); dtrace_probe_t *probe; dtrace_icookie_t cookie; int i; /* * We disable interrupts to walk through the probe array. This is * safe -- the dtrace_sync() in dtrace_unregister() assures that we * won't see stale data. */ cookie = dtrace_interrupt_disable(); for (i = 0; i < dtrace_nprobes; i++) { if ((probe = dtrace_probes[i]) == NULL) continue; if (probe->dtpr_ecb == NULL) { /* * This probe isn't enabled -- don't call the function. */ continue; } prov = probe->dtpr_provider; func = *((void(**)(void *, dtrace_id_t, void *)) ((uintptr_t)&prov->dtpv_pops + offs)); func(prov->dtpv_arg, i + 1, probe->dtpr_arg); } dtrace_interrupt_enable(cookie); } #endif static int dtrace_probe_enable(dtrace_probedesc_t *desc, dtrace_enabling_t *enab) { dtrace_probekey_t pkey; uint32_t priv; uid_t uid; zoneid_t zoneid; ASSERT(MUTEX_HELD(&dtrace_lock)); dtrace_ecb_create_cache = NULL; if (desc == NULL) { /* * If we're passed a NULL description, we're being asked to * create an ECB with a NULL probe. */ (void) dtrace_ecb_create_enable(NULL, enab); return (0); } dtrace_probekey(desc, &pkey); dtrace_cred2priv(enab->dten_vstate->dtvs_state->dts_cred.dcr_cred, &priv, &uid, &zoneid); return (dtrace_match(&pkey, priv, uid, zoneid, dtrace_ecb_create_enable, enab)); } /* * DTrace Helper Provider Functions */ static void dtrace_dofattr2attr(dtrace_attribute_t *attr, const dof_attr_t dofattr) { attr->dtat_name = DOF_ATTR_NAME(dofattr); attr->dtat_data = DOF_ATTR_DATA(dofattr); attr->dtat_class = DOF_ATTR_CLASS(dofattr); } static void dtrace_dofprov2hprov(dtrace_helper_provdesc_t *hprov, const dof_provider_t *dofprov, char *strtab) { hprov->dthpv_provname = strtab + dofprov->dofpv_name; dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_provider, dofprov->dofpv_provattr); dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_mod, dofprov->dofpv_modattr); dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_func, dofprov->dofpv_funcattr); dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_name, dofprov->dofpv_nameattr); dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_args, dofprov->dofpv_argsattr); } static void dtrace_helper_provide_one(dof_helper_t *dhp, dof_sec_t *sec, pid_t pid) { uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; dof_hdr_t *dof = (dof_hdr_t *)daddr; dof_sec_t *str_sec, *prb_sec, *arg_sec, *off_sec, *enoff_sec; dof_provider_t *provider; dof_probe_t *probe; uint32_t *off, *enoff; uint8_t *arg; char *strtab; uint_t i, nprobes; dtrace_helper_provdesc_t dhpv; dtrace_helper_probedesc_t dhpb; dtrace_meta_t *meta = dtrace_meta_pid; dtrace_mops_t *mops = &meta->dtm_mops; void *parg; provider = (dof_provider_t *)(uintptr_t)(daddr + sec->dofs_offset); str_sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + provider->dofpv_strtab * dof->dofh_secsize); prb_sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + provider->dofpv_probes * dof->dofh_secsize); arg_sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + provider->dofpv_prargs * dof->dofh_secsize); off_sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + provider->dofpv_proffs * dof->dofh_secsize); strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); off = (uint32_t *)(uintptr_t)(daddr + off_sec->dofs_offset); arg = (uint8_t *)(uintptr_t)(daddr + arg_sec->dofs_offset); enoff = NULL; /* * See dtrace_helper_provider_validate(). */ if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && provider->dofpv_prenoffs != DOF_SECT_NONE) { enoff_sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + provider->dofpv_prenoffs * dof->dofh_secsize); enoff = (uint32_t *)(uintptr_t)(daddr + enoff_sec->dofs_offset); } nprobes = prb_sec->dofs_size / prb_sec->dofs_entsize; /* * Create the provider. */ dtrace_dofprov2hprov(&dhpv, provider, strtab); if ((parg = mops->dtms_provide_pid(meta->dtm_arg, &dhpv, pid)) == NULL) return; meta->dtm_count++; /* * Create the probes. */ for (i = 0; i < nprobes; i++) { probe = (dof_probe_t *)(uintptr_t)(daddr + prb_sec->dofs_offset + i * prb_sec->dofs_entsize); /* See the check in dtrace_helper_provider_validate(). */ if (strlen(strtab + probe->dofpr_func) >= DTRACE_FUNCNAMELEN) continue; dhpb.dthpb_mod = dhp->dofhp_mod; dhpb.dthpb_func = strtab + probe->dofpr_func; dhpb.dthpb_name = strtab + probe->dofpr_name; dhpb.dthpb_base = probe->dofpr_addr; dhpb.dthpb_offs = off + probe->dofpr_offidx; dhpb.dthpb_noffs = probe->dofpr_noffs; if (enoff != NULL) { dhpb.dthpb_enoffs = enoff + probe->dofpr_enoffidx; dhpb.dthpb_nenoffs = probe->dofpr_nenoffs; } else { dhpb.dthpb_enoffs = NULL; dhpb.dthpb_nenoffs = 0; } dhpb.dthpb_args = arg + probe->dofpr_argidx; dhpb.dthpb_nargc = probe->dofpr_nargc; dhpb.dthpb_xargc = probe->dofpr_xargc; dhpb.dthpb_ntypes = strtab + probe->dofpr_nargv; dhpb.dthpb_xtypes = strtab + probe->dofpr_xargv; mops->dtms_create_probe(meta->dtm_arg, parg, &dhpb); } } static void dtrace_helper_provide(dof_helper_t *dhp, pid_t pid) { uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; dof_hdr_t *dof = (dof_hdr_t *)daddr; int i; ASSERT(MUTEX_HELD(&dtrace_meta_lock)); for (i = 0; i < dof->dofh_secnum; i++) { dof_sec_t *sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + i * dof->dofh_secsize); if (sec->dofs_type != DOF_SECT_PROVIDER) continue; dtrace_helper_provide_one(dhp, sec, pid); } /* * We may have just created probes, so we must now rematch against * any retained enablings. Note that this call will acquire both * cpu_lock and dtrace_lock; the fact that we are holding * dtrace_meta_lock now is what defines the ordering with respect to * these three locks. */ dtrace_enabling_matchall(); } static void dtrace_helper_provider_remove_one(dof_helper_t *dhp, dof_sec_t *sec, pid_t pid) { uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; dof_hdr_t *dof = (dof_hdr_t *)daddr; dof_sec_t *str_sec; dof_provider_t *provider; char *strtab; dtrace_helper_provdesc_t dhpv; dtrace_meta_t *meta = dtrace_meta_pid; dtrace_mops_t *mops = &meta->dtm_mops; provider = (dof_provider_t *)(uintptr_t)(daddr + sec->dofs_offset); str_sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + provider->dofpv_strtab * dof->dofh_secsize); strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); /* * Create the provider. */ dtrace_dofprov2hprov(&dhpv, provider, strtab); mops->dtms_remove_pid(meta->dtm_arg, &dhpv, pid); meta->dtm_count--; } static void dtrace_helper_provider_remove(dof_helper_t *dhp, pid_t pid) { uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; dof_hdr_t *dof = (dof_hdr_t *)daddr; int i; ASSERT(MUTEX_HELD(&dtrace_meta_lock)); for (i = 0; i < dof->dofh_secnum; i++) { dof_sec_t *sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + i * dof->dofh_secsize); if (sec->dofs_type != DOF_SECT_PROVIDER) continue; dtrace_helper_provider_remove_one(dhp, sec, pid); } } /* * DTrace Meta Provider-to-Framework API Functions * * These functions implement the Meta Provider-to-Framework API, as described * in . */ int dtrace_meta_register(const char *name, const dtrace_mops_t *mops, void *arg, dtrace_meta_provider_id_t *idp) { dtrace_meta_t *meta; dtrace_helpers_t *help, *next; int i; *idp = DTRACE_METAPROVNONE; /* * We strictly don't need the name, but we hold onto it for * debuggability. All hail error queues! */ if (name == NULL) { cmn_err(CE_WARN, "failed to register meta-provider: " "invalid name"); return (EINVAL); } if (mops == NULL || mops->dtms_create_probe == NULL || mops->dtms_provide_pid == NULL || mops->dtms_remove_pid == NULL) { cmn_err(CE_WARN, "failed to register meta-register %s: " "invalid ops", name); return (EINVAL); } meta = kmem_zalloc(sizeof (dtrace_meta_t), KM_SLEEP); meta->dtm_mops = *mops; meta->dtm_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); (void) strcpy(meta->dtm_name, name); meta->dtm_arg = arg; mutex_enter(&dtrace_meta_lock); mutex_enter(&dtrace_lock); if (dtrace_meta_pid != NULL) { mutex_exit(&dtrace_lock); mutex_exit(&dtrace_meta_lock); cmn_err(CE_WARN, "failed to register meta-register %s: " "user-land meta-provider exists", name); kmem_free(meta->dtm_name, strlen(meta->dtm_name) + 1); kmem_free(meta, sizeof (dtrace_meta_t)); return (EINVAL); } dtrace_meta_pid = meta; *idp = (dtrace_meta_provider_id_t)meta; /* * If there are providers and probes ready to go, pass them * off to the new meta provider now. */ help = dtrace_deferred_pid; dtrace_deferred_pid = NULL; mutex_exit(&dtrace_lock); while (help != NULL) { for (i = 0; i < help->dthps_nprovs; i++) { dtrace_helper_provide(&help->dthps_provs[i]->dthp_prov, help->dthps_pid); } next = help->dthps_next; help->dthps_next = NULL; help->dthps_prev = NULL; help->dthps_deferred = 0; help = next; } mutex_exit(&dtrace_meta_lock); return (0); } int dtrace_meta_unregister(dtrace_meta_provider_id_t id) { dtrace_meta_t **pp, *old = (dtrace_meta_t *)id; mutex_enter(&dtrace_meta_lock); mutex_enter(&dtrace_lock); if (old == dtrace_meta_pid) { pp = &dtrace_meta_pid; } else { panic("attempt to unregister non-existent " "dtrace meta-provider %p\n", (void *)old); } if (old->dtm_count != 0) { mutex_exit(&dtrace_lock); mutex_exit(&dtrace_meta_lock); return (EBUSY); } *pp = NULL; mutex_exit(&dtrace_lock); mutex_exit(&dtrace_meta_lock); kmem_free(old->dtm_name, strlen(old->dtm_name) + 1); kmem_free(old, sizeof (dtrace_meta_t)); return (0); } /* * DTrace DIF Object Functions */ static int dtrace_difo_err(uint_t pc, const char *format, ...) { if (dtrace_err_verbose) { va_list alist; (void) uprintf("dtrace DIF object error: [%u]: ", pc); va_start(alist, format); (void) vuprintf(format, alist); va_end(alist); } #ifdef DTRACE_ERRDEBUG dtrace_errdebug(format); #endif return (1); } /* * Validate a DTrace DIF object by checking the IR instructions. The following * rules are currently enforced by dtrace_difo_validate(): * * 1. Each instruction must have a valid opcode * 2. Each register, string, variable, or subroutine reference must be valid * 3. No instruction can modify register %r0 (must be zero) * 4. All instruction reserved bits must be set to zero * 5. The last instruction must be a "ret" instruction * 6. All branch targets must reference a valid instruction _after_ the branch */ static int dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs, cred_t *cr) { int err = 0, i; int (*efunc)(uint_t pc, const char *, ...) = dtrace_difo_err; int kcheckload; uint_t pc; int maxglobal = -1, maxlocal = -1, maxtlocal = -1; kcheckload = cr == NULL || (vstate->dtvs_state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL) == 0; dp->dtdo_destructive = 0; for (pc = 0; pc < dp->dtdo_len && err == 0; pc++) { dif_instr_t instr = dp->dtdo_buf[pc]; uint_t r1 = DIF_INSTR_R1(instr); uint_t r2 = DIF_INSTR_R2(instr); uint_t rd = DIF_INSTR_RD(instr); uint_t rs = DIF_INSTR_RS(instr); uint_t label = DIF_INSTR_LABEL(instr); uint_t v = DIF_INSTR_VAR(instr); uint_t subr = DIF_INSTR_SUBR(instr); uint_t type = DIF_INSTR_TYPE(instr); uint_t op = DIF_INSTR_OP(instr); switch (op) { case DIF_OP_OR: case DIF_OP_XOR: case DIF_OP_AND: case DIF_OP_SLL: case DIF_OP_SRL: case DIF_OP_SRA: case DIF_OP_SUB: case DIF_OP_ADD: case DIF_OP_MUL: case DIF_OP_SDIV: case DIF_OP_UDIV: case DIF_OP_SREM: case DIF_OP_UREM: case DIF_OP_COPYS: if (r1 >= nregs) err += efunc(pc, "invalid register %u\n", r1); if (r2 >= nregs) err += efunc(pc, "invalid register %u\n", r2); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); break; case DIF_OP_NOT: case DIF_OP_MOV: case DIF_OP_ALLOCS: if (r1 >= nregs) err += efunc(pc, "invalid register %u\n", r1); if (r2 != 0) err += efunc(pc, "non-zero reserved bits\n"); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); break; case DIF_OP_LDSB: case DIF_OP_LDSH: case DIF_OP_LDSW: case DIF_OP_LDUB: case DIF_OP_LDUH: case DIF_OP_LDUW: case DIF_OP_LDX: if (r1 >= nregs) err += efunc(pc, "invalid register %u\n", r1); if (r2 != 0) err += efunc(pc, "non-zero reserved bits\n"); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); if (kcheckload) dp->dtdo_buf[pc] = DIF_INSTR_LOAD(op + DIF_OP_RLDSB - DIF_OP_LDSB, r1, rd); break; case DIF_OP_RLDSB: case DIF_OP_RLDSH: case DIF_OP_RLDSW: case DIF_OP_RLDUB: case DIF_OP_RLDUH: case DIF_OP_RLDUW: case DIF_OP_RLDX: if (r1 >= nregs) err += efunc(pc, "invalid register %u\n", r1); if (r2 != 0) err += efunc(pc, "non-zero reserved bits\n"); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); break; case DIF_OP_ULDSB: case DIF_OP_ULDSH: case DIF_OP_ULDSW: case DIF_OP_ULDUB: case DIF_OP_ULDUH: case DIF_OP_ULDUW: case DIF_OP_ULDX: if (r1 >= nregs) err += efunc(pc, "invalid register %u\n", r1); if (r2 != 0) err += efunc(pc, "non-zero reserved bits\n"); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); break; case DIF_OP_STB: case DIF_OP_STH: case DIF_OP_STW: case DIF_OP_STX: if (r1 >= nregs) err += efunc(pc, "invalid register %u\n", r1); if (r2 != 0) err += efunc(pc, "non-zero reserved bits\n"); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to 0 address\n"); break; case DIF_OP_CMP: case DIF_OP_SCMP: if (r1 >= nregs) err += efunc(pc, "invalid register %u\n", r1); if (r2 >= nregs) err += efunc(pc, "invalid register %u\n", r2); if (rd != 0) err += efunc(pc, "non-zero reserved bits\n"); break; case DIF_OP_TST: if (r1 >= nregs) err += efunc(pc, "invalid register %u\n", r1); if (r2 != 0 || rd != 0) err += efunc(pc, "non-zero reserved bits\n"); break; case DIF_OP_BA: case DIF_OP_BE: case DIF_OP_BNE: case DIF_OP_BG: case DIF_OP_BGU: case DIF_OP_BGE: case DIF_OP_BGEU: case DIF_OP_BL: case DIF_OP_BLU: case DIF_OP_BLE: case DIF_OP_BLEU: if (label >= dp->dtdo_len) { err += efunc(pc, "invalid branch target %u\n", label); } if (label <= pc) { err += efunc(pc, "backward branch to %u\n", label); } break; case DIF_OP_RET: if (r1 != 0 || r2 != 0) err += efunc(pc, "non-zero reserved bits\n"); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); break; case DIF_OP_NOP: case DIF_OP_POPTS: case DIF_OP_FLUSHTS: if (r1 != 0 || r2 != 0 || rd != 0) err += efunc(pc, "non-zero reserved bits\n"); break; case DIF_OP_SETX: if (DIF_INSTR_INTEGER(instr) >= dp->dtdo_intlen) { err += efunc(pc, "invalid integer ref %u\n", DIF_INSTR_INTEGER(instr)); } if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); break; case DIF_OP_SETS: if (DIF_INSTR_STRING(instr) >= dp->dtdo_strlen) { err += efunc(pc, "invalid string ref %u\n", DIF_INSTR_STRING(instr)); } if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); break; case DIF_OP_LDGA: case DIF_OP_LDTA: if (r1 > DIF_VAR_ARRAY_MAX) err += efunc(pc, "invalid array %u\n", r1); if (r2 >= nregs) err += efunc(pc, "invalid register %u\n", r2); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); break; case DIF_OP_LDGS: case DIF_OP_LDTS: case DIF_OP_LDLS: case DIF_OP_LDGAA: case DIF_OP_LDTAA: if (v < DIF_VAR_OTHER_MIN || v > DIF_VAR_OTHER_MAX) err += efunc(pc, "invalid variable %u\n", v); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); break; case DIF_OP_STGS: case DIF_OP_STTS: case DIF_OP_STLS: case DIF_OP_STGAA: case DIF_OP_STTAA: if (v < DIF_VAR_OTHER_UBASE || v > DIF_VAR_OTHER_MAX) err += efunc(pc, "invalid variable %u\n", v); if (rs >= nregs) err += efunc(pc, "invalid register %u\n", rd); break; case DIF_OP_CALL: if (subr > DIF_SUBR_MAX) err += efunc(pc, "invalid subr %u\n", subr); if (rd >= nregs) err += efunc(pc, "invalid register %u\n", rd); if (rd == 0) err += efunc(pc, "cannot write to %r0\n"); if (subr == DIF_SUBR_COPYOUT || subr == DIF_SUBR_COPYOUTSTR) { dp->dtdo_destructive = 1; } if (subr == DIF_SUBR_GETF) { /* * If we have a getf() we need to record that * in our state. Note that our state can be * NULL if this is a helper -- but in that * case, the call to getf() is itself illegal, * and will be caught (slightly later) when * the helper is validated. */ if (vstate->dtvs_state != NULL) vstate->dtvs_state->dts_getf++; } break; case DIF_OP_PUSHTR: if (type != DIF_TYPE_STRING && type != DIF_TYPE_CTF) err += efunc(pc, "invalid ref type %u\n", type); if (r2 >= nregs) err += efunc(pc, "invalid register %u\n", r2); if (rs >= nregs) err += efunc(pc, "invalid register %u\n", rs); break; case DIF_OP_PUSHTV: if (type != DIF_TYPE_CTF) err += efunc(pc, "invalid val type %u\n", type); if (r2 >= nregs) err += efunc(pc, "invalid register %u\n", r2); if (rs >= nregs) err += efunc(pc, "invalid register %u\n", rs); break; default: err += efunc(pc, "invalid opcode %u\n", DIF_INSTR_OP(instr)); } } if (dp->dtdo_len != 0 && DIF_INSTR_OP(dp->dtdo_buf[dp->dtdo_len - 1]) != DIF_OP_RET) { err += efunc(dp->dtdo_len - 1, "expected 'ret' as last DIF instruction\n"); } if (!(dp->dtdo_rtype.dtdt_flags & (DIF_TF_BYREF | DIF_TF_BYUREF))) { /* * If we're not returning by reference, the size must be either * 0 or the size of one of the base types. */ switch (dp->dtdo_rtype.dtdt_size) { case 0: case sizeof (uint8_t): case sizeof (uint16_t): case sizeof (uint32_t): case sizeof (uint64_t): break; default: err += efunc(dp->dtdo_len - 1, "bad return size\n"); } } for (i = 0; i < dp->dtdo_varlen && err == 0; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i], *existing = NULL; dtrace_diftype_t *vt, *et; uint_t id, ndx; if (v->dtdv_scope != DIFV_SCOPE_GLOBAL && v->dtdv_scope != DIFV_SCOPE_THREAD && v->dtdv_scope != DIFV_SCOPE_LOCAL) { err += efunc(i, "unrecognized variable scope %d\n", v->dtdv_scope); break; } if (v->dtdv_kind != DIFV_KIND_ARRAY && v->dtdv_kind != DIFV_KIND_SCALAR) { err += efunc(i, "unrecognized variable type %d\n", v->dtdv_kind); break; } if ((id = v->dtdv_id) > DIF_VARIABLE_MAX) { err += efunc(i, "%d exceeds variable id limit\n", id); break; } if (id < DIF_VAR_OTHER_UBASE) continue; /* * For user-defined variables, we need to check that this * definition is identical to any previous definition that we * encountered. */ ndx = id - DIF_VAR_OTHER_UBASE; switch (v->dtdv_scope) { case DIFV_SCOPE_GLOBAL: if (maxglobal == -1 || ndx > maxglobal) maxglobal = ndx; if (ndx < vstate->dtvs_nglobals) { dtrace_statvar_t *svar; if ((svar = vstate->dtvs_globals[ndx]) != NULL) existing = &svar->dtsv_var; } break; case DIFV_SCOPE_THREAD: if (maxtlocal == -1 || ndx > maxtlocal) maxtlocal = ndx; if (ndx < vstate->dtvs_ntlocals) existing = &vstate->dtvs_tlocals[ndx]; break; case DIFV_SCOPE_LOCAL: if (maxlocal == -1 || ndx > maxlocal) maxlocal = ndx; if (ndx < vstate->dtvs_nlocals) { dtrace_statvar_t *svar; if ((svar = vstate->dtvs_locals[ndx]) != NULL) existing = &svar->dtsv_var; } break; } vt = &v->dtdv_type; if (vt->dtdt_flags & DIF_TF_BYREF) { if (vt->dtdt_size == 0) { err += efunc(i, "zero-sized variable\n"); break; } if ((v->dtdv_scope == DIFV_SCOPE_GLOBAL || v->dtdv_scope == DIFV_SCOPE_LOCAL) && vt->dtdt_size > dtrace_statvar_maxsize) { err += efunc(i, "oversized by-ref static\n"); break; } } if (existing == NULL || existing->dtdv_id == 0) continue; ASSERT(existing->dtdv_id == v->dtdv_id); ASSERT(existing->dtdv_scope == v->dtdv_scope); if (existing->dtdv_kind != v->dtdv_kind) err += efunc(i, "%d changed variable kind\n", id); et = &existing->dtdv_type; if (vt->dtdt_flags != et->dtdt_flags) { err += efunc(i, "%d changed variable type flags\n", id); break; } if (vt->dtdt_size != 0 && vt->dtdt_size != et->dtdt_size) { err += efunc(i, "%d changed variable type size\n", id); break; } } for (pc = 0; pc < dp->dtdo_len && err == 0; pc++) { dif_instr_t instr = dp->dtdo_buf[pc]; uint_t v = DIF_INSTR_VAR(instr); uint_t op = DIF_INSTR_OP(instr); switch (op) { case DIF_OP_LDGS: case DIF_OP_LDGAA: case DIF_OP_STGS: case DIF_OP_STGAA: if (v > DIF_VAR_OTHER_UBASE + maxglobal) err += efunc(pc, "invalid variable %u\n", v); break; case DIF_OP_LDTS: case DIF_OP_LDTAA: case DIF_OP_STTS: case DIF_OP_STTAA: if (v > DIF_VAR_OTHER_UBASE + maxtlocal) err += efunc(pc, "invalid variable %u\n", v); break; case DIF_OP_LDLS: case DIF_OP_STLS: if (v > DIF_VAR_OTHER_UBASE + maxlocal) err += efunc(pc, "invalid variable %u\n", v); break; default: break; } } return (err); } /* * Validate a DTrace DIF object that it is to be used as a helper. Helpers * are much more constrained than normal DIFOs. Specifically, they may * not: * * 1. Make calls to subroutines other than copyin(), copyinstr() or * miscellaneous string routines * 2. Access DTrace variables other than the args[] array, and the * curthread, pid, ppid, tid, execname, zonename, uid and gid variables. * 3. Have thread-local variables. * 4. Have dynamic variables. */ static int dtrace_difo_validate_helper(dtrace_difo_t *dp) { int (*efunc)(uint_t pc, const char *, ...) = dtrace_difo_err; int err = 0; uint_t pc; for (pc = 0; pc < dp->dtdo_len; pc++) { dif_instr_t instr = dp->dtdo_buf[pc]; uint_t v = DIF_INSTR_VAR(instr); uint_t subr = DIF_INSTR_SUBR(instr); uint_t op = DIF_INSTR_OP(instr); switch (op) { case DIF_OP_OR: case DIF_OP_XOR: case DIF_OP_AND: case DIF_OP_SLL: case DIF_OP_SRL: case DIF_OP_SRA: case DIF_OP_SUB: case DIF_OP_ADD: case DIF_OP_MUL: case DIF_OP_SDIV: case DIF_OP_UDIV: case DIF_OP_SREM: case DIF_OP_UREM: case DIF_OP_COPYS: case DIF_OP_NOT: case DIF_OP_MOV: case DIF_OP_RLDSB: case DIF_OP_RLDSH: case DIF_OP_RLDSW: case DIF_OP_RLDUB: case DIF_OP_RLDUH: case DIF_OP_RLDUW: case DIF_OP_RLDX: case DIF_OP_ULDSB: case DIF_OP_ULDSH: case DIF_OP_ULDSW: case DIF_OP_ULDUB: case DIF_OP_ULDUH: case DIF_OP_ULDUW: case DIF_OP_ULDX: case DIF_OP_STB: case DIF_OP_STH: case DIF_OP_STW: case DIF_OP_STX: case DIF_OP_ALLOCS: case DIF_OP_CMP: case DIF_OP_SCMP: case DIF_OP_TST: case DIF_OP_BA: case DIF_OP_BE: case DIF_OP_BNE: case DIF_OP_BG: case DIF_OP_BGU: case DIF_OP_BGE: case DIF_OP_BGEU: case DIF_OP_BL: case DIF_OP_BLU: case DIF_OP_BLE: case DIF_OP_BLEU: case DIF_OP_RET: case DIF_OP_NOP: case DIF_OP_POPTS: case DIF_OP_FLUSHTS: case DIF_OP_SETX: case DIF_OP_SETS: case DIF_OP_LDGA: case DIF_OP_LDLS: case DIF_OP_STGS: case DIF_OP_STLS: case DIF_OP_PUSHTR: case DIF_OP_PUSHTV: break; case DIF_OP_LDGS: if (v >= DIF_VAR_OTHER_UBASE) break; if (v >= DIF_VAR_ARG0 && v <= DIF_VAR_ARG9) break; if (v == DIF_VAR_CURTHREAD || v == DIF_VAR_PID || v == DIF_VAR_PPID || v == DIF_VAR_TID || v == DIF_VAR_EXECARGS || v == DIF_VAR_EXECNAME || v == DIF_VAR_ZONENAME || v == DIF_VAR_UID || v == DIF_VAR_GID) break; err += efunc(pc, "illegal variable %u\n", v); break; case DIF_OP_LDTA: case DIF_OP_LDTS: case DIF_OP_LDGAA: case DIF_OP_LDTAA: err += efunc(pc, "illegal dynamic variable load\n"); break; case DIF_OP_STTS: case DIF_OP_STGAA: case DIF_OP_STTAA: err += efunc(pc, "illegal dynamic variable store\n"); break; case DIF_OP_CALL: if (subr == DIF_SUBR_ALLOCA || subr == DIF_SUBR_BCOPY || subr == DIF_SUBR_COPYIN || subr == DIF_SUBR_COPYINTO || subr == DIF_SUBR_COPYINSTR || subr == DIF_SUBR_INDEX || subr == DIF_SUBR_INET_NTOA || subr == DIF_SUBR_INET_NTOA6 || subr == DIF_SUBR_INET_NTOP || subr == DIF_SUBR_JSON || subr == DIF_SUBR_LLTOSTR || subr == DIF_SUBR_STRTOLL || subr == DIF_SUBR_RINDEX || subr == DIF_SUBR_STRCHR || subr == DIF_SUBR_STRJOIN || subr == DIF_SUBR_STRRCHR || subr == DIF_SUBR_STRSTR || subr == DIF_SUBR_HTONS || subr == DIF_SUBR_HTONL || subr == DIF_SUBR_HTONLL || subr == DIF_SUBR_NTOHS || subr == DIF_SUBR_NTOHL || subr == DIF_SUBR_NTOHLL || subr == DIF_SUBR_MEMREF) break; #ifdef __FreeBSD__ if (subr == DIF_SUBR_MEMSTR) break; #endif err += efunc(pc, "invalid subr %u\n", subr); break; default: err += efunc(pc, "invalid opcode %u\n", DIF_INSTR_OP(instr)); } } return (err); } /* * Returns 1 if the expression in the DIF object can be cached on a per-thread * basis; 0 if not. */ static int dtrace_difo_cacheable(dtrace_difo_t *dp) { int i; if (dp == NULL) return (0); for (i = 0; i < dp->dtdo_varlen; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i]; if (v->dtdv_scope != DIFV_SCOPE_GLOBAL) continue; switch (v->dtdv_id) { case DIF_VAR_CURTHREAD: case DIF_VAR_PID: case DIF_VAR_TID: case DIF_VAR_EXECARGS: case DIF_VAR_EXECNAME: case DIF_VAR_ZONENAME: break; default: return (0); } } /* * This DIF object may be cacheable. Now we need to look for any * array loading instructions, any memory loading instructions, or * any stores to thread-local variables. */ for (i = 0; i < dp->dtdo_len; i++) { uint_t op = DIF_INSTR_OP(dp->dtdo_buf[i]); if ((op >= DIF_OP_LDSB && op <= DIF_OP_LDX) || (op >= DIF_OP_ULDSB && op <= DIF_OP_ULDX) || (op >= DIF_OP_RLDSB && op <= DIF_OP_RLDX) || op == DIF_OP_LDGA || op == DIF_OP_STTS) return (0); } return (1); } static void dtrace_difo_hold(dtrace_difo_t *dp) { int i; ASSERT(MUTEX_HELD(&dtrace_lock)); dp->dtdo_refcnt++; ASSERT(dp->dtdo_refcnt != 0); /* * We need to check this DIF object for references to the variable * DIF_VAR_VTIMESTAMP. */ for (i = 0; i < dp->dtdo_varlen; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i]; if (v->dtdv_id != DIF_VAR_VTIMESTAMP) continue; if (dtrace_vtime_references++ == 0) dtrace_vtime_enable(); } } /* * This routine calculates the dynamic variable chunksize for a given DIF * object. The calculation is not fool-proof, and can probably be tricked by * malicious DIF -- but it works for all compiler-generated DIF. Because this * calculation is likely imperfect, dtrace_dynvar() is able to gracefully fail * if a dynamic variable size exceeds the chunksize. */ static void dtrace_difo_chunksize(dtrace_difo_t *dp, dtrace_vstate_t *vstate) { uint64_t sval = 0; dtrace_key_t tupregs[DIF_DTR_NREGS + 2]; /* +2 for thread and id */ const dif_instr_t *text = dp->dtdo_buf; uint_t pc, srd = 0; uint_t ttop = 0; size_t size, ksize; uint_t id, i; for (pc = 0; pc < dp->dtdo_len; pc++) { dif_instr_t instr = text[pc]; uint_t op = DIF_INSTR_OP(instr); uint_t rd = DIF_INSTR_RD(instr); uint_t r1 = DIF_INSTR_R1(instr); uint_t nkeys = 0; uchar_t scope = 0; dtrace_key_t *key = tupregs; switch (op) { case DIF_OP_SETX: sval = dp->dtdo_inttab[DIF_INSTR_INTEGER(instr)]; srd = rd; continue; case DIF_OP_STTS: key = &tupregs[DIF_DTR_NREGS]; key[0].dttk_size = 0; key[1].dttk_size = 0; nkeys = 2; scope = DIFV_SCOPE_THREAD; break; case DIF_OP_STGAA: case DIF_OP_STTAA: nkeys = ttop; if (DIF_INSTR_OP(instr) == DIF_OP_STTAA) key[nkeys++].dttk_size = 0; key[nkeys++].dttk_size = 0; if (op == DIF_OP_STTAA) { scope = DIFV_SCOPE_THREAD; } else { scope = DIFV_SCOPE_GLOBAL; } break; case DIF_OP_PUSHTR: if (ttop == DIF_DTR_NREGS) return; if ((srd == 0 || sval == 0) && r1 == DIF_TYPE_STRING) { /* * If the register for the size of the "pushtr" * is %r0 (or the value is 0) and the type is * a string, we'll use the system-wide default * string size. */ tupregs[ttop++].dttk_size = dtrace_strsize_default; } else { if (srd == 0) return; if (sval > LONG_MAX) return; tupregs[ttop++].dttk_size = sval; } break; case DIF_OP_PUSHTV: if (ttop == DIF_DTR_NREGS) return; tupregs[ttop++].dttk_size = 0; break; case DIF_OP_FLUSHTS: ttop = 0; break; case DIF_OP_POPTS: if (ttop != 0) ttop--; break; } sval = 0; srd = 0; if (nkeys == 0) continue; /* * We have a dynamic variable allocation; calculate its size. */ for (ksize = 0, i = 0; i < nkeys; i++) ksize += P2ROUNDUP(key[i].dttk_size, sizeof (uint64_t)); size = sizeof (dtrace_dynvar_t); size += sizeof (dtrace_key_t) * (nkeys - 1); size += ksize; /* * Now we need to determine the size of the stored data. */ id = DIF_INSTR_VAR(instr); for (i = 0; i < dp->dtdo_varlen; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i]; if (v->dtdv_id == id && v->dtdv_scope == scope) { size += v->dtdv_type.dtdt_size; break; } } if (i == dp->dtdo_varlen) return; /* * We have the size. If this is larger than the chunk size * for our dynamic variable state, reset the chunk size. */ size = P2ROUNDUP(size, sizeof (uint64_t)); /* * Before setting the chunk size, check that we're not going * to set it to a negative value... */ if (size > LONG_MAX) return; /* * ...and make certain that we didn't badly overflow. */ if (size < ksize || size < sizeof (dtrace_dynvar_t)) return; if (size > vstate->dtvs_dynvars.dtds_chunksize) vstate->dtvs_dynvars.dtds_chunksize = size; } } static void dtrace_difo_init(dtrace_difo_t *dp, dtrace_vstate_t *vstate) { int i, oldsvars, osz, nsz, otlocals, ntlocals; uint_t id; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(dp->dtdo_buf != NULL && dp->dtdo_len != 0); for (i = 0; i < dp->dtdo_varlen; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i]; dtrace_statvar_t *svar, ***svarp = NULL; size_t dsize = 0; uint8_t scope = v->dtdv_scope; int *np = NULL; if ((id = v->dtdv_id) < DIF_VAR_OTHER_UBASE) continue; id -= DIF_VAR_OTHER_UBASE; switch (scope) { case DIFV_SCOPE_THREAD: while (id >= (otlocals = vstate->dtvs_ntlocals)) { dtrace_difv_t *tlocals; if ((ntlocals = (otlocals << 1)) == 0) ntlocals = 1; osz = otlocals * sizeof (dtrace_difv_t); nsz = ntlocals * sizeof (dtrace_difv_t); tlocals = kmem_zalloc(nsz, KM_SLEEP); if (osz != 0) { bcopy(vstate->dtvs_tlocals, tlocals, osz); kmem_free(vstate->dtvs_tlocals, osz); } vstate->dtvs_tlocals = tlocals; vstate->dtvs_ntlocals = ntlocals; } vstate->dtvs_tlocals[id] = *v; continue; case DIFV_SCOPE_LOCAL: np = &vstate->dtvs_nlocals; svarp = &vstate->dtvs_locals; if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) dsize = NCPU * (v->dtdv_type.dtdt_size + sizeof (uint64_t)); else dsize = NCPU * sizeof (uint64_t); break; case DIFV_SCOPE_GLOBAL: np = &vstate->dtvs_nglobals; svarp = &vstate->dtvs_globals; if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) dsize = v->dtdv_type.dtdt_size + sizeof (uint64_t); break; default: ASSERT(0); } while (id >= (oldsvars = *np)) { dtrace_statvar_t **statics; int newsvars, oldsize, newsize; if ((newsvars = (oldsvars << 1)) == 0) newsvars = 1; oldsize = oldsvars * sizeof (dtrace_statvar_t *); newsize = newsvars * sizeof (dtrace_statvar_t *); statics = kmem_zalloc(newsize, KM_SLEEP); if (oldsize != 0) { bcopy(*svarp, statics, oldsize); kmem_free(*svarp, oldsize); } *svarp = statics; *np = newsvars; } if ((svar = (*svarp)[id]) == NULL) { svar = kmem_zalloc(sizeof (dtrace_statvar_t), KM_SLEEP); svar->dtsv_var = *v; if ((svar->dtsv_size = dsize) != 0) { svar->dtsv_data = (uint64_t)(uintptr_t) kmem_zalloc(dsize, KM_SLEEP); } (*svarp)[id] = svar; } svar->dtsv_refcnt++; } dtrace_difo_chunksize(dp, vstate); dtrace_difo_hold(dp); } static dtrace_difo_t * dtrace_difo_duplicate(dtrace_difo_t *dp, dtrace_vstate_t *vstate) { dtrace_difo_t *new; size_t sz; ASSERT(dp->dtdo_buf != NULL); ASSERT(dp->dtdo_refcnt != 0); new = kmem_zalloc(sizeof (dtrace_difo_t), KM_SLEEP); ASSERT(dp->dtdo_buf != NULL); sz = dp->dtdo_len * sizeof (dif_instr_t); new->dtdo_buf = kmem_alloc(sz, KM_SLEEP); bcopy(dp->dtdo_buf, new->dtdo_buf, sz); new->dtdo_len = dp->dtdo_len; if (dp->dtdo_strtab != NULL) { ASSERT(dp->dtdo_strlen != 0); new->dtdo_strtab = kmem_alloc(dp->dtdo_strlen, KM_SLEEP); bcopy(dp->dtdo_strtab, new->dtdo_strtab, dp->dtdo_strlen); new->dtdo_strlen = dp->dtdo_strlen; } if (dp->dtdo_inttab != NULL) { ASSERT(dp->dtdo_intlen != 0); sz = dp->dtdo_intlen * sizeof (uint64_t); new->dtdo_inttab = kmem_alloc(sz, KM_SLEEP); bcopy(dp->dtdo_inttab, new->dtdo_inttab, sz); new->dtdo_intlen = dp->dtdo_intlen; } if (dp->dtdo_vartab != NULL) { ASSERT(dp->dtdo_varlen != 0); sz = dp->dtdo_varlen * sizeof (dtrace_difv_t); new->dtdo_vartab = kmem_alloc(sz, KM_SLEEP); bcopy(dp->dtdo_vartab, new->dtdo_vartab, sz); new->dtdo_varlen = dp->dtdo_varlen; } dtrace_difo_init(new, vstate); return (new); } static void dtrace_difo_destroy(dtrace_difo_t *dp, dtrace_vstate_t *vstate) { int i; ASSERT(dp->dtdo_refcnt == 0); for (i = 0; i < dp->dtdo_varlen; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i]; dtrace_statvar_t *svar, **svarp = NULL; uint_t id; uint8_t scope = v->dtdv_scope; int *np = NULL; switch (scope) { case DIFV_SCOPE_THREAD: continue; case DIFV_SCOPE_LOCAL: np = &vstate->dtvs_nlocals; svarp = vstate->dtvs_locals; break; case DIFV_SCOPE_GLOBAL: np = &vstate->dtvs_nglobals; svarp = vstate->dtvs_globals; break; default: ASSERT(0); } if ((id = v->dtdv_id) < DIF_VAR_OTHER_UBASE) continue; id -= DIF_VAR_OTHER_UBASE; ASSERT(id < *np); svar = svarp[id]; ASSERT(svar != NULL); ASSERT(svar->dtsv_refcnt > 0); if (--svar->dtsv_refcnt > 0) continue; if (svar->dtsv_size != 0) { ASSERT(svar->dtsv_data != 0); kmem_free((void *)(uintptr_t)svar->dtsv_data, svar->dtsv_size); } kmem_free(svar, sizeof (dtrace_statvar_t)); svarp[id] = NULL; } if (dp->dtdo_buf != NULL) kmem_free(dp->dtdo_buf, dp->dtdo_len * sizeof (dif_instr_t)); if (dp->dtdo_inttab != NULL) kmem_free(dp->dtdo_inttab, dp->dtdo_intlen * sizeof (uint64_t)); if (dp->dtdo_strtab != NULL) kmem_free(dp->dtdo_strtab, dp->dtdo_strlen); if (dp->dtdo_vartab != NULL) kmem_free(dp->dtdo_vartab, dp->dtdo_varlen * sizeof (dtrace_difv_t)); kmem_free(dp, sizeof (dtrace_difo_t)); } static void dtrace_difo_release(dtrace_difo_t *dp, dtrace_vstate_t *vstate) { int i; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(dp->dtdo_refcnt != 0); for (i = 0; i < dp->dtdo_varlen; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i]; if (v->dtdv_id != DIF_VAR_VTIMESTAMP) continue; ASSERT(dtrace_vtime_references > 0); if (--dtrace_vtime_references == 0) dtrace_vtime_disable(); } if (--dp->dtdo_refcnt == 0) dtrace_difo_destroy(dp, vstate); } /* * DTrace Format Functions */ static uint16_t dtrace_format_add(dtrace_state_t *state, char *str) { char *fmt, **new; uint16_t ndx, len = strlen(str) + 1; fmt = kmem_zalloc(len, KM_SLEEP); bcopy(str, fmt, len); for (ndx = 0; ndx < state->dts_nformats; ndx++) { if (state->dts_formats[ndx] == NULL) { state->dts_formats[ndx] = fmt; return (ndx + 1); } } if (state->dts_nformats == USHRT_MAX) { /* * This is only likely if a denial-of-service attack is being * attempted. As such, it's okay to fail silently here. */ kmem_free(fmt, len); return (0); } /* * For simplicity, we always resize the formats array to be exactly the * number of formats. */ ndx = state->dts_nformats++; new = kmem_alloc((ndx + 1) * sizeof (char *), KM_SLEEP); if (state->dts_formats != NULL) { ASSERT(ndx != 0); bcopy(state->dts_formats, new, ndx * sizeof (char *)); kmem_free(state->dts_formats, ndx * sizeof (char *)); } state->dts_formats = new; state->dts_formats[ndx] = fmt; return (ndx + 1); } static void dtrace_format_remove(dtrace_state_t *state, uint16_t format) { char *fmt; ASSERT(state->dts_formats != NULL); ASSERT(format <= state->dts_nformats); ASSERT(state->dts_formats[format - 1] != NULL); fmt = state->dts_formats[format - 1]; kmem_free(fmt, strlen(fmt) + 1); state->dts_formats[format - 1] = NULL; } static void dtrace_format_destroy(dtrace_state_t *state) { int i; if (state->dts_nformats == 0) { ASSERT(state->dts_formats == NULL); return; } ASSERT(state->dts_formats != NULL); for (i = 0; i < state->dts_nformats; i++) { char *fmt = state->dts_formats[i]; if (fmt == NULL) continue; kmem_free(fmt, strlen(fmt) + 1); } kmem_free(state->dts_formats, state->dts_nformats * sizeof (char *)); state->dts_nformats = 0; state->dts_formats = NULL; } /* * DTrace Predicate Functions */ static dtrace_predicate_t * dtrace_predicate_create(dtrace_difo_t *dp) { dtrace_predicate_t *pred; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(dp->dtdo_refcnt != 0); pred = kmem_zalloc(sizeof (dtrace_predicate_t), KM_SLEEP); pred->dtp_difo = dp; pred->dtp_refcnt = 1; if (!dtrace_difo_cacheable(dp)) return (pred); if (dtrace_predcache_id == DTRACE_CACHEIDNONE) { /* * This is only theoretically possible -- we have had 2^32 * cacheable predicates on this machine. We cannot allow any * more predicates to become cacheable: as unlikely as it is, * there may be a thread caching a (now stale) predicate cache * ID. (N.B.: the temptation is being successfully resisted to * have this cmn_err() "Holy shit -- we executed this code!") */ return (pred); } pred->dtp_cacheid = dtrace_predcache_id++; return (pred); } static void dtrace_predicate_hold(dtrace_predicate_t *pred) { ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(pred->dtp_difo != NULL && pred->dtp_difo->dtdo_refcnt != 0); ASSERT(pred->dtp_refcnt > 0); pred->dtp_refcnt++; } static void dtrace_predicate_release(dtrace_predicate_t *pred, dtrace_vstate_t *vstate) { dtrace_difo_t *dp = pred->dtp_difo; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(dp != NULL && dp->dtdo_refcnt != 0); ASSERT(pred->dtp_refcnt > 0); if (--pred->dtp_refcnt == 0) { dtrace_difo_release(pred->dtp_difo, vstate); kmem_free(pred, sizeof (dtrace_predicate_t)); } } /* * DTrace Action Description Functions */ static dtrace_actdesc_t * dtrace_actdesc_create(dtrace_actkind_t kind, uint32_t ntuple, uint64_t uarg, uint64_t arg) { dtrace_actdesc_t *act; #ifdef illumos ASSERT(!DTRACEACT_ISPRINTFLIKE(kind) || (arg != NULL && arg >= KERNELBASE) || (arg == NULL && kind == DTRACEACT_PRINTA)); #endif act = kmem_zalloc(sizeof (dtrace_actdesc_t), KM_SLEEP); act->dtad_kind = kind; act->dtad_ntuple = ntuple; act->dtad_uarg = uarg; act->dtad_arg = arg; act->dtad_refcnt = 1; return (act); } static void dtrace_actdesc_hold(dtrace_actdesc_t *act) { ASSERT(act->dtad_refcnt >= 1); act->dtad_refcnt++; } static void dtrace_actdesc_release(dtrace_actdesc_t *act, dtrace_vstate_t *vstate) { dtrace_actkind_t kind = act->dtad_kind; dtrace_difo_t *dp; ASSERT(act->dtad_refcnt >= 1); if (--act->dtad_refcnt != 0) return; if ((dp = act->dtad_difo) != NULL) dtrace_difo_release(dp, vstate); if (DTRACEACT_ISPRINTFLIKE(kind)) { char *str = (char *)(uintptr_t)act->dtad_arg; #ifdef illumos ASSERT((str != NULL && (uintptr_t)str >= KERNELBASE) || (str == NULL && act->dtad_kind == DTRACEACT_PRINTA)); #endif if (str != NULL) kmem_free(str, strlen(str) + 1); } kmem_free(act, sizeof (dtrace_actdesc_t)); } /* * DTrace ECB Functions */ static dtrace_ecb_t * dtrace_ecb_add(dtrace_state_t *state, dtrace_probe_t *probe) { dtrace_ecb_t *ecb; dtrace_epid_t epid; ASSERT(MUTEX_HELD(&dtrace_lock)); ecb = kmem_zalloc(sizeof (dtrace_ecb_t), KM_SLEEP); ecb->dte_predicate = NULL; ecb->dte_probe = probe; /* * The default size is the size of the default action: recording * the header. */ ecb->dte_size = ecb->dte_needed = sizeof (dtrace_rechdr_t); ecb->dte_alignment = sizeof (dtrace_epid_t); epid = state->dts_epid++; if (epid - 1 >= state->dts_necbs) { dtrace_ecb_t **oecbs = state->dts_ecbs, **ecbs; int necbs = state->dts_necbs << 1; ASSERT(epid == state->dts_necbs + 1); if (necbs == 0) { ASSERT(oecbs == NULL); necbs = 1; } ecbs = kmem_zalloc(necbs * sizeof (*ecbs), KM_SLEEP); if (oecbs != NULL) bcopy(oecbs, ecbs, state->dts_necbs * sizeof (*ecbs)); dtrace_membar_producer(); state->dts_ecbs = ecbs; if (oecbs != NULL) { /* * If this state is active, we must dtrace_sync() * before we can free the old dts_ecbs array: we're * coming in hot, and there may be active ring * buffer processing (which indexes into the dts_ecbs * array) on another CPU. */ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) dtrace_sync(); kmem_free(oecbs, state->dts_necbs * sizeof (*ecbs)); } dtrace_membar_producer(); state->dts_necbs = necbs; } ecb->dte_state = state; ASSERT(state->dts_ecbs[epid - 1] == NULL); dtrace_membar_producer(); state->dts_ecbs[(ecb->dte_epid = epid) - 1] = ecb; return (ecb); } static void dtrace_ecb_enable(dtrace_ecb_t *ecb) { dtrace_probe_t *probe = ecb->dte_probe; ASSERT(MUTEX_HELD(&cpu_lock)); ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(ecb->dte_next == NULL); if (probe == NULL) { /* * This is the NULL probe -- there's nothing to do. */ return; } if (probe->dtpr_ecb == NULL) { dtrace_provider_t *prov = probe->dtpr_provider; /* * We're the first ECB on this probe. */ probe->dtpr_ecb = probe->dtpr_ecb_last = ecb; if (ecb->dte_predicate != NULL) probe->dtpr_predcache = ecb->dte_predicate->dtp_cacheid; prov->dtpv_pops.dtps_enable(prov->dtpv_arg, probe->dtpr_id, probe->dtpr_arg); } else { /* * This probe is already active. Swing the last pointer to * point to the new ECB, and issue a dtrace_sync() to assure * that all CPUs have seen the change. */ ASSERT(probe->dtpr_ecb_last != NULL); probe->dtpr_ecb_last->dte_next = ecb; probe->dtpr_ecb_last = ecb; probe->dtpr_predcache = 0; dtrace_sync(); } } static int dtrace_ecb_resize(dtrace_ecb_t *ecb) { dtrace_action_t *act; uint32_t curneeded = UINT32_MAX; uint32_t aggbase = UINT32_MAX; /* * If we record anything, we always record the dtrace_rechdr_t. (And * we always record it first.) */ ecb->dte_size = sizeof (dtrace_rechdr_t); ecb->dte_alignment = sizeof (dtrace_epid_t); for (act = ecb->dte_action; act != NULL; act = act->dta_next) { dtrace_recdesc_t *rec = &act->dta_rec; ASSERT(rec->dtrd_size > 0 || rec->dtrd_alignment == 1); ecb->dte_alignment = MAX(ecb->dte_alignment, rec->dtrd_alignment); if (DTRACEACT_ISAGG(act->dta_kind)) { dtrace_aggregation_t *agg = (dtrace_aggregation_t *)act; ASSERT(rec->dtrd_size != 0); ASSERT(agg->dtag_first != NULL); ASSERT(act->dta_prev->dta_intuple); ASSERT(aggbase != UINT32_MAX); ASSERT(curneeded != UINT32_MAX); agg->dtag_base = aggbase; curneeded = P2ROUNDUP(curneeded, rec->dtrd_alignment); rec->dtrd_offset = curneeded; if (curneeded + rec->dtrd_size < curneeded) return (EINVAL); curneeded += rec->dtrd_size; ecb->dte_needed = MAX(ecb->dte_needed, curneeded); aggbase = UINT32_MAX; curneeded = UINT32_MAX; } else if (act->dta_intuple) { if (curneeded == UINT32_MAX) { /* * This is the first record in a tuple. Align * curneeded to be at offset 4 in an 8-byte * aligned block. */ ASSERT(act->dta_prev == NULL || !act->dta_prev->dta_intuple); ASSERT3U(aggbase, ==, UINT32_MAX); curneeded = P2PHASEUP(ecb->dte_size, sizeof (uint64_t), sizeof (dtrace_aggid_t)); aggbase = curneeded - sizeof (dtrace_aggid_t); ASSERT(IS_P2ALIGNED(aggbase, sizeof (uint64_t))); } curneeded = P2ROUNDUP(curneeded, rec->dtrd_alignment); rec->dtrd_offset = curneeded; if (curneeded + rec->dtrd_size < curneeded) return (EINVAL); curneeded += rec->dtrd_size; } else { /* tuples must be followed by an aggregation */ ASSERT(act->dta_prev == NULL || !act->dta_prev->dta_intuple); ecb->dte_size = P2ROUNDUP(ecb->dte_size, rec->dtrd_alignment); rec->dtrd_offset = ecb->dte_size; if (ecb->dte_size + rec->dtrd_size < ecb->dte_size) return (EINVAL); ecb->dte_size += rec->dtrd_size; ecb->dte_needed = MAX(ecb->dte_needed, ecb->dte_size); } } if ((act = ecb->dte_action) != NULL && !(act->dta_kind == DTRACEACT_SPECULATE && act->dta_next == NULL) && ecb->dte_size == sizeof (dtrace_rechdr_t)) { /* * If the size is still sizeof (dtrace_rechdr_t), then all * actions store no data; set the size to 0. */ ecb->dte_size = 0; } ecb->dte_size = P2ROUNDUP(ecb->dte_size, sizeof (dtrace_epid_t)); ecb->dte_needed = P2ROUNDUP(ecb->dte_needed, (sizeof (dtrace_epid_t))); ecb->dte_state->dts_needed = MAX(ecb->dte_state->dts_needed, ecb->dte_needed); return (0); } static dtrace_action_t * dtrace_ecb_aggregation_create(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc) { dtrace_aggregation_t *agg; size_t size = sizeof (uint64_t); int ntuple = desc->dtad_ntuple; dtrace_action_t *act; dtrace_recdesc_t *frec; dtrace_aggid_t aggid; dtrace_state_t *state = ecb->dte_state; agg = kmem_zalloc(sizeof (dtrace_aggregation_t), KM_SLEEP); agg->dtag_ecb = ecb; ASSERT(DTRACEACT_ISAGG(desc->dtad_kind)); switch (desc->dtad_kind) { case DTRACEAGG_MIN: agg->dtag_initial = INT64_MAX; agg->dtag_aggregate = dtrace_aggregate_min; break; case DTRACEAGG_MAX: agg->dtag_initial = INT64_MIN; agg->dtag_aggregate = dtrace_aggregate_max; break; case DTRACEAGG_COUNT: agg->dtag_aggregate = dtrace_aggregate_count; break; case DTRACEAGG_QUANTIZE: agg->dtag_aggregate = dtrace_aggregate_quantize; size = (((sizeof (uint64_t) * NBBY) - 1) * 2 + 1) * sizeof (uint64_t); break; case DTRACEAGG_LQUANTIZE: { uint16_t step = DTRACE_LQUANTIZE_STEP(desc->dtad_arg); uint16_t levels = DTRACE_LQUANTIZE_LEVELS(desc->dtad_arg); agg->dtag_initial = desc->dtad_arg; agg->dtag_aggregate = dtrace_aggregate_lquantize; if (step == 0 || levels == 0) goto err; size = levels * sizeof (uint64_t) + 3 * sizeof (uint64_t); break; } case DTRACEAGG_LLQUANTIZE: { uint16_t factor = DTRACE_LLQUANTIZE_FACTOR(desc->dtad_arg); uint16_t low = DTRACE_LLQUANTIZE_LOW(desc->dtad_arg); uint16_t high = DTRACE_LLQUANTIZE_HIGH(desc->dtad_arg); uint16_t nsteps = DTRACE_LLQUANTIZE_NSTEP(desc->dtad_arg); int64_t v; agg->dtag_initial = desc->dtad_arg; agg->dtag_aggregate = dtrace_aggregate_llquantize; if (factor < 2 || low >= high || nsteps < factor) goto err; /* * Now check that the number of steps evenly divides a power * of the factor. (This assures both integer bucket size and * linearity within each magnitude.) */ for (v = factor; v < nsteps; v *= factor) continue; if ((v % nsteps) || (nsteps % factor)) goto err; size = (dtrace_aggregate_llquantize_bucket(factor, low, high, nsteps, INT64_MAX) + 2) * sizeof (uint64_t); break; } case DTRACEAGG_AVG: agg->dtag_aggregate = dtrace_aggregate_avg; size = sizeof (uint64_t) * 2; break; case DTRACEAGG_STDDEV: agg->dtag_aggregate = dtrace_aggregate_stddev; size = sizeof (uint64_t) * 4; break; case DTRACEAGG_SUM: agg->dtag_aggregate = dtrace_aggregate_sum; break; default: goto err; } agg->dtag_action.dta_rec.dtrd_size = size; if (ntuple == 0) goto err; /* * We must make sure that we have enough actions for the n-tuple. */ for (act = ecb->dte_action_last; act != NULL; act = act->dta_prev) { if (DTRACEACT_ISAGG(act->dta_kind)) break; if (--ntuple == 0) { /* * This is the action with which our n-tuple begins. */ agg->dtag_first = act; goto success; } } /* * This n-tuple is short by ntuple elements. Return failure. */ ASSERT(ntuple != 0); err: kmem_free(agg, sizeof (dtrace_aggregation_t)); return (NULL); success: /* * If the last action in the tuple has a size of zero, it's actually * an expression argument for the aggregating action. */ ASSERT(ecb->dte_action_last != NULL); act = ecb->dte_action_last; if (act->dta_kind == DTRACEACT_DIFEXPR) { ASSERT(act->dta_difo != NULL); if (act->dta_difo->dtdo_rtype.dtdt_size == 0) agg->dtag_hasarg = 1; } /* * We need to allocate an id for this aggregation. */ #ifdef illumos aggid = (dtrace_aggid_t)(uintptr_t)vmem_alloc(state->dts_aggid_arena, 1, VM_BESTFIT | VM_SLEEP); #else aggid = alloc_unr(state->dts_aggid_arena); #endif if (aggid - 1 >= state->dts_naggregations) { dtrace_aggregation_t **oaggs = state->dts_aggregations; dtrace_aggregation_t **aggs; int naggs = state->dts_naggregations << 1; int onaggs = state->dts_naggregations; ASSERT(aggid == state->dts_naggregations + 1); if (naggs == 0) { ASSERT(oaggs == NULL); naggs = 1; } aggs = kmem_zalloc(naggs * sizeof (*aggs), KM_SLEEP); if (oaggs != NULL) { bcopy(oaggs, aggs, onaggs * sizeof (*aggs)); kmem_free(oaggs, onaggs * sizeof (*aggs)); } state->dts_aggregations = aggs; state->dts_naggregations = naggs; } ASSERT(state->dts_aggregations[aggid - 1] == NULL); state->dts_aggregations[(agg->dtag_id = aggid) - 1] = agg; frec = &agg->dtag_first->dta_rec; if (frec->dtrd_alignment < sizeof (dtrace_aggid_t)) frec->dtrd_alignment = sizeof (dtrace_aggid_t); for (act = agg->dtag_first; act != NULL; act = act->dta_next) { ASSERT(!act->dta_intuple); act->dta_intuple = 1; } return (&agg->dtag_action); } static void dtrace_ecb_aggregation_destroy(dtrace_ecb_t *ecb, dtrace_action_t *act) { dtrace_aggregation_t *agg = (dtrace_aggregation_t *)act; dtrace_state_t *state = ecb->dte_state; dtrace_aggid_t aggid = agg->dtag_id; ASSERT(DTRACEACT_ISAGG(act->dta_kind)); #ifdef illumos vmem_free(state->dts_aggid_arena, (void *)(uintptr_t)aggid, 1); #else free_unr(state->dts_aggid_arena, aggid); #endif ASSERT(state->dts_aggregations[aggid - 1] == agg); state->dts_aggregations[aggid - 1] = NULL; kmem_free(agg, sizeof (dtrace_aggregation_t)); } static int dtrace_ecb_action_add(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc) { dtrace_action_t *action, *last; dtrace_difo_t *dp = desc->dtad_difo; uint32_t size = 0, align = sizeof (uint8_t), mask; uint16_t format = 0; dtrace_recdesc_t *rec; dtrace_state_t *state = ecb->dte_state; dtrace_optval_t *opt = state->dts_options, nframes = 0, strsize; uint64_t arg = desc->dtad_arg; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(ecb->dte_action == NULL || ecb->dte_action->dta_refcnt == 1); if (DTRACEACT_ISAGG(desc->dtad_kind)) { /* * If this is an aggregating action, there must be neither * a speculate nor a commit on the action chain. */ dtrace_action_t *act; for (act = ecb->dte_action; act != NULL; act = act->dta_next) { if (act->dta_kind == DTRACEACT_COMMIT) return (EINVAL); if (act->dta_kind == DTRACEACT_SPECULATE) return (EINVAL); } action = dtrace_ecb_aggregation_create(ecb, desc); if (action == NULL) return (EINVAL); } else { if (DTRACEACT_ISDESTRUCTIVE(desc->dtad_kind) || (desc->dtad_kind == DTRACEACT_DIFEXPR && dp != NULL && dp->dtdo_destructive)) { state->dts_destructive = 1; } switch (desc->dtad_kind) { case DTRACEACT_PRINTF: case DTRACEACT_PRINTA: case DTRACEACT_SYSTEM: case DTRACEACT_FREOPEN: case DTRACEACT_DIFEXPR: /* * We know that our arg is a string -- turn it into a * format. */ if (arg == 0) { ASSERT(desc->dtad_kind == DTRACEACT_PRINTA || desc->dtad_kind == DTRACEACT_DIFEXPR); format = 0; } else { ASSERT(arg != 0); #ifdef illumos ASSERT(arg > KERNELBASE); #endif format = dtrace_format_add(state, (char *)(uintptr_t)arg); } /*FALLTHROUGH*/ case DTRACEACT_LIBACT: case DTRACEACT_TRACEMEM: case DTRACEACT_TRACEMEM_DYNSIZE: if (dp == NULL) return (EINVAL); if ((size = dp->dtdo_rtype.dtdt_size) != 0) break; if (dp->dtdo_rtype.dtdt_kind == DIF_TYPE_STRING) { if (!(dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) return (EINVAL); size = opt[DTRACEOPT_STRSIZE]; } break; case DTRACEACT_STACK: if ((nframes = arg) == 0) { nframes = opt[DTRACEOPT_STACKFRAMES]; ASSERT(nframes > 0); arg = nframes; } size = nframes * sizeof (pc_t); break; case DTRACEACT_JSTACK: if ((strsize = DTRACE_USTACK_STRSIZE(arg)) == 0) strsize = opt[DTRACEOPT_JSTACKSTRSIZE]; if ((nframes = DTRACE_USTACK_NFRAMES(arg)) == 0) nframes = opt[DTRACEOPT_JSTACKFRAMES]; arg = DTRACE_USTACK_ARG(nframes, strsize); /*FALLTHROUGH*/ case DTRACEACT_USTACK: if (desc->dtad_kind != DTRACEACT_JSTACK && (nframes = DTRACE_USTACK_NFRAMES(arg)) == 0) { strsize = DTRACE_USTACK_STRSIZE(arg); nframes = opt[DTRACEOPT_USTACKFRAMES]; ASSERT(nframes > 0); arg = DTRACE_USTACK_ARG(nframes, strsize); } /* * Save a slot for the pid. */ size = (nframes + 1) * sizeof (uint64_t); size += DTRACE_USTACK_STRSIZE(arg); size = P2ROUNDUP(size, (uint32_t)(sizeof (uintptr_t))); break; case DTRACEACT_SYM: case DTRACEACT_MOD: if (dp == NULL || ((size = dp->dtdo_rtype.dtdt_size) != sizeof (uint64_t)) || (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) return (EINVAL); break; case DTRACEACT_USYM: case DTRACEACT_UMOD: case DTRACEACT_UADDR: if (dp == NULL || (dp->dtdo_rtype.dtdt_size != sizeof (uint64_t)) || (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) return (EINVAL); /* * We have a slot for the pid, plus a slot for the * argument. To keep things simple (aligned with * bitness-neutral sizing), we store each as a 64-bit * quantity. */ size = 2 * sizeof (uint64_t); break; case DTRACEACT_STOP: case DTRACEACT_BREAKPOINT: case DTRACEACT_PANIC: break; case DTRACEACT_CHILL: case DTRACEACT_DISCARD: case DTRACEACT_RAISE: if (dp == NULL) return (EINVAL); break; case DTRACEACT_EXIT: if (dp == NULL || (size = dp->dtdo_rtype.dtdt_size) != sizeof (int) || (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) return (EINVAL); break; case DTRACEACT_SPECULATE: if (ecb->dte_size > sizeof (dtrace_rechdr_t)) return (EINVAL); if (dp == NULL) return (EINVAL); state->dts_speculates = 1; break; case DTRACEACT_PRINTM: size = dp->dtdo_rtype.dtdt_size; break; case DTRACEACT_COMMIT: { dtrace_action_t *act = ecb->dte_action; for (; act != NULL; act = act->dta_next) { if (act->dta_kind == DTRACEACT_COMMIT) return (EINVAL); } if (dp == NULL) return (EINVAL); break; } default: return (EINVAL); } if (size != 0 || desc->dtad_kind == DTRACEACT_SPECULATE) { /* * If this is a data-storing action or a speculate, * we must be sure that there isn't a commit on the * action chain. */ dtrace_action_t *act = ecb->dte_action; for (; act != NULL; act = act->dta_next) { if (act->dta_kind == DTRACEACT_COMMIT) return (EINVAL); } } action = kmem_zalloc(sizeof (dtrace_action_t), KM_SLEEP); action->dta_rec.dtrd_size = size; } action->dta_refcnt = 1; rec = &action->dta_rec; size = rec->dtrd_size; for (mask = sizeof (uint64_t) - 1; size != 0 && mask > 0; mask >>= 1) { if (!(size & mask)) { align = mask + 1; break; } } action->dta_kind = desc->dtad_kind; if ((action->dta_difo = dp) != NULL) dtrace_difo_hold(dp); rec->dtrd_action = action->dta_kind; rec->dtrd_arg = arg; rec->dtrd_uarg = desc->dtad_uarg; rec->dtrd_alignment = (uint16_t)align; rec->dtrd_format = format; if ((last = ecb->dte_action_last) != NULL) { ASSERT(ecb->dte_action != NULL); action->dta_prev = last; last->dta_next = action; } else { ASSERT(ecb->dte_action == NULL); ecb->dte_action = action; } ecb->dte_action_last = action; return (0); } static void dtrace_ecb_action_remove(dtrace_ecb_t *ecb) { dtrace_action_t *act = ecb->dte_action, *next; dtrace_vstate_t *vstate = &ecb->dte_state->dts_vstate; dtrace_difo_t *dp; uint16_t format; if (act != NULL && act->dta_refcnt > 1) { ASSERT(act->dta_next == NULL || act->dta_next->dta_refcnt == 1); act->dta_refcnt--; } else { for (; act != NULL; act = next) { next = act->dta_next; ASSERT(next != NULL || act == ecb->dte_action_last); ASSERT(act->dta_refcnt == 1); if ((format = act->dta_rec.dtrd_format) != 0) dtrace_format_remove(ecb->dte_state, format); if ((dp = act->dta_difo) != NULL) dtrace_difo_release(dp, vstate); if (DTRACEACT_ISAGG(act->dta_kind)) { dtrace_ecb_aggregation_destroy(ecb, act); } else { kmem_free(act, sizeof (dtrace_action_t)); } } } ecb->dte_action = NULL; ecb->dte_action_last = NULL; ecb->dte_size = 0; } static void dtrace_ecb_disable(dtrace_ecb_t *ecb) { /* * We disable the ECB by removing it from its probe. */ dtrace_ecb_t *pecb, *prev = NULL; dtrace_probe_t *probe = ecb->dte_probe; ASSERT(MUTEX_HELD(&dtrace_lock)); if (probe == NULL) { /* * This is the NULL probe; there is nothing to disable. */ return; } for (pecb = probe->dtpr_ecb; pecb != NULL; pecb = pecb->dte_next) { if (pecb == ecb) break; prev = pecb; } ASSERT(pecb != NULL); if (prev == NULL) { probe->dtpr_ecb = ecb->dte_next; } else { prev->dte_next = ecb->dte_next; } if (ecb == probe->dtpr_ecb_last) { ASSERT(ecb->dte_next == NULL); probe->dtpr_ecb_last = prev; } /* * The ECB has been disconnected from the probe; now sync to assure * that all CPUs have seen the change before returning. */ dtrace_sync(); if (probe->dtpr_ecb == NULL) { /* * That was the last ECB on the probe; clear the predicate * cache ID for the probe, disable it and sync one more time * to assure that we'll never hit it again. */ dtrace_provider_t *prov = probe->dtpr_provider; ASSERT(ecb->dte_next == NULL); ASSERT(probe->dtpr_ecb_last == NULL); probe->dtpr_predcache = DTRACE_CACHEIDNONE; prov->dtpv_pops.dtps_disable(prov->dtpv_arg, probe->dtpr_id, probe->dtpr_arg); dtrace_sync(); } else { /* * There is at least one ECB remaining on the probe. If there * is _exactly_ one, set the probe's predicate cache ID to be * the predicate cache ID of the remaining ECB. */ ASSERT(probe->dtpr_ecb_last != NULL); ASSERT(probe->dtpr_predcache == DTRACE_CACHEIDNONE); if (probe->dtpr_ecb == probe->dtpr_ecb_last) { dtrace_predicate_t *p = probe->dtpr_ecb->dte_predicate; ASSERT(probe->dtpr_ecb->dte_next == NULL); if (p != NULL) probe->dtpr_predcache = p->dtp_cacheid; } ecb->dte_next = NULL; } } static void dtrace_ecb_destroy(dtrace_ecb_t *ecb) { dtrace_state_t *state = ecb->dte_state; dtrace_vstate_t *vstate = &state->dts_vstate; dtrace_predicate_t *pred; dtrace_epid_t epid = ecb->dte_epid; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(ecb->dte_next == NULL); ASSERT(ecb->dte_probe == NULL || ecb->dte_probe->dtpr_ecb != ecb); if ((pred = ecb->dte_predicate) != NULL) dtrace_predicate_release(pred, vstate); dtrace_ecb_action_remove(ecb); ASSERT(state->dts_ecbs[epid - 1] == ecb); state->dts_ecbs[epid - 1] = NULL; kmem_free(ecb, sizeof (dtrace_ecb_t)); } static dtrace_ecb_t * dtrace_ecb_create(dtrace_state_t *state, dtrace_probe_t *probe, dtrace_enabling_t *enab) { dtrace_ecb_t *ecb; dtrace_predicate_t *pred; dtrace_actdesc_t *act; dtrace_provider_t *prov; dtrace_ecbdesc_t *desc = enab->dten_current; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(state != NULL); ecb = dtrace_ecb_add(state, probe); ecb->dte_uarg = desc->dted_uarg; if ((pred = desc->dted_pred.dtpdd_predicate) != NULL) { dtrace_predicate_hold(pred); ecb->dte_predicate = pred; } if (probe != NULL) { /* * If the provider shows more leg than the consumer is old * enough to see, we need to enable the appropriate implicit * predicate bits to prevent the ecb from activating at * revealing times. * * Providers specifying DTRACE_PRIV_USER at register time * are stating that they need the /proc-style privilege * model to be enforced, and this is what DTRACE_COND_OWNER * and DTRACE_COND_ZONEOWNER will then do at probe time. */ prov = probe->dtpr_provider; if (!(state->dts_cred.dcr_visible & DTRACE_CRV_ALLPROC) && (prov->dtpv_priv.dtpp_flags & DTRACE_PRIV_USER)) ecb->dte_cond |= DTRACE_COND_OWNER; if (!(state->dts_cred.dcr_visible & DTRACE_CRV_ALLZONE) && (prov->dtpv_priv.dtpp_flags & DTRACE_PRIV_USER)) ecb->dte_cond |= DTRACE_COND_ZONEOWNER; /* * If the provider shows us kernel innards and the user * is lacking sufficient privilege, enable the * DTRACE_COND_USERMODE implicit predicate. */ if (!(state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL) && (prov->dtpv_priv.dtpp_flags & DTRACE_PRIV_KERNEL)) ecb->dte_cond |= DTRACE_COND_USERMODE; } if (dtrace_ecb_create_cache != NULL) { /* * If we have a cached ecb, we'll use its action list instead * of creating our own (saving both time and space). */ dtrace_ecb_t *cached = dtrace_ecb_create_cache; dtrace_action_t *act = cached->dte_action; if (act != NULL) { ASSERT(act->dta_refcnt > 0); act->dta_refcnt++; ecb->dte_action = act; ecb->dte_action_last = cached->dte_action_last; ecb->dte_needed = cached->dte_needed; ecb->dte_size = cached->dte_size; ecb->dte_alignment = cached->dte_alignment; } return (ecb); } for (act = desc->dted_action; act != NULL; act = act->dtad_next) { if ((enab->dten_error = dtrace_ecb_action_add(ecb, act)) != 0) { dtrace_ecb_destroy(ecb); return (NULL); } } if ((enab->dten_error = dtrace_ecb_resize(ecb)) != 0) { dtrace_ecb_destroy(ecb); return (NULL); } return (dtrace_ecb_create_cache = ecb); } static int dtrace_ecb_create_enable(dtrace_probe_t *probe, void *arg) { dtrace_ecb_t *ecb; dtrace_enabling_t *enab = arg; dtrace_state_t *state = enab->dten_vstate->dtvs_state; ASSERT(state != NULL); if (probe != NULL && probe->dtpr_gen < enab->dten_probegen) { /* * This probe was created in a generation for which this * enabling has previously created ECBs; we don't want to * enable it again, so just kick out. */ return (DTRACE_MATCH_NEXT); } if ((ecb = dtrace_ecb_create(state, probe, enab)) == NULL) return (DTRACE_MATCH_DONE); dtrace_ecb_enable(ecb); return (DTRACE_MATCH_NEXT); } static dtrace_ecb_t * dtrace_epid2ecb(dtrace_state_t *state, dtrace_epid_t id) { dtrace_ecb_t *ecb; ASSERT(MUTEX_HELD(&dtrace_lock)); if (id == 0 || id > state->dts_necbs) return (NULL); ASSERT(state->dts_necbs > 0 && state->dts_ecbs != NULL); ASSERT((ecb = state->dts_ecbs[id - 1]) == NULL || ecb->dte_epid == id); return (state->dts_ecbs[id - 1]); } static dtrace_aggregation_t * dtrace_aggid2agg(dtrace_state_t *state, dtrace_aggid_t id) { dtrace_aggregation_t *agg; ASSERT(MUTEX_HELD(&dtrace_lock)); if (id == 0 || id > state->dts_naggregations) return (NULL); ASSERT(state->dts_naggregations > 0 && state->dts_aggregations != NULL); ASSERT((agg = state->dts_aggregations[id - 1]) == NULL || agg->dtag_id == id); return (state->dts_aggregations[id - 1]); } /* * DTrace Buffer Functions * * The following functions manipulate DTrace buffers. Most of these functions * are called in the context of establishing or processing consumer state; * exceptions are explicitly noted. */ /* * Note: called from cross call context. This function switches the two * buffers on a given CPU. The atomicity of this operation is assured by * disabling interrupts while the actual switch takes place; the disabling of * interrupts serializes the execution with any execution of dtrace_probe() on * the same CPU. */ static void dtrace_buffer_switch(dtrace_buffer_t *buf) { caddr_t tomax = buf->dtb_tomax; caddr_t xamot = buf->dtb_xamot; dtrace_icookie_t cookie; hrtime_t now; ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); ASSERT(!(buf->dtb_flags & DTRACEBUF_RING)); cookie = dtrace_interrupt_disable(); now = dtrace_gethrtime(); buf->dtb_tomax = xamot; buf->dtb_xamot = tomax; buf->dtb_xamot_drops = buf->dtb_drops; buf->dtb_xamot_offset = buf->dtb_offset; buf->dtb_xamot_errors = buf->dtb_errors; buf->dtb_xamot_flags = buf->dtb_flags; buf->dtb_offset = 0; buf->dtb_drops = 0; buf->dtb_errors = 0; buf->dtb_flags &= ~(DTRACEBUF_ERROR | DTRACEBUF_DROPPED); buf->dtb_interval = now - buf->dtb_switched; buf->dtb_switched = now; dtrace_interrupt_enable(cookie); } /* * Note: called from cross call context. This function activates a buffer * on a CPU. As with dtrace_buffer_switch(), the atomicity of the operation * is guaranteed by the disabling of interrupts. */ static void dtrace_buffer_activate(dtrace_state_t *state) { dtrace_buffer_t *buf; dtrace_icookie_t cookie = dtrace_interrupt_disable(); buf = &state->dts_buffer[curcpu]; if (buf->dtb_tomax != NULL) { /* * We might like to assert that the buffer is marked inactive, * but this isn't necessarily true: the buffer for the CPU * that processes the BEGIN probe has its buffer activated * manually. In this case, we take the (harmless) action * re-clearing the bit INACTIVE bit. */ buf->dtb_flags &= ~DTRACEBUF_INACTIVE; } dtrace_interrupt_enable(cookie); } #ifdef __FreeBSD__ /* * Activate the specified per-CPU buffer. This is used instead of * dtrace_buffer_activate() when APs have not yet started, i.e. when * activating anonymous state. */ static void dtrace_buffer_activate_cpu(dtrace_state_t *state, int cpu) { if (state->dts_buffer[cpu].dtb_tomax != NULL) state->dts_buffer[cpu].dtb_flags &= ~DTRACEBUF_INACTIVE; } #endif static int dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags, processorid_t cpu, int *factor) { #ifdef illumos cpu_t *cp; #endif dtrace_buffer_t *buf; int allocated = 0, desired = 0; #ifdef illumos ASSERT(MUTEX_HELD(&cpu_lock)); ASSERT(MUTEX_HELD(&dtrace_lock)); *factor = 1; if (size > dtrace_nonroot_maxsize && !PRIV_POLICY_CHOICE(CRED(), PRIV_ALL, B_FALSE)) return (EFBIG); cp = cpu_list; do { if (cpu != DTRACE_CPUALL && cpu != cp->cpu_id) continue; buf = &bufs[cp->cpu_id]; /* * If there is already a buffer allocated for this CPU, it * is only possible that this is a DR event. In this case, */ if (buf->dtb_tomax != NULL) { ASSERT(buf->dtb_size == size); continue; } ASSERT(buf->dtb_xamot == NULL); if ((buf->dtb_tomax = kmem_zalloc(size, KM_NOSLEEP | KM_NORMALPRI)) == NULL) goto err; buf->dtb_size = size; buf->dtb_flags = flags; buf->dtb_offset = 0; buf->dtb_drops = 0; if (flags & DTRACEBUF_NOSWITCH) continue; if ((buf->dtb_xamot = kmem_zalloc(size, KM_NOSLEEP | KM_NORMALPRI)) == NULL) goto err; } while ((cp = cp->cpu_next) != cpu_list); return (0); err: cp = cpu_list; do { if (cpu != DTRACE_CPUALL && cpu != cp->cpu_id) continue; buf = &bufs[cp->cpu_id]; desired += 2; if (buf->dtb_xamot != NULL) { ASSERT(buf->dtb_tomax != NULL); ASSERT(buf->dtb_size == size); kmem_free(buf->dtb_xamot, size); allocated++; } if (buf->dtb_tomax != NULL) { ASSERT(buf->dtb_size == size); kmem_free(buf->dtb_tomax, size); allocated++; } buf->dtb_tomax = NULL; buf->dtb_xamot = NULL; buf->dtb_size = 0; } while ((cp = cp->cpu_next) != cpu_list); #else int i; *factor = 1; #if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \ defined(__mips__) || defined(__powerpc__) || defined(__riscv__) /* * FreeBSD isn't good at limiting the amount of memory we * ask to malloc, so let's place a limit here before trying * to do something that might well end in tears at bedtime. */ if (size > physmem * PAGE_SIZE / (128 * (mp_maxid + 1))) return (ENOMEM); #endif ASSERT(MUTEX_HELD(&dtrace_lock)); CPU_FOREACH(i) { if (cpu != DTRACE_CPUALL && cpu != i) continue; buf = &bufs[i]; /* * If there is already a buffer allocated for this CPU, it * is only possible that this is a DR event. In this case, * the buffer size must match our specified size. */ if (buf->dtb_tomax != NULL) { ASSERT(buf->dtb_size == size); continue; } ASSERT(buf->dtb_xamot == NULL); if ((buf->dtb_tomax = kmem_zalloc(size, KM_NOSLEEP | KM_NORMALPRI)) == NULL) goto err; buf->dtb_size = size; buf->dtb_flags = flags; buf->dtb_offset = 0; buf->dtb_drops = 0; if (flags & DTRACEBUF_NOSWITCH) continue; if ((buf->dtb_xamot = kmem_zalloc(size, KM_NOSLEEP | KM_NORMALPRI)) == NULL) goto err; } return (0); err: /* * Error allocating memory, so free the buffers that were * allocated before the failed allocation. */ CPU_FOREACH(i) { if (cpu != DTRACE_CPUALL && cpu != i) continue; buf = &bufs[i]; desired += 2; if (buf->dtb_xamot != NULL) { ASSERT(buf->dtb_tomax != NULL); ASSERT(buf->dtb_size == size); kmem_free(buf->dtb_xamot, size); allocated++; } if (buf->dtb_tomax != NULL) { ASSERT(buf->dtb_size == size); kmem_free(buf->dtb_tomax, size); allocated++; } buf->dtb_tomax = NULL; buf->dtb_xamot = NULL; buf->dtb_size = 0; } #endif *factor = desired / (allocated > 0 ? allocated : 1); return (ENOMEM); } /* * Note: called from probe context. This function just increments the drop * count on a buffer. It has been made a function to allow for the * possibility of understanding the source of mysterious drop counts. (A * problem for which one may be particularly disappointed that DTrace cannot * be used to understand DTrace.) */ static void dtrace_buffer_drop(dtrace_buffer_t *buf) { buf->dtb_drops++; } /* * Note: called from probe context. This function is called to reserve space * in a buffer. If mstate is non-NULL, sets the scratch base and size in the * mstate. Returns the new offset in the buffer, or a negative value if an * error has occurred. */ static intptr_t dtrace_buffer_reserve(dtrace_buffer_t *buf, size_t needed, size_t align, dtrace_state_t *state, dtrace_mstate_t *mstate) { intptr_t offs = buf->dtb_offset, soffs; intptr_t woffs; caddr_t tomax; size_t total; if (buf->dtb_flags & DTRACEBUF_INACTIVE) return (-1); if ((tomax = buf->dtb_tomax) == NULL) { dtrace_buffer_drop(buf); return (-1); } if (!(buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL))) { while (offs & (align - 1)) { /* * Assert that our alignment is off by a number which * is itself sizeof (uint32_t) aligned. */ ASSERT(!((align - (offs & (align - 1))) & (sizeof (uint32_t) - 1))); DTRACE_STORE(uint32_t, tomax, offs, DTRACE_EPIDNONE); offs += sizeof (uint32_t); } if ((soffs = offs + needed) > buf->dtb_size) { dtrace_buffer_drop(buf); return (-1); } if (mstate == NULL) return (offs); mstate->dtms_scratch_base = (uintptr_t)tomax + soffs; mstate->dtms_scratch_size = buf->dtb_size - soffs; mstate->dtms_scratch_ptr = mstate->dtms_scratch_base; return (offs); } if (buf->dtb_flags & DTRACEBUF_FILL) { if (state->dts_activity != DTRACE_ACTIVITY_COOLDOWN && (buf->dtb_flags & DTRACEBUF_FULL)) return (-1); goto out; } total = needed + (offs & (align - 1)); /* * For a ring buffer, life is quite a bit more complicated. Before * we can store any padding, we need to adjust our wrapping offset. * (If we've never before wrapped or we're not about to, no adjustment * is required.) */ if ((buf->dtb_flags & DTRACEBUF_WRAPPED) || offs + total > buf->dtb_size) { woffs = buf->dtb_xamot_offset; if (offs + total > buf->dtb_size) { /* * We can't fit in the end of the buffer. First, a * sanity check that we can fit in the buffer at all. */ if (total > buf->dtb_size) { dtrace_buffer_drop(buf); return (-1); } /* * We're going to be storing at the top of the buffer, * so now we need to deal with the wrapped offset. We * only reset our wrapped offset to 0 if it is * currently greater than the current offset. If it * is less than the current offset, it is because a * previous allocation induced a wrap -- but the * allocation didn't subsequently take the space due * to an error or false predicate evaluation. In this * case, we'll just leave the wrapped offset alone: if * the wrapped offset hasn't been advanced far enough * for this allocation, it will be adjusted in the * lower loop. */ if (buf->dtb_flags & DTRACEBUF_WRAPPED) { if (woffs >= offs) woffs = 0; } else { woffs = 0; } /* * Now we know that we're going to be storing to the * top of the buffer and that there is room for us * there. We need to clear the buffer from the current * offset to the end (there may be old gunk there). */ while (offs < buf->dtb_size) tomax[offs++] = 0; /* * We need to set our offset to zero. And because we * are wrapping, we need to set the bit indicating as * much. We can also adjust our needed space back * down to the space required by the ECB -- we know * that the top of the buffer is aligned. */ offs = 0; total = needed; buf->dtb_flags |= DTRACEBUF_WRAPPED; } else { /* * There is room for us in the buffer, so we simply * need to check the wrapped offset. */ if (woffs < offs) { /* * The wrapped offset is less than the offset. * This can happen if we allocated buffer space * that induced a wrap, but then we didn't * subsequently take the space due to an error * or false predicate evaluation. This is * okay; we know that _this_ allocation isn't * going to induce a wrap. We still can't * reset the wrapped offset to be zero, * however: the space may have been trashed in * the previous failed probe attempt. But at * least the wrapped offset doesn't need to * be adjusted at all... */ goto out; } } while (offs + total > woffs) { dtrace_epid_t epid = *(uint32_t *)(tomax + woffs); size_t size; if (epid == DTRACE_EPIDNONE) { size = sizeof (uint32_t); } else { ASSERT3U(epid, <=, state->dts_necbs); ASSERT(state->dts_ecbs[epid - 1] != NULL); size = state->dts_ecbs[epid - 1]->dte_size; } ASSERT(woffs + size <= buf->dtb_size); ASSERT(size != 0); if (woffs + size == buf->dtb_size) { /* * We've reached the end of the buffer; we want * to set the wrapped offset to 0 and break * out. However, if the offs is 0, then we're * in a strange edge-condition: the amount of * space that we want to reserve plus the size * of the record that we're overwriting is * greater than the size of the buffer. This * is problematic because if we reserve the * space but subsequently don't consume it (due * to a failed predicate or error) the wrapped * offset will be 0 -- yet the EPID at offset 0 * will not be committed. This situation is * relatively easy to deal with: if we're in * this case, the buffer is indistinguishable * from one that hasn't wrapped; we need only * finish the job by clearing the wrapped bit, * explicitly setting the offset to be 0, and * zero'ing out the old data in the buffer. */ if (offs == 0) { buf->dtb_flags &= ~DTRACEBUF_WRAPPED; buf->dtb_offset = 0; woffs = total; while (woffs < buf->dtb_size) tomax[woffs++] = 0; } woffs = 0; break; } woffs += size; } /* * We have a wrapped offset. It may be that the wrapped offset * has become zero -- that's okay. */ buf->dtb_xamot_offset = woffs; } out: /* * Now we can plow the buffer with any necessary padding. */ while (offs & (align - 1)) { /* * Assert that our alignment is off by a number which * is itself sizeof (uint32_t) aligned. */ ASSERT(!((align - (offs & (align - 1))) & (sizeof (uint32_t) - 1))); DTRACE_STORE(uint32_t, tomax, offs, DTRACE_EPIDNONE); offs += sizeof (uint32_t); } if (buf->dtb_flags & DTRACEBUF_FILL) { if (offs + needed > buf->dtb_size - state->dts_reserve) { buf->dtb_flags |= DTRACEBUF_FULL; return (-1); } } if (mstate == NULL) return (offs); /* * For ring buffers and fill buffers, the scratch space is always * the inactive buffer. */ mstate->dtms_scratch_base = (uintptr_t)buf->dtb_xamot; mstate->dtms_scratch_size = buf->dtb_size; mstate->dtms_scratch_ptr = mstate->dtms_scratch_base; return (offs); } static void dtrace_buffer_polish(dtrace_buffer_t *buf) { ASSERT(buf->dtb_flags & DTRACEBUF_RING); ASSERT(MUTEX_HELD(&dtrace_lock)); if (!(buf->dtb_flags & DTRACEBUF_WRAPPED)) return; /* * We need to polish the ring buffer. There are three cases: * * - The first (and presumably most common) is that there is no gap * between the buffer offset and the wrapped offset. In this case, * there is nothing in the buffer that isn't valid data; we can * mark the buffer as polished and return. * * - The second (less common than the first but still more common * than the third) is that there is a gap between the buffer offset * and the wrapped offset, and the wrapped offset is larger than the * buffer offset. This can happen because of an alignment issue, or * can happen because of a call to dtrace_buffer_reserve() that * didn't subsequently consume the buffer space. In this case, * we need to zero the data from the buffer offset to the wrapped * offset. * * - The third (and least common) is that there is a gap between the * buffer offset and the wrapped offset, but the wrapped offset is * _less_ than the buffer offset. This can only happen because a * call to dtrace_buffer_reserve() induced a wrap, but the space * was not subsequently consumed. In this case, we need to zero the * space from the offset to the end of the buffer _and_ from the * top of the buffer to the wrapped offset. */ if (buf->dtb_offset < buf->dtb_xamot_offset) { bzero(buf->dtb_tomax + buf->dtb_offset, buf->dtb_xamot_offset - buf->dtb_offset); } if (buf->dtb_offset > buf->dtb_xamot_offset) { bzero(buf->dtb_tomax + buf->dtb_offset, buf->dtb_size - buf->dtb_offset); bzero(buf->dtb_tomax, buf->dtb_xamot_offset); } } /* * This routine determines if data generated at the specified time has likely * been entirely consumed at user-level. This routine is called to determine * if an ECB on a defunct probe (but for an active enabling) can be safely * disabled and destroyed. */ static int dtrace_buffer_consumed(dtrace_buffer_t *bufs, hrtime_t when) { int i; for (i = 0; i < NCPU; i++) { dtrace_buffer_t *buf = &bufs[i]; if (buf->dtb_size == 0) continue; if (buf->dtb_flags & DTRACEBUF_RING) return (0); if (!buf->dtb_switched && buf->dtb_offset != 0) return (0); if (buf->dtb_switched - buf->dtb_interval < when) return (0); } return (1); } static void dtrace_buffer_free(dtrace_buffer_t *bufs) { int i; for (i = 0; i < NCPU; i++) { dtrace_buffer_t *buf = &bufs[i]; if (buf->dtb_tomax == NULL) { ASSERT(buf->dtb_xamot == NULL); ASSERT(buf->dtb_size == 0); continue; } if (buf->dtb_xamot != NULL) { ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); kmem_free(buf->dtb_xamot, buf->dtb_size); } kmem_free(buf->dtb_tomax, buf->dtb_size); buf->dtb_size = 0; buf->dtb_tomax = NULL; buf->dtb_xamot = NULL; } } /* * DTrace Enabling Functions */ static dtrace_enabling_t * dtrace_enabling_create(dtrace_vstate_t *vstate) { dtrace_enabling_t *enab; enab = kmem_zalloc(sizeof (dtrace_enabling_t), KM_SLEEP); enab->dten_vstate = vstate; return (enab); } static void dtrace_enabling_add(dtrace_enabling_t *enab, dtrace_ecbdesc_t *ecb) { dtrace_ecbdesc_t **ndesc; size_t osize, nsize; /* * We can't add to enablings after we've enabled them, or after we've * retained them. */ ASSERT(enab->dten_probegen == 0); ASSERT(enab->dten_next == NULL && enab->dten_prev == NULL); if (enab->dten_ndesc < enab->dten_maxdesc) { enab->dten_desc[enab->dten_ndesc++] = ecb; return; } osize = enab->dten_maxdesc * sizeof (dtrace_enabling_t *); if (enab->dten_maxdesc == 0) { enab->dten_maxdesc = 1; } else { enab->dten_maxdesc <<= 1; } ASSERT(enab->dten_ndesc < enab->dten_maxdesc); nsize = enab->dten_maxdesc * sizeof (dtrace_enabling_t *); ndesc = kmem_zalloc(nsize, KM_SLEEP); bcopy(enab->dten_desc, ndesc, osize); if (enab->dten_desc != NULL) kmem_free(enab->dten_desc, osize); enab->dten_desc = ndesc; enab->dten_desc[enab->dten_ndesc++] = ecb; } static void dtrace_enabling_addlike(dtrace_enabling_t *enab, dtrace_ecbdesc_t *ecb, dtrace_probedesc_t *pd) { dtrace_ecbdesc_t *new; dtrace_predicate_t *pred; dtrace_actdesc_t *act; /* * We're going to create a new ECB description that matches the * specified ECB in every way, but has the specified probe description. */ new = kmem_zalloc(sizeof (dtrace_ecbdesc_t), KM_SLEEP); if ((pred = ecb->dted_pred.dtpdd_predicate) != NULL) dtrace_predicate_hold(pred); for (act = ecb->dted_action; act != NULL; act = act->dtad_next) dtrace_actdesc_hold(act); new->dted_action = ecb->dted_action; new->dted_pred = ecb->dted_pred; new->dted_probe = *pd; new->dted_uarg = ecb->dted_uarg; dtrace_enabling_add(enab, new); } static void dtrace_enabling_dump(dtrace_enabling_t *enab) { int i; for (i = 0; i < enab->dten_ndesc; i++) { dtrace_probedesc_t *desc = &enab->dten_desc[i]->dted_probe; #ifdef __FreeBSD__ printf("dtrace: enabling probe %d (%s:%s:%s:%s)\n", i, desc->dtpd_provider, desc->dtpd_mod, desc->dtpd_func, desc->dtpd_name); #else cmn_err(CE_NOTE, "enabling probe %d (%s:%s:%s:%s)", i, desc->dtpd_provider, desc->dtpd_mod, desc->dtpd_func, desc->dtpd_name); #endif } } static void dtrace_enabling_destroy(dtrace_enabling_t *enab) { int i; dtrace_ecbdesc_t *ep; dtrace_vstate_t *vstate = enab->dten_vstate; ASSERT(MUTEX_HELD(&dtrace_lock)); for (i = 0; i < enab->dten_ndesc; i++) { dtrace_actdesc_t *act, *next; dtrace_predicate_t *pred; ep = enab->dten_desc[i]; if ((pred = ep->dted_pred.dtpdd_predicate) != NULL) dtrace_predicate_release(pred, vstate); for (act = ep->dted_action; act != NULL; act = next) { next = act->dtad_next; dtrace_actdesc_release(act, vstate); } kmem_free(ep, sizeof (dtrace_ecbdesc_t)); } if (enab->dten_desc != NULL) kmem_free(enab->dten_desc, enab->dten_maxdesc * sizeof (dtrace_enabling_t *)); /* * If this was a retained enabling, decrement the dts_nretained count * and take it off of the dtrace_retained list. */ if (enab->dten_prev != NULL || enab->dten_next != NULL || dtrace_retained == enab) { ASSERT(enab->dten_vstate->dtvs_state != NULL); ASSERT(enab->dten_vstate->dtvs_state->dts_nretained > 0); enab->dten_vstate->dtvs_state->dts_nretained--; dtrace_retained_gen++; } if (enab->dten_prev == NULL) { if (dtrace_retained == enab) { dtrace_retained = enab->dten_next; if (dtrace_retained != NULL) dtrace_retained->dten_prev = NULL; } } else { ASSERT(enab != dtrace_retained); ASSERT(dtrace_retained != NULL); enab->dten_prev->dten_next = enab->dten_next; } if (enab->dten_next != NULL) { ASSERT(dtrace_retained != NULL); enab->dten_next->dten_prev = enab->dten_prev; } kmem_free(enab, sizeof (dtrace_enabling_t)); } static int dtrace_enabling_retain(dtrace_enabling_t *enab) { dtrace_state_t *state; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(enab->dten_next == NULL && enab->dten_prev == NULL); ASSERT(enab->dten_vstate != NULL); state = enab->dten_vstate->dtvs_state; ASSERT(state != NULL); /* * We only allow each state to retain dtrace_retain_max enablings. */ if (state->dts_nretained >= dtrace_retain_max) return (ENOSPC); state->dts_nretained++; dtrace_retained_gen++; if (dtrace_retained == NULL) { dtrace_retained = enab; return (0); } enab->dten_next = dtrace_retained; dtrace_retained->dten_prev = enab; dtrace_retained = enab; return (0); } static int dtrace_enabling_replicate(dtrace_state_t *state, dtrace_probedesc_t *match, dtrace_probedesc_t *create) { dtrace_enabling_t *new, *enab; int found = 0, err = ENOENT; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(strlen(match->dtpd_provider) < DTRACE_PROVNAMELEN); ASSERT(strlen(match->dtpd_mod) < DTRACE_MODNAMELEN); ASSERT(strlen(match->dtpd_func) < DTRACE_FUNCNAMELEN); ASSERT(strlen(match->dtpd_name) < DTRACE_NAMELEN); new = dtrace_enabling_create(&state->dts_vstate); /* * Iterate over all retained enablings, looking for enablings that * match the specified state. */ for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) { int i; /* * dtvs_state can only be NULL for helper enablings -- and * helper enablings can't be retained. */ ASSERT(enab->dten_vstate->dtvs_state != NULL); if (enab->dten_vstate->dtvs_state != state) continue; /* * Now iterate over each probe description; we're looking for * an exact match to the specified probe description. */ for (i = 0; i < enab->dten_ndesc; i++) { dtrace_ecbdesc_t *ep = enab->dten_desc[i]; dtrace_probedesc_t *pd = &ep->dted_probe; if (strcmp(pd->dtpd_provider, match->dtpd_provider)) continue; if (strcmp(pd->dtpd_mod, match->dtpd_mod)) continue; if (strcmp(pd->dtpd_func, match->dtpd_func)) continue; if (strcmp(pd->dtpd_name, match->dtpd_name)) continue; /* * We have a winning probe! Add it to our growing * enabling. */ found = 1; dtrace_enabling_addlike(new, ep, create); } } if (!found || (err = dtrace_enabling_retain(new)) != 0) { dtrace_enabling_destroy(new); return (err); } return (0); } static void dtrace_enabling_retract(dtrace_state_t *state) { dtrace_enabling_t *enab, *next; ASSERT(MUTEX_HELD(&dtrace_lock)); /* * Iterate over all retained enablings, destroy the enablings retained * for the specified state. */ for (enab = dtrace_retained; enab != NULL; enab = next) { next = enab->dten_next; /* * dtvs_state can only be NULL for helper enablings -- and * helper enablings can't be retained. */ ASSERT(enab->dten_vstate->dtvs_state != NULL); if (enab->dten_vstate->dtvs_state == state) { ASSERT(state->dts_nretained > 0); dtrace_enabling_destroy(enab); } } ASSERT(state->dts_nretained == 0); } static int dtrace_enabling_match(dtrace_enabling_t *enab, int *nmatched) { int i = 0; int matched = 0; ASSERT(MUTEX_HELD(&cpu_lock)); ASSERT(MUTEX_HELD(&dtrace_lock)); for (i = 0; i < enab->dten_ndesc; i++) { dtrace_ecbdesc_t *ep = enab->dten_desc[i]; enab->dten_current = ep; enab->dten_error = 0; matched += dtrace_probe_enable(&ep->dted_probe, enab); if (enab->dten_error != 0) { /* * If we get an error half-way through enabling the * probes, we kick out -- perhaps with some number of * them enabled. Leaving enabled probes enabled may * be slightly confusing for user-level, but we expect * that no one will attempt to actually drive on in * the face of such errors. If this is an anonymous * enabling (indicated with a NULL nmatched pointer), * we cmn_err() a message. We aren't expecting to * get such an error -- such as it can exist at all, * it would be a result of corrupted DOF in the driver * properties. */ if (nmatched == NULL) { cmn_err(CE_WARN, "dtrace_enabling_match() " "error on %p: %d", (void *)ep, enab->dten_error); } return (enab->dten_error); } } enab->dten_probegen = dtrace_probegen; if (nmatched != NULL) *nmatched = matched; return (0); } static void dtrace_enabling_matchall(void) { dtrace_enabling_t *enab; mutex_enter(&cpu_lock); mutex_enter(&dtrace_lock); /* * Iterate over all retained enablings to see if any probes match * against them. We only perform this operation on enablings for which * we have sufficient permissions by virtue of being in the global zone * or in the same zone as the DTrace client. Because we can be called * after dtrace_detach() has been called, we cannot assert that there * are retained enablings. We can safely load from dtrace_retained, * however: the taskq_destroy() at the end of dtrace_detach() will * block pending our completion. */ for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) { #ifdef illumos cred_t *cr = enab->dten_vstate->dtvs_state->dts_cred.dcr_cred; if (INGLOBALZONE(curproc) || cr != NULL && getzoneid() == crgetzoneid(cr)) #endif (void) dtrace_enabling_match(enab, NULL); } mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); } /* * If an enabling is to be enabled without having matched probes (that is, if * dtrace_state_go() is to be called on the underlying dtrace_state_t), the * enabling must be _primed_ by creating an ECB for every ECB description. * This must be done to assure that we know the number of speculations, the * number of aggregations, the minimum buffer size needed, etc. before we * transition out of DTRACE_ACTIVITY_INACTIVE. To do this without actually * enabling any probes, we create ECBs for every ECB decription, but with a * NULL probe -- which is exactly what this function does. */ static void dtrace_enabling_prime(dtrace_state_t *state) { dtrace_enabling_t *enab; int i; for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) { ASSERT(enab->dten_vstate->dtvs_state != NULL); if (enab->dten_vstate->dtvs_state != state) continue; /* * We don't want to prime an enabling more than once, lest * we allow a malicious user to induce resource exhaustion. * (The ECBs that result from priming an enabling aren't * leaked -- but they also aren't deallocated until the * consumer state is destroyed.) */ if (enab->dten_primed) continue; for (i = 0; i < enab->dten_ndesc; i++) { enab->dten_current = enab->dten_desc[i]; (void) dtrace_probe_enable(NULL, enab); } enab->dten_primed = 1; } } /* * Called to indicate that probes should be provided due to retained * enablings. This is implemented in terms of dtrace_probe_provide(), but it * must take an initial lap through the enabling calling the dtps_provide() * entry point explicitly to allow for autocreated probes. */ static void dtrace_enabling_provide(dtrace_provider_t *prv) { int i, all = 0; dtrace_probedesc_t desc; dtrace_genid_t gen; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(MUTEX_HELD(&dtrace_provider_lock)); if (prv == NULL) { all = 1; prv = dtrace_provider; } do { dtrace_enabling_t *enab; void *parg = prv->dtpv_arg; retry: gen = dtrace_retained_gen; for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) { for (i = 0; i < enab->dten_ndesc; i++) { desc = enab->dten_desc[i]->dted_probe; mutex_exit(&dtrace_lock); prv->dtpv_pops.dtps_provide(parg, &desc); mutex_enter(&dtrace_lock); /* * Process the retained enablings again if * they have changed while we weren't holding * dtrace_lock. */ if (gen != dtrace_retained_gen) goto retry; } } } while (all && (prv = prv->dtpv_next) != NULL); mutex_exit(&dtrace_lock); dtrace_probe_provide(NULL, all ? NULL : prv); mutex_enter(&dtrace_lock); } /* * Called to reap ECBs that are attached to probes from defunct providers. */ static void dtrace_enabling_reap(void) { dtrace_provider_t *prov; dtrace_probe_t *probe; dtrace_ecb_t *ecb; hrtime_t when; int i; mutex_enter(&cpu_lock); mutex_enter(&dtrace_lock); for (i = 0; i < dtrace_nprobes; i++) { if ((probe = dtrace_probes[i]) == NULL) continue; if (probe->dtpr_ecb == NULL) continue; prov = probe->dtpr_provider; if ((when = prov->dtpv_defunct) == 0) continue; /* * We have ECBs on a defunct provider: we want to reap these * ECBs to allow the provider to unregister. The destruction * of these ECBs must be done carefully: if we destroy the ECB * and the consumer later wishes to consume an EPID that * corresponds to the destroyed ECB (and if the EPID metadata * has not been previously consumed), the consumer will abort * processing on the unknown EPID. To reduce (but not, sadly, * eliminate) the possibility of this, we will only destroy an * ECB for a defunct provider if, for the state that * corresponds to the ECB: * * (a) There is no speculative tracing (which can effectively * cache an EPID for an arbitrary amount of time). * * (b) The principal buffers have been switched twice since the * provider became defunct. * * (c) The aggregation buffers are of zero size or have been * switched twice since the provider became defunct. * * We use dts_speculates to determine (a) and call a function * (dtrace_buffer_consumed()) to determine (b) and (c). Note * that as soon as we've been unable to destroy one of the ECBs * associated with the probe, we quit trying -- reaping is only * fruitful in as much as we can destroy all ECBs associated * with the defunct provider's probes. */ while ((ecb = probe->dtpr_ecb) != NULL) { dtrace_state_t *state = ecb->dte_state; dtrace_buffer_t *buf = state->dts_buffer; dtrace_buffer_t *aggbuf = state->dts_aggbuffer; if (state->dts_speculates) break; if (!dtrace_buffer_consumed(buf, when)) break; if (!dtrace_buffer_consumed(aggbuf, when)) break; dtrace_ecb_disable(ecb); ASSERT(probe->dtpr_ecb != ecb); dtrace_ecb_destroy(ecb); } } mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); } /* * DTrace DOF Functions */ /*ARGSUSED*/ static void dtrace_dof_error(dof_hdr_t *dof, const char *str) { if (dtrace_err_verbose) cmn_err(CE_WARN, "failed to process DOF: %s", str); #ifdef DTRACE_ERRDEBUG dtrace_errdebug(str); #endif } /* * Create DOF out of a currently enabled state. Right now, we only create * DOF containing the run-time options -- but this could be expanded to create * complete DOF representing the enabled state. */ static dof_hdr_t * dtrace_dof_create(dtrace_state_t *state) { dof_hdr_t *dof; dof_sec_t *sec; dof_optdesc_t *opt; int i, len = sizeof (dof_hdr_t) + roundup(sizeof (dof_sec_t), sizeof (uint64_t)) + sizeof (dof_optdesc_t) * DTRACEOPT_MAX; ASSERT(MUTEX_HELD(&dtrace_lock)); dof = kmem_zalloc(len, KM_SLEEP); dof->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; dof->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; dof->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; dof->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION; dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION; dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS; dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS; dof->dofh_flags = 0; dof->dofh_hdrsize = sizeof (dof_hdr_t); dof->dofh_secsize = sizeof (dof_sec_t); dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */ dof->dofh_secoff = sizeof (dof_hdr_t); dof->dofh_loadsz = len; dof->dofh_filesz = len; dof->dofh_pad = 0; /* * Fill in the option section header... */ sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t)); sec->dofs_type = DOF_SECT_OPTDESC; sec->dofs_align = sizeof (uint64_t); sec->dofs_flags = DOF_SECF_LOAD; sec->dofs_entsize = sizeof (dof_optdesc_t); opt = (dof_optdesc_t *)((uintptr_t)sec + roundup(sizeof (dof_sec_t), sizeof (uint64_t))); sec->dofs_offset = (uintptr_t)opt - (uintptr_t)dof; sec->dofs_size = sizeof (dof_optdesc_t) * DTRACEOPT_MAX; for (i = 0; i < DTRACEOPT_MAX; i++) { opt[i].dofo_option = i; opt[i].dofo_strtab = DOF_SECIDX_NONE; opt[i].dofo_value = state->dts_options[i]; } return (dof); } static dof_hdr_t * dtrace_dof_copyin(uintptr_t uarg, int *errp) { dof_hdr_t hdr, *dof; ASSERT(!MUTEX_HELD(&dtrace_lock)); /* * First, we're going to copyin() the sizeof (dof_hdr_t). */ if (copyin((void *)uarg, &hdr, sizeof (hdr)) != 0) { dtrace_dof_error(NULL, "failed to copyin DOF header"); *errp = EFAULT; return (NULL); } /* * Now we'll allocate the entire DOF and copy it in -- provided * that the length isn't outrageous. */ if (hdr.dofh_loadsz >= dtrace_dof_maxsize) { dtrace_dof_error(&hdr, "load size exceeds maximum"); *errp = E2BIG; return (NULL); } if (hdr.dofh_loadsz < sizeof (hdr)) { dtrace_dof_error(&hdr, "invalid load size"); *errp = EINVAL; return (NULL); } dof = kmem_alloc(hdr.dofh_loadsz, KM_SLEEP); if (copyin((void *)uarg, dof, hdr.dofh_loadsz) != 0 || dof->dofh_loadsz != hdr.dofh_loadsz) { kmem_free(dof, hdr.dofh_loadsz); *errp = EFAULT; return (NULL); } return (dof); } #ifdef __FreeBSD__ static dof_hdr_t * dtrace_dof_copyin_proc(struct proc *p, uintptr_t uarg, int *errp) { dof_hdr_t hdr, *dof; struct thread *td; size_t loadsz; ASSERT(!MUTEX_HELD(&dtrace_lock)); td = curthread; /* * First, we're going to copyin() the sizeof (dof_hdr_t). */ if (proc_readmem(td, p, uarg, &hdr, sizeof(hdr)) != sizeof(hdr)) { dtrace_dof_error(NULL, "failed to copyin DOF header"); *errp = EFAULT; return (NULL); } /* * Now we'll allocate the entire DOF and copy it in -- provided * that the length isn't outrageous. */ if (hdr.dofh_loadsz >= dtrace_dof_maxsize) { dtrace_dof_error(&hdr, "load size exceeds maximum"); *errp = E2BIG; return (NULL); } loadsz = (size_t)hdr.dofh_loadsz; if (loadsz < sizeof (hdr)) { dtrace_dof_error(&hdr, "invalid load size"); *errp = EINVAL; return (NULL); } dof = kmem_alloc(loadsz, KM_SLEEP); if (proc_readmem(td, p, uarg, dof, loadsz) != loadsz || dof->dofh_loadsz != loadsz) { kmem_free(dof, hdr.dofh_loadsz); *errp = EFAULT; return (NULL); } return (dof); } static __inline uchar_t dtrace_dof_char(char c) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return (c - '0'); case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': return (c - 'A' + 10); case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return (c - 'a' + 10); } /* Should not reach here. */ return (UCHAR_MAX); } #endif /* __FreeBSD__ */ static dof_hdr_t * dtrace_dof_property(const char *name) { #ifdef __FreeBSD__ uint8_t *dofbuf; u_char *data, *eol; caddr_t doffile; size_t bytes, len, i; dof_hdr_t *dof; u_char c1, c2; dof = NULL; doffile = preload_search_by_type("dtrace_dof"); if (doffile == NULL) return (NULL); data = preload_fetch_addr(doffile); len = preload_fetch_size(doffile); for (;;) { /* Look for the end of the line. All lines end in a newline. */ eol = memchr(data, '\n', len); if (eol == NULL) return (NULL); if (strncmp(name, data, strlen(name)) == 0) break; eol++; /* skip past the newline */ len -= eol - data; data = eol; } /* We've found the data corresponding to the specified key. */ data += strlen(name) + 1; /* skip past the '=' */ len = eol - data; + if (len % 2 != 0) { + dtrace_dof_error(NULL, "invalid DOF encoding length"); + goto doferr; + } bytes = len / 2; - if (bytes < sizeof(dof_hdr_t)) { dtrace_dof_error(NULL, "truncated header"); goto doferr; } /* * Each byte is represented by the two ASCII characters in its hex * representation. */ dofbuf = malloc(bytes, M_SOLARIS, M_WAITOK); for (i = 0; i < bytes; i++) { c1 = dtrace_dof_char(data[i * 2]); c2 = dtrace_dof_char(data[i * 2 + 1]); if (c1 == UCHAR_MAX || c2 == UCHAR_MAX) { dtrace_dof_error(NULL, "invalid hex char in DOF"); goto doferr; } dofbuf[i] = c1 * 16 + c2; } dof = (dof_hdr_t *)dofbuf; if (bytes < dof->dofh_loadsz) { dtrace_dof_error(NULL, "truncated DOF"); goto doferr; } if (dof->dofh_loadsz >= dtrace_dof_maxsize) { dtrace_dof_error(NULL, "oversized DOF"); goto doferr; } return (dof); doferr: free(dof, M_SOLARIS); return (NULL); #else /* __FreeBSD__ */ uchar_t *buf; uint64_t loadsz; unsigned int len, i; dof_hdr_t *dof; /* * Unfortunately, array of values in .conf files are always (and * only) interpreted to be integer arrays. We must read our DOF * as an integer array, and then squeeze it into a byte array. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dtrace_devi, 0, (char *)name, (int **)&buf, &len) != DDI_PROP_SUCCESS) return (NULL); for (i = 0; i < len; i++) buf[i] = (uchar_t)(((int *)buf)[i]); if (len < sizeof (dof_hdr_t)) { ddi_prop_free(buf); dtrace_dof_error(NULL, "truncated header"); return (NULL); } if (len < (loadsz = ((dof_hdr_t *)buf)->dofh_loadsz)) { ddi_prop_free(buf); dtrace_dof_error(NULL, "truncated DOF"); return (NULL); } if (loadsz >= dtrace_dof_maxsize) { ddi_prop_free(buf); dtrace_dof_error(NULL, "oversized DOF"); return (NULL); } dof = kmem_alloc(loadsz, KM_SLEEP); bcopy(buf, dof, loadsz); ddi_prop_free(buf); return (dof); #endif /* !__FreeBSD__ */ } static void dtrace_dof_destroy(dof_hdr_t *dof) { kmem_free(dof, dof->dofh_loadsz); } /* * Return the dof_sec_t pointer corresponding to a given section index. If the * index is not valid, dtrace_dof_error() is called and NULL is returned. If * a type other than DOF_SECT_NONE is specified, the header is checked against * this type and NULL is returned if the types do not match. */ static dof_sec_t * dtrace_dof_sect(dof_hdr_t *dof, uint32_t type, dof_secidx_t i) { dof_sec_t *sec = (dof_sec_t *)(uintptr_t) ((uintptr_t)dof + dof->dofh_secoff + i * dof->dofh_secsize); if (i >= dof->dofh_secnum) { dtrace_dof_error(dof, "referenced section index is invalid"); return (NULL); } if (!(sec->dofs_flags & DOF_SECF_LOAD)) { dtrace_dof_error(dof, "referenced section is not loadable"); return (NULL); } if (type != DOF_SECT_NONE && type != sec->dofs_type) { dtrace_dof_error(dof, "referenced section is the wrong type"); return (NULL); } return (sec); } static dtrace_probedesc_t * dtrace_dof_probedesc(dof_hdr_t *dof, dof_sec_t *sec, dtrace_probedesc_t *desc) { dof_probedesc_t *probe; dof_sec_t *strtab; uintptr_t daddr = (uintptr_t)dof; uintptr_t str; size_t size; if (sec->dofs_type != DOF_SECT_PROBEDESC) { dtrace_dof_error(dof, "invalid probe section"); return (NULL); } if (sec->dofs_align != sizeof (dof_secidx_t)) { dtrace_dof_error(dof, "bad alignment in probe description"); return (NULL); } if (sec->dofs_offset + sizeof (dof_probedesc_t) > dof->dofh_loadsz) { dtrace_dof_error(dof, "truncated probe description"); return (NULL); } probe = (dof_probedesc_t *)(uintptr_t)(daddr + sec->dofs_offset); strtab = dtrace_dof_sect(dof, DOF_SECT_STRTAB, probe->dofp_strtab); if (strtab == NULL) return (NULL); str = daddr + strtab->dofs_offset; size = strtab->dofs_size; if (probe->dofp_provider >= strtab->dofs_size) { dtrace_dof_error(dof, "corrupt probe provider"); return (NULL); } (void) strncpy(desc->dtpd_provider, (char *)(str + probe->dofp_provider), MIN(DTRACE_PROVNAMELEN - 1, size - probe->dofp_provider)); if (probe->dofp_mod >= strtab->dofs_size) { dtrace_dof_error(dof, "corrupt probe module"); return (NULL); } (void) strncpy(desc->dtpd_mod, (char *)(str + probe->dofp_mod), MIN(DTRACE_MODNAMELEN - 1, size - probe->dofp_mod)); if (probe->dofp_func >= strtab->dofs_size) { dtrace_dof_error(dof, "corrupt probe function"); return (NULL); } (void) strncpy(desc->dtpd_func, (char *)(str + probe->dofp_func), MIN(DTRACE_FUNCNAMELEN - 1, size - probe->dofp_func)); if (probe->dofp_name >= strtab->dofs_size) { dtrace_dof_error(dof, "corrupt probe name"); return (NULL); } (void) strncpy(desc->dtpd_name, (char *)(str + probe->dofp_name), MIN(DTRACE_NAMELEN - 1, size - probe->dofp_name)); return (desc); } static dtrace_difo_t * dtrace_dof_difo(dof_hdr_t *dof, dof_sec_t *sec, dtrace_vstate_t *vstate, cred_t *cr) { dtrace_difo_t *dp; size_t ttl = 0; dof_difohdr_t *dofd; uintptr_t daddr = (uintptr_t)dof; size_t max = dtrace_difo_maxsize; int i, l, n; static const struct { int section; int bufoffs; int lenoffs; int entsize; int align; const char *msg; } difo[] = { { DOF_SECT_DIF, offsetof(dtrace_difo_t, dtdo_buf), offsetof(dtrace_difo_t, dtdo_len), sizeof (dif_instr_t), sizeof (dif_instr_t), "multiple DIF sections" }, { DOF_SECT_INTTAB, offsetof(dtrace_difo_t, dtdo_inttab), offsetof(dtrace_difo_t, dtdo_intlen), sizeof (uint64_t), sizeof (uint64_t), "multiple integer tables" }, { DOF_SECT_STRTAB, offsetof(dtrace_difo_t, dtdo_strtab), offsetof(dtrace_difo_t, dtdo_strlen), 0, sizeof (char), "multiple string tables" }, { DOF_SECT_VARTAB, offsetof(dtrace_difo_t, dtdo_vartab), offsetof(dtrace_difo_t, dtdo_varlen), sizeof (dtrace_difv_t), sizeof (uint_t), "multiple variable tables" }, { DOF_SECT_NONE, 0, 0, 0, 0, NULL } }; if (sec->dofs_type != DOF_SECT_DIFOHDR) { dtrace_dof_error(dof, "invalid DIFO header section"); return (NULL); } if (sec->dofs_align != sizeof (dof_secidx_t)) { dtrace_dof_error(dof, "bad alignment in DIFO header"); return (NULL); } if (sec->dofs_size < sizeof (dof_difohdr_t) || sec->dofs_size % sizeof (dof_secidx_t)) { dtrace_dof_error(dof, "bad size in DIFO header"); return (NULL); } dofd = (dof_difohdr_t *)(uintptr_t)(daddr + sec->dofs_offset); n = (sec->dofs_size - sizeof (*dofd)) / sizeof (dof_secidx_t) + 1; dp = kmem_zalloc(sizeof (dtrace_difo_t), KM_SLEEP); dp->dtdo_rtype = dofd->dofd_rtype; for (l = 0; l < n; l++) { dof_sec_t *subsec; void **bufp; uint32_t *lenp; if ((subsec = dtrace_dof_sect(dof, DOF_SECT_NONE, dofd->dofd_links[l])) == NULL) goto err; /* invalid section link */ if (ttl + subsec->dofs_size > max) { dtrace_dof_error(dof, "exceeds maximum size"); goto err; } ttl += subsec->dofs_size; for (i = 0; difo[i].section != DOF_SECT_NONE; i++) { if (subsec->dofs_type != difo[i].section) continue; if (!(subsec->dofs_flags & DOF_SECF_LOAD)) { dtrace_dof_error(dof, "section not loaded"); goto err; } if (subsec->dofs_align != difo[i].align) { dtrace_dof_error(dof, "bad alignment"); goto err; } bufp = (void **)((uintptr_t)dp + difo[i].bufoffs); lenp = (uint32_t *)((uintptr_t)dp + difo[i].lenoffs); if (*bufp != NULL) { dtrace_dof_error(dof, difo[i].msg); goto err; } if (difo[i].entsize != subsec->dofs_entsize) { dtrace_dof_error(dof, "entry size mismatch"); goto err; } if (subsec->dofs_entsize != 0 && (subsec->dofs_size % subsec->dofs_entsize) != 0) { dtrace_dof_error(dof, "corrupt entry size"); goto err; } *lenp = subsec->dofs_size; *bufp = kmem_alloc(subsec->dofs_size, KM_SLEEP); bcopy((char *)(uintptr_t)(daddr + subsec->dofs_offset), *bufp, subsec->dofs_size); if (subsec->dofs_entsize != 0) *lenp /= subsec->dofs_entsize; break; } /* * If we encounter a loadable DIFO sub-section that is not * known to us, assume this is a broken program and fail. */ if (difo[i].section == DOF_SECT_NONE && (subsec->dofs_flags & DOF_SECF_LOAD)) { dtrace_dof_error(dof, "unrecognized DIFO subsection"); goto err; } } if (dp->dtdo_buf == NULL) { /* * We can't have a DIF object without DIF text. */ dtrace_dof_error(dof, "missing DIF text"); goto err; } /* * Before we validate the DIF object, run through the variable table * looking for the strings -- if any of their size are under, we'll set * their size to be the system-wide default string size. Note that * this should _not_ happen if the "strsize" option has been set -- * in this case, the compiler should have set the size to reflect the * setting of the option. */ for (i = 0; i < dp->dtdo_varlen; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i]; dtrace_diftype_t *t = &v->dtdv_type; if (v->dtdv_id < DIF_VAR_OTHER_UBASE) continue; if (t->dtdt_kind == DIF_TYPE_STRING && t->dtdt_size == 0) t->dtdt_size = dtrace_strsize_default; } if (dtrace_difo_validate(dp, vstate, DIF_DIR_NREGS, cr) != 0) goto err; dtrace_difo_init(dp, vstate); return (dp); err: kmem_free(dp->dtdo_buf, dp->dtdo_len * sizeof (dif_instr_t)); kmem_free(dp->dtdo_inttab, dp->dtdo_intlen * sizeof (uint64_t)); kmem_free(dp->dtdo_strtab, dp->dtdo_strlen); kmem_free(dp->dtdo_vartab, dp->dtdo_varlen * sizeof (dtrace_difv_t)); kmem_free(dp, sizeof (dtrace_difo_t)); return (NULL); } static dtrace_predicate_t * dtrace_dof_predicate(dof_hdr_t *dof, dof_sec_t *sec, dtrace_vstate_t *vstate, cred_t *cr) { dtrace_difo_t *dp; if ((dp = dtrace_dof_difo(dof, sec, vstate, cr)) == NULL) return (NULL); return (dtrace_predicate_create(dp)); } static dtrace_actdesc_t * dtrace_dof_actdesc(dof_hdr_t *dof, dof_sec_t *sec, dtrace_vstate_t *vstate, cred_t *cr) { dtrace_actdesc_t *act, *first = NULL, *last = NULL, *next; dof_actdesc_t *desc; dof_sec_t *difosec; size_t offs; uintptr_t daddr = (uintptr_t)dof; uint64_t arg; dtrace_actkind_t kind; if (sec->dofs_type != DOF_SECT_ACTDESC) { dtrace_dof_error(dof, "invalid action section"); return (NULL); } if (sec->dofs_offset + sizeof (dof_actdesc_t) > dof->dofh_loadsz) { dtrace_dof_error(dof, "truncated action description"); return (NULL); } if (sec->dofs_align != sizeof (uint64_t)) { dtrace_dof_error(dof, "bad alignment in action description"); return (NULL); } if (sec->dofs_size < sec->dofs_entsize) { dtrace_dof_error(dof, "section entry size exceeds total size"); return (NULL); } if (sec->dofs_entsize != sizeof (dof_actdesc_t)) { dtrace_dof_error(dof, "bad entry size in action description"); return (NULL); } if (sec->dofs_size / sec->dofs_entsize > dtrace_actions_max) { dtrace_dof_error(dof, "actions exceed dtrace_actions_max"); return (NULL); } for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) { desc = (dof_actdesc_t *)(daddr + (uintptr_t)sec->dofs_offset + offs); kind = (dtrace_actkind_t)desc->dofa_kind; if ((DTRACEACT_ISPRINTFLIKE(kind) && (kind != DTRACEACT_PRINTA || desc->dofa_strtab != DOF_SECIDX_NONE)) || (kind == DTRACEACT_DIFEXPR && desc->dofa_strtab != DOF_SECIDX_NONE)) { dof_sec_t *strtab; char *str, *fmt; uint64_t i; /* * The argument to these actions is an index into the * DOF string table. For printf()-like actions, this * is the format string. For print(), this is the * CTF type of the expression result. */ if ((strtab = dtrace_dof_sect(dof, DOF_SECT_STRTAB, desc->dofa_strtab)) == NULL) goto err; str = (char *)((uintptr_t)dof + (uintptr_t)strtab->dofs_offset); for (i = desc->dofa_arg; i < strtab->dofs_size; i++) { if (str[i] == '\0') break; } if (i >= strtab->dofs_size) { dtrace_dof_error(dof, "bogus format string"); goto err; } if (i == desc->dofa_arg) { dtrace_dof_error(dof, "empty format string"); goto err; } i -= desc->dofa_arg; fmt = kmem_alloc(i + 1, KM_SLEEP); bcopy(&str[desc->dofa_arg], fmt, i + 1); arg = (uint64_t)(uintptr_t)fmt; } else { if (kind == DTRACEACT_PRINTA) { ASSERT(desc->dofa_strtab == DOF_SECIDX_NONE); arg = 0; } else { arg = desc->dofa_arg; } } act = dtrace_actdesc_create(kind, desc->dofa_ntuple, desc->dofa_uarg, arg); if (last != NULL) { last->dtad_next = act; } else { first = act; } last = act; if (desc->dofa_difo == DOF_SECIDX_NONE) continue; if ((difosec = dtrace_dof_sect(dof, DOF_SECT_DIFOHDR, desc->dofa_difo)) == NULL) goto err; act->dtad_difo = dtrace_dof_difo(dof, difosec, vstate, cr); if (act->dtad_difo == NULL) goto err; } ASSERT(first != NULL); return (first); err: for (act = first; act != NULL; act = next) { next = act->dtad_next; dtrace_actdesc_release(act, vstate); } return (NULL); } static dtrace_ecbdesc_t * dtrace_dof_ecbdesc(dof_hdr_t *dof, dof_sec_t *sec, dtrace_vstate_t *vstate, cred_t *cr) { dtrace_ecbdesc_t *ep; dof_ecbdesc_t *ecb; dtrace_probedesc_t *desc; dtrace_predicate_t *pred = NULL; if (sec->dofs_size < sizeof (dof_ecbdesc_t)) { dtrace_dof_error(dof, "truncated ECB description"); return (NULL); } if (sec->dofs_align != sizeof (uint64_t)) { dtrace_dof_error(dof, "bad alignment in ECB description"); return (NULL); } ecb = (dof_ecbdesc_t *)((uintptr_t)dof + (uintptr_t)sec->dofs_offset); sec = dtrace_dof_sect(dof, DOF_SECT_PROBEDESC, ecb->dofe_probes); if (sec == NULL) return (NULL); ep = kmem_zalloc(sizeof (dtrace_ecbdesc_t), KM_SLEEP); ep->dted_uarg = ecb->dofe_uarg; desc = &ep->dted_probe; if (dtrace_dof_probedesc(dof, sec, desc) == NULL) goto err; if (ecb->dofe_pred != DOF_SECIDX_NONE) { if ((sec = dtrace_dof_sect(dof, DOF_SECT_DIFOHDR, ecb->dofe_pred)) == NULL) goto err; if ((pred = dtrace_dof_predicate(dof, sec, vstate, cr)) == NULL) goto err; ep->dted_pred.dtpdd_predicate = pred; } if (ecb->dofe_actions != DOF_SECIDX_NONE) { if ((sec = dtrace_dof_sect(dof, DOF_SECT_ACTDESC, ecb->dofe_actions)) == NULL) goto err; ep->dted_action = dtrace_dof_actdesc(dof, sec, vstate, cr); if (ep->dted_action == NULL) goto err; } return (ep); err: if (pred != NULL) dtrace_predicate_release(pred, vstate); kmem_free(ep, sizeof (dtrace_ecbdesc_t)); return (NULL); } /* * Apply the relocations from the specified 'sec' (a DOF_SECT_URELHDR) to the - * specified DOF. At present, this amounts to simply adding 'ubase' to the - * site of any user SETX relocations to account for load object base address. - * In the future, if we need other relocations, this function can be extended. + * specified DOF. SETX relocations are computed using 'ubase', the base load + * address of the object containing the DOF, and DOFREL relocations are relative + * to the relocation offset within the DOF. */ static int -dtrace_dof_relocate(dof_hdr_t *dof, dof_sec_t *sec, uint64_t ubase) +dtrace_dof_relocate(dof_hdr_t *dof, dof_sec_t *sec, uint64_t ubase, + uint64_t udaddr) { uintptr_t daddr = (uintptr_t)dof; dof_relohdr_t *dofr = (dof_relohdr_t *)(uintptr_t)(daddr + sec->dofs_offset); dof_sec_t *ss, *rs, *ts; dof_relodesc_t *r; uint_t i, n; if (sec->dofs_size < sizeof (dof_relohdr_t) || sec->dofs_align != sizeof (dof_secidx_t)) { dtrace_dof_error(dof, "invalid relocation header"); return (-1); } ss = dtrace_dof_sect(dof, DOF_SECT_STRTAB, dofr->dofr_strtab); rs = dtrace_dof_sect(dof, DOF_SECT_RELTAB, dofr->dofr_relsec); ts = dtrace_dof_sect(dof, DOF_SECT_NONE, dofr->dofr_tgtsec); if (ss == NULL || rs == NULL || ts == NULL) return (-1); /* dtrace_dof_error() has been called already */ if (rs->dofs_entsize < sizeof (dof_relodesc_t) || rs->dofs_align != sizeof (uint64_t)) { dtrace_dof_error(dof, "invalid relocation section"); return (-1); } r = (dof_relodesc_t *)(uintptr_t)(daddr + rs->dofs_offset); n = rs->dofs_size / rs->dofs_entsize; for (i = 0; i < n; i++) { uintptr_t taddr = daddr + ts->dofs_offset + r->dofr_offset; switch (r->dofr_type) { case DOF_RELO_NONE: break; case DOF_RELO_SETX: + case DOF_RELO_DOFREL: if (r->dofr_offset >= ts->dofs_size || r->dofr_offset + sizeof (uint64_t) > ts->dofs_size) { dtrace_dof_error(dof, "bad relocation offset"); return (-1); } if (!IS_P2ALIGNED(taddr, sizeof (uint64_t))) { dtrace_dof_error(dof, "misaligned setx relo"); return (-1); } - *(uint64_t *)taddr += ubase; + if (r->dofr_type == DOF_RELO_SETX) + *(uint64_t *)taddr += ubase; + else + *(uint64_t *)taddr += + udaddr + ts->dofs_offset + r->dofr_offset; break; default: dtrace_dof_error(dof, "invalid relocation type"); return (-1); } r = (dof_relodesc_t *)((uintptr_t)r + rs->dofs_entsize); } return (0); } /* * The dof_hdr_t passed to dtrace_dof_slurp() should be a partially validated * header: it should be at the front of a memory region that is at least * sizeof (dof_hdr_t) in size -- and then at least dof_hdr.dofh_loadsz in * size. It need not be validated in any other way. */ static int dtrace_dof_slurp(dof_hdr_t *dof, dtrace_vstate_t *vstate, cred_t *cr, - dtrace_enabling_t **enabp, uint64_t ubase, int noprobes) + dtrace_enabling_t **enabp, uint64_t ubase, uint64_t udaddr, int noprobes) { uint64_t len = dof->dofh_loadsz, seclen; uintptr_t daddr = (uintptr_t)dof; dtrace_ecbdesc_t *ep; dtrace_enabling_t *enab; uint_t i; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(dof->dofh_loadsz >= sizeof (dof_hdr_t)); /* * Check the DOF header identification bytes. In addition to checking * valid settings, we also verify that unused bits/bytes are zeroed so * we can use them later without fear of regressing existing binaries. */ if (bcmp(&dof->dofh_ident[DOF_ID_MAG0], DOF_MAG_STRING, DOF_MAG_STRLEN) != 0) { dtrace_dof_error(dof, "DOF magic string mismatch"); return (-1); } if (dof->dofh_ident[DOF_ID_MODEL] != DOF_MODEL_ILP32 && dof->dofh_ident[DOF_ID_MODEL] != DOF_MODEL_LP64) { dtrace_dof_error(dof, "DOF has invalid data model"); return (-1); } if (dof->dofh_ident[DOF_ID_ENCODING] != DOF_ENCODE_NATIVE) { dtrace_dof_error(dof, "DOF encoding mismatch"); return (-1); } if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_2) { dtrace_dof_error(dof, "DOF version mismatch"); return (-1); } if (dof->dofh_ident[DOF_ID_DIFVERS] != DIF_VERSION_2) { dtrace_dof_error(dof, "DOF uses unsupported instruction set"); return (-1); } if (dof->dofh_ident[DOF_ID_DIFIREG] > DIF_DIR_NREGS) { dtrace_dof_error(dof, "DOF uses too many integer registers"); return (-1); } if (dof->dofh_ident[DOF_ID_DIFTREG] > DIF_DTR_NREGS) { dtrace_dof_error(dof, "DOF uses too many tuple registers"); return (-1); } for (i = DOF_ID_PAD; i < DOF_ID_SIZE; i++) { if (dof->dofh_ident[i] != 0) { dtrace_dof_error(dof, "DOF has invalid ident byte set"); return (-1); } } if (dof->dofh_flags & ~DOF_FL_VALID) { dtrace_dof_error(dof, "DOF has invalid flag bits set"); return (-1); } if (dof->dofh_secsize == 0) { dtrace_dof_error(dof, "zero section header size"); return (-1); } /* * Check that the section headers don't exceed the amount of DOF * data. Note that we cast the section size and number of sections * to uint64_t's to prevent possible overflow in the multiplication. */ seclen = (uint64_t)dof->dofh_secnum * (uint64_t)dof->dofh_secsize; if (dof->dofh_secoff > len || seclen > len || dof->dofh_secoff + seclen > len) { dtrace_dof_error(dof, "truncated section headers"); return (-1); } if (!IS_P2ALIGNED(dof->dofh_secoff, sizeof (uint64_t))) { dtrace_dof_error(dof, "misaligned section headers"); return (-1); } if (!IS_P2ALIGNED(dof->dofh_secsize, sizeof (uint64_t))) { dtrace_dof_error(dof, "misaligned section size"); return (-1); } /* * Take an initial pass through the section headers to be sure that * the headers don't have stray offsets. If the 'noprobes' flag is * set, do not permit sections relating to providers, probes, or args. */ for (i = 0; i < dof->dofh_secnum; i++) { dof_sec_t *sec = (dof_sec_t *)(daddr + (uintptr_t)dof->dofh_secoff + i * dof->dofh_secsize); if (noprobes) { switch (sec->dofs_type) { case DOF_SECT_PROVIDER: case DOF_SECT_PROBES: case DOF_SECT_PRARGS: case DOF_SECT_PROFFS: dtrace_dof_error(dof, "illegal sections " "for enabling"); return (-1); } } if (DOF_SEC_ISLOADABLE(sec->dofs_type) && !(sec->dofs_flags & DOF_SECF_LOAD)) { dtrace_dof_error(dof, "loadable section with load " "flag unset"); return (-1); } if (!(sec->dofs_flags & DOF_SECF_LOAD)) continue; /* just ignore non-loadable sections */ if (!ISP2(sec->dofs_align)) { dtrace_dof_error(dof, "bad section alignment"); return (-1); } if (sec->dofs_offset & (sec->dofs_align - 1)) { dtrace_dof_error(dof, "misaligned section"); return (-1); } if (sec->dofs_offset > len || sec->dofs_size > len || sec->dofs_offset + sec->dofs_size > len) { dtrace_dof_error(dof, "corrupt section header"); return (-1); } if (sec->dofs_type == DOF_SECT_STRTAB && *((char *)daddr + sec->dofs_offset + sec->dofs_size - 1) != '\0') { dtrace_dof_error(dof, "non-terminating string table"); return (-1); } } /* * Take a second pass through the sections and locate and perform any * relocations that are present. We do this after the first pass to * be sure that all sections have had their headers validated. */ for (i = 0; i < dof->dofh_secnum; i++) { dof_sec_t *sec = (dof_sec_t *)(daddr + (uintptr_t)dof->dofh_secoff + i * dof->dofh_secsize); if (!(sec->dofs_flags & DOF_SECF_LOAD)) continue; /* skip sections that are not loadable */ switch (sec->dofs_type) { case DOF_SECT_URELHDR: - if (dtrace_dof_relocate(dof, sec, ubase) != 0) + if (dtrace_dof_relocate(dof, sec, ubase, udaddr) != 0) return (-1); break; } } if ((enab = *enabp) == NULL) enab = *enabp = dtrace_enabling_create(vstate); for (i = 0; i < dof->dofh_secnum; i++) { dof_sec_t *sec = (dof_sec_t *)(daddr + (uintptr_t)dof->dofh_secoff + i * dof->dofh_secsize); if (sec->dofs_type != DOF_SECT_ECBDESC) continue; if ((ep = dtrace_dof_ecbdesc(dof, sec, vstate, cr)) == NULL) { dtrace_enabling_destroy(enab); *enabp = NULL; return (-1); } dtrace_enabling_add(enab, ep); } return (0); } /* * Process DOF for any options. This routine assumes that the DOF has been * at least processed by dtrace_dof_slurp(). */ static int dtrace_dof_options(dof_hdr_t *dof, dtrace_state_t *state) { int i, rval; uint32_t entsize; size_t offs; dof_optdesc_t *desc; for (i = 0; i < dof->dofh_secnum; i++) { dof_sec_t *sec = (dof_sec_t *)((uintptr_t)dof + (uintptr_t)dof->dofh_secoff + i * dof->dofh_secsize); if (sec->dofs_type != DOF_SECT_OPTDESC) continue; if (sec->dofs_align != sizeof (uint64_t)) { dtrace_dof_error(dof, "bad alignment in " "option description"); return (EINVAL); } if ((entsize = sec->dofs_entsize) == 0) { dtrace_dof_error(dof, "zeroed option entry size"); return (EINVAL); } if (entsize < sizeof (dof_optdesc_t)) { dtrace_dof_error(dof, "bad option entry size"); return (EINVAL); } for (offs = 0; offs < sec->dofs_size; offs += entsize) { desc = (dof_optdesc_t *)((uintptr_t)dof + (uintptr_t)sec->dofs_offset + offs); if (desc->dofo_strtab != DOF_SECIDX_NONE) { dtrace_dof_error(dof, "non-zero option string"); return (EINVAL); } if (desc->dofo_value == DTRACEOPT_UNSET) { dtrace_dof_error(dof, "unset option"); return (EINVAL); } if ((rval = dtrace_state_option(state, desc->dofo_option, desc->dofo_value)) != 0) { dtrace_dof_error(dof, "rejected option"); return (rval); } } } return (0); } /* * DTrace Consumer State Functions */ static int dtrace_dstate_init(dtrace_dstate_t *dstate, size_t size) { size_t hashsize, maxper, min, chunksize = dstate->dtds_chunksize; void *base; uintptr_t limit; dtrace_dynvar_t *dvar, *next, *start; int i; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(dstate->dtds_base == NULL && dstate->dtds_percpu == NULL); bzero(dstate, sizeof (dtrace_dstate_t)); if ((dstate->dtds_chunksize = chunksize) == 0) dstate->dtds_chunksize = DTRACE_DYNVAR_CHUNKSIZE; VERIFY(dstate->dtds_chunksize < LONG_MAX); if (size < (min = dstate->dtds_chunksize + sizeof (dtrace_dynhash_t))) size = min; if ((base = kmem_zalloc(size, KM_NOSLEEP | KM_NORMALPRI)) == NULL) return (ENOMEM); dstate->dtds_size = size; dstate->dtds_base = base; dstate->dtds_percpu = kmem_cache_alloc(dtrace_state_cache, KM_SLEEP); bzero(dstate->dtds_percpu, NCPU * sizeof (dtrace_dstate_percpu_t)); hashsize = size / (dstate->dtds_chunksize + sizeof (dtrace_dynhash_t)); if (hashsize != 1 && (hashsize & 1)) hashsize--; dstate->dtds_hashsize = hashsize; dstate->dtds_hash = dstate->dtds_base; /* * Set all of our hash buckets to point to the single sink, and (if * it hasn't already been set), set the sink's hash value to be the * sink sentinel value. The sink is needed for dynamic variable * lookups to know that they have iterated over an entire, valid hash * chain. */ for (i = 0; i < hashsize; i++) dstate->dtds_hash[i].dtdh_chain = &dtrace_dynhash_sink; if (dtrace_dynhash_sink.dtdv_hashval != DTRACE_DYNHASH_SINK) dtrace_dynhash_sink.dtdv_hashval = DTRACE_DYNHASH_SINK; /* * Determine number of active CPUs. Divide free list evenly among * active CPUs. */ start = (dtrace_dynvar_t *) ((uintptr_t)base + hashsize * sizeof (dtrace_dynhash_t)); limit = (uintptr_t)base + size; VERIFY((uintptr_t)start < limit); VERIFY((uintptr_t)start >= (uintptr_t)base); maxper = (limit - (uintptr_t)start) / NCPU; maxper = (maxper / dstate->dtds_chunksize) * dstate->dtds_chunksize; #ifndef illumos CPU_FOREACH(i) { #else for (i = 0; i < NCPU; i++) { #endif dstate->dtds_percpu[i].dtdsc_free = dvar = start; /* * If we don't even have enough chunks to make it once through * NCPUs, we're just going to allocate everything to the first * CPU. And if we're on the last CPU, we're going to allocate * whatever is left over. In either case, we set the limit to * be the limit of the dynamic variable space. */ if (maxper == 0 || i == NCPU - 1) { limit = (uintptr_t)base + size; start = NULL; } else { limit = (uintptr_t)start + maxper; start = (dtrace_dynvar_t *)limit; } VERIFY(limit <= (uintptr_t)base + size); for (;;) { next = (dtrace_dynvar_t *)((uintptr_t)dvar + dstate->dtds_chunksize); if ((uintptr_t)next + dstate->dtds_chunksize >= limit) break; VERIFY((uintptr_t)dvar >= (uintptr_t)base && (uintptr_t)dvar <= (uintptr_t)base + size); dvar->dtdv_next = next; dvar = next; } if (maxper == 0) break; } return (0); } static void dtrace_dstate_fini(dtrace_dstate_t *dstate) { ASSERT(MUTEX_HELD(&cpu_lock)); if (dstate->dtds_base == NULL) return; kmem_free(dstate->dtds_base, dstate->dtds_size); kmem_cache_free(dtrace_state_cache, dstate->dtds_percpu); } static void dtrace_vstate_fini(dtrace_vstate_t *vstate) { /* * Logical XOR, where are you? */ ASSERT((vstate->dtvs_nglobals == 0) ^ (vstate->dtvs_globals != NULL)); if (vstate->dtvs_nglobals > 0) { kmem_free(vstate->dtvs_globals, vstate->dtvs_nglobals * sizeof (dtrace_statvar_t *)); } if (vstate->dtvs_ntlocals > 0) { kmem_free(vstate->dtvs_tlocals, vstate->dtvs_ntlocals * sizeof (dtrace_difv_t)); } ASSERT((vstate->dtvs_nlocals == 0) ^ (vstate->dtvs_locals != NULL)); if (vstate->dtvs_nlocals > 0) { kmem_free(vstate->dtvs_locals, vstate->dtvs_nlocals * sizeof (dtrace_statvar_t *)); } } #ifdef illumos static void dtrace_state_clean(dtrace_state_t *state) { if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) return; dtrace_dynvar_clean(&state->dts_vstate.dtvs_dynvars); dtrace_speculation_clean(state); } static void dtrace_state_deadman(dtrace_state_t *state) { hrtime_t now; dtrace_sync(); now = dtrace_gethrtime(); if (state != dtrace_anon.dta_state && now - state->dts_laststatus >= dtrace_deadman_user) return; /* * We must be sure that dts_alive never appears to be less than the * value upon entry to dtrace_state_deadman(), and because we lack a * dtrace_cas64(), we cannot store to it atomically. We thus instead * store INT64_MAX to it, followed by a memory barrier, followed by * the new value. This assures that dts_alive never appears to be * less than its true value, regardless of the order in which the * stores to the underlying storage are issued. */ state->dts_alive = INT64_MAX; dtrace_membar_producer(); state->dts_alive = now; } #else /* !illumos */ static void dtrace_state_clean(void *arg) { dtrace_state_t *state = arg; dtrace_optval_t *opt = state->dts_options; if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) return; dtrace_dynvar_clean(&state->dts_vstate.dtvs_dynvars); dtrace_speculation_clean(state); callout_reset(&state->dts_cleaner, hz * opt[DTRACEOPT_CLEANRATE] / NANOSEC, dtrace_state_clean, state); } static void dtrace_state_deadman(void *arg) { dtrace_state_t *state = arg; hrtime_t now; dtrace_sync(); dtrace_debug_output(); now = dtrace_gethrtime(); if (state != dtrace_anon.dta_state && now - state->dts_laststatus >= dtrace_deadman_user) return; /* * We must be sure that dts_alive never appears to be less than the * value upon entry to dtrace_state_deadman(), and because we lack a * dtrace_cas64(), we cannot store to it atomically. We thus instead * store INT64_MAX to it, followed by a memory barrier, followed by * the new value. This assures that dts_alive never appears to be * less than its true value, regardless of the order in which the * stores to the underlying storage are issued. */ state->dts_alive = INT64_MAX; dtrace_membar_producer(); state->dts_alive = now; callout_reset(&state->dts_deadman, hz * dtrace_deadman_interval / NANOSEC, dtrace_state_deadman, state); } #endif /* illumos */ static dtrace_state_t * #ifdef illumos dtrace_state_create(dev_t *devp, cred_t *cr) #else dtrace_state_create(struct cdev *dev, struct ucred *cred __unused) #endif { #ifdef illumos minor_t minor; major_t major; #else cred_t *cr = NULL; int m = 0; #endif char c[30]; dtrace_state_t *state; dtrace_optval_t *opt; int bufsize = NCPU * sizeof (dtrace_buffer_t), i; int cpu_it; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(MUTEX_HELD(&cpu_lock)); #ifdef illumos minor = (minor_t)(uintptr_t)vmem_alloc(dtrace_minor, 1, VM_BESTFIT | VM_SLEEP); if (ddi_soft_state_zalloc(dtrace_softstate, minor) != DDI_SUCCESS) { vmem_free(dtrace_minor, (void *)(uintptr_t)minor, 1); return (NULL); } state = ddi_get_soft_state(dtrace_softstate, minor); #else if (dev != NULL) { cr = dev->si_cred; m = dev2unit(dev); } /* Allocate memory for the state. */ state = kmem_zalloc(sizeof(dtrace_state_t), KM_SLEEP); #endif state->dts_epid = DTRACE_EPIDNONE + 1; (void) snprintf(c, sizeof (c), "dtrace_aggid_%d", m); #ifdef illumos state->dts_aggid_arena = vmem_create(c, (void *)1, UINT32_MAX, 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER); if (devp != NULL) { major = getemajor(*devp); } else { major = ddi_driver_major(dtrace_devi); } state->dts_dev = makedevice(major, minor); if (devp != NULL) *devp = state->dts_dev; #else state->dts_aggid_arena = new_unrhdr(1, INT_MAX, &dtrace_unr_mtx); state->dts_dev = dev; #endif /* * We allocate NCPU buffers. On the one hand, this can be quite * a bit of memory per instance (nearly 36K on a Starcat). On the * other hand, it saves an additional memory reference in the probe * path. */ state->dts_buffer = kmem_zalloc(bufsize, KM_SLEEP); state->dts_aggbuffer = kmem_zalloc(bufsize, KM_SLEEP); /* * Allocate and initialise the per-process per-CPU random state. * SI_SUB_RANDOM < SI_SUB_DTRACE_ANON therefore entropy device is * assumed to be seeded at this point (if from Fortuna seed file). */ (void) read_random(&state->dts_rstate[0], 2 * sizeof(uint64_t)); for (cpu_it = 1; cpu_it < NCPU; cpu_it++) { /* * Each CPU is assigned a 2^64 period, non-overlapping * subsequence. */ dtrace_xoroshiro128_plus_jump(state->dts_rstate[cpu_it-1], state->dts_rstate[cpu_it]); } #ifdef illumos state->dts_cleaner = CYCLIC_NONE; state->dts_deadman = CYCLIC_NONE; #else callout_init(&state->dts_cleaner, 1); callout_init(&state->dts_deadman, 1); #endif state->dts_vstate.dtvs_state = state; for (i = 0; i < DTRACEOPT_MAX; i++) state->dts_options[i] = DTRACEOPT_UNSET; /* * Set the default options. */ opt = state->dts_options; opt[DTRACEOPT_BUFPOLICY] = DTRACEOPT_BUFPOLICY_SWITCH; opt[DTRACEOPT_BUFRESIZE] = DTRACEOPT_BUFRESIZE_AUTO; opt[DTRACEOPT_NSPEC] = dtrace_nspec_default; opt[DTRACEOPT_SPECSIZE] = dtrace_specsize_default; opt[DTRACEOPT_CPU] = (dtrace_optval_t)DTRACE_CPUALL; opt[DTRACEOPT_STRSIZE] = dtrace_strsize_default; opt[DTRACEOPT_STACKFRAMES] = dtrace_stackframes_default; opt[DTRACEOPT_USTACKFRAMES] = dtrace_ustackframes_default; opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_default; opt[DTRACEOPT_AGGRATE] = dtrace_aggrate_default; opt[DTRACEOPT_SWITCHRATE] = dtrace_switchrate_default; opt[DTRACEOPT_STATUSRATE] = dtrace_statusrate_default; opt[DTRACEOPT_JSTACKFRAMES] = dtrace_jstackframes_default; opt[DTRACEOPT_JSTACKSTRSIZE] = dtrace_jstackstrsize_default; state->dts_activity = DTRACE_ACTIVITY_INACTIVE; /* * Depending on the user credentials, we set flag bits which alter probe * visibility or the amount of destructiveness allowed. In the case of * actual anonymous tracing, or the possession of all privileges, all of * the normal checks are bypassed. */ if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) { state->dts_cred.dcr_visible = DTRACE_CRV_ALL; state->dts_cred.dcr_action = DTRACE_CRA_ALL; } else { /* * Set up the credentials for this instantiation. We take a * hold on the credential to prevent it from disappearing on * us; this in turn prevents the zone_t referenced by this * credential from disappearing. This means that we can * examine the credential and the zone from probe context. */ crhold(cr); state->dts_cred.dcr_cred = cr; /* * CRA_PROC means "we have *some* privilege for dtrace" and * unlocks the use of variables like pid, zonename, etc. */ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_USER, B_FALSE) || PRIV_POLICY_ONLY(cr, PRIV_DTRACE_PROC, B_FALSE)) { state->dts_cred.dcr_action |= DTRACE_CRA_PROC; } /* * dtrace_user allows use of syscall and profile providers. * If the user also has proc_owner and/or proc_zone, we * extend the scope to include additional visibility and * destructive power. */ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_USER, B_FALSE)) { if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, B_FALSE)) { state->dts_cred.dcr_visible |= DTRACE_CRV_ALLPROC; state->dts_cred.dcr_action |= DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER; } if (PRIV_POLICY_ONLY(cr, PRIV_PROC_ZONE, B_FALSE)) { state->dts_cred.dcr_visible |= DTRACE_CRV_ALLZONE; state->dts_cred.dcr_action |= DTRACE_CRA_PROC_DESTRUCTIVE_ALLZONE; } /* * If we have all privs in whatever zone this is, * we can do destructive things to processes which * have altered credentials. */ #ifdef illumos if (priv_isequalset(priv_getset(cr, PRIV_EFFECTIVE), cr->cr_zone->zone_privset)) { state->dts_cred.dcr_action |= DTRACE_CRA_PROC_DESTRUCTIVE_CREDCHG; } #endif } /* * Holding the dtrace_kernel privilege also implies that * the user has the dtrace_user privilege from a visibility * perspective. But without further privileges, some * destructive actions are not available. */ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_KERNEL, B_FALSE)) { /* * Make all probes in all zones visible. However, * this doesn't mean that all actions become available * to all zones. */ state->dts_cred.dcr_visible |= DTRACE_CRV_KERNEL | DTRACE_CRV_ALLPROC | DTRACE_CRV_ALLZONE; state->dts_cred.dcr_action |= DTRACE_CRA_KERNEL | DTRACE_CRA_PROC; /* * Holding proc_owner means that destructive actions * for *this* zone are allowed. */ if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, B_FALSE)) state->dts_cred.dcr_action |= DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER; /* * Holding proc_zone means that destructive actions * for this user/group ID in all zones is allowed. */ if (PRIV_POLICY_ONLY(cr, PRIV_PROC_ZONE, B_FALSE)) state->dts_cred.dcr_action |= DTRACE_CRA_PROC_DESTRUCTIVE_ALLZONE; #ifdef illumos /* * If we have all privs in whatever zone this is, * we can do destructive things to processes which * have altered credentials. */ if (priv_isequalset(priv_getset(cr, PRIV_EFFECTIVE), cr->cr_zone->zone_privset)) { state->dts_cred.dcr_action |= DTRACE_CRA_PROC_DESTRUCTIVE_CREDCHG; } #endif } /* * Holding the dtrace_proc privilege gives control over fasttrap * and pid providers. We need to grant wider destructive * privileges in the event that the user has proc_owner and/or * proc_zone. */ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_PROC, B_FALSE)) { if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, B_FALSE)) state->dts_cred.dcr_action |= DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER; if (PRIV_POLICY_ONLY(cr, PRIV_PROC_ZONE, B_FALSE)) state->dts_cred.dcr_action |= DTRACE_CRA_PROC_DESTRUCTIVE_ALLZONE; } } return (state); } static int dtrace_state_buffer(dtrace_state_t *state, dtrace_buffer_t *buf, int which) { dtrace_optval_t *opt = state->dts_options, size; processorid_t cpu = 0;; int flags = 0, rval, factor, divisor = 1; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(MUTEX_HELD(&cpu_lock)); ASSERT(which < DTRACEOPT_MAX); ASSERT(state->dts_activity == DTRACE_ACTIVITY_INACTIVE || (state == dtrace_anon.dta_state && state->dts_activity == DTRACE_ACTIVITY_ACTIVE)); if (opt[which] == DTRACEOPT_UNSET || opt[which] == 0) return (0); if (opt[DTRACEOPT_CPU] != DTRACEOPT_UNSET) cpu = opt[DTRACEOPT_CPU]; if (which == DTRACEOPT_SPECSIZE) flags |= DTRACEBUF_NOSWITCH; if (which == DTRACEOPT_BUFSIZE) { if (opt[DTRACEOPT_BUFPOLICY] == DTRACEOPT_BUFPOLICY_RING) flags |= DTRACEBUF_RING; if (opt[DTRACEOPT_BUFPOLICY] == DTRACEOPT_BUFPOLICY_FILL) flags |= DTRACEBUF_FILL; if (state != dtrace_anon.dta_state || state->dts_activity != DTRACE_ACTIVITY_ACTIVE) flags |= DTRACEBUF_INACTIVE; } for (size = opt[which]; size >= sizeof (uint64_t); size /= divisor) { /* * The size must be 8-byte aligned. If the size is not 8-byte * aligned, drop it down by the difference. */ if (size & (sizeof (uint64_t) - 1)) size -= size & (sizeof (uint64_t) - 1); if (size < state->dts_reserve) { /* * Buffers always must be large enough to accommodate * their prereserved space. We return E2BIG instead * of ENOMEM in this case to allow for user-level * software to differentiate the cases. */ return (E2BIG); } rval = dtrace_buffer_alloc(buf, size, flags, cpu, &factor); if (rval != ENOMEM) { opt[which] = size; return (rval); } if (opt[DTRACEOPT_BUFRESIZE] == DTRACEOPT_BUFRESIZE_MANUAL) return (rval); for (divisor = 2; divisor < factor; divisor <<= 1) continue; } return (ENOMEM); } static int dtrace_state_buffers(dtrace_state_t *state) { dtrace_speculation_t *spec = state->dts_speculations; int rval, i; if ((rval = dtrace_state_buffer(state, state->dts_buffer, DTRACEOPT_BUFSIZE)) != 0) return (rval); if ((rval = dtrace_state_buffer(state, state->dts_aggbuffer, DTRACEOPT_AGGSIZE)) != 0) return (rval); for (i = 0; i < state->dts_nspeculations; i++) { if ((rval = dtrace_state_buffer(state, spec[i].dtsp_buffer, DTRACEOPT_SPECSIZE)) != 0) return (rval); } return (0); } static void dtrace_state_prereserve(dtrace_state_t *state) { dtrace_ecb_t *ecb; dtrace_probe_t *probe; state->dts_reserve = 0; if (state->dts_options[DTRACEOPT_BUFPOLICY] != DTRACEOPT_BUFPOLICY_FILL) return; /* * If our buffer policy is a "fill" buffer policy, we need to set the * prereserved space to be the space required by the END probes. */ probe = dtrace_probes[dtrace_probeid_end - 1]; ASSERT(probe != NULL); for (ecb = probe->dtpr_ecb; ecb != NULL; ecb = ecb->dte_next) { if (ecb->dte_state != state) continue; state->dts_reserve += ecb->dte_needed + ecb->dte_alignment; } } static int dtrace_state_go(dtrace_state_t *state, processorid_t *cpu) { dtrace_optval_t *opt = state->dts_options, sz, nspec; dtrace_speculation_t *spec; dtrace_buffer_t *buf; #ifdef illumos cyc_handler_t hdlr; cyc_time_t when; #endif int rval = 0, i, bufsize = NCPU * sizeof (dtrace_buffer_t); dtrace_icookie_t cookie; mutex_enter(&cpu_lock); mutex_enter(&dtrace_lock); if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) { rval = EBUSY; goto out; } /* * Before we can perform any checks, we must prime all of the * retained enablings that correspond to this state. */ dtrace_enabling_prime(state); if (state->dts_destructive && !state->dts_cred.dcr_destructive) { rval = EACCES; goto out; } dtrace_state_prereserve(state); /* * Now we want to do is try to allocate our speculations. * We do not automatically resize the number of speculations; if * this fails, we will fail the operation. */ nspec = opt[DTRACEOPT_NSPEC]; ASSERT(nspec != DTRACEOPT_UNSET); if (nspec > INT_MAX) { rval = ENOMEM; goto out; } spec = kmem_zalloc(nspec * sizeof (dtrace_speculation_t), KM_NOSLEEP | KM_NORMALPRI); if (spec == NULL) { rval = ENOMEM; goto out; } state->dts_speculations = spec; state->dts_nspeculations = (int)nspec; for (i = 0; i < nspec; i++) { if ((buf = kmem_zalloc(bufsize, KM_NOSLEEP | KM_NORMALPRI)) == NULL) { rval = ENOMEM; goto err; } spec[i].dtsp_buffer = buf; } if (opt[DTRACEOPT_GRABANON] != DTRACEOPT_UNSET) { if (dtrace_anon.dta_state == NULL) { rval = ENOENT; goto out; } if (state->dts_necbs != 0) { rval = EALREADY; goto out; } state->dts_anon = dtrace_anon_grab(); ASSERT(state->dts_anon != NULL); state = state->dts_anon; /* * We want "grabanon" to be set in the grabbed state, so we'll * copy that option value from the grabbing state into the * grabbed state. */ state->dts_options[DTRACEOPT_GRABANON] = opt[DTRACEOPT_GRABANON]; *cpu = dtrace_anon.dta_beganon; /* * If the anonymous state is active (as it almost certainly * is if the anonymous enabling ultimately matched anything), * we don't allow any further option processing -- but we * don't return failure. */ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) goto out; } if (opt[DTRACEOPT_AGGSIZE] != DTRACEOPT_UNSET && opt[DTRACEOPT_AGGSIZE] != 0) { if (state->dts_aggregations == NULL) { /* * We're not going to create an aggregation buffer * because we don't have any ECBs that contain * aggregations -- set this option to 0. */ opt[DTRACEOPT_AGGSIZE] = 0; } else { /* * If we have an aggregation buffer, we must also have * a buffer to use as scratch. */ if (opt[DTRACEOPT_BUFSIZE] == DTRACEOPT_UNSET || opt[DTRACEOPT_BUFSIZE] < state->dts_needed) { opt[DTRACEOPT_BUFSIZE] = state->dts_needed; } } } if (opt[DTRACEOPT_SPECSIZE] != DTRACEOPT_UNSET && opt[DTRACEOPT_SPECSIZE] != 0) { if (!state->dts_speculates) { /* * We're not going to create speculation buffers * because we don't have any ECBs that actually * speculate -- set the speculation size to 0. */ opt[DTRACEOPT_SPECSIZE] = 0; } } /* * The bare minimum size for any buffer that we're actually going to * do anything to is sizeof (uint64_t). */ sz = sizeof (uint64_t); if ((state->dts_needed != 0 && opt[DTRACEOPT_BUFSIZE] < sz) || (state->dts_speculates && opt[DTRACEOPT_SPECSIZE] < sz) || (state->dts_aggregations != NULL && opt[DTRACEOPT_AGGSIZE] < sz)) { /* * A buffer size has been explicitly set to 0 (or to a size * that will be adjusted to 0) and we need the space -- we * need to return failure. We return ENOSPC to differentiate * it from failing to allocate a buffer due to failure to meet * the reserve (for which we return E2BIG). */ rval = ENOSPC; goto out; } if ((rval = dtrace_state_buffers(state)) != 0) goto err; if ((sz = opt[DTRACEOPT_DYNVARSIZE]) == DTRACEOPT_UNSET) sz = dtrace_dstate_defsize; do { rval = dtrace_dstate_init(&state->dts_vstate.dtvs_dynvars, sz); if (rval == 0) break; if (opt[DTRACEOPT_BUFRESIZE] == DTRACEOPT_BUFRESIZE_MANUAL) goto err; } while (sz >>= 1); opt[DTRACEOPT_DYNVARSIZE] = sz; if (rval != 0) goto err; if (opt[DTRACEOPT_STATUSRATE] > dtrace_statusrate_max) opt[DTRACEOPT_STATUSRATE] = dtrace_statusrate_max; if (opt[DTRACEOPT_CLEANRATE] == 0) opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_max; if (opt[DTRACEOPT_CLEANRATE] < dtrace_cleanrate_min) opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_min; if (opt[DTRACEOPT_CLEANRATE] > dtrace_cleanrate_max) opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_max; state->dts_alive = state->dts_laststatus = dtrace_gethrtime(); #ifdef illumos hdlr.cyh_func = (cyc_func_t)dtrace_state_clean; hdlr.cyh_arg = state; hdlr.cyh_level = CY_LOW_LEVEL; when.cyt_when = 0; when.cyt_interval = opt[DTRACEOPT_CLEANRATE]; state->dts_cleaner = cyclic_add(&hdlr, &when); hdlr.cyh_func = (cyc_func_t)dtrace_state_deadman; hdlr.cyh_arg = state; hdlr.cyh_level = CY_LOW_LEVEL; when.cyt_when = 0; when.cyt_interval = dtrace_deadman_interval; state->dts_deadman = cyclic_add(&hdlr, &when); #else callout_reset(&state->dts_cleaner, hz * opt[DTRACEOPT_CLEANRATE] / NANOSEC, dtrace_state_clean, state); callout_reset(&state->dts_deadman, hz * dtrace_deadman_interval / NANOSEC, dtrace_state_deadman, state); #endif state->dts_activity = DTRACE_ACTIVITY_WARMUP; #ifdef illumos if (state->dts_getf != 0 && !(state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL)) { /* * We don't have kernel privs but we have at least one call * to getf(); we need to bump our zone's count, and (if * this is the first enabling to have an unprivileged call * to getf()) we need to hook into closef(). */ state->dts_cred.dcr_cred->cr_zone->zone_dtrace_getf++; if (dtrace_getf++ == 0) { ASSERT(dtrace_closef == NULL); dtrace_closef = dtrace_getf_barrier; } } #endif /* * Now it's time to actually fire the BEGIN probe. We need to disable * interrupts here both to record the CPU on which we fired the BEGIN * probe (the data from this CPU will be processed first at user * level) and to manually activate the buffer for this CPU. */ cookie = dtrace_interrupt_disable(); *cpu = curcpu; ASSERT(state->dts_buffer[*cpu].dtb_flags & DTRACEBUF_INACTIVE); state->dts_buffer[*cpu].dtb_flags &= ~DTRACEBUF_INACTIVE; dtrace_probe(dtrace_probeid_begin, (uint64_t)(uintptr_t)state, 0, 0, 0, 0); dtrace_interrupt_enable(cookie); /* * We may have had an exit action from a BEGIN probe; only change our * state to ACTIVE if we're still in WARMUP. */ ASSERT(state->dts_activity == DTRACE_ACTIVITY_WARMUP || state->dts_activity == DTRACE_ACTIVITY_DRAINING); if (state->dts_activity == DTRACE_ACTIVITY_WARMUP) state->dts_activity = DTRACE_ACTIVITY_ACTIVE; #ifdef __FreeBSD__ /* * We enable anonymous tracing before APs are started, so we must * activate buffers using the current CPU. */ if (state == dtrace_anon.dta_state) for (int i = 0; i < NCPU; i++) dtrace_buffer_activate_cpu(state, i); else dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_buffer_activate, state); #else /* * Regardless of whether or not now we're in ACTIVE or DRAINING, we * want each CPU to transition its principal buffer out of the * INACTIVE state. Doing this assures that no CPU will suddenly begin * processing an ECB halfway down a probe's ECB chain; all CPUs will * atomically transition from processing none of a state's ECBs to * processing all of them. */ dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_buffer_activate, state); #endif goto out; err: dtrace_buffer_free(state->dts_buffer); dtrace_buffer_free(state->dts_aggbuffer); if ((nspec = state->dts_nspeculations) == 0) { ASSERT(state->dts_speculations == NULL); goto out; } spec = state->dts_speculations; ASSERT(spec != NULL); for (i = 0; i < state->dts_nspeculations; i++) { if ((buf = spec[i].dtsp_buffer) == NULL) break; dtrace_buffer_free(buf); kmem_free(buf, bufsize); } kmem_free(spec, nspec * sizeof (dtrace_speculation_t)); state->dts_nspeculations = 0; state->dts_speculations = NULL; out: mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); return (rval); } static int dtrace_state_stop(dtrace_state_t *state, processorid_t *cpu) { dtrace_icookie_t cookie; ASSERT(MUTEX_HELD(&dtrace_lock)); if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE && state->dts_activity != DTRACE_ACTIVITY_DRAINING) return (EINVAL); /* * We'll set the activity to DTRACE_ACTIVITY_DRAINING, and issue a sync * to be sure that every CPU has seen it. See below for the details * on why this is done. */ state->dts_activity = DTRACE_ACTIVITY_DRAINING; dtrace_sync(); /* * By this point, it is impossible for any CPU to be still processing * with DTRACE_ACTIVITY_ACTIVE. We can thus set our activity to * DTRACE_ACTIVITY_COOLDOWN and know that we're not racing with any * other CPU in dtrace_buffer_reserve(). This allows dtrace_probe() * and callees to know that the activity is DTRACE_ACTIVITY_COOLDOWN * iff we're in the END probe. */ state->dts_activity = DTRACE_ACTIVITY_COOLDOWN; dtrace_sync(); ASSERT(state->dts_activity == DTRACE_ACTIVITY_COOLDOWN); /* * Finally, we can release the reserve and call the END probe. We * disable interrupts across calling the END probe to allow us to * return the CPU on which we actually called the END probe. This * allows user-land to be sure that this CPU's principal buffer is * processed last. */ state->dts_reserve = 0; cookie = dtrace_interrupt_disable(); *cpu = curcpu; dtrace_probe(dtrace_probeid_end, (uint64_t)(uintptr_t)state, 0, 0, 0, 0); dtrace_interrupt_enable(cookie); state->dts_activity = DTRACE_ACTIVITY_STOPPED; dtrace_sync(); #ifdef illumos if (state->dts_getf != 0 && !(state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL)) { /* * We don't have kernel privs but we have at least one call * to getf(); we need to lower our zone's count, and (if * this is the last enabling to have an unprivileged call * to getf()) we need to clear the closef() hook. */ ASSERT(state->dts_cred.dcr_cred->cr_zone->zone_dtrace_getf > 0); ASSERT(dtrace_closef == dtrace_getf_barrier); ASSERT(dtrace_getf > 0); state->dts_cred.dcr_cred->cr_zone->zone_dtrace_getf--; if (--dtrace_getf == 0) dtrace_closef = NULL; } #endif return (0); } static int dtrace_state_option(dtrace_state_t *state, dtrace_optid_t option, dtrace_optval_t val) { ASSERT(MUTEX_HELD(&dtrace_lock)); if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) return (EBUSY); if (option >= DTRACEOPT_MAX) return (EINVAL); if (option != DTRACEOPT_CPU && val < 0) return (EINVAL); switch (option) { case DTRACEOPT_DESTRUCTIVE: if (dtrace_destructive_disallow) return (EACCES); state->dts_cred.dcr_destructive = 1; break; case DTRACEOPT_BUFSIZE: case DTRACEOPT_DYNVARSIZE: case DTRACEOPT_AGGSIZE: case DTRACEOPT_SPECSIZE: case DTRACEOPT_STRSIZE: if (val < 0) return (EINVAL); if (val >= LONG_MAX) { /* * If this is an otherwise negative value, set it to * the highest multiple of 128m less than LONG_MAX. * Technically, we're adjusting the size without * regard to the buffer resizing policy, but in fact, * this has no effect -- if we set the buffer size to * ~LONG_MAX and the buffer policy is ultimately set to * be "manual", the buffer allocation is guaranteed to * fail, if only because the allocation requires two * buffers. (We set the the size to the highest * multiple of 128m because it ensures that the size * will remain a multiple of a megabyte when * repeatedly halved -- all the way down to 15m.) */ val = LONG_MAX - (1 << 27) + 1; } } state->dts_options[option] = val; return (0); } static void dtrace_state_destroy(dtrace_state_t *state) { dtrace_ecb_t *ecb; dtrace_vstate_t *vstate = &state->dts_vstate; #ifdef illumos minor_t minor = getminor(state->dts_dev); #endif int i, bufsize = NCPU * sizeof (dtrace_buffer_t); dtrace_speculation_t *spec = state->dts_speculations; int nspec = state->dts_nspeculations; uint32_t match; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(MUTEX_HELD(&cpu_lock)); /* * First, retract any retained enablings for this state. */ dtrace_enabling_retract(state); ASSERT(state->dts_nretained == 0); if (state->dts_activity == DTRACE_ACTIVITY_ACTIVE || state->dts_activity == DTRACE_ACTIVITY_DRAINING) { /* * We have managed to come into dtrace_state_destroy() on a * hot enabling -- almost certainly because of a disorderly * shutdown of a consumer. (That is, a consumer that is * exiting without having called dtrace_stop().) In this case, * we're going to set our activity to be KILLED, and then * issue a sync to be sure that everyone is out of probe * context before we start blowing away ECBs. */ state->dts_activity = DTRACE_ACTIVITY_KILLED; dtrace_sync(); } /* * Release the credential hold we took in dtrace_state_create(). */ if (state->dts_cred.dcr_cred != NULL) crfree(state->dts_cred.dcr_cred); /* * Now we can safely disable and destroy any enabled probes. Because * any DTRACE_PRIV_KERNEL probes may actually be slowing our progress * (especially if they're all enabled), we take two passes through the * ECBs: in the first, we disable just DTRACE_PRIV_KERNEL probes, and * in the second we disable whatever is left over. */ for (match = DTRACE_PRIV_KERNEL; ; match = 0) { for (i = 0; i < state->dts_necbs; i++) { if ((ecb = state->dts_ecbs[i]) == NULL) continue; if (match && ecb->dte_probe != NULL) { dtrace_probe_t *probe = ecb->dte_probe; dtrace_provider_t *prov = probe->dtpr_provider; if (!(prov->dtpv_priv.dtpp_flags & match)) continue; } dtrace_ecb_disable(ecb); dtrace_ecb_destroy(ecb); } if (!match) break; } /* * Before we free the buffers, perform one more sync to assure that * every CPU is out of probe context. */ dtrace_sync(); dtrace_buffer_free(state->dts_buffer); dtrace_buffer_free(state->dts_aggbuffer); for (i = 0; i < nspec; i++) dtrace_buffer_free(spec[i].dtsp_buffer); #ifdef illumos if (state->dts_cleaner != CYCLIC_NONE) cyclic_remove(state->dts_cleaner); if (state->dts_deadman != CYCLIC_NONE) cyclic_remove(state->dts_deadman); #else callout_stop(&state->dts_cleaner); callout_drain(&state->dts_cleaner); callout_stop(&state->dts_deadman); callout_drain(&state->dts_deadman); #endif dtrace_dstate_fini(&vstate->dtvs_dynvars); dtrace_vstate_fini(vstate); if (state->dts_ecbs != NULL) kmem_free(state->dts_ecbs, state->dts_necbs * sizeof (dtrace_ecb_t *)); if (state->dts_aggregations != NULL) { #ifdef DEBUG for (i = 0; i < state->dts_naggregations; i++) ASSERT(state->dts_aggregations[i] == NULL); #endif ASSERT(state->dts_naggregations > 0); kmem_free(state->dts_aggregations, state->dts_naggregations * sizeof (dtrace_aggregation_t *)); } kmem_free(state->dts_buffer, bufsize); kmem_free(state->dts_aggbuffer, bufsize); for (i = 0; i < nspec; i++) kmem_free(spec[i].dtsp_buffer, bufsize); if (spec != NULL) kmem_free(spec, nspec * sizeof (dtrace_speculation_t)); dtrace_format_destroy(state); if (state->dts_aggid_arena != NULL) { #ifdef illumos vmem_destroy(state->dts_aggid_arena); #else delete_unrhdr(state->dts_aggid_arena); #endif state->dts_aggid_arena = NULL; } #ifdef illumos ddi_soft_state_free(dtrace_softstate, minor); vmem_free(dtrace_minor, (void *)(uintptr_t)minor, 1); #endif } /* * DTrace Anonymous Enabling Functions */ static dtrace_state_t * dtrace_anon_grab(void) { dtrace_state_t *state; ASSERT(MUTEX_HELD(&dtrace_lock)); if ((state = dtrace_anon.dta_state) == NULL) { ASSERT(dtrace_anon.dta_enabling == NULL); return (NULL); } ASSERT(dtrace_anon.dta_enabling != NULL); ASSERT(dtrace_retained != NULL); dtrace_enabling_destroy(dtrace_anon.dta_enabling); dtrace_anon.dta_enabling = NULL; dtrace_anon.dta_state = NULL; return (state); } static void dtrace_anon_property(void) { int i, rv; dtrace_state_t *state; dof_hdr_t *dof; char c[32]; /* enough for "dof-data-" + digits */ ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(MUTEX_HELD(&cpu_lock)); for (i = 0; ; i++) { (void) snprintf(c, sizeof (c), "dof-data-%d", i); dtrace_err_verbose = 1; if ((dof = dtrace_dof_property(c)) == NULL) { dtrace_err_verbose = 0; break; } #ifdef illumos /* * We want to create anonymous state, so we need to transition * the kernel debugger to indicate that DTrace is active. If * this fails (e.g. because the debugger has modified text in * some way), we won't continue with the processing. */ if (kdi_dtrace_set(KDI_DTSET_DTRACE_ACTIVATE) != 0) { cmn_err(CE_NOTE, "kernel debugger active; anonymous " "enabling ignored."); dtrace_dof_destroy(dof); break; } #endif /* * If we haven't allocated an anonymous state, we'll do so now. */ if ((state = dtrace_anon.dta_state) == NULL) { state = dtrace_state_create(NULL, NULL); dtrace_anon.dta_state = state; if (state == NULL) { /* * This basically shouldn't happen: the only * failure mode from dtrace_state_create() is a * failure of ddi_soft_state_zalloc() that * itself should never happen. Still, the * interface allows for a failure mode, and * we want to fail as gracefully as possible: * we'll emit an error message and cease * processing anonymous state in this case. */ cmn_err(CE_WARN, "failed to create " "anonymous state"); dtrace_dof_destroy(dof); break; } } rv = dtrace_dof_slurp(dof, &state->dts_vstate, CRED(), - &dtrace_anon.dta_enabling, 0, B_TRUE); + &dtrace_anon.dta_enabling, 0, 0, B_TRUE); if (rv == 0) rv = dtrace_dof_options(dof, state); dtrace_err_verbose = 0; dtrace_dof_destroy(dof); if (rv != 0) { /* * This is malformed DOF; chuck any anonymous state * that we created. */ ASSERT(dtrace_anon.dta_enabling == NULL); dtrace_state_destroy(state); dtrace_anon.dta_state = NULL; break; } ASSERT(dtrace_anon.dta_enabling != NULL); } if (dtrace_anon.dta_enabling != NULL) { int rval; /* * dtrace_enabling_retain() can only fail because we are * trying to retain more enablings than are allowed -- but * we only have one anonymous enabling, and we are guaranteed * to be allowed at least one retained enabling; we assert * that dtrace_enabling_retain() returns success. */ rval = dtrace_enabling_retain(dtrace_anon.dta_enabling); ASSERT(rval == 0); dtrace_enabling_dump(dtrace_anon.dta_enabling); } } /* * DTrace Helper Functions */ static void dtrace_helper_trace(dtrace_helper_action_t *helper, dtrace_mstate_t *mstate, dtrace_vstate_t *vstate, int where) { uint32_t size, next, nnext, i; dtrace_helptrace_t *ent, *buffer; uint16_t flags = cpu_core[curcpu].cpuc_dtrace_flags; if ((buffer = dtrace_helptrace_buffer) == NULL) return; ASSERT(vstate->dtvs_nlocals <= dtrace_helptrace_nlocals); /* * What would a tracing framework be without its own tracing * framework? (Well, a hell of a lot simpler, for starters...) */ size = sizeof (dtrace_helptrace_t) + dtrace_helptrace_nlocals * sizeof (uint64_t) - sizeof (uint64_t); /* * Iterate until we can allocate a slot in the trace buffer. */ do { next = dtrace_helptrace_next; if (next + size < dtrace_helptrace_bufsize) { nnext = next + size; } else { nnext = size; } } while (dtrace_cas32(&dtrace_helptrace_next, next, nnext) != next); /* * We have our slot; fill it in. */ if (nnext == size) { dtrace_helptrace_wrapped++; next = 0; } ent = (dtrace_helptrace_t *)((uintptr_t)buffer + next); ent->dtht_helper = helper; ent->dtht_where = where; ent->dtht_nlocals = vstate->dtvs_nlocals; ent->dtht_fltoffs = (mstate->dtms_present & DTRACE_MSTATE_FLTOFFS) ? mstate->dtms_fltoffs : -1; ent->dtht_fault = DTRACE_FLAGS2FLT(flags); ent->dtht_illval = cpu_core[curcpu].cpuc_dtrace_illval; for (i = 0; i < vstate->dtvs_nlocals; i++) { dtrace_statvar_t *svar; if ((svar = vstate->dtvs_locals[i]) == NULL) continue; ASSERT(svar->dtsv_size >= NCPU * sizeof (uint64_t)); ent->dtht_locals[i] = ((uint64_t *)(uintptr_t)svar->dtsv_data)[curcpu]; } } static uint64_t dtrace_helper(int which, dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t arg0, uint64_t arg1) { uint16_t *flags = &cpu_core[curcpu].cpuc_dtrace_flags; uint64_t sarg0 = mstate->dtms_arg[0]; uint64_t sarg1 = mstate->dtms_arg[1]; uint64_t rval = 0; dtrace_helpers_t *helpers = curproc->p_dtrace_helpers; dtrace_helper_action_t *helper; dtrace_vstate_t *vstate; dtrace_difo_t *pred; int i, trace = dtrace_helptrace_buffer != NULL; ASSERT(which >= 0 && which < DTRACE_NHELPER_ACTIONS); if (helpers == NULL) return (0); if ((helper = helpers->dthps_actions[which]) == NULL) return (0); vstate = &helpers->dthps_vstate; mstate->dtms_arg[0] = arg0; mstate->dtms_arg[1] = arg1; /* * Now iterate over each helper. If its predicate evaluates to 'true', * we'll call the corresponding actions. Note that the below calls * to dtrace_dif_emulate() may set faults in machine state. This is * okay: our caller (the outer dtrace_dif_emulate()) will simply plow * the stored DIF offset with its own (which is the desired behavior). * Also, note the calls to dtrace_dif_emulate() may allocate scratch * from machine state; this is okay, too. */ for (; helper != NULL; helper = helper->dtha_next) { if ((pred = helper->dtha_predicate) != NULL) { if (trace) dtrace_helper_trace(helper, mstate, vstate, 0); if (!dtrace_dif_emulate(pred, mstate, vstate, state)) goto next; if (*flags & CPU_DTRACE_FAULT) goto err; } for (i = 0; i < helper->dtha_nactions; i++) { if (trace) dtrace_helper_trace(helper, mstate, vstate, i + 1); rval = dtrace_dif_emulate(helper->dtha_actions[i], mstate, vstate, state); if (*flags & CPU_DTRACE_FAULT) goto err; } next: if (trace) dtrace_helper_trace(helper, mstate, vstate, DTRACE_HELPTRACE_NEXT); } if (trace) dtrace_helper_trace(helper, mstate, vstate, DTRACE_HELPTRACE_DONE); /* * Restore the arg0 that we saved upon entry. */ mstate->dtms_arg[0] = sarg0; mstate->dtms_arg[1] = sarg1; return (rval); err: if (trace) dtrace_helper_trace(helper, mstate, vstate, DTRACE_HELPTRACE_ERR); /* * Restore the arg0 that we saved upon entry. */ mstate->dtms_arg[0] = sarg0; mstate->dtms_arg[1] = sarg1; return (0); } static void dtrace_helper_action_destroy(dtrace_helper_action_t *helper, dtrace_vstate_t *vstate) { int i; if (helper->dtha_predicate != NULL) dtrace_difo_release(helper->dtha_predicate, vstate); for (i = 0; i < helper->dtha_nactions; i++) { ASSERT(helper->dtha_actions[i] != NULL); dtrace_difo_release(helper->dtha_actions[i], vstate); } kmem_free(helper->dtha_actions, helper->dtha_nactions * sizeof (dtrace_difo_t *)); kmem_free(helper, sizeof (dtrace_helper_action_t)); } static int dtrace_helper_destroygen(dtrace_helpers_t *help, int gen) { proc_t *p = curproc; dtrace_vstate_t *vstate; int i; if (help == NULL) help = p->p_dtrace_helpers; ASSERT(MUTEX_HELD(&dtrace_lock)); if (help == NULL || gen > help->dthps_generation) return (EINVAL); vstate = &help->dthps_vstate; for (i = 0; i < DTRACE_NHELPER_ACTIONS; i++) { dtrace_helper_action_t *last = NULL, *h, *next; for (h = help->dthps_actions[i]; h != NULL; h = next) { next = h->dtha_next; if (h->dtha_generation == gen) { if (last != NULL) { last->dtha_next = next; } else { help->dthps_actions[i] = next; } dtrace_helper_action_destroy(h, vstate); } else { last = h; } } } /* * Interate until we've cleared out all helper providers with the * given generation number. */ for (;;) { dtrace_helper_provider_t *prov; /* * Look for a helper provider with the right generation. We * have to start back at the beginning of the list each time * because we drop dtrace_lock. It's unlikely that we'll make * more than two passes. */ for (i = 0; i < help->dthps_nprovs; i++) { prov = help->dthps_provs[i]; if (prov->dthp_generation == gen) break; } /* * If there were no matches, we're done. */ if (i == help->dthps_nprovs) break; /* * Move the last helper provider into this slot. */ help->dthps_nprovs--; help->dthps_provs[i] = help->dthps_provs[help->dthps_nprovs]; help->dthps_provs[help->dthps_nprovs] = NULL; mutex_exit(&dtrace_lock); /* * If we have a meta provider, remove this helper provider. */ mutex_enter(&dtrace_meta_lock); if (dtrace_meta_pid != NULL) { ASSERT(dtrace_deferred_pid == NULL); dtrace_helper_provider_remove(&prov->dthp_prov, p->p_pid); } mutex_exit(&dtrace_meta_lock); dtrace_helper_provider_destroy(prov); mutex_enter(&dtrace_lock); } return (0); } static int dtrace_helper_validate(dtrace_helper_action_t *helper) { int err = 0, i; dtrace_difo_t *dp; if ((dp = helper->dtha_predicate) != NULL) err += dtrace_difo_validate_helper(dp); for (i = 0; i < helper->dtha_nactions; i++) err += dtrace_difo_validate_helper(helper->dtha_actions[i]); return (err == 0); } static int dtrace_helper_action_add(int which, dtrace_ecbdesc_t *ep, dtrace_helpers_t *help) { dtrace_helper_action_t *helper, *last; dtrace_actdesc_t *act; dtrace_vstate_t *vstate; dtrace_predicate_t *pred; int count = 0, nactions = 0, i; if (which < 0 || which >= DTRACE_NHELPER_ACTIONS) return (EINVAL); last = help->dthps_actions[which]; vstate = &help->dthps_vstate; for (count = 0; last != NULL; last = last->dtha_next) { count++; if (last->dtha_next == NULL) break; } /* * If we already have dtrace_helper_actions_max helper actions for this * helper action type, we'll refuse to add a new one. */ if (count >= dtrace_helper_actions_max) return (ENOSPC); helper = kmem_zalloc(sizeof (dtrace_helper_action_t), KM_SLEEP); helper->dtha_generation = help->dthps_generation; if ((pred = ep->dted_pred.dtpdd_predicate) != NULL) { ASSERT(pred->dtp_difo != NULL); dtrace_difo_hold(pred->dtp_difo); helper->dtha_predicate = pred->dtp_difo; } for (act = ep->dted_action; act != NULL; act = act->dtad_next) { if (act->dtad_kind != DTRACEACT_DIFEXPR) goto err; if (act->dtad_difo == NULL) goto err; nactions++; } helper->dtha_actions = kmem_zalloc(sizeof (dtrace_difo_t *) * (helper->dtha_nactions = nactions), KM_SLEEP); for (act = ep->dted_action, i = 0; act != NULL; act = act->dtad_next) { dtrace_difo_hold(act->dtad_difo); helper->dtha_actions[i++] = act->dtad_difo; } if (!dtrace_helper_validate(helper)) goto err; if (last == NULL) { help->dthps_actions[which] = helper; } else { last->dtha_next = helper; } if (vstate->dtvs_nlocals > dtrace_helptrace_nlocals) { dtrace_helptrace_nlocals = vstate->dtvs_nlocals; dtrace_helptrace_next = 0; } return (0); err: dtrace_helper_action_destroy(helper, vstate); return (EINVAL); } static void dtrace_helper_provider_register(proc_t *p, dtrace_helpers_t *help, dof_helper_t *dofhp) { ASSERT(MUTEX_NOT_HELD(&dtrace_lock)); mutex_enter(&dtrace_meta_lock); mutex_enter(&dtrace_lock); if (!dtrace_attached() || dtrace_meta_pid == NULL) { /* * If the dtrace module is loaded but not attached, or if * there aren't isn't a meta provider registered to deal with * these provider descriptions, we need to postpone creating * the actual providers until later. */ if (help->dthps_next == NULL && help->dthps_prev == NULL && dtrace_deferred_pid != help) { help->dthps_deferred = 1; help->dthps_pid = p->p_pid; help->dthps_next = dtrace_deferred_pid; help->dthps_prev = NULL; if (dtrace_deferred_pid != NULL) dtrace_deferred_pid->dthps_prev = help; dtrace_deferred_pid = help; } mutex_exit(&dtrace_lock); } else if (dofhp != NULL) { /* * If the dtrace module is loaded and we have a particular * helper provider description, pass that off to the * meta provider. */ mutex_exit(&dtrace_lock); dtrace_helper_provide(dofhp, p->p_pid); } else { /* * Otherwise, just pass all the helper provider descriptions * off to the meta provider. */ int i; mutex_exit(&dtrace_lock); for (i = 0; i < help->dthps_nprovs; i++) { dtrace_helper_provide(&help->dthps_provs[i]->dthp_prov, p->p_pid); } } mutex_exit(&dtrace_meta_lock); } static int dtrace_helper_provider_add(dof_helper_t *dofhp, dtrace_helpers_t *help, int gen) { dtrace_helper_provider_t *hprov, **tmp_provs; uint_t tmp_maxprovs, i; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(help != NULL); /* * If we already have dtrace_helper_providers_max helper providers, * we're refuse to add a new one. */ if (help->dthps_nprovs >= dtrace_helper_providers_max) return (ENOSPC); /* * Check to make sure this isn't a duplicate. */ for (i = 0; i < help->dthps_nprovs; i++) { if (dofhp->dofhp_addr == help->dthps_provs[i]->dthp_prov.dofhp_addr) return (EALREADY); } hprov = kmem_zalloc(sizeof (dtrace_helper_provider_t), KM_SLEEP); hprov->dthp_prov = *dofhp; hprov->dthp_ref = 1; hprov->dthp_generation = gen; /* * Allocate a bigger table for helper providers if it's already full. */ if (help->dthps_maxprovs == help->dthps_nprovs) { tmp_maxprovs = help->dthps_maxprovs; tmp_provs = help->dthps_provs; if (help->dthps_maxprovs == 0) help->dthps_maxprovs = 2; else help->dthps_maxprovs *= 2; if (help->dthps_maxprovs > dtrace_helper_providers_max) help->dthps_maxprovs = dtrace_helper_providers_max; ASSERT(tmp_maxprovs < help->dthps_maxprovs); help->dthps_provs = kmem_zalloc(help->dthps_maxprovs * sizeof (dtrace_helper_provider_t *), KM_SLEEP); if (tmp_provs != NULL) { bcopy(tmp_provs, help->dthps_provs, tmp_maxprovs * sizeof (dtrace_helper_provider_t *)); kmem_free(tmp_provs, tmp_maxprovs * sizeof (dtrace_helper_provider_t *)); } } help->dthps_provs[help->dthps_nprovs] = hprov; help->dthps_nprovs++; return (0); } static void dtrace_helper_provider_destroy(dtrace_helper_provider_t *hprov) { mutex_enter(&dtrace_lock); if (--hprov->dthp_ref == 0) { dof_hdr_t *dof; mutex_exit(&dtrace_lock); dof = (dof_hdr_t *)(uintptr_t)hprov->dthp_prov.dofhp_dof; dtrace_dof_destroy(dof); kmem_free(hprov, sizeof (dtrace_helper_provider_t)); } else { mutex_exit(&dtrace_lock); } } static int dtrace_helper_provider_validate(dof_hdr_t *dof, dof_sec_t *sec) { uintptr_t daddr = (uintptr_t)dof; dof_sec_t *str_sec, *prb_sec, *arg_sec, *off_sec, *enoff_sec; dof_provider_t *provider; dof_probe_t *probe; uint8_t *arg; char *strtab, *typestr; dof_stridx_t typeidx; size_t typesz; uint_t nprobes, j, k; ASSERT(sec->dofs_type == DOF_SECT_PROVIDER); if (sec->dofs_offset & (sizeof (uint_t) - 1)) { dtrace_dof_error(dof, "misaligned section offset"); return (-1); } /* * The section needs to be large enough to contain the DOF provider * structure appropriate for the given version. */ if (sec->dofs_size < ((dof->dofh_ident[DOF_ID_VERSION] == DOF_VERSION_1) ? offsetof(dof_provider_t, dofpv_prenoffs) : sizeof (dof_provider_t))) { dtrace_dof_error(dof, "provider section too small"); return (-1); } provider = (dof_provider_t *)(uintptr_t)(daddr + sec->dofs_offset); str_sec = dtrace_dof_sect(dof, DOF_SECT_STRTAB, provider->dofpv_strtab); prb_sec = dtrace_dof_sect(dof, DOF_SECT_PROBES, provider->dofpv_probes); arg_sec = dtrace_dof_sect(dof, DOF_SECT_PRARGS, provider->dofpv_prargs); off_sec = dtrace_dof_sect(dof, DOF_SECT_PROFFS, provider->dofpv_proffs); if (str_sec == NULL || prb_sec == NULL || arg_sec == NULL || off_sec == NULL) return (-1); enoff_sec = NULL; if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && provider->dofpv_prenoffs != DOF_SECT_NONE && (enoff_sec = dtrace_dof_sect(dof, DOF_SECT_PRENOFFS, provider->dofpv_prenoffs)) == NULL) return (-1); strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); if (provider->dofpv_name >= str_sec->dofs_size || strlen(strtab + provider->dofpv_name) >= DTRACE_PROVNAMELEN) { dtrace_dof_error(dof, "invalid provider name"); return (-1); } if (prb_sec->dofs_entsize == 0 || prb_sec->dofs_entsize > prb_sec->dofs_size) { dtrace_dof_error(dof, "invalid entry size"); return (-1); } if (prb_sec->dofs_entsize & (sizeof (uintptr_t) - 1)) { dtrace_dof_error(dof, "misaligned entry size"); return (-1); } if (off_sec->dofs_entsize != sizeof (uint32_t)) { dtrace_dof_error(dof, "invalid entry size"); return (-1); } if (off_sec->dofs_offset & (sizeof (uint32_t) - 1)) { dtrace_dof_error(dof, "misaligned section offset"); return (-1); } if (arg_sec->dofs_entsize != sizeof (uint8_t)) { dtrace_dof_error(dof, "invalid entry size"); return (-1); } arg = (uint8_t *)(uintptr_t)(daddr + arg_sec->dofs_offset); nprobes = prb_sec->dofs_size / prb_sec->dofs_entsize; /* * Take a pass through the probes to check for errors. */ for (j = 0; j < nprobes; j++) { probe = (dof_probe_t *)(uintptr_t)(daddr + prb_sec->dofs_offset + j * prb_sec->dofs_entsize); if (probe->dofpr_func >= str_sec->dofs_size) { dtrace_dof_error(dof, "invalid function name"); return (-1); } if (strlen(strtab + probe->dofpr_func) >= DTRACE_FUNCNAMELEN) { dtrace_dof_error(dof, "function name too long"); /* * Keep going if the function name is too long. * Unlike provider and probe names, we cannot reasonably * impose restrictions on function names, since they're * a property of the code being instrumented. We will * skip this probe in dtrace_helper_provide_one(). */ } if (probe->dofpr_name >= str_sec->dofs_size || strlen(strtab + probe->dofpr_name) >= DTRACE_NAMELEN) { dtrace_dof_error(dof, "invalid probe name"); return (-1); } /* * The offset count must not wrap the index, and the offsets * must also not overflow the section's data. */ if (probe->dofpr_offidx + probe->dofpr_noffs < probe->dofpr_offidx || (probe->dofpr_offidx + probe->dofpr_noffs) * off_sec->dofs_entsize > off_sec->dofs_size) { dtrace_dof_error(dof, "invalid probe offset"); return (-1); } if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1) { /* * If there's no is-enabled offset section, make sure * there aren't any is-enabled offsets. Otherwise * perform the same checks as for probe offsets * (immediately above). */ if (enoff_sec == NULL) { if (probe->dofpr_enoffidx != 0 || probe->dofpr_nenoffs != 0) { dtrace_dof_error(dof, "is-enabled " "offsets with null section"); return (-1); } } else if (probe->dofpr_enoffidx + probe->dofpr_nenoffs < probe->dofpr_enoffidx || (probe->dofpr_enoffidx + probe->dofpr_nenoffs) * enoff_sec->dofs_entsize > enoff_sec->dofs_size) { dtrace_dof_error(dof, "invalid is-enabled " "offset"); return (-1); } if (probe->dofpr_noffs + probe->dofpr_nenoffs == 0) { dtrace_dof_error(dof, "zero probe and " "is-enabled offsets"); return (-1); } } else if (probe->dofpr_noffs == 0) { dtrace_dof_error(dof, "zero probe offsets"); return (-1); } if (probe->dofpr_argidx + probe->dofpr_xargc < probe->dofpr_argidx || (probe->dofpr_argidx + probe->dofpr_xargc) * arg_sec->dofs_entsize > arg_sec->dofs_size) { dtrace_dof_error(dof, "invalid args"); return (-1); } typeidx = probe->dofpr_nargv; typestr = strtab + probe->dofpr_nargv; for (k = 0; k < probe->dofpr_nargc; k++) { if (typeidx >= str_sec->dofs_size) { dtrace_dof_error(dof, "bad " "native argument type"); return (-1); } typesz = strlen(typestr) + 1; if (typesz > DTRACE_ARGTYPELEN) { dtrace_dof_error(dof, "native " "argument type too long"); return (-1); } typeidx += typesz; typestr += typesz; } typeidx = probe->dofpr_xargv; typestr = strtab + probe->dofpr_xargv; for (k = 0; k < probe->dofpr_xargc; k++) { if (arg[probe->dofpr_argidx + k] > probe->dofpr_nargc) { dtrace_dof_error(dof, "bad " "native argument index"); return (-1); } if (typeidx >= str_sec->dofs_size) { dtrace_dof_error(dof, "bad " "translated argument type"); return (-1); } typesz = strlen(typestr) + 1; if (typesz > DTRACE_ARGTYPELEN) { dtrace_dof_error(dof, "translated argument " "type too long"); return (-1); } typeidx += typesz; typestr += typesz; } } return (0); } static int dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp, struct proc *p) { dtrace_helpers_t *help; dtrace_vstate_t *vstate; dtrace_enabling_t *enab = NULL; int i, gen, rv, nhelpers = 0, nprovs = 0, destroy = 1; uintptr_t daddr = (uintptr_t)dof; ASSERT(MUTEX_HELD(&dtrace_lock)); if ((help = p->p_dtrace_helpers) == NULL) help = dtrace_helpers_create(p); vstate = &help->dthps_vstate; if ((rv = dtrace_dof_slurp(dof, vstate, NULL, &enab, dhp->dofhp_addr, - B_FALSE)) != 0) { + dhp->dofhp_dof, B_FALSE)) != 0) { dtrace_dof_destroy(dof); return (rv); } /* * Look for helper providers and validate their descriptions. */ for (i = 0; i < dof->dofh_secnum; i++) { dof_sec_t *sec = (dof_sec_t *)(uintptr_t)(daddr + dof->dofh_secoff + i * dof->dofh_secsize); if (sec->dofs_type != DOF_SECT_PROVIDER) continue; if (dtrace_helper_provider_validate(dof, sec) != 0) { dtrace_enabling_destroy(enab); dtrace_dof_destroy(dof); return (-1); } nprovs++; } /* * Now we need to walk through the ECB descriptions in the enabling. */ for (i = 0; i < enab->dten_ndesc; i++) { dtrace_ecbdesc_t *ep = enab->dten_desc[i]; dtrace_probedesc_t *desc = &ep->dted_probe; if (strcmp(desc->dtpd_provider, "dtrace") != 0) continue; if (strcmp(desc->dtpd_mod, "helper") != 0) continue; if (strcmp(desc->dtpd_func, "ustack") != 0) continue; if ((rv = dtrace_helper_action_add(DTRACE_HELPER_ACTION_USTACK, ep, help)) != 0) { /* * Adding this helper action failed -- we are now going * to rip out the entire generation and return failure. */ (void) dtrace_helper_destroygen(help, help->dthps_generation); dtrace_enabling_destroy(enab); dtrace_dof_destroy(dof); return (-1); } nhelpers++; } if (nhelpers < enab->dten_ndesc) dtrace_dof_error(dof, "unmatched helpers"); gen = help->dthps_generation++; dtrace_enabling_destroy(enab); if (nprovs > 0) { /* * Now that this is in-kernel, we change the sense of the * members: dofhp_dof denotes the in-kernel copy of the DOF * and dofhp_addr denotes the address at user-level. */ dhp->dofhp_addr = dhp->dofhp_dof; dhp->dofhp_dof = (uint64_t)(uintptr_t)dof; if (dtrace_helper_provider_add(dhp, help, gen) == 0) { mutex_exit(&dtrace_lock); dtrace_helper_provider_register(p, help, dhp); mutex_enter(&dtrace_lock); destroy = 0; } } if (destroy) dtrace_dof_destroy(dof); return (gen); } static dtrace_helpers_t * dtrace_helpers_create(proc_t *p) { dtrace_helpers_t *help; ASSERT(MUTEX_HELD(&dtrace_lock)); ASSERT(p->p_dtrace_helpers == NULL); help = kmem_zalloc(sizeof (dtrace_helpers_t), KM_SLEEP); help->dthps_actions = kmem_zalloc(sizeof (dtrace_helper_action_t *) * DTRACE_NHELPER_ACTIONS, KM_SLEEP); p->p_dtrace_helpers = help; dtrace_helpers++; return (help); } #ifdef illumos static #endif void dtrace_helpers_destroy(proc_t *p) { dtrace_helpers_t *help; dtrace_vstate_t *vstate; #ifdef illumos proc_t *p = curproc; #endif int i; mutex_enter(&dtrace_lock); ASSERT(p->p_dtrace_helpers != NULL); ASSERT(dtrace_helpers > 0); help = p->p_dtrace_helpers; vstate = &help->dthps_vstate; /* * We're now going to lose the help from this process. */ p->p_dtrace_helpers = NULL; dtrace_sync(); /* * Destory the helper actions. */ for (i = 0; i < DTRACE_NHELPER_ACTIONS; i++) { dtrace_helper_action_t *h, *next; for (h = help->dthps_actions[i]; h != NULL; h = next) { next = h->dtha_next; dtrace_helper_action_destroy(h, vstate); h = next; } } mutex_exit(&dtrace_lock); /* * Destroy the helper providers. */ if (help->dthps_maxprovs > 0) { mutex_enter(&dtrace_meta_lock); if (dtrace_meta_pid != NULL) { ASSERT(dtrace_deferred_pid == NULL); for (i = 0; i < help->dthps_nprovs; i++) { dtrace_helper_provider_remove( &help->dthps_provs[i]->dthp_prov, p->p_pid); } } else { mutex_enter(&dtrace_lock); ASSERT(help->dthps_deferred == 0 || help->dthps_next != NULL || help->dthps_prev != NULL || help == dtrace_deferred_pid); /* * Remove the helper from the deferred list. */ if (help->dthps_next != NULL) help->dthps_next->dthps_prev = help->dthps_prev; if (help->dthps_prev != NULL) help->dthps_prev->dthps_next = help->dthps_next; if (dtrace_deferred_pid == help) { dtrace_deferred_pid = help->dthps_next; ASSERT(help->dthps_prev == NULL); } mutex_exit(&dtrace_lock); } mutex_exit(&dtrace_meta_lock); for (i = 0; i < help->dthps_nprovs; i++) { dtrace_helper_provider_destroy(help->dthps_provs[i]); } kmem_free(help->dthps_provs, help->dthps_maxprovs * sizeof (dtrace_helper_provider_t *)); } mutex_enter(&dtrace_lock); dtrace_vstate_fini(&help->dthps_vstate); kmem_free(help->dthps_actions, sizeof (dtrace_helper_action_t *) * DTRACE_NHELPER_ACTIONS); kmem_free(help, sizeof (dtrace_helpers_t)); --dtrace_helpers; mutex_exit(&dtrace_lock); } #ifdef illumos static #endif void dtrace_helpers_duplicate(proc_t *from, proc_t *to) { dtrace_helpers_t *help, *newhelp; dtrace_helper_action_t *helper, *new, *last; dtrace_difo_t *dp; dtrace_vstate_t *vstate; int i, j, sz, hasprovs = 0; mutex_enter(&dtrace_lock); ASSERT(from->p_dtrace_helpers != NULL); ASSERT(dtrace_helpers > 0); help = from->p_dtrace_helpers; newhelp = dtrace_helpers_create(to); ASSERT(to->p_dtrace_helpers != NULL); newhelp->dthps_generation = help->dthps_generation; vstate = &newhelp->dthps_vstate; /* * Duplicate the helper actions. */ for (i = 0; i < DTRACE_NHELPER_ACTIONS; i++) { if ((helper = help->dthps_actions[i]) == NULL) continue; for (last = NULL; helper != NULL; helper = helper->dtha_next) { new = kmem_zalloc(sizeof (dtrace_helper_action_t), KM_SLEEP); new->dtha_generation = helper->dtha_generation; if ((dp = helper->dtha_predicate) != NULL) { dp = dtrace_difo_duplicate(dp, vstate); new->dtha_predicate = dp; } new->dtha_nactions = helper->dtha_nactions; sz = sizeof (dtrace_difo_t *) * new->dtha_nactions; new->dtha_actions = kmem_alloc(sz, KM_SLEEP); for (j = 0; j < new->dtha_nactions; j++) { dtrace_difo_t *dp = helper->dtha_actions[j]; ASSERT(dp != NULL); dp = dtrace_difo_duplicate(dp, vstate); new->dtha_actions[j] = dp; } if (last != NULL) { last->dtha_next = new; } else { newhelp->dthps_actions[i] = new; } last = new; } } /* * Duplicate the helper providers and register them with the * DTrace framework. */ if (help->dthps_nprovs > 0) { newhelp->dthps_nprovs = help->dthps_nprovs; newhelp->dthps_maxprovs = help->dthps_nprovs; newhelp->dthps_provs = kmem_alloc(newhelp->dthps_nprovs * sizeof (dtrace_helper_provider_t *), KM_SLEEP); for (i = 0; i < newhelp->dthps_nprovs; i++) { newhelp->dthps_provs[i] = help->dthps_provs[i]; newhelp->dthps_provs[i]->dthp_ref++; } hasprovs = 1; } mutex_exit(&dtrace_lock); if (hasprovs) dtrace_helper_provider_register(to, newhelp, NULL); } /* * DTrace Hook Functions */ static void dtrace_module_loaded(modctl_t *ctl) { dtrace_provider_t *prv; mutex_enter(&dtrace_provider_lock); #ifdef illumos mutex_enter(&mod_lock); #endif #ifdef illumos ASSERT(ctl->mod_busy); #endif /* * We're going to call each providers per-module provide operation * specifying only this module. */ for (prv = dtrace_provider; prv != NULL; prv = prv->dtpv_next) prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, ctl); #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_provider_lock); /* * If we have any retained enablings, we need to match against them. * Enabling probes requires that cpu_lock be held, and we cannot hold * cpu_lock here -- it is legal for cpu_lock to be held when loading a * module. (In particular, this happens when loading scheduling * classes.) So if we have any retained enablings, we need to dispatch * our task queue to do the match for us. */ mutex_enter(&dtrace_lock); if (dtrace_retained == NULL) { mutex_exit(&dtrace_lock); return; } (void) taskq_dispatch(dtrace_taskq, (task_func_t *)dtrace_enabling_matchall, NULL, TQ_SLEEP); mutex_exit(&dtrace_lock); /* * And now, for a little heuristic sleaze: in general, we want to * match modules as soon as they load. However, we cannot guarantee * this, because it would lead us to the lock ordering violation * outlined above. The common case, of course, is that cpu_lock is * _not_ held -- so we delay here for a clock tick, hoping that that's * long enough for the task queue to do its work. If it's not, it's * not a serious problem -- it just means that the module that we * just loaded may not be immediately instrumentable. */ delay(1); } static void #ifdef illumos dtrace_module_unloaded(modctl_t *ctl) #else dtrace_module_unloaded(modctl_t *ctl, int *error) #endif { dtrace_probe_t template, *probe, *first, *next; dtrace_provider_t *prov; #ifndef illumos char modname[DTRACE_MODNAMELEN]; size_t len; #endif #ifdef illumos template.dtpr_mod = ctl->mod_modname; #else /* Handle the fact that ctl->filename may end in ".ko". */ strlcpy(modname, ctl->filename, sizeof(modname)); len = strlen(ctl->filename); if (len > 3 && strcmp(modname + len - 3, ".ko") == 0) modname[len - 3] = '\0'; template.dtpr_mod = modname; #endif mutex_enter(&dtrace_provider_lock); #ifdef illumos mutex_enter(&mod_lock); #endif mutex_enter(&dtrace_lock); #ifndef illumos if (ctl->nenabled > 0) { /* Don't allow unloads if a probe is enabled. */ mutex_exit(&dtrace_provider_lock); mutex_exit(&dtrace_lock); *error = -1; printf( "kldunload: attempt to unload module that has DTrace probes enabled\n"); return; } #endif if (dtrace_bymod == NULL) { /* * The DTrace module is loaded (obviously) but not attached; * we don't have any work to do. */ mutex_exit(&dtrace_provider_lock); #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_lock); return; } for (probe = first = dtrace_hash_lookup(dtrace_bymod, &template); probe != NULL; probe = probe->dtpr_nextmod) { if (probe->dtpr_ecb != NULL) { mutex_exit(&dtrace_provider_lock); #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_lock); /* * This shouldn't _actually_ be possible -- we're * unloading a module that has an enabled probe in it. * (It's normally up to the provider to make sure that * this can't happen.) However, because dtps_enable() * doesn't have a failure mode, there can be an * enable/unload race. Upshot: we don't want to * assert, but we're not going to disable the * probe, either. */ if (dtrace_err_verbose) { #ifdef illumos cmn_err(CE_WARN, "unloaded module '%s' had " "enabled probes", ctl->mod_modname); #else cmn_err(CE_WARN, "unloaded module '%s' had " "enabled probes", modname); #endif } return; } } probe = first; for (first = NULL; probe != NULL; probe = next) { ASSERT(dtrace_probes[probe->dtpr_id - 1] == probe); dtrace_probes[probe->dtpr_id - 1] = NULL; next = probe->dtpr_nextmod; dtrace_hash_remove(dtrace_bymod, probe); dtrace_hash_remove(dtrace_byfunc, probe); dtrace_hash_remove(dtrace_byname, probe); if (first == NULL) { first = probe; probe->dtpr_nextmod = NULL; } else { probe->dtpr_nextmod = first; first = probe; } } /* * We've removed all of the module's probes from the hash chains and * from the probe array. Now issue a dtrace_sync() to be sure that * everyone has cleared out from any probe array processing. */ dtrace_sync(); for (probe = first; probe != NULL; probe = first) { first = probe->dtpr_nextmod; prov = probe->dtpr_provider; prov->dtpv_pops.dtps_destroy(prov->dtpv_arg, probe->dtpr_id, probe->dtpr_arg); kmem_free(probe->dtpr_mod, strlen(probe->dtpr_mod) + 1); kmem_free(probe->dtpr_func, strlen(probe->dtpr_func) + 1); kmem_free(probe->dtpr_name, strlen(probe->dtpr_name) + 1); #ifdef illumos vmem_free(dtrace_arena, (void *)(uintptr_t)probe->dtpr_id, 1); #else free_unr(dtrace_arena, probe->dtpr_id); #endif kmem_free(probe, sizeof (dtrace_probe_t)); } mutex_exit(&dtrace_lock); #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_provider_lock); } #ifndef illumos static void dtrace_kld_load(void *arg __unused, linker_file_t lf) { dtrace_module_loaded(lf); } static void dtrace_kld_unload_try(void *arg __unused, linker_file_t lf, int *error) { if (*error != 0) /* We already have an error, so don't do anything. */ return; dtrace_module_unloaded(lf, error); } #endif #ifdef illumos static void dtrace_suspend(void) { dtrace_probe_foreach(offsetof(dtrace_pops_t, dtps_suspend)); } static void dtrace_resume(void) { dtrace_probe_foreach(offsetof(dtrace_pops_t, dtps_resume)); } #endif static int dtrace_cpu_setup(cpu_setup_t what, processorid_t cpu) { ASSERT(MUTEX_HELD(&cpu_lock)); mutex_enter(&dtrace_lock); switch (what) { case CPU_CONFIG: { dtrace_state_t *state; dtrace_optval_t *opt, rs, c; /* * For now, we only allocate a new buffer for anonymous state. */ if ((state = dtrace_anon.dta_state) == NULL) break; if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE) break; opt = state->dts_options; c = opt[DTRACEOPT_CPU]; if (c != DTRACE_CPUALL && c != DTRACEOPT_UNSET && c != cpu) break; /* * Regardless of what the actual policy is, we're going to * temporarily set our resize policy to be manual. We're * also going to temporarily set our CPU option to denote * the newly configured CPU. */ rs = opt[DTRACEOPT_BUFRESIZE]; opt[DTRACEOPT_BUFRESIZE] = DTRACEOPT_BUFRESIZE_MANUAL; opt[DTRACEOPT_CPU] = (dtrace_optval_t)cpu; (void) dtrace_state_buffers(state); opt[DTRACEOPT_BUFRESIZE] = rs; opt[DTRACEOPT_CPU] = c; break; } case CPU_UNCONFIG: /* * We don't free the buffer in the CPU_UNCONFIG case. (The * buffer will be freed when the consumer exits.) */ break; default: break; } mutex_exit(&dtrace_lock); return (0); } #ifdef illumos static void dtrace_cpu_setup_initial(processorid_t cpu) { (void) dtrace_cpu_setup(CPU_CONFIG, cpu); } #endif static void dtrace_toxrange_add(uintptr_t base, uintptr_t limit) { if (dtrace_toxranges >= dtrace_toxranges_max) { int osize, nsize; dtrace_toxrange_t *range; osize = dtrace_toxranges_max * sizeof (dtrace_toxrange_t); if (osize == 0) { ASSERT(dtrace_toxrange == NULL); ASSERT(dtrace_toxranges_max == 0); dtrace_toxranges_max = 1; } else { dtrace_toxranges_max <<= 1; } nsize = dtrace_toxranges_max * sizeof (dtrace_toxrange_t); range = kmem_zalloc(nsize, KM_SLEEP); if (dtrace_toxrange != NULL) { ASSERT(osize != 0); bcopy(dtrace_toxrange, range, osize); kmem_free(dtrace_toxrange, osize); } dtrace_toxrange = range; } ASSERT(dtrace_toxrange[dtrace_toxranges].dtt_base == 0); ASSERT(dtrace_toxrange[dtrace_toxranges].dtt_limit == 0); dtrace_toxrange[dtrace_toxranges].dtt_base = base; dtrace_toxrange[dtrace_toxranges].dtt_limit = limit; dtrace_toxranges++; } static void dtrace_getf_barrier() { #ifdef illumos /* * When we have unprivileged (that is, non-DTRACE_CRV_KERNEL) enablings * that contain calls to getf(), this routine will be called on every * closef() before either the underlying vnode is released or the * file_t itself is freed. By the time we are here, it is essential * that the file_t can no longer be accessed from a call to getf() * in probe context -- that assures that a dtrace_sync() can be used * to clear out any enablings referring to the old structures. */ if (curthread->t_procp->p_zone->zone_dtrace_getf != 0 || kcred->cr_zone->zone_dtrace_getf != 0) dtrace_sync(); #endif } /* * DTrace Driver Cookbook Functions */ #ifdef illumos /*ARGSUSED*/ static int dtrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { dtrace_provider_id_t id; dtrace_state_t *state = NULL; dtrace_enabling_t *enab; mutex_enter(&cpu_lock); mutex_enter(&dtrace_provider_lock); mutex_enter(&dtrace_lock); if (ddi_soft_state_init(&dtrace_softstate, sizeof (dtrace_state_t), 0) != 0) { cmn_err(CE_NOTE, "/dev/dtrace failed to initialize soft state"); mutex_exit(&cpu_lock); mutex_exit(&dtrace_provider_lock); mutex_exit(&dtrace_lock); return (DDI_FAILURE); } if (ddi_create_minor_node(devi, DTRACEMNR_DTRACE, S_IFCHR, DTRACEMNRN_DTRACE, DDI_PSEUDO, NULL) == DDI_FAILURE || ddi_create_minor_node(devi, DTRACEMNR_HELPER, S_IFCHR, DTRACEMNRN_HELPER, DDI_PSEUDO, NULL) == DDI_FAILURE) { cmn_err(CE_NOTE, "/dev/dtrace couldn't create minor nodes"); ddi_remove_minor_node(devi, NULL); ddi_soft_state_fini(&dtrace_softstate); mutex_exit(&cpu_lock); mutex_exit(&dtrace_provider_lock); mutex_exit(&dtrace_lock); return (DDI_FAILURE); } ddi_report_dev(devi); dtrace_devi = devi; dtrace_modload = dtrace_module_loaded; dtrace_modunload = dtrace_module_unloaded; dtrace_cpu_init = dtrace_cpu_setup_initial; dtrace_helpers_cleanup = dtrace_helpers_destroy; dtrace_helpers_fork = dtrace_helpers_duplicate; dtrace_cpustart_init = dtrace_suspend; dtrace_cpustart_fini = dtrace_resume; dtrace_debugger_init = dtrace_suspend; dtrace_debugger_fini = dtrace_resume; register_cpu_setup_func((cpu_setup_func_t *)dtrace_cpu_setup, NULL); ASSERT(MUTEX_HELD(&cpu_lock)); dtrace_arena = vmem_create("dtrace", (void *)1, UINT32_MAX, 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER); dtrace_minor = vmem_create("dtrace_minor", (void *)DTRACEMNRN_CLONE, UINT32_MAX - DTRACEMNRN_CLONE, 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER); dtrace_taskq = taskq_create("dtrace_taskq", 1, maxclsyspri, 1, INT_MAX, 0); dtrace_state_cache = kmem_cache_create("dtrace_state_cache", sizeof (dtrace_dstate_percpu_t) * NCPU, DTRACE_STATE_ALIGN, NULL, NULL, NULL, NULL, NULL, 0); ASSERT(MUTEX_HELD(&cpu_lock)); dtrace_bymod = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_mod), offsetof(dtrace_probe_t, dtpr_nextmod), offsetof(dtrace_probe_t, dtpr_prevmod)); dtrace_byfunc = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_func), offsetof(dtrace_probe_t, dtpr_nextfunc), offsetof(dtrace_probe_t, dtpr_prevfunc)); dtrace_byname = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_name), offsetof(dtrace_probe_t, dtpr_nextname), offsetof(dtrace_probe_t, dtpr_prevname)); if (dtrace_retain_max < 1) { cmn_err(CE_WARN, "illegal value (%lu) for dtrace_retain_max; " "setting to 1", dtrace_retain_max); dtrace_retain_max = 1; } /* * Now discover our toxic ranges. */ dtrace_toxic_ranges(dtrace_toxrange_add); /* * Before we register ourselves as a provider to our own framework, * we would like to assert that dtrace_provider is NULL -- but that's * not true if we were loaded as a dependency of a DTrace provider. * Once we've registered, we can assert that dtrace_provider is our * pseudo provider. */ (void) dtrace_register("dtrace", &dtrace_provider_attr, DTRACE_PRIV_NONE, 0, &dtrace_provider_ops, NULL, &id); ASSERT(dtrace_provider != NULL); ASSERT((dtrace_provider_id_t)dtrace_provider == id); dtrace_probeid_begin = dtrace_probe_create((dtrace_provider_id_t) dtrace_provider, NULL, NULL, "BEGIN", 0, NULL); dtrace_probeid_end = dtrace_probe_create((dtrace_provider_id_t) dtrace_provider, NULL, NULL, "END", 0, NULL); dtrace_probeid_error = dtrace_probe_create((dtrace_provider_id_t) dtrace_provider, NULL, NULL, "ERROR", 1, NULL); dtrace_anon_property(); mutex_exit(&cpu_lock); /* * If there are already providers, we must ask them to provide their * probes, and then match any anonymous enabling against them. Note * that there should be no other retained enablings at this time: * the only retained enablings at this time should be the anonymous * enabling. */ if (dtrace_anon.dta_enabling != NULL) { ASSERT(dtrace_retained == dtrace_anon.dta_enabling); dtrace_enabling_provide(NULL); state = dtrace_anon.dta_state; /* * We couldn't hold cpu_lock across the above call to * dtrace_enabling_provide(), but we must hold it to actually * enable the probes. We have to drop all of our locks, pick * up cpu_lock, and regain our locks before matching the * retained anonymous enabling. */ mutex_exit(&dtrace_lock); mutex_exit(&dtrace_provider_lock); mutex_enter(&cpu_lock); mutex_enter(&dtrace_provider_lock); mutex_enter(&dtrace_lock); if ((enab = dtrace_anon.dta_enabling) != NULL) (void) dtrace_enabling_match(enab, NULL); mutex_exit(&cpu_lock); } mutex_exit(&dtrace_lock); mutex_exit(&dtrace_provider_lock); if (state != NULL) { /* * If we created any anonymous state, set it going now. */ (void) dtrace_state_go(state, &dtrace_anon.dta_beganon); } return (DDI_SUCCESS); } #endif /* illumos */ #ifndef illumos static void dtrace_dtr(void *); #endif /*ARGSUSED*/ static int #ifdef illumos dtrace_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) #else dtrace_open(struct cdev *dev, int oflags, int devtype, struct thread *td) #endif { dtrace_state_t *state; uint32_t priv; uid_t uid; zoneid_t zoneid; #ifdef illumos if (getminor(*devp) == DTRACEMNRN_HELPER) return (0); /* * If this wasn't an open with the "helper" minor, then it must be * the "dtrace" minor. */ if (getminor(*devp) == DTRACEMNRN_DTRACE) return (ENXIO); #else cred_t *cred_p = NULL; cred_p = dev->si_cred; /* * If no DTRACE_PRIV_* bits are set in the credential, then the * caller lacks sufficient permission to do anything with DTrace. */ dtrace_cred2priv(cred_p, &priv, &uid, &zoneid); if (priv == DTRACE_PRIV_NONE) { #endif return (EACCES); } /* * Ask all providers to provide all their probes. */ mutex_enter(&dtrace_provider_lock); dtrace_probe_provide(NULL, NULL); mutex_exit(&dtrace_provider_lock); mutex_enter(&cpu_lock); mutex_enter(&dtrace_lock); dtrace_opens++; dtrace_membar_producer(); #ifdef illumos /* * If the kernel debugger is active (that is, if the kernel debugger * modified text in some way), we won't allow the open. */ if (kdi_dtrace_set(KDI_DTSET_DTRACE_ACTIVATE) != 0) { dtrace_opens--; mutex_exit(&cpu_lock); mutex_exit(&dtrace_lock); return (EBUSY); } if (dtrace_helptrace_enable && dtrace_helptrace_buffer == NULL) { /* * If DTrace helper tracing is enabled, we need to allocate the * trace buffer and initialize the values. */ dtrace_helptrace_buffer = kmem_zalloc(dtrace_helptrace_bufsize, KM_SLEEP); dtrace_helptrace_next = 0; dtrace_helptrace_wrapped = 0; dtrace_helptrace_enable = 0; } state = dtrace_state_create(devp, cred_p); #else state = dtrace_state_create(dev, NULL); devfs_set_cdevpriv(state, dtrace_dtr); #endif mutex_exit(&cpu_lock); if (state == NULL) { #ifdef illumos if (--dtrace_opens == 0 && dtrace_anon.dta_enabling == NULL) (void) kdi_dtrace_set(KDI_DTSET_DTRACE_DEACTIVATE); #else --dtrace_opens; #endif mutex_exit(&dtrace_lock); return (EAGAIN); } mutex_exit(&dtrace_lock); return (0); } /*ARGSUSED*/ #ifdef illumos static int dtrace_close(dev_t dev, int flag, int otyp, cred_t *cred_p) #else static void dtrace_dtr(void *data) #endif { #ifdef illumos minor_t minor = getminor(dev); dtrace_state_t *state; #endif dtrace_helptrace_t *buf = NULL; #ifdef illumos if (minor == DTRACEMNRN_HELPER) return (0); state = ddi_get_soft_state(dtrace_softstate, minor); #else dtrace_state_t *state = data; #endif mutex_enter(&cpu_lock); mutex_enter(&dtrace_lock); #ifdef illumos if (state->dts_anon) #else if (state != NULL && state->dts_anon) #endif { /* * There is anonymous state. Destroy that first. */ ASSERT(dtrace_anon.dta_state == NULL); dtrace_state_destroy(state->dts_anon); } if (dtrace_helptrace_disable) { /* * If we have been told to disable helper tracing, set the * buffer to NULL before calling into dtrace_state_destroy(); * we take advantage of its dtrace_sync() to know that no * CPU is in probe context with enabled helper tracing * after it returns. */ buf = dtrace_helptrace_buffer; dtrace_helptrace_buffer = NULL; } #ifdef illumos dtrace_state_destroy(state); #else if (state != NULL) { dtrace_state_destroy(state); kmem_free(state, 0); } #endif ASSERT(dtrace_opens > 0); #ifdef illumos /* * Only relinquish control of the kernel debugger interface when there * are no consumers and no anonymous enablings. */ if (--dtrace_opens == 0 && dtrace_anon.dta_enabling == NULL) (void) kdi_dtrace_set(KDI_DTSET_DTRACE_DEACTIVATE); #else --dtrace_opens; #endif if (buf != NULL) { kmem_free(buf, dtrace_helptrace_bufsize); dtrace_helptrace_disable = 0; } mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); #ifdef illumos return (0); #endif } #ifdef illumos /*ARGSUSED*/ static int dtrace_ioctl_helper(int cmd, intptr_t arg, int *rv) { int rval; dof_helper_t help, *dhp = NULL; switch (cmd) { case DTRACEHIOC_ADDDOF: if (copyin((void *)arg, &help, sizeof (help)) != 0) { dtrace_dof_error(NULL, "failed to copyin DOF helper"); return (EFAULT); } dhp = &help; arg = (intptr_t)help.dofhp_dof; /*FALLTHROUGH*/ case DTRACEHIOC_ADD: { dof_hdr_t *dof = dtrace_dof_copyin(arg, &rval); if (dof == NULL) return (rval); mutex_enter(&dtrace_lock); /* * dtrace_helper_slurp() takes responsibility for the dof -- * it may free it now or it may save it and free it later. */ if ((rval = dtrace_helper_slurp(dof, dhp)) != -1) { *rv = rval; rval = 0; } else { rval = EINVAL; } mutex_exit(&dtrace_lock); return (rval); } case DTRACEHIOC_REMOVE: { mutex_enter(&dtrace_lock); rval = dtrace_helper_destroygen(NULL, arg); mutex_exit(&dtrace_lock); return (rval); } default: break; } return (ENOTTY); } /*ARGSUSED*/ static int dtrace_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv) { minor_t minor = getminor(dev); dtrace_state_t *state; int rval; if (minor == DTRACEMNRN_HELPER) return (dtrace_ioctl_helper(cmd, arg, rv)); state = ddi_get_soft_state(dtrace_softstate, minor); if (state->dts_anon) { ASSERT(dtrace_anon.dta_state == NULL); state = state->dts_anon; } switch (cmd) { case DTRACEIOC_PROVIDER: { dtrace_providerdesc_t pvd; dtrace_provider_t *pvp; if (copyin((void *)arg, &pvd, sizeof (pvd)) != 0) return (EFAULT); pvd.dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0'; mutex_enter(&dtrace_provider_lock); for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) { if (strcmp(pvp->dtpv_name, pvd.dtvd_name) == 0) break; } mutex_exit(&dtrace_provider_lock); if (pvp == NULL) return (ESRCH); bcopy(&pvp->dtpv_priv, &pvd.dtvd_priv, sizeof (dtrace_ppriv_t)); bcopy(&pvp->dtpv_attr, &pvd.dtvd_attr, sizeof (dtrace_pattr_t)); if (copyout(&pvd, (void *)arg, sizeof (pvd)) != 0) return (EFAULT); return (0); } case DTRACEIOC_EPROBE: { dtrace_eprobedesc_t epdesc; dtrace_ecb_t *ecb; dtrace_action_t *act; void *buf; size_t size; uintptr_t dest; int nrecs; if (copyin((void *)arg, &epdesc, sizeof (epdesc)) != 0) return (EFAULT); mutex_enter(&dtrace_lock); if ((ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid)) == NULL) { mutex_exit(&dtrace_lock); return (EINVAL); } if (ecb->dte_probe == NULL) { mutex_exit(&dtrace_lock); return (EINVAL); } epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id; epdesc.dtepd_uarg = ecb->dte_uarg; epdesc.dtepd_size = ecb->dte_size; nrecs = epdesc.dtepd_nrecs; epdesc.dtepd_nrecs = 0; for (act = ecb->dte_action; act != NULL; act = act->dta_next) { if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) continue; epdesc.dtepd_nrecs++; } /* * Now that we have the size, we need to allocate a temporary * buffer in which to store the complete description. We need * the temporary buffer to be able to drop dtrace_lock() * across the copyout(), below. */ size = sizeof (dtrace_eprobedesc_t) + (epdesc.dtepd_nrecs * sizeof (dtrace_recdesc_t)); buf = kmem_alloc(size, KM_SLEEP); dest = (uintptr_t)buf; bcopy(&epdesc, (void *)dest, sizeof (epdesc)); dest += offsetof(dtrace_eprobedesc_t, dtepd_rec[0]); for (act = ecb->dte_action; act != NULL; act = act->dta_next) { if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) continue; if (nrecs-- == 0) break; bcopy(&act->dta_rec, (void *)dest, sizeof (dtrace_recdesc_t)); dest += sizeof (dtrace_recdesc_t); } mutex_exit(&dtrace_lock); if (copyout(buf, (void *)arg, dest - (uintptr_t)buf) != 0) { kmem_free(buf, size); return (EFAULT); } kmem_free(buf, size); return (0); } case DTRACEIOC_AGGDESC: { dtrace_aggdesc_t aggdesc; dtrace_action_t *act; dtrace_aggregation_t *agg; int nrecs; uint32_t offs; dtrace_recdesc_t *lrec; void *buf; size_t size; uintptr_t dest; if (copyin((void *)arg, &aggdesc, sizeof (aggdesc)) != 0) return (EFAULT); mutex_enter(&dtrace_lock); if ((agg = dtrace_aggid2agg(state, aggdesc.dtagd_id)) == NULL) { mutex_exit(&dtrace_lock); return (EINVAL); } aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid; nrecs = aggdesc.dtagd_nrecs; aggdesc.dtagd_nrecs = 0; offs = agg->dtag_base; lrec = &agg->dtag_action.dta_rec; aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - offs; for (act = agg->dtag_first; ; act = act->dta_next) { ASSERT(act->dta_intuple || DTRACEACT_ISAGG(act->dta_kind)); /* * If this action has a record size of zero, it * denotes an argument to the aggregating action. * Because the presence of this record doesn't (or * shouldn't) affect the way the data is interpreted, * we don't copy it out to save user-level the * confusion of dealing with a zero-length record. */ if (act->dta_rec.dtrd_size == 0) { ASSERT(agg->dtag_hasarg); continue; } aggdesc.dtagd_nrecs++; if (act == &agg->dtag_action) break; } /* * Now that we have the size, we need to allocate a temporary * buffer in which to store the complete description. We need * the temporary buffer to be able to drop dtrace_lock() * across the copyout(), below. */ size = sizeof (dtrace_aggdesc_t) + (aggdesc.dtagd_nrecs * sizeof (dtrace_recdesc_t)); buf = kmem_alloc(size, KM_SLEEP); dest = (uintptr_t)buf; bcopy(&aggdesc, (void *)dest, sizeof (aggdesc)); dest += offsetof(dtrace_aggdesc_t, dtagd_rec[0]); for (act = agg->dtag_first; ; act = act->dta_next) { dtrace_recdesc_t rec = act->dta_rec; /* * See the comment in the above loop for why we pass * over zero-length records. */ if (rec.dtrd_size == 0) { ASSERT(agg->dtag_hasarg); continue; } if (nrecs-- == 0) break; rec.dtrd_offset -= offs; bcopy(&rec, (void *)dest, sizeof (rec)); dest += sizeof (dtrace_recdesc_t); if (act == &agg->dtag_action) break; } mutex_exit(&dtrace_lock); if (copyout(buf, (void *)arg, dest - (uintptr_t)buf) != 0) { kmem_free(buf, size); return (EFAULT); } kmem_free(buf, size); return (0); } case DTRACEIOC_ENABLE: { dof_hdr_t *dof; dtrace_enabling_t *enab = NULL; dtrace_vstate_t *vstate; int err = 0; *rv = 0; /* * If a NULL argument has been passed, we take this as our * cue to reevaluate our enablings. */ if (arg == NULL) { dtrace_enabling_matchall(); return (0); } if ((dof = dtrace_dof_copyin(arg, &rval)) == NULL) return (rval); mutex_enter(&cpu_lock); mutex_enter(&dtrace_lock); vstate = &state->dts_vstate; if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) { mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); dtrace_dof_destroy(dof); return (EBUSY); } if (dtrace_dof_slurp(dof, vstate, cr, &enab, 0, B_TRUE) != 0) { mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); dtrace_dof_destroy(dof); return (EINVAL); } if ((rval = dtrace_dof_options(dof, state)) != 0) { dtrace_enabling_destroy(enab); mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); dtrace_dof_destroy(dof); return (rval); } if ((err = dtrace_enabling_match(enab, rv)) == 0) { err = dtrace_enabling_retain(enab); } else { dtrace_enabling_destroy(enab); } mutex_exit(&cpu_lock); mutex_exit(&dtrace_lock); dtrace_dof_destroy(dof); return (err); } case DTRACEIOC_REPLICATE: { dtrace_repldesc_t desc; dtrace_probedesc_t *match = &desc.dtrpd_match; dtrace_probedesc_t *create = &desc.dtrpd_create; int err; if (copyin((void *)arg, &desc, sizeof (desc)) != 0) return (EFAULT); match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; match->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; create->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; mutex_enter(&dtrace_lock); err = dtrace_enabling_replicate(state, match, create); mutex_exit(&dtrace_lock); return (err); } case DTRACEIOC_PROBEMATCH: case DTRACEIOC_PROBES: { dtrace_probe_t *probe = NULL; dtrace_probedesc_t desc; dtrace_probekey_t pkey; dtrace_id_t i; int m = 0; uint32_t priv; uid_t uid; zoneid_t zoneid; if (copyin((void *)arg, &desc, sizeof (desc)) != 0) return (EFAULT); desc.dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; desc.dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; desc.dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; desc.dtpd_name[DTRACE_NAMELEN - 1] = '\0'; /* * Before we attempt to match this probe, we want to give * all providers the opportunity to provide it. */ if (desc.dtpd_id == DTRACE_IDNONE) { mutex_enter(&dtrace_provider_lock); dtrace_probe_provide(&desc, NULL); mutex_exit(&dtrace_provider_lock); desc.dtpd_id++; } if (cmd == DTRACEIOC_PROBEMATCH) { dtrace_probekey(&desc, &pkey); pkey.dtpk_id = DTRACE_IDNONE; } dtrace_cred2priv(cr, &priv, &uid, &zoneid); mutex_enter(&dtrace_lock); if (cmd == DTRACEIOC_PROBEMATCH) { for (i = desc.dtpd_id; i <= dtrace_nprobes; i++) { if ((probe = dtrace_probes[i - 1]) != NULL && (m = dtrace_match_probe(probe, &pkey, priv, uid, zoneid)) != 0) break; } if (m < 0) { mutex_exit(&dtrace_lock); return (EINVAL); } } else { for (i = desc.dtpd_id; i <= dtrace_nprobes; i++) { if ((probe = dtrace_probes[i - 1]) != NULL && dtrace_match_priv(probe, priv, uid, zoneid)) break; } } if (probe == NULL) { mutex_exit(&dtrace_lock); return (ESRCH); } dtrace_probe_description(probe, &desc); mutex_exit(&dtrace_lock); if (copyout(&desc, (void *)arg, sizeof (desc)) != 0) return (EFAULT); return (0); } case DTRACEIOC_PROBEARG: { dtrace_argdesc_t desc; dtrace_probe_t *probe; dtrace_provider_t *prov; if (copyin((void *)arg, &desc, sizeof (desc)) != 0) return (EFAULT); if (desc.dtargd_id == DTRACE_IDNONE) return (EINVAL); if (desc.dtargd_ndx == DTRACE_ARGNONE) return (EINVAL); mutex_enter(&dtrace_provider_lock); mutex_enter(&mod_lock); mutex_enter(&dtrace_lock); if (desc.dtargd_id > dtrace_nprobes) { mutex_exit(&dtrace_lock); mutex_exit(&mod_lock); mutex_exit(&dtrace_provider_lock); return (EINVAL); } if ((probe = dtrace_probes[desc.dtargd_id - 1]) == NULL) { mutex_exit(&dtrace_lock); mutex_exit(&mod_lock); mutex_exit(&dtrace_provider_lock); return (EINVAL); } mutex_exit(&dtrace_lock); prov = probe->dtpr_provider; if (prov->dtpv_pops.dtps_getargdesc == NULL) { /* * There isn't any typed information for this probe. * Set the argument number to DTRACE_ARGNONE. */ desc.dtargd_ndx = DTRACE_ARGNONE; } else { desc.dtargd_native[0] = '\0'; desc.dtargd_xlate[0] = '\0'; desc.dtargd_mapping = desc.dtargd_ndx; prov->dtpv_pops.dtps_getargdesc(prov->dtpv_arg, probe->dtpr_id, probe->dtpr_arg, &desc); } mutex_exit(&mod_lock); mutex_exit(&dtrace_provider_lock); if (copyout(&desc, (void *)arg, sizeof (desc)) != 0) return (EFAULT); return (0); } case DTRACEIOC_GO: { processorid_t cpuid; rval = dtrace_state_go(state, &cpuid); if (rval != 0) return (rval); if (copyout(&cpuid, (void *)arg, sizeof (cpuid)) != 0) return (EFAULT); return (0); } case DTRACEIOC_STOP: { processorid_t cpuid; mutex_enter(&dtrace_lock); rval = dtrace_state_stop(state, &cpuid); mutex_exit(&dtrace_lock); if (rval != 0) return (rval); if (copyout(&cpuid, (void *)arg, sizeof (cpuid)) != 0) return (EFAULT); return (0); } case DTRACEIOC_DOFGET: { dof_hdr_t hdr, *dof; uint64_t len; if (copyin((void *)arg, &hdr, sizeof (hdr)) != 0) return (EFAULT); mutex_enter(&dtrace_lock); dof = dtrace_dof_create(state); mutex_exit(&dtrace_lock); len = MIN(hdr.dofh_loadsz, dof->dofh_loadsz); rval = copyout(dof, (void *)arg, len); dtrace_dof_destroy(dof); return (rval == 0 ? 0 : EFAULT); } case DTRACEIOC_AGGSNAP: case DTRACEIOC_BUFSNAP: { dtrace_bufdesc_t desc; caddr_t cached; dtrace_buffer_t *buf; if (copyin((void *)arg, &desc, sizeof (desc)) != 0) return (EFAULT); if (desc.dtbd_cpu < 0 || desc.dtbd_cpu >= NCPU) return (EINVAL); mutex_enter(&dtrace_lock); if (cmd == DTRACEIOC_BUFSNAP) { buf = &state->dts_buffer[desc.dtbd_cpu]; } else { buf = &state->dts_aggbuffer[desc.dtbd_cpu]; } if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) { size_t sz = buf->dtb_offset; if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) { mutex_exit(&dtrace_lock); return (EBUSY); } /* * If this buffer has already been consumed, we're * going to indicate that there's nothing left here * to consume. */ if (buf->dtb_flags & DTRACEBUF_CONSUMED) { mutex_exit(&dtrace_lock); desc.dtbd_size = 0; desc.dtbd_drops = 0; desc.dtbd_errors = 0; desc.dtbd_oldest = 0; sz = sizeof (desc); if (copyout(&desc, (void *)arg, sz) != 0) return (EFAULT); return (0); } /* * If this is a ring buffer that has wrapped, we want * to copy the whole thing out. */ if (buf->dtb_flags & DTRACEBUF_WRAPPED) { dtrace_buffer_polish(buf); sz = buf->dtb_size; } if (copyout(buf->dtb_tomax, desc.dtbd_data, sz) != 0) { mutex_exit(&dtrace_lock); return (EFAULT); } desc.dtbd_size = sz; desc.dtbd_drops = buf->dtb_drops; desc.dtbd_errors = buf->dtb_errors; desc.dtbd_oldest = buf->dtb_xamot_offset; desc.dtbd_timestamp = dtrace_gethrtime(); mutex_exit(&dtrace_lock); if (copyout(&desc, (void *)arg, sizeof (desc)) != 0) return (EFAULT); buf->dtb_flags |= DTRACEBUF_CONSUMED; return (0); } if (buf->dtb_tomax == NULL) { ASSERT(buf->dtb_xamot == NULL); mutex_exit(&dtrace_lock); return (ENOENT); } cached = buf->dtb_tomax; ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); dtrace_xcall(desc.dtbd_cpu, (dtrace_xcall_t)dtrace_buffer_switch, buf); state->dts_errors += buf->dtb_xamot_errors; /* * If the buffers did not actually switch, then the cross call * did not take place -- presumably because the given CPU is * not in the ready set. If this is the case, we'll return * ENOENT. */ if (buf->dtb_tomax == cached) { ASSERT(buf->dtb_xamot != cached); mutex_exit(&dtrace_lock); return (ENOENT); } ASSERT(cached == buf->dtb_xamot); /* * We have our snapshot; now copy it out. */ if (copyout(buf->dtb_xamot, desc.dtbd_data, buf->dtb_xamot_offset) != 0) { mutex_exit(&dtrace_lock); return (EFAULT); } desc.dtbd_size = buf->dtb_xamot_offset; desc.dtbd_drops = buf->dtb_xamot_drops; desc.dtbd_errors = buf->dtb_xamot_errors; desc.dtbd_oldest = 0; desc.dtbd_timestamp = buf->dtb_switched; mutex_exit(&dtrace_lock); /* * Finally, copy out the buffer description. */ if (copyout(&desc, (void *)arg, sizeof (desc)) != 0) return (EFAULT); return (0); } case DTRACEIOC_CONF: { dtrace_conf_t conf; bzero(&conf, sizeof (conf)); conf.dtc_difversion = DIF_VERSION; conf.dtc_difintregs = DIF_DIR_NREGS; conf.dtc_diftupregs = DIF_DTR_NREGS; conf.dtc_ctfmodel = CTF_MODEL_NATIVE; if (copyout(&conf, (void *)arg, sizeof (conf)) != 0) return (EFAULT); return (0); } case DTRACEIOC_STATUS: { dtrace_status_t stat; dtrace_dstate_t *dstate; int i, j; uint64_t nerrs; /* * See the comment in dtrace_state_deadman() for the reason * for setting dts_laststatus to INT64_MAX before setting * it to the correct value. */ state->dts_laststatus = INT64_MAX; dtrace_membar_producer(); state->dts_laststatus = dtrace_gethrtime(); bzero(&stat, sizeof (stat)); mutex_enter(&dtrace_lock); if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) { mutex_exit(&dtrace_lock); return (ENOENT); } if (state->dts_activity == DTRACE_ACTIVITY_DRAINING) stat.dtst_exiting = 1; nerrs = state->dts_errors; dstate = &state->dts_vstate.dtvs_dynvars; for (i = 0; i < NCPU; i++) { dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[i]; stat.dtst_dyndrops += dcpu->dtdsc_drops; stat.dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops; stat.dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops; if (state->dts_buffer[i].dtb_flags & DTRACEBUF_FULL) stat.dtst_filled++; nerrs += state->dts_buffer[i].dtb_errors; for (j = 0; j < state->dts_nspeculations; j++) { dtrace_speculation_t *spec; dtrace_buffer_t *buf; spec = &state->dts_speculations[j]; buf = &spec->dtsp_buffer[i]; stat.dtst_specdrops += buf->dtb_xamot_drops; } } stat.dtst_specdrops_busy = state->dts_speculations_busy; stat.dtst_specdrops_unavail = state->dts_speculations_unavail; stat.dtst_stkstroverflows = state->dts_stkstroverflows; stat.dtst_dblerrors = state->dts_dblerrors; stat.dtst_killed = (state->dts_activity == DTRACE_ACTIVITY_KILLED); stat.dtst_errors = nerrs; mutex_exit(&dtrace_lock); if (copyout(&stat, (void *)arg, sizeof (stat)) != 0) return (EFAULT); return (0); } case DTRACEIOC_FORMAT: { dtrace_fmtdesc_t fmt; char *str; int len; if (copyin((void *)arg, &fmt, sizeof (fmt)) != 0) return (EFAULT); mutex_enter(&dtrace_lock); if (fmt.dtfd_format == 0 || fmt.dtfd_format > state->dts_nformats) { mutex_exit(&dtrace_lock); return (EINVAL); } /* * Format strings are allocated contiguously and they are * never freed; if a format index is less than the number * of formats, we can assert that the format map is non-NULL * and that the format for the specified index is non-NULL. */ ASSERT(state->dts_formats != NULL); str = state->dts_formats[fmt.dtfd_format - 1]; ASSERT(str != NULL); len = strlen(str) + 1; if (len > fmt.dtfd_length) { fmt.dtfd_length = len; if (copyout(&fmt, (void *)arg, sizeof (fmt)) != 0) { mutex_exit(&dtrace_lock); return (EINVAL); } } else { if (copyout(str, fmt.dtfd_string, len) != 0) { mutex_exit(&dtrace_lock); return (EINVAL); } } mutex_exit(&dtrace_lock); return (0); } default: break; } return (ENOTTY); } /*ARGSUSED*/ static int dtrace_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { dtrace_state_t *state; switch (cmd) { case DDI_DETACH: break; case DDI_SUSPEND: return (DDI_SUCCESS); default: return (DDI_FAILURE); } mutex_enter(&cpu_lock); mutex_enter(&dtrace_provider_lock); mutex_enter(&dtrace_lock); ASSERT(dtrace_opens == 0); if (dtrace_helpers > 0) { mutex_exit(&dtrace_provider_lock); mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); return (DDI_FAILURE); } if (dtrace_unregister((dtrace_provider_id_t)dtrace_provider) != 0) { mutex_exit(&dtrace_provider_lock); mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); return (DDI_FAILURE); } dtrace_provider = NULL; if ((state = dtrace_anon_grab()) != NULL) { /* * If there were ECBs on this state, the provider should * have not been allowed to detach; assert that there is * none. */ ASSERT(state->dts_necbs == 0); dtrace_state_destroy(state); /* * If we're being detached with anonymous state, we need to * indicate to the kernel debugger that DTrace is now inactive. */ (void) kdi_dtrace_set(KDI_DTSET_DTRACE_DEACTIVATE); } bzero(&dtrace_anon, sizeof (dtrace_anon_t)); unregister_cpu_setup_func((cpu_setup_func_t *)dtrace_cpu_setup, NULL); dtrace_cpu_init = NULL; dtrace_helpers_cleanup = NULL; dtrace_helpers_fork = NULL; dtrace_cpustart_init = NULL; dtrace_cpustart_fini = NULL; dtrace_debugger_init = NULL; dtrace_debugger_fini = NULL; dtrace_modload = NULL; dtrace_modunload = NULL; ASSERT(dtrace_getf == 0); ASSERT(dtrace_closef == NULL); mutex_exit(&cpu_lock); kmem_free(dtrace_probes, dtrace_nprobes * sizeof (dtrace_probe_t *)); dtrace_probes = NULL; dtrace_nprobes = 0; dtrace_hash_destroy(dtrace_bymod); dtrace_hash_destroy(dtrace_byfunc); dtrace_hash_destroy(dtrace_byname); dtrace_bymod = NULL; dtrace_byfunc = NULL; dtrace_byname = NULL; kmem_cache_destroy(dtrace_state_cache); vmem_destroy(dtrace_minor); vmem_destroy(dtrace_arena); if (dtrace_toxrange != NULL) { kmem_free(dtrace_toxrange, dtrace_toxranges_max * sizeof (dtrace_toxrange_t)); dtrace_toxrange = NULL; dtrace_toxranges = 0; dtrace_toxranges_max = 0; } ddi_remove_minor_node(dtrace_devi, NULL); dtrace_devi = NULL; ddi_soft_state_fini(&dtrace_softstate); ASSERT(dtrace_vtime_references == 0); ASSERT(dtrace_opens == 0); ASSERT(dtrace_retained == NULL); mutex_exit(&dtrace_lock); mutex_exit(&dtrace_provider_lock); /* * We don't destroy the task queue until after we have dropped our * locks (taskq_destroy() may block on running tasks). To prevent * attempting to do work after we have effectively detached but before * the task queue has been destroyed, all tasks dispatched via the * task queue must check that DTrace is still attached before * performing any operation. */ taskq_destroy(dtrace_taskq); dtrace_taskq = NULL; return (DDI_SUCCESS); } #endif #ifdef illumos /*ARGSUSED*/ static int dtrace_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) { int error; switch (infocmd) { case DDI_INFO_DEVT2DEVINFO: *result = (void *)dtrace_devi; error = DDI_SUCCESS; break; case DDI_INFO_DEVT2INSTANCE: *result = (void *)0; error = DDI_SUCCESS; break; default: error = DDI_FAILURE; } return (error); } #endif #ifdef illumos static struct cb_ops dtrace_cb_ops = { dtrace_open, /* open */ dtrace_close, /* close */ nulldev, /* strategy */ nulldev, /* print */ nodev, /* dump */ nodev, /* read */ nodev, /* write */ dtrace_ioctl, /* ioctl */ nodev, /* devmap */ nodev, /* mmap */ nodev, /* segmap */ nochpoll, /* poll */ ddi_prop_op, /* cb_prop_op */ 0, /* streamtab */ D_NEW | D_MP /* Driver compatibility flag */ }; static struct dev_ops dtrace_ops = { DEVO_REV, /* devo_rev */ 0, /* refcnt */ dtrace_info, /* get_dev_info */ nulldev, /* identify */ nulldev, /* probe */ dtrace_attach, /* attach */ dtrace_detach, /* detach */ nodev, /* reset */ &dtrace_cb_ops, /* driver operations */ NULL, /* bus operations */ nodev /* dev power */ }; static struct modldrv modldrv = { &mod_driverops, /* module type (this is a pseudo driver) */ "Dynamic Tracing", /* name of module */ &dtrace_ops, /* driver ops */ }; static struct modlinkage modlinkage = { MODREV_1, (void *)&modldrv, NULL }; int _init(void) { return (mod_install(&modlinkage)); } int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } int _fini(void) { return (mod_remove(&modlinkage)); } #else static d_ioctl_t dtrace_ioctl; static d_ioctl_t dtrace_ioctl_helper; static void dtrace_load(void *); static int dtrace_unload(void); static struct cdev *dtrace_dev; static struct cdev *helper_dev; void dtrace_invop_init(void); void dtrace_invop_uninit(void); static struct cdevsw dtrace_cdevsw = { .d_version = D_VERSION, .d_ioctl = dtrace_ioctl, .d_open = dtrace_open, .d_name = "dtrace", }; static struct cdevsw helper_cdevsw = { .d_version = D_VERSION, .d_ioctl = dtrace_ioctl_helper, .d_name = "helper", }; #include #include #include #include #include #include #include #include #include SYSINIT(dtrace_load, SI_SUB_DTRACE, SI_ORDER_FIRST, dtrace_load, NULL); SYSUNINIT(dtrace_unload, SI_SUB_DTRACE, SI_ORDER_FIRST, dtrace_unload, NULL); SYSINIT(dtrace_anon_init, SI_SUB_DTRACE_ANON, SI_ORDER_FIRST, dtrace_anon_init, NULL); DEV_MODULE(dtrace, dtrace_modevent, NULL); MODULE_VERSION(dtrace, 1); MODULE_DEPEND(dtrace, opensolaris, 1, 1, 1); #endif Index: projects/ipsec/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h =================================================================== --- projects/ipsec/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h (revision 313312) +++ projects/ipsec/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h (revision 313313) @@ -1,2509 +1,2510 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. */ #ifndef _SYS_DTRACE_H #define _SYS_DTRACE_H #ifdef __cplusplus extern "C" { #endif /* * DTrace Dynamic Tracing Software: Kernel Interfaces * * Note: The contents of this file are private to the implementation of the * Solaris system and DTrace subsystem and are subject to change at any time * without notice. Applications and drivers using these interfaces will fail * to run on future releases. These interfaces should not be used for any * purpose except those expressly outlined in dtrace(7D) and libdtrace(3LIB). * Please refer to the "Solaris Dynamic Tracing Guide" for more information. */ #ifndef _ASM #include #include #include #ifdef illumos #include #else #include #include #include #include #include typedef int model_t; #endif #include #ifdef illumos #include #include #else #include #endif /* * DTrace Universal Constants and Typedefs */ #define DTRACE_CPUALL -1 /* all CPUs */ #define DTRACE_IDNONE 0 /* invalid probe identifier */ #define DTRACE_EPIDNONE 0 /* invalid enabled probe identifier */ #define DTRACE_AGGIDNONE 0 /* invalid aggregation identifier */ #define DTRACE_AGGVARIDNONE 0 /* invalid aggregation variable ID */ #define DTRACE_CACHEIDNONE 0 /* invalid predicate cache */ #define DTRACE_PROVNONE 0 /* invalid provider identifier */ #define DTRACE_METAPROVNONE 0 /* invalid meta-provider identifier */ #define DTRACE_ARGNONE -1 /* invalid argument index */ #define DTRACE_PROVNAMELEN 64 #define DTRACE_MODNAMELEN 64 #define DTRACE_FUNCNAMELEN 192 #define DTRACE_NAMELEN 64 #define DTRACE_FULLNAMELEN (DTRACE_PROVNAMELEN + DTRACE_MODNAMELEN + \ DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 4) #define DTRACE_ARGTYPELEN 128 typedef uint32_t dtrace_id_t; /* probe identifier */ typedef uint32_t dtrace_epid_t; /* enabled probe identifier */ typedef uint32_t dtrace_aggid_t; /* aggregation identifier */ typedef int64_t dtrace_aggvarid_t; /* aggregation variable identifier */ typedef uint16_t dtrace_actkind_t; /* action kind */ typedef int64_t dtrace_optval_t; /* option value */ typedef uint32_t dtrace_cacheid_t; /* predicate cache identifier */ typedef enum dtrace_probespec { DTRACE_PROBESPEC_NONE = -1, DTRACE_PROBESPEC_PROVIDER = 0, DTRACE_PROBESPEC_MOD, DTRACE_PROBESPEC_FUNC, DTRACE_PROBESPEC_NAME } dtrace_probespec_t; /* * DTrace Intermediate Format (DIF) * * The following definitions describe the DTrace Intermediate Format (DIF), a * a RISC-like instruction set and program encoding used to represent * predicates and actions that can be bound to DTrace probes. The constants * below defining the number of available registers are suggested minimums; the * compiler should use DTRACEIOC_CONF to dynamically obtain the number of * registers provided by the current DTrace implementation. */ #define DIF_VERSION_1 1 /* DIF version 1: Solaris 10 Beta */ #define DIF_VERSION_2 2 /* DIF version 2: Solaris 10 FCS */ #define DIF_VERSION DIF_VERSION_2 /* latest DIF instruction set version */ #define DIF_DIR_NREGS 8 /* number of DIF integer registers */ #define DIF_DTR_NREGS 8 /* number of DIF tuple registers */ #define DIF_OP_OR 1 /* or r1, r2, rd */ #define DIF_OP_XOR 2 /* xor r1, r2, rd */ #define DIF_OP_AND 3 /* and r1, r2, rd */ #define DIF_OP_SLL 4 /* sll r1, r2, rd */ #define DIF_OP_SRL 5 /* srl r1, r2, rd */ #define DIF_OP_SUB 6 /* sub r1, r2, rd */ #define DIF_OP_ADD 7 /* add r1, r2, rd */ #define DIF_OP_MUL 8 /* mul r1, r2, rd */ #define DIF_OP_SDIV 9 /* sdiv r1, r2, rd */ #define DIF_OP_UDIV 10 /* udiv r1, r2, rd */ #define DIF_OP_SREM 11 /* srem r1, r2, rd */ #define DIF_OP_UREM 12 /* urem r1, r2, rd */ #define DIF_OP_NOT 13 /* not r1, rd */ #define DIF_OP_MOV 14 /* mov r1, rd */ #define DIF_OP_CMP 15 /* cmp r1, r2 */ #define DIF_OP_TST 16 /* tst r1 */ #define DIF_OP_BA 17 /* ba label */ #define DIF_OP_BE 18 /* be label */ #define DIF_OP_BNE 19 /* bne label */ #define DIF_OP_BG 20 /* bg label */ #define DIF_OP_BGU 21 /* bgu label */ #define DIF_OP_BGE 22 /* bge label */ #define DIF_OP_BGEU 23 /* bgeu label */ #define DIF_OP_BL 24 /* bl label */ #define DIF_OP_BLU 25 /* blu label */ #define DIF_OP_BLE 26 /* ble label */ #define DIF_OP_BLEU 27 /* bleu label */ #define DIF_OP_LDSB 28 /* ldsb [r1], rd */ #define DIF_OP_LDSH 29 /* ldsh [r1], rd */ #define DIF_OP_LDSW 30 /* ldsw [r1], rd */ #define DIF_OP_LDUB 31 /* ldub [r1], rd */ #define DIF_OP_LDUH 32 /* lduh [r1], rd */ #define DIF_OP_LDUW 33 /* lduw [r1], rd */ #define DIF_OP_LDX 34 /* ldx [r1], rd */ #define DIF_OP_RET 35 /* ret rd */ #define DIF_OP_NOP 36 /* nop */ #define DIF_OP_SETX 37 /* setx intindex, rd */ #define DIF_OP_SETS 38 /* sets strindex, rd */ #define DIF_OP_SCMP 39 /* scmp r1, r2 */ #define DIF_OP_LDGA 40 /* ldga var, ri, rd */ #define DIF_OP_LDGS 41 /* ldgs var, rd */ #define DIF_OP_STGS 42 /* stgs var, rs */ #define DIF_OP_LDTA 43 /* ldta var, ri, rd */ #define DIF_OP_LDTS 44 /* ldts var, rd */ #define DIF_OP_STTS 45 /* stts var, rs */ #define DIF_OP_SRA 46 /* sra r1, r2, rd */ #define DIF_OP_CALL 47 /* call subr, rd */ #define DIF_OP_PUSHTR 48 /* pushtr type, rs, rr */ #define DIF_OP_PUSHTV 49 /* pushtv type, rs, rv */ #define DIF_OP_POPTS 50 /* popts */ #define DIF_OP_FLUSHTS 51 /* flushts */ #define DIF_OP_LDGAA 52 /* ldgaa var, rd */ #define DIF_OP_LDTAA 53 /* ldtaa var, rd */ #define DIF_OP_STGAA 54 /* stgaa var, rs */ #define DIF_OP_STTAA 55 /* sttaa var, rs */ #define DIF_OP_LDLS 56 /* ldls var, rd */ #define DIF_OP_STLS 57 /* stls var, rs */ #define DIF_OP_ALLOCS 58 /* allocs r1, rd */ #define DIF_OP_COPYS 59 /* copys r1, r2, rd */ #define DIF_OP_STB 60 /* stb r1, [rd] */ #define DIF_OP_STH 61 /* sth r1, [rd] */ #define DIF_OP_STW 62 /* stw r1, [rd] */ #define DIF_OP_STX 63 /* stx r1, [rd] */ #define DIF_OP_ULDSB 64 /* uldsb [r1], rd */ #define DIF_OP_ULDSH 65 /* uldsh [r1], rd */ #define DIF_OP_ULDSW 66 /* uldsw [r1], rd */ #define DIF_OP_ULDUB 67 /* uldub [r1], rd */ #define DIF_OP_ULDUH 68 /* ulduh [r1], rd */ #define DIF_OP_ULDUW 69 /* ulduw [r1], rd */ #define DIF_OP_ULDX 70 /* uldx [r1], rd */ #define DIF_OP_RLDSB 71 /* rldsb [r1], rd */ #define DIF_OP_RLDSH 72 /* rldsh [r1], rd */ #define DIF_OP_RLDSW 73 /* rldsw [r1], rd */ #define DIF_OP_RLDUB 74 /* rldub [r1], rd */ #define DIF_OP_RLDUH 75 /* rlduh [r1], rd */ #define DIF_OP_RLDUW 76 /* rlduw [r1], rd */ #define DIF_OP_RLDX 77 /* rldx [r1], rd */ #define DIF_OP_XLATE 78 /* xlate xlrindex, rd */ #define DIF_OP_XLARG 79 /* xlarg xlrindex, rd */ #define DIF_INTOFF_MAX 0xffff /* highest integer table offset */ #define DIF_STROFF_MAX 0xffff /* highest string table offset */ #define DIF_REGISTER_MAX 0xff /* highest register number */ #define DIF_VARIABLE_MAX 0xffff /* highest variable identifier */ #define DIF_SUBROUTINE_MAX 0xffff /* highest subroutine code */ #define DIF_VAR_ARRAY_MIN 0x0000 /* lowest numbered array variable */ #define DIF_VAR_ARRAY_UBASE 0x0080 /* lowest user-defined array */ #define DIF_VAR_ARRAY_MAX 0x00ff /* highest numbered array variable */ #define DIF_VAR_OTHER_MIN 0x0100 /* lowest numbered scalar or assc */ #define DIF_VAR_OTHER_UBASE 0x0500 /* lowest user-defined scalar or assc */ #define DIF_VAR_OTHER_MAX 0xffff /* highest numbered scalar or assc */ #define DIF_VAR_ARGS 0x0000 /* arguments array */ #define DIF_VAR_REGS 0x0001 /* registers array */ #define DIF_VAR_UREGS 0x0002 /* user registers array */ #define DIF_VAR_CURTHREAD 0x0100 /* thread pointer */ #define DIF_VAR_TIMESTAMP 0x0101 /* timestamp */ #define DIF_VAR_VTIMESTAMP 0x0102 /* virtual timestamp */ #define DIF_VAR_IPL 0x0103 /* interrupt priority level */ #define DIF_VAR_EPID 0x0104 /* enabled probe ID */ #define DIF_VAR_ID 0x0105 /* probe ID */ #define DIF_VAR_ARG0 0x0106 /* first argument */ #define DIF_VAR_ARG1 0x0107 /* second argument */ #define DIF_VAR_ARG2 0x0108 /* third argument */ #define DIF_VAR_ARG3 0x0109 /* fourth argument */ #define DIF_VAR_ARG4 0x010a /* fifth argument */ #define DIF_VAR_ARG5 0x010b /* sixth argument */ #define DIF_VAR_ARG6 0x010c /* seventh argument */ #define DIF_VAR_ARG7 0x010d /* eighth argument */ #define DIF_VAR_ARG8 0x010e /* ninth argument */ #define DIF_VAR_ARG9 0x010f /* tenth argument */ #define DIF_VAR_STACKDEPTH 0x0110 /* stack depth */ #define DIF_VAR_CALLER 0x0111 /* caller */ #define DIF_VAR_PROBEPROV 0x0112 /* probe provider */ #define DIF_VAR_PROBEMOD 0x0113 /* probe module */ #define DIF_VAR_PROBEFUNC 0x0114 /* probe function */ #define DIF_VAR_PROBENAME 0x0115 /* probe name */ #define DIF_VAR_PID 0x0116 /* process ID */ #define DIF_VAR_TID 0x0117 /* (per-process) thread ID */ #define DIF_VAR_EXECNAME 0x0118 /* name of executable */ #define DIF_VAR_ZONENAME 0x0119 /* zone name associated with process */ #define DIF_VAR_WALLTIMESTAMP 0x011a /* wall-clock timestamp */ #define DIF_VAR_USTACKDEPTH 0x011b /* user-land stack depth */ #define DIF_VAR_UCALLER 0x011c /* user-level caller */ #define DIF_VAR_PPID 0x011d /* parent process ID */ #define DIF_VAR_UID 0x011e /* process user ID */ #define DIF_VAR_GID 0x011f /* process group ID */ #define DIF_VAR_ERRNO 0x0120 /* thread errno */ #define DIF_VAR_EXECARGS 0x0121 /* process arguments */ #ifndef illumos #define DIF_VAR_CPU 0x0200 #endif #define DIF_SUBR_RAND 0 #define DIF_SUBR_MUTEX_OWNED 1 #define DIF_SUBR_MUTEX_OWNER 2 #define DIF_SUBR_MUTEX_TYPE_ADAPTIVE 3 #define DIF_SUBR_MUTEX_TYPE_SPIN 4 #define DIF_SUBR_RW_READ_HELD 5 #define DIF_SUBR_RW_WRITE_HELD 6 #define DIF_SUBR_RW_ISWRITER 7 #define DIF_SUBR_COPYIN 8 #define DIF_SUBR_COPYINSTR 9 #define DIF_SUBR_SPECULATION 10 #define DIF_SUBR_PROGENYOF 11 #define DIF_SUBR_STRLEN 12 #define DIF_SUBR_COPYOUT 13 #define DIF_SUBR_COPYOUTSTR 14 #define DIF_SUBR_ALLOCA 15 #define DIF_SUBR_BCOPY 16 #define DIF_SUBR_COPYINTO 17 #define DIF_SUBR_MSGDSIZE 18 #define DIF_SUBR_MSGSIZE 19 #define DIF_SUBR_GETMAJOR 20 #define DIF_SUBR_GETMINOR 21 #define DIF_SUBR_DDI_PATHNAME 22 #define DIF_SUBR_STRJOIN 23 #define DIF_SUBR_LLTOSTR 24 #define DIF_SUBR_BASENAME 25 #define DIF_SUBR_DIRNAME 26 #define DIF_SUBR_CLEANPATH 27 #define DIF_SUBR_STRCHR 28 #define DIF_SUBR_STRRCHR 29 #define DIF_SUBR_STRSTR 30 #define DIF_SUBR_STRTOK 31 #define DIF_SUBR_SUBSTR 32 #define DIF_SUBR_INDEX 33 #define DIF_SUBR_RINDEX 34 #define DIF_SUBR_HTONS 35 #define DIF_SUBR_HTONL 36 #define DIF_SUBR_HTONLL 37 #define DIF_SUBR_NTOHS 38 #define DIF_SUBR_NTOHL 39 #define DIF_SUBR_NTOHLL 40 #define DIF_SUBR_INET_NTOP 41 #define DIF_SUBR_INET_NTOA 42 #define DIF_SUBR_INET_NTOA6 43 #define DIF_SUBR_TOUPPER 44 #define DIF_SUBR_TOLOWER 45 #define DIF_SUBR_MEMREF 46 #define DIF_SUBR_SX_SHARED_HELD 47 #define DIF_SUBR_SX_EXCLUSIVE_HELD 48 #define DIF_SUBR_SX_ISEXCLUSIVE 49 #define DIF_SUBR_MEMSTR 50 #define DIF_SUBR_GETF 51 #define DIF_SUBR_JSON 52 #define DIF_SUBR_STRTOLL 53 #define DIF_SUBR_MAX 53 /* max subroutine value */ typedef uint32_t dif_instr_t; #define DIF_INSTR_OP(i) (((i) >> 24) & 0xff) #define DIF_INSTR_R1(i) (((i) >> 16) & 0xff) #define DIF_INSTR_R2(i) (((i) >> 8) & 0xff) #define DIF_INSTR_RD(i) ((i) & 0xff) #define DIF_INSTR_RS(i) ((i) & 0xff) #define DIF_INSTR_LABEL(i) ((i) & 0xffffff) #define DIF_INSTR_VAR(i) (((i) >> 8) & 0xffff) #define DIF_INSTR_INTEGER(i) (((i) >> 8) & 0xffff) #define DIF_INSTR_STRING(i) (((i) >> 8) & 0xffff) #define DIF_INSTR_SUBR(i) (((i) >> 8) & 0xffff) #define DIF_INSTR_TYPE(i) (((i) >> 16) & 0xff) #define DIF_INSTR_XLREF(i) (((i) >> 8) & 0xffff) #define DIF_INSTR_FMT(op, r1, r2, d) \ (((op) << 24) | ((r1) << 16) | ((r2) << 8) | (d)) #define DIF_INSTR_NOT(r1, d) (DIF_INSTR_FMT(DIF_OP_NOT, r1, 0, d)) #define DIF_INSTR_MOV(r1, d) (DIF_INSTR_FMT(DIF_OP_MOV, r1, 0, d)) #define DIF_INSTR_CMP(op, r1, r2) (DIF_INSTR_FMT(op, r1, r2, 0)) #define DIF_INSTR_TST(r1) (DIF_INSTR_FMT(DIF_OP_TST, r1, 0, 0)) #define DIF_INSTR_BRANCH(op, label) (((op) << 24) | (label)) #define DIF_INSTR_LOAD(op, r1, d) (DIF_INSTR_FMT(op, r1, 0, d)) #define DIF_INSTR_STORE(op, r1, d) (DIF_INSTR_FMT(op, r1, 0, d)) #define DIF_INSTR_SETX(i, d) ((DIF_OP_SETX << 24) | ((i) << 8) | (d)) #define DIF_INSTR_SETS(s, d) ((DIF_OP_SETS << 24) | ((s) << 8) | (d)) #define DIF_INSTR_RET(d) (DIF_INSTR_FMT(DIF_OP_RET, 0, 0, d)) #define DIF_INSTR_NOP (DIF_OP_NOP << 24) #define DIF_INSTR_LDA(op, v, r, d) (DIF_INSTR_FMT(op, v, r, d)) #define DIF_INSTR_LDV(op, v, d) (((op) << 24) | ((v) << 8) | (d)) #define DIF_INSTR_STV(op, v, rs) (((op) << 24) | ((v) << 8) | (rs)) #define DIF_INSTR_CALL(s, d) ((DIF_OP_CALL << 24) | ((s) << 8) | (d)) #define DIF_INSTR_PUSHTS(op, t, r2, rs) (DIF_INSTR_FMT(op, t, r2, rs)) #define DIF_INSTR_POPTS (DIF_OP_POPTS << 24) #define DIF_INSTR_FLUSHTS (DIF_OP_FLUSHTS << 24) #define DIF_INSTR_ALLOCS(r1, d) (DIF_INSTR_FMT(DIF_OP_ALLOCS, r1, 0, d)) #define DIF_INSTR_COPYS(r1, r2, d) (DIF_INSTR_FMT(DIF_OP_COPYS, r1, r2, d)) #define DIF_INSTR_XLATE(op, r, d) (((op) << 24) | ((r) << 8) | (d)) #define DIF_REG_R0 0 /* %r0 is always set to zero */ /* * A DTrace Intermediate Format Type (DIF Type) is used to represent the types * of variables, function and associative array arguments, and the return type * for each DIF object (shown below). It contains a description of the type, * its size in bytes, and a module identifier. */ typedef struct dtrace_diftype { uint8_t dtdt_kind; /* type kind (see below) */ uint8_t dtdt_ckind; /* type kind in CTF */ uint8_t dtdt_flags; /* type flags (see below) */ uint8_t dtdt_pad; /* reserved for future use */ uint32_t dtdt_size; /* type size in bytes (unless string) */ } dtrace_diftype_t; #define DIF_TYPE_CTF 0 /* type is a CTF type */ #define DIF_TYPE_STRING 1 /* type is a D string */ #define DIF_TF_BYREF 0x1 /* type is passed by reference */ #define DIF_TF_BYUREF 0x2 /* user type is passed by reference */ /* * A DTrace Intermediate Format variable record is used to describe each of the * variables referenced by a given DIF object. It contains an integer variable * identifier along with variable scope and properties, as shown below. The * size of this structure must be sizeof (int) aligned. */ typedef struct dtrace_difv { uint32_t dtdv_name; /* variable name index in dtdo_strtab */ uint32_t dtdv_id; /* variable reference identifier */ uint8_t dtdv_kind; /* variable kind (see below) */ uint8_t dtdv_scope; /* variable scope (see below) */ uint16_t dtdv_flags; /* variable flags (see below) */ dtrace_diftype_t dtdv_type; /* variable type (see above) */ } dtrace_difv_t; #define DIFV_KIND_ARRAY 0 /* variable is an array of quantities */ #define DIFV_KIND_SCALAR 1 /* variable is a scalar quantity */ #define DIFV_SCOPE_GLOBAL 0 /* variable has global scope */ #define DIFV_SCOPE_THREAD 1 /* variable has thread scope */ #define DIFV_SCOPE_LOCAL 2 /* variable has local scope */ #define DIFV_F_REF 0x1 /* variable is referenced by DIFO */ #define DIFV_F_MOD 0x2 /* variable is written by DIFO */ /* * DTrace Actions * * The upper byte determines the class of the action; the low bytes determines * the specific action within that class. The classes of actions are as * follows: * * [ no class ] <= May record process- or kernel-related data * DTRACEACT_PROC <= Only records process-related data * DTRACEACT_PROC_DESTRUCTIVE <= Potentially destructive to processes * DTRACEACT_KERNEL <= Only records kernel-related data * DTRACEACT_KERNEL_DESTRUCTIVE <= Potentially destructive to the kernel * DTRACEACT_SPECULATIVE <= Speculation-related action * DTRACEACT_AGGREGATION <= Aggregating action */ #define DTRACEACT_NONE 0 /* no action */ #define DTRACEACT_DIFEXPR 1 /* action is DIF expression */ #define DTRACEACT_EXIT 2 /* exit() action */ #define DTRACEACT_PRINTF 3 /* printf() action */ #define DTRACEACT_PRINTA 4 /* printa() action */ #define DTRACEACT_LIBACT 5 /* library-controlled action */ #define DTRACEACT_TRACEMEM 6 /* tracemem() action */ #define DTRACEACT_TRACEMEM_DYNSIZE 7 /* dynamic tracemem() size */ #define DTRACEACT_PRINTM 8 /* printm() action (BSD) */ #define DTRACEACT_PROC 0x0100 #define DTRACEACT_USTACK (DTRACEACT_PROC + 1) #define DTRACEACT_JSTACK (DTRACEACT_PROC + 2) #define DTRACEACT_USYM (DTRACEACT_PROC + 3) #define DTRACEACT_UMOD (DTRACEACT_PROC + 4) #define DTRACEACT_UADDR (DTRACEACT_PROC + 5) #define DTRACEACT_PROC_DESTRUCTIVE 0x0200 #define DTRACEACT_STOP (DTRACEACT_PROC_DESTRUCTIVE + 1) #define DTRACEACT_RAISE (DTRACEACT_PROC_DESTRUCTIVE + 2) #define DTRACEACT_SYSTEM (DTRACEACT_PROC_DESTRUCTIVE + 3) #define DTRACEACT_FREOPEN (DTRACEACT_PROC_DESTRUCTIVE + 4) #define DTRACEACT_PROC_CONTROL 0x0300 #define DTRACEACT_KERNEL 0x0400 #define DTRACEACT_STACK (DTRACEACT_KERNEL + 1) #define DTRACEACT_SYM (DTRACEACT_KERNEL + 2) #define DTRACEACT_MOD (DTRACEACT_KERNEL + 3) #define DTRACEACT_KERNEL_DESTRUCTIVE 0x0500 #define DTRACEACT_BREAKPOINT (DTRACEACT_KERNEL_DESTRUCTIVE + 1) #define DTRACEACT_PANIC (DTRACEACT_KERNEL_DESTRUCTIVE + 2) #define DTRACEACT_CHILL (DTRACEACT_KERNEL_DESTRUCTIVE + 3) #define DTRACEACT_SPECULATIVE 0x0600 #define DTRACEACT_SPECULATE (DTRACEACT_SPECULATIVE + 1) #define DTRACEACT_COMMIT (DTRACEACT_SPECULATIVE + 2) #define DTRACEACT_DISCARD (DTRACEACT_SPECULATIVE + 3) #define DTRACEACT_CLASS(x) ((x) & 0xff00) #define DTRACEACT_ISDESTRUCTIVE(x) \ (DTRACEACT_CLASS(x) == DTRACEACT_PROC_DESTRUCTIVE || \ DTRACEACT_CLASS(x) == DTRACEACT_KERNEL_DESTRUCTIVE) #define DTRACEACT_ISSPECULATIVE(x) \ (DTRACEACT_CLASS(x) == DTRACEACT_SPECULATIVE) #define DTRACEACT_ISPRINTFLIKE(x) \ ((x) == DTRACEACT_PRINTF || (x) == DTRACEACT_PRINTA || \ (x) == DTRACEACT_SYSTEM || (x) == DTRACEACT_FREOPEN) /* * DTrace Aggregating Actions * * These are functions f(x) for which the following is true: * * f(f(x_0) U f(x_1) U ... U f(x_n)) = f(x_0 U x_1 U ... U x_n) * * where x_n is a set of arbitrary data. Aggregating actions are in their own * DTrace action class, DTTRACEACT_AGGREGATION. The macros provided here allow * for easier processing of the aggregation argument and data payload for a few * aggregating actions (notably: quantize(), lquantize(), and ustack()). */ #define DTRACEACT_AGGREGATION 0x0700 #define DTRACEAGG_COUNT (DTRACEACT_AGGREGATION + 1) #define DTRACEAGG_MIN (DTRACEACT_AGGREGATION + 2) #define DTRACEAGG_MAX (DTRACEACT_AGGREGATION + 3) #define DTRACEAGG_AVG (DTRACEACT_AGGREGATION + 4) #define DTRACEAGG_SUM (DTRACEACT_AGGREGATION + 5) #define DTRACEAGG_STDDEV (DTRACEACT_AGGREGATION + 6) #define DTRACEAGG_QUANTIZE (DTRACEACT_AGGREGATION + 7) #define DTRACEAGG_LQUANTIZE (DTRACEACT_AGGREGATION + 8) #define DTRACEAGG_LLQUANTIZE (DTRACEACT_AGGREGATION + 9) #define DTRACEACT_ISAGG(x) \ (DTRACEACT_CLASS(x) == DTRACEACT_AGGREGATION) #define DTRACE_QUANTIZE_NBUCKETS \ (((sizeof (uint64_t) * NBBY) - 1) * 2 + 1) #define DTRACE_QUANTIZE_ZEROBUCKET ((sizeof (uint64_t) * NBBY) - 1) #define DTRACE_QUANTIZE_BUCKETVAL(buck) \ (int64_t)((buck) < DTRACE_QUANTIZE_ZEROBUCKET ? \ -(1LL << (DTRACE_QUANTIZE_ZEROBUCKET - 1 - (buck))) : \ (buck) == DTRACE_QUANTIZE_ZEROBUCKET ? 0 : \ 1LL << ((buck) - DTRACE_QUANTIZE_ZEROBUCKET - 1)) #define DTRACE_LQUANTIZE_STEPSHIFT 48 #define DTRACE_LQUANTIZE_STEPMASK ((uint64_t)UINT16_MAX << 48) #define DTRACE_LQUANTIZE_LEVELSHIFT 32 #define DTRACE_LQUANTIZE_LEVELMASK ((uint64_t)UINT16_MAX << 32) #define DTRACE_LQUANTIZE_BASESHIFT 0 #define DTRACE_LQUANTIZE_BASEMASK UINT32_MAX #define DTRACE_LQUANTIZE_STEP(x) \ (uint16_t)(((x) & DTRACE_LQUANTIZE_STEPMASK) >> \ DTRACE_LQUANTIZE_STEPSHIFT) #define DTRACE_LQUANTIZE_LEVELS(x) \ (uint16_t)(((x) & DTRACE_LQUANTIZE_LEVELMASK) >> \ DTRACE_LQUANTIZE_LEVELSHIFT) #define DTRACE_LQUANTIZE_BASE(x) \ (int32_t)(((x) & DTRACE_LQUANTIZE_BASEMASK) >> \ DTRACE_LQUANTIZE_BASESHIFT) #define DTRACE_LLQUANTIZE_FACTORSHIFT 48 #define DTRACE_LLQUANTIZE_FACTORMASK ((uint64_t)UINT16_MAX << 48) #define DTRACE_LLQUANTIZE_LOWSHIFT 32 #define DTRACE_LLQUANTIZE_LOWMASK ((uint64_t)UINT16_MAX << 32) #define DTRACE_LLQUANTIZE_HIGHSHIFT 16 #define DTRACE_LLQUANTIZE_HIGHMASK ((uint64_t)UINT16_MAX << 16) #define DTRACE_LLQUANTIZE_NSTEPSHIFT 0 #define DTRACE_LLQUANTIZE_NSTEPMASK UINT16_MAX #define DTRACE_LLQUANTIZE_FACTOR(x) \ (uint16_t)(((x) & DTRACE_LLQUANTIZE_FACTORMASK) >> \ DTRACE_LLQUANTIZE_FACTORSHIFT) #define DTRACE_LLQUANTIZE_LOW(x) \ (uint16_t)(((x) & DTRACE_LLQUANTIZE_LOWMASK) >> \ DTRACE_LLQUANTIZE_LOWSHIFT) #define DTRACE_LLQUANTIZE_HIGH(x) \ (uint16_t)(((x) & DTRACE_LLQUANTIZE_HIGHMASK) >> \ DTRACE_LLQUANTIZE_HIGHSHIFT) #define DTRACE_LLQUANTIZE_NSTEP(x) \ (uint16_t)(((x) & DTRACE_LLQUANTIZE_NSTEPMASK) >> \ DTRACE_LLQUANTIZE_NSTEPSHIFT) #define DTRACE_USTACK_NFRAMES(x) (uint32_t)((x) & UINT32_MAX) #define DTRACE_USTACK_STRSIZE(x) (uint32_t)((x) >> 32) #define DTRACE_USTACK_ARG(x, y) \ ((((uint64_t)(y)) << 32) | ((x) & UINT32_MAX)) #ifndef _LP64 #if BYTE_ORDER == _BIG_ENDIAN #define DTRACE_PTR(type, name) uint32_t name##pad; type *name #else #define DTRACE_PTR(type, name) type *name; uint32_t name##pad #endif #else #define DTRACE_PTR(type, name) type *name #endif /* * DTrace Object Format (DOF) * * DTrace programs can be persistently encoded in the DOF format so that they * may be embedded in other programs (for example, in an ELF file) or in the * dtrace driver configuration file for use in anonymous tracing. The DOF * format is versioned and extensible so that it can be revised and so that * internal data structures can be modified or extended compatibly. All DOF * structures use fixed-size types, so the 32-bit and 64-bit representations * are identical and consumers can use either data model transparently. * * The file layout is structured as follows: * * +---------------+-------------------+----- ... ----+---- ... ------+ * | dof_hdr_t | dof_sec_t[ ... ] | loadable | non-loadable | * | (file header) | (section headers) | section data | section data | * +---------------+-------------------+----- ... ----+---- ... ------+ * |<------------ dof_hdr.dofh_loadsz --------------->| | * |<------------ dof_hdr.dofh_filesz ------------------------------->| * * The file header stores meta-data including a magic number, data model for * the instrumentation, data encoding, and properties of the DIF code within. * The header describes its own size and the size of the section headers. By * convention, an array of section headers follows the file header, and then * the data for all loadable sections and unloadable sections. This permits * consumer code to easily download the headers and all loadable data into the * DTrace driver in one contiguous chunk, omitting other extraneous sections. * * The section headers describe the size, offset, alignment, and section type * for each section. Sections are described using a set of #defines that tell * the consumer what kind of data is expected. Sections can contain links to * other sections by storing a dof_secidx_t, an index into the section header * array, inside of the section data structures. The section header includes * an entry size so that sections with data arrays can grow their structures. * * The DOF data itself can contain many snippets of DIF (i.e. >1 DIFOs), which * are represented themselves as a collection of related DOF sections. This * permits us to change the set of sections associated with a DIFO over time, * and also permits us to encode DIFOs that contain different sets of sections. * When a DOF section wants to refer to a DIFO, it stores the dof_secidx_t of a * section of type DOF_SECT_DIFOHDR. This section's data is then an array of * dof_secidx_t's which in turn denote the sections associated with this DIFO. * * This loose coupling of the file structure (header and sections) to the * structure of the DTrace program itself (ECB descriptions, action * descriptions, and DIFOs) permits activities such as relocation processing * to occur in a single pass without having to understand D program structure. * * Finally, strings are always stored in ELF-style string tables along with a * string table section index and string table offset. Therefore strings in * DOF are always arbitrary-length and not bound to the current implementation. */ #define DOF_ID_SIZE 16 /* total size of dofh_ident[] in bytes */ typedef struct dof_hdr { uint8_t dofh_ident[DOF_ID_SIZE]; /* identification bytes (see below) */ uint32_t dofh_flags; /* file attribute flags (if any) */ uint32_t dofh_hdrsize; /* size of file header in bytes */ uint32_t dofh_secsize; /* size of section header in bytes */ uint32_t dofh_secnum; /* number of section headers */ uint64_t dofh_secoff; /* file offset of section headers */ uint64_t dofh_loadsz; /* file size of loadable portion */ uint64_t dofh_filesz; /* file size of entire DOF file */ uint64_t dofh_pad; /* reserved for future use */ } dof_hdr_t; #define DOF_ID_MAG0 0 /* first byte of magic number */ #define DOF_ID_MAG1 1 /* second byte of magic number */ #define DOF_ID_MAG2 2 /* third byte of magic number */ #define DOF_ID_MAG3 3 /* fourth byte of magic number */ #define DOF_ID_MODEL 4 /* DOF data model (see below) */ #define DOF_ID_ENCODING 5 /* DOF data encoding (see below) */ #define DOF_ID_VERSION 6 /* DOF file format major version (see below) */ #define DOF_ID_DIFVERS 7 /* DIF instruction set version */ #define DOF_ID_DIFIREG 8 /* DIF integer registers used by compiler */ #define DOF_ID_DIFTREG 9 /* DIF tuple registers used by compiler */ #define DOF_ID_PAD 10 /* start of padding bytes (all zeroes) */ #define DOF_MAG_MAG0 0x7F /* DOF_ID_MAG[0-3] */ #define DOF_MAG_MAG1 'D' #define DOF_MAG_MAG2 'O' #define DOF_MAG_MAG3 'F' #define DOF_MAG_STRING "\177DOF" #define DOF_MAG_STRLEN 4 #define DOF_MODEL_NONE 0 /* DOF_ID_MODEL */ #define DOF_MODEL_ILP32 1 #define DOF_MODEL_LP64 2 #ifdef _LP64 #define DOF_MODEL_NATIVE DOF_MODEL_LP64 #else #define DOF_MODEL_NATIVE DOF_MODEL_ILP32 #endif #define DOF_ENCODE_NONE 0 /* DOF_ID_ENCODING */ #define DOF_ENCODE_LSB 1 #define DOF_ENCODE_MSB 2 #if BYTE_ORDER == _BIG_ENDIAN #define DOF_ENCODE_NATIVE DOF_ENCODE_MSB #else #define DOF_ENCODE_NATIVE DOF_ENCODE_LSB #endif #define DOF_VERSION_1 1 /* DOF version 1: Solaris 10 FCS */ #define DOF_VERSION_2 2 /* DOF version 2: Solaris Express 6/06 */ #define DOF_VERSION DOF_VERSION_2 /* Latest DOF version */ #define DOF_FL_VALID 0 /* mask of all valid dofh_flags bits */ typedef uint32_t dof_secidx_t; /* section header table index type */ typedef uint32_t dof_stridx_t; /* string table index type */ #define DOF_SECIDX_NONE (-1U) /* null value for section indices */ #define DOF_STRIDX_NONE (-1U) /* null value for string indices */ typedef struct dof_sec { uint32_t dofs_type; /* section type (see below) */ uint32_t dofs_align; /* section data memory alignment */ uint32_t dofs_flags; /* section flags (if any) */ uint32_t dofs_entsize; /* size of section entry (if table) */ uint64_t dofs_offset; /* offset of section data within file */ uint64_t dofs_size; /* size of section data in bytes */ } dof_sec_t; #define DOF_SECT_NONE 0 /* null section */ #define DOF_SECT_COMMENTS 1 /* compiler comments */ #define DOF_SECT_SOURCE 2 /* D program source code */ #define DOF_SECT_ECBDESC 3 /* dof_ecbdesc_t */ #define DOF_SECT_PROBEDESC 4 /* dof_probedesc_t */ #define DOF_SECT_ACTDESC 5 /* dof_actdesc_t array */ #define DOF_SECT_DIFOHDR 6 /* dof_difohdr_t (variable length) */ #define DOF_SECT_DIF 7 /* uint32_t array of byte code */ #define DOF_SECT_STRTAB 8 /* string table */ #define DOF_SECT_VARTAB 9 /* dtrace_difv_t array */ #define DOF_SECT_RELTAB 10 /* dof_relodesc_t array */ #define DOF_SECT_TYPTAB 11 /* dtrace_diftype_t array */ #define DOF_SECT_URELHDR 12 /* dof_relohdr_t (user relocations) */ #define DOF_SECT_KRELHDR 13 /* dof_relohdr_t (kernel relocations) */ #define DOF_SECT_OPTDESC 14 /* dof_optdesc_t array */ #define DOF_SECT_PROVIDER 15 /* dof_provider_t */ #define DOF_SECT_PROBES 16 /* dof_probe_t array */ #define DOF_SECT_PRARGS 17 /* uint8_t array (probe arg mappings) */ #define DOF_SECT_PROFFS 18 /* uint32_t array (probe arg offsets) */ #define DOF_SECT_INTTAB 19 /* uint64_t array */ #define DOF_SECT_UTSNAME 20 /* struct utsname */ #define DOF_SECT_XLTAB 21 /* dof_xlref_t array */ #define DOF_SECT_XLMEMBERS 22 /* dof_xlmember_t array */ #define DOF_SECT_XLIMPORT 23 /* dof_xlator_t */ #define DOF_SECT_XLEXPORT 24 /* dof_xlator_t */ #define DOF_SECT_PREXPORT 25 /* dof_secidx_t array (exported objs) */ #define DOF_SECT_PRENOFFS 26 /* uint32_t array (enabled offsets) */ #define DOF_SECF_LOAD 1 /* section should be loaded */ #define DOF_SEC_ISLOADABLE(x) \ (((x) == DOF_SECT_ECBDESC) || ((x) == DOF_SECT_PROBEDESC) || \ ((x) == DOF_SECT_ACTDESC) || ((x) == DOF_SECT_DIFOHDR) || \ ((x) == DOF_SECT_DIF) || ((x) == DOF_SECT_STRTAB) || \ ((x) == DOF_SECT_VARTAB) || ((x) == DOF_SECT_RELTAB) || \ ((x) == DOF_SECT_TYPTAB) || ((x) == DOF_SECT_URELHDR) || \ ((x) == DOF_SECT_KRELHDR) || ((x) == DOF_SECT_OPTDESC) || \ ((x) == DOF_SECT_PROVIDER) || ((x) == DOF_SECT_PROBES) || \ ((x) == DOF_SECT_PRARGS) || ((x) == DOF_SECT_PROFFS) || \ ((x) == DOF_SECT_INTTAB) || ((x) == DOF_SECT_XLTAB) || \ ((x) == DOF_SECT_XLMEMBERS) || ((x) == DOF_SECT_XLIMPORT) || \ ((x) == DOF_SECT_XLEXPORT) || ((x) == DOF_SECT_PREXPORT) || \ ((x) == DOF_SECT_PRENOFFS)) typedef struct dof_ecbdesc { dof_secidx_t dofe_probes; /* link to DOF_SECT_PROBEDESC */ dof_secidx_t dofe_pred; /* link to DOF_SECT_DIFOHDR */ dof_secidx_t dofe_actions; /* link to DOF_SECT_ACTDESC */ uint32_t dofe_pad; /* reserved for future use */ uint64_t dofe_uarg; /* user-supplied library argument */ } dof_ecbdesc_t; typedef struct dof_probedesc { dof_secidx_t dofp_strtab; /* link to DOF_SECT_STRTAB section */ dof_stridx_t dofp_provider; /* provider string */ dof_stridx_t dofp_mod; /* module string */ dof_stridx_t dofp_func; /* function string */ dof_stridx_t dofp_name; /* name string */ uint32_t dofp_id; /* probe identifier (or zero) */ } dof_probedesc_t; typedef struct dof_actdesc { dof_secidx_t dofa_difo; /* link to DOF_SECT_DIFOHDR */ dof_secidx_t dofa_strtab; /* link to DOF_SECT_STRTAB section */ uint32_t dofa_kind; /* action kind (DTRACEACT_* constant) */ uint32_t dofa_ntuple; /* number of subsequent tuple actions */ uint64_t dofa_arg; /* kind-specific argument */ uint64_t dofa_uarg; /* user-supplied argument */ } dof_actdesc_t; typedef struct dof_difohdr { dtrace_diftype_t dofd_rtype; /* return type for this fragment */ dof_secidx_t dofd_links[1]; /* variable length array of indices */ } dof_difohdr_t; typedef struct dof_relohdr { dof_secidx_t dofr_strtab; /* link to DOF_SECT_STRTAB for names */ dof_secidx_t dofr_relsec; /* link to DOF_SECT_RELTAB for relos */ dof_secidx_t dofr_tgtsec; /* link to section we are relocating */ } dof_relohdr_t; typedef struct dof_relodesc { dof_stridx_t dofr_name; /* string name of relocation symbol */ uint32_t dofr_type; /* relo type (DOF_RELO_* constant) */ uint64_t dofr_offset; /* byte offset for relocation */ uint64_t dofr_data; /* additional type-specific data */ } dof_relodesc_t; #define DOF_RELO_NONE 0 /* empty relocation entry */ #define DOF_RELO_SETX 1 /* relocate setx value */ +#define DOF_RELO_DOFREL 2 /* relocate DOF-relative value */ typedef struct dof_optdesc { uint32_t dofo_option; /* option identifier */ dof_secidx_t dofo_strtab; /* string table, if string option */ uint64_t dofo_value; /* option value or string index */ } dof_optdesc_t; typedef uint32_t dof_attr_t; /* encoded stability attributes */ #define DOF_ATTR(n, d, c) (((n) << 24) | ((d) << 16) | ((c) << 8)) #define DOF_ATTR_NAME(a) (((a) >> 24) & 0xff) #define DOF_ATTR_DATA(a) (((a) >> 16) & 0xff) #define DOF_ATTR_CLASS(a) (((a) >> 8) & 0xff) typedef struct dof_provider { dof_secidx_t dofpv_strtab; /* link to DOF_SECT_STRTAB section */ dof_secidx_t dofpv_probes; /* link to DOF_SECT_PROBES section */ dof_secidx_t dofpv_prargs; /* link to DOF_SECT_PRARGS section */ dof_secidx_t dofpv_proffs; /* link to DOF_SECT_PROFFS section */ dof_stridx_t dofpv_name; /* provider name string */ dof_attr_t dofpv_provattr; /* provider attributes */ dof_attr_t dofpv_modattr; /* module attributes */ dof_attr_t dofpv_funcattr; /* function attributes */ dof_attr_t dofpv_nameattr; /* name attributes */ dof_attr_t dofpv_argsattr; /* args attributes */ dof_secidx_t dofpv_prenoffs; /* link to DOF_SECT_PRENOFFS section */ } dof_provider_t; typedef struct dof_probe { uint64_t dofpr_addr; /* probe base address or offset */ dof_stridx_t dofpr_func; /* probe function string */ dof_stridx_t dofpr_name; /* probe name string */ dof_stridx_t dofpr_nargv; /* native argument type strings */ dof_stridx_t dofpr_xargv; /* translated argument type strings */ uint32_t dofpr_argidx; /* index of first argument mapping */ uint32_t dofpr_offidx; /* index of first offset entry */ uint8_t dofpr_nargc; /* native argument count */ uint8_t dofpr_xargc; /* translated argument count */ uint16_t dofpr_noffs; /* number of offset entries for probe */ uint32_t dofpr_enoffidx; /* index of first is-enabled offset */ uint16_t dofpr_nenoffs; /* number of is-enabled offsets */ uint16_t dofpr_pad1; /* reserved for future use */ uint32_t dofpr_pad2; /* reserved for future use */ } dof_probe_t; typedef struct dof_xlator { dof_secidx_t dofxl_members; /* link to DOF_SECT_XLMEMBERS section */ dof_secidx_t dofxl_strtab; /* link to DOF_SECT_STRTAB section */ dof_stridx_t dofxl_argv; /* input parameter type strings */ uint32_t dofxl_argc; /* input parameter list length */ dof_stridx_t dofxl_type; /* output type string name */ dof_attr_t dofxl_attr; /* output stability attributes */ } dof_xlator_t; typedef struct dof_xlmember { dof_secidx_t dofxm_difo; /* member link to DOF_SECT_DIFOHDR */ dof_stridx_t dofxm_name; /* member name */ dtrace_diftype_t dofxm_type; /* member type */ } dof_xlmember_t; typedef struct dof_xlref { dof_secidx_t dofxr_xlator; /* link to DOF_SECT_XLATORS section */ uint32_t dofxr_member; /* index of referenced dof_xlmember */ uint32_t dofxr_argn; /* index of argument for DIF_OP_XLARG */ } dof_xlref_t; /* * DTrace Intermediate Format Object (DIFO) * * A DIFO is used to store the compiled DIF for a D expression, its return * type, and its string and variable tables. The string table is a single * buffer of character data into which sets instructions and variable * references can reference strings using a byte offset. The variable table * is an array of dtrace_difv_t structures that describe the name and type of * each variable and the id used in the DIF code. This structure is described * above in the DIF section of this header file. The DIFO is used at both * user-level (in the library) and in the kernel, but the structure is never * passed between the two: the DOF structures form the only interface. As a * result, the definition can change depending on the presence of _KERNEL. */ typedef struct dtrace_difo { dif_instr_t *dtdo_buf; /* instruction buffer */ uint64_t *dtdo_inttab; /* integer table (optional) */ char *dtdo_strtab; /* string table (optional) */ dtrace_difv_t *dtdo_vartab; /* variable table (optional) */ uint_t dtdo_len; /* length of instruction buffer */ uint_t dtdo_intlen; /* length of integer table */ uint_t dtdo_strlen; /* length of string table */ uint_t dtdo_varlen; /* length of variable table */ dtrace_diftype_t dtdo_rtype; /* return type */ uint_t dtdo_refcnt; /* owner reference count */ uint_t dtdo_destructive; /* invokes destructive subroutines */ #ifndef _KERNEL dof_relodesc_t *dtdo_kreltab; /* kernel relocations */ dof_relodesc_t *dtdo_ureltab; /* user relocations */ struct dt_node **dtdo_xlmtab; /* translator references */ uint_t dtdo_krelen; /* length of krelo table */ uint_t dtdo_urelen; /* length of urelo table */ uint_t dtdo_xlmlen; /* length of translator table */ #endif } dtrace_difo_t; /* * DTrace Enabling Description Structures * * When DTrace is tracking the description of a DTrace enabling entity (probe, * predicate, action, ECB, record, etc.), it does so in a description * structure. These structures all end in "desc", and are used at both * user-level and in the kernel -- but (with the exception of * dtrace_probedesc_t) they are never passed between them. Typically, * user-level will use the description structures when assembling an enabling. * It will then distill those description structures into a DOF object (see * above), and send it into the kernel. The kernel will again use the * description structures to create a description of the enabling as it reads * the DOF. When the description is complete, the enabling will be actually * created -- turning it into the structures that represent the enabling * instead of merely describing it. Not surprisingly, the description * structures bear a strong resemblance to the DOF structures that act as their * conduit. */ struct dtrace_predicate; typedef struct dtrace_probedesc { dtrace_id_t dtpd_id; /* probe identifier */ char dtpd_provider[DTRACE_PROVNAMELEN]; /* probe provider name */ char dtpd_mod[DTRACE_MODNAMELEN]; /* probe module name */ char dtpd_func[DTRACE_FUNCNAMELEN]; /* probe function name */ char dtpd_name[DTRACE_NAMELEN]; /* probe name */ } dtrace_probedesc_t; typedef struct dtrace_repldesc { dtrace_probedesc_t dtrpd_match; /* probe descr. to match */ dtrace_probedesc_t dtrpd_create; /* probe descr. to create */ } dtrace_repldesc_t; typedef struct dtrace_preddesc { dtrace_difo_t *dtpdd_difo; /* pointer to DIF object */ struct dtrace_predicate *dtpdd_predicate; /* pointer to predicate */ } dtrace_preddesc_t; typedef struct dtrace_actdesc { dtrace_difo_t *dtad_difo; /* pointer to DIF object */ struct dtrace_actdesc *dtad_next; /* next action */ dtrace_actkind_t dtad_kind; /* kind of action */ uint32_t dtad_ntuple; /* number in tuple */ uint64_t dtad_arg; /* action argument */ uint64_t dtad_uarg; /* user argument */ int dtad_refcnt; /* reference count */ } dtrace_actdesc_t; typedef struct dtrace_ecbdesc { dtrace_actdesc_t *dted_action; /* action description(s) */ dtrace_preddesc_t dted_pred; /* predicate description */ dtrace_probedesc_t dted_probe; /* probe description */ uint64_t dted_uarg; /* library argument */ int dted_refcnt; /* reference count */ } dtrace_ecbdesc_t; /* * DTrace Metadata Description Structures * * DTrace separates the trace data stream from the metadata stream. The only * metadata tokens placed in the data stream are the dtrace_rechdr_t (EPID + * timestamp) or (in the case of aggregations) aggregation identifiers. To * determine the structure of the data, DTrace consumers pass the token to the * kernel, and receive in return a corresponding description of the enabled * probe (via the dtrace_eprobedesc structure) or the aggregation (via the * dtrace_aggdesc structure). Both of these structures are expressed in terms * of record descriptions (via the dtrace_recdesc structure) that describe the * exact structure of the data. Some record descriptions may also contain a * format identifier; this additional bit of metadata can be retrieved from the * kernel, for which a format description is returned via the dtrace_fmtdesc * structure. Note that all four of these structures must be bitness-neutral * to allow for a 32-bit DTrace consumer on a 64-bit kernel. */ typedef struct dtrace_recdesc { dtrace_actkind_t dtrd_action; /* kind of action */ uint32_t dtrd_size; /* size of record */ uint32_t dtrd_offset; /* offset in ECB's data */ uint16_t dtrd_alignment; /* required alignment */ uint16_t dtrd_format; /* format, if any */ uint64_t dtrd_arg; /* action argument */ uint64_t dtrd_uarg; /* user argument */ } dtrace_recdesc_t; typedef struct dtrace_eprobedesc { dtrace_epid_t dtepd_epid; /* enabled probe ID */ dtrace_id_t dtepd_probeid; /* probe ID */ uint64_t dtepd_uarg; /* library argument */ uint32_t dtepd_size; /* total size */ int dtepd_nrecs; /* number of records */ dtrace_recdesc_t dtepd_rec[1]; /* records themselves */ } dtrace_eprobedesc_t; typedef struct dtrace_aggdesc { DTRACE_PTR(char, dtagd_name); /* not filled in by kernel */ dtrace_aggvarid_t dtagd_varid; /* not filled in by kernel */ int dtagd_flags; /* not filled in by kernel */ dtrace_aggid_t dtagd_id; /* aggregation ID */ dtrace_epid_t dtagd_epid; /* enabled probe ID */ uint32_t dtagd_size; /* size in bytes */ int dtagd_nrecs; /* number of records */ uint32_t dtagd_pad; /* explicit padding */ dtrace_recdesc_t dtagd_rec[1]; /* record descriptions */ } dtrace_aggdesc_t; typedef struct dtrace_fmtdesc { DTRACE_PTR(char, dtfd_string); /* format string */ int dtfd_length; /* length of format string */ uint16_t dtfd_format; /* format identifier */ } dtrace_fmtdesc_t; #define DTRACE_SIZEOF_EPROBEDESC(desc) \ (sizeof (dtrace_eprobedesc_t) + ((desc)->dtepd_nrecs ? \ (((desc)->dtepd_nrecs - 1) * sizeof (dtrace_recdesc_t)) : 0)) #define DTRACE_SIZEOF_AGGDESC(desc) \ (sizeof (dtrace_aggdesc_t) + ((desc)->dtagd_nrecs ? \ (((desc)->dtagd_nrecs - 1) * sizeof (dtrace_recdesc_t)) : 0)) /* * DTrace Option Interface * * Run-time DTrace options are set and retrieved via DOF_SECT_OPTDESC sections * in a DOF image. The dof_optdesc structure contains an option identifier and * an option value. The valid option identifiers are found below; the mapping * between option identifiers and option identifying strings is maintained at * user-level. Note that the value of DTRACEOPT_UNSET is such that all of the * following are potentially valid option values: all positive integers, zero * and negative one. Some options (notably "bufpolicy" and "bufresize") take * predefined tokens as their values; these are defined with * DTRACEOPT_{option}_{token}. */ #define DTRACEOPT_BUFSIZE 0 /* buffer size */ #define DTRACEOPT_BUFPOLICY 1 /* buffer policy */ #define DTRACEOPT_DYNVARSIZE 2 /* dynamic variable size */ #define DTRACEOPT_AGGSIZE 3 /* aggregation size */ #define DTRACEOPT_SPECSIZE 4 /* speculation size */ #define DTRACEOPT_NSPEC 5 /* number of speculations */ #define DTRACEOPT_STRSIZE 6 /* string size */ #define DTRACEOPT_CLEANRATE 7 /* dynvar cleaning rate */ #define DTRACEOPT_CPU 8 /* CPU to trace */ #define DTRACEOPT_BUFRESIZE 9 /* buffer resizing policy */ #define DTRACEOPT_GRABANON 10 /* grab anonymous state, if any */ #define DTRACEOPT_FLOWINDENT 11 /* indent function entry/return */ #define DTRACEOPT_QUIET 12 /* only output explicitly traced data */ #define DTRACEOPT_STACKFRAMES 13 /* number of stack frames */ #define DTRACEOPT_USTACKFRAMES 14 /* number of user stack frames */ #define DTRACEOPT_AGGRATE 15 /* aggregation snapshot rate */ #define DTRACEOPT_SWITCHRATE 16 /* buffer switching rate */ #define DTRACEOPT_STATUSRATE 17 /* status rate */ #define DTRACEOPT_DESTRUCTIVE 18 /* destructive actions allowed */ #define DTRACEOPT_STACKINDENT 19 /* output indent for stack traces */ #define DTRACEOPT_RAWBYTES 20 /* always print bytes in raw form */ #define DTRACEOPT_JSTACKFRAMES 21 /* number of jstack() frames */ #define DTRACEOPT_JSTACKSTRSIZE 22 /* size of jstack() string table */ #define DTRACEOPT_AGGSORTKEY 23 /* sort aggregations by key */ #define DTRACEOPT_AGGSORTREV 24 /* reverse-sort aggregations */ #define DTRACEOPT_AGGSORTPOS 25 /* agg. position to sort on */ #define DTRACEOPT_AGGSORTKEYPOS 26 /* agg. key position to sort on */ #define DTRACEOPT_TEMPORAL 27 /* temporally ordered output */ #define DTRACEOPT_AGGHIST 28 /* histogram aggregation output */ #define DTRACEOPT_AGGPACK 29 /* packed aggregation output */ #define DTRACEOPT_AGGZOOM 30 /* zoomed aggregation scaling */ #define DTRACEOPT_ZONE 31 /* zone in which to enable probes */ #define DTRACEOPT_MAX 32 /* number of options */ #define DTRACEOPT_UNSET (dtrace_optval_t)-2 /* unset option */ #define DTRACEOPT_BUFPOLICY_RING 0 /* ring buffer */ #define DTRACEOPT_BUFPOLICY_FILL 1 /* fill buffer, then stop */ #define DTRACEOPT_BUFPOLICY_SWITCH 2 /* switch buffers */ #define DTRACEOPT_BUFRESIZE_AUTO 0 /* automatic resizing */ #define DTRACEOPT_BUFRESIZE_MANUAL 1 /* manual resizing */ /* * DTrace Buffer Interface * * In order to get a snapshot of the principal or aggregation buffer, * user-level passes a buffer description to the kernel with the dtrace_bufdesc * structure. This describes which CPU user-level is interested in, and * where user-level wishes the kernel to snapshot the buffer to (the * dtbd_data field). The kernel uses the same structure to pass back some * information regarding the buffer: the size of data actually copied out, the * number of drops, the number of errors, the offset of the oldest record, * and the time of the snapshot. * * If the buffer policy is a "switch" policy, taking a snapshot of the * principal buffer has the additional effect of switching the active and * inactive buffers. Taking a snapshot of the aggregation buffer _always_ has * the additional effect of switching the active and inactive buffers. */ typedef struct dtrace_bufdesc { uint64_t dtbd_size; /* size of buffer */ uint32_t dtbd_cpu; /* CPU or DTRACE_CPUALL */ uint32_t dtbd_errors; /* number of errors */ uint64_t dtbd_drops; /* number of drops */ DTRACE_PTR(char, dtbd_data); /* data */ uint64_t dtbd_oldest; /* offset of oldest record */ uint64_t dtbd_timestamp; /* hrtime of snapshot */ } dtrace_bufdesc_t; /* * Each record in the buffer (dtbd_data) begins with a header that includes * the epid and a timestamp. The timestamp is split into two 4-byte parts * so that we do not require 8-byte alignment. */ typedef struct dtrace_rechdr { dtrace_epid_t dtrh_epid; /* enabled probe id */ uint32_t dtrh_timestamp_hi; /* high bits of hrtime_t */ uint32_t dtrh_timestamp_lo; /* low bits of hrtime_t */ } dtrace_rechdr_t; #define DTRACE_RECORD_LOAD_TIMESTAMP(dtrh) \ ((dtrh)->dtrh_timestamp_lo + \ ((uint64_t)(dtrh)->dtrh_timestamp_hi << 32)) #define DTRACE_RECORD_STORE_TIMESTAMP(dtrh, hrtime) { \ (dtrh)->dtrh_timestamp_lo = (uint32_t)hrtime; \ (dtrh)->dtrh_timestamp_hi = hrtime >> 32; \ } /* * DTrace Status * * The status of DTrace is relayed via the dtrace_status structure. This * structure contains members to count drops other than the capacity drops * available via the buffer interface (see above). This consists of dynamic * drops (including capacity dynamic drops, rinsing drops and dirty drops), and * speculative drops (including capacity speculative drops, drops due to busy * speculative buffers and drops due to unavailable speculative buffers). * Additionally, the status structure contains a field to indicate the number * of "fill"-policy buffers have been filled and a boolean field to indicate * that exit() has been called. If the dtst_exiting field is non-zero, no * further data will be generated until tracing is stopped (at which time any * enablings of the END action will be processed); if user-level sees that * this field is non-zero, tracing should be stopped as soon as possible. */ typedef struct dtrace_status { uint64_t dtst_dyndrops; /* dynamic drops */ uint64_t dtst_dyndrops_rinsing; /* dyn drops due to rinsing */ uint64_t dtst_dyndrops_dirty; /* dyn drops due to dirty */ uint64_t dtst_specdrops; /* speculative drops */ uint64_t dtst_specdrops_busy; /* spec drops due to busy */ uint64_t dtst_specdrops_unavail; /* spec drops due to unavail */ uint64_t dtst_errors; /* total errors */ uint64_t dtst_filled; /* number of filled bufs */ uint64_t dtst_stkstroverflows; /* stack string tab overflows */ uint64_t dtst_dblerrors; /* errors in ERROR probes */ char dtst_killed; /* non-zero if killed */ char dtst_exiting; /* non-zero if exit() called */ char dtst_pad[6]; /* pad out to 64-bit align */ } dtrace_status_t; /* * DTrace Configuration * * User-level may need to understand some elements of the kernel DTrace * configuration in order to generate correct DIF. This information is * conveyed via the dtrace_conf structure. */ typedef struct dtrace_conf { uint_t dtc_difversion; /* supported DIF version */ uint_t dtc_difintregs; /* # of DIF integer registers */ uint_t dtc_diftupregs; /* # of DIF tuple registers */ uint_t dtc_ctfmodel; /* CTF data model */ uint_t dtc_pad[8]; /* reserved for future use */ } dtrace_conf_t; /* * DTrace Faults * * The constants below DTRACEFLT_LIBRARY indicate probe processing faults; * constants at or above DTRACEFLT_LIBRARY indicate faults in probe * postprocessing at user-level. Probe processing faults induce an ERROR * probe and are replicated in unistd.d to allow users' ERROR probes to decode * the error condition using thse symbolic labels. */ #define DTRACEFLT_UNKNOWN 0 /* Unknown fault */ #define DTRACEFLT_BADADDR 1 /* Bad address */ #define DTRACEFLT_BADALIGN 2 /* Bad alignment */ #define DTRACEFLT_ILLOP 3 /* Illegal operation */ #define DTRACEFLT_DIVZERO 4 /* Divide-by-zero */ #define DTRACEFLT_NOSCRATCH 5 /* Out of scratch space */ #define DTRACEFLT_KPRIV 6 /* Illegal kernel access */ #define DTRACEFLT_UPRIV 7 /* Illegal user access */ #define DTRACEFLT_TUPOFLOW 8 /* Tuple stack overflow */ #define DTRACEFLT_BADSTACK 9 /* Bad stack */ #define DTRACEFLT_LIBRARY 1000 /* Library-level fault */ /* * DTrace Argument Types * * Because it would waste both space and time, argument types do not reside * with the probe. In order to determine argument types for args[X] * variables, the D compiler queries for argument types on a probe-by-probe * basis. (This optimizes for the common case that arguments are either not * used or used in an untyped fashion.) Typed arguments are specified with a * string of the type name in the dtragd_native member of the argument * description structure. Typed arguments may be further translated to types * of greater stability; the provider indicates such a translated argument by * filling in the dtargd_xlate member with the string of the translated type. * Finally, the provider may indicate which argument value a given argument * maps to by setting the dtargd_mapping member -- allowing a single argument * to map to multiple args[X] variables. */ typedef struct dtrace_argdesc { dtrace_id_t dtargd_id; /* probe identifier */ int dtargd_ndx; /* arg number (-1 iff none) */ int dtargd_mapping; /* value mapping */ char dtargd_native[DTRACE_ARGTYPELEN]; /* native type name */ char dtargd_xlate[DTRACE_ARGTYPELEN]; /* translated type name */ } dtrace_argdesc_t; /* * DTrace Stability Attributes * * Each DTrace provider advertises the name and data stability of each of its * probe description components, as well as its architectural dependencies. * The D compiler can query the provider attributes (dtrace_pattr_t below) in * order to compute the properties of an input program and report them. */ typedef uint8_t dtrace_stability_t; /* stability code (see attributes(5)) */ typedef uint8_t dtrace_class_t; /* architectural dependency class */ #define DTRACE_STABILITY_INTERNAL 0 /* private to DTrace itself */ #define DTRACE_STABILITY_PRIVATE 1 /* private to Sun (see docs) */ #define DTRACE_STABILITY_OBSOLETE 2 /* scheduled for removal */ #define DTRACE_STABILITY_EXTERNAL 3 /* not controlled by Sun */ #define DTRACE_STABILITY_UNSTABLE 4 /* new or rapidly changing */ #define DTRACE_STABILITY_EVOLVING 5 /* less rapidly changing */ #define DTRACE_STABILITY_STABLE 6 /* mature interface from Sun */ #define DTRACE_STABILITY_STANDARD 7 /* industry standard */ #define DTRACE_STABILITY_MAX 7 /* maximum valid stability */ #define DTRACE_CLASS_UNKNOWN 0 /* unknown architectural dependency */ #define DTRACE_CLASS_CPU 1 /* CPU-module-specific */ #define DTRACE_CLASS_PLATFORM 2 /* platform-specific (uname -i) */ #define DTRACE_CLASS_GROUP 3 /* hardware-group-specific (uname -m) */ #define DTRACE_CLASS_ISA 4 /* ISA-specific (uname -p) */ #define DTRACE_CLASS_COMMON 5 /* common to all systems */ #define DTRACE_CLASS_MAX 5 /* maximum valid class */ #define DTRACE_PRIV_NONE 0x0000 #define DTRACE_PRIV_KERNEL 0x0001 #define DTRACE_PRIV_USER 0x0002 #define DTRACE_PRIV_PROC 0x0004 #define DTRACE_PRIV_OWNER 0x0008 #define DTRACE_PRIV_ZONEOWNER 0x0010 #define DTRACE_PRIV_ALL \ (DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER | \ DTRACE_PRIV_PROC | DTRACE_PRIV_OWNER | DTRACE_PRIV_ZONEOWNER) typedef struct dtrace_ppriv { uint32_t dtpp_flags; /* privilege flags */ uid_t dtpp_uid; /* user ID */ zoneid_t dtpp_zoneid; /* zone ID */ } dtrace_ppriv_t; typedef struct dtrace_attribute { dtrace_stability_t dtat_name; /* entity name stability */ dtrace_stability_t dtat_data; /* entity data stability */ dtrace_class_t dtat_class; /* entity data dependency */ } dtrace_attribute_t; typedef struct dtrace_pattr { dtrace_attribute_t dtpa_provider; /* provider attributes */ dtrace_attribute_t dtpa_mod; /* module attributes */ dtrace_attribute_t dtpa_func; /* function attributes */ dtrace_attribute_t dtpa_name; /* name attributes */ dtrace_attribute_t dtpa_args; /* args[] attributes */ } dtrace_pattr_t; typedef struct dtrace_providerdesc { char dtvd_name[DTRACE_PROVNAMELEN]; /* provider name */ dtrace_pattr_t dtvd_attr; /* stability attributes */ dtrace_ppriv_t dtvd_priv; /* privileges required */ } dtrace_providerdesc_t; /* * DTrace Pseudodevice Interface * * DTrace is controlled through ioctl(2)'s to the in-kernel dtrace:dtrace * pseudodevice driver. These ioctls comprise the user-kernel interface to * DTrace. */ #ifdef illumos #define DTRACEIOC (('d' << 24) | ('t' << 16) | ('r' << 8)) #define DTRACEIOC_PROVIDER (DTRACEIOC | 1) /* provider query */ #define DTRACEIOC_PROBES (DTRACEIOC | 2) /* probe query */ #define DTRACEIOC_BUFSNAP (DTRACEIOC | 4) /* snapshot buffer */ #define DTRACEIOC_PROBEMATCH (DTRACEIOC | 5) /* match probes */ #define DTRACEIOC_ENABLE (DTRACEIOC | 6) /* enable probes */ #define DTRACEIOC_AGGSNAP (DTRACEIOC | 7) /* snapshot agg. */ #define DTRACEIOC_EPROBE (DTRACEIOC | 8) /* get eprobe desc. */ #define DTRACEIOC_PROBEARG (DTRACEIOC | 9) /* get probe arg */ #define DTRACEIOC_CONF (DTRACEIOC | 10) /* get config. */ #define DTRACEIOC_STATUS (DTRACEIOC | 11) /* get status */ #define DTRACEIOC_GO (DTRACEIOC | 12) /* start tracing */ #define DTRACEIOC_STOP (DTRACEIOC | 13) /* stop tracing */ #define DTRACEIOC_AGGDESC (DTRACEIOC | 15) /* get agg. desc. */ #define DTRACEIOC_FORMAT (DTRACEIOC | 16) /* get format str */ #define DTRACEIOC_DOFGET (DTRACEIOC | 17) /* get DOF */ #define DTRACEIOC_REPLICATE (DTRACEIOC | 18) /* replicate enab */ #else #define DTRACEIOC_PROVIDER _IOWR('x',1,dtrace_providerdesc_t) /* provider query */ #define DTRACEIOC_PROBES _IOWR('x',2,dtrace_probedesc_t) /* probe query */ #define DTRACEIOC_BUFSNAP _IOW('x',4,dtrace_bufdesc_t *) /* snapshot buffer */ #define DTRACEIOC_PROBEMATCH _IOWR('x',5,dtrace_probedesc_t) /* match probes */ typedef struct { void *dof; /* DOF userland address written to driver. */ int n_matched; /* # matches returned by driver. */ } dtrace_enable_io_t; #define DTRACEIOC_ENABLE _IOWR('x',6,dtrace_enable_io_t) /* enable probes */ #define DTRACEIOC_AGGSNAP _IOW('x',7,dtrace_bufdesc_t *) /* snapshot agg. */ #define DTRACEIOC_EPROBE _IOW('x',8,dtrace_eprobedesc_t) /* get eprobe desc. */ #define DTRACEIOC_PROBEARG _IOWR('x',9,dtrace_argdesc_t) /* get probe arg */ #define DTRACEIOC_CONF _IOR('x',10,dtrace_conf_t) /* get config. */ #define DTRACEIOC_STATUS _IOR('x',11,dtrace_status_t) /* get status */ #define DTRACEIOC_GO _IOR('x',12,processorid_t) /* start tracing */ #define DTRACEIOC_STOP _IOWR('x',13,processorid_t) /* stop tracing */ #define DTRACEIOC_AGGDESC _IOW('x',15,dtrace_aggdesc_t *) /* get agg. desc. */ #define DTRACEIOC_FORMAT _IOWR('x',16,dtrace_fmtdesc_t) /* get format str */ #define DTRACEIOC_DOFGET _IOW('x',17,dof_hdr_t *) /* get DOF */ #define DTRACEIOC_REPLICATE _IOW('x',18,dtrace_repldesc_t) /* replicate enab */ #endif /* * DTrace Helpers * * In general, DTrace establishes probes in processes and takes actions on * processes without knowing their specific user-level structures. Instead of * existing in the framework, process-specific knowledge is contained by the * enabling D program -- which can apply process-specific knowledge by making * appropriate use of DTrace primitives like copyin() and copyinstr() to * operate on user-level data. However, there may exist some specific probes * of particular semantic relevance that the application developer may wish to * explicitly export. For example, an application may wish to export a probe * at the point that it begins and ends certain well-defined transactions. In * addition to providing probes, programs may wish to offer assistance for * certain actions. For example, in highly dynamic environments (e.g., Java), * it may be difficult to obtain a stack trace in terms of meaningful symbol * names (the translation from instruction addresses to corresponding symbol * names may only be possible in situ); these environments may wish to define * a series of actions to be applied in situ to obtain a meaningful stack * trace. * * These two mechanisms -- user-level statically defined tracing and assisting * DTrace actions -- are provided via DTrace _helpers_. Helpers are specified * via DOF, but unlike enabling DOF, helper DOF may contain definitions of * providers, probes and their arguments. If a helper wishes to provide * action assistance, probe descriptions and corresponding DIF actions may be * specified in the helper DOF. For such helper actions, however, the probe * description describes the specific helper: all DTrace helpers have the * provider name "dtrace" and the module name "helper", and the name of the * helper is contained in the function name (for example, the ustack() helper * is named "ustack"). Any helper-specific name may be contained in the name * (for example, if a helper were to have a constructor, it might be named * "dtrace:helper::init"). Helper actions are only called when the * action that they are helping is taken. Helper actions may only return DIF * expressions, and may only call the following subroutines: * * alloca() <= Allocates memory out of the consumer's scratch space * bcopy() <= Copies memory to scratch space * copyin() <= Copies memory from user-level into consumer's scratch * copyinto() <= Copies memory into a specific location in scratch * copyinstr() <= Copies a string into a specific location in scratch * * Helper actions may only access the following built-in variables: * * curthread <= Current kthread_t pointer * tid <= Current thread identifier * pid <= Current process identifier * ppid <= Parent process identifier * uid <= Current user ID * gid <= Current group ID * execname <= Current executable name * zonename <= Current zone name * * Helper actions may not manipulate or allocate dynamic variables, but they * may have clause-local and statically-allocated global variables. The * helper action variable state is specific to the helper action -- variables * used by the helper action may not be accessed outside of the helper * action, and the helper action may not access variables that like outside * of it. Helper actions may not load from kernel memory at-large; they are * restricting to loading current user state (via copyin() and variants) and * scratch space. As with probe enablings, helper actions are executed in * program order. The result of the helper action is the result of the last * executing helper expression. * * Helpers -- composed of either providers/probes or probes/actions (or both) * -- are added by opening the "helper" minor node, and issuing an ioctl(2) * (DTRACEHIOC_ADDDOF) that specifies the dof_helper_t structure. This * encapsulates the name and base address of the user-level library or * executable publishing the helpers and probes as well as the DOF that * contains the definitions of those helpers and probes. * * The DTRACEHIOC_ADD and DTRACEHIOC_REMOVE are left in place for legacy * helpers and should no longer be used. No other ioctls are valid on the * helper minor node. */ #ifdef illumos #define DTRACEHIOC (('d' << 24) | ('t' << 16) | ('h' << 8)) #define DTRACEHIOC_ADD (DTRACEHIOC | 1) /* add helper */ #define DTRACEHIOC_REMOVE (DTRACEHIOC | 2) /* remove helper */ #define DTRACEHIOC_ADDDOF (DTRACEHIOC | 3) /* add helper DOF */ #else #define DTRACEHIOC_REMOVE _IOW('z', 2, int) /* remove helper */ #define DTRACEHIOC_ADDDOF _IOWR('z', 3, dof_helper_t)/* add helper DOF */ #endif typedef struct dof_helper { char dofhp_mod[DTRACE_MODNAMELEN]; /* executable or library name */ uint64_t dofhp_addr; /* base address of object */ uint64_t dofhp_dof; /* address of helper DOF */ #ifdef __FreeBSD__ pid_t dofhp_pid; /* target process ID */ int dofhp_gen; #endif } dof_helper_t; #define DTRACEMNR_DTRACE "dtrace" /* node for DTrace ops */ #define DTRACEMNR_HELPER "helper" /* node for helpers */ #define DTRACEMNRN_DTRACE 0 /* minor for DTrace ops */ #define DTRACEMNRN_HELPER 1 /* minor for helpers */ #define DTRACEMNRN_CLONE 2 /* first clone minor */ #ifdef _KERNEL /* * DTrace Provider API * * The following functions are implemented by the DTrace framework and are * used to implement separate in-kernel DTrace providers. Common functions * are provided in uts/common/os/dtrace.c. ISA-dependent subroutines are * defined in uts//dtrace/dtrace_asm.s or uts//dtrace/dtrace_isa.c. * * The provider API has two halves: the API that the providers consume from * DTrace, and the API that providers make available to DTrace. * * 1 Framework-to-Provider API * * 1.1 Overview * * The Framework-to-Provider API is represented by the dtrace_pops structure * that the provider passes to the framework when registering itself. This * structure consists of the following members: * * dtps_provide() <-- Provide all probes, all modules * dtps_provide_module() <-- Provide all probes in specified module * dtps_enable() <-- Enable specified probe * dtps_disable() <-- Disable specified probe * dtps_suspend() <-- Suspend specified probe * dtps_resume() <-- Resume specified probe * dtps_getargdesc() <-- Get the argument description for args[X] * dtps_getargval() <-- Get the value for an argX or args[X] variable * dtps_usermode() <-- Find out if the probe was fired in user mode * dtps_destroy() <-- Destroy all state associated with this probe * * 1.2 void dtps_provide(void *arg, const dtrace_probedesc_t *spec) * * 1.2.1 Overview * * Called to indicate that the provider should provide all probes. If the * specified description is non-NULL, dtps_provide() is being called because * no probe matched a specified probe -- if the provider has the ability to * create custom probes, it may wish to create a probe that matches the * specified description. * * 1.2.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is a pointer to a probe description that the provider may * wish to consider when creating custom probes. The provider is expected to * call back into the DTrace framework via dtrace_probe_create() to create * any necessary probes. dtps_provide() may be called even if the provider * has made available all probes; the provider should check the return value * of dtrace_probe_create() to handle this case. Note that the provider need * not implement both dtps_provide() and dtps_provide_module(); see * "Arguments and Notes" for dtrace_register(), below. * * 1.2.3 Return value * * None. * * 1.2.4 Caller's context * * dtps_provide() is typically called from open() or ioctl() context, but may * be called from other contexts as well. The DTrace framework is locked in * such a way that providers may not register or unregister. This means that * the provider may not call any DTrace API that affects its registration with * the framework, including dtrace_register(), dtrace_unregister(), * dtrace_invalidate(), and dtrace_condense(). However, the context is such * that the provider may (and indeed, is expected to) call probe-related * DTrace routines, including dtrace_probe_create(), dtrace_probe_lookup(), * and dtrace_probe_arg(). * * 1.3 void dtps_provide_module(void *arg, modctl_t *mp) * * 1.3.1 Overview * * Called to indicate that the provider should provide all probes in the * specified module. * * 1.3.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is a pointer to a modctl structure that indicates the * module for which probes should be created. * * 1.3.3 Return value * * None. * * 1.3.4 Caller's context * * dtps_provide_module() may be called from open() or ioctl() context, but * may also be called from a module loading context. mod_lock is held, and * the DTrace framework is locked in such a way that providers may not * register or unregister. This means that the provider may not call any * DTrace API that affects its registration with the framework, including * dtrace_register(), dtrace_unregister(), dtrace_invalidate(), and * dtrace_condense(). However, the context is such that the provider may (and * indeed, is expected to) call probe-related DTrace routines, including * dtrace_probe_create(), dtrace_probe_lookup(), and dtrace_probe_arg(). Note * that the provider need not implement both dtps_provide() and * dtps_provide_module(); see "Arguments and Notes" for dtrace_register(), * below. * * 1.4 void dtps_enable(void *arg, dtrace_id_t id, void *parg) * * 1.4.1 Overview * * Called to enable the specified probe. * * 1.4.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is the identifier of the probe to be enabled. The third * argument is the probe argument as passed to dtrace_probe_create(). * dtps_enable() will be called when a probe transitions from not being * enabled at all to having one or more ECB. The number of ECBs associated * with the probe may change without subsequent calls into the provider. * When the number of ECBs drops to zero, the provider will be explicitly * told to disable the probe via dtps_disable(). dtrace_probe() should never * be called for a probe identifier that hasn't been explicitly enabled via * dtps_enable(). * * 1.4.3 Return value * * None. * * 1.4.4 Caller's context * * The DTrace framework is locked in such a way that it may not be called * back into at all. cpu_lock is held. mod_lock is not held and may not * be acquired. * * 1.5 void dtps_disable(void *arg, dtrace_id_t id, void *parg) * * 1.5.1 Overview * * Called to disable the specified probe. * * 1.5.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is the identifier of the probe to be disabled. The third * argument is the probe argument as passed to dtrace_probe_create(). * dtps_disable() will be called when a probe transitions from being enabled * to having zero ECBs. dtrace_probe() should never be called for a probe * identifier that has been explicitly enabled via dtps_disable(). * * 1.5.3 Return value * * None. * * 1.5.4 Caller's context * * The DTrace framework is locked in such a way that it may not be called * back into at all. cpu_lock is held. mod_lock is not held and may not * be acquired. * * 1.6 void dtps_suspend(void *arg, dtrace_id_t id, void *parg) * * 1.6.1 Overview * * Called to suspend the specified enabled probe. This entry point is for * providers that may need to suspend some or all of their probes when CPUs * are being powered on or when the boot monitor is being entered for a * prolonged period of time. * * 1.6.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is the identifier of the probe to be suspended. The * third argument is the probe argument as passed to dtrace_probe_create(). * dtps_suspend will only be called on an enabled probe. Providers that * provide a dtps_suspend entry point will want to take roughly the action * that it takes for dtps_disable. * * 1.6.3 Return value * * None. * * 1.6.4 Caller's context * * Interrupts are disabled. The DTrace framework is in a state such that the * specified probe cannot be disabled or destroyed for the duration of * dtps_suspend(). As interrupts are disabled, the provider is afforded * little latitude; the provider is expected to do no more than a store to * memory. * * 1.7 void dtps_resume(void *arg, dtrace_id_t id, void *parg) * * 1.7.1 Overview * * Called to resume the specified enabled probe. This entry point is for * providers that may need to resume some or all of their probes after the * completion of an event that induced a call to dtps_suspend(). * * 1.7.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is the identifier of the probe to be resumed. The * third argument is the probe argument as passed to dtrace_probe_create(). * dtps_resume will only be called on an enabled probe. Providers that * provide a dtps_resume entry point will want to take roughly the action * that it takes for dtps_enable. * * 1.7.3 Return value * * None. * * 1.7.4 Caller's context * * Interrupts are disabled. The DTrace framework is in a state such that the * specified probe cannot be disabled or destroyed for the duration of * dtps_resume(). As interrupts are disabled, the provider is afforded * little latitude; the provider is expected to do no more than a store to * memory. * * 1.8 void dtps_getargdesc(void *arg, dtrace_id_t id, void *parg, * dtrace_argdesc_t *desc) * * 1.8.1 Overview * * Called to retrieve the argument description for an args[X] variable. * * 1.8.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is the identifier of the current probe. The third * argument is the probe argument as passed to dtrace_probe_create(). The * fourth argument is a pointer to the argument description. This * description is both an input and output parameter: it contains the * index of the desired argument in the dtargd_ndx field, and expects * the other fields to be filled in upon return. If there is no argument * corresponding to the specified index, the dtargd_ndx field should be set * to DTRACE_ARGNONE. * * 1.8.3 Return value * * None. The dtargd_ndx, dtargd_native, dtargd_xlate and dtargd_mapping * members of the dtrace_argdesc_t structure are all output values. * * 1.8.4 Caller's context * * dtps_getargdesc() is called from ioctl() context. mod_lock is held, and * the DTrace framework is locked in such a way that providers may not * register or unregister. This means that the provider may not call any * DTrace API that affects its registration with the framework, including * dtrace_register(), dtrace_unregister(), dtrace_invalidate(), and * dtrace_condense(). * * 1.9 uint64_t dtps_getargval(void *arg, dtrace_id_t id, void *parg, * int argno, int aframes) * * 1.9.1 Overview * * Called to retrieve a value for an argX or args[X] variable. * * 1.9.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is the identifier of the current probe. The third * argument is the probe argument as passed to dtrace_probe_create(). The * fourth argument is the number of the argument (the X in the example in * 1.9.1). The fifth argument is the number of stack frames that were used * to get from the actual place in the code that fired the probe to * dtrace_probe() itself, the so-called artificial frames. This argument may * be used to descend an appropriate number of frames to find the correct * values. If this entry point is left NULL, the dtrace_getarg() built-in * function is used. * * 1.9.3 Return value * * The value of the argument. * * 1.9.4 Caller's context * * This is called from within dtrace_probe() meaning that interrupts * are disabled. No locks should be taken within this entry point. * * 1.10 int dtps_usermode(void *arg, dtrace_id_t id, void *parg) * * 1.10.1 Overview * * Called to determine if the probe was fired in a user context. * * 1.10.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is the identifier of the current probe. The third * argument is the probe argument as passed to dtrace_probe_create(). This * entry point must not be left NULL for providers whose probes allow for * mixed mode tracing, that is to say those probes that can fire during * kernel- _or_ user-mode execution * * 1.10.3 Return value * * A bitwise OR that encapsulates both the mode (either DTRACE_MODE_KERNEL * or DTRACE_MODE_USER) and the policy when the privilege of the enabling * is insufficient for that mode (a combination of DTRACE_MODE_NOPRIV_DROP, * DTRACE_MODE_NOPRIV_RESTRICT, and DTRACE_MODE_LIMITEDPRIV_RESTRICT). If * DTRACE_MODE_NOPRIV_DROP bit is set, insufficient privilege will result * in the probe firing being silently ignored for the enabling; if the * DTRACE_NODE_NOPRIV_RESTRICT bit is set, insufficient privilege will not * prevent probe processing for the enabling, but restrictions will be in * place that induce a UPRIV fault upon attempt to examine probe arguments * or current process state. If the DTRACE_MODE_LIMITEDPRIV_RESTRICT bit * is set, similar restrictions will be placed upon operation if the * privilege is sufficient to process the enabling, but does not otherwise * entitle the enabling to all zones. The DTRACE_MODE_NOPRIV_DROP and * DTRACE_MODE_NOPRIV_RESTRICT are mutually exclusive (and one of these * two policies must be specified), but either may be combined (or not) * with DTRACE_MODE_LIMITEDPRIV_RESTRICT. * * 1.10.4 Caller's context * * This is called from within dtrace_probe() meaning that interrupts * are disabled. No locks should be taken within this entry point. * * 1.11 void dtps_destroy(void *arg, dtrace_id_t id, void *parg) * * 1.11.1 Overview * * Called to destroy the specified probe. * * 1.11.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_register(). The * second argument is the identifier of the probe to be destroyed. The third * argument is the probe argument as passed to dtrace_probe_create(). The * provider should free all state associated with the probe. The framework * guarantees that dtps_destroy() is only called for probes that have either * been disabled via dtps_disable() or were never enabled via dtps_enable(). * Once dtps_disable() has been called for a probe, no further call will be * made specifying the probe. * * 1.11.3 Return value * * None. * * 1.11.4 Caller's context * * The DTrace framework is locked in such a way that it may not be called * back into at all. mod_lock is held. cpu_lock is not held, and may not be * acquired. * * * 2 Provider-to-Framework API * * 2.1 Overview * * The Provider-to-Framework API provides the mechanism for the provider to * register itself with the DTrace framework, to create probes, to lookup * probes and (most importantly) to fire probes. The Provider-to-Framework * consists of: * * dtrace_register() <-- Register a provider with the DTrace framework * dtrace_unregister() <-- Remove a provider's DTrace registration * dtrace_invalidate() <-- Invalidate the specified provider * dtrace_condense() <-- Remove a provider's unenabled probes * dtrace_attached() <-- Indicates whether or not DTrace has attached * dtrace_probe_create() <-- Create a DTrace probe * dtrace_probe_lookup() <-- Lookup a DTrace probe based on its name * dtrace_probe_arg() <-- Return the probe argument for a specific probe * dtrace_probe() <-- Fire the specified probe * * 2.2 int dtrace_register(const char *name, const dtrace_pattr_t *pap, * uint32_t priv, cred_t *cr, const dtrace_pops_t *pops, void *arg, * dtrace_provider_id_t *idp) * * 2.2.1 Overview * * dtrace_register() registers the calling provider with the DTrace * framework. It should generally be called by DTrace providers in their * attach(9E) entry point. * * 2.2.2 Arguments and Notes * * The first argument is the name of the provider. The second argument is a * pointer to the stability attributes for the provider. The third argument * is the privilege flags for the provider, and must be some combination of: * * DTRACE_PRIV_NONE <= All users may enable probes from this provider * * DTRACE_PRIV_PROC <= Any user with privilege of PRIV_DTRACE_PROC may * enable probes from this provider * * DTRACE_PRIV_USER <= Any user with privilege of PRIV_DTRACE_USER may * enable probes from this provider * * DTRACE_PRIV_KERNEL <= Any user with privilege of PRIV_DTRACE_KERNEL * may enable probes from this provider * * DTRACE_PRIV_OWNER <= This flag places an additional constraint on * the privilege requirements above. These probes * require either (a) a user ID matching the user * ID of the cred passed in the fourth argument * or (b) the PRIV_PROC_OWNER privilege. * * DTRACE_PRIV_ZONEOWNER<= This flag places an additional constraint on * the privilege requirements above. These probes * require either (a) a zone ID matching the zone * ID of the cred passed in the fourth argument * or (b) the PRIV_PROC_ZONE privilege. * * Note that these flags designate the _visibility_ of the probes, not * the conditions under which they may or may not fire. * * The fourth argument is the credential that is associated with the * provider. This argument should be NULL if the privilege flags don't * include DTRACE_PRIV_OWNER or DTRACE_PRIV_ZONEOWNER. If non-NULL, the * framework stashes the uid and zoneid represented by this credential * for use at probe-time, in implicit predicates. These limit visibility * of the probes to users and/or zones which have sufficient privilege to * access them. * * The fifth argument is a DTrace provider operations vector, which provides * the implementation for the Framework-to-Provider API. (See Section 1, * above.) This must be non-NULL, and each member must be non-NULL. The * exceptions to this are (1) the dtps_provide() and dtps_provide_module() * members (if the provider so desires, _one_ of these members may be left * NULL -- denoting that the provider only implements the other) and (2) * the dtps_suspend() and dtps_resume() members, which must either both be * NULL or both be non-NULL. * * The sixth argument is a cookie to be specified as the first argument for * each function in the Framework-to-Provider API. This argument may have * any value. * * The final argument is a pointer to dtrace_provider_id_t. If * dtrace_register() successfully completes, the provider identifier will be * stored in the memory pointed to be this argument. This argument must be * non-NULL. * * 2.2.3 Return value * * On success, dtrace_register() returns 0 and stores the new provider's * identifier into the memory pointed to by the idp argument. On failure, * dtrace_register() returns an errno: * * EINVAL The arguments passed to dtrace_register() were somehow invalid. * This may because a parameter that must be non-NULL was NULL, * because the name was invalid (either empty or an illegal * provider name) or because the attributes were invalid. * * No other failure code is returned. * * 2.2.4 Caller's context * * dtrace_register() may induce calls to dtrace_provide(); the provider must * hold no locks across dtrace_register() that may also be acquired by * dtrace_provide(). cpu_lock and mod_lock must not be held. * * 2.3 int dtrace_unregister(dtrace_provider_t id) * * 2.3.1 Overview * * Unregisters the specified provider from the DTrace framework. It should * generally be called by DTrace providers in their detach(9E) entry point. * * 2.3.2 Arguments and Notes * * The only argument is the provider identifier, as returned from a * successful call to dtrace_register(). As a result of calling * dtrace_unregister(), the DTrace framework will call back into the provider * via the dtps_destroy() entry point. Once dtrace_unregister() successfully * completes, however, the DTrace framework will no longer make calls through * the Framework-to-Provider API. * * 2.3.3 Return value * * On success, dtrace_unregister returns 0. On failure, dtrace_unregister() * returns an errno: * * EBUSY There are currently processes that have the DTrace pseudodevice * open, or there exists an anonymous enabling that hasn't yet * been claimed. * * No other failure code is returned. * * 2.3.4 Caller's context * * Because a call to dtrace_unregister() may induce calls through the * Framework-to-Provider API, the caller may not hold any lock across * dtrace_register() that is also acquired in any of the Framework-to- * Provider API functions. Additionally, mod_lock may not be held. * * 2.4 void dtrace_invalidate(dtrace_provider_id_t id) * * 2.4.1 Overview * * Invalidates the specified provider. All subsequent probe lookups for the * specified provider will fail, but its probes will not be removed. * * 2.4.2 Arguments and note * * The only argument is the provider identifier, as returned from a * successful call to dtrace_register(). In general, a provider's probes * always remain valid; dtrace_invalidate() is a mechanism for invalidating * an entire provider, regardless of whether or not probes are enabled or * not. Note that dtrace_invalidate() will _not_ prevent already enabled * probes from firing -- it will merely prevent any new enablings of the * provider's probes. * * 2.5 int dtrace_condense(dtrace_provider_id_t id) * * 2.5.1 Overview * * Removes all the unenabled probes for the given provider. This function is * not unlike dtrace_unregister(), except that it doesn't remove the * provider just as many of its associated probes as it can. * * 2.5.2 Arguments and Notes * * As with dtrace_unregister(), the sole argument is the provider identifier * as returned from a successful call to dtrace_register(). As a result of * calling dtrace_condense(), the DTrace framework will call back into the * given provider's dtps_destroy() entry point for each of the provider's * unenabled probes. * * 2.5.3 Return value * * Currently, dtrace_condense() always returns 0. However, consumers of this * function should check the return value as appropriate; its behavior may * change in the future. * * 2.5.4 Caller's context * * As with dtrace_unregister(), the caller may not hold any lock across * dtrace_condense() that is also acquired in the provider's entry points. * Also, mod_lock may not be held. * * 2.6 int dtrace_attached() * * 2.6.1 Overview * * Indicates whether or not DTrace has attached. * * 2.6.2 Arguments and Notes * * For most providers, DTrace makes initial contact beyond registration. * That is, once a provider has registered with DTrace, it waits to hear * from DTrace to create probes. However, some providers may wish to * proactively create probes without first being told by DTrace to do so. * If providers wish to do this, they must first call dtrace_attached() to * determine if DTrace itself has attached. If dtrace_attached() returns 0, * the provider must not make any other Provider-to-Framework API call. * * 2.6.3 Return value * * dtrace_attached() returns 1 if DTrace has attached, 0 otherwise. * * 2.7 int dtrace_probe_create(dtrace_provider_t id, const char *mod, * const char *func, const char *name, int aframes, void *arg) * * 2.7.1 Overview * * Creates a probe with specified module name, function name, and name. * * 2.7.2 Arguments and Notes * * The first argument is the provider identifier, as returned from a * successful call to dtrace_register(). The second, third, and fourth * arguments are the module name, function name, and probe name, * respectively. Of these, module name and function name may both be NULL * (in which case the probe is considered to be unanchored), or they may both * be non-NULL. The name must be non-NULL, and must point to a non-empty * string. * * The fifth argument is the number of artificial stack frames that will be * found on the stack when dtrace_probe() is called for the new probe. These * artificial frames will be automatically be pruned should the stack() or * stackdepth() functions be called as part of one of the probe's ECBs. If * the parameter doesn't add an artificial frame, this parameter should be * zero. * * The final argument is a probe argument that will be passed back to the * provider when a probe-specific operation is called. (e.g., via * dtps_enable(), dtps_disable(), etc.) * * Note that it is up to the provider to be sure that the probe that it * creates does not already exist -- if the provider is unsure of the probe's * existence, it should assure its absence with dtrace_probe_lookup() before * calling dtrace_probe_create(). * * 2.7.3 Return value * * dtrace_probe_create() always succeeds, and always returns the identifier * of the newly-created probe. * * 2.7.4 Caller's context * * While dtrace_probe_create() is generally expected to be called from * dtps_provide() and/or dtps_provide_module(), it may be called from other * non-DTrace contexts. Neither cpu_lock nor mod_lock may be held. * * 2.8 dtrace_id_t dtrace_probe_lookup(dtrace_provider_t id, const char *mod, * const char *func, const char *name) * * 2.8.1 Overview * * Looks up a probe based on provdider and one or more of module name, * function name and probe name. * * 2.8.2 Arguments and Notes * * The first argument is the provider identifier, as returned from a * successful call to dtrace_register(). The second, third, and fourth * arguments are the module name, function name, and probe name, * respectively. Any of these may be NULL; dtrace_probe_lookup() will return * the identifier of the first probe that is provided by the specified * provider and matches all of the non-NULL matching criteria. * dtrace_probe_lookup() is generally used by a provider to be check the * existence of a probe before creating it with dtrace_probe_create(). * * 2.8.3 Return value * * If the probe exists, returns its identifier. If the probe does not exist, * return DTRACE_IDNONE. * * 2.8.4 Caller's context * * While dtrace_probe_lookup() is generally expected to be called from * dtps_provide() and/or dtps_provide_module(), it may also be called from * other non-DTrace contexts. Neither cpu_lock nor mod_lock may be held. * * 2.9 void *dtrace_probe_arg(dtrace_provider_t id, dtrace_id_t probe) * * 2.9.1 Overview * * Returns the probe argument associated with the specified probe. * * 2.9.2 Arguments and Notes * * The first argument is the provider identifier, as returned from a * successful call to dtrace_register(). The second argument is a probe * identifier, as returned from dtrace_probe_lookup() or * dtrace_probe_create(). This is useful if a probe has multiple * provider-specific components to it: the provider can create the probe * once with provider-specific state, and then add to the state by looking * up the probe based on probe identifier. * * 2.9.3 Return value * * Returns the argument associated with the specified probe. If the * specified probe does not exist, or if the specified probe is not provided * by the specified provider, NULL is returned. * * 2.9.4 Caller's context * * While dtrace_probe_arg() is generally expected to be called from * dtps_provide() and/or dtps_provide_module(), it may also be called from * other non-DTrace contexts. Neither cpu_lock nor mod_lock may be held. * * 2.10 void dtrace_probe(dtrace_id_t probe, uintptr_t arg0, uintptr_t arg1, * uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) * * 2.10.1 Overview * * The epicenter of DTrace: fires the specified probes with the specified * arguments. * * 2.10.2 Arguments and Notes * * The first argument is a probe identifier as returned by * dtrace_probe_create() or dtrace_probe_lookup(). The second through sixth * arguments are the values to which the D variables "arg0" through "arg4" * will be mapped. * * dtrace_probe() should be called whenever the specified probe has fired -- * however the provider defines it. * * 2.10.3 Return value * * None. * * 2.10.4 Caller's context * * dtrace_probe() may be called in virtually any context: kernel, user, * interrupt, high-level interrupt, with arbitrary adaptive locks held, with * dispatcher locks held, with interrupts disabled, etc. The only latitude * that must be afforded to DTrace is the ability to make calls within * itself (and to its in-kernel subroutines) and the ability to access * arbitrary (but mapped) memory. On some platforms, this constrains * context. For example, on UltraSPARC, dtrace_probe() cannot be called * from any context in which TL is greater than zero. dtrace_probe() may * also not be called from any routine which may be called by dtrace_probe() * -- which includes functions in the DTrace framework and some in-kernel * DTrace subroutines. All such functions "dtrace_"; providers that * instrument the kernel arbitrarily should be sure to not instrument these * routines. */ typedef struct dtrace_pops { void (*dtps_provide)(void *arg, dtrace_probedesc_t *spec); void (*dtps_provide_module)(void *arg, modctl_t *mp); void (*dtps_enable)(void *arg, dtrace_id_t id, void *parg); void (*dtps_disable)(void *arg, dtrace_id_t id, void *parg); void (*dtps_suspend)(void *arg, dtrace_id_t id, void *parg); void (*dtps_resume)(void *arg, dtrace_id_t id, void *parg); void (*dtps_getargdesc)(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc); uint64_t (*dtps_getargval)(void *arg, dtrace_id_t id, void *parg, int argno, int aframes); int (*dtps_usermode)(void *arg, dtrace_id_t id, void *parg); void (*dtps_destroy)(void *arg, dtrace_id_t id, void *parg); } dtrace_pops_t; #define DTRACE_MODE_KERNEL 0x01 #define DTRACE_MODE_USER 0x02 #define DTRACE_MODE_NOPRIV_DROP 0x10 #define DTRACE_MODE_NOPRIV_RESTRICT 0x20 #define DTRACE_MODE_LIMITEDPRIV_RESTRICT 0x40 typedef uintptr_t dtrace_provider_id_t; extern int dtrace_register(const char *, const dtrace_pattr_t *, uint32_t, cred_t *, const dtrace_pops_t *, void *, dtrace_provider_id_t *); extern int dtrace_unregister(dtrace_provider_id_t); extern int dtrace_condense(dtrace_provider_id_t); extern void dtrace_invalidate(dtrace_provider_id_t); extern dtrace_id_t dtrace_probe_lookup(dtrace_provider_id_t, char *, char *, char *); extern dtrace_id_t dtrace_probe_create(dtrace_provider_id_t, const char *, const char *, const char *, int, void *); extern void *dtrace_probe_arg(dtrace_provider_id_t, dtrace_id_t); extern void dtrace_probe(dtrace_id_t, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4); /* * DTrace Meta Provider API * * The following functions are implemented by the DTrace framework and are * used to implement meta providers. Meta providers plug into the DTrace * framework and are used to instantiate new providers on the fly. At * present, there is only one type of meta provider and only one meta * provider may be registered with the DTrace framework at a time. The * sole meta provider type provides user-land static tracing facilities * by taking meta probe descriptions and adding a corresponding provider * into the DTrace framework. * * 1 Framework-to-Provider * * 1.1 Overview * * The Framework-to-Provider API is represented by the dtrace_mops structure * that the meta provider passes to the framework when registering itself as * a meta provider. This structure consists of the following members: * * dtms_create_probe() <-- Add a new probe to a created provider * dtms_provide_pid() <-- Create a new provider for a given process * dtms_remove_pid() <-- Remove a previously created provider * * 1.2 void dtms_create_probe(void *arg, void *parg, * dtrace_helper_probedesc_t *probedesc); * * 1.2.1 Overview * * Called by the DTrace framework to create a new probe in a provider * created by this meta provider. * * 1.2.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_meta_register(). * The second argument is the provider cookie for the associated provider; * this is obtained from the return value of dtms_provide_pid(). The third * argument is the helper probe description. * * 1.2.3 Return value * * None * * 1.2.4 Caller's context * * dtms_create_probe() is called from either ioctl() or module load context * in the context of a newly-created provider (that is, a provider that * is a result of a call to dtms_provide_pid()). The DTrace framework is * locked in such a way that meta providers may not register or unregister, * such that no other thread can call into a meta provider operation and that * atomicity is assured with respect to meta provider operations across * dtms_provide_pid() and subsequent calls to dtms_create_probe(). * The context is thus effectively single-threaded with respect to the meta * provider, and that the meta provider cannot call dtrace_meta_register() * or dtrace_meta_unregister(). However, the context is such that the * provider may (and is expected to) call provider-related DTrace provider * APIs including dtrace_probe_create(). * * 1.3 void *dtms_provide_pid(void *arg, dtrace_meta_provider_t *mprov, * pid_t pid) * * 1.3.1 Overview * * Called by the DTrace framework to instantiate a new provider given the * description of the provider and probes in the mprov argument. The * meta provider should call dtrace_register() to insert the new provider * into the DTrace framework. * * 1.3.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_meta_register(). * The second argument is a pointer to a structure describing the new * helper provider. The third argument is the process identifier for * process associated with this new provider. Note that the name of the * provider as passed to dtrace_register() should be the contatenation of * the dtmpb_provname member of the mprov argument and the processs * identifier as a string. * * 1.3.3 Return value * * The cookie for the provider that the meta provider creates. This is * the same value that it passed to dtrace_register(). * * 1.3.4 Caller's context * * dtms_provide_pid() is called from either ioctl() or module load context. * The DTrace framework is locked in such a way that meta providers may not * register or unregister. This means that the meta provider cannot call * dtrace_meta_register() or dtrace_meta_unregister(). However, the context * is such that the provider may -- and is expected to -- call * provider-related DTrace provider APIs including dtrace_register(). * * 1.4 void dtms_remove_pid(void *arg, dtrace_meta_provider_t *mprov, * pid_t pid) * * 1.4.1 Overview * * Called by the DTrace framework to remove a provider that had previously * been instantiated via the dtms_provide_pid() entry point. The meta * provider need not remove the provider immediately, but this entry * point indicates that the provider should be removed as soon as possible * using the dtrace_unregister() API. * * 1.4.2 Arguments and notes * * The first argument is the cookie as passed to dtrace_meta_register(). * The second argument is a pointer to a structure describing the helper * provider. The third argument is the process identifier for process * associated with this new provider. * * 1.4.3 Return value * * None * * 1.4.4 Caller's context * * dtms_remove_pid() is called from either ioctl() or exit() context. * The DTrace framework is locked in such a way that meta providers may not * register or unregister. This means that the meta provider cannot call * dtrace_meta_register() or dtrace_meta_unregister(). However, the context * is such that the provider may -- and is expected to -- call * provider-related DTrace provider APIs including dtrace_unregister(). */ typedef struct dtrace_helper_probedesc { char *dthpb_mod; /* probe module */ char *dthpb_func; /* probe function */ char *dthpb_name; /* probe name */ uint64_t dthpb_base; /* base address */ uint32_t *dthpb_offs; /* offsets array */ uint32_t *dthpb_enoffs; /* is-enabled offsets array */ uint32_t dthpb_noffs; /* offsets count */ uint32_t dthpb_nenoffs; /* is-enabled offsets count */ uint8_t *dthpb_args; /* argument mapping array */ uint8_t dthpb_xargc; /* translated argument count */ uint8_t dthpb_nargc; /* native argument count */ char *dthpb_xtypes; /* translated types strings */ char *dthpb_ntypes; /* native types strings */ } dtrace_helper_probedesc_t; typedef struct dtrace_helper_provdesc { char *dthpv_provname; /* provider name */ dtrace_pattr_t dthpv_pattr; /* stability attributes */ } dtrace_helper_provdesc_t; typedef struct dtrace_mops { void (*dtms_create_probe)(void *, void *, dtrace_helper_probedesc_t *); void *(*dtms_provide_pid)(void *, dtrace_helper_provdesc_t *, pid_t); void (*dtms_remove_pid)(void *, dtrace_helper_provdesc_t *, pid_t); } dtrace_mops_t; typedef uintptr_t dtrace_meta_provider_id_t; extern int dtrace_meta_register(const char *, const dtrace_mops_t *, void *, dtrace_meta_provider_id_t *); extern int dtrace_meta_unregister(dtrace_meta_provider_id_t); /* * DTrace Kernel Hooks * * The following functions are implemented by the base kernel and form a set of * hooks used by the DTrace framework. DTrace hooks are implemented in either * uts/common/os/dtrace_subr.c, an ISA-specific assembly file, or in a * uts//os/dtrace_subr.c corresponding to each hardware platform. */ typedef enum dtrace_vtime_state { DTRACE_VTIME_INACTIVE = 0, /* No DTrace, no TNF */ DTRACE_VTIME_ACTIVE, /* DTrace virtual time, no TNF */ DTRACE_VTIME_INACTIVE_TNF, /* No DTrace, TNF active */ DTRACE_VTIME_ACTIVE_TNF /* DTrace virtual time _and_ TNF */ } dtrace_vtime_state_t; #ifdef illumos extern dtrace_vtime_state_t dtrace_vtime_active; #endif extern void dtrace_vtime_switch(kthread_t *next); extern void dtrace_vtime_enable_tnf(void); extern void dtrace_vtime_disable_tnf(void); extern void dtrace_vtime_enable(void); extern void dtrace_vtime_disable(void); struct regs; struct reg; #ifdef illumos extern int (*dtrace_pid_probe_ptr)(struct reg *); extern int (*dtrace_return_probe_ptr)(struct reg *); extern void (*dtrace_fasttrap_fork_ptr)(proc_t *, proc_t *); extern void (*dtrace_fasttrap_exec_ptr)(proc_t *); extern void (*dtrace_fasttrap_exit_ptr)(proc_t *); extern void dtrace_fasttrap_fork(proc_t *, proc_t *); #endif typedef uintptr_t dtrace_icookie_t; typedef void (*dtrace_xcall_t)(void *); extern dtrace_icookie_t dtrace_interrupt_disable(void); extern void dtrace_interrupt_enable(dtrace_icookie_t); extern void dtrace_membar_producer(void); extern void dtrace_membar_consumer(void); extern void (*dtrace_cpu_init)(processorid_t); #ifdef illumos extern void (*dtrace_modload)(modctl_t *); extern void (*dtrace_modunload)(modctl_t *); #endif extern void (*dtrace_helpers_cleanup)(void); extern void (*dtrace_helpers_fork)(proc_t *parent, proc_t *child); extern void (*dtrace_cpustart_init)(void); extern void (*dtrace_cpustart_fini)(void); extern void (*dtrace_closef)(void); extern void (*dtrace_debugger_init)(void); extern void (*dtrace_debugger_fini)(void); extern dtrace_cacheid_t dtrace_predcache_id; #ifdef illumos extern hrtime_t dtrace_gethrtime(void); #else void dtrace_debug_printf(const char *, ...) __printflike(1, 2); #endif extern void dtrace_sync(void); extern void dtrace_toxic_ranges(void (*)(uintptr_t, uintptr_t)); extern void dtrace_xcall(processorid_t, dtrace_xcall_t, void *); extern void dtrace_vpanic(const char *, __va_list); extern void dtrace_panic(const char *, ...); extern int dtrace_safe_defer_signal(void); extern void dtrace_safe_synchronous_signal(void); extern int dtrace_mach_aframes(void); #if defined(__i386) || defined(__amd64) extern int dtrace_instr_size(uchar_t *instr); extern int dtrace_instr_size_isa(uchar_t *, model_t, int *); extern void dtrace_invop_callsite(void); #endif extern void dtrace_invop_add(int (*)(uintptr_t, struct trapframe *, uintptr_t)); extern void dtrace_invop_remove(int (*)(uintptr_t, struct trapframe *, uintptr_t)); #ifdef __sparc extern int dtrace_blksuword32(uintptr_t, uint32_t *, int); extern void dtrace_getfsr(uint64_t *); #endif #ifndef illumos extern void dtrace_helpers_duplicate(proc_t *, proc_t *); extern void dtrace_helpers_destroy(proc_t *); #endif #define DTRACE_CPUFLAG_ISSET(flag) \ (cpu_core[curcpu].cpuc_dtrace_flags & (flag)) #define DTRACE_CPUFLAG_SET(flag) \ (cpu_core[curcpu].cpuc_dtrace_flags |= (flag)) #define DTRACE_CPUFLAG_CLEAR(flag) \ (cpu_core[curcpu].cpuc_dtrace_flags &= ~(flag)) #endif /* _KERNEL */ #endif /* _ASM */ #if defined(__i386) || defined(__amd64) #define DTRACE_INVOP_PUSHL_EBP 1 #define DTRACE_INVOP_PUSHQ_RBP DTRACE_INVOP_PUSHL_EBP #define DTRACE_INVOP_POPL_EBP 2 #define DTRACE_INVOP_POPQ_RBP DTRACE_INVOP_POPL_EBP #define DTRACE_INVOP_LEAVE 3 #define DTRACE_INVOP_NOP 4 #define DTRACE_INVOP_RET 5 #elif defined(__powerpc__) #define DTRACE_INVOP_RET 1 #define DTRACE_INVOP_BCTR 2 #define DTRACE_INVOP_BLR 3 #define DTRACE_INVOP_JUMP 4 #define DTRACE_INVOP_MFLR_R0 5 #define DTRACE_INVOP_NOP 6 #elif defined(__arm__) #define DTRACE_INVOP_SHIFT 4 #define DTRACE_INVOP_MASK ((1 << DTRACE_INVOP_SHIFT) - 1) #define DTRACE_INVOP_DATA(x) ((x) >> DTRACE_INVOP_SHIFT) #define DTRACE_INVOP_PUSHM 1 #define DTRACE_INVOP_POPM 2 #define DTRACE_INVOP_B 3 #elif defined(__aarch64__) #define INSN_SIZE 4 #define B_MASK 0xff000000 #define B_DATA_MASK 0x00ffffff #define B_INSTR 0x14000000 #define RET_INSTR 0xd65f03c0 #define LDP_STP_MASK 0xffc00000 #define STP_32 0x29800000 #define STP_64 0xa9800000 #define LDP_32 0x28c00000 #define LDP_64 0xa8c00000 #define LDP_STP_PREIND (1 << 24) #define LDP_STP_DIR (1 << 22) /* Load instruction */ #define ARG1_SHIFT 0 #define ARG1_MASK 0x1f #define ARG2_SHIFT 10 #define ARG2_MASK 0x1f #define OFFSET_SHIFT 15 #define OFFSET_SIZE 7 #define OFFSET_MASK ((1 << OFFSET_SIZE) - 1) #define DTRACE_INVOP_PUSHM 1 #define DTRACE_INVOP_RET 2 #define DTRACE_INVOP_B 3 #elif defined(__mips__) #define INSN_SIZE 4 /* Load/Store double RA to/from SP */ #define LDSD_RA_SP_MASK 0xffff0000 #define LDSD_DATA_MASK 0x0000ffff #define SD_RA_SP 0xffbf0000 #define LD_RA_SP 0xdfbf0000 #define DTRACE_INVOP_SD 1 #define DTRACE_INVOP_LD 2 #elif defined(__riscv__) #define SD_RA_SP_MASK 0x01fff07f #define SD_RA_SP 0x00113023 #define DTRACE_INVOP_SD 1 #define DTRACE_INVOP_RET 2 #define DTRACE_INVOP_NOP 3 #endif #ifdef __cplusplus } #endif #endif /* _SYS_DTRACE_H */ Index: projects/ipsec/sys/cddl/contrib/opensolaris =================================================================== --- projects/ipsec/sys/cddl/contrib/opensolaris (revision 313312) +++ projects/ipsec/sys/cddl/contrib/opensolaris (revision 313313) Property changes on: projects/ipsec/sys/cddl/contrib/opensolaris ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/cddl/contrib/opensolaris:r313187-313312 Index: projects/ipsec/sys/cddl/dev/dtrace/dtrace_ioctl.c =================================================================== --- projects/ipsec/sys/cddl/dev/dtrace/dtrace_ioctl.c (revision 313312) +++ projects/ipsec/sys/cddl/dev/dtrace/dtrace_ioctl.c (revision 313313) @@ -1,853 +1,854 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * $FreeBSD$ * */ static int dtrace_verbose_ioctl; SYSCTL_INT(_debug_dtrace, OID_AUTO, verbose_ioctl, CTLFLAG_RW, &dtrace_verbose_ioctl, 0, "log DTrace ioctls"); #define DTRACE_IOCTL_PRINTF(fmt, ...) if (dtrace_verbose_ioctl) printf(fmt, ## __VA_ARGS__ ) static int dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) { struct proc *p; dof_helper_t *dhp; dof_hdr_t *dof; int rval; dhp = NULL; dof = NULL; rval = 0; switch (cmd) { case DTRACEHIOC_ADDDOF: dhp = (dof_helper_t *)addr; addr = (caddr_t)(uintptr_t)dhp->dofhp_dof; p = curproc; if (p->p_pid == dhp->dofhp_pid) { dof = dtrace_dof_copyin((uintptr_t)addr, &rval); } else { p = pfind(dhp->dofhp_pid); if (p == NULL) return (EINVAL); if (!P_SHOULDSTOP(p) || (p->p_flag & (P_TRACED | P_WEXIT)) != P_TRACED || p->p_pptr != curproc) { PROC_UNLOCK(p); return (EINVAL); } _PHOLD(p); PROC_UNLOCK(p); dof = dtrace_dof_copyin_proc(p, (uintptr_t)addr, &rval); } if (dof == NULL) { if (p != curproc) PRELE(p); break; } mutex_enter(&dtrace_lock); if ((rval = dtrace_helper_slurp(dof, dhp, p)) != -1) { dhp->dofhp_gen = rval; rval = 0; } else { rval = EINVAL; } mutex_exit(&dtrace_lock); if (p != curproc) PRELE(p); break; case DTRACEHIOC_REMOVE: mutex_enter(&dtrace_lock); rval = dtrace_helper_destroygen(NULL, *(int *)(uintptr_t)addr); mutex_exit(&dtrace_lock); break; default: rval = ENOTTY; break; } return (rval); } /* ARGSUSED */ static int dtrace_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags __unused, struct thread *td) { dtrace_state_t *state; devfs_get_cdevpriv((void **) &state); int error = 0; if (state == NULL) return (EINVAL); if (state->dts_anon) { ASSERT(dtrace_anon.dta_state == NULL); state = state->dts_anon; } switch (cmd) { case DTRACEIOC_AGGDESC: { dtrace_aggdesc_t **paggdesc = (dtrace_aggdesc_t **) addr; dtrace_aggdesc_t aggdesc; dtrace_action_t *act; dtrace_aggregation_t *agg; int nrecs; uint32_t offs; dtrace_recdesc_t *lrec; void *buf; size_t size; uintptr_t dest; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_AGGDESC\n",__func__,__LINE__); if (copyin((void *) *paggdesc, &aggdesc, sizeof (aggdesc)) != 0) return (EFAULT); mutex_enter(&dtrace_lock); if ((agg = dtrace_aggid2agg(state, aggdesc.dtagd_id)) == NULL) { mutex_exit(&dtrace_lock); return (EINVAL); } aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid; nrecs = aggdesc.dtagd_nrecs; aggdesc.dtagd_nrecs = 0; offs = agg->dtag_base; lrec = &agg->dtag_action.dta_rec; aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - offs; for (act = agg->dtag_first; ; act = act->dta_next) { ASSERT(act->dta_intuple || DTRACEACT_ISAGG(act->dta_kind)); /* * If this action has a record size of zero, it * denotes an argument to the aggregating action. * Because the presence of this record doesn't (or * shouldn't) affect the way the data is interpreted, * we don't copy it out to save user-level the * confusion of dealing with a zero-length record. */ if (act->dta_rec.dtrd_size == 0) { ASSERT(agg->dtag_hasarg); continue; } aggdesc.dtagd_nrecs++; if (act == &agg->dtag_action) break; } /* * Now that we have the size, we need to allocate a temporary * buffer in which to store the complete description. We need * the temporary buffer to be able to drop dtrace_lock() * across the copyout(), below. */ size = sizeof (dtrace_aggdesc_t) + (aggdesc.dtagd_nrecs * sizeof (dtrace_recdesc_t)); buf = kmem_alloc(size, KM_SLEEP); dest = (uintptr_t)buf; bcopy(&aggdesc, (void *)dest, sizeof (aggdesc)); dest += offsetof(dtrace_aggdesc_t, dtagd_rec[0]); for (act = agg->dtag_first; ; act = act->dta_next) { dtrace_recdesc_t rec = act->dta_rec; /* * See the comment in the above loop for why we pass * over zero-length records. */ if (rec.dtrd_size == 0) { ASSERT(agg->dtag_hasarg); continue; } if (nrecs-- == 0) break; rec.dtrd_offset -= offs; bcopy(&rec, (void *)dest, sizeof (rec)); dest += sizeof (dtrace_recdesc_t); if (act == &agg->dtag_action) break; } mutex_exit(&dtrace_lock); if (copyout(buf, (void *) *paggdesc, dest - (uintptr_t)buf) != 0) { kmem_free(buf, size); return (EFAULT); } kmem_free(buf, size); return (0); } case DTRACEIOC_AGGSNAP: case DTRACEIOC_BUFSNAP: { dtrace_bufdesc_t **pdesc = (dtrace_bufdesc_t **) addr; dtrace_bufdesc_t desc; caddr_t cached; dtrace_buffer_t *buf; dtrace_debug_output(); if (copyin((void *) *pdesc, &desc, sizeof (desc)) != 0) return (EFAULT); DTRACE_IOCTL_PRINTF("%s(%d): %s curcpu %d cpu %d\n", __func__,__LINE__, cmd == DTRACEIOC_AGGSNAP ? "DTRACEIOC_AGGSNAP":"DTRACEIOC_BUFSNAP", curcpu, desc.dtbd_cpu); if (desc.dtbd_cpu >= NCPU) return (ENOENT); if (pcpu_find(desc.dtbd_cpu) == NULL) return (ENOENT); mutex_enter(&dtrace_lock); if (cmd == DTRACEIOC_BUFSNAP) { buf = &state->dts_buffer[desc.dtbd_cpu]; } else { buf = &state->dts_aggbuffer[desc.dtbd_cpu]; } if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) { size_t sz = buf->dtb_offset; if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) { mutex_exit(&dtrace_lock); return (EBUSY); } /* * If this buffer has already been consumed, we're * going to indicate that there's nothing left here * to consume. */ if (buf->dtb_flags & DTRACEBUF_CONSUMED) { mutex_exit(&dtrace_lock); desc.dtbd_size = 0; desc.dtbd_drops = 0; desc.dtbd_errors = 0; desc.dtbd_oldest = 0; sz = sizeof (desc); if (copyout(&desc, (void *) *pdesc, sz) != 0) return (EFAULT); return (0); } /* * If this is a ring buffer that has wrapped, we want * to copy the whole thing out. */ if (buf->dtb_flags & DTRACEBUF_WRAPPED) { dtrace_buffer_polish(buf); sz = buf->dtb_size; } if (copyout(buf->dtb_tomax, desc.dtbd_data, sz) != 0) { mutex_exit(&dtrace_lock); return (EFAULT); } desc.dtbd_size = sz; desc.dtbd_drops = buf->dtb_drops; desc.dtbd_errors = buf->dtb_errors; desc.dtbd_oldest = buf->dtb_xamot_offset; desc.dtbd_timestamp = dtrace_gethrtime(); mutex_exit(&dtrace_lock); if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0) return (EFAULT); buf->dtb_flags |= DTRACEBUF_CONSUMED; return (0); } if (buf->dtb_tomax == NULL) { ASSERT(buf->dtb_xamot == NULL); mutex_exit(&dtrace_lock); return (ENOENT); } cached = buf->dtb_tomax; ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); dtrace_xcall(desc.dtbd_cpu, (dtrace_xcall_t)dtrace_buffer_switch, buf); state->dts_errors += buf->dtb_xamot_errors; /* * If the buffers did not actually switch, then the cross call * did not take place -- presumably because the given CPU is * not in the ready set. If this is the case, we'll return * ENOENT. */ if (buf->dtb_tomax == cached) { ASSERT(buf->dtb_xamot != cached); mutex_exit(&dtrace_lock); return (ENOENT); } ASSERT(cached == buf->dtb_xamot); DTRACE_IOCTL_PRINTF("%s(%d): copyout the buffer snapshot\n",__func__,__LINE__); /* * We have our snapshot; now copy it out. */ if (copyout(buf->dtb_xamot, desc.dtbd_data, buf->dtb_xamot_offset) != 0) { mutex_exit(&dtrace_lock); return (EFAULT); } desc.dtbd_size = buf->dtb_xamot_offset; desc.dtbd_drops = buf->dtb_xamot_drops; desc.dtbd_errors = buf->dtb_xamot_errors; desc.dtbd_oldest = 0; desc.dtbd_timestamp = buf->dtb_switched; mutex_exit(&dtrace_lock); DTRACE_IOCTL_PRINTF("%s(%d): copyout buffer desc: size %zd drops %lu errors %lu\n",__func__,__LINE__,(size_t) desc.dtbd_size,(u_long) desc.dtbd_drops,(u_long) desc.dtbd_errors); /* * Finally, copy out the buffer description. */ if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0) return (EFAULT); return (0); } case DTRACEIOC_CONF: { dtrace_conf_t conf; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_CONF\n",__func__,__LINE__); bzero(&conf, sizeof (conf)); conf.dtc_difversion = DIF_VERSION; conf.dtc_difintregs = DIF_DIR_NREGS; conf.dtc_diftupregs = DIF_DTR_NREGS; conf.dtc_ctfmodel = CTF_MODEL_NATIVE; *((dtrace_conf_t *) addr) = conf; return (0); } case DTRACEIOC_DOFGET: { dof_hdr_t **pdof = (dof_hdr_t **) addr; dof_hdr_t hdr, *dof = *pdof; int rval; uint64_t len; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_DOFGET\n",__func__,__LINE__); if (copyin((void *)dof, &hdr, sizeof (hdr)) != 0) return (EFAULT); mutex_enter(&dtrace_lock); dof = dtrace_dof_create(state); mutex_exit(&dtrace_lock); len = MIN(hdr.dofh_loadsz, dof->dofh_loadsz); rval = copyout(dof, (void *) *pdof, len); dtrace_dof_destroy(dof); return (rval == 0 ? 0 : EFAULT); } case DTRACEIOC_ENABLE: { dof_hdr_t *dof = NULL; dtrace_enabling_t *enab = NULL; dtrace_vstate_t *vstate; int err = 0; int rval; dtrace_enable_io_t *p = (dtrace_enable_io_t *) addr; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_ENABLE\n",__func__,__LINE__); /* * If a NULL argument has been passed, we take this as our * cue to reevaluate our enablings. */ if (p->dof == NULL) { dtrace_enabling_matchall(); return (0); } if ((dof = dtrace_dof_copyin((uintptr_t) p->dof, &rval)) == NULL) return (EINVAL); mutex_enter(&cpu_lock); mutex_enter(&dtrace_lock); vstate = &state->dts_vstate; if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) { mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); dtrace_dof_destroy(dof); return (EBUSY); } - if (dtrace_dof_slurp(dof, vstate, td->td_ucred, &enab, 0, B_TRUE) != 0) { + if (dtrace_dof_slurp(dof, vstate, td->td_ucred, &enab, 0, 0, + B_TRUE) != 0) { mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); dtrace_dof_destroy(dof); return (EINVAL); } if ((rval = dtrace_dof_options(dof, state)) != 0) { dtrace_enabling_destroy(enab); mutex_exit(&dtrace_lock); mutex_exit(&cpu_lock); dtrace_dof_destroy(dof); return (rval); } if ((err = dtrace_enabling_match(enab, &p->n_matched)) == 0) { err = dtrace_enabling_retain(enab); } else { dtrace_enabling_destroy(enab); } mutex_exit(&cpu_lock); mutex_exit(&dtrace_lock); dtrace_dof_destroy(dof); return (err); } case DTRACEIOC_EPROBE: { dtrace_eprobedesc_t **pepdesc = (dtrace_eprobedesc_t **) addr; dtrace_eprobedesc_t epdesc; dtrace_ecb_t *ecb; dtrace_action_t *act; void *buf; size_t size; uintptr_t dest; int nrecs; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_EPROBE\n",__func__,__LINE__); if (copyin((void *)*pepdesc, &epdesc, sizeof (epdesc)) != 0) return (EFAULT); mutex_enter(&dtrace_lock); if ((ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid)) == NULL) { mutex_exit(&dtrace_lock); return (EINVAL); } if (ecb->dte_probe == NULL) { mutex_exit(&dtrace_lock); return (EINVAL); } epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id; epdesc.dtepd_uarg = ecb->dte_uarg; epdesc.dtepd_size = ecb->dte_size; nrecs = epdesc.dtepd_nrecs; epdesc.dtepd_nrecs = 0; for (act = ecb->dte_action; act != NULL; act = act->dta_next) { if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) continue; epdesc.dtepd_nrecs++; } /* * Now that we have the size, we need to allocate a temporary * buffer in which to store the complete description. We need * the temporary buffer to be able to drop dtrace_lock() * across the copyout(), below. */ size = sizeof (dtrace_eprobedesc_t) + (epdesc.dtepd_nrecs * sizeof (dtrace_recdesc_t)); buf = kmem_alloc(size, KM_SLEEP); dest = (uintptr_t)buf; bcopy(&epdesc, (void *)dest, sizeof (epdesc)); dest += offsetof(dtrace_eprobedesc_t, dtepd_rec[0]); for (act = ecb->dte_action; act != NULL; act = act->dta_next) { if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) continue; if (nrecs-- == 0) break; bcopy(&act->dta_rec, (void *)dest, sizeof (dtrace_recdesc_t)); dest += sizeof (dtrace_recdesc_t); } mutex_exit(&dtrace_lock); if (copyout(buf, (void *) *pepdesc, dest - (uintptr_t)buf) != 0) { kmem_free(buf, size); return (EFAULT); } kmem_free(buf, size); return (0); } case DTRACEIOC_FORMAT: { dtrace_fmtdesc_t *fmt = (dtrace_fmtdesc_t *) addr; char *str; int len; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_FORMAT\n",__func__,__LINE__); mutex_enter(&dtrace_lock); if (fmt->dtfd_format == 0 || fmt->dtfd_format > state->dts_nformats) { mutex_exit(&dtrace_lock); return (EINVAL); } /* * Format strings are allocated contiguously and they are * never freed; if a format index is less than the number * of formats, we can assert that the format map is non-NULL * and that the format for the specified index is non-NULL. */ ASSERT(state->dts_formats != NULL); str = state->dts_formats[fmt->dtfd_format - 1]; ASSERT(str != NULL); len = strlen(str) + 1; if (len > fmt->dtfd_length) { fmt->dtfd_length = len; } else { if (copyout(str, fmt->dtfd_string, len) != 0) { mutex_exit(&dtrace_lock); return (EINVAL); } } mutex_exit(&dtrace_lock); return (0); } case DTRACEIOC_GO: { int rval; processorid_t *cpuid = (processorid_t *) addr; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_GO\n",__func__,__LINE__); rval = dtrace_state_go(state, cpuid); return (rval); } case DTRACEIOC_PROBEARG: { dtrace_argdesc_t *desc = (dtrace_argdesc_t *) addr; dtrace_probe_t *probe; dtrace_provider_t *prov; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROBEARG\n",__func__,__LINE__); if (desc->dtargd_id == DTRACE_IDNONE) return (EINVAL); if (desc->dtargd_ndx == DTRACE_ARGNONE) return (EINVAL); mutex_enter(&dtrace_provider_lock); #ifdef illumos mutex_enter(&mod_lock); #endif mutex_enter(&dtrace_lock); if (desc->dtargd_id > dtrace_nprobes) { mutex_exit(&dtrace_lock); #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_provider_lock); return (EINVAL); } if ((probe = dtrace_probes[desc->dtargd_id - 1]) == NULL) { mutex_exit(&dtrace_lock); #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_provider_lock); return (EINVAL); } mutex_exit(&dtrace_lock); prov = probe->dtpr_provider; if (prov->dtpv_pops.dtps_getargdesc == NULL) { /* * There isn't any typed information for this probe. * Set the argument number to DTRACE_ARGNONE. */ desc->dtargd_ndx = DTRACE_ARGNONE; } else { desc->dtargd_native[0] = '\0'; desc->dtargd_xlate[0] = '\0'; desc->dtargd_mapping = desc->dtargd_ndx; prov->dtpv_pops.dtps_getargdesc(prov->dtpv_arg, probe->dtpr_id, probe->dtpr_arg, desc); } #ifdef illumos mutex_exit(&mod_lock); #endif mutex_exit(&dtrace_provider_lock); return (0); } case DTRACEIOC_PROBEMATCH: case DTRACEIOC_PROBES: { dtrace_probedesc_t *p_desc = (dtrace_probedesc_t *) addr; dtrace_probe_t *probe = NULL; dtrace_probekey_t pkey; dtrace_id_t i; int m = 0; uint32_t priv = 0; uid_t uid = 0; zoneid_t zoneid = 0; DTRACE_IOCTL_PRINTF("%s(%d): %s\n",__func__,__LINE__, cmd == DTRACEIOC_PROBEMATCH ? "DTRACEIOC_PROBEMATCH":"DTRACEIOC_PROBES"); p_desc->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; p_desc->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; p_desc->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; p_desc->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; /* * Before we attempt to match this probe, we want to give * all providers the opportunity to provide it. */ if (p_desc->dtpd_id == DTRACE_IDNONE) { mutex_enter(&dtrace_provider_lock); dtrace_probe_provide(p_desc, NULL); mutex_exit(&dtrace_provider_lock); p_desc->dtpd_id++; } if (cmd == DTRACEIOC_PROBEMATCH) { dtrace_probekey(p_desc, &pkey); pkey.dtpk_id = DTRACE_IDNONE; } dtrace_cred2priv(td->td_ucred, &priv, &uid, &zoneid); mutex_enter(&dtrace_lock); if (cmd == DTRACEIOC_PROBEMATCH) { for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) { if ((probe = dtrace_probes[i - 1]) != NULL && (m = dtrace_match_probe(probe, &pkey, priv, uid, zoneid)) != 0) break; } if (m < 0) { mutex_exit(&dtrace_lock); return (EINVAL); } } else { for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) { if ((probe = dtrace_probes[i - 1]) != NULL && dtrace_match_priv(probe, priv, uid, zoneid)) break; } } if (probe == NULL) { mutex_exit(&dtrace_lock); return (ESRCH); } dtrace_probe_description(probe, p_desc); mutex_exit(&dtrace_lock); return (0); } case DTRACEIOC_PROVIDER: { dtrace_providerdesc_t *pvd = (dtrace_providerdesc_t *) addr; dtrace_provider_t *pvp; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROVIDER\n",__func__,__LINE__); pvd->dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0'; mutex_enter(&dtrace_provider_lock); for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) { if (strcmp(pvp->dtpv_name, pvd->dtvd_name) == 0) break; } mutex_exit(&dtrace_provider_lock); if (pvp == NULL) return (ESRCH); bcopy(&pvp->dtpv_priv, &pvd->dtvd_priv, sizeof (dtrace_ppriv_t)); bcopy(&pvp->dtpv_attr, &pvd->dtvd_attr, sizeof (dtrace_pattr_t)); return (0); } case DTRACEIOC_REPLICATE: { dtrace_repldesc_t *desc = (dtrace_repldesc_t *) addr; dtrace_probedesc_t *match = &desc->dtrpd_match; dtrace_probedesc_t *create = &desc->dtrpd_create; int err; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_REPLICATE\n",__func__,__LINE__); match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; match->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; create->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; mutex_enter(&dtrace_lock); err = dtrace_enabling_replicate(state, match, create); mutex_exit(&dtrace_lock); return (err); } case DTRACEIOC_STATUS: { dtrace_status_t *stat = (dtrace_status_t *) addr; dtrace_dstate_t *dstate; int i, j; uint64_t nerrs; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STATUS\n",__func__,__LINE__); /* * See the comment in dtrace_state_deadman() for the reason * for setting dts_laststatus to INT64_MAX before setting * it to the correct value. */ state->dts_laststatus = INT64_MAX; dtrace_membar_producer(); state->dts_laststatus = dtrace_gethrtime(); bzero(stat, sizeof (*stat)); mutex_enter(&dtrace_lock); if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) { mutex_exit(&dtrace_lock); return (ENOENT); } if (state->dts_activity == DTRACE_ACTIVITY_DRAINING) stat->dtst_exiting = 1; nerrs = state->dts_errors; dstate = &state->dts_vstate.dtvs_dynvars; for (i = 0; i < NCPU; i++) { #ifndef illumos if (pcpu_find(i) == NULL) continue; #endif dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[i]; stat->dtst_dyndrops += dcpu->dtdsc_drops; stat->dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops; stat->dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops; if (state->dts_buffer[i].dtb_flags & DTRACEBUF_FULL) stat->dtst_filled++; nerrs += state->dts_buffer[i].dtb_errors; for (j = 0; j < state->dts_nspeculations; j++) { dtrace_speculation_t *spec; dtrace_buffer_t *buf; spec = &state->dts_speculations[j]; buf = &spec->dtsp_buffer[i]; stat->dtst_specdrops += buf->dtb_xamot_drops; } } stat->dtst_specdrops_busy = state->dts_speculations_busy; stat->dtst_specdrops_unavail = state->dts_speculations_unavail; stat->dtst_stkstroverflows = state->dts_stkstroverflows; stat->dtst_dblerrors = state->dts_dblerrors; stat->dtst_killed = (state->dts_activity == DTRACE_ACTIVITY_KILLED); stat->dtst_errors = nerrs; mutex_exit(&dtrace_lock); return (0); } case DTRACEIOC_STOP: { int rval; processorid_t *cpuid = (processorid_t *) addr; DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STOP\n",__func__,__LINE__); mutex_enter(&dtrace_lock); rval = dtrace_state_stop(state, cpuid); mutex_exit(&dtrace_lock); return (rval); } default: error = ENOTTY; } return (error); } Index: projects/ipsec/sys/compat/freebsd32/freebsd32_misc.c =================================================================== --- projects/ipsec/sys/compat/freebsd32/freebsd32_misc.c (revision 313312) +++ projects/ipsec/sys/compat/freebsd32/freebsd32_misc.c (revision 313313) @@ -1,3127 +1,3115 @@ /*- * Copyright (c) 2002 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_inet.h" #include "opt_inet6.h" #define __ELF_WORD_SIZE 32 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Must come after sys/malloc.h */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Must come after sys/selinfo.h */ #include /* Must come after sys/selinfo.h */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include FEATURE(compat_freebsd_32bit, "Compatible with 32-bit FreeBSD"); #ifndef __mips__ CTASSERT(sizeof(struct timeval32) == 8); CTASSERT(sizeof(struct timespec32) == 8); CTASSERT(sizeof(struct itimerval32) == 16); #endif CTASSERT(sizeof(struct statfs32) == 256); #ifndef __mips__ CTASSERT(sizeof(struct rusage32) == 72); #endif CTASSERT(sizeof(struct sigaltstack32) == 12); CTASSERT(sizeof(struct kevent32) == 20); CTASSERT(sizeof(struct iovec32) == 8); CTASSERT(sizeof(struct msghdr32) == 28); #ifndef __mips__ CTASSERT(sizeof(struct stat32) == 96); #endif CTASSERT(sizeof(struct sigaction32) == 24); static int freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count); static int freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count); void freebsd32_rusage_out(const struct rusage *s, struct rusage32 *s32) { TV_CP(*s, *s32, ru_utime); TV_CP(*s, *s32, ru_stime); CP(*s, *s32, ru_maxrss); CP(*s, *s32, ru_ixrss); CP(*s, *s32, ru_idrss); CP(*s, *s32, ru_isrss); CP(*s, *s32, ru_minflt); CP(*s, *s32, ru_majflt); CP(*s, *s32, ru_nswap); CP(*s, *s32, ru_inblock); CP(*s, *s32, ru_oublock); CP(*s, *s32, ru_msgsnd); CP(*s, *s32, ru_msgrcv); CP(*s, *s32, ru_nsignals); CP(*s, *s32, ru_nvcsw); CP(*s, *s32, ru_nivcsw); } int freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap) { int error, status; struct rusage32 ru32; struct rusage ru, *rup; if (uap->rusage != NULL) rup = &ru; else rup = NULL; error = kern_wait(td, uap->pid, &status, uap->options, rup); if (error) return (error); if (uap->status != NULL) error = copyout(&status, uap->status, sizeof(status)); if (uap->rusage != NULL && error == 0) { freebsd32_rusage_out(&ru, &ru32); error = copyout(&ru32, uap->rusage, sizeof(ru32)); } return (error); } int freebsd32_wait6(struct thread *td, struct freebsd32_wait6_args *uap) { struct wrusage32 wru32; struct __wrusage wru, *wrup; struct siginfo32 si32; struct __siginfo si, *sip; int error, status; if (uap->wrusage != NULL) wrup = &wru; else wrup = NULL; if (uap->info != NULL) { sip = &si; bzero(sip, sizeof(*sip)); } else sip = NULL; error = kern_wait6(td, uap->idtype, PAIR32TO64(id_t, uap->id), &status, uap->options, wrup, sip); if (error != 0) return (error); if (uap->status != NULL) error = copyout(&status, uap->status, sizeof(status)); if (uap->wrusage != NULL && error == 0) { freebsd32_rusage_out(&wru.wru_self, &wru32.wru_self); freebsd32_rusage_out(&wru.wru_children, &wru32.wru_children); error = copyout(&wru32, uap->wrusage, sizeof(wru32)); } if (uap->info != NULL && error == 0) { siginfo_to_siginfo32 (&si, &si32); error = copyout(&si32, uap->info, sizeof(si32)); } return (error); } #ifdef COMPAT_FREEBSD4 static void copy_statfs(struct statfs *in, struct statfs32 *out) { statfs_scale_blocks(in, INT32_MAX); bzero(out, sizeof(*out)); CP(*in, *out, f_bsize); out->f_iosize = MIN(in->f_iosize, INT32_MAX); CP(*in, *out, f_blocks); CP(*in, *out, f_bfree); CP(*in, *out, f_bavail); out->f_files = MIN(in->f_files, INT32_MAX); out->f_ffree = MIN(in->f_ffree, INT32_MAX); CP(*in, *out, f_fsid); CP(*in, *out, f_owner); CP(*in, *out, f_type); CP(*in, *out, f_flags); out->f_syncwrites = MIN(in->f_syncwrites, INT32_MAX); out->f_asyncwrites = MIN(in->f_asyncwrites, INT32_MAX); strlcpy(out->f_fstypename, in->f_fstypename, MFSNAMELEN); strlcpy(out->f_mntonname, in->f_mntonname, min(MNAMELEN, FREEBSD4_MNAMELEN)); out->f_syncreads = MIN(in->f_syncreads, INT32_MAX); out->f_asyncreads = MIN(in->f_asyncreads, INT32_MAX); strlcpy(out->f_mntfromname, in->f_mntfromname, min(MNAMELEN, FREEBSD4_MNAMELEN)); } #endif #ifdef COMPAT_FREEBSD4 int freebsd4_freebsd32_getfsstat(struct thread *td, struct freebsd4_freebsd32_getfsstat_args *uap) { struct statfs *buf, *sp; struct statfs32 stat32; size_t count, size, copycount; int error; count = uap->bufsize / sizeof(struct statfs32); size = count * sizeof(struct statfs); error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, uap->mode); if (size > 0) { sp = buf; copycount = count; while (copycount > 0 && error == 0) { copy_statfs(sp, &stat32); error = copyout(&stat32, uap->buf, sizeof(stat32)); sp++; uap->buf++; copycount--; } free(buf, M_STATFS); } if (error == 0) td->td_retval[0] = count; return (error); } #endif #ifdef COMPAT_FREEBSD10 int freebsd10_freebsd32_pipe(struct thread *td, struct freebsd10_freebsd32_pipe_args *uap) { return (freebsd10_pipe(td, (struct freebsd10_pipe_args*)uap)); } #endif int freebsd32_sigaltstack(struct thread *td, struct freebsd32_sigaltstack_args *uap) { struct sigaltstack32 s32; struct sigaltstack ss, oss, *ssp; int error; if (uap->ss != NULL) { error = copyin(uap->ss, &s32, sizeof(s32)); if (error) return (error); PTRIN_CP(s32, ss, ss_sp); CP(s32, ss, ss_size); CP(s32, ss, ss_flags); ssp = &ss; } else ssp = NULL; error = kern_sigaltstack(td, ssp, &oss); if (error == 0 && uap->oss != NULL) { PTROUT_CP(oss, s32, ss_sp); CP(oss, s32, ss_size); CP(oss, s32, ss_flags); error = copyout(&s32, uap->oss, sizeof(s32)); } return (error); } /* * Custom version of exec_copyin_args() so that we can translate * the pointers. */ int freebsd32_exec_copyin_args(struct image_args *args, char *fname, enum uio_seg segflg, u_int32_t *argv, u_int32_t *envv) { char *argp, *envp; u_int32_t *p32, arg; size_t length; int error; bzero(args, sizeof(*args)); if (argv == NULL) return (EFAULT); /* * Allocate demand-paged memory for the file name, argument, and * environment strings. */ error = exec_alloc_args(args); if (error != 0) return (error); /* * Copy the file name. */ if (fname != NULL) { args->fname = args->buf; error = (segflg == UIO_SYSSPACE) ? copystr(fname, args->fname, PATH_MAX, &length) : copyinstr(fname, args->fname, PATH_MAX, &length); if (error != 0) goto err_exit; } else length = 0; args->begin_argv = args->buf + length; args->endp = args->begin_argv; args->stringspace = ARG_MAX; /* * extract arguments first */ p32 = argv; for (;;) { error = copyin(p32++, &arg, sizeof(arg)); if (error) goto err_exit; if (arg == 0) break; argp = PTRIN(arg); error = copyinstr(argp, args->endp, args->stringspace, &length); if (error) { if (error == ENAMETOOLONG) error = E2BIG; goto err_exit; } args->stringspace -= length; args->endp += length; args->argc++; } args->begin_envv = args->endp; /* * extract environment strings */ if (envv) { p32 = envv; for (;;) { error = copyin(p32++, &arg, sizeof(arg)); if (error) goto err_exit; if (arg == 0) break; envp = PTRIN(arg); error = copyinstr(envp, args->endp, args->stringspace, &length); if (error) { if (error == ENAMETOOLONG) error = E2BIG; goto err_exit; } args->stringspace -= length; args->endp += length; args->envc++; } } return (0); err_exit: exec_free_args(args); return (error); } int freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap) { struct image_args eargs; struct vmspace *oldvmspace; int error; error = pre_execve(td, &oldvmspace); if (error != 0) return (error); error = freebsd32_exec_copyin_args(&eargs, uap->fname, UIO_USERSPACE, uap->argv, uap->envv); if (error == 0) error = kern_execve(td, &eargs, NULL); post_execve(td, error, oldvmspace); return (error); } int freebsd32_fexecve(struct thread *td, struct freebsd32_fexecve_args *uap) { struct image_args eargs; struct vmspace *oldvmspace; int error; error = pre_execve(td, &oldvmspace); if (error != 0) return (error); error = freebsd32_exec_copyin_args(&eargs, NULL, UIO_SYSSPACE, uap->argv, uap->envv); if (error == 0) { eargs.fd = uap->fd; error = kern_execve(td, &eargs, NULL); } post_execve(td, error, oldvmspace); return (error); } int freebsd32_mprotect(struct thread *td, struct freebsd32_mprotect_args *uap) { struct mprotect_args ap; ap.addr = PTRIN(uap->addr); ap.len = uap->len; ap.prot = uap->prot; #if defined(__amd64__) if (i386_read_exec && (ap.prot & PROT_READ) != 0) ap.prot |= PROT_EXEC; #endif return (sys_mprotect(td, &ap)); } int freebsd32_mmap(struct thread *td, struct freebsd32_mmap_args *uap) { struct mmap_args ap; vm_offset_t addr = (vm_offset_t) uap->addr; vm_size_t len = uap->len; int prot = uap->prot; int flags = uap->flags; int fd = uap->fd; off_t pos = PAIR32TO64(off_t,uap->pos); #if defined(__amd64__) if (i386_read_exec && (prot & PROT_READ)) prot |= PROT_EXEC; #endif ap.addr = (void *) addr; ap.len = len; ap.prot = prot; ap.flags = flags; ap.fd = fd; ap.pos = pos; return (sys_mmap(td, &ap)); } #ifdef COMPAT_FREEBSD6 int freebsd6_freebsd32_mmap(struct thread *td, struct freebsd6_freebsd32_mmap_args *uap) { struct freebsd32_mmap_args ap; ap.addr = uap->addr; ap.len = uap->len; ap.prot = uap->prot; ap.flags = uap->flags; ap.fd = uap->fd; ap.pos1 = uap->pos1; ap.pos2 = uap->pos2; return (freebsd32_mmap(td, &ap)); } #endif int freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap) { struct itimerval itv, oitv, *itvp; struct itimerval32 i32; int error; if (uap->itv != NULL) { error = copyin(uap->itv, &i32, sizeof(i32)); if (error) return (error); TV_CP(i32, itv, it_interval); TV_CP(i32, itv, it_value); itvp = &itv; } else itvp = NULL; error = kern_setitimer(td, uap->which, itvp, &oitv); if (error || uap->oitv == NULL) return (error); TV_CP(oitv, i32, it_interval); TV_CP(oitv, i32, it_value); return (copyout(&i32, uap->oitv, sizeof(i32))); } int freebsd32_getitimer(struct thread *td, struct freebsd32_getitimer_args *uap) { struct itimerval itv; struct itimerval32 i32; int error; error = kern_getitimer(td, uap->which, &itv); if (error || uap->itv == NULL) return (error); TV_CP(itv, i32, it_interval); TV_CP(itv, i32, it_value); return (copyout(&i32, uap->itv, sizeof(i32))); } int freebsd32_select(struct thread *td, struct freebsd32_select_args *uap) { struct timeval32 tv32; struct timeval tv, *tvp; int error; if (uap->tv != NULL) { error = copyin(uap->tv, &tv32, sizeof(tv32)); if (error) return (error); CP(tv32, tv, tv_sec); CP(tv32, tv, tv_usec); tvp = &tv; } else tvp = NULL; /* * XXX Do pointers need PTRIN()? */ return (kern_select(td, uap->nd, uap->in, uap->ou, uap->ex, tvp, sizeof(int32_t) * 8)); } int freebsd32_pselect(struct thread *td, struct freebsd32_pselect_args *uap) { struct timespec32 ts32; struct timespec ts; struct timeval tv, *tvp; sigset_t set, *uset; int error; if (uap->ts != NULL) { error = copyin(uap->ts, &ts32, sizeof(ts32)); if (error != 0) return (error); CP(ts32, ts, tv_sec); CP(ts32, ts, tv_nsec); TIMESPEC_TO_TIMEVAL(&tv, &ts); tvp = &tv; } else tvp = NULL; if (uap->sm != NULL) { error = copyin(uap->sm, &set, sizeof(set)); if (error != 0) return (error); uset = &set; } else uset = NULL; /* * XXX Do pointers need PTRIN()? */ error = kern_pselect(td, uap->nd, uap->in, uap->ou, uap->ex, tvp, uset, sizeof(int32_t) * 8); return (error); } /* * Copy 'count' items into the destination list pointed to by uap->eventlist. */ static int freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count) { struct freebsd32_kevent_args *uap; struct kevent32 ks32[KQ_NEVENTS]; int i, error = 0; KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count)); uap = (struct freebsd32_kevent_args *)arg; for (i = 0; i < count; i++) { CP(kevp[i], ks32[i], ident); CP(kevp[i], ks32[i], filter); CP(kevp[i], ks32[i], flags); CP(kevp[i], ks32[i], fflags); CP(kevp[i], ks32[i], data); PTROUT_CP(kevp[i], ks32[i], udata); } error = copyout(ks32, uap->eventlist, count * sizeof *ks32); if (error == 0) uap->eventlist += count; return (error); } /* * Copy 'count' items from the list pointed to by uap->changelist. */ static int freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count) { struct freebsd32_kevent_args *uap; struct kevent32 ks32[KQ_NEVENTS]; int i, error = 0; KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count)); uap = (struct freebsd32_kevent_args *)arg; error = copyin(uap->changelist, ks32, count * sizeof *ks32); if (error) goto done; uap->changelist += count; for (i = 0; i < count; i++) { CP(ks32[i], kevp[i], ident); CP(ks32[i], kevp[i], filter); CP(ks32[i], kevp[i], flags); CP(ks32[i], kevp[i], fflags); CP(ks32[i], kevp[i], data); PTRIN_CP(ks32[i], kevp[i], udata); } done: return (error); } int freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap) { struct timespec32 ts32; struct timespec ts, *tsp; struct kevent_copyops k_ops = { uap, freebsd32_kevent_copyout, freebsd32_kevent_copyin}; int error; if (uap->timeout) { error = copyin(uap->timeout, &ts32, sizeof(ts32)); if (error) return (error); CP(ts32, ts, tv_sec); CP(ts32, ts, tv_nsec); tsp = &ts; } else tsp = NULL; error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents, &k_ops, tsp); return (error); } int freebsd32_gettimeofday(struct thread *td, struct freebsd32_gettimeofday_args *uap) { struct timeval atv; struct timeval32 atv32; struct timezone rtz; int error = 0; if (uap->tp) { microtime(&atv); CP(atv, atv32, tv_sec); CP(atv, atv32, tv_usec); error = copyout(&atv32, uap->tp, sizeof (atv32)); } if (error == 0 && uap->tzp != NULL) { rtz.tz_minuteswest = tz_minuteswest; rtz.tz_dsttime = tz_dsttime; error = copyout(&rtz, uap->tzp, sizeof (rtz)); } return (error); } int freebsd32_getrusage(struct thread *td, struct freebsd32_getrusage_args *uap) { struct rusage32 s32; struct rusage s; int error; error = kern_getrusage(td, uap->who, &s); if (error) return (error); if (uap->rusage != NULL) { freebsd32_rusage_out(&s, &s32); error = copyout(&s32, uap->rusage, sizeof(s32)); } return (error); } static int freebsd32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) { struct iovec32 iov32; struct iovec *iov; struct uio *uio; u_int iovlen; int error, i; *uiop = NULL; if (iovcnt > UIO_MAXIOV) return (EINVAL); iovlen = iovcnt * sizeof(struct iovec); uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK); iov = (struct iovec *)(uio + 1); for (i = 0; i < iovcnt; i++) { error = copyin(&iovp[i], &iov32, sizeof(struct iovec32)); if (error) { free(uio, M_IOV); return (error); } iov[i].iov_base = PTRIN(iov32.iov_base); iov[i].iov_len = iov32.iov_len; } uio->uio_iov = iov; uio->uio_iovcnt = iovcnt; uio->uio_segflg = UIO_USERSPACE; uio->uio_offset = -1; uio->uio_resid = 0; for (i = 0; i < iovcnt; i++) { if (iov->iov_len > INT_MAX - uio->uio_resid) { free(uio, M_IOV); return (EINVAL); } uio->uio_resid += iov->iov_len; iov++; } *uiop = uio; return (0); } int freebsd32_readv(struct thread *td, struct freebsd32_readv_args *uap) { struct uio *auio; int error; error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio); if (error) return (error); error = kern_readv(td, uap->fd, auio); free(auio, M_IOV); return (error); } int freebsd32_writev(struct thread *td, struct freebsd32_writev_args *uap) { struct uio *auio; int error; error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio); if (error) return (error); error = kern_writev(td, uap->fd, auio); free(auio, M_IOV); return (error); } int freebsd32_preadv(struct thread *td, struct freebsd32_preadv_args *uap) { struct uio *auio; int error; error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio); if (error) return (error); error = kern_preadv(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset)); free(auio, M_IOV); return (error); } int freebsd32_pwritev(struct thread *td, struct freebsd32_pwritev_args *uap) { struct uio *auio; int error; error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio); if (error) return (error); error = kern_pwritev(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset)); free(auio, M_IOV); return (error); } int freebsd32_copyiniov(struct iovec32 *iovp32, u_int iovcnt, struct iovec **iovp, int error) { struct iovec32 iov32; struct iovec *iov; u_int iovlen; int i; *iovp = NULL; if (iovcnt > UIO_MAXIOV) return (error); iovlen = iovcnt * sizeof(struct iovec); iov = malloc(iovlen, M_IOV, M_WAITOK); for (i = 0; i < iovcnt; i++) { error = copyin(&iovp32[i], &iov32, sizeof(struct iovec32)); if (error) { free(iov, M_IOV); return (error); } iov[i].iov_base = PTRIN(iov32.iov_base); iov[i].iov_len = iov32.iov_len; } *iovp = iov; return (0); } static int freebsd32_copyinmsghdr(struct msghdr32 *msg32, struct msghdr *msg) { struct msghdr32 m32; int error; error = copyin(msg32, &m32, sizeof(m32)); if (error) return (error); msg->msg_name = PTRIN(m32.msg_name); msg->msg_namelen = m32.msg_namelen; msg->msg_iov = PTRIN(m32.msg_iov); msg->msg_iovlen = m32.msg_iovlen; msg->msg_control = PTRIN(m32.msg_control); msg->msg_controllen = m32.msg_controllen; msg->msg_flags = m32.msg_flags; return (0); } static int freebsd32_copyoutmsghdr(struct msghdr *msg, struct msghdr32 *msg32) { struct msghdr32 m32; int error; m32.msg_name = PTROUT(msg->msg_name); m32.msg_namelen = msg->msg_namelen; m32.msg_iov = PTROUT(msg->msg_iov); m32.msg_iovlen = msg->msg_iovlen; m32.msg_control = PTROUT(msg->msg_control); m32.msg_controllen = msg->msg_controllen; m32.msg_flags = msg->msg_flags; error = copyout(&m32, msg32, sizeof(m32)); return (error); } #ifndef __mips__ #define FREEBSD32_ALIGNBYTES (sizeof(int) - 1) #else #define FREEBSD32_ALIGNBYTES (sizeof(long) - 1) #endif #define FREEBSD32_ALIGN(p) \ (((u_long)(p) + FREEBSD32_ALIGNBYTES) & ~FREEBSD32_ALIGNBYTES) #define FREEBSD32_CMSG_SPACE(l) \ (FREEBSD32_ALIGN(sizeof(struct cmsghdr)) + FREEBSD32_ALIGN(l)) #define FREEBSD32_CMSG_DATA(cmsg) ((unsigned char *)(cmsg) + \ FREEBSD32_ALIGN(sizeof(struct cmsghdr))) static int freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf *control) { struct cmsghdr *cm; void *data; socklen_t clen, datalen; int error; caddr_t ctlbuf; int len, maxlen, copylen; struct mbuf *m; error = 0; len = msg->msg_controllen; maxlen = msg->msg_controllen; msg->msg_controllen = 0; m = control; ctlbuf = msg->msg_control; while (m && len > 0) { cm = mtod(m, struct cmsghdr *); clen = m->m_len; while (cm != NULL) { if (sizeof(struct cmsghdr) > clen || cm->cmsg_len > clen) { error = EINVAL; break; } data = CMSG_DATA(cm); datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; /* Adjust message length */ cm->cmsg_len = FREEBSD32_ALIGN(sizeof(struct cmsghdr)) + datalen; /* Copy cmsghdr */ copylen = sizeof(struct cmsghdr); if (len < copylen) { msg->msg_flags |= MSG_CTRUNC; copylen = len; } error = copyout(cm,ctlbuf,copylen); if (error) goto exit; ctlbuf += FREEBSD32_ALIGN(copylen); len -= FREEBSD32_ALIGN(copylen); if (len <= 0) break; /* Copy data */ copylen = datalen; if (len < copylen) { msg->msg_flags |= MSG_CTRUNC; copylen = len; } error = copyout(data,ctlbuf,copylen); if (error) goto exit; ctlbuf += FREEBSD32_ALIGN(copylen); len -= FREEBSD32_ALIGN(copylen); if (CMSG_SPACE(datalen) < clen) { clen -= CMSG_SPACE(datalen); cm = (struct cmsghdr *) ((caddr_t)cm + CMSG_SPACE(datalen)); } else { clen = 0; cm = NULL; } } m = m->m_next; } msg->msg_controllen = (len <= 0) ? maxlen : ctlbuf - (caddr_t)msg->msg_control; exit: return (error); } int freebsd32_recvmsg(td, uap) struct thread *td; struct freebsd32_recvmsg_args /* { int s; struct msghdr32 *msg; int flags; } */ *uap; { struct msghdr msg; struct msghdr32 m32; struct iovec *uiov, *iov; struct mbuf *control = NULL; struct mbuf **controlp; int error; error = copyin(uap->msg, &m32, sizeof(m32)); if (error) return (error); error = freebsd32_copyinmsghdr(uap->msg, &msg); if (error) return (error); error = freebsd32_copyiniov(PTRIN(m32.msg_iov), m32.msg_iovlen, &iov, EMSGSIZE); if (error) return (error); msg.msg_flags = uap->flags; uiov = msg.msg_iov; msg.msg_iov = iov; controlp = (msg.msg_control != NULL) ? &control : NULL; error = kern_recvit(td, uap->s, &msg, UIO_USERSPACE, controlp); if (error == 0) { msg.msg_iov = uiov; if (control != NULL) error = freebsd32_copy_msg_out(&msg, control); else msg.msg_controllen = 0; if (error == 0) error = freebsd32_copyoutmsghdr(&msg, uap->msg); } free(iov, M_IOV); if (control != NULL) m_freem(control); return (error); } /* * Copy-in the array of control messages constructed using alignment * and padding suitable for a 32-bit environment and construct an * mbuf using alignment and padding suitable for a 64-bit kernel. * The alignment and padding are defined indirectly by CMSG_DATA(), * CMSG_SPACE() and CMSG_LEN(). */ static int freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen) { struct mbuf *m; void *md; u_int idx, len, msglen; int error; buflen = FREEBSD32_ALIGN(buflen); if (buflen > MCLBYTES) return (EINVAL); /* * Iterate over the buffer and get the length of each message * in there. This has 32-bit alignment and padding. Use it to * determine the length of these messages when using 64-bit * alignment and padding. */ idx = 0; len = 0; while (idx < buflen) { error = copyin(buf + idx, &msglen, sizeof(msglen)); if (error) return (error); if (msglen < sizeof(struct cmsghdr)) return (EINVAL); msglen = FREEBSD32_ALIGN(msglen); if (idx + msglen > buflen) return (EINVAL); idx += msglen; msglen += CMSG_ALIGN(sizeof(struct cmsghdr)) - FREEBSD32_ALIGN(sizeof(struct cmsghdr)); len += CMSG_ALIGN(msglen); } if (len > MCLBYTES) return (EINVAL); m = m_get(M_WAITOK, MT_CONTROL); if (len > MLEN) MCLGET(m, M_WAITOK); m->m_len = len; md = mtod(m, void *); while (buflen > 0) { error = copyin(buf, md, sizeof(struct cmsghdr)); if (error) break; msglen = *(u_int *)md; msglen = FREEBSD32_ALIGN(msglen); /* Modify the message length to account for alignment. */ *(u_int *)md = msglen + CMSG_ALIGN(sizeof(struct cmsghdr)) - FREEBSD32_ALIGN(sizeof(struct cmsghdr)); md = (char *)md + CMSG_ALIGN(sizeof(struct cmsghdr)); buf += FREEBSD32_ALIGN(sizeof(struct cmsghdr)); buflen -= FREEBSD32_ALIGN(sizeof(struct cmsghdr)); msglen -= FREEBSD32_ALIGN(sizeof(struct cmsghdr)); if (msglen > 0) { error = copyin(buf, md, msglen); if (error) break; md = (char *)md + CMSG_ALIGN(msglen); buf += msglen; buflen -= msglen; } } if (error) m_free(m); else *mp = m; return (error); } int freebsd32_sendmsg(struct thread *td, struct freebsd32_sendmsg_args *uap) { struct msghdr msg; struct msghdr32 m32; struct iovec *iov; struct mbuf *control = NULL; struct sockaddr *to = NULL; int error; error = copyin(uap->msg, &m32, sizeof(m32)); if (error) return (error); error = freebsd32_copyinmsghdr(uap->msg, &msg); if (error) return (error); error = freebsd32_copyiniov(PTRIN(m32.msg_iov), m32.msg_iovlen, &iov, EMSGSIZE); if (error) return (error); msg.msg_iov = iov; if (msg.msg_name != NULL) { error = getsockaddr(&to, msg.msg_name, msg.msg_namelen); if (error) { to = NULL; goto out; } msg.msg_name = to; } if (msg.msg_control) { if (msg.msg_controllen < sizeof(struct cmsghdr)) { error = EINVAL; goto out; } error = freebsd32_copyin_control(&control, msg.msg_control, msg.msg_controllen); if (error) goto out; msg.msg_control = NULL; msg.msg_controllen = 0; } error = kern_sendit(td, uap->s, &msg, uap->flags, control, UIO_USERSPACE); out: free(iov, M_IOV); if (to) free(to, M_SONAME); return (error); } int freebsd32_recvfrom(struct thread *td, struct freebsd32_recvfrom_args *uap) { struct msghdr msg; struct iovec aiov; int error; if (uap->fromlenaddr) { error = copyin(PTRIN(uap->fromlenaddr), &msg.msg_namelen, sizeof(msg.msg_namelen)); if (error) return (error); } else { msg.msg_namelen = 0; } msg.msg_name = PTRIN(uap->from); msg.msg_iov = &aiov; msg.msg_iovlen = 1; aiov.iov_base = PTRIN(uap->buf); aiov.iov_len = uap->len; msg.msg_control = NULL; msg.msg_flags = uap->flags; error = kern_recvit(td, uap->s, &msg, UIO_USERSPACE, NULL); if (error == 0 && uap->fromlenaddr) error = copyout(&msg.msg_namelen, PTRIN(uap->fromlenaddr), sizeof (msg.msg_namelen)); return (error); } int freebsd32_settimeofday(struct thread *td, struct freebsd32_settimeofday_args *uap) { struct timeval32 tv32; struct timeval tv, *tvp; struct timezone tz, *tzp; int error; if (uap->tv) { error = copyin(uap->tv, &tv32, sizeof(tv32)); if (error) return (error); CP(tv32, tv, tv_sec); CP(tv32, tv, tv_usec); tvp = &tv; } else tvp = NULL; if (uap->tzp) { error = copyin(uap->tzp, &tz, sizeof(tz)); if (error) return (error); tzp = &tz; } else tzp = NULL; return (kern_settimeofday(td, tvp, tzp)); } int freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap) { struct timeval32 s32[2]; struct timeval s[2], *sp; int error; if (uap->tptr != NULL) { error = copyin(uap->tptr, s32, sizeof(s32)); if (error) return (error); CP(s32[0], s[0], tv_sec); CP(s32[0], s[0], tv_usec); CP(s32[1], s[1], tv_sec); CP(s32[1], s[1], tv_usec); sp = s; } else sp = NULL; return (kern_utimesat(td, AT_FDCWD, uap->path, UIO_USERSPACE, sp, UIO_SYSSPACE)); } int freebsd32_lutimes(struct thread *td, struct freebsd32_lutimes_args *uap) { struct timeval32 s32[2]; struct timeval s[2], *sp; int error; if (uap->tptr != NULL) { error = copyin(uap->tptr, s32, sizeof(s32)); if (error) return (error); CP(s32[0], s[0], tv_sec); CP(s32[0], s[0], tv_usec); CP(s32[1], s[1], tv_sec); CP(s32[1], s[1], tv_usec); sp = s; } else sp = NULL; return (kern_lutimes(td, uap->path, UIO_USERSPACE, sp, UIO_SYSSPACE)); } int freebsd32_futimes(struct thread *td, struct freebsd32_futimes_args *uap) { struct timeval32 s32[2]; struct timeval s[2], *sp; int error; if (uap->tptr != NULL) { error = copyin(uap->tptr, s32, sizeof(s32)); if (error) return (error); CP(s32[0], s[0], tv_sec); CP(s32[0], s[0], tv_usec); CP(s32[1], s[1], tv_sec); CP(s32[1], s[1], tv_usec); sp = s; } else sp = NULL; return (kern_futimes(td, uap->fd, sp, UIO_SYSSPACE)); } int freebsd32_futimesat(struct thread *td, struct freebsd32_futimesat_args *uap) { struct timeval32 s32[2]; struct timeval s[2], *sp; int error; if (uap->times != NULL) { error = copyin(uap->times, s32, sizeof(s32)); if (error) return (error); CP(s32[0], s[0], tv_sec); CP(s32[0], s[0], tv_usec); CP(s32[1], s[1], tv_sec); CP(s32[1], s[1], tv_usec); sp = s; } else sp = NULL; return (kern_utimesat(td, uap->fd, uap->path, UIO_USERSPACE, sp, UIO_SYSSPACE)); } int freebsd32_futimens(struct thread *td, struct freebsd32_futimens_args *uap) { struct timespec32 ts32[2]; struct timespec ts[2], *tsp; int error; if (uap->times != NULL) { error = copyin(uap->times, ts32, sizeof(ts32)); if (error) return (error); CP(ts32[0], ts[0], tv_sec); CP(ts32[0], ts[0], tv_nsec); CP(ts32[1], ts[1], tv_sec); CP(ts32[1], ts[1], tv_nsec); tsp = ts; } else tsp = NULL; return (kern_futimens(td, uap->fd, tsp, UIO_SYSSPACE)); } int freebsd32_utimensat(struct thread *td, struct freebsd32_utimensat_args *uap) { struct timespec32 ts32[2]; struct timespec ts[2], *tsp; int error; if (uap->times != NULL) { error = copyin(uap->times, ts32, sizeof(ts32)); if (error) return (error); CP(ts32[0], ts[0], tv_sec); CP(ts32[0], ts[0], tv_nsec); CP(ts32[1], ts[1], tv_sec); CP(ts32[1], ts[1], tv_nsec); tsp = ts; } else tsp = NULL; return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE, tsp, UIO_SYSSPACE, uap->flag)); } int freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap) { struct timeval32 tv32; struct timeval delta, olddelta, *deltap; int error; if (uap->delta) { error = copyin(uap->delta, &tv32, sizeof(tv32)); if (error) return (error); CP(tv32, delta, tv_sec); CP(tv32, delta, tv_usec); deltap = δ } else deltap = NULL; error = kern_adjtime(td, deltap, &olddelta); if (uap->olddelta && error == 0) { CP(olddelta, tv32, tv_sec); CP(olddelta, tv32, tv_usec); error = copyout(&tv32, uap->olddelta, sizeof(tv32)); } return (error); } #ifdef COMPAT_FREEBSD4 int freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_args *uap) { struct statfs32 s32; struct statfs *sp; int error; sp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_statfs(td, uap->path, UIO_USERSPACE, sp); if (error == 0) { copy_statfs(sp, &s32); error = copyout(&s32, uap->buf, sizeof(s32)); } free(sp, M_STATFS); return (error); } #endif #ifdef COMPAT_FREEBSD4 int freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap) { struct statfs32 s32; struct statfs *sp; int error; sp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_fstatfs(td, uap->fd, sp); if (error == 0) { copy_statfs(sp, &s32); error = copyout(&s32, uap->buf, sizeof(s32)); } free(sp, M_STATFS); return (error); } #endif #ifdef COMPAT_FREEBSD4 int freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap) { struct statfs32 s32; struct statfs *sp; fhandle_t fh; int error; if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0) return (error); sp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_fhstatfs(td, fh, sp); if (error == 0) { copy_statfs(sp, &s32); error = copyout(&s32, uap->buf, sizeof(s32)); } free(sp, M_STATFS); return (error); } #endif int freebsd32_pread(struct thread *td, struct freebsd32_pread_args *uap) { return (kern_pread(td, uap->fd, uap->buf, uap->nbyte, PAIR32TO64(off_t, uap->offset))); } int freebsd32_pwrite(struct thread *td, struct freebsd32_pwrite_args *uap) { return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, PAIR32TO64(off_t, uap->offset))); } #ifdef COMPAT_43 int ofreebsd32_lseek(struct thread *td, struct ofreebsd32_lseek_args *uap) { return (kern_lseek(td, uap->fd, uap->offset, uap->whence)); } #endif int freebsd32_lseek(struct thread *td, struct freebsd32_lseek_args *uap) { int error; off_t pos; error = kern_lseek(td, uap->fd, PAIR32TO64(off_t, uap->offset), uap->whence); /* Expand the quad return into two parts for eax and edx */ pos = td->td_uretoff.tdu_off; td->td_retval[RETVAL_LO] = pos & 0xffffffff; /* %eax */ td->td_retval[RETVAL_HI] = pos >> 32; /* %edx */ return error; } int freebsd32_truncate(struct thread *td, struct freebsd32_truncate_args *uap) { return (kern_truncate(td, uap->path, UIO_USERSPACE, PAIR32TO64(off_t, uap->length))); } int freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap) { return (kern_ftruncate(td, uap->fd, PAIR32TO64(off_t, uap->length))); } #ifdef COMPAT_43 int ofreebsd32_getdirentries(struct thread *td, struct ofreebsd32_getdirentries_args *uap) { struct ogetdirentries_args ap; int error; long loff; int32_t loff_cut; ap.fd = uap->fd; ap.buf = uap->buf; ap.count = uap->count; ap.basep = NULL; error = kern_ogetdirentries(td, &ap, &loff); if (error == 0) { loff_cut = loff; error = copyout(&loff_cut, uap->basep, sizeof(int32_t)); } return (error); } #endif int freebsd32_getdirentries(struct thread *td, struct freebsd32_getdirentries_args *uap) { long base; int32_t base32; int error; error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base, NULL, UIO_USERSPACE); if (error) return (error); if (uap->basep != NULL) { base32 = base; error = copyout(&base32, uap->basep, sizeof(int32_t)); } return (error); } #ifdef COMPAT_FREEBSD6 /* versions with the 'int pad' argument */ int freebsd6_freebsd32_pread(struct thread *td, struct freebsd6_freebsd32_pread_args *uap) { return (kern_pread(td, uap->fd, uap->buf, uap->nbyte, PAIR32TO64(off_t, uap->offset))); } int freebsd6_freebsd32_pwrite(struct thread *td, struct freebsd6_freebsd32_pwrite_args *uap) { return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, PAIR32TO64(off_t, uap->offset))); } int freebsd6_freebsd32_lseek(struct thread *td, struct freebsd6_freebsd32_lseek_args *uap) { int error; off_t pos; error = kern_lseek(td, uap->fd, PAIR32TO64(off_t, uap->offset), uap->whence); /* Expand the quad return into two parts for eax and edx */ pos = *(off_t *)(td->td_retval); td->td_retval[RETVAL_LO] = pos & 0xffffffff; /* %eax */ td->td_retval[RETVAL_HI] = pos >> 32; /* %edx */ return error; } int freebsd6_freebsd32_truncate(struct thread *td, struct freebsd6_freebsd32_truncate_args *uap) { return (kern_truncate(td, uap->path, UIO_USERSPACE, PAIR32TO64(off_t, uap->length))); } int freebsd6_freebsd32_ftruncate(struct thread *td, struct freebsd6_freebsd32_ftruncate_args *uap) { return (kern_ftruncate(td, uap->fd, PAIR32TO64(off_t, uap->length))); } #endif /* COMPAT_FREEBSD6 */ struct sf_hdtr32 { uint32_t headers; int hdr_cnt; uint32_t trailers; int trl_cnt; }; static int freebsd32_do_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap, int compat) { struct sf_hdtr32 hdtr32; struct sf_hdtr hdtr; struct uio *hdr_uio, *trl_uio; struct file *fp; cap_rights_t rights; struct iovec32 *iov32; off_t offset, sbytes; int error; offset = PAIR32TO64(off_t, uap->offset); if (offset < 0) return (EINVAL); hdr_uio = trl_uio = NULL; if (uap->hdtr != NULL) { error = copyin(uap->hdtr, &hdtr32, sizeof(hdtr32)); if (error) goto out; PTRIN_CP(hdtr32, hdtr, headers); CP(hdtr32, hdtr, hdr_cnt); PTRIN_CP(hdtr32, hdtr, trailers); CP(hdtr32, hdtr, trl_cnt); if (hdtr.headers != NULL) { iov32 = PTRIN(hdtr32.headers); error = freebsd32_copyinuio(iov32, hdtr32.hdr_cnt, &hdr_uio); if (error) goto out; #ifdef COMPAT_FREEBSD4 /* * In FreeBSD < 5.0 the nbytes to send also included * the header. If compat is specified subtract the * header size from nbytes. */ if (compat) { if (uap->nbytes > hdr_uio->uio_resid) uap->nbytes -= hdr_uio->uio_resid; else uap->nbytes = 0; } #endif } if (hdtr.trailers != NULL) { iov32 = PTRIN(hdtr32.trailers); error = freebsd32_copyinuio(iov32, hdtr32.trl_cnt, &trl_uio); if (error) goto out; } } AUDIT_ARG_FD(uap->fd); if ((error = fget_read(td, uap->fd, cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) goto out; error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, offset, uap->nbytes, &sbytes, uap->flags, td); fdrop(fp, td); if (uap->sbytes != NULL) copyout(&sbytes, uap->sbytes, sizeof(off_t)); out: if (hdr_uio) free(hdr_uio, M_IOV); if (trl_uio) free(trl_uio, M_IOV); return (error); } #ifdef COMPAT_FREEBSD4 int freebsd4_freebsd32_sendfile(struct thread *td, struct freebsd4_freebsd32_sendfile_args *uap) { return (freebsd32_do_sendfile(td, (struct freebsd32_sendfile_args *)uap, 1)); } #endif int freebsd32_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap) { return (freebsd32_do_sendfile(td, uap, 0)); } static void copy_stat(struct stat *in, struct stat32 *out) { CP(*in, *out, st_dev); CP(*in, *out, st_ino); CP(*in, *out, st_mode); CP(*in, *out, st_nlink); CP(*in, *out, st_uid); CP(*in, *out, st_gid); CP(*in, *out, st_rdev); TS_CP(*in, *out, st_atim); TS_CP(*in, *out, st_mtim); TS_CP(*in, *out, st_ctim); CP(*in, *out, st_size); CP(*in, *out, st_blocks); CP(*in, *out, st_blksize); CP(*in, *out, st_flags); CP(*in, *out, st_gen); TS_CP(*in, *out, st_birthtim); } #ifdef COMPAT_43 static void copy_ostat(struct stat *in, struct ostat32 *out) { CP(*in, *out, st_dev); CP(*in, *out, st_ino); CP(*in, *out, st_mode); CP(*in, *out, st_nlink); CP(*in, *out, st_uid); CP(*in, *out, st_gid); CP(*in, *out, st_rdev); CP(*in, *out, st_size); TS_CP(*in, *out, st_atim); TS_CP(*in, *out, st_mtim); TS_CP(*in, *out, st_ctim); CP(*in, *out, st_blksize); CP(*in, *out, st_blocks); CP(*in, *out, st_flags); CP(*in, *out, st_gen); } #endif int freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap) { struct stat sb; struct stat32 sb32; int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb, NULL); if (error) return (error); copy_stat(&sb, &sb32); error = copyout(&sb32, uap->ub, sizeof (sb32)); return (error); } #ifdef COMPAT_43 int ofreebsd32_stat(struct thread *td, struct ofreebsd32_stat_args *uap) { struct stat sb; struct ostat32 sb32; int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb, NULL); if (error) return (error); copy_ostat(&sb, &sb32); error = copyout(&sb32, uap->ub, sizeof (sb32)); return (error); } #endif int freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap) { struct stat ub; struct stat32 ub32; int error; error = kern_fstat(td, uap->fd, &ub); if (error) return (error); copy_stat(&ub, &ub32); error = copyout(&ub32, uap->ub, sizeof(ub32)); return (error); } #ifdef COMPAT_43 int ofreebsd32_fstat(struct thread *td, struct ofreebsd32_fstat_args *uap) { struct stat ub; struct ostat32 ub32; int error; error = kern_fstat(td, uap->fd, &ub); if (error) return (error); copy_ostat(&ub, &ub32); error = copyout(&ub32, uap->ub, sizeof(ub32)); return (error); } #endif int freebsd32_fstatat(struct thread *td, struct freebsd32_fstatat_args *uap) { struct stat ub; struct stat32 ub32; int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE, &ub, NULL); if (error) return (error); copy_stat(&ub, &ub32); error = copyout(&ub32, uap->buf, sizeof(ub32)); return (error); } int freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap) { struct stat sb; struct stat32 sb32; int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, UIO_USERSPACE, &sb, NULL); if (error) return (error); copy_stat(&sb, &sb32); error = copyout(&sb32, uap->ub, sizeof (sb32)); return (error); } #ifdef COMPAT_43 int ofreebsd32_lstat(struct thread *td, struct ofreebsd32_lstat_args *uap) { struct stat sb; struct ostat32 sb32; int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, UIO_USERSPACE, &sb, NULL); if (error) return (error); copy_ostat(&sb, &sb32); error = copyout(&sb32, uap->ub, sizeof (sb32)); return (error); } #endif int freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap) { int error, name[CTL_MAXNAME]; size_t j, oldlen; uint32_t tmp; if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) return (EINVAL); error = copyin(uap->name, name, uap->namelen * sizeof(int)); if (error) return (error); if (uap->oldlenp) { error = fueword32(uap->oldlenp, &tmp); oldlen = tmp; } else { oldlen = 0; } if (error != 0) return (EFAULT); error = userland_sysctl(td, name, uap->namelen, uap->old, &oldlen, 1, uap->new, uap->newlen, &j, SCTL_MASK32); if (error && error != ENOMEM) return (error); if (uap->oldlenp) suword32(uap->oldlenp, j); return (0); } int freebsd32_jail(struct thread *td, struct freebsd32_jail_args *uap) { uint32_t version; int error; struct jail j; error = copyin(uap->jail, &version, sizeof(uint32_t)); if (error) return (error); switch (version) { case 0: { /* FreeBSD single IPv4 jails. */ struct jail32_v0 j32_v0; bzero(&j, sizeof(struct jail)); error = copyin(uap->jail, &j32_v0, sizeof(struct jail32_v0)); if (error) return (error); CP(j32_v0, j, version); PTRIN_CP(j32_v0, j, path); PTRIN_CP(j32_v0, j, hostname); j.ip4s = htonl(j32_v0.ip_number); /* jail_v0 is host order */ break; } case 1: /* * Version 1 was used by multi-IPv4 jail implementations * that never made it into the official kernel. */ return (EINVAL); case 2: /* JAIL_API_VERSION */ { /* FreeBSD multi-IPv4/IPv6,noIP jails. */ struct jail32 j32; error = copyin(uap->jail, &j32, sizeof(struct jail32)); if (error) return (error); CP(j32, j, version); PTRIN_CP(j32, j, path); PTRIN_CP(j32, j, hostname); PTRIN_CP(j32, j, jailname); CP(j32, j, ip4s); CP(j32, j, ip6s); PTRIN_CP(j32, j, ip4); PTRIN_CP(j32, j, ip6); break; } default: /* Sci-Fi jails are not supported, sorry. */ return (EINVAL); } return (kern_jail(td, &j)); } int freebsd32_jail_set(struct thread *td, struct freebsd32_jail_set_args *uap) { struct uio *auio; int error; /* Check that we have an even number of iovecs. */ if (uap->iovcnt & 1) return (EINVAL); error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio); if (error) return (error); error = kern_jail_set(td, auio, uap->flags); free(auio, M_IOV); return (error); } int freebsd32_jail_get(struct thread *td, struct freebsd32_jail_get_args *uap) { struct iovec32 iov32; struct uio *auio; int error, i; /* Check that we have an even number of iovecs. */ if (uap->iovcnt & 1) return (EINVAL); error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio); if (error) return (error); error = kern_jail_get(td, auio, uap->flags); if (error == 0) for (i = 0; i < uap->iovcnt; i++) { PTROUT_CP(auio->uio_iov[i], iov32, iov_base); CP(auio->uio_iov[i], iov32, iov_len); error = copyout(&iov32, uap->iovp + i, sizeof(iov32)); if (error != 0) break; } free(auio, M_IOV); return (error); } int freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap) { struct sigaction32 s32; struct sigaction sa, osa, *sap; int error; if (uap->act) { error = copyin(uap->act, &s32, sizeof(s32)); if (error) return (error); sa.sa_handler = PTRIN(s32.sa_u); CP(s32, sa, sa_flags); CP(s32, sa, sa_mask); sap = &sa; } else sap = NULL; error = kern_sigaction(td, uap->sig, sap, &osa, 0); if (error == 0 && uap->oact != NULL) { s32.sa_u = PTROUT(osa.sa_handler); CP(osa, s32, sa_flags); CP(osa, s32, sa_mask); error = copyout(&s32, uap->oact, sizeof(s32)); } return (error); } #ifdef COMPAT_FREEBSD4 int freebsd4_freebsd32_sigaction(struct thread *td, struct freebsd4_freebsd32_sigaction_args *uap) { struct sigaction32 s32; struct sigaction sa, osa, *sap; int error; if (uap->act) { error = copyin(uap->act, &s32, sizeof(s32)); if (error) return (error); sa.sa_handler = PTRIN(s32.sa_u); CP(s32, sa, sa_flags); CP(s32, sa, sa_mask); sap = &sa; } else sap = NULL; error = kern_sigaction(td, uap->sig, sap, &osa, KSA_FREEBSD4); if (error == 0 && uap->oact != NULL) { s32.sa_u = PTROUT(osa.sa_handler); CP(osa, s32, sa_flags); CP(osa, s32, sa_mask); error = copyout(&s32, uap->oact, sizeof(s32)); } return (error); } #endif #ifdef COMPAT_43 struct osigaction32 { u_int32_t sa_u; osigset_t sa_mask; int sa_flags; }; #define ONSIG 32 int ofreebsd32_sigaction(struct thread *td, struct ofreebsd32_sigaction_args *uap) { struct osigaction32 s32; struct sigaction sa, osa, *sap; int error; if (uap->signum <= 0 || uap->signum >= ONSIG) return (EINVAL); if (uap->nsa) { error = copyin(uap->nsa, &s32, sizeof(s32)); if (error) return (error); sa.sa_handler = PTRIN(s32.sa_u); CP(s32, sa, sa_flags); OSIG2SIG(s32.sa_mask, sa.sa_mask); sap = &sa; } else sap = NULL; error = kern_sigaction(td, uap->signum, sap, &osa, KSA_OSIGSET); if (error == 0 && uap->osa != NULL) { s32.sa_u = PTROUT(osa.sa_handler); CP(osa, s32, sa_flags); SIG2OSIG(osa.sa_mask, s32.sa_mask); error = copyout(&s32, uap->osa, sizeof(s32)); } return (error); } int ofreebsd32_sigprocmask(struct thread *td, struct ofreebsd32_sigprocmask_args *uap) { sigset_t set, oset; int error; OSIG2SIG(uap->mask, set); error = kern_sigprocmask(td, uap->how, &set, &oset, SIGPROCMASK_OLD); SIG2OSIG(oset, td->td_retval[0]); return (error); } int ofreebsd32_sigpending(struct thread *td, struct ofreebsd32_sigpending_args *uap) { struct proc *p = td->td_proc; sigset_t siglist; PROC_LOCK(p); siglist = p->p_siglist; SIGSETOR(siglist, td->td_siglist); PROC_UNLOCK(p); SIG2OSIG(siglist, td->td_retval[0]); return (0); } struct sigvec32 { u_int32_t sv_handler; int sv_mask; int sv_flags; }; int ofreebsd32_sigvec(struct thread *td, struct ofreebsd32_sigvec_args *uap) { struct sigvec32 vec; struct sigaction sa, osa, *sap; int error; if (uap->signum <= 0 || uap->signum >= ONSIG) return (EINVAL); if (uap->nsv) { error = copyin(uap->nsv, &vec, sizeof(vec)); if (error) return (error); sa.sa_handler = PTRIN(vec.sv_handler); OSIG2SIG(vec.sv_mask, sa.sa_mask); sa.sa_flags = vec.sv_flags; sa.sa_flags ^= SA_RESTART; sap = &sa; } else sap = NULL; error = kern_sigaction(td, uap->signum, sap, &osa, KSA_OSIGSET); if (error == 0 && uap->osv != NULL) { vec.sv_handler = PTROUT(osa.sa_handler); SIG2OSIG(osa.sa_mask, vec.sv_mask); vec.sv_flags = osa.sa_flags; vec.sv_flags &= ~SA_NOCLDWAIT; vec.sv_flags ^= SA_RESTART; error = copyout(&vec, uap->osv, sizeof(vec)); } return (error); } int ofreebsd32_sigblock(struct thread *td, struct ofreebsd32_sigblock_args *uap) { sigset_t set, oset; OSIG2SIG(uap->mask, set); kern_sigprocmask(td, SIG_BLOCK, &set, &oset, 0); SIG2OSIG(oset, td->td_retval[0]); return (0); } int ofreebsd32_sigsetmask(struct thread *td, struct ofreebsd32_sigsetmask_args *uap) { sigset_t set, oset; OSIG2SIG(uap->mask, set); kern_sigprocmask(td, SIG_SETMASK, &set, &oset, 0); SIG2OSIG(oset, td->td_retval[0]); return (0); } int ofreebsd32_sigsuspend(struct thread *td, struct ofreebsd32_sigsuspend_args *uap) { sigset_t mask; OSIG2SIG(uap->mask, mask); return (kern_sigsuspend(td, mask)); } struct sigstack32 { u_int32_t ss_sp; int ss_onstack; }; int ofreebsd32_sigstack(struct thread *td, struct ofreebsd32_sigstack_args *uap) { struct sigstack32 s32; struct sigstack nss, oss; int error = 0, unss; if (uap->nss != NULL) { error = copyin(uap->nss, &s32, sizeof(s32)); if (error) return (error); nss.ss_sp = PTRIN(s32.ss_sp); CP(s32, nss, ss_onstack); unss = 1; } else { unss = 0; } oss.ss_sp = td->td_sigstk.ss_sp; oss.ss_onstack = sigonstack(cpu_getstack(td)); if (unss) { td->td_sigstk.ss_sp = nss.ss_sp; td->td_sigstk.ss_size = 0; td->td_sigstk.ss_flags |= (nss.ss_onstack & SS_ONSTACK); td->td_pflags |= TDP_ALTSTACK; } if (uap->oss != NULL) { s32.ss_sp = PTROUT(oss.ss_sp); CP(oss, s32, ss_onstack); error = copyout(&s32, uap->oss, sizeof(s32)); } return (error); } #endif int freebsd32_nanosleep(struct thread *td, struct freebsd32_nanosleep_args *uap) { struct timespec32 rmt32, rqt32; struct timespec rmt, rqt; int error; error = copyin(uap->rqtp, &rqt32, sizeof(rqt32)); if (error) return (error); CP(rqt32, rqt, tv_sec); CP(rqt32, rqt, tv_nsec); if (uap->rmtp && !useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) return (EFAULT); error = kern_nanosleep(td, &rqt, &rmt); if (error && uap->rmtp) { int error2; CP(rmt, rmt32, tv_sec); CP(rmt, rmt32, tv_nsec); error2 = copyout(&rmt32, uap->rmtp, sizeof(rmt32)); if (error2) error = error2; } return (error); } int freebsd32_clock_gettime(struct thread *td, struct freebsd32_clock_gettime_args *uap) { struct timespec ats; struct timespec32 ats32; int error; error = kern_clock_gettime(td, uap->clock_id, &ats); if (error == 0) { CP(ats, ats32, tv_sec); CP(ats, ats32, tv_nsec); error = copyout(&ats32, uap->tp, sizeof(ats32)); } return (error); } int freebsd32_clock_settime(struct thread *td, struct freebsd32_clock_settime_args *uap) { struct timespec ats; struct timespec32 ats32; int error; error = copyin(uap->tp, &ats32, sizeof(ats32)); if (error) return (error); CP(ats32, ats, tv_sec); CP(ats32, ats, tv_nsec); return (kern_clock_settime(td, uap->clock_id, &ats)); } int freebsd32_clock_getres(struct thread *td, struct freebsd32_clock_getres_args *uap) { struct timespec ts; struct timespec32 ts32; int error; if (uap->tp == NULL) return (0); error = kern_clock_getres(td, uap->clock_id, &ts); if (error == 0) { CP(ts, ts32, tv_sec); CP(ts, ts32, tv_nsec); error = copyout(&ts32, uap->tp, sizeof(ts32)); } return (error); } int freebsd32_ktimer_create(struct thread *td, struct freebsd32_ktimer_create_args *uap) { struct sigevent32 ev32; struct sigevent ev, *evp; int error, id; if (uap->evp == NULL) { evp = NULL; } else { evp = &ev; error = copyin(uap->evp, &ev32, sizeof(ev32)); if (error != 0) return (error); error = convert_sigevent32(&ev32, &ev); if (error != 0) return (error); } error = kern_ktimer_create(td, uap->clock_id, evp, &id, -1); if (error == 0) { error = copyout(&id, uap->timerid, sizeof(int)); if (error != 0) kern_ktimer_delete(td, id); } return (error); } int freebsd32_ktimer_settime(struct thread *td, struct freebsd32_ktimer_settime_args *uap) { struct itimerspec32 val32, oval32; struct itimerspec val, oval, *ovalp; int error; error = copyin(uap->value, &val32, sizeof(val32)); if (error != 0) return (error); ITS_CP(val32, val); ovalp = uap->ovalue != NULL ? &oval : NULL; error = kern_ktimer_settime(td, uap->timerid, uap->flags, &val, ovalp); if (error == 0 && uap->ovalue != NULL) { ITS_CP(oval, oval32); error = copyout(&oval32, uap->ovalue, sizeof(oval32)); } return (error); } int freebsd32_ktimer_gettime(struct thread *td, struct freebsd32_ktimer_gettime_args *uap) { struct itimerspec32 val32; struct itimerspec val; int error; error = kern_ktimer_gettime(td, uap->timerid, &val); if (error == 0) { ITS_CP(val, val32); error = copyout(&val32, uap->value, sizeof(val32)); } return (error); } int freebsd32_clock_getcpuclockid2(struct thread *td, struct freebsd32_clock_getcpuclockid2_args *uap) { clockid_t clk_id; int error; error = kern_clock_getcpuclockid2(td, PAIR32TO64(id_t, uap->id), uap->which, &clk_id); if (error == 0) error = copyout(&clk_id, uap->clock_id, sizeof(clockid_t)); return (error); } int freebsd32_thr_new(struct thread *td, struct freebsd32_thr_new_args *uap) { struct thr_param32 param32; struct thr_param param; int error; if (uap->param_size < 0 || uap->param_size > sizeof(struct thr_param32)) return (EINVAL); bzero(¶m, sizeof(struct thr_param)); bzero(¶m32, sizeof(struct thr_param32)); error = copyin(uap->param, ¶m32, uap->param_size); if (error != 0) return (error); param.start_func = PTRIN(param32.start_func); param.arg = PTRIN(param32.arg); param.stack_base = PTRIN(param32.stack_base); param.stack_size = param32.stack_size; param.tls_base = PTRIN(param32.tls_base); param.tls_size = param32.tls_size; param.child_tid = PTRIN(param32.child_tid); param.parent_tid = PTRIN(param32.parent_tid); param.flags = param32.flags; param.rtp = PTRIN(param32.rtp); param.spare[0] = PTRIN(param32.spare[0]); param.spare[1] = PTRIN(param32.spare[1]); param.spare[2] = PTRIN(param32.spare[2]); return (kern_thr_new(td, ¶m)); } int freebsd32_thr_suspend(struct thread *td, struct freebsd32_thr_suspend_args *uap) { struct timespec32 ts32; struct timespec ts, *tsp; int error; error = 0; tsp = NULL; if (uap->timeout != NULL) { error = copyin((const void *)uap->timeout, (void *)&ts32, sizeof(struct timespec32)); if (error != 0) return (error); ts.tv_sec = ts32.tv_sec; ts.tv_nsec = ts32.tv_nsec; tsp = &ts; } return (kern_thr_suspend(td, tsp)); } void siginfo_to_siginfo32(const siginfo_t *src, struct siginfo32 *dst) { bzero(dst, sizeof(*dst)); dst->si_signo = src->si_signo; dst->si_errno = src->si_errno; dst->si_code = src->si_code; dst->si_pid = src->si_pid; dst->si_uid = src->si_uid; dst->si_status = src->si_status; dst->si_addr = (uintptr_t)src->si_addr; dst->si_value.sival_int = src->si_value.sival_int; dst->si_timerid = src->si_timerid; dst->si_overrun = src->si_overrun; } int freebsd32_sigtimedwait(struct thread *td, struct freebsd32_sigtimedwait_args *uap) { struct timespec32 ts32; struct timespec ts; struct timespec *timeout; sigset_t set; ksiginfo_t ksi; struct siginfo32 si32; int error; if (uap->timeout) { error = copyin(uap->timeout, &ts32, sizeof(ts32)); if (error) return (error); ts.tv_sec = ts32.tv_sec; ts.tv_nsec = ts32.tv_nsec; timeout = &ts; } else timeout = NULL; error = copyin(uap->set, &set, sizeof(set)); if (error) return (error); error = kern_sigtimedwait(td, set, &ksi, timeout); if (error) return (error); if (uap->info) { siginfo_to_siginfo32(&ksi.ksi_info, &si32); error = copyout(&si32, uap->info, sizeof(struct siginfo32)); } if (error == 0) td->td_retval[0] = ksi.ksi_signo; return (error); } /* * MPSAFE */ int freebsd32_sigwaitinfo(struct thread *td, struct freebsd32_sigwaitinfo_args *uap) { ksiginfo_t ksi; struct siginfo32 si32; sigset_t set; int error; error = copyin(uap->set, &set, sizeof(set)); if (error) return (error); error = kern_sigtimedwait(td, set, &ksi, NULL); if (error) return (error); if (uap->info) { siginfo_to_siginfo32(&ksi.ksi_info, &si32); error = copyout(&si32, uap->info, sizeof(struct siginfo32)); } if (error == 0) td->td_retval[0] = ksi.ksi_signo; return (error); } int freebsd32_cpuset_setid(struct thread *td, struct freebsd32_cpuset_setid_args *uap) { return (kern_cpuset_setid(td, uap->which, PAIR32TO64(id_t, uap->id), uap->setid)); } int freebsd32_cpuset_getid(struct thread *td, struct freebsd32_cpuset_getid_args *uap) { return (kern_cpuset_getid(td, uap->level, uap->which, PAIR32TO64(id_t, uap->id), uap->setid)); } int freebsd32_cpuset_getaffinity(struct thread *td, struct freebsd32_cpuset_getaffinity_args *uap) { - struct cpuset_getaffinity_args ap; - ap.level = uap->level; - ap.which = uap->which; - ap.id = PAIR32TO64(id_t,uap->id); - ap.cpusetsize = uap->cpusetsize; - ap.mask = uap->mask; - - return (sys_cpuset_getaffinity(td, &ap)); + return (kern_cpuset_getaffinity(td, uap->level, uap->which, + PAIR32TO64(id_t,uap->id), uap->cpusetsize, uap->mask)); } int freebsd32_cpuset_setaffinity(struct thread *td, struct freebsd32_cpuset_setaffinity_args *uap) { - struct cpuset_setaffinity_args ap; - ap.level = uap->level; - ap.which = uap->which; - ap.id = PAIR32TO64(id_t,uap->id); - ap.cpusetsize = uap->cpusetsize; - ap.mask = uap->mask; - - return (sys_cpuset_setaffinity(td, &ap)); + return (kern_cpuset_setaffinity(td, uap->level, uap->which, + PAIR32TO64(id_t,uap->id), uap->cpusetsize, uap->mask)); } int freebsd32_nmount(struct thread *td, struct freebsd32_nmount_args /* { struct iovec *iovp; unsigned int iovcnt; int flags; } */ *uap) { struct uio *auio; uint64_t flags; int error; /* * Mount flags are now 64-bits. On 32-bit archtectures only * 32-bits are passed in, but from here on everything handles * 64-bit flags correctly. */ flags = uap->flags; AUDIT_ARG_FFLAGS(flags); /* * Filter out MNT_ROOTFS. We do not want clients of nmount() in * userspace to set this flag, but we must filter it out if we want * MNT_UPDATE on the root file system to work. * MNT_ROOTFS should only be set by the kernel when mounting its * root file system. */ flags &= ~MNT_ROOTFS; /* * check that we have an even number of iovec's * and that we have at least two options. */ if ((uap->iovcnt & 1) || (uap->iovcnt < 4)) return (EINVAL); error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio); if (error) return (error); error = vfs_donmount(td, flags, auio); free(auio, M_IOV); return error; } #if 0 int freebsd32_xxx(struct thread *td, struct freebsd32_xxx_args *uap) { struct yyy32 *p32, s32; struct yyy *p = NULL, s; struct xxx_arg ap; int error; if (uap->zzz) { error = copyin(uap->zzz, &s32, sizeof(s32)); if (error) return (error); /* translate in */ p = &s; } error = kern_xxx(td, p); if (error) return (error); if (uap->zzz) { /* translate out */ error = copyout(&s32, p32, sizeof(s32)); } return (error); } #endif int syscall32_register(int *offset, struct sysent *new_sysent, struct sysent *old_sysent, int flags) { if ((flags & ~SY_THR_STATIC) != 0) return (EINVAL); if (*offset == NO_SYSCALL) { int i; for (i = 1; i < SYS_MAXSYSCALL; ++i) if (freebsd32_sysent[i].sy_call == (sy_call_t *)lkmnosys) break; if (i == SYS_MAXSYSCALL) return (ENFILE); *offset = i; } else if (*offset < 0 || *offset >= SYS_MAXSYSCALL) return (EINVAL); else if (freebsd32_sysent[*offset].sy_call != (sy_call_t *)lkmnosys && freebsd32_sysent[*offset].sy_call != (sy_call_t *)lkmressys) return (EEXIST); *old_sysent = freebsd32_sysent[*offset]; freebsd32_sysent[*offset] = *new_sysent; atomic_store_rel_32(&freebsd32_sysent[*offset].sy_thrcnt, flags); return (0); } int syscall32_deregister(int *offset, struct sysent *old_sysent) { if (*offset == 0) return (0); freebsd32_sysent[*offset] = *old_sysent; return (0); } int syscall32_module_handler(struct module *mod, int what, void *arg) { struct syscall_module_data *data = (struct syscall_module_data*)arg; modspecific_t ms; int error; switch (what) { case MOD_LOAD: error = syscall32_register(data->offset, data->new_sysent, &data->old_sysent, SY_THR_STATIC_KLD); if (error) { /* Leave a mark so we know to safely unload below. */ data->offset = NULL; return error; } ms.intval = *data->offset; MOD_XLOCK; module_setspecific(mod, &ms); MOD_XUNLOCK; if (data->chainevh) error = data->chainevh(mod, what, data->chainarg); return (error); case MOD_UNLOAD: /* * MOD_LOAD failed, so just return without calling the * chained handler since we didn't pass along the MOD_LOAD * event. */ if (data->offset == NULL) return (0); if (data->chainevh) { error = data->chainevh(mod, what, data->chainarg); if (error) return (error); } error = syscall32_deregister(data->offset, &data->old_sysent); return (error); default: error = EOPNOTSUPP; if (data->chainevh) error = data->chainevh(mod, what, data->chainarg); return (error); } } int syscall32_helper_register(struct syscall_helper_data *sd, int flags) { struct syscall_helper_data *sd1; int error; for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) { error = syscall32_register(&sd1->syscall_no, &sd1->new_sysent, &sd1->old_sysent, flags); if (error != 0) { syscall32_helper_unregister(sd); return (error); } sd1->registered = 1; } return (0); } int syscall32_helper_unregister(struct syscall_helper_data *sd) { struct syscall_helper_data *sd1; for (sd1 = sd; sd1->registered != 0; sd1++) { syscall32_deregister(&sd1->syscall_no, &sd1->old_sysent); sd1->registered = 0; } return (0); } register_t * freebsd32_copyout_strings(struct image_params *imgp) { int argc, envc, i; u_int32_t *vectp; char *stringp; uintptr_t destp; u_int32_t *stack_base; struct freebsd32_ps_strings *arginfo; char canary[sizeof(long) * 8]; int32_t pagesizes32[MAXPAGESIZES]; size_t execpath_len; int szsigcode; /* * Calculate string base and vector table pointers. * Also deal with signal trampoline code for this exec type. */ if (imgp->execpath != NULL && imgp->auxargs != NULL) execpath_len = strlen(imgp->execpath) + 1; else execpath_len = 0; arginfo = (struct freebsd32_ps_strings *)curproc->p_sysent-> sv_psstrings; if (imgp->proc->p_sysent->sv_sigcode_base == 0) szsigcode = *(imgp->proc->p_sysent->sv_szsigcode); else szsigcode = 0; destp = (uintptr_t)arginfo; /* * install sigcode */ if (szsigcode != 0) { destp -= szsigcode; destp = rounddown2(destp, sizeof(uint32_t)); copyout(imgp->proc->p_sysent->sv_sigcode, (void *)destp, szsigcode); } /* * Copy the image path for the rtld. */ if (execpath_len != 0) { destp -= execpath_len; imgp->execpathp = destp; copyout(imgp->execpath, (void *)destp, execpath_len); } /* * Prepare the canary for SSP. */ arc4rand(canary, sizeof(canary), 0); destp -= sizeof(canary); imgp->canary = destp; copyout(canary, (void *)destp, sizeof(canary)); imgp->canarylen = sizeof(canary); /* * Prepare the pagesizes array. */ for (i = 0; i < MAXPAGESIZES; i++) pagesizes32[i] = (uint32_t)pagesizes[i]; destp -= sizeof(pagesizes32); destp = rounddown2(destp, sizeof(uint32_t)); imgp->pagesizes = destp; copyout(pagesizes32, (void *)destp, sizeof(pagesizes32)); imgp->pagesizeslen = sizeof(pagesizes32); destp -= ARG_MAX - imgp->args->stringspace; destp = rounddown2(destp, sizeof(uint32_t)); /* * If we have a valid auxargs ptr, prepare some room * on the stack. */ if (imgp->auxargs) { /* * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for * lower compatibility. */ imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : (AT_COUNT * 2); /* * The '+ 2' is for the null pointers at the end of each of * the arg and env vector sets,and imgp->auxarg_size is room * for argument of Runtime loader. */ vectp = (u_int32_t *) (destp - (imgp->args->argc + imgp->args->envc + 2 + imgp->auxarg_size + execpath_len) * sizeof(u_int32_t)); } else { /* * The '+ 2' is for the null pointers at the end of each of * the arg and env vector sets */ vectp = (u_int32_t *)(destp - (imgp->args->argc + imgp->args->envc + 2) * sizeof(u_int32_t)); } /* * vectp also becomes our initial stack base */ stack_base = vectp; stringp = imgp->args->begin_argv; argc = imgp->args->argc; envc = imgp->args->envc; /* * Copy out strings - arguments and environment. */ copyout(stringp, (void *)destp, ARG_MAX - imgp->args->stringspace); /* * Fill in "ps_strings" struct for ps, w, etc. */ suword32(&arginfo->ps_argvstr, (u_int32_t)(intptr_t)vectp); suword32(&arginfo->ps_nargvstr, argc); /* * Fill in argument portion of vector table. */ for (; argc > 0; --argc) { suword32(vectp++, (u_int32_t)(intptr_t)destp); while (*stringp++ != 0) destp++; destp++; } /* a null vector table pointer separates the argp's from the envp's */ suword32(vectp++, 0); suword32(&arginfo->ps_envstr, (u_int32_t)(intptr_t)vectp); suword32(&arginfo->ps_nenvstr, envc); /* * Fill in environment portion of vector table. */ for (; envc > 0; --envc) { suword32(vectp++, (u_int32_t)(intptr_t)destp); while (*stringp++ != 0) destp++; destp++; } /* end of vector table is a null pointer */ suword32(vectp, 0); return ((register_t *)stack_base); } int freebsd32_kldstat(struct thread *td, struct freebsd32_kldstat_args *uap) { struct kld_file_stat stat; struct kld32_file_stat stat32; int error, version; if ((error = copyin(&uap->stat->version, &version, sizeof(version))) != 0) return (error); if (version != sizeof(struct kld32_file_stat_1) && version != sizeof(struct kld32_file_stat)) return (EINVAL); error = kern_kldstat(td, uap->fileid, &stat); if (error != 0) return (error); bcopy(&stat.name[0], &stat32.name[0], sizeof(stat.name)); CP(stat, stat32, refs); CP(stat, stat32, id); PTROUT_CP(stat, stat32, address); CP(stat, stat32, size); bcopy(&stat.pathname[0], &stat32.pathname[0], sizeof(stat.pathname)); return (copyout(&stat32, uap->stat, version)); } int freebsd32_posix_fallocate(struct thread *td, struct freebsd32_posix_fallocate_args *uap) { int error; error = kern_posix_fallocate(td, uap->fd, PAIR32TO64(off_t, uap->offset), PAIR32TO64(off_t, uap->len)); return (kern_posix_error(td, error)); } int freebsd32_posix_fadvise(struct thread *td, struct freebsd32_posix_fadvise_args *uap) { int error; error = kern_posix_fadvise(td, uap->fd, PAIR32TO64(off_t, uap->offset), PAIR32TO64(off_t, uap->len), uap->advice); return (kern_posix_error(td, error)); } int convert_sigevent32(struct sigevent32 *sig32, struct sigevent *sig) { CP(*sig32, *sig, sigev_notify); switch (sig->sigev_notify) { case SIGEV_NONE: break; case SIGEV_THREAD_ID: CP(*sig32, *sig, sigev_notify_thread_id); /* FALLTHROUGH */ case SIGEV_SIGNAL: CP(*sig32, *sig, sigev_signo); PTRIN_CP(*sig32, *sig, sigev_value.sival_ptr); break; case SIGEV_KEVENT: CP(*sig32, *sig, sigev_notify_kqueue); CP(*sig32, *sig, sigev_notify_kevent_flags); PTRIN_CP(*sig32, *sig, sigev_value.sival_ptr); break; default: return (EINVAL); } return (0); } int freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap) { void *data; union { struct procctl_reaper_status rs; struct procctl_reaper_pids rp; struct procctl_reaper_kill rk; } x; union { struct procctl_reaper_pids32 rp; } x32; int error, error1, flags; switch (uap->com) { case PROC_SPROTECT: case PROC_TRACE_CTL: case PROC_TRAPCAP_CTL: error = copyin(PTRIN(uap->data), &flags, sizeof(flags)); if (error != 0) return (error); data = &flags; break; case PROC_REAP_ACQUIRE: case PROC_REAP_RELEASE: if (uap->data != NULL) return (EINVAL); data = NULL; break; case PROC_REAP_STATUS: data = &x.rs; break; case PROC_REAP_GETPIDS: error = copyin(uap->data, &x32.rp, sizeof(x32.rp)); if (error != 0) return (error); CP(x32.rp, x.rp, rp_count); PTRIN_CP(x32.rp, x.rp, rp_pids); data = &x.rp; break; case PROC_REAP_KILL: error = copyin(uap->data, &x.rk, sizeof(x.rk)); if (error != 0) return (error); data = &x.rk; break; case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: data = &flags; break; default: return (EINVAL); } error = kern_procctl(td, uap->idtype, PAIR32TO64(id_t, uap->id), uap->com, data); switch (uap->com) { case PROC_REAP_STATUS: if (error == 0) error = copyout(&x.rs, uap->data, sizeof(x.rs)); break; case PROC_REAP_KILL: error1 = copyout(&x.rk, uap->data, sizeof(x.rk)); if (error == 0) error = error1; break; case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: if (error == 0) error = copyout(&flags, uap->data, sizeof(flags)); break; } return (error); } int freebsd32_fcntl(struct thread *td, struct freebsd32_fcntl_args *uap) { long tmp; switch (uap->cmd) { /* * Do unsigned conversion for arg when operation * interprets it as flags or pointer. */ case F_SETLK_REMOTE: case F_SETLKW: case F_SETLK: case F_GETLK: case F_SETFD: case F_SETFL: case F_OGETLK: case F_OSETLK: case F_OSETLKW: tmp = (unsigned int)(uap->arg); break; default: tmp = uap->arg; break; } return (kern_fcntl_freebsd(td, uap->fd, uap->cmd, tmp)); } int freebsd32_ppoll(struct thread *td, struct freebsd32_ppoll_args *uap) { struct timespec32 ts32; struct timespec ts, *tsp; sigset_t set, *ssp; int error; if (uap->ts != NULL) { error = copyin(uap->ts, &ts32, sizeof(ts32)); if (error != 0) return (error); CP(ts32, ts, tv_sec); CP(ts32, ts, tv_nsec); tsp = &ts; } else tsp = NULL; if (uap->set != NULL) { error = copyin(uap->set, &set, sizeof(set)); if (error != 0) return (error); ssp = &set; } else ssp = NULL; return (kern_poll(td, uap->fds, uap->nfds, tsp, ssp)); } Index: projects/ipsec/sys/compat/linux/linux_file.c =================================================================== --- projects/ipsec/sys/compat/linux/linux_file.c (revision 313312) +++ projects/ipsec/sys/compat/linux/linux_file.c (revision 313313) @@ -1,1606 +1,1616 @@ /*- * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef COMPAT_LINUX32 #include #include #else #include #include #endif #include #include #include int linux_creat(struct thread *td, struct linux_creat_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(creat)) printf(ARGS(creat, "%s, %d"), path, args->mode); #endif error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, args->mode); LFREEPATH(path); return (error); } static int linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) { cap_rights_t rights; struct proc *p = td->td_proc; struct file *fp; int fd; int bsd_flags, error; bsd_flags = 0; switch (l_flags & LINUX_O_ACCMODE) { case LINUX_O_WRONLY: bsd_flags |= O_WRONLY; break; case LINUX_O_RDWR: bsd_flags |= O_RDWR; break; default: bsd_flags |= O_RDONLY; } if (l_flags & LINUX_O_NDELAY) bsd_flags |= O_NONBLOCK; if (l_flags & LINUX_O_APPEND) bsd_flags |= O_APPEND; if (l_flags & LINUX_O_SYNC) bsd_flags |= O_FSYNC; if (l_flags & LINUX_O_NONBLOCK) bsd_flags |= O_NONBLOCK; if (l_flags & LINUX_FASYNC) bsd_flags |= O_ASYNC; if (l_flags & LINUX_O_CREAT) bsd_flags |= O_CREAT; if (l_flags & LINUX_O_TRUNC) bsd_flags |= O_TRUNC; if (l_flags & LINUX_O_EXCL) bsd_flags |= O_EXCL; if (l_flags & LINUX_O_NOCTTY) bsd_flags |= O_NOCTTY; if (l_flags & LINUX_O_DIRECT) bsd_flags |= O_DIRECT; if (l_flags & LINUX_O_NOFOLLOW) bsd_flags |= O_NOFOLLOW; if (l_flags & LINUX_O_DIRECTORY) bsd_flags |= O_DIRECTORY; /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode); if (error != 0) goto done; if (bsd_flags & O_NOCTTY) goto done; /* * XXX In between kern_open() and fget(), another process * having the same filedesc could use that fd without * checking below. */ fd = td->td_retval[0]; if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) { if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); goto done; } sx_slock(&proctree_lock); PROC_LOCK(p); if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { PROC_UNLOCK(p); sx_sunlock(&proctree_lock); /* XXXPJD: Verify if TIOCSCTTY is allowed. */ (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, td); } else { PROC_UNLOCK(p); sx_sunlock(&proctree_lock); } fdrop(fp, td); } done: #ifdef DEBUG if (ldebug(open)) printf(LMSG("open returns error %d"), error); #endif LFREEPATH(path); return (error); } int linux_openat(struct thread *td, struct linux_openat_args *args) { char *path; int dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; if (args->flags & LINUX_O_CREAT) LCONVPATH_AT(td, args->filename, &path, 1, dfd); else LCONVPATH_AT(td, args->filename, &path, 0, dfd); #ifdef DEBUG if (ldebug(openat)) printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, path, args->flags, args->mode); #endif return (linux_common_open(td, dfd, path, args->flags, args->mode)); } int linux_open(struct thread *td, struct linux_open_args *args) { char *path; if (args->flags & LINUX_O_CREAT) LCONVPATHCREAT(td, args->path, &path); else LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(open)) printf(ARGS(open, "%s, 0x%x, 0x%x"), path, args->flags, args->mode); #endif return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode)); } int linux_lseek(struct thread *td, struct linux_lseek_args *args) { #ifdef DEBUG if (ldebug(lseek)) printf(ARGS(lseek, "%d, %ld, %d"), args->fdes, (long)args->off, args->whence); #endif return (kern_lseek(td, args->fdes, args->off, args->whence)); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_llseek(struct thread *td, struct linux_llseek_args *args) { int error; off_t off; #ifdef DEBUG if (ldebug(llseek)) printf(ARGS(llseek, "%d, %d:%d, %d"), args->fd, args->ohigh, args->olow, args->whence); #endif off = (args->olow) | (((off_t) args->ohigh) << 32); error = kern_lseek(td, args->fd, off, args->whence); if (error != 0) return (error); error = copyout(td->td_retval, args->res, sizeof(off_t)); if (error != 0) return (error); td->td_retval[0] = 0; return (0); } int linux_readdir(struct thread *td, struct linux_readdir_args *args) { struct linux_getdents_args lda; lda.fd = args->fd; lda.dent = args->dent; lda.count = 1; return (linux_getdents(td, &lda)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ /* * Note that linux_getdents(2) and linux_getdents64(2) have the same * arguments. They only differ in the definition of struct dirent they * operate on. We use this to common the code, with the exception of * accessing struct dirent. Note that linux_readdir(2) is implemented * by means of linux_getdents(2). In this case we never operate on * struct dirent64 and thus don't need to handle it... */ struct l_dirent { l_ulong d_ino; l_off_t d_off; l_ushort d_reclen; char d_name[LINUX_NAME_MAX + 1]; }; struct l_dirent64 { uint64_t d_ino; int64_t d_off; l_ushort d_reclen; u_char d_type; char d_name[LINUX_NAME_MAX + 1]; }; /* * Linux uses the last byte in the dirent buffer to store d_type, * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes. */ #define LINUX_RECLEN(namlen) \ roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong)) #define LINUX_RECLEN64(namlen) \ roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1, \ sizeof(uint64_t)) #define LINUX_MAXRECLEN max(LINUX_RECLEN(LINUX_NAME_MAX), \ LINUX_RECLEN64(LINUX_NAME_MAX)) #define LINUX_DIRBLKSIZ 512 static int getdents_common(struct thread *td, struct linux_getdents64_args *args, int is64bit) { struct dirent *bdp; struct vnode *vp; caddr_t inp, buf; /* BSD-format */ int len, reclen; /* BSD-format */ caddr_t outp; /* Linux-format */ int resid, linuxreclen=0; /* Linux-format */ caddr_t lbuf; /* Linux-format */ cap_rights_t rights; struct file *fp; struct uio auio; struct iovec aiov; off_t off; struct l_dirent *linux_dirent; struct l_dirent64 *linux_dirent64; int buflen, error, eofflag, nbytes, justone; u_long *cookies = NULL, *cookiep; int ncookies; nbytes = args->count; if (nbytes == 1) { /* readdir(2) case. Always struct dirent. */ if (is64bit) return (EINVAL); nbytes = sizeof(*linux_dirent); justone = 1; } else justone = 0; error = getvnode(td, args->fd, cap_rights_init(&rights, CAP_READ), &fp); if (error != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); return (EBADF); } off = foffset_lock(fp, 0); vp = fp->f_vnode; if (vp->v_type != VDIR) { foffset_unlock(fp, off, 0); fdrop(fp, td); return (EINVAL); } buflen = max(LINUX_DIRBLKSIZ, nbytes); buflen = min(buflen, MAXBSIZE); buf = malloc(buflen, M_LINUX, M_WAITOK); lbuf = malloc(LINUX_MAXRECLEN, M_LINUX, M_WAITOK | M_ZERO); vn_lock(vp, LK_SHARED | LK_RETRY); aiov.iov_base = buf; aiov.iov_len = buflen; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_SYSSPACE; auio.uio_td = td; auio.uio_resid = buflen; auio.uio_offset = off; #ifdef MAC /* * Do directory search MAC check using non-cached credentials. */ if ((error = mac_vnode_check_readdir(td->td_ucred, vp))) goto out; #endif /* MAC */ if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies))) goto out; inp = buf; outp = (caddr_t)args->dirent; resid = nbytes; if ((len = buflen - auio.uio_resid) <= 0) goto eof; cookiep = cookies; if (cookies) { /* * When using cookies, the vfs has the option of reading from * a different offset than that supplied (UFS truncates the * offset to a block boundary to make sure that it never reads * partway through a directory entry, even if the directory * has been compacted). */ while (len > 0 && ncookies > 0 && *cookiep <= off) { bdp = (struct dirent *) inp; len -= bdp->d_reclen; inp += bdp->d_reclen; cookiep++; ncookies--; } } while (len > 0) { if (cookiep && ncookies == 0) break; bdp = (struct dirent *) inp; reclen = bdp->d_reclen; if (reclen & 3) { error = EFAULT; goto out; } if (bdp->d_fileno == 0) { inp += reclen; if (cookiep) { off = *cookiep++; ncookies--; } else off += reclen; len -= reclen; continue; } linuxreclen = (is64bit) ? LINUX_RECLEN64(bdp->d_namlen) : LINUX_RECLEN(bdp->d_namlen); if (reclen > len || resid < linuxreclen) { outp++; break; } if (justone) { /* readdir(2) case. */ linux_dirent = (struct l_dirent*)lbuf; linux_dirent->d_ino = bdp->d_fileno; linux_dirent->d_off = (l_off_t)linuxreclen; linux_dirent->d_reclen = (l_ushort)bdp->d_namlen; strlcpy(linux_dirent->d_name, bdp->d_name, linuxreclen - offsetof(struct l_dirent, d_name)); error = copyout(linux_dirent, outp, linuxreclen); } if (is64bit) { linux_dirent64 = (struct l_dirent64*)lbuf; linux_dirent64->d_ino = bdp->d_fileno; linux_dirent64->d_off = (cookiep) ? (l_off_t)*cookiep : (l_off_t)(off + reclen); linux_dirent64->d_reclen = (l_ushort)linuxreclen; linux_dirent64->d_type = bdp->d_type; strlcpy(linux_dirent64->d_name, bdp->d_name, linuxreclen - offsetof(struct l_dirent64, d_name)); error = copyout(linux_dirent64, outp, linuxreclen); } else if (!justone) { linux_dirent = (struct l_dirent*)lbuf; linux_dirent->d_ino = bdp->d_fileno; linux_dirent->d_off = (cookiep) ? (l_off_t)*cookiep : (l_off_t)(off + reclen); linux_dirent->d_reclen = (l_ushort)linuxreclen; /* * Copy d_type to last byte of l_dirent buffer */ lbuf[linuxreclen-1] = bdp->d_type; strlcpy(linux_dirent->d_name, bdp->d_name, linuxreclen - offsetof(struct l_dirent, d_name)-1); error = copyout(linux_dirent, outp, linuxreclen); } if (error) goto out; inp += reclen; if (cookiep) { off = *cookiep++; ncookies--; } else off += reclen; outp += linuxreclen; resid -= linuxreclen; len -= reclen; if (justone) break; } if (outp == (caddr_t)args->dirent) { nbytes = resid; goto eof; } if (justone) nbytes = resid + linuxreclen; eof: td->td_retval[0] = nbytes - resid; out: free(cookies, M_TEMP); VOP_UNLOCK(vp, 0); foffset_unlock(fp, off, 0); fdrop(fp, td); free(buf, M_LINUX); free(lbuf, M_LINUX); return (error); } int linux_getdents(struct thread *td, struct linux_getdents_args *args) { #ifdef DEBUG if (ldebug(getdents)) printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); #endif return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); } int linux_getdents64(struct thread *td, struct linux_getdents64_args *args) { #ifdef DEBUG if (ldebug(getdents64)) printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); #endif return (getdents_common(td, args, 1)); } /* * These exist mainly for hooks for doing /compat/linux translation. */ int linux_access(struct thread *td, struct linux_access_args *args) { char *path; int error; /* linux convention */ if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) return (EINVAL); LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(access)) printf(ARGS(access, "%s, %d"), path, args->amode); #endif error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, args->amode); LFREEPATH(path); return (error); } int linux_faccessat(struct thread *td, struct linux_faccessat_args *args) { char *path; int error, dfd; /* linux convention */ if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) return (EINVAL); dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->filename, &path, dfd); #ifdef DEBUG if (ldebug(access)) printf(ARGS(access, "%s, %d"), path, args->amode); #endif error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode); LFREEPATH(path); return (error); } int linux_unlink(struct thread *td, struct linux_unlink_args *args) { char *path; int error; struct stat st; LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(unlink)) printf(ARGS(unlink, "%s"), path); #endif error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0); if (error == EPERM) { /* Introduce POSIX noncompliant behaviour of Linux */ if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st, NULL) == 0) { if (S_ISDIR(st.st_mode)) error = EISDIR; } } LFREEPATH(path); return (error); } int linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) { char *path; int error, dfd; struct stat st; if (args->flag & ~LINUX_AT_REMOVEDIR) return (EINVAL); dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); #ifdef DEBUG if (ldebug(unlinkat)) printf(ARGS(unlinkat, "%s"), path); #endif if (args->flag & LINUX_AT_REMOVEDIR) error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE); else error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0); if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { /* Introduce POSIX noncompliant behaviour of Linux */ if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode)) error = EISDIR; } LFREEPATH(path); return (error); } int linux_chdir(struct thread *td, struct linux_chdir_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(chdir)) printf(ARGS(chdir, "%s"), path); #endif error = kern_chdir(td, path, UIO_SYSSPACE); LFREEPATH(path); return (error); } int linux_chmod(struct thread *td, struct linux_chmod_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(chmod)) printf(ARGS(chmod, "%s, %d"), path, args->mode); #endif error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode, 0); LFREEPATH(path); return (error); } int linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) { char *path; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->filename, &path, dfd); #ifdef DEBUG if (ldebug(fchmodat)) printf(ARGS(fchmodat, "%s, %d"), path, args->mode); #endif error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); LFREEPATH(path); return (error); } int linux_mkdir(struct thread *td, struct linux_mkdir_args *args) { char *path; int error; LCONVPATHCREAT(td, args->path, &path); #ifdef DEBUG if (ldebug(mkdir)) printf(ARGS(mkdir, "%s, %d"), path, args->mode); #endif error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode); LFREEPATH(path); return (error); } int linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) { char *path; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); #ifdef DEBUG if (ldebug(mkdirat)) printf(ARGS(mkdirat, "%s, %d"), path, args->mode); #endif error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); LFREEPATH(path); return (error); } int linux_rmdir(struct thread *td, struct linux_rmdir_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(rmdir)) printf(ARGS(rmdir, "%s"), path); #endif error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE); LFREEPATH(path); return (error); } int linux_rename(struct thread *td, struct linux_rename_args *args) { char *from, *to; int error; LCONVPATHEXIST(td, args->from, &from); /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); if (to == NULL) { LFREEPATH(from); return (error); } #ifdef DEBUG if (ldebug(rename)) printf(ARGS(rename, "%s, %s"), from, to); #endif error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE); LFREEPATH(from); LFREEPATH(to); return (error); } int linux_renameat(struct thread *td, struct linux_renameat_args *args) { char *from, *to; int error, olddfd, newdfd; olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd); /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); if (to == NULL) { LFREEPATH(from); return (error); } #ifdef DEBUG if (ldebug(renameat)) printf(ARGS(renameat, "%s, %s"), from, to); #endif error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); LFREEPATH(from); LFREEPATH(to); return (error); } int linux_symlink(struct thread *td, struct linux_symlink_args *args) { char *path, *to; int error; LCONVPATHEXIST(td, args->path, &path); /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); if (to == NULL) { LFREEPATH(path); return (error); } #ifdef DEBUG if (ldebug(symlink)) printf(ARGS(symlink, "%s, %s"), path, to); #endif error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE); LFREEPATH(path); LFREEPATH(to); return (error); } int linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) { char *path, *to; int error, dfd; dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; LCONVPATHEXIST_AT(td, args->oldname, &path, dfd); /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); if (to == NULL) { LFREEPATH(path); return (error); } #ifdef DEBUG if (ldebug(symlinkat)) printf(ARGS(symlinkat, "%s, %s"), path, to); #endif error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); LFREEPATH(path); LFREEPATH(to); return (error); } int linux_readlink(struct thread *td, struct linux_readlink_args *args) { char *name; int error; LCONVPATHEXIST(td, args->name, &name); #ifdef DEBUG if (ldebug(readlink)) printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, args->count); #endif error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, args->count); LFREEPATH(name); return (error); } int linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) { char *name; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->path, &name, dfd); #ifdef DEBUG if (ldebug(readlinkat)) printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf, args->bufsiz); #endif error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, args->bufsiz); LFREEPATH(name); return (error); } int linux_truncate(struct thread *td, struct linux_truncate_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(truncate)) printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); #endif error = kern_truncate(td, path, UIO_SYSSPACE, args->length); LFREEPATH(path); return (error); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_truncate64(struct thread *td, struct linux_truncate64_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(truncate64)) printf(ARGS(truncate64, "%s, %jd"), path, args->length); #endif error = kern_truncate(td, path, UIO_SYSSPACE, args->length); LFREEPATH(path); return (error); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) { return (kern_ftruncate(td, args->fd, args->length)); } int linux_link(struct thread *td, struct linux_link_args *args) { char *path, *to; int error; LCONVPATHEXIST(td, args->path, &path); /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); if (to == NULL) { LFREEPATH(path); return (error); } #ifdef DEBUG if (ldebug(link)) printf(ARGS(link, "%s, %s"), path, to); #endif error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE, FOLLOW); LFREEPATH(path); LFREEPATH(to); return (error); } int linux_linkat(struct thread *td, struct linux_linkat_args *args) { char *path, *to; int error, olddfd, newdfd, follow; if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW) return (EINVAL); olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd); /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); if (to == NULL) { LFREEPATH(path); return (error); } #ifdef DEBUG if (ldebug(linkat)) printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path, args->newdfd, to, args->flag); #endif follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW : FOLLOW; error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow); LFREEPATH(path); LFREEPATH(to); return (error); } int linux_fdatasync(td, uap) struct thread *td; struct linux_fdatasync_args *uap; { return (kern_fsync(td, uap->fd, false)); } int linux_pread(struct thread *td, struct linux_pread_args *uap) { cap_rights_t rights; struct vnode *vp; int error; error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, uap->offset); if (error == 0) { /* This seems to violate POSIX but linux does it */ error = fgetvp(td, uap->fd, cap_rights_init(&rights, CAP_PREAD), &vp); if (error != 0) return (error); if (vp->v_type == VDIR) { vrele(vp); return (EISDIR); } vrele(vp); } return (error); } int linux_pwrite(struct thread *td, struct linux_pwrite_args *uap) { return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, uap->offset)); } int linux_mount(struct thread *td, struct linux_mount_args *args) { char fstypename[MFSNAMELEN]; char mntonname[MNAMELEN], mntfromname[MNAMELEN]; int error; int fsflags; error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, NULL); if (error) return (error); error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); if (error) return (error); error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); if (error) return (error); #ifdef DEBUG if (ldebug(mount)) printf(ARGS(mount, "%s, %s, %s"), fstypename, mntfromname, mntonname); #endif if (strcmp(fstypename, "ext2") == 0) { strcpy(fstypename, "ext2fs"); } else if (strcmp(fstypename, "proc") == 0) { strcpy(fstypename, "linprocfs"); } else if (strcmp(fstypename, "vfat") == 0) { strcpy(fstypename, "msdosfs"); } fsflags = 0; if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { /* * Linux SYNC flag is not included; the closest equivalent * FreeBSD has is !ASYNC, which is our default. */ if (args->rwflag & LINUX_MS_RDONLY) fsflags |= MNT_RDONLY; if (args->rwflag & LINUX_MS_NOSUID) fsflags |= MNT_NOSUID; if (args->rwflag & LINUX_MS_NOEXEC) fsflags |= MNT_NOEXEC; if (args->rwflag & LINUX_MS_REMOUNT) fsflags |= MNT_UPDATE; } error = kernel_vmount(fsflags, "fstype", fstypename, "fspath", mntonname, "from", mntfromname, NULL); return (error); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_oldumount(struct thread *td, struct linux_oldumount_args *args) { struct linux_umount_args args2; args2.path = args->path; args2.flags = 0; return (linux_umount(td, &args2)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_umount(struct thread *td, struct linux_umount_args *args) { struct unmount_args bsd; bsd.path = args->path; bsd.flags = args->flags; /* XXX correct? */ return (sys_unmount(td, &bsd)); } /* * fcntl family of syscalls */ struct l_flock { l_short l_type; l_short l_whence; l_off_t l_start; l_off_t l_len; l_pid_t l_pid; } #if defined(__amd64__) && defined(COMPAT_LINUX32) __packed #endif ; static void linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) { switch (linux_flock->l_type) { case LINUX_F_RDLCK: bsd_flock->l_type = F_RDLCK; break; case LINUX_F_WRLCK: bsd_flock->l_type = F_WRLCK; break; case LINUX_F_UNLCK: bsd_flock->l_type = F_UNLCK; break; default: bsd_flock->l_type = -1; break; } bsd_flock->l_whence = linux_flock->l_whence; bsd_flock->l_start = (off_t)linux_flock->l_start; bsd_flock->l_len = (off_t)linux_flock->l_len; bsd_flock->l_pid = (pid_t)linux_flock->l_pid; bsd_flock->l_sysid = 0; } static void bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) { switch (bsd_flock->l_type) { case F_RDLCK: linux_flock->l_type = LINUX_F_RDLCK; break; case F_WRLCK: linux_flock->l_type = LINUX_F_WRLCK; break; case F_UNLCK: linux_flock->l_type = LINUX_F_UNLCK; break; } linux_flock->l_whence = bsd_flock->l_whence; linux_flock->l_start = (l_off_t)bsd_flock->l_start; linux_flock->l_len = (l_off_t)bsd_flock->l_len; linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) struct l_flock64 { l_short l_type; l_short l_whence; l_loff_t l_start; l_loff_t l_len; l_pid_t l_pid; } #if defined(__amd64__) && defined(COMPAT_LINUX32) __packed #endif ; static void linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) { switch (linux_flock->l_type) { case LINUX_F_RDLCK: bsd_flock->l_type = F_RDLCK; break; case LINUX_F_WRLCK: bsd_flock->l_type = F_WRLCK; break; case LINUX_F_UNLCK: bsd_flock->l_type = F_UNLCK; break; default: bsd_flock->l_type = -1; break; } bsd_flock->l_whence = linux_flock->l_whence; bsd_flock->l_start = (off_t)linux_flock->l_start; bsd_flock->l_len = (off_t)linux_flock->l_len; bsd_flock->l_pid = (pid_t)linux_flock->l_pid; bsd_flock->l_sysid = 0; } static void bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) { switch (bsd_flock->l_type) { case F_RDLCK: linux_flock->l_type = LINUX_F_RDLCK; break; case F_WRLCK: linux_flock->l_type = LINUX_F_WRLCK; break; case F_UNLCK: linux_flock->l_type = LINUX_F_UNLCK; break; } linux_flock->l_whence = bsd_flock->l_whence; linux_flock->l_start = (l_loff_t)bsd_flock->l_start; linux_flock->l_len = (l_loff_t)bsd_flock->l_len; linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ static int fcntl_common(struct thread *td, struct linux_fcntl_args *args) { struct l_flock linux_flock; struct flock bsd_flock; cap_rights_t rights; struct file *fp; long arg; int error, result; switch (args->cmd) { case LINUX_F_DUPFD: return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); case LINUX_F_GETFD: return (kern_fcntl(td, args->fd, F_GETFD, 0)); case LINUX_F_SETFD: return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); case LINUX_F_GETFL: error = kern_fcntl(td, args->fd, F_GETFL, 0); result = td->td_retval[0]; td->td_retval[0] = 0; if (result & O_RDONLY) td->td_retval[0] |= LINUX_O_RDONLY; if (result & O_WRONLY) td->td_retval[0] |= LINUX_O_WRONLY; if (result & O_RDWR) td->td_retval[0] |= LINUX_O_RDWR; if (result & O_NDELAY) td->td_retval[0] |= LINUX_O_NONBLOCK; if (result & O_APPEND) td->td_retval[0] |= LINUX_O_APPEND; if (result & O_FSYNC) td->td_retval[0] |= LINUX_O_SYNC; if (result & O_ASYNC) td->td_retval[0] |= LINUX_FASYNC; #ifdef LINUX_O_NOFOLLOW if (result & O_NOFOLLOW) td->td_retval[0] |= LINUX_O_NOFOLLOW; #endif #ifdef LINUX_O_DIRECT if (result & O_DIRECT) td->td_retval[0] |= LINUX_O_DIRECT; #endif return (error); case LINUX_F_SETFL: arg = 0; if (args->arg & LINUX_O_NDELAY) arg |= O_NONBLOCK; if (args->arg & LINUX_O_APPEND) arg |= O_APPEND; if (args->arg & LINUX_O_SYNC) arg |= O_FSYNC; if (args->arg & LINUX_FASYNC) arg |= O_ASYNC; #ifdef LINUX_O_NOFOLLOW if (args->arg & LINUX_O_NOFOLLOW) arg |= O_NOFOLLOW; #endif #ifdef LINUX_O_DIRECT if (args->arg & LINUX_O_DIRECT) arg |= O_DIRECT; #endif return (kern_fcntl(td, args->fd, F_SETFL, arg)); case LINUX_F_GETLK: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock(&linux_flock, &bsd_flock); error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); if (error) return (error); bsd_to_linux_flock(&bsd_flock, &linux_flock); return (copyout(&linux_flock, (void *)args->arg, sizeof(linux_flock))); case LINUX_F_SETLK: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock(&linux_flock, &bsd_flock); return (kern_fcntl(td, args->fd, F_SETLK, (intptr_t)&bsd_flock)); case LINUX_F_SETLKW: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock(&linux_flock, &bsd_flock); return (kern_fcntl(td, args->fd, F_SETLKW, (intptr_t)&bsd_flock)); case LINUX_F_GETOWN: return (kern_fcntl(td, args->fd, F_GETOWN, 0)); case LINUX_F_SETOWN: /* * XXX some Linux applications depend on F_SETOWN having no * significant effect for pipes (SIGIO is not delivered for * pipes under Linux-2.2.35 at least). */ error = fget(td, args->fd, cap_rights_init(&rights, CAP_FCNTL), &fp); if (error) return (error); if (fp->f_type == DTYPE_PIPE) { fdrop(fp, td); return (EINVAL); } fdrop(fp, td); return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); case LINUX_F_DUPFD_CLOEXEC: return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg)); } return (EINVAL); } int linux_fcntl(struct thread *td, struct linux_fcntl_args *args) { #ifdef DEBUG if (ldebug(fcntl)) printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); #endif return (fcntl_common(td, args)); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) { struct l_flock64 linux_flock; struct flock bsd_flock; struct linux_fcntl_args fcntl_args; int error; #ifdef DEBUG if (ldebug(fcntl64)) printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); #endif switch (args->cmd) { case LINUX_F_GETLK64: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock64(&linux_flock, &bsd_flock); error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); if (error) return (error); bsd_to_linux_flock64(&bsd_flock, &linux_flock); return (copyout(&linux_flock, (void *)args->arg, sizeof(linux_flock))); case LINUX_F_SETLK64: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock64(&linux_flock, &bsd_flock); return (kern_fcntl(td, args->fd, F_SETLK, (intptr_t)&bsd_flock)); case LINUX_F_SETLKW64: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock64(&linux_flock, &bsd_flock); return (kern_fcntl(td, args->fd, F_SETLKW, (intptr_t)&bsd_flock)); } fcntl_args.fd = args->fd; fcntl_args.cmd = args->cmd; fcntl_args.arg = args->arg; return (fcntl_common(td, &fcntl_args)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_chown(struct thread *td, struct linux_chown_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(chown)) printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); #endif error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid, 0); LFREEPATH(path); return (error); } int linux_fchownat(struct thread *td, struct linux_fchownat_args *args) { char *path; int error, dfd, flag; if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) return (EINVAL); dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->filename, &path, dfd); #ifdef DEBUG if (ldebug(fchownat)) printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid); #endif flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : AT_SYMLINK_NOFOLLOW; error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, flag); LFREEPATH(path); return (error); } int linux_lchown(struct thread *td, struct linux_lchown_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); #ifdef DEBUG if (ldebug(lchown)) printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); #endif error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid, AT_SYMLINK_NOFOLLOW); LFREEPATH(path); return (error); } static int convert_fadvice(int advice) { switch (advice) { case LINUX_POSIX_FADV_NORMAL: return (POSIX_FADV_NORMAL); case LINUX_POSIX_FADV_RANDOM: return (POSIX_FADV_RANDOM); case LINUX_POSIX_FADV_SEQUENTIAL: return (POSIX_FADV_SEQUENTIAL); case LINUX_POSIX_FADV_WILLNEED: return (POSIX_FADV_WILLNEED); case LINUX_POSIX_FADV_DONTNEED: return (POSIX_FADV_DONTNEED); case LINUX_POSIX_FADV_NOREUSE: return (POSIX_FADV_NOREUSE); default: return (-1); } } int linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args) { int advice; advice = convert_fadvice(args->advice); if (advice == -1) return (EINVAL); return (kern_posix_fadvise(td, args->fd, args->offset, args->len, advice)); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args) { int advice; advice = convert_fadvice(args->advice); if (advice == -1) return (EINVAL); return (kern_posix_fadvise(td, args->fd, args->offset, args->len, advice)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_pipe(struct thread *td, struct linux_pipe_args *args) { int fildes[2]; int error; #ifdef DEBUG if (ldebug(pipe)) printf(ARGS(pipe, "*")); #endif error = kern_pipe(td, fildes, 0, NULL, NULL); - if (error) + if (error != 0) return (error); - /* XXX: Close descriptors on error. */ - return (copyout(fildes, args->pipefds, sizeof(fildes))); + error = copyout(fildes, args->pipefds, sizeof(fildes)); + if (error != 0) { + (void)kern_close(td, fildes[0]); + (void)kern_close(td, fildes[1]); + } + + return (error); } int linux_pipe2(struct thread *td, struct linux_pipe2_args *args) { int fildes[2]; int error, flags; #ifdef DEBUG if (ldebug(pipe2)) printf(ARGS(pipe2, "*, %d"), args->flags); #endif if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0) return (EINVAL); flags = 0; if ((args->flags & LINUX_O_NONBLOCK) != 0) flags |= O_NONBLOCK; if ((args->flags & LINUX_O_CLOEXEC) != 0) flags |= O_CLOEXEC; error = kern_pipe(td, fildes, flags, NULL, NULL); - if (error) + if (error != 0) return (error); - /* XXX: Close descriptors on error. */ - return (copyout(fildes, args->pipefds, sizeof(fildes))); + error = copyout(fildes, args->pipefds, sizeof(fildes)); + if (error != 0) { + (void)kern_close(td, fildes[0]); + (void)kern_close(td, fildes[1]); + } + + return (error); } int linux_dup3(struct thread *td, struct linux_dup3_args *args) { int cmd; intptr_t newfd; if (args->oldfd == args->newfd) return (EINVAL); if ((args->flags & ~LINUX_O_CLOEXEC) != 0) return (EINVAL); if (args->flags & LINUX_O_CLOEXEC) cmd = F_DUP2FD_CLOEXEC; else cmd = F_DUP2FD; newfd = args->newfd; return (kern_fcntl(td, args->oldfd, cmd, newfd)); } int linux_fallocate(struct thread *td, struct linux_fallocate_args *args) { /* * We emulate only posix_fallocate system call for which * mode should be 0. */ if (args->mode != 0) return (ENOSYS); return (kern_posix_fallocate(td, args->fd, args->offset, args->len)); } Index: projects/ipsec/sys/compat/linux/linux_misc.c =================================================================== --- projects/ipsec/sys/compat/linux/linux_misc.c (revision 313312) +++ projects/ipsec/sys/compat/linux/linux_misc.c (revision 313313) @@ -1,2522 +1,2513 @@ /*- * Copyright (c) 2002 Doug Rabson * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #if defined(__i386__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef COMPAT_LINUX32 #include #include #else #include #include #endif #include #include #include #include #include #include #include #include #include /** * Special DTrace provider for the linuxulator. * * In this file we define the provider for the entire linuxulator. All * modules (= files of the linuxulator) use it. * * We define a different name depending on the emulated bitsize, see * ../..//linux{,32}/linux.h, e.g.: * native bitsize = linuxulator * amd64, 32bit emulation = linuxulator32 */ LIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE); int stclohz; /* Statistics clock frequency */ static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, RLIMIT_MEMLOCK, RLIMIT_AS }; struct l_sysinfo { l_long uptime; /* Seconds since boot */ l_ulong loads[3]; /* 1, 5, and 15 minute load averages */ #define LINUX_SYSINFO_LOADS_SCALE 65536 l_ulong totalram; /* Total usable main memory size */ l_ulong freeram; /* Available memory size */ l_ulong sharedram; /* Amount of shared memory */ l_ulong bufferram; /* Memory used by buffers */ l_ulong totalswap; /* Total swap space size */ l_ulong freeswap; /* swap space still available */ l_ushort procs; /* Number of current processes */ l_ushort pads; l_ulong totalbig; l_ulong freebig; l_uint mem_unit; char _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* padding */ }; struct l_pselect6arg { l_uintptr_t ss; l_size_t ss_len; }; static int linux_utimensat_nsec_valid(l_long); int linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) { struct l_sysinfo sysinfo; vm_object_t object; int i, j; struct timespec ts; bzero(&sysinfo, sizeof(sysinfo)); getnanouptime(&ts); if (ts.tv_nsec != 0) ts.tv_sec++; sysinfo.uptime = ts.tv_sec; /* Use the information from the mib to get our load averages */ for (i = 0; i < 3; i++) sysinfo.loads[i] = averunnable.ldavg[i] * LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale; sysinfo.totalram = physmem * PAGE_SIZE; sysinfo.freeram = sysinfo.totalram - vm_cnt.v_wire_count * PAGE_SIZE; sysinfo.sharedram = 0; mtx_lock(&vm_object_list_mtx); TAILQ_FOREACH(object, &vm_object_list, object_list) if (object->shadow_count > 1) sysinfo.sharedram += object->resident_page_count; mtx_unlock(&vm_object_list_mtx); sysinfo.sharedram *= PAGE_SIZE; sysinfo.bufferram = 0; swap_pager_status(&i, &j); sysinfo.totalswap = i * PAGE_SIZE; sysinfo.freeswap = (i - j) * PAGE_SIZE; sysinfo.procs = nprocs; /* The following are only present in newer Linux kernels. */ sysinfo.totalbig = 0; sysinfo.freebig = 0; sysinfo.mem_unit = 1; return (copyout(&sysinfo, args->info, sizeof(sysinfo))); } int linux_alarm(struct thread *td, struct linux_alarm_args *args) { struct itimerval it, old_it; u_int secs; int error; #ifdef DEBUG if (ldebug(alarm)) printf(ARGS(alarm, "%u"), args->secs); #endif secs = args->secs; /* * Linux alarm() is always successful. Limit secs to INT32_MAX / 2 * to match kern_setitimer()'s limit to avoid error from it. * * XXX. Linux limit secs to INT_MAX on 32 and does not limit on 64-bit * platforms. */ if (secs > INT32_MAX / 2) secs = INT32_MAX / 2; it.it_value.tv_sec = secs; it.it_value.tv_usec = 0; timevalclear(&it.it_interval); error = kern_setitimer(td, ITIMER_REAL, &it, &old_it); KASSERT(error == 0, ("kern_setitimer returns %d", error)); if ((old_it.it_value.tv_sec == 0 && old_it.it_value.tv_usec > 0) || old_it.it_value.tv_usec >= 500000) old_it.it_value.tv_sec++; td->td_retval[0] = old_it.it_value.tv_sec; return (0); } int linux_brk(struct thread *td, struct linux_brk_args *args) { struct vmspace *vm = td->td_proc->p_vmspace; vm_offset_t new, old; struct obreak_args /* { char * nsize; } */ tmp; #ifdef DEBUG if (ldebug(brk)) printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend); #endif old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); new = (vm_offset_t)args->dsend; tmp.nsize = (char *)new; if (((caddr_t)new > vm->vm_daddr) && !sys_obreak(td, &tmp)) td->td_retval[0] = (long)new; else td->td_retval[0] = (long)old; return (0); } #if defined(__i386__) /* XXX: what about amd64/linux32? */ int linux_uselib(struct thread *td, struct linux_uselib_args *args) { struct nameidata ni; struct vnode *vp; struct exec *a_out; struct vattr attr; vm_offset_t vmaddr; unsigned long file_offset; unsigned long bss_size; char *library; ssize_t aresid; int error, locked, writecount; LCONVPATHEXIST(td, args->library, &library); #ifdef DEBUG if (ldebug(uselib)) printf(ARGS(uselib, "%s"), library); #endif a_out = NULL; locked = 0; vp = NULL; NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_SYSSPACE, library, td); error = namei(&ni); LFREEPATH(library); if (error) goto cleanup; vp = ni.ni_vp; NDFREE(&ni, NDF_ONLY_PNBUF); /* * From here on down, we have a locked vnode that must be unlocked. * XXX: The code below largely duplicates exec_check_permissions(). */ locked = 1; /* Writable? */ error = VOP_GET_WRITECOUNT(vp, &writecount); if (error != 0) goto cleanup; if (writecount != 0) { error = ETXTBSY; goto cleanup; } /* Executable? */ error = VOP_GETATTR(vp, &attr, td->td_ucred); if (error) goto cleanup; if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) { /* EACCESS is what exec(2) returns. */ error = ENOEXEC; goto cleanup; } /* Sensible size? */ if (attr.va_size == 0) { error = ENOEXEC; goto cleanup; } /* Can we access it? */ error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); if (error) goto cleanup; /* * XXX: This should use vn_open() so that it is properly authorized, * and to reduce code redundancy all over the place here. * XXX: Not really, it duplicates far more of exec_check_permissions() * than vn_open(). */ #ifdef MAC error = mac_vnode_check_open(td->td_ucred, vp, VREAD); if (error) goto cleanup; #endif error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL); if (error) goto cleanup; /* Pull in executable header into exec_map */ error = vm_mmap(exec_map, (vm_offset_t *)&a_out, PAGE_SIZE, VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0); if (error) goto cleanup; /* Is it a Linux binary ? */ if (((a_out->a_magic >> 16) & 0xff) != 0x64) { error = ENOEXEC; goto cleanup; } /* * While we are here, we should REALLY do some more checks */ /* Set file/virtual offset based on a.out variant. */ switch ((int)(a_out->a_magic & 0xffff)) { case 0413: /* ZMAGIC */ file_offset = 1024; break; case 0314: /* QMAGIC */ file_offset = 0; break; default: error = ENOEXEC; goto cleanup; } bss_size = round_page(a_out->a_bss); /* Check various fields in header for validity/bounds. */ if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) { error = ENOEXEC; goto cleanup; } /* text + data can't exceed file size */ if (a_out->a_data + a_out->a_text > attr.va_size) { error = EFAULT; goto cleanup; } /* * text/data/bss must not exceed limits * XXX - this is not complete. it should check current usage PLUS * the resources needed by this library. */ PROC_LOCK(td->td_proc); if (a_out->a_text > maxtsiz || a_out->a_data + bss_size > lim_cur_proc(td->td_proc, RLIMIT_DATA) || racct_set(td->td_proc, RACCT_DATA, a_out->a_data + bss_size) != 0) { PROC_UNLOCK(td->td_proc); error = ENOMEM; goto cleanup; } PROC_UNLOCK(td->td_proc); /* * Prevent more writers. * XXX: Note that if any of the VM operations fail below we don't * clear this flag. */ VOP_SET_TEXT(vp); /* * Lock no longer needed */ locked = 0; VOP_UNLOCK(vp, 0); /* * Check if file_offset page aligned. Currently we cannot handle * misalinged file offsets, and so we read in the entire image * (what a waste). */ if (file_offset & PAGE_MASK) { #ifdef DEBUG printf("uselib: Non page aligned binary %lu\n", file_offset); #endif /* Map text+data read/write/execute */ /* a_entry is the load address and is page aligned */ vmaddr = trunc_page(a_out->a_entry); /* get anon user mapping, read+write+execute */ error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, &vmaddr, a_out->a_text + a_out->a_data, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0); if (error) goto cleanup; error = vn_rdwr(UIO_READ, vp, (void *)vmaddr, file_offset, a_out->a_text + a_out->a_data, UIO_USERSPACE, 0, td->td_ucred, NOCRED, &aresid, td); if (error != 0) goto cleanup; if (aresid != 0) { error = ENOEXEC; goto cleanup; } } else { #ifdef DEBUG printf("uselib: Page aligned binary %lu\n", file_offset); #endif /* * for QMAGIC, a_entry is 20 bytes beyond the load address * to skip the executable header */ vmaddr = trunc_page(a_out->a_entry); /* * Map it all into the process's space as a single * copy-on-write "data" segment. */ error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr, a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset); if (error) goto cleanup; } #ifdef DEBUG printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long *)vmaddr)[0], ((long *)vmaddr)[1]); #endif if (bss_size != 0) { /* Calculate BSS start address */ vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data; /* allocate some 'anon' space */ error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, &vmaddr, bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0); if (error) goto cleanup; } cleanup: /* Unlock vnode if needed */ if (locked) VOP_UNLOCK(vp, 0); /* Release the temporary mapping. */ if (a_out) kmap_free_wakeup(exec_map, (vm_offset_t)a_out, PAGE_SIZE); return (error); } #endif /* __i386__ */ int linux_select(struct thread *td, struct linux_select_args *args) { l_timeval ltv; struct timeval tv0, tv1, utv, *tvp; int error; #ifdef DEBUG if (ldebug(select)) printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds, (void *)args->readfds, (void *)args->writefds, (void *)args->exceptfds, (void *)args->timeout); #endif /* * Store current time for computation of the amount of * time left. */ if (args->timeout) { if ((error = copyin(args->timeout, <v, sizeof(ltv)))) goto select_out; utv.tv_sec = ltv.tv_sec; utv.tv_usec = ltv.tv_usec; #ifdef DEBUG if (ldebug(select)) printf(LMSG("incoming timeout (%jd/%ld)"), (intmax_t)utv.tv_sec, utv.tv_usec); #endif if (itimerfix(&utv)) { /* * The timeval was invalid. Convert it to something * valid that will act as it does under Linux. */ utv.tv_sec += utv.tv_usec / 1000000; utv.tv_usec %= 1000000; if (utv.tv_usec < 0) { utv.tv_sec -= 1; utv.tv_usec += 1000000; } if (utv.tv_sec < 0) timevalclear(&utv); } microtime(&tv0); tvp = &utv; } else tvp = NULL; error = kern_select(td, args->nfds, args->readfds, args->writefds, args->exceptfds, tvp, LINUX_NFDBITS); #ifdef DEBUG if (ldebug(select)) printf(LMSG("real select returns %d"), error); #endif if (error) goto select_out; if (args->timeout) { if (td->td_retval[0]) { /* * Compute how much time was left of the timeout, * by subtracting the current time and the time * before we started the call, and subtracting * that result from the user-supplied value. */ microtime(&tv1); timevalsub(&tv1, &tv0); timevalsub(&utv, &tv1); if (utv.tv_sec < 0) timevalclear(&utv); } else timevalclear(&utv); #ifdef DEBUG if (ldebug(select)) printf(LMSG("outgoing timeout (%jd/%ld)"), (intmax_t)utv.tv_sec, utv.tv_usec); #endif ltv.tv_sec = utv.tv_sec; ltv.tv_usec = utv.tv_usec; if ((error = copyout(<v, args->timeout, sizeof(ltv)))) goto select_out; } select_out: #ifdef DEBUG if (ldebug(select)) printf(LMSG("select_out -> %d"), error); #endif return (error); } int linux_mremap(struct thread *td, struct linux_mremap_args *args) { struct munmap_args /* { void *addr; size_t len; } */ bsd_args; int error = 0; #ifdef DEBUG if (ldebug(mremap)) printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"), (void *)(uintptr_t)args->addr, (unsigned long)args->old_len, (unsigned long)args->new_len, (unsigned long)args->flags); #endif if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) { td->td_retval[0] = 0; return (EINVAL); } /* * Check for the page alignment. * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK. */ if (args->addr & PAGE_MASK) { td->td_retval[0] = 0; return (EINVAL); } args->new_len = round_page(args->new_len); args->old_len = round_page(args->old_len); if (args->new_len > args->old_len) { td->td_retval[0] = 0; return (ENOMEM); } if (args->new_len < args->old_len) { bsd_args.addr = (caddr_t)((uintptr_t)args->addr + args->new_len); bsd_args.len = args->old_len - args->new_len; error = sys_munmap(td, &bsd_args); } td->td_retval[0] = error ? 0 : (uintptr_t)args->addr; return (error); } #define LINUX_MS_ASYNC 0x0001 #define LINUX_MS_INVALIDATE 0x0002 #define LINUX_MS_SYNC 0x0004 int linux_msync(struct thread *td, struct linux_msync_args *args) { struct msync_args bsd_args; bsd_args.addr = (caddr_t)(uintptr_t)args->addr; bsd_args.len = (uintptr_t)args->len; bsd_args.flags = args->fl & ~LINUX_MS_SYNC; return (sys_msync(td, &bsd_args)); } int linux_time(struct thread *td, struct linux_time_args *args) { struct timeval tv; l_time_t tm; int error; #ifdef DEBUG if (ldebug(time)) printf(ARGS(time, "*")); #endif microtime(&tv); tm = tv.tv_sec; if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm)))) return (error); td->td_retval[0] = tm; return (0); } struct l_times_argv { l_clock_t tms_utime; l_clock_t tms_stime; l_clock_t tms_cutime; l_clock_t tms_cstime; }; /* * Glibc versions prior to 2.2.1 always use hard-coded CLK_TCK value. * Since 2.2.1 Glibc uses value exported from kernel via AT_CLKTCK * auxiliary vector entry. */ #define CLK_TCK 100 #define CONVOTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) #define CONVNTCK(r) (r.tv_sec * stclohz + r.tv_usec / (1000000 / stclohz)) #define CONVTCK(r) (linux_kernver(td) >= LINUX_KERNVER_2004000 ? \ CONVNTCK(r) : CONVOTCK(r)) int linux_times(struct thread *td, struct linux_times_args *args) { struct timeval tv, utime, stime, cutime, cstime; struct l_times_argv tms; struct proc *p; int error; #ifdef DEBUG if (ldebug(times)) printf(ARGS(times, "*")); #endif if (args->buf != NULL) { p = td->td_proc; PROC_LOCK(p); PROC_STATLOCK(p); calcru(p, &utime, &stime); PROC_STATUNLOCK(p); calccru(p, &cutime, &cstime); PROC_UNLOCK(p); tms.tms_utime = CONVTCK(utime); tms.tms_stime = CONVTCK(stime); tms.tms_cutime = CONVTCK(cutime); tms.tms_cstime = CONVTCK(cstime); if ((error = copyout(&tms, args->buf, sizeof(tms)))) return (error); } microuptime(&tv); td->td_retval[0] = (int)CONVTCK(tv); return (0); } int linux_newuname(struct thread *td, struct linux_newuname_args *args) { struct l_new_utsname utsname; char osname[LINUX_MAX_UTSNAME]; char osrelease[LINUX_MAX_UTSNAME]; char *p; #ifdef DEBUG if (ldebug(newuname)) printf(ARGS(newuname, "*")); #endif linux_get_osname(td, osname); linux_get_osrelease(td, osrelease); bzero(&utsname, sizeof(utsname)); strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME); getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME); getcreddomainname(td->td_ucred, utsname.domainname, LINUX_MAX_UTSNAME); strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME); strlcpy(utsname.version, version, LINUX_MAX_UTSNAME); for (p = utsname.version; *p != '\0'; ++p) if (*p == '\n') { *p = '\0'; break; } strlcpy(utsname.machine, linux_kplatform, LINUX_MAX_UTSNAME); return (copyout(&utsname, args->buf, sizeof(utsname))); } struct l_utimbuf { l_time_t l_actime; l_time_t l_modtime; }; int linux_utime(struct thread *td, struct linux_utime_args *args) { struct timeval tv[2], *tvp; struct l_utimbuf lut; char *fname; int error; LCONVPATHEXIST(td, args->fname, &fname); #ifdef DEBUG if (ldebug(utime)) printf(ARGS(utime, "%s, *"), fname); #endif if (args->times) { if ((error = copyin(args->times, &lut, sizeof lut))) { LFREEPATH(fname); return (error); } tv[0].tv_sec = lut.l_actime; tv[0].tv_usec = 0; tv[1].tv_sec = lut.l_modtime; tv[1].tv_usec = 0; tvp = tv; } else tvp = NULL; error = kern_utimesat(td, AT_FDCWD, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); LFREEPATH(fname); return (error); } int linux_utimes(struct thread *td, struct linux_utimes_args *args) { l_timeval ltv[2]; struct timeval tv[2], *tvp = NULL; char *fname; int error; LCONVPATHEXIST(td, args->fname, &fname); #ifdef DEBUG if (ldebug(utimes)) printf(ARGS(utimes, "%s, *"), fname); #endif if (args->tptr != NULL) { if ((error = copyin(args->tptr, ltv, sizeof ltv))) { LFREEPATH(fname); return (error); } tv[0].tv_sec = ltv[0].tv_sec; tv[0].tv_usec = ltv[0].tv_usec; tv[1].tv_sec = ltv[1].tv_sec; tv[1].tv_usec = ltv[1].tv_usec; tvp = tv; } error = kern_utimesat(td, AT_FDCWD, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); LFREEPATH(fname); return (error); } static int linux_utimensat_nsec_valid(l_long nsec) { if (nsec == LINUX_UTIME_OMIT || nsec == LINUX_UTIME_NOW) return (0); if (nsec >= 0 && nsec <= 999999999) return (0); return (1); } int linux_utimensat(struct thread *td, struct linux_utimensat_args *args) { struct l_timespec l_times[2]; struct timespec times[2], *timesp = NULL; char *path = NULL; int error, dfd, flags = 0; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; #ifdef DEBUG if (ldebug(utimensat)) printf(ARGS(utimensat, "%d, *"), dfd); #endif if (args->flags & ~LINUX_AT_SYMLINK_NOFOLLOW) return (EINVAL); if (args->times != NULL) { error = copyin(args->times, l_times, sizeof(l_times)); if (error != 0) return (error); if (linux_utimensat_nsec_valid(l_times[0].tv_nsec) != 0 || linux_utimensat_nsec_valid(l_times[1].tv_nsec) != 0) return (EINVAL); times[0].tv_sec = l_times[0].tv_sec; switch (l_times[0].tv_nsec) { case LINUX_UTIME_OMIT: times[0].tv_nsec = UTIME_OMIT; break; case LINUX_UTIME_NOW: times[0].tv_nsec = UTIME_NOW; break; default: times[0].tv_nsec = l_times[0].tv_nsec; } times[1].tv_sec = l_times[1].tv_sec; switch (l_times[1].tv_nsec) { case LINUX_UTIME_OMIT: times[1].tv_nsec = UTIME_OMIT; break; case LINUX_UTIME_NOW: times[1].tv_nsec = UTIME_NOW; break; default: times[1].tv_nsec = l_times[1].tv_nsec; break; } timesp = times; /* This breaks POSIX, but is what the Linux kernel does * _on purpose_ (documented in the man page for utimensat(2)), * so we must follow that behaviour. */ if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) return (0); } if (args->pathname != NULL) LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); else if (args->flags != 0) return (EINVAL); if (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) flags |= AT_SYMLINK_NOFOLLOW; if (path == NULL) error = kern_futimens(td, dfd, timesp, UIO_SYSSPACE); else { error = kern_utimensat(td, dfd, path, UIO_SYSSPACE, timesp, UIO_SYSSPACE, flags); LFREEPATH(path); } return (error); } int linux_futimesat(struct thread *td, struct linux_futimesat_args *args) { l_timeval ltv[2]; struct timeval tv[2], *tvp = NULL; char *fname; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->filename, &fname, dfd); #ifdef DEBUG if (ldebug(futimesat)) printf(ARGS(futimesat, "%s, *"), fname); #endif if (args->utimes != NULL) { if ((error = copyin(args->utimes, ltv, sizeof ltv))) { LFREEPATH(fname); return (error); } tv[0].tv_sec = ltv[0].tv_sec; tv[0].tv_usec = ltv[0].tv_usec; tv[1].tv_sec = ltv[1].tv_sec; tv[1].tv_usec = ltv[1].tv_usec; tvp = tv; } error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); LFREEPATH(fname); return (error); } int linux_common_wait(struct thread *td, int pid, int *status, int options, struct rusage *ru) { int error, tmpstat; error = kern_wait(td, pid, &tmpstat, options, ru); if (error) return (error); if (status) { tmpstat &= 0xffff; if (WIFSIGNALED(tmpstat)) tmpstat = (tmpstat & 0xffffff80) | bsd_to_linux_signal(WTERMSIG(tmpstat)); else if (WIFSTOPPED(tmpstat)) tmpstat = (tmpstat & 0xffff00ff) | (bsd_to_linux_signal(WSTOPSIG(tmpstat)) << 8); else if (WIFCONTINUED(tmpstat)) tmpstat = 0xffff; error = copyout(&tmpstat, status, sizeof(int)); } return (error); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_waitpid(struct thread *td, struct linux_waitpid_args *args) { struct linux_wait4_args wait4_args; #ifdef DEBUG if (ldebug(waitpid)) printf(ARGS(waitpid, "%d, %p, %d"), args->pid, (void *)args->status, args->options); #endif wait4_args.pid = args->pid; wait4_args.status = args->status; wait4_args.options = args->options; wait4_args.rusage = NULL; return (linux_wait4(td, &wait4_args)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_wait4(struct thread *td, struct linux_wait4_args *args) { int error, options; struct rusage ru, *rup; #ifdef DEBUG if (ldebug(wait4)) printf(ARGS(wait4, "%d, %p, %d, %p"), args->pid, (void *)args->status, args->options, (void *)args->rusage); #endif if (args->options & ~(LINUX_WUNTRACED | LINUX_WNOHANG | LINUX_WCONTINUED | __WCLONE | __WNOTHREAD | __WALL)) return (EINVAL); options = WEXITED; linux_to_bsd_waitopts(args->options, &options); if (args->rusage != NULL) rup = &ru; else rup = NULL; error = linux_common_wait(td, args->pid, args->status, options, rup); if (error != 0) return (error); if (args->rusage != NULL) error = linux_copyout_rusage(&ru, args->rusage); return (error); } int linux_waitid(struct thread *td, struct linux_waitid_args *args) { int status, options, sig; struct __wrusage wru; siginfo_t siginfo; l_siginfo_t lsi; idtype_t idtype; struct proc *p; int error; options = 0; linux_to_bsd_waitopts(args->options, &options); if (options & ~(WNOHANG | WNOWAIT | WEXITED | WUNTRACED | WCONTINUED)) return (EINVAL); if (!(options & (WEXITED | WUNTRACED | WCONTINUED))) return (EINVAL); switch (args->idtype) { case LINUX_P_ALL: idtype = P_ALL; break; case LINUX_P_PID: if (args->id <= 0) return (EINVAL); idtype = P_PID; break; case LINUX_P_PGID: if (args->id <= 0) return (EINVAL); idtype = P_PGID; break; default: return (EINVAL); } error = kern_wait6(td, idtype, args->id, &status, options, &wru, &siginfo); if (error != 0) return (error); if (args->rusage != NULL) { error = linux_copyout_rusage(&wru.wru_children, args->rusage); if (error != 0) return (error); } if (args->info != NULL) { p = td->td_proc; if (td->td_retval[0] == 0) bzero(&lsi, sizeof(lsi)); else { sig = bsd_to_linux_signal(siginfo.si_signo); siginfo_to_lsiginfo(&siginfo, &lsi, sig); } error = copyout(&lsi, args->info, sizeof(lsi)); } td->td_retval[0] = 0; return (error); } int linux_mknod(struct thread *td, struct linux_mknod_args *args) { char *path; int error; LCONVPATHCREAT(td, args->path, &path); #ifdef DEBUG if (ldebug(mknod)) printf(ARGS(mknod, "%s, %d, %ju"), path, args->mode, (uintmax_t)args->dev); #endif switch (args->mode & S_IFMT) { case S_IFIFO: case S_IFSOCK: error = kern_mkfifoat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode); break; case S_IFCHR: case S_IFBLK: error = kern_mknodat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode, args->dev); break; case S_IFDIR: error = EPERM; break; case 0: args->mode |= S_IFREG; /* FALLTHROUGH */ case S_IFREG: error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, args->mode); if (error == 0) kern_close(td, td->td_retval[0]); break; default: error = EINVAL; break; } LFREEPATH(path); return (error); } int linux_mknodat(struct thread *td, struct linux_mknodat_args *args) { char *path; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHCREAT_AT(td, args->filename, &path, dfd); #ifdef DEBUG if (ldebug(mknodat)) printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev); #endif switch (args->mode & S_IFMT) { case S_IFIFO: case S_IFSOCK: error = kern_mkfifoat(td, dfd, path, UIO_SYSSPACE, args->mode); break; case S_IFCHR: case S_IFBLK: error = kern_mknodat(td, dfd, path, UIO_SYSSPACE, args->mode, args->dev); break; case S_IFDIR: error = EPERM; break; case 0: args->mode |= S_IFREG; /* FALLTHROUGH */ case S_IFREG: error = kern_openat(td, dfd, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, args->mode); if (error == 0) kern_close(td, td->td_retval[0]); break; default: error = EINVAL; break; } LFREEPATH(path); return (error); } /* * UGH! This is just about the dumbest idea I've ever heard!! */ int linux_personality(struct thread *td, struct linux_personality_args *args) { struct linux_pemuldata *pem; struct proc *p = td->td_proc; uint32_t old; #ifdef DEBUG if (ldebug(personality)) printf(ARGS(personality, "%u"), args->per); #endif PROC_LOCK(p); pem = pem_find(p); old = pem->persona; if (args->per != 0xffffffff) pem->persona = args->per; PROC_UNLOCK(p); td->td_retval[0] = old; return (0); } struct l_itimerval { l_timeval it_interval; l_timeval it_value; }; #define B2L_ITIMERVAL(bip, lip) \ (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \ (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \ (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \ (bip)->it_value.tv_usec = (lip)->it_value.tv_usec; int linux_setitimer(struct thread *td, struct linux_setitimer_args *uap) { int error; struct l_itimerval ls; struct itimerval aitv, oitv; #ifdef DEBUG if (ldebug(setitimer)) printf(ARGS(setitimer, "%p, %p"), (void *)uap->itv, (void *)uap->oitv); #endif if (uap->itv == NULL) { uap->itv = uap->oitv; return (linux_getitimer(td, (struct linux_getitimer_args *)uap)); } error = copyin(uap->itv, &ls, sizeof(ls)); if (error != 0) return (error); B2L_ITIMERVAL(&aitv, &ls); #ifdef DEBUG if (ldebug(setitimer)) { printf("setitimer: value: sec: %jd, usec: %ld\n", (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec); printf("setitimer: interval: sec: %jd, usec: %ld\n", (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec); } #endif error = kern_setitimer(td, uap->which, &aitv, &oitv); if (error != 0 || uap->oitv == NULL) return (error); B2L_ITIMERVAL(&ls, &oitv); return (copyout(&ls, uap->oitv, sizeof(ls))); } int linux_getitimer(struct thread *td, struct linux_getitimer_args *uap) { int error; struct l_itimerval ls; struct itimerval aitv; #ifdef DEBUG if (ldebug(getitimer)) printf(ARGS(getitimer, "%p"), (void *)uap->itv); #endif error = kern_getitimer(td, uap->which, &aitv); if (error != 0) return (error); B2L_ITIMERVAL(&ls, &aitv); return (copyout(&ls, uap->itv, sizeof(ls))); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_nice(struct thread *td, struct linux_nice_args *args) { struct setpriority_args bsd_args; bsd_args.which = PRIO_PROCESS; bsd_args.who = 0; /* current process */ bsd_args.prio = args->inc; return (sys_setpriority(td, &bsd_args)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_setgroups(struct thread *td, struct linux_setgroups_args *args) { struct ucred *newcred, *oldcred; l_gid_t *linux_gidset; gid_t *bsd_gidset; int ngrp, error; struct proc *p; ngrp = args->gidsetsize; if (ngrp < 0 || ngrp >= ngroups_max + 1) return (EINVAL); linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); if (error) goto out; newcred = crget(); crextend(newcred, ngrp + 1); p = td->td_proc; PROC_LOCK(p); oldcred = p->p_ucred; crcopy(newcred, oldcred); /* * cr_groups[0] holds egid. Setting the whole set from * the supplied set will cause egid to be changed too. * Keep cr_groups[0] unchanged to prevent that. */ if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0) { PROC_UNLOCK(p); crfree(newcred); goto out; } if (ngrp > 0) { newcred->cr_ngroups = ngrp + 1; bsd_gidset = newcred->cr_groups; ngrp--; while (ngrp >= 0) { bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; ngrp--; } } else newcred->cr_ngroups = 1; setsugid(p); proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); error = 0; out: free(linux_gidset, M_LINUX); return (error); } int linux_getgroups(struct thread *td, struct linux_getgroups_args *args) { struct ucred *cred; l_gid_t *linux_gidset; gid_t *bsd_gidset; int bsd_gidsetsz, ngrp, error; cred = td->td_ucred; bsd_gidset = cred->cr_groups; bsd_gidsetsz = cred->cr_ngroups - 1; /* * cr_groups[0] holds egid. Returning the whole set * here will cause a duplicate. Exclude cr_groups[0] * to prevent that. */ if ((ngrp = args->gidsetsize) == 0) { td->td_retval[0] = bsd_gidsetsz; return (0); } if (ngrp < bsd_gidsetsz) return (EINVAL); ngrp = 0; linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), M_LINUX, M_WAITOK); while (ngrp < bsd_gidsetsz) { linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; ngrp++; } error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t)); free(linux_gidset, M_LINUX); if (error) return (error); td->td_retval[0] = ngrp; return (0); } int linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) { struct rlimit bsd_rlim; struct l_rlimit rlim; u_int which; int error; #ifdef DEBUG if (ldebug(setrlimit)) printf(ARGS(setrlimit, "%d, %p"), args->resource, (void *)args->rlim); #endif if (args->resource >= LINUX_RLIM_NLIMITS) return (EINVAL); which = linux_to_bsd_resource[args->resource]; if (which == -1) return (EINVAL); error = copyin(args->rlim, &rlim, sizeof(rlim)); if (error) return (error); bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur; bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max; return (kern_setrlimit(td, which, &bsd_rlim)); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) { struct l_rlimit rlim; struct rlimit bsd_rlim; u_int which; #ifdef DEBUG if (ldebug(old_getrlimit)) printf(ARGS(old_getrlimit, "%d, %p"), args->resource, (void *)args->rlim); #endif if (args->resource >= LINUX_RLIM_NLIMITS) return (EINVAL); which = linux_to_bsd_resource[args->resource]; if (which == -1) return (EINVAL); lim_rlimit(td, which, &bsd_rlim); #ifdef COMPAT_LINUX32 rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur; if (rlim.rlim_cur == UINT_MAX) rlim.rlim_cur = INT_MAX; rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max; if (rlim.rlim_max == UINT_MAX) rlim.rlim_max = INT_MAX; #else rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur; if (rlim.rlim_cur == ULONG_MAX) rlim.rlim_cur = LONG_MAX; rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max; if (rlim.rlim_max == ULONG_MAX) rlim.rlim_max = LONG_MAX; #endif return (copyout(&rlim, args->rlim, sizeof(rlim))); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) { struct l_rlimit rlim; struct rlimit bsd_rlim; u_int which; #ifdef DEBUG if (ldebug(getrlimit)) printf(ARGS(getrlimit, "%d, %p"), args->resource, (void *)args->rlim); #endif if (args->resource >= LINUX_RLIM_NLIMITS) return (EINVAL); which = linux_to_bsd_resource[args->resource]; if (which == -1) return (EINVAL); lim_rlimit(td, which, &bsd_rlim); rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur; rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max; return (copyout(&rlim, args->rlim, sizeof(rlim))); } int linux_sched_setscheduler(struct thread *td, struct linux_sched_setscheduler_args *args) { struct sched_param sched_param; struct thread *tdt; int error, policy; #ifdef DEBUG if (ldebug(sched_setscheduler)) printf(ARGS(sched_setscheduler, "%d, %d, %p"), args->pid, args->policy, (const void *)args->param); #endif switch (args->policy) { case LINUX_SCHED_OTHER: policy = SCHED_OTHER; break; case LINUX_SCHED_FIFO: policy = SCHED_FIFO; break; case LINUX_SCHED_RR: policy = SCHED_RR; break; default: return (EINVAL); } error = copyin(args->param, &sched_param, sizeof(sched_param)); if (error) return (error); tdt = linux_tdfind(td, args->pid, -1); if (tdt == NULL) return (ESRCH); error = kern_sched_setscheduler(td, tdt, policy, &sched_param); PROC_UNLOCK(tdt->td_proc); return (error); } int linux_sched_getscheduler(struct thread *td, struct linux_sched_getscheduler_args *args) { struct thread *tdt; int error, policy; #ifdef DEBUG if (ldebug(sched_getscheduler)) printf(ARGS(sched_getscheduler, "%d"), args->pid); #endif tdt = linux_tdfind(td, args->pid, -1); if (tdt == NULL) return (ESRCH); error = kern_sched_getscheduler(td, tdt, &policy); PROC_UNLOCK(tdt->td_proc); switch (policy) { case SCHED_OTHER: td->td_retval[0] = LINUX_SCHED_OTHER; break; case SCHED_FIFO: td->td_retval[0] = LINUX_SCHED_FIFO; break; case SCHED_RR: td->td_retval[0] = LINUX_SCHED_RR; break; } return (error); } int linux_sched_get_priority_max(struct thread *td, struct linux_sched_get_priority_max_args *args) { struct sched_get_priority_max_args bsd; #ifdef DEBUG if (ldebug(sched_get_priority_max)) printf(ARGS(sched_get_priority_max, "%d"), args->policy); #endif switch (args->policy) { case LINUX_SCHED_OTHER: bsd.policy = SCHED_OTHER; break; case LINUX_SCHED_FIFO: bsd.policy = SCHED_FIFO; break; case LINUX_SCHED_RR: bsd.policy = SCHED_RR; break; default: return (EINVAL); } return (sys_sched_get_priority_max(td, &bsd)); } int linux_sched_get_priority_min(struct thread *td, struct linux_sched_get_priority_min_args *args) { struct sched_get_priority_min_args bsd; #ifdef DEBUG if (ldebug(sched_get_priority_min)) printf(ARGS(sched_get_priority_min, "%d"), args->policy); #endif switch (args->policy) { case LINUX_SCHED_OTHER: bsd.policy = SCHED_OTHER; break; case LINUX_SCHED_FIFO: bsd.policy = SCHED_FIFO; break; case LINUX_SCHED_RR: bsd.policy = SCHED_RR; break; default: return (EINVAL); } return (sys_sched_get_priority_min(td, &bsd)); } #define REBOOT_CAD_ON 0x89abcdef #define REBOOT_CAD_OFF 0 #define REBOOT_HALT 0xcdef0123 #define REBOOT_RESTART 0x01234567 #define REBOOT_RESTART2 0xA1B2C3D4 #define REBOOT_POWEROFF 0x4321FEDC #define REBOOT_MAGIC1 0xfee1dead #define REBOOT_MAGIC2 0x28121969 #define REBOOT_MAGIC2A 0x05121996 #define REBOOT_MAGIC2B 0x16041998 int linux_reboot(struct thread *td, struct linux_reboot_args *args) { struct reboot_args bsd_args; #ifdef DEBUG if (ldebug(reboot)) printf(ARGS(reboot, "0x%x"), args->cmd); #endif if (args->magic1 != REBOOT_MAGIC1) return (EINVAL); switch (args->magic2) { case REBOOT_MAGIC2: case REBOOT_MAGIC2A: case REBOOT_MAGIC2B: break; default: return (EINVAL); } switch (args->cmd) { case REBOOT_CAD_ON: case REBOOT_CAD_OFF: return (priv_check(td, PRIV_REBOOT)); case REBOOT_HALT: bsd_args.opt = RB_HALT; break; case REBOOT_RESTART: case REBOOT_RESTART2: bsd_args.opt = 0; break; case REBOOT_POWEROFF: bsd_args.opt = RB_POWEROFF; break; default: return (EINVAL); } return (sys_reboot(td, &bsd_args)); } /* * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify * td->td_retval[1] when COMPAT_43 is defined. This clobbers registers that * are assumed to be preserved. The following lightweight syscalls fixes * this. See also linux_getgid16() and linux_getuid16() in linux_uid16.c * * linux_getpid() - MP SAFE * linux_getgid() - MP SAFE * linux_getuid() - MP SAFE */ int linux_getpid(struct thread *td, struct linux_getpid_args *args) { #ifdef DEBUG if (ldebug(getpid)) printf(ARGS(getpid, "")); #endif td->td_retval[0] = td->td_proc->p_pid; return (0); } int linux_gettid(struct thread *td, struct linux_gettid_args *args) { struct linux_emuldata *em; #ifdef DEBUG if (ldebug(gettid)) printf(ARGS(gettid, "")); #endif em = em_find(td); KASSERT(em != NULL, ("gettid: emuldata not found.\n")); td->td_retval[0] = em->em_tid; return (0); } int linux_getppid(struct thread *td, struct linux_getppid_args *args) { #ifdef DEBUG if (ldebug(getppid)) printf(ARGS(getppid, "")); #endif td->td_retval[0] = kern_getppid(td); return (0); } int linux_getgid(struct thread *td, struct linux_getgid_args *args) { #ifdef DEBUG if (ldebug(getgid)) printf(ARGS(getgid, "")); #endif td->td_retval[0] = td->td_ucred->cr_rgid; return (0); } int linux_getuid(struct thread *td, struct linux_getuid_args *args) { #ifdef DEBUG if (ldebug(getuid)) printf(ARGS(getuid, "")); #endif td->td_retval[0] = td->td_ucred->cr_ruid; return (0); } int linux_getsid(struct thread *td, struct linux_getsid_args *args) { struct getsid_args bsd; #ifdef DEBUG if (ldebug(getsid)) printf(ARGS(getsid, "%i"), args->pid); #endif bsd.pid = args->pid; return (sys_getsid(td, &bsd)); } int linux_nosys(struct thread *td, struct nosys_args *ignore) { return (ENOSYS); } int linux_getpriority(struct thread *td, struct linux_getpriority_args *args) { struct getpriority_args bsd_args; int error; #ifdef DEBUG if (ldebug(getpriority)) printf(ARGS(getpriority, "%i, %i"), args->which, args->who); #endif bsd_args.which = args->which; bsd_args.who = args->who; error = sys_getpriority(td, &bsd_args); td->td_retval[0] = 20 - td->td_retval[0]; return (error); } int linux_sethostname(struct thread *td, struct linux_sethostname_args *args) { int name[2]; #ifdef DEBUG if (ldebug(sethostname)) printf(ARGS(sethostname, "*, %i"), args->len); #endif name[0] = CTL_KERN; name[1] = KERN_HOSTNAME; return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname, args->len, 0, 0)); } int linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args) { int name[2]; #ifdef DEBUG if (ldebug(setdomainname)) printf(ARGS(setdomainname, "*, %i"), args->len); #endif name[0] = CTL_KERN; name[1] = KERN_NISDOMAINNAME; return (userland_sysctl(td, name, 2, 0, 0, 0, args->name, args->len, 0, 0)); } int linux_exit_group(struct thread *td, struct linux_exit_group_args *args) { #ifdef DEBUG if (ldebug(exit_group)) printf(ARGS(exit_group, "%i"), args->error_code); #endif LINUX_CTR2(exit_group, "thread(%d) (%d)", td->td_tid, args->error_code); /* * XXX: we should send a signal to the parent if * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?) * as it doesnt occur often. */ exit1(td, args->error_code, 0); /* NOTREACHED */ } #define _LINUX_CAPABILITY_VERSION 0x19980330 struct l_user_cap_header { l_int version; l_int pid; }; struct l_user_cap_data { l_int effective; l_int permitted; l_int inheritable; }; int linux_capget(struct thread *td, struct linux_capget_args *args) { struct l_user_cap_header luch; struct l_user_cap_data lucd; int error; if (args->hdrp == NULL) return (EFAULT); error = copyin(args->hdrp, &luch, sizeof(luch)); if (error != 0) return (error); if (luch.version != _LINUX_CAPABILITY_VERSION) { luch.version = _LINUX_CAPABILITY_VERSION; error = copyout(&luch, args->hdrp, sizeof(luch)); if (error) return (error); return (EINVAL); } if (luch.pid) return (EPERM); if (args->datap) { /* * The current implementation doesn't support setting * a capability (it's essentially a stub) so indicate * that no capabilities are currently set or available * to request. */ bzero (&lucd, sizeof(lucd)); error = copyout(&lucd, args->datap, sizeof(lucd)); } return (error); } int linux_capset(struct thread *td, struct linux_capset_args *args) { struct l_user_cap_header luch; struct l_user_cap_data lucd; int error; if (args->hdrp == NULL || args->datap == NULL) return (EFAULT); error = copyin(args->hdrp, &luch, sizeof(luch)); if (error != 0) return (error); if (luch.version != _LINUX_CAPABILITY_VERSION) { luch.version = _LINUX_CAPABILITY_VERSION; error = copyout(&luch, args->hdrp, sizeof(luch)); if (error) return (error); return (EINVAL); } if (luch.pid) return (EPERM); error = copyin(args->datap, &lucd, sizeof(lucd)); if (error != 0) return (error); /* We currently don't support setting any capabilities. */ if (lucd.effective || lucd.permitted || lucd.inheritable) { linux_msg(td, "capset effective=0x%x, permitted=0x%x, " "inheritable=0x%x is not implemented", (int)lucd.effective, (int)lucd.permitted, (int)lucd.inheritable); return (EPERM); } return (0); } int linux_prctl(struct thread *td, struct linux_prctl_args *args) { int error = 0, max_size; struct proc *p = td->td_proc; char comm[LINUX_MAX_COMM_LEN]; struct linux_emuldata *em; int pdeath_signal; #ifdef DEBUG if (ldebug(prctl)) printf(ARGS(prctl, "%d, %ju, %ju, %ju, %ju"), args->option, (uintmax_t)args->arg2, (uintmax_t)args->arg3, (uintmax_t)args->arg4, (uintmax_t)args->arg5); #endif switch (args->option) { case LINUX_PR_SET_PDEATHSIG: if (!LINUX_SIG_VALID(args->arg2)) return (EINVAL); em = em_find(td); KASSERT(em != NULL, ("prctl: emuldata not found.\n")); em->pdeath_signal = args->arg2; break; case LINUX_PR_GET_PDEATHSIG: em = em_find(td); KASSERT(em != NULL, ("prctl: emuldata not found.\n")); pdeath_signal = em->pdeath_signal; error = copyout(&pdeath_signal, (void *)(register_t)args->arg2, sizeof(pdeath_signal)); break; case LINUX_PR_GET_KEEPCAPS: /* * Indicate that we always clear the effective and * permitted capability sets when the user id becomes * non-zero (actually the capability sets are simply * always zero in the current implementation). */ td->td_retval[0] = 0; break; case LINUX_PR_SET_KEEPCAPS: /* * Ignore requests to keep the effective and permitted * capability sets when the user id becomes non-zero. */ break; case LINUX_PR_SET_NAME: /* * To be on the safe side we need to make sure to not * overflow the size a linux program expects. We already * do this here in the copyin, so that we don't need to * check on copyout. */ max_size = MIN(sizeof(comm), sizeof(p->p_comm)); error = copyinstr((void *)(register_t)args->arg2, comm, max_size, NULL); /* Linux silently truncates the name if it is too long. */ if (error == ENAMETOOLONG) { /* * XXX: copyinstr() isn't documented to populate the * array completely, so do a copyin() to be on the * safe side. This should be changed in case * copyinstr() is changed to guarantee this. */ error = copyin((void *)(register_t)args->arg2, comm, max_size - 1); comm[max_size - 1] = '\0'; } if (error) return (error); PROC_LOCK(p); strlcpy(p->p_comm, comm, sizeof(p->p_comm)); PROC_UNLOCK(p); break; case LINUX_PR_GET_NAME: PROC_LOCK(p); strlcpy(comm, p->p_comm, sizeof(comm)); PROC_UNLOCK(p); error = copyout(comm, (void *)(register_t)args->arg2, strlen(comm) + 1); break; default: error = EINVAL; break; } return (error); } int linux_sched_setparam(struct thread *td, struct linux_sched_setparam_args *uap) { struct sched_param sched_param; struct thread *tdt; int error; #ifdef DEBUG if (ldebug(sched_setparam)) printf(ARGS(sched_setparam, "%d, *"), uap->pid); #endif error = copyin(uap->param, &sched_param, sizeof(sched_param)); if (error) return (error); tdt = linux_tdfind(td, uap->pid, -1); if (tdt == NULL) return (ESRCH); error = kern_sched_setparam(td, tdt, &sched_param); PROC_UNLOCK(tdt->td_proc); return (error); } int linux_sched_getparam(struct thread *td, struct linux_sched_getparam_args *uap) { struct sched_param sched_param; struct thread *tdt; int error; #ifdef DEBUG if (ldebug(sched_getparam)) printf(ARGS(sched_getparam, "%d, *"), uap->pid); #endif tdt = linux_tdfind(td, uap->pid, -1); if (tdt == NULL) return (ESRCH); error = kern_sched_getparam(td, tdt, &sched_param); PROC_UNLOCK(tdt->td_proc); if (error == 0) error = copyout(&sched_param, uap->param, sizeof(sched_param)); return (error); } /* * Get affinity of a process. */ int linux_sched_getaffinity(struct thread *td, struct linux_sched_getaffinity_args *args) { int error; struct thread *tdt; - struct cpuset_getaffinity_args cga; #ifdef DEBUG if (ldebug(sched_getaffinity)) printf(ARGS(sched_getaffinity, "%d, %d, *"), args->pid, args->len); #endif if (args->len < sizeof(cpuset_t)) return (EINVAL); tdt = linux_tdfind(td, args->pid, -1); if (tdt == NULL) return (ESRCH); PROC_UNLOCK(tdt->td_proc); - cga.level = CPU_LEVEL_WHICH; - cga.which = CPU_WHICH_TID; - cga.id = tdt->td_tid; - cga.cpusetsize = sizeof(cpuset_t); - cga.mask = (cpuset_t *) args->user_mask_ptr; - if ((error = sys_cpuset_getaffinity(td, &cga)) == 0) + error = kern_cpuset_getaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, + tdt->td_tid, sizeof(cpuset_t), (cpuset_t *)args->user_mask_ptr); + if (error == 0) td->td_retval[0] = sizeof(cpuset_t); return (error); } /* * Set affinity of a process. */ int linux_sched_setaffinity(struct thread *td, struct linux_sched_setaffinity_args *args) { - struct cpuset_setaffinity_args csa; struct thread *tdt; #ifdef DEBUG if (ldebug(sched_setaffinity)) printf(ARGS(sched_setaffinity, "%d, %d, *"), args->pid, args->len); #endif if (args->len < sizeof(cpuset_t)) return (EINVAL); tdt = linux_tdfind(td, args->pid, -1); if (tdt == NULL) return (ESRCH); PROC_UNLOCK(tdt->td_proc); - csa.level = CPU_LEVEL_WHICH; - csa.which = CPU_WHICH_TID; - csa.id = tdt->td_tid; - csa.cpusetsize = sizeof(cpuset_t); - csa.mask = (cpuset_t *) args->user_mask_ptr; - return (sys_cpuset_setaffinity(td, &csa)); + return (kern_cpuset_setaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, + tdt->td_tid, sizeof(cpuset_t), (cpuset_t *) args->user_mask_ptr)); } struct linux_rlimit64 { uint64_t rlim_cur; uint64_t rlim_max; }; int linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args) { struct rlimit rlim, nrlim; struct linux_rlimit64 lrlim; struct proc *p; u_int which; int flags; int error; #ifdef DEBUG if (ldebug(prlimit64)) printf(ARGS(prlimit64, "%d, %d, %p, %p"), args->pid, args->resource, (void *)args->new, (void *)args->old); #endif if (args->resource >= LINUX_RLIM_NLIMITS) return (EINVAL); which = linux_to_bsd_resource[args->resource]; if (which == -1) return (EINVAL); if (args->new != NULL) { /* * Note. Unlike FreeBSD where rlim is signed 64-bit Linux * rlim is unsigned 64-bit. FreeBSD treats negative limits * as INFINITY so we do not need a conversion even. */ error = copyin(args->new, &nrlim, sizeof(nrlim)); if (error != 0) return (error); } flags = PGET_HOLD | PGET_NOTWEXIT; if (args->new != NULL) flags |= PGET_CANDEBUG; else flags |= PGET_CANSEE; error = pget(args->pid, flags, &p); if (error != 0) return (error); if (args->old != NULL) { PROC_LOCK(p); lim_rlimit_proc(p, which, &rlim); PROC_UNLOCK(p); if (rlim.rlim_cur == RLIM_INFINITY) lrlim.rlim_cur = LINUX_RLIM_INFINITY; else lrlim.rlim_cur = rlim.rlim_cur; if (rlim.rlim_max == RLIM_INFINITY) lrlim.rlim_max = LINUX_RLIM_INFINITY; else lrlim.rlim_max = rlim.rlim_max; error = copyout(&lrlim, args->old, sizeof(lrlim)); if (error != 0) goto out; } if (args->new != NULL) error = kern_proc_setrlimit(td, p, which, &nrlim); out: PRELE(p); return (error); } int linux_pselect6(struct thread *td, struct linux_pselect6_args *args) { struct timeval utv, tv0, tv1, *tvp; struct l_pselect6arg lpse6; struct l_timespec lts; struct timespec uts; l_sigset_t l_ss; sigset_t *ssp; sigset_t ss; int error; ssp = NULL; if (args->sig != NULL) { error = copyin(args->sig, &lpse6, sizeof(lpse6)); if (error != 0) return (error); if (lpse6.ss_len != sizeof(l_ss)) return (EINVAL); if (lpse6.ss != 0) { error = copyin(PTRIN(lpse6.ss), &l_ss, sizeof(l_ss)); if (error != 0) return (error); linux_to_bsd_sigset(&l_ss, &ss); ssp = &ss; } } /* * Currently glibc changes nanosecond number to microsecond. * This mean losing precision but for now it is hardly seen. */ if (args->tsp != NULL) { error = copyin(args->tsp, <s, sizeof(lts)); if (error != 0) return (error); error = linux_to_native_timespec(&uts, <s); if (error != 0) return (error); TIMESPEC_TO_TIMEVAL(&utv, &uts); if (itimerfix(&utv)) return (EINVAL); microtime(&tv0); tvp = &utv; } else tvp = NULL; error = kern_pselect(td, args->nfds, args->readfds, args->writefds, args->exceptfds, tvp, ssp, LINUX_NFDBITS); if (error == 0 && args->tsp != NULL) { if (td->td_retval[0] != 0) { /* * Compute how much time was left of the timeout, * by subtracting the current time and the time * before we started the call, and subtracting * that result from the user-supplied value. */ microtime(&tv1); timevalsub(&tv1, &tv0); timevalsub(&utv, &tv1); if (utv.tv_sec < 0) timevalclear(&utv); } else timevalclear(&utv); TIMEVAL_TO_TIMESPEC(&utv, &uts); native_to_linux_timespec(<s, &uts); error = copyout(<s, args->tsp, sizeof(lts)); } return (error); } int linux_ppoll(struct thread *td, struct linux_ppoll_args *args) { struct timespec ts0, ts1; struct l_timespec lts; struct timespec uts, *tsp; l_sigset_t l_ss; sigset_t *ssp; sigset_t ss; int error; if (args->sset != NULL) { if (args->ssize != sizeof(l_ss)) return (EINVAL); error = copyin(args->sset, &l_ss, sizeof(l_ss)); if (error) return (error); linux_to_bsd_sigset(&l_ss, &ss); ssp = &ss; } else ssp = NULL; if (args->tsp != NULL) { error = copyin(args->tsp, <s, sizeof(lts)); if (error) return (error); error = linux_to_native_timespec(&uts, <s); if (error != 0) return (error); nanotime(&ts0); tsp = &uts; } else tsp = NULL; error = kern_poll(td, args->fds, args->nfds, tsp, ssp); if (error == 0 && args->tsp != NULL) { if (td->td_retval[0]) { nanotime(&ts1); timespecsub(&ts1, &ts0); timespecsub(&uts, &ts1); if (uts.tv_sec < 0) timespecclear(&uts); } else timespecclear(&uts); native_to_linux_timespec(<s, &uts); error = copyout(<s, args->tsp, sizeof(lts)); } return (error); } #if defined(DEBUG) || defined(KTR) /* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */ #ifdef COMPAT_LINUX32 #define L_MAXSYSCALL LINUX32_SYS_MAXSYSCALL #else #define L_MAXSYSCALL LINUX_SYS_MAXSYSCALL #endif u_char linux_debug_map[howmany(L_MAXSYSCALL, sizeof(u_char))]; static int linux_debug(int syscall, int toggle, int global) { if (global) { char c = toggle ? 0 : 0xff; memset(linux_debug_map, c, sizeof(linux_debug_map)); return (0); } if (syscall < 0 || syscall >= L_MAXSYSCALL) return (EINVAL); if (toggle) clrbit(linux_debug_map, syscall); else setbit(linux_debug_map, syscall); return (0); } #undef L_MAXSYSCALL /* * Usage: sysctl linux.debug=.<0/1> * * E.g.: sysctl linux.debug=21.0 * * As a special case, syscall "all" will apply to all syscalls globally. */ #define LINUX_MAX_DEBUGSTR 16 int linux_sysctl_debug(SYSCTL_HANDLER_ARGS) { char value[LINUX_MAX_DEBUGSTR], *p; int error, sysc, toggle; int global = 0; value[0] = '\0'; error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req); if (error || req->newptr == NULL) return (error); for (p = value; *p != '\0' && *p != '.'; p++); if (*p == '\0') return (EINVAL); *p++ = '\0'; sysc = strtol(value, NULL, 0); toggle = strtol(p, NULL, 0); if (strcmp(value, "all") == 0) global = 1; error = linux_debug(sysc, toggle, global); return (error); } #endif /* DEBUG || KTR */ int linux_sched_rr_get_interval(struct thread *td, struct linux_sched_rr_get_interval_args *uap) { struct timespec ts; struct l_timespec lts; struct thread *tdt; int error; /* * According to man in case the invalid pid specified * EINVAL should be returned. */ if (uap->pid < 0) return (EINVAL); tdt = linux_tdfind(td, uap->pid, -1); if (tdt == NULL) return (ESRCH); error = kern_sched_rr_get_interval_td(td, tdt, &ts); PROC_UNLOCK(tdt->td_proc); if (error != 0) return (error); native_to_linux_timespec(<s, &ts); return (copyout(<s, uap->interval, sizeof(lts))); } /* * In case when the Linux thread is the initial thread in * the thread group thread id is equal to the process id. * Glibc depends on this magic (assert in pthread_getattr_np.c). */ struct thread * linux_tdfind(struct thread *td, lwpid_t tid, pid_t pid) { struct linux_emuldata *em; struct thread *tdt; struct proc *p; tdt = NULL; if (tid == 0 || tid == td->td_tid) { tdt = td; PROC_LOCK(tdt->td_proc); } else if (tid > PID_MAX) tdt = tdfind(tid, pid); else { /* * Initial thread where the tid equal to the pid. */ p = pfind(tid); if (p != NULL) { if (SV_PROC_ABI(p) != SV_ABI_LINUX) { /* * p is not a Linuxulator process. */ PROC_UNLOCK(p); return (NULL); } FOREACH_THREAD_IN_PROC(p, tdt) { em = em_find(tdt); if (tid == em->em_tid) return (tdt); } PROC_UNLOCK(p); } return (NULL); } return (tdt); } void linux_to_bsd_waitopts(int options, int *bsdopts) { if (options & LINUX_WNOHANG) *bsdopts |= WNOHANG; if (options & LINUX_WUNTRACED) *bsdopts |= WUNTRACED; if (options & LINUX_WEXITED) *bsdopts |= WEXITED; if (options & LINUX_WCONTINUED) *bsdopts |= WCONTINUED; if (options & LINUX_WNOWAIT) *bsdopts |= WNOWAIT; if (options & __WCLONE) *bsdopts |= WLINUXCLONE; } Index: projects/ipsec/sys/compat/linux/linux_socket.h =================================================================== --- projects/ipsec/sys/compat/linux/linux_socket.h (revision 313312) +++ projects/ipsec/sys/compat/linux/linux_socket.h (revision 313313) @@ -1,337 +1,224 @@ /*- * Copyright (c) 2000 Assar Westerlund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _LINUX_SOCKET_H_ #define _LINUX_SOCKET_H_ /* msg flags in recvfrom/recvmsg */ #define LINUX_MSG_OOB 0x01 #define LINUX_MSG_PEEK 0x02 #define LINUX_MSG_DONTROUTE 0x04 #define LINUX_MSG_CTRUNC 0x08 #define LINUX_MSG_PROXY 0x10 #define LINUX_MSG_TRUNC 0x20 #define LINUX_MSG_DONTWAIT 0x40 #define LINUX_MSG_EOR 0x80 #define LINUX_MSG_WAITALL 0x100 #define LINUX_MSG_FIN 0x200 #define LINUX_MSG_SYN 0x400 #define LINUX_MSG_CONFIRM 0x800 #define LINUX_MSG_RST 0x1000 #define LINUX_MSG_ERRQUEUE 0x2000 #define LINUX_MSG_NOSIGNAL 0x4000 #define LINUX_MSG_WAITFORONE 0x10000 #define LINUX_MSG_CMSG_CLOEXEC 0x40000000 /* Socket-level control message types */ #define LINUX_SCM_RIGHTS 0x01 #define LINUX_SCM_CREDENTIALS 0x02 #define LINUX_SCM_TIMESTAMP 0x1D struct l_msghdr { l_uintptr_t msg_name; l_int msg_namelen; l_uintptr_t msg_iov; l_size_t msg_iovlen; l_uintptr_t msg_control; l_size_t msg_controllen; l_uint msg_flags; }; struct l_mmsghdr { struct l_msghdr msg_hdr; l_uint msg_len; }; struct l_cmsghdr { l_size_t cmsg_len; l_int cmsg_level; l_int cmsg_type; }; /* Ancillary data object information macros */ #define LINUX_CMSG_ALIGN(len) roundup2(len, sizeof(l_ulong)) #define LINUX_CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + \ LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)))) #define LINUX_CMSG_SPACE(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ LINUX_CMSG_ALIGN(len)) #define LINUX_CMSG_LEN(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ (len)) #define LINUX_CMSG_FIRSTHDR(msg) \ ((msg)->msg_controllen >= \ sizeof(struct l_cmsghdr) ? \ (struct l_cmsghdr *) \ PTRIN((msg)->msg_control) : \ (struct l_cmsghdr *)(NULL)) #define LINUX_CMSG_NXTHDR(msg, cmsg) \ ((((char *)(cmsg) + \ LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \ sizeof(*(cmsg))) > \ (((char *)PTRIN((msg)->msg_control)) + \ (msg)->msg_controllen)) ? \ (struct l_cmsghdr *) NULL : \ (struct l_cmsghdr *)((char *)(cmsg) + \ LINUX_CMSG_ALIGN((cmsg)->cmsg_len))) #define CMSG_HDRSZ CMSG_LEN(0) #define L_CMSG_HDRSZ LINUX_CMSG_LEN(0) /* Supported address families */ #define LINUX_AF_UNSPEC 0 #define LINUX_AF_UNIX 1 #define LINUX_AF_INET 2 #define LINUX_AF_AX25 3 #define LINUX_AF_IPX 4 #define LINUX_AF_APPLETALK 5 #define LINUX_AF_INET6 10 /* Supported socket types */ #define LINUX_SOCK_STREAM 1 #define LINUX_SOCK_DGRAM 2 #define LINUX_SOCK_RAW 3 #define LINUX_SOCK_RDM 4 #define LINUX_SOCK_SEQPACKET 5 #define LINUX_SOCK_MAX LINUX_SOCK_SEQPACKET #define LINUX_SOCK_TYPE_MASK 0xf /* Flags for socket, socketpair, accept4 */ #define LINUX_SOCK_CLOEXEC LINUX_O_CLOEXEC #define LINUX_SOCK_NONBLOCK LINUX_O_NONBLOCK struct l_ucred { uint32_t pid; uint32_t uid; uint32_t gid; }; #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -struct linux_sendto_args { - int s; - l_uintptr_t msg; - int len; - int flags; - l_uintptr_t to; - int tolen; -}; - -struct linux_socket_args { - int domain; - int type; - int protocol; -}; - -struct linux_bind_args { - int s; - l_uintptr_t name; - int namelen; -}; - -struct linux_connect_args { - int s; - l_uintptr_t name; - int namelen; -}; - -struct linux_listen_args { - int s; - int backlog; -}; - struct linux_accept_args { int s; l_uintptr_t addr; l_uintptr_t namelen; }; -struct linux_accept4_args { - int s; - l_uintptr_t addr; - l_uintptr_t namelen; - int flags; -}; - -struct linux_getsockname_args { - int s; - l_uintptr_t addr; - l_uintptr_t namelen; -}; - -struct linux_getpeername_args { - int s; - l_uintptr_t addr; - l_uintptr_t namelen; -}; - -struct linux_socketpair_args { - int domain; - int type; - int protocol; - l_uintptr_t rsv; -}; - -struct linux_recvfrom_args { - int s; - l_uintptr_t buf; - int len; - int flags; - l_uintptr_t from; - l_uintptr_t fromlen; -}; - -struct linux_sendmsg_args { - int s; - l_uintptr_t msg; - int flags; -}; - -struct linux_recvmsg_args { - int s; - l_uintptr_t msg; - int flags; -}; - -struct linux_shutdown_args { - int s; - int how; -}; - -struct linux_setsockopt_args { - int s; - int level; - int optname; - l_uintptr_t optval; - int optlen; -}; - -struct linux_getsockopt_args { - int s; - int level; - int optname; - l_uintptr_t optval; - l_uintptr_t optlen; -}; - -int linux_socket(struct thread *td, struct linux_socket_args *args); -int linux_bind(struct thread *td, struct linux_bind_args *args); -int linux_connect(struct thread *, struct linux_connect_args *); -int linux_listen(struct thread *td, struct linux_listen_args *args); int linux_accept(struct thread *td, struct linux_accept_args *args); -int linux_accept4(struct thread *td, struct linux_accept4_args *args); -int linux_getsockname(struct thread *td, struct linux_getsockname_args *args); -int linux_getpeername(struct thread *td, struct linux_getpeername_args *args); -int linux_socketpair(struct thread *td, struct linux_socketpair_args *args); -int linux_sendto(struct thread *td, struct linux_sendto_args *args); -int linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args); -int linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args); -int linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args); -int linux_shutdown(struct thread *td, struct linux_shutdown_args *args); -int linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args); -int linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args); #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + + /* Operations for socketcall */ #define LINUX_SOCKET 1 #define LINUX_BIND 2 #define LINUX_CONNECT 3 #define LINUX_LISTEN 4 #define LINUX_ACCEPT 5 #define LINUX_GETSOCKNAME 6 #define LINUX_GETPEERNAME 7 #define LINUX_SOCKETPAIR 8 #define LINUX_SEND 9 #define LINUX_RECV 10 #define LINUX_SENDTO 11 #define LINUX_RECVFROM 12 #define LINUX_SHUTDOWN 13 #define LINUX_SETSOCKOPT 14 #define LINUX_GETSOCKOPT 15 #define LINUX_SENDMSG 16 #define LINUX_RECVMSG 17 #define LINUX_ACCEPT4 18 #define LINUX_RECVMMSG 19 #define LINUX_SENDMMSG 20 /* Socket options */ #define LINUX_IP_TOS 1 #define LINUX_IP_TTL 2 #define LINUX_IP_HDRINCL 3 #define LINUX_IP_OPTIONS 4 #define LINUX_IP_MULTICAST_IF 32 #define LINUX_IP_MULTICAST_TTL 33 #define LINUX_IP_MULTICAST_LOOP 34 #define LINUX_IP_ADD_MEMBERSHIP 35 #define LINUX_IP_DROP_MEMBERSHIP 36 #define LINUX_IPV6_CHECKSUM 7 #define LINUX_IPV6_NEXTHOP 9 #define LINUX_IPV6_UNICAST_HOPS 16 #define LINUX_IPV6_MULTICAST_IF 17 #define LINUX_IPV6_MULTICAST_HOPS 18 #define LINUX_IPV6_MULTICAST_LOOP 19 #define LINUX_IPV6_ADD_MEMBERSHIP 20 #define LINUX_IPV6_DROP_MEMBERSHIP 21 #define LINUX_IPV6_V6ONLY 26 #define LINUX_IPV6_RECVPKTINFO 49 #define LINUX_IPV6_PKTINFO 50 #define LINUX_IPV6_RECVHOPLIMIT 51 #define LINUX_IPV6_HOPLIMIT 52 #define LINUX_IPV6_RECVHOPOPTS 53 #define LINUX_IPV6_HOPOPTS 54 #define LINUX_IPV6_RTHDRDSTOPTS 55 #define LINUX_IPV6_RECVRTHDR 56 #define LINUX_IPV6_RTHDR 57 #define LINUX_IPV6_RECVDSTOPTS 58 #define LINUX_IPV6_DSTOPTS 59 #define LINUX_IPV6_RECVPATHMTU 60 #define LINUX_IPV6_PATHMTU 61 #define LINUX_IPV6_DONTFRAG 62 #define LINUX_TCP_NODELAY 1 #define LINUX_TCP_MAXSEG 2 #define LINUX_TCP_KEEPIDLE 4 #define LINUX_TCP_KEEPINTVL 5 #define LINUX_TCP_KEEPCNT 6 #define LINUX_TCP_MD5SIG 14 #endif /* _LINUX_SOCKET_H_ */ Index: projects/ipsec/sys/dev/iwm/if_iwm.c =================================================================== --- projects/ipsec/sys/dev/iwm/if_iwm.c (revision 313312) +++ projects/ipsec/sys/dev/iwm/if_iwm.c (revision 313313) @@ -1,6278 +1,6382 @@ /* $OpenBSD: if_iwm.c,v 1.42 2015/05/30 02:49:23 deraadt Exp $ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * * Driver version we are currently based off of is * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT * OWNER 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. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#define IWM_NVM_HW_SECTION_NUM_FAMILY_7000 0 +#define IWM_NVM_HW_SECTION_NUM_FAMILY_8000 10 + +/* lower blocks contain EEPROM image and calibration data */ +#define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_7000 (16 * 512 * sizeof(uint16_t)) /* 16 KB */ +#define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_8000 (32 * 512 * sizeof(uint16_t)) /* 32 KB */ + +#define IWM7260_FW "iwm7260fw" +#define IWM3160_FW "iwm3160fw" +#define IWM7265_FW "iwm7265fw" +#define IWM7265D_FW "iwm7265Dfw" +#define IWM8000_FW "iwm8000Cfw" + +#define IWM_DEVICE_7000_COMMON \ + .device_family = IWM_DEVICE_FAMILY_7000, \ + .eeprom_size = IWM_OTP_LOW_IMAGE_SIZE_FAMILY_7000, \ + .nvm_hw_section_num = IWM_NVM_HW_SECTION_NUM_FAMILY_7000 + +const struct iwm_cfg iwm7260_cfg = { + .fw_name = IWM7260_FW, + IWM_DEVICE_7000_COMMON, + .host_interrupt_operation_mode = 1, +}; + +const struct iwm_cfg iwm3160_cfg = { + .fw_name = IWM3160_FW, + IWM_DEVICE_7000_COMMON, + .host_interrupt_operation_mode = 1, +}; + +const struct iwm_cfg iwm3165_cfg = { + /* XXX IWM7265D_FW doesn't seem to work properly yet */ + .fw_name = IWM7265_FW, + IWM_DEVICE_7000_COMMON, + .host_interrupt_operation_mode = 0, +}; + +const struct iwm_cfg iwm7265_cfg = { + .fw_name = IWM7265_FW, + IWM_DEVICE_7000_COMMON, + .host_interrupt_operation_mode = 0, +}; + +const struct iwm_cfg iwm7265d_cfg = { + /* XXX IWM7265D_FW doesn't seem to work properly yet */ + .fw_name = IWM7265_FW, + IWM_DEVICE_7000_COMMON, + .host_interrupt_operation_mode = 0, +}; + +#define IWM_DEVICE_8000_COMMON \ + .device_family = IWM_DEVICE_FAMILY_8000, \ + .eeprom_size = IWM_OTP_LOW_IMAGE_SIZE_FAMILY_8000, \ + .nvm_hw_section_num = IWM_NVM_HW_SECTION_NUM_FAMILY_8000 + +const struct iwm_cfg iwm8260_cfg = { + .fw_name = IWM8000_FW, + IWM_DEVICE_8000_COMMON, + .host_interrupt_operation_mode = 0, +}; + const uint8_t iwm_nvm_channels[] = { /* 2.4 GHz */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 5 GHz */ 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165 }; _Static_assert(nitems(iwm_nvm_channels) <= IWM_NUM_CHANNELS, "IWM_NUM_CHANNELS is too small"); const uint8_t iwm_nvm_channels_8000[] = { /* 2.4 GHz */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 5 GHz */ 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, 177, 181 }; _Static_assert(nitems(iwm_nvm_channels_8000) <= IWM_NUM_CHANNELS_8000, "IWM_NUM_CHANNELS_8000 is too small"); #define IWM_NUM_2GHZ_CHANNELS 14 #define IWM_N_HW_ADDR_MASK 0xF /* * XXX For now, there's simply a fixed set of rate table entries * that are populated. */ const struct iwm_rate { uint8_t rate; uint8_t plcp; } iwm_rates[] = { { 2, IWM_RATE_1M_PLCP }, { 4, IWM_RATE_2M_PLCP }, { 11, IWM_RATE_5M_PLCP }, { 22, IWM_RATE_11M_PLCP }, { 12, IWM_RATE_6M_PLCP }, { 18, IWM_RATE_9M_PLCP }, { 24, IWM_RATE_12M_PLCP }, { 36, IWM_RATE_18M_PLCP }, { 48, IWM_RATE_24M_PLCP }, { 72, IWM_RATE_36M_PLCP }, { 96, IWM_RATE_48M_PLCP }, { 108, IWM_RATE_54M_PLCP }, }; #define IWM_RIDX_CCK 0 #define IWM_RIDX_OFDM 4 #define IWM_RIDX_MAX (nitems(iwm_rates)-1) #define IWM_RIDX_IS_CCK(_i_) ((_i_) < IWM_RIDX_OFDM) #define IWM_RIDX_IS_OFDM(_i_) ((_i_) >= IWM_RIDX_OFDM) struct iwm_nvm_section { uint16_t length; uint8_t *data; }; static int iwm_store_cscheme(struct iwm_softc *, const uint8_t *, size_t); static int iwm_firmware_store_section(struct iwm_softc *, enum iwm_ucode_type, const uint8_t *, size_t); static int iwm_set_default_calib(struct iwm_softc *, const void *); static void iwm_fw_info_free(struct iwm_fw_info *); static int iwm_read_firmware(struct iwm_softc *, enum iwm_ucode_type); static void iwm_dma_map_addr(void *, bus_dma_segment_t *, int, int); static int iwm_dma_contig_alloc(bus_dma_tag_t, struct iwm_dma_info *, bus_size_t, bus_size_t); static void iwm_dma_contig_free(struct iwm_dma_info *); static int iwm_alloc_fwmem(struct iwm_softc *); static int iwm_alloc_sched(struct iwm_softc *); static int iwm_alloc_kw(struct iwm_softc *); static int iwm_alloc_ict(struct iwm_softc *); static int iwm_alloc_rx_ring(struct iwm_softc *, struct iwm_rx_ring *); static void iwm_disable_rx_dma(struct iwm_softc *); static void iwm_reset_rx_ring(struct iwm_softc *, struct iwm_rx_ring *); static void iwm_free_rx_ring(struct iwm_softc *, struct iwm_rx_ring *); static int iwm_alloc_tx_ring(struct iwm_softc *, struct iwm_tx_ring *, int); static void iwm_reset_tx_ring(struct iwm_softc *, struct iwm_tx_ring *); static void iwm_free_tx_ring(struct iwm_softc *, struct iwm_tx_ring *); static void iwm_enable_interrupts(struct iwm_softc *); static void iwm_restore_interrupts(struct iwm_softc *); static void iwm_disable_interrupts(struct iwm_softc *); static void iwm_ict_reset(struct iwm_softc *); static int iwm_allow_mcast(struct ieee80211vap *, struct iwm_softc *); static void iwm_stop_device(struct iwm_softc *); static void iwm_mvm_nic_config(struct iwm_softc *); static int iwm_nic_rx_init(struct iwm_softc *); static int iwm_nic_tx_init(struct iwm_softc *); static int iwm_nic_init(struct iwm_softc *); static int iwm_enable_txq(struct iwm_softc *, int, int, int); static int iwm_post_alive(struct iwm_softc *); static int iwm_nvm_read_chunk(struct iwm_softc *, uint16_t, uint16_t, uint16_t, uint8_t *, uint16_t *); static int iwm_nvm_read_section(struct iwm_softc *, uint16_t, uint8_t *, - uint16_t *, size_t); + uint16_t *, uint32_t); static uint32_t iwm_eeprom_channel_flags(uint16_t); static void iwm_add_channel_band(struct iwm_softc *, struct ieee80211_channel[], int, int *, int, size_t, const uint8_t[]); static void iwm_init_channel_map(struct ieee80211com *, int, int *, struct ieee80211_channel[]); -static int iwm_parse_nvm_data(struct iwm_softc *, const uint16_t *, - const uint16_t *, const uint16_t *, - const uint16_t *, const uint16_t *, - const uint16_t *); -static void iwm_set_hw_address_8000(struct iwm_softc *, - struct iwm_nvm_data *, - const uint16_t *, const uint16_t *); +static struct iwm_nvm_data * + iwm_parse_nvm_data(struct iwm_softc *, const uint16_t *, + const uint16_t *, const uint16_t *, + const uint16_t *, const uint16_t *, + const uint16_t *); +static void iwm_free_nvm_data(struct iwm_nvm_data *); +static void iwm_set_hw_address_family_8000(struct iwm_softc *, + struct iwm_nvm_data *, + const uint16_t *, + const uint16_t *); static int iwm_get_sku(const struct iwm_softc *, const uint16_t *, const uint16_t *); static int iwm_get_nvm_version(const struct iwm_softc *, const uint16_t *); static int iwm_get_radio_cfg(const struct iwm_softc *, const uint16_t *, const uint16_t *); static int iwm_get_n_hw_addrs(const struct iwm_softc *, const uint16_t *); static void iwm_set_radio_cfg(const struct iwm_softc *, struct iwm_nvm_data *, uint32_t); -static int iwm_parse_nvm_sections(struct iwm_softc *, - struct iwm_nvm_section *); +static struct iwm_nvm_data * + iwm_parse_nvm_sections(struct iwm_softc *, struct iwm_nvm_section *); static int iwm_nvm_init(struct iwm_softc *); static int iwm_firmware_load_sect(struct iwm_softc *, uint32_t, const uint8_t *, uint32_t); static int iwm_firmware_load_chunk(struct iwm_softc *, uint32_t, const uint8_t *, uint32_t); static int iwm_load_firmware_7000(struct iwm_softc *, enum iwm_ucode_type); static int iwm_load_cpu_sections_8000(struct iwm_softc *, struct iwm_fw_sects *, int , int *); static int iwm_load_firmware_8000(struct iwm_softc *, enum iwm_ucode_type); static int iwm_load_firmware(struct iwm_softc *, enum iwm_ucode_type); static int iwm_start_fw(struct iwm_softc *, enum iwm_ucode_type); static int iwm_send_tx_ant_cfg(struct iwm_softc *, uint8_t); static int iwm_send_phy_cfg_cmd(struct iwm_softc *); static int iwm_mvm_load_ucode_wait_alive(struct iwm_softc *, enum iwm_ucode_type); static int iwm_run_init_mvm_ucode(struct iwm_softc *, int); static int iwm_rx_addbuf(struct iwm_softc *, int, int); static int iwm_mvm_calc_rssi(struct iwm_softc *, struct iwm_rx_phy_info *); static int iwm_mvm_get_signal_strength(struct iwm_softc *, struct iwm_rx_phy_info *); static void iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_rx_data *); static int iwm_get_noise(struct iwm_softc *sc, const struct iwm_mvm_statistics_rx_non_phy *); static void iwm_mvm_rx_rx_mpdu(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_rx_data *); static int iwm_mvm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_node *); static void iwm_mvm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_rx_data *); static void iwm_cmd_done(struct iwm_softc *, struct iwm_rx_packet *); #if 0 static void iwm_update_sched(struct iwm_softc *, int, int, uint8_t, uint16_t); #endif static const struct iwm_rate * iwm_tx_fill_cmd(struct iwm_softc *, struct iwm_node *, struct mbuf *, struct iwm_tx_cmd *); static int iwm_tx(struct iwm_softc *, struct mbuf *, struct ieee80211_node *, int); static int iwm_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static int iwm_mvm_flush_tx_path(struct iwm_softc *sc, uint32_t tfd_msk, uint32_t flags); static int iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *, struct iwm_mvm_add_sta_cmd_v7 *, int *); static int iwm_mvm_sta_send_to_fw(struct iwm_softc *, struct iwm_node *, int); static int iwm_mvm_add_sta(struct iwm_softc *, struct iwm_node *); static int iwm_mvm_update_sta(struct iwm_softc *, struct iwm_node *); static int iwm_mvm_add_int_sta_common(struct iwm_softc *, struct iwm_int_sta *, const uint8_t *, uint16_t, uint16_t); static int iwm_mvm_add_aux_sta(struct iwm_softc *); static int iwm_mvm_update_quotas(struct iwm_softc *, struct iwm_node *); static int iwm_auth(struct ieee80211vap *, struct iwm_softc *); static int iwm_assoc(struct ieee80211vap *, struct iwm_softc *); static int iwm_release(struct iwm_softc *, struct iwm_node *); static struct ieee80211_node * iwm_node_alloc(struct ieee80211vap *, const uint8_t[IEEE80211_ADDR_LEN]); static void iwm_setrates(struct iwm_softc *, struct iwm_node *); static int iwm_media_change(struct ifnet *); static int iwm_newstate(struct ieee80211vap *, enum ieee80211_state, int); static void iwm_endscan_cb(void *, int); static void iwm_mvm_fill_sf_command(struct iwm_softc *, struct iwm_sf_cfg_cmd *, struct ieee80211_node *); static int iwm_mvm_sf_config(struct iwm_softc *, enum iwm_sf_state); static int iwm_send_bt_init_conf(struct iwm_softc *); static int iwm_send_update_mcc_cmd(struct iwm_softc *, const char *); static void iwm_mvm_tt_tx_backoff(struct iwm_softc *, uint32_t); static int iwm_init_hw(struct iwm_softc *); static void iwm_init(struct iwm_softc *); static void iwm_start(struct iwm_softc *); static void iwm_stop(struct iwm_softc *); static void iwm_watchdog(void *); static void iwm_parent(struct ieee80211com *); #ifdef IWM_DEBUG static const char * iwm_desc_lookup(uint32_t); static void iwm_nic_error(struct iwm_softc *); static void iwm_nic_umac_error(struct iwm_softc *); #endif static void iwm_notif_intr(struct iwm_softc *); static void iwm_intr(void *); static int iwm_attach(device_t); static int iwm_is_valid_ether_addr(uint8_t *); static void iwm_preinit(void *); static int iwm_detach_local(struct iwm_softc *sc, int); static void iwm_init_task(void *); static void iwm_radiotap_attach(struct iwm_softc *); static struct ieee80211vap * iwm_vap_create(struct ieee80211com *, const char [IFNAMSIZ], int, enum ieee80211_opmode, int, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void iwm_vap_delete(struct ieee80211vap *); static void iwm_scan_start(struct ieee80211com *); static void iwm_scan_end(struct ieee80211com *); static void iwm_update_mcast(struct ieee80211com *); static void iwm_set_channel(struct ieee80211com *); static void iwm_scan_curchan(struct ieee80211_scan_state *, unsigned long); static void iwm_scan_mindwell(struct ieee80211_scan_state *); static int iwm_detach(device_t); /* * Firmware parser. */ static int iwm_store_cscheme(struct iwm_softc *sc, const uint8_t *data, size_t dlen) { const struct iwm_fw_cscheme_list *l = (const void *)data; if (dlen < sizeof(*l) || dlen < sizeof(l->size) + l->size * sizeof(*l->cs)) return EINVAL; /* we don't actually store anything for now, always use s/w crypto */ return 0; } static int iwm_firmware_store_section(struct iwm_softc *sc, enum iwm_ucode_type type, const uint8_t *data, size_t dlen) { struct iwm_fw_sects *fws; struct iwm_fw_onesect *fwone; if (type >= IWM_UCODE_TYPE_MAX) return EINVAL; if (dlen < sizeof(uint32_t)) return EINVAL; fws = &sc->sc_fw.fw_sects[type]; if (fws->fw_count >= IWM_UCODE_SECT_MAX) return EINVAL; fwone = &fws->fw_sect[fws->fw_count]; /* first 32bit are device load offset */ memcpy(&fwone->fws_devoff, data, sizeof(uint32_t)); /* rest is data */ fwone->fws_data = data + sizeof(uint32_t); fwone->fws_len = dlen - sizeof(uint32_t); fws->fw_count++; return 0; } #define IWM_DEFAULT_SCAN_CHANNELS 40 /* iwlwifi: iwl-drv.c */ struct iwm_tlv_calib_data { uint32_t ucode_type; struct iwm_tlv_calib_ctrl calib; } __packed; static int iwm_set_default_calib(struct iwm_softc *sc, const void *data) { const struct iwm_tlv_calib_data *def_calib = data; uint32_t ucode_type = le32toh(def_calib->ucode_type); if (ucode_type >= IWM_UCODE_TYPE_MAX) { device_printf(sc->sc_dev, "Wrong ucode_type %u for default " "calibration.\n", ucode_type); return EINVAL; } sc->sc_default_calib[ucode_type].flow_trigger = def_calib->calib.flow_trigger; sc->sc_default_calib[ucode_type].event_trigger = def_calib->calib.event_trigger; return 0; } static void iwm_fw_info_free(struct iwm_fw_info *fw) { firmware_put(fw->fw_fp, FIRMWARE_UNLOAD); fw->fw_fp = NULL; /* don't touch fw->fw_status */ memset(fw->fw_sects, 0, sizeof(fw->fw_sects)); } static int iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { struct iwm_fw_info *fw = &sc->sc_fw; const struct iwm_tlv_ucode_header *uhdr; struct iwm_ucode_tlv tlv; enum iwm_ucode_tlv_type tlv_type; const struct firmware *fwp; const uint8_t *data; int error = 0; size_t len; if (fw->fw_status == IWM_FW_STATUS_DONE && ucode_type != IWM_UCODE_TYPE_INIT) return 0; while (fw->fw_status == IWM_FW_STATUS_INPROGRESS) msleep(&sc->sc_fw, &sc->sc_mtx, 0, "iwmfwp", 0); fw->fw_status = IWM_FW_STATUS_INPROGRESS; if (fw->fw_fp != NULL) iwm_fw_info_free(fw); /* * Load firmware into driver memory. * fw_fp will be set. */ IWM_UNLOCK(sc); - fwp = firmware_get(sc->sc_fwname); + fwp = firmware_get(sc->cfg->fw_name); IWM_LOCK(sc); if (fwp == NULL) { device_printf(sc->sc_dev, "could not read firmware %s (error %d)\n", - sc->sc_fwname, error); + sc->cfg->fw_name, error); goto out; } fw->fw_fp = fwp; /* (Re-)Initialize default values. */ sc->sc_capaflags = 0; sc->sc_capa_n_scan_channels = IWM_DEFAULT_SCAN_CHANNELS; memset(sc->sc_enabled_capa, 0, sizeof(sc->sc_enabled_capa)); memset(sc->sc_fw_mcc, 0, sizeof(sc->sc_fw_mcc)); /* * Parse firmware contents */ uhdr = (const void *)fw->fw_fp->data; if (*(const uint32_t *)fw->fw_fp->data != 0 || le32toh(uhdr->magic) != IWM_TLV_UCODE_MAGIC) { device_printf(sc->sc_dev, "invalid firmware %s\n", - sc->sc_fwname); + sc->cfg->fw_name); error = EINVAL; goto out; } snprintf(sc->sc_fwver, sizeof(sc->sc_fwver), "%d.%d (API ver %d)", IWM_UCODE_MAJOR(le32toh(uhdr->ver)), IWM_UCODE_MINOR(le32toh(uhdr->ver)), IWM_UCODE_API(le32toh(uhdr->ver))); data = uhdr->data; len = fw->fw_fp->datasize - sizeof(*uhdr); while (len >= sizeof(tlv)) { size_t tlv_len; const void *tlv_data; memcpy(&tlv, data, sizeof(tlv)); tlv_len = le32toh(tlv.length); tlv_type = le32toh(tlv.type); len -= sizeof(tlv); data += sizeof(tlv); tlv_data = data; if (len < tlv_len) { device_printf(sc->sc_dev, "firmware too short: %zu bytes\n", len); error = EINVAL; goto parse_out; } switch ((int)tlv_type) { case IWM_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len < sizeof(uint32_t)) { device_printf(sc->sc_dev, "%s: PROBE_MAX_LEN (%d) < sizeof(uint32_t)\n", __func__, (int) tlv_len); error = EINVAL; goto parse_out; } sc->sc_capa_max_probe_len = le32toh(*(const uint32_t *)tlv_data); /* limit it to something sensible */ if (sc->sc_capa_max_probe_len > IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE) { IWM_DPRINTF(sc, IWM_DEBUG_FIRMWARE_TLV, "%s: IWM_UCODE_TLV_PROBE_MAX_LEN " "ridiculous\n", __func__); error = EINVAL; goto parse_out; } break; case IWM_UCODE_TLV_PAN: if (tlv_len) { device_printf(sc->sc_dev, "%s: IWM_UCODE_TLV_PAN: tlv_len (%d) > 0\n", __func__, (int) tlv_len); error = EINVAL; goto parse_out; } sc->sc_capaflags |= IWM_UCODE_TLV_FLAGS_PAN; break; case IWM_UCODE_TLV_FLAGS: if (tlv_len < sizeof(uint32_t)) { device_printf(sc->sc_dev, "%s: IWM_UCODE_TLV_FLAGS: tlv_len (%d) < sizeof(uint32_t)\n", __func__, (int) tlv_len); error = EINVAL; goto parse_out; } /* * Apparently there can be many flags, but Linux driver * parses only the first one, and so do we. * * XXX: why does this override IWM_UCODE_TLV_PAN? * Intentional or a bug? Observations from * current firmware file: * 1) TLV_PAN is parsed first * 2) TLV_FLAGS contains TLV_FLAGS_PAN * ==> this resets TLV_PAN to itself... hnnnk */ sc->sc_capaflags = le32toh(*(const uint32_t *)tlv_data); break; case IWM_UCODE_TLV_CSCHEME: if ((error = iwm_store_cscheme(sc, tlv_data, tlv_len)) != 0) { device_printf(sc->sc_dev, "%s: iwm_store_cscheme(): returned %d\n", __func__, error); goto parse_out; } break; case IWM_UCODE_TLV_NUM_OF_CPU: { uint32_t num_cpu; if (tlv_len != sizeof(uint32_t)) { device_printf(sc->sc_dev, "%s: IWM_UCODE_TLV_NUM_OF_CPU: tlv_len (%d) < sizeof(uint32_t)\n", __func__, (int) tlv_len); error = EINVAL; goto parse_out; } num_cpu = le32toh(*(const uint32_t *)tlv_data); if (num_cpu < 1 || num_cpu > 2) { device_printf(sc->sc_dev, "%s: Driver supports only 1 or 2 CPUs\n", __func__); error = EINVAL; goto parse_out; } break; } case IWM_UCODE_TLV_SEC_RT: if ((error = iwm_firmware_store_section(sc, IWM_UCODE_TYPE_REGULAR, tlv_data, tlv_len)) != 0) { device_printf(sc->sc_dev, "%s: IWM_UCODE_TYPE_REGULAR: iwm_firmware_store_section() failed; %d\n", __func__, error); goto parse_out; } break; case IWM_UCODE_TLV_SEC_INIT: if ((error = iwm_firmware_store_section(sc, IWM_UCODE_TYPE_INIT, tlv_data, tlv_len)) != 0) { device_printf(sc->sc_dev, "%s: IWM_UCODE_TYPE_INIT: iwm_firmware_store_section() failed; %d\n", __func__, error); goto parse_out; } break; case IWM_UCODE_TLV_SEC_WOWLAN: if ((error = iwm_firmware_store_section(sc, IWM_UCODE_TYPE_WOW, tlv_data, tlv_len)) != 0) { device_printf(sc->sc_dev, "%s: IWM_UCODE_TYPE_WOW: iwm_firmware_store_section() failed; %d\n", __func__, error); goto parse_out; } break; case IWM_UCODE_TLV_DEF_CALIB: if (tlv_len != sizeof(struct iwm_tlv_calib_data)) { device_printf(sc->sc_dev, "%s: IWM_UCODE_TLV_DEV_CALIB: tlv_len (%d) < sizeof(iwm_tlv_calib_data) (%d)\n", __func__, (int) tlv_len, (int) sizeof(struct iwm_tlv_calib_data)); error = EINVAL; goto parse_out; } if ((error = iwm_set_default_calib(sc, tlv_data)) != 0) { device_printf(sc->sc_dev, "%s: iwm_set_default_calib() failed: %d\n", __func__, error); goto parse_out; } break; case IWM_UCODE_TLV_PHY_SKU: if (tlv_len != sizeof(uint32_t)) { error = EINVAL; device_printf(sc->sc_dev, "%s: IWM_UCODE_TLV_PHY_SKU: tlv_len (%d) < sizeof(uint32_t)\n", __func__, (int) tlv_len); goto parse_out; } sc->sc_fw_phy_config = le32toh(*(const uint32_t *)tlv_data); break; case IWM_UCODE_TLV_API_CHANGES_SET: { const struct iwm_ucode_api *api; if (tlv_len != sizeof(*api)) { error = EINVAL; goto parse_out; } api = (const struct iwm_ucode_api *)tlv_data; /* Flags may exceed 32 bits in future firmware. */ if (le32toh(api->api_index) > 0) { device_printf(sc->sc_dev, "unsupported API index %d\n", le32toh(api->api_index)); goto parse_out; } sc->sc_ucode_api = le32toh(api->api_flags); break; } case IWM_UCODE_TLV_ENABLED_CAPABILITIES: { const struct iwm_ucode_capa *capa; int idx, i; if (tlv_len != sizeof(*capa)) { error = EINVAL; goto parse_out; } capa = (const struct iwm_ucode_capa *)tlv_data; idx = le32toh(capa->api_index); if (idx >= howmany(IWM_NUM_UCODE_TLV_CAPA, 32)) { device_printf(sc->sc_dev, "unsupported API index %d\n", idx); goto parse_out; } for (i = 0; i < 32; i++) { if ((le32toh(capa->api_capa) & (1U << i)) == 0) continue; setbit(sc->sc_enabled_capa, i + (32 * idx)); } break; } case 48: /* undocumented TLV */ case IWM_UCODE_TLV_SDIO_ADMA_ADDR: case IWM_UCODE_TLV_FW_GSCAN_CAPA: /* ignore, not used by current driver */ break; case IWM_UCODE_TLV_SEC_RT_USNIFFER: if ((error = iwm_firmware_store_section(sc, IWM_UCODE_TYPE_REGULAR_USNIFFER, tlv_data, tlv_len)) != 0) goto parse_out; break; case IWM_UCODE_TLV_N_SCAN_CHANNELS: if (tlv_len != sizeof(uint32_t)) { error = EINVAL; goto parse_out; } sc->sc_capa_n_scan_channels = le32toh(*(const uint32_t *)tlv_data); break; case IWM_UCODE_TLV_FW_VERSION: if (tlv_len != sizeof(uint32_t) * 3) { error = EINVAL; goto parse_out; } snprintf(sc->sc_fwver, sizeof(sc->sc_fwver), "%d.%d.%d", le32toh(((const uint32_t *)tlv_data)[0]), le32toh(((const uint32_t *)tlv_data)[1]), le32toh(((const uint32_t *)tlv_data)[2])); break; default: device_printf(sc->sc_dev, "%s: unknown firmware section %d, abort\n", __func__, tlv_type); error = EINVAL; goto parse_out; } len -= roundup(tlv_len, 4); data += roundup(tlv_len, 4); } KASSERT(error == 0, ("unhandled error")); parse_out: if (error) { device_printf(sc->sc_dev, "firmware parse error %d, " "section type %d\n", error, tlv_type); } if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) { device_printf(sc->sc_dev, "device uses unsupported power ops\n"); error = ENOTSUP; } out: if (error) { fw->fw_status = IWM_FW_STATUS_NONE; if (fw->fw_fp != NULL) iwm_fw_info_free(fw); } else fw->fw_status = IWM_FW_STATUS_DONE; wakeup(&sc->sc_fw); return error; } /* * DMA resource routines */ static void iwm_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { if (error != 0) return; KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); *(bus_addr_t *)arg = segs[0].ds_addr; } static int iwm_dma_contig_alloc(bus_dma_tag_t tag, struct iwm_dma_info *dma, bus_size_t size, bus_size_t alignment) { int error; dma->tag = NULL; dma->map = NULL; dma->size = size; dma->vaddr = NULL; error = bus_dma_tag_create(tag, alignment, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, NULL, NULL, &dma->tag); if (error != 0) goto fail; error = bus_dmamem_alloc(dma->tag, (void **)&dma->vaddr, BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, &dma->map); if (error != 0) goto fail; error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr, size, iwm_dma_map_addr, &dma->paddr, BUS_DMA_NOWAIT); if (error != 0) { bus_dmamem_free(dma->tag, dma->vaddr, dma->map); dma->vaddr = NULL; goto fail; } bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); return 0; fail: iwm_dma_contig_free(dma); return error; } static void iwm_dma_contig_free(struct iwm_dma_info *dma) { if (dma->vaddr != NULL) { bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(dma->tag, dma->map); bus_dmamem_free(dma->tag, dma->vaddr, dma->map); dma->vaddr = NULL; } if (dma->tag != NULL) { bus_dma_tag_destroy(dma->tag); dma->tag = NULL; } } /* fwmem is used to load firmware onto the card */ static int iwm_alloc_fwmem(struct iwm_softc *sc) { /* Must be aligned on a 16-byte boundary. */ return iwm_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma, sc->sc_fwdmasegsz, 16); } /* tx scheduler rings. not used? */ static int iwm_alloc_sched(struct iwm_softc *sc) { /* TX scheduler rings must be aligned on a 1KB boundary. */ return iwm_dma_contig_alloc(sc->sc_dmat, &sc->sched_dma, nitems(sc->txq) * sizeof(struct iwm_agn_scd_bc_tbl), 1024); } /* keep-warm page is used internally by the card. see iwl-fh.h for more info */ static int iwm_alloc_kw(struct iwm_softc *sc) { return iwm_dma_contig_alloc(sc->sc_dmat, &sc->kw_dma, 4096, 4096); } /* interrupt cause table */ static int iwm_alloc_ict(struct iwm_softc *sc) { return iwm_dma_contig_alloc(sc->sc_dmat, &sc->ict_dma, IWM_ICT_SIZE, 1<cur = 0; /* Allocate RX descriptors (256-byte aligned). */ size = IWM_RX_RING_COUNT * sizeof(uint32_t); error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, size, 256); if (error != 0) { device_printf(sc->sc_dev, "could not allocate RX ring DMA memory\n"); goto fail; } ring->desc = ring->desc_dma.vaddr; /* Allocate RX status area (16-byte aligned). */ error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->stat_dma, sizeof(*ring->stat), 16); if (error != 0) { device_printf(sc->sc_dev, "could not allocate RX status DMA memory\n"); goto fail; } ring->stat = ring->stat_dma.vaddr; /* Create RX buffer DMA tag. */ error = bus_dma_tag_create(sc->sc_dmat, 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, IWM_RBUF_SIZE, 1, IWM_RBUF_SIZE, 0, NULL, NULL, &ring->data_dmat); if (error != 0) { device_printf(sc->sc_dev, "%s: could not create RX buf DMA tag, error %d\n", __func__, error); goto fail; } /* Allocate spare bus_dmamap_t for iwm_rx_addbuf() */ error = bus_dmamap_create(ring->data_dmat, 0, &ring->spare_map); if (error != 0) { device_printf(sc->sc_dev, "%s: could not create RX buf DMA map, error %d\n", __func__, error); goto fail; } /* * Allocate and map RX buffers. */ for (i = 0; i < IWM_RX_RING_COUNT; i++) { struct iwm_rx_data *data = &ring->data[i]; error = bus_dmamap_create(ring->data_dmat, 0, &data->map); if (error != 0) { device_printf(sc->sc_dev, "%s: could not create RX buf DMA map, error %d\n", __func__, error); goto fail; } data->m = NULL; if ((error = iwm_rx_addbuf(sc, IWM_RBUF_SIZE, i)) != 0) { goto fail; } } return 0; fail: iwm_free_rx_ring(sc, ring); return error; } static void iwm_disable_rx_dma(struct iwm_softc *sc) { /* XXX conditional nic locks are stupid */ /* XXX print out if we can't lock the NIC? */ if (iwm_nic_lock(sc)) { /* XXX handle if RX stop doesn't finish? */ (void) iwm_pcie_rx_stop(sc); iwm_nic_unlock(sc); } } static void iwm_reset_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) { /* Reset the ring state */ ring->cur = 0; /* * The hw rx ring index in shared memory must also be cleared, * otherwise the discrepancy can cause reprocessing chaos. */ memset(sc->rxq.stat, 0, sizeof(*sc->rxq.stat)); } static void iwm_free_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) { int i; iwm_dma_contig_free(&ring->desc_dma); iwm_dma_contig_free(&ring->stat_dma); for (i = 0; i < IWM_RX_RING_COUNT; i++) { struct iwm_rx_data *data = &ring->data[i]; if (data->m != NULL) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; } if (data->map != NULL) { bus_dmamap_destroy(ring->data_dmat, data->map); data->map = NULL; } } if (ring->spare_map != NULL) { bus_dmamap_destroy(ring->data_dmat, ring->spare_map); ring->spare_map = NULL; } if (ring->data_dmat != NULL) { bus_dma_tag_destroy(ring->data_dmat); ring->data_dmat = NULL; } } static int iwm_alloc_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring, int qid) { bus_addr_t paddr; bus_size_t size; size_t maxsize; int nsegments; int i, error; ring->qid = qid; ring->queued = 0; ring->cur = 0; /* Allocate TX descriptors (256-byte aligned). */ size = IWM_TX_RING_COUNT * sizeof (struct iwm_tfd); error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, size, 256); if (error != 0) { device_printf(sc->sc_dev, "could not allocate TX ring DMA memory\n"); goto fail; } ring->desc = ring->desc_dma.vaddr; /* * We only use rings 0 through 9 (4 EDCA + cmd) so there is no need * to allocate commands space for other rings. */ if (qid > IWM_MVM_CMD_QUEUE) return 0; size = IWM_TX_RING_COUNT * sizeof(struct iwm_device_cmd); error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, size, 4); if (error != 0) { device_printf(sc->sc_dev, "could not allocate TX cmd DMA memory\n"); goto fail; } ring->cmd = ring->cmd_dma.vaddr; /* FW commands may require more mapped space than packets. */ if (qid == IWM_MVM_CMD_QUEUE) { maxsize = IWM_RBUF_SIZE; nsegments = 1; } else { maxsize = MCLBYTES; nsegments = IWM_MAX_SCATTER - 2; } error = bus_dma_tag_create(sc->sc_dmat, 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, maxsize, nsegments, maxsize, 0, NULL, NULL, &ring->data_dmat); if (error != 0) { device_printf(sc->sc_dev, "could not create TX buf DMA tag\n"); goto fail; } paddr = ring->cmd_dma.paddr; for (i = 0; i < IWM_TX_RING_COUNT; i++) { struct iwm_tx_data *data = &ring->data[i]; data->cmd_paddr = paddr; data->scratch_paddr = paddr + sizeof(struct iwm_cmd_header) + offsetof(struct iwm_tx_cmd, scratch); paddr += sizeof(struct iwm_device_cmd); error = bus_dmamap_create(ring->data_dmat, 0, &data->map); if (error != 0) { device_printf(sc->sc_dev, "could not create TX buf DMA map\n"); goto fail; } } KASSERT(paddr == ring->cmd_dma.paddr + size, ("invalid physical address")); return 0; fail: iwm_free_tx_ring(sc, ring); return error; } static void iwm_reset_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring) { int i; for (i = 0; i < IWM_TX_RING_COUNT; i++) { struct iwm_tx_data *data = &ring->data[i]; if (data->m != NULL) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; } } /* Clear TX descriptors. */ memset(ring->desc, 0, ring->desc_dma.size); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); sc->qfullmsk &= ~(1 << ring->qid); ring->queued = 0; ring->cur = 0; } static void iwm_free_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring) { int i; iwm_dma_contig_free(&ring->desc_dma); iwm_dma_contig_free(&ring->cmd_dma); for (i = 0; i < IWM_TX_RING_COUNT; i++) { struct iwm_tx_data *data = &ring->data[i]; if (data->m != NULL) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; } if (data->map != NULL) { bus_dmamap_destroy(ring->data_dmat, data->map); data->map = NULL; } } if (ring->data_dmat != NULL) { bus_dma_tag_destroy(ring->data_dmat); ring->data_dmat = NULL; } } /* * High-level hardware frobbing routines */ static void iwm_enable_interrupts(struct iwm_softc *sc) { sc->sc_intmask = IWM_CSR_INI_SET_MASK; IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); } static void iwm_restore_interrupts(struct iwm_softc *sc) { IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); } static void iwm_disable_interrupts(struct iwm_softc *sc) { /* disable interrupts */ IWM_WRITE(sc, IWM_CSR_INT_MASK, 0); /* acknowledge all interrupts */ IWM_WRITE(sc, IWM_CSR_INT, ~0); IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, ~0); } static void iwm_ict_reset(struct iwm_softc *sc) { iwm_disable_interrupts(sc); /* Reset ICT table. */ memset(sc->ict_dma.vaddr, 0, IWM_ICT_SIZE); sc->ict_cur = 0; /* Set physical address of ICT table (4KB aligned). */ IWM_WRITE(sc, IWM_CSR_DRAM_INT_TBL_REG, IWM_CSR_DRAM_INT_TBL_ENABLE | IWM_CSR_DRAM_INIT_TBL_WRITE_POINTER | IWM_CSR_DRAM_INIT_TBL_WRAP_CHECK | sc->ict_dma.paddr >> IWM_ICT_PADDR_SHIFT); /* Switch to ICT interrupt mode in driver. */ sc->sc_flags |= IWM_FLAG_USE_ICT; /* Re-enable interrupts. */ IWM_WRITE(sc, IWM_CSR_INT, ~0); iwm_enable_interrupts(sc); } /* iwlwifi pcie/trans.c */ /* * Since this .. hard-resets things, it's time to actually * mark the first vap (if any) as having no mac context. * It's annoying, but since the driver is potentially being * stop/start'ed whilst active (thanks openbsd port!) we * have to correctly track this. */ static void iwm_stop_device(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); int chnl, qid; uint32_t mask = 0; /* tell the device to stop sending interrupts */ iwm_disable_interrupts(sc); /* * FreeBSD-local: mark the first vap as not-uploaded, * so the next transition through auth/assoc * will correctly populate the MAC context. */ if (vap) { struct iwm_vap *iv = IWM_VAP(vap); iv->is_uploaded = 0; } /* device going down, Stop using ICT table */ sc->sc_flags &= ~IWM_FLAG_USE_ICT; /* stop tx and rx. tx and rx bits, as usual, are from if_iwn */ iwm_write_prph(sc, IWM_SCD_TXFACT, 0); if (iwm_nic_lock(sc)) { /* Stop each Tx DMA channel */ for (chnl = 0; chnl < IWM_FH_TCSR_CHNL_NUM; chnl++) { IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl), 0); mask |= IWM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(chnl); } /* Wait for DMA channels to be idle */ if (!iwm_poll_bit(sc, IWM_FH_TSSR_TX_STATUS_REG, mask, mask, 5000)) { device_printf(sc->sc_dev, "Failing on timeout while stopping DMA channel: [0x%08x]\n", IWM_READ(sc, IWM_FH_TSSR_TX_STATUS_REG)); } iwm_nic_unlock(sc); } iwm_disable_rx_dma(sc); /* Stop RX ring. */ iwm_reset_rx_ring(sc, &sc->rxq); /* Reset all TX rings. */ for (qid = 0; qid < nitems(sc->txq); qid++) iwm_reset_tx_ring(sc, &sc->txq[qid]); /* * Power-down device's busmaster DMA clocks */ iwm_write_prph(sc, IWM_APMG_CLK_DIS_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT); DELAY(5); /* Make sure (redundant) we've released our request to stay awake */ IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* Stop the device, and put it in low power state */ iwm_apm_stop(sc); /* Upon stop, the APM issues an interrupt if HW RF kill is set. * Clean again the interrupt here */ iwm_disable_interrupts(sc); /* stop and reset the on-board processor */ IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET); /* * Even if we stop the HW, we still want the RF kill * interrupt */ iwm_enable_rfkill_int(sc); iwm_check_rfkill(sc); } /* iwlwifi: mvm/ops.c */ static void iwm_mvm_nic_config(struct iwm_softc *sc) { uint8_t radio_cfg_type, radio_cfg_step, radio_cfg_dash; uint32_t reg_val = 0; radio_cfg_type = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_TYPE) >> IWM_FW_PHY_CFG_RADIO_TYPE_POS; radio_cfg_step = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_STEP) >> IWM_FW_PHY_CFG_RADIO_STEP_POS; radio_cfg_dash = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_DASH) >> IWM_FW_PHY_CFG_RADIO_DASH_POS; /* SKU control */ reg_val |= IWM_CSR_HW_REV_STEP(sc->sc_hw_rev) << IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; reg_val |= IWM_CSR_HW_REV_DASH(sc->sc_hw_rev) << IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; /* radio configuration */ reg_val |= radio_cfg_type << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; reg_val |= radio_cfg_step << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; reg_val |= radio_cfg_dash << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; IWM_WRITE(sc, IWM_CSR_HW_IF_CONFIG_REG, reg_val); IWM_DPRINTF(sc, IWM_DEBUG_RESET, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, radio_cfg_step, radio_cfg_dash); /* * W/A : NIC is stuck in a reset state after Early PCIe power off * (PCIe power is lost before PERST# is asserted), causing ME FW * to lose ownership and not being able to obtain it back. */ - if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) { iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG, IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); } } static int iwm_nic_rx_init(struct iwm_softc *sc) { if (!iwm_nic_lock(sc)) return EBUSY; /* * Initialize RX ring. This is from the iwn driver. */ memset(sc->rxq.stat, 0, sizeof(*sc->rxq.stat)); /* stop DMA */ iwm_disable_rx_dma(sc); IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0); IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0); IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RDPTR, 0); IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); /* Set physical address of RX ring (256-byte aligned). */ IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG, sc->rxq.desc_dma.paddr >> 8); /* Set physical address of RX status (16-byte aligned). */ IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG, sc->rxq.stat_dma.paddr >> 4); /* Enable RX. */ IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, IWM_FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | /* HW bug */ IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | IWM_FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK | (IWM_RX_RB_TIMEOUT << IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) | IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K | IWM_RX_QUEUE_SIZE_LOG << IWM_FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS); IWM_WRITE_1(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_TIMEOUT_DEF); /* W/A for interrupt coalescing bug in 7260 and 3160 */ - if (sc->host_interrupt_operation_mode) + if (sc->cfg->host_interrupt_operation_mode) IWM_SETBITS(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_OPER_MODE); /* * Thus sayeth el jefe (iwlwifi) via a comment: * * This value should initially be 0 (before preparing any * RBs), should be 8 after preparing the first 8 RBs (for example) */ IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, 8); iwm_nic_unlock(sc); return 0; } static int iwm_nic_tx_init(struct iwm_softc *sc) { int qid; if (!iwm_nic_lock(sc)) return EBUSY; /* Deactivate TX scheduler. */ iwm_write_prph(sc, IWM_SCD_TXFACT, 0); /* Set physical address of "keep warm" page (16-byte aligned). */ IWM_WRITE(sc, IWM_FH_KW_MEM_ADDR_REG, sc->kw_dma.paddr >> 4); /* Initialize TX rings. */ for (qid = 0; qid < nitems(sc->txq); qid++) { struct iwm_tx_ring *txq = &sc->txq[qid]; /* Set physical address of TX ring (256-byte aligned). */ IWM_WRITE(sc, IWM_FH_MEM_CBBC_QUEUE(qid), txq->desc_dma.paddr >> 8); IWM_DPRINTF(sc, IWM_DEBUG_XMIT, "%s: loading ring %d descriptors (%p) at %lx\n", __func__, qid, txq->desc, (unsigned long) (txq->desc_dma.paddr >> 8)); } iwm_write_prph(sc, IWM_SCD_GP_CTRL, IWM_SCD_GP_CTRL_AUTO_ACTIVE_MODE); iwm_nic_unlock(sc); return 0; } static int iwm_nic_init(struct iwm_softc *sc) { int error; iwm_apm_init(sc); - if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) iwm_set_pwr(sc); iwm_mvm_nic_config(sc); if ((error = iwm_nic_rx_init(sc)) != 0) return error; /* * Ditto for TX, from iwn */ if ((error = iwm_nic_tx_init(sc)) != 0) return error; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "%s: shadow registers enabled\n", __func__); IWM_SETBITS(sc, IWM_CSR_MAC_SHADOW_REG_CTRL, 0x800fffff); return 0; } const uint8_t iwm_mvm_ac_to_tx_fifo[] = { IWM_MVM_TX_FIFO_VO, IWM_MVM_TX_FIFO_VI, IWM_MVM_TX_FIFO_BE, IWM_MVM_TX_FIFO_BK, }; static int iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo) { if (!iwm_nic_lock(sc)) { device_printf(sc->sc_dev, "%s: cannot enable txq %d\n", __func__, qid); return EBUSY; } IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0); if (qid == IWM_MVM_CMD_QUEUE) { /* unactivate before configuration */ iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid), (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) | (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid)); iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0); iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0); /* Set scheduler window size and frame limit. */ iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) + sizeof(uint32_t), ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid), (1 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) | (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) | (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) | IWM_SCD_QUEUE_STTS_REG_MSK); } else { struct iwm_scd_txq_cfg_cmd cmd; int error; iwm_nic_unlock(sc); memset(&cmd, 0, sizeof(cmd)); cmd.scd_queue = qid; cmd.enable = 1; cmd.sta_id = sta_id; cmd.tx_fifo = fifo; cmd.aggregate = 0; cmd.window = IWM_FRAME_LIMIT; error = iwm_mvm_send_cmd_pdu(sc, IWM_SCD_QUEUE_CFG, IWM_CMD_SYNC, sizeof(cmd), &cmd); if (error) { device_printf(sc->sc_dev, "cannot enable txq %d\n", qid); return error; } if (!iwm_nic_lock(sc)) return EBUSY; } iwm_write_prph(sc, IWM_SCD_EN_CTRL, iwm_read_prph(sc, IWM_SCD_EN_CTRL) | qid); iwm_nic_unlock(sc); IWM_DPRINTF(sc, IWM_DEBUG_XMIT, "%s: enabled txq %d FIFO %d\n", __func__, qid, fifo); return 0; } static int iwm_post_alive(struct iwm_softc *sc) { int nwords; int error, chnl; uint32_t base; if (!iwm_nic_lock(sc)) return EBUSY; base = iwm_read_prph(sc, IWM_SCD_SRAM_BASE_ADDR); if (sc->sched_base != base) { device_printf(sc->sc_dev, "%s: sched addr mismatch: alive: 0x%x prph: 0x%x\n", __func__, sc->sched_base, base); } iwm_ict_reset(sc); /* Clear TX scheduler state in SRAM. */ nwords = (IWM_SCD_TRANS_TBL_MEM_UPPER_BOUND - IWM_SCD_CONTEXT_MEM_LOWER_BOUND) / sizeof(uint32_t); error = iwm_write_mem(sc, sc->sched_base + IWM_SCD_CONTEXT_MEM_LOWER_BOUND, NULL, nwords); if (error) goto out; /* Set physical address of TX scheduler rings (1KB aligned). */ iwm_write_prph(sc, IWM_SCD_DRAM_BASE_ADDR, sc->sched_dma.paddr >> 10); iwm_write_prph(sc, IWM_SCD_CHAINEXT_EN, 0); iwm_nic_unlock(sc); /* enable command channel */ error = iwm_enable_txq(sc, 0 /* unused */, IWM_MVM_CMD_QUEUE, 7); if (error) return error; if (!iwm_nic_lock(sc)) return EBUSY; iwm_write_prph(sc, IWM_SCD_TXFACT, 0xff); /* Enable DMA channels. */ for (chnl = 0; chnl < IWM_FH_TCSR_CHNL_NUM; chnl++) { IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl), IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); } IWM_SETBITS(sc, IWM_FH_TX_CHICKEN_BITS_REG, IWM_FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); /* Enable L1-Active */ - if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { iwm_clear_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG, IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS); } out: iwm_nic_unlock(sc); return error; } /* * NVM read access and content parsing. We do not support * external NVM or writing NVM. * iwlwifi/mvm/nvm.c */ -/* list of NVM sections we are allowed/need to read */ -const int nvm_to_read[] = { - IWM_NVM_SECTION_TYPE_HW, - IWM_NVM_SECTION_TYPE_SW, - IWM_NVM_SECTION_TYPE_REGULATORY, - IWM_NVM_SECTION_TYPE_CALIBRATION, - IWM_NVM_SECTION_TYPE_PRODUCTION, - IWM_NVM_SECTION_TYPE_HW_8000, - IWM_NVM_SECTION_TYPE_MAC_OVERRIDE, - IWM_NVM_SECTION_TYPE_PHY_SKU, -}; - /* Default NVM size to read */ #define IWM_NVM_DEFAULT_CHUNK_SIZE (2*1024) -#define IWM_MAX_NVM_SECTION_SIZE 8192 #define IWM_NVM_WRITE_OPCODE 1 #define IWM_NVM_READ_OPCODE 0 /* load nvm chunk response */ enum { IWM_READ_NVM_CHUNK_SUCCEED = 0, IWM_READ_NVM_CHUNK_NOT_VALID_ADDRESS = 1 }; static int iwm_nvm_read_chunk(struct iwm_softc *sc, uint16_t section, uint16_t offset, uint16_t length, uint8_t *data, uint16_t *len) { - offset = 0; struct iwm_nvm_access_cmd nvm_access_cmd = { .offset = htole16(offset), .length = htole16(length), .type = htole16(section), .op_code = IWM_NVM_READ_OPCODE, }; struct iwm_nvm_access_resp *nvm_resp; struct iwm_rx_packet *pkt; struct iwm_host_cmd cmd = { .id = IWM_NVM_ACCESS_CMD, .flags = IWM_CMD_WANT_SKB | IWM_CMD_SEND_IN_RFKILL, .data = { &nvm_access_cmd, }, }; int ret, bytes_read, offset_read; uint8_t *resp_data; cmd.len[0] = sizeof(struct iwm_nvm_access_cmd); ret = iwm_send_cmd(sc, &cmd); if (ret) { device_printf(sc->sc_dev, "Could not send NVM_ACCESS command (error=%d)\n", ret); return ret; } pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWM_CMD_FAILED_MSK) { - device_printf(sc->sc_dev, - "Bad return from IWM_NVM_ACCES_COMMAND (0x%08X)\n", - pkt->hdr.flags); - ret = EIO; - goto exit; - } /* Extract NVM response */ nvm_resp = (void *)pkt->data; - ret = le16toh(nvm_resp->status); bytes_read = le16toh(nvm_resp->length); offset_read = le16toh(nvm_resp->offset); resp_data = nvm_resp->data; if (ret) { if ((offset != 0) && (ret == IWM_READ_NVM_CHUNK_NOT_VALID_ADDRESS)) { /* * meaning of NOT_VALID_ADDRESS: * driver try to read chunk from address that is * multiple of 2K and got an error since addr is empty. * meaning of (offset != 0): driver already * read valid data from another chunk so this case * is not an error. */ IWM_DPRINTF(sc, IWM_DEBUG_EEPROM | IWM_DEBUG_RESET, "NVM access command failed on offset 0x%x since that section size is multiple 2K\n", offset); *len = 0; ret = 0; } else { IWM_DPRINTF(sc, IWM_DEBUG_EEPROM | IWM_DEBUG_RESET, "NVM access command failed with status %d\n", ret); ret = EIO; } goto exit; } if (offset_read != offset) { device_printf(sc->sc_dev, "NVM ACCESS response with invalid offset %d\n", offset_read); ret = EINVAL; goto exit; } if (bytes_read > length) { device_printf(sc->sc_dev, "NVM ACCESS response with too much data " "(%d bytes requested, %d bytes received)\n", length, bytes_read); ret = EINVAL; goto exit; } + /* Write data to NVM */ memcpy(data + offset, resp_data, bytes_read); *len = bytes_read; exit: iwm_free_resp(sc, &cmd); return ret; } /* * Reads an NVM section completely. * NICs prior to 7000 family don't have a real NVM, but just read * section 0 which is the EEPROM. Because the EEPROM reading is unlimited * by uCode, we need to manually check in this case that we don't * overflow and try to read more than the EEPROM size. * For 7000 family NICs, we supply the maximal size we can read, and * the uCode fills the response with as much data as we can, * without overflowing, so no check is needed. */ static int iwm_nvm_read_section(struct iwm_softc *sc, - uint16_t section, uint8_t *data, uint16_t *len, size_t max_len) + uint16_t section, uint8_t *data, uint16_t *len, uint32_t size_read) { - uint16_t chunklen, seglen; - int error = 0; + uint16_t seglen, length, offset = 0; + int ret; - IWM_DPRINTF(sc, IWM_DEBUG_RESET, - "reading NVM section %d\n", section); + /* Set nvm section read length */ + length = IWM_NVM_DEFAULT_CHUNK_SIZE; - chunklen = seglen = IWM_NVM_DEFAULT_CHUNK_SIZE; - *len = 0; + seglen = length; - /* Read NVM chunks until exhausted (reading less than requested) */ - while (seglen == chunklen && *len < max_len) { - error = iwm_nvm_read_chunk(sc, - section, *len, chunklen, data, &seglen); - if (error) { - IWM_DPRINTF(sc, IWM_DEBUG_RESET, - "Cannot read from NVM section " - "%d at offset %d\n", section, *len); - return error; + /* Read the NVM until exhausted (reading less than requested) */ + while (seglen == length) { + /* Check no memory assumptions fail and cause an overflow */ + if ((size_read + offset + length) > + sc->cfg->eeprom_size) { + device_printf(sc->sc_dev, + "EEPROM size is too small for NVM\n"); + return ENOBUFS; } - *len += seglen; + + ret = iwm_nvm_read_chunk(sc, section, offset, length, data, &seglen); + if (ret) { + IWM_DPRINTF(sc, IWM_DEBUG_EEPROM | IWM_DEBUG_RESET, + "Cannot read NVM from section %d offset %d, length %d\n", + section, offset, length); + return ret; + } + offset += seglen; } - IWM_DPRINTF(sc, IWM_DEBUG_RESET, - "NVM section %d read completed (%d bytes, error=%d)\n", - section, *len, error); - return error; + IWM_DPRINTF(sc, IWM_DEBUG_EEPROM | IWM_DEBUG_RESET, + "NVM section %d read completed\n", section); + *len = offset; + return 0; } /* * BEGIN IWM_NVM_PARSE */ /* iwlwifi/iwl-nvm-parse.c */ /* NVM offsets (in words) definitions */ enum iwm_nvm_offsets { /* NVM HW-Section offset (in words) definitions */ IWM_HW_ADDR = 0x15, /* NVM SW-Section offset (in words) definitions */ IWM_NVM_SW_SECTION = 0x1C0, IWM_NVM_VERSION = 0, IWM_RADIO_CFG = 1, IWM_SKU = 2, IWM_N_HW_ADDRS = 3, IWM_NVM_CHANNELS = 0x1E0 - IWM_NVM_SW_SECTION, /* NVM calibration section offset (in words) definitions */ IWM_NVM_CALIB_SECTION = 0x2B8, IWM_XTAL_CALIB = 0x316 - IWM_NVM_CALIB_SECTION }; enum iwm_8000_nvm_offsets { /* NVM HW-Section offset (in words) definitions */ IWM_HW_ADDR0_WFPM_8000 = 0x12, IWM_HW_ADDR1_WFPM_8000 = 0x16, IWM_HW_ADDR0_PCIE_8000 = 0x8A, IWM_HW_ADDR1_PCIE_8000 = 0x8E, IWM_MAC_ADDRESS_OVERRIDE_8000 = 1, /* NVM SW-Section offset (in words) definitions */ IWM_NVM_SW_SECTION_8000 = 0x1C0, IWM_NVM_VERSION_8000 = 0, IWM_RADIO_CFG_8000 = 0, IWM_SKU_8000 = 2, IWM_N_HW_ADDRS_8000 = 3, /* NVM REGULATORY -Section offset (in words) definitions */ IWM_NVM_CHANNELS_8000 = 0, IWM_NVM_LAR_OFFSET_8000_OLD = 0x4C7, IWM_NVM_LAR_OFFSET_8000 = 0x507, IWM_NVM_LAR_ENABLED_8000 = 0x7, /* NVM calibration section offset (in words) definitions */ IWM_NVM_CALIB_SECTION_8000 = 0x2B8, IWM_XTAL_CALIB_8000 = 0x316 - IWM_NVM_CALIB_SECTION_8000 }; /* SKU Capabilities (actual values from NVM definition) */ enum nvm_sku_bits { IWM_NVM_SKU_CAP_BAND_24GHZ = (1 << 0), IWM_NVM_SKU_CAP_BAND_52GHZ = (1 << 1), IWM_NVM_SKU_CAP_11N_ENABLE = (1 << 2), IWM_NVM_SKU_CAP_11AC_ENABLE = (1 << 3), }; /* radio config bits (actual values from NVM definition) */ #define IWM_NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ #define IWM_NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ #define IWM_NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ #define IWM_NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ #define IWM_NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ #define IWM_NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ #define IWM_NVM_RF_CFG_FLAVOR_MSK_8000(x) (x & 0xF) #define IWM_NVM_RF_CFG_DASH_MSK_8000(x) ((x >> 4) & 0xF) #define IWM_NVM_RF_CFG_STEP_MSK_8000(x) ((x >> 8) & 0xF) #define IWM_NVM_RF_CFG_TYPE_MSK_8000(x) ((x >> 12) & 0xFFF) #define IWM_NVM_RF_CFG_TX_ANT_MSK_8000(x) ((x >> 24) & 0xF) #define IWM_NVM_RF_CFG_RX_ANT_MSK_8000(x) ((x >> 28) & 0xF) #define DEFAULT_MAX_TX_POWER 16 /** * enum iwm_nvm_channel_flags - channel flags in NVM * @IWM_NVM_CHANNEL_VALID: channel is usable for this SKU/geo * @IWM_NVM_CHANNEL_IBSS: usable as an IBSS channel * @IWM_NVM_CHANNEL_ACTIVE: active scanning allowed * @IWM_NVM_CHANNEL_RADAR: radar detection required - * XXX cannot find this (DFS) flag in iwl-nvm-parse.c + * XXX cannot find this (DFS) flag in iwm-nvm-parse.c * @IWM_NVM_CHANNEL_DFS: dynamic freq selection candidate * @IWM_NVM_CHANNEL_WIDE: 20 MHz channel okay (?) * @IWM_NVM_CHANNEL_40MHZ: 40 MHz channel okay (?) * @IWM_NVM_CHANNEL_80MHZ: 80 MHz channel okay (?) * @IWM_NVM_CHANNEL_160MHZ: 160 MHz channel okay (?) */ enum iwm_nvm_channel_flags { IWM_NVM_CHANNEL_VALID = (1 << 0), IWM_NVM_CHANNEL_IBSS = (1 << 1), IWM_NVM_CHANNEL_ACTIVE = (1 << 3), IWM_NVM_CHANNEL_RADAR = (1 << 4), IWM_NVM_CHANNEL_DFS = (1 << 7), IWM_NVM_CHANNEL_WIDE = (1 << 8), IWM_NVM_CHANNEL_40MHZ = (1 << 9), IWM_NVM_CHANNEL_80MHZ = (1 << 10), IWM_NVM_CHANNEL_160MHZ = (1 << 11), }; /* * Translate EEPROM flags to net80211. */ static uint32_t iwm_eeprom_channel_flags(uint16_t ch_flags) { uint32_t nflags; nflags = 0; if ((ch_flags & IWM_NVM_CHANNEL_ACTIVE) == 0) nflags |= IEEE80211_CHAN_PASSIVE; if ((ch_flags & IWM_NVM_CHANNEL_IBSS) == 0) nflags |= IEEE80211_CHAN_NOADHOC; if (ch_flags & IWM_NVM_CHANNEL_RADAR) { nflags |= IEEE80211_CHAN_DFS; /* Just in case. */ nflags |= IEEE80211_CHAN_NOADHOC; } return (nflags); } static void iwm_add_channel_band(struct iwm_softc *sc, struct ieee80211_channel chans[], int maxchans, int *nchans, int ch_idx, size_t ch_num, const uint8_t bands[]) { - const uint16_t * const nvm_ch_flags = sc->sc_nvm.nvm_ch_flags; + const uint16_t * const nvm_ch_flags = sc->nvm_data->nvm_ch_flags; uint32_t nflags; uint16_t ch_flags; uint8_t ieee; int error; for (; ch_idx < ch_num; ch_idx++) { ch_flags = le16_to_cpup(nvm_ch_flags + ch_idx); - if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) ieee = iwm_nvm_channels[ch_idx]; else ieee = iwm_nvm_channels_8000[ch_idx]; if (!(ch_flags & IWM_NVM_CHANNEL_VALID)) { IWM_DPRINTF(sc, IWM_DEBUG_EEPROM, "Ch. %d Flags %x [%sGHz] - No traffic\n", ieee, ch_flags, (ch_idx >= IWM_NUM_2GHZ_CHANNELS) ? "5.2" : "2.4"); continue; } nflags = iwm_eeprom_channel_flags(ch_flags); error = ieee80211_add_channel(chans, maxchans, nchans, ieee, 0, 0, nflags, bands); if (error != 0) break; IWM_DPRINTF(sc, IWM_DEBUG_EEPROM, "Ch. %d Flags %x [%sGHz] - Added\n", ieee, ch_flags, (ch_idx >= IWM_NUM_2GHZ_CHANNELS) ? "5.2" : "2.4"); } } static void iwm_init_channel_map(struct ieee80211com *ic, int maxchans, int *nchans, struct ieee80211_channel chans[]) { struct iwm_softc *sc = ic->ic_softc; - struct iwm_nvm_data *data = &sc->sc_nvm; + struct iwm_nvm_data *data = sc->nvm_data; uint8_t bands[IEEE80211_MODE_BYTES]; size_t ch_num; memset(bands, 0, sizeof(bands)); /* 1-13: 11b/g channels. */ setbit(bands, IEEE80211_MODE_11B); setbit(bands, IEEE80211_MODE_11G); iwm_add_channel_band(sc, chans, maxchans, nchans, 0, IWM_NUM_2GHZ_CHANNELS - 1, bands); /* 14: 11b channel only. */ clrbit(bands, IEEE80211_MODE_11G); iwm_add_channel_band(sc, chans, maxchans, nchans, IWM_NUM_2GHZ_CHANNELS - 1, IWM_NUM_2GHZ_CHANNELS, bands); if (data->sku_cap_band_52GHz_enable) { - if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) ch_num = nitems(iwm_nvm_channels); else ch_num = nitems(iwm_nvm_channels_8000); memset(bands, 0, sizeof(bands)); setbit(bands, IEEE80211_MODE_11A); iwm_add_channel_band(sc, chans, maxchans, nchans, IWM_NUM_2GHZ_CHANNELS, ch_num, bands); } } static void -iwm_set_hw_address_8000(struct iwm_softc *sc, struct iwm_nvm_data *data, +iwm_set_hw_address_family_8000(struct iwm_softc *sc, struct iwm_nvm_data *data, const uint16_t *mac_override, const uint16_t *nvm_hw) { const uint8_t *hw_addr; if (mac_override) { static const uint8_t reserved_mac[] = { 0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00 }; hw_addr = (const uint8_t *)(mac_override + IWM_MAC_ADDRESS_OVERRIDE_8000); /* * Store the MAC address from MAO section. * No byte swapping is required in MAO section */ IEEE80211_ADDR_COPY(data->hw_addr, hw_addr); /* * Force the use of the OTP MAC address in case of reserved MAC * address in the NVM, or if address is given but invalid. */ if (!IEEE80211_ADDR_EQ(reserved_mac, hw_addr) && !IEEE80211_ADDR_EQ(ieee80211broadcastaddr, data->hw_addr) && iwm_is_valid_ether_addr(data->hw_addr) && !IEEE80211_IS_MULTICAST(data->hw_addr)) return; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "%s: mac address from nvm override section invalid\n", __func__); } if (nvm_hw) { /* read the mac address from WFMP registers */ uint32_t mac_addr0 = htole32(iwm_read_prph(sc, IWM_WFMP_MAC_ADDR_0)); uint32_t mac_addr1 = htole32(iwm_read_prph(sc, IWM_WFMP_MAC_ADDR_1)); hw_addr = (const uint8_t *)&mac_addr0; data->hw_addr[0] = hw_addr[3]; data->hw_addr[1] = hw_addr[2]; data->hw_addr[2] = hw_addr[1]; data->hw_addr[3] = hw_addr[0]; hw_addr = (const uint8_t *)&mac_addr1; data->hw_addr[4] = hw_addr[1]; data->hw_addr[5] = hw_addr[0]; return; } device_printf(sc->sc_dev, "%s: mac address not found\n", __func__); memset(data->hw_addr, 0, sizeof(data->hw_addr)); } static int iwm_get_sku(const struct iwm_softc *sc, const uint16_t *nvm_sw, const uint16_t *phy_sku) { - if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + IWM_SKU); return le32_to_cpup((const uint32_t *)(phy_sku + IWM_SKU_8000)); } static int iwm_get_nvm_version(const struct iwm_softc *sc, const uint16_t *nvm_sw) { - if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + IWM_NVM_VERSION); else return le32_to_cpup((const uint32_t *)(nvm_sw + IWM_NVM_VERSION_8000)); } static int iwm_get_radio_cfg(const struct iwm_softc *sc, const uint16_t *nvm_sw, const uint16_t *phy_sku) { - if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + IWM_RADIO_CFG); return le32_to_cpup((const uint32_t *)(phy_sku + IWM_RADIO_CFG_8000)); } static int iwm_get_n_hw_addrs(const struct iwm_softc *sc, const uint16_t *nvm_sw) { int n_hw_addr; - if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + IWM_N_HW_ADDRS); n_hw_addr = le32_to_cpup((const uint32_t *)(nvm_sw + IWM_N_HW_ADDRS_8000)); return n_hw_addr & IWM_N_HW_ADDR_MASK; } static void iwm_set_radio_cfg(const struct iwm_softc *sc, struct iwm_nvm_data *data, uint32_t radio_cfg) { - if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { data->radio_cfg_type = IWM_NVM_RF_CFG_TYPE_MSK(radio_cfg); data->radio_cfg_step = IWM_NVM_RF_CFG_STEP_MSK(radio_cfg); data->radio_cfg_dash = IWM_NVM_RF_CFG_DASH_MSK(radio_cfg); data->radio_cfg_pnum = IWM_NVM_RF_CFG_PNUM_MSK(radio_cfg); return; } /* set the radio configuration for family 8000 */ data->radio_cfg_type = IWM_NVM_RF_CFG_TYPE_MSK_8000(radio_cfg); data->radio_cfg_step = IWM_NVM_RF_CFG_STEP_MSK_8000(radio_cfg); data->radio_cfg_dash = IWM_NVM_RF_CFG_DASH_MSK_8000(radio_cfg); data->radio_cfg_pnum = IWM_NVM_RF_CFG_FLAVOR_MSK_8000(radio_cfg); data->valid_tx_ant = IWM_NVM_RF_CFG_TX_ANT_MSK_8000(radio_cfg); data->valid_rx_ant = IWM_NVM_RF_CFG_RX_ANT_MSK_8000(radio_cfg); } static int +iwm_set_hw_address(struct iwm_softc *sc, struct iwm_nvm_data *data, + const uint16_t *nvm_hw, const uint16_t *mac_override) +{ +#ifdef notyet /* for FAMILY 9000 */ + if (cfg->mac_addr_from_csr) { + iwm_set_hw_address_from_csr(sc, data); + } else +#endif + if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { + const uint8_t *hw_addr = (const uint8_t *)(nvm_hw + IWM_HW_ADDR); + + /* The byte order is little endian 16 bit, meaning 214365 */ + data->hw_addr[0] = hw_addr[1]; + data->hw_addr[1] = hw_addr[0]; + data->hw_addr[2] = hw_addr[3]; + data->hw_addr[3] = hw_addr[2]; + data->hw_addr[4] = hw_addr[5]; + data->hw_addr[5] = hw_addr[4]; + } else { + iwm_set_hw_address_family_8000(sc, data, mac_override, nvm_hw); + } + + if (!iwm_is_valid_ether_addr(data->hw_addr)) { + device_printf(sc->sc_dev, "no valid mac address was found\n"); + return EINVAL; + } + + return 0; +} + +static struct iwm_nvm_data * iwm_parse_nvm_data(struct iwm_softc *sc, const uint16_t *nvm_hw, const uint16_t *nvm_sw, const uint16_t *nvm_calib, const uint16_t *mac_override, const uint16_t *phy_sku, const uint16_t *regulatory) { - struct iwm_nvm_data *data = &sc->sc_nvm; - uint8_t hw_addr[IEEE80211_ADDR_LEN]; + struct iwm_nvm_data *data; uint32_t sku, radio_cfg; + if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { + data = malloc(sizeof(*data) + + IWM_NUM_CHANNELS * sizeof(uint16_t), + M_DEVBUF, M_NOWAIT | M_ZERO); + } else { + data = malloc(sizeof(*data) + + IWM_NUM_CHANNELS_8000 * sizeof(uint16_t), + M_DEVBUF, M_NOWAIT | M_ZERO); + } + if (!data) + return NULL; + data->nvm_version = iwm_get_nvm_version(sc, nvm_sw); radio_cfg = iwm_get_radio_cfg(sc, nvm_sw, phy_sku); iwm_set_radio_cfg(sc, data, radio_cfg); sku = iwm_get_sku(sc, nvm_sw, phy_sku); data->sku_cap_band_24GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_24GHZ; data->sku_cap_band_52GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_52GHZ; data->sku_cap_11n_enable = 0; data->n_hw_addrs = iwm_get_n_hw_addrs(sc, nvm_sw); - /* The byte order is little endian 16 bit, meaning 214365 */ - if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { - IEEE80211_ADDR_COPY(hw_addr, nvm_hw + IWM_HW_ADDR); - data->hw_addr[0] = hw_addr[1]; - data->hw_addr[1] = hw_addr[0]; - data->hw_addr[2] = hw_addr[3]; - data->hw_addr[3] = hw_addr[2]; - data->hw_addr[4] = hw_addr[5]; - data->hw_addr[5] = hw_addr[4]; - } else { - iwm_set_hw_address_8000(sc, data, mac_override, nvm_hw); + /* If no valid mac address was found - bail out */ + if (iwm_set_hw_address(sc, data, nvm_hw, mac_override)) { + free(data, M_DEVBUF); + return NULL; } - if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) { memcpy(data->nvm_ch_flags, &nvm_sw[IWM_NVM_CHANNELS], IWM_NUM_CHANNELS * sizeof(uint16_t)); } else { memcpy(data->nvm_ch_flags, ®ulatory[IWM_NVM_CHANNELS_8000], IWM_NUM_CHANNELS_8000 * sizeof(uint16_t)); } - return 0; + return data; } -/* - * END NVM PARSE - */ +static void +iwm_free_nvm_data(struct iwm_nvm_data *data) +{ + if (data != NULL) + free(data, M_DEVBUF); +} -static int +static struct iwm_nvm_data * iwm_parse_nvm_sections(struct iwm_softc *sc, struct iwm_nvm_section *sections) { const uint16_t *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; /* Checking for required sections */ - if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) { if (!sections[IWM_NVM_SECTION_TYPE_SW].data || - !sections[IWM_NVM_SECTION_TYPE_HW].data) { + !sections[sc->cfg->nvm_hw_section_num].data) { device_printf(sc->sc_dev, "Can't parse empty OTP/NVM sections\n"); - return ENOENT; + return NULL; } - - hw = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_HW].data; - } else if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) { + } else if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) { /* SW and REGULATORY sections are mandatory */ if (!sections[IWM_NVM_SECTION_TYPE_SW].data || !sections[IWM_NVM_SECTION_TYPE_REGULATORY].data) { device_printf(sc->sc_dev, "Can't parse empty OTP/NVM sections\n"); - return ENOENT; + return NULL; } /* MAC_OVERRIDE or at least HW section must exist */ - if (!sections[IWM_NVM_SECTION_TYPE_HW_8000].data && + if (!sections[sc->cfg->nvm_hw_section_num].data && !sections[IWM_NVM_SECTION_TYPE_MAC_OVERRIDE].data) { device_printf(sc->sc_dev, "Can't parse mac_address, empty sections\n"); - return ENOENT; + return NULL; } /* PHY_SKU section is mandatory in B0 */ if (!sections[IWM_NVM_SECTION_TYPE_PHY_SKU].data) { device_printf(sc->sc_dev, "Can't parse phy_sku in B0, empty sections\n"); - return ENOENT; + return NULL; } - - hw = (const uint16_t *) - sections[IWM_NVM_SECTION_TYPE_HW_8000].data; } else { - panic("unknown device family %d\n", sc->sc_device_family); + panic("unknown device family %d\n", sc->cfg->device_family); } + hw = (const uint16_t *) sections[sc->cfg->nvm_hw_section_num].data; sw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_SW].data; calib = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data; regulatory = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_REGULATORY].data; mac_override = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_MAC_OVERRIDE].data; phy_sku = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_PHY_SKU].data; return iwm_parse_nvm_data(sc, hw, sw, calib, mac_override, phy_sku, regulatory); } static int iwm_nvm_init(struct iwm_softc *sc) { - struct iwm_nvm_section nvm_sections[IWM_NVM_NUM_OF_SECTIONS]; - int i, section, error; + struct iwm_nvm_section nvm_sections[IWM_NVM_MAX_NUM_SECTIONS]; + int i, ret, section; + uint32_t size_read = 0; + uint8_t *nvm_buffer, *temp; uint16_t len; - uint8_t *buf; - const size_t bufsz = IWM_MAX_NVM_SECTION_SIZE; - memset(nvm_sections, 0 , sizeof(nvm_sections)); + memset(nvm_sections, 0, sizeof(nvm_sections)); - buf = malloc(bufsz, M_DEVBUF, M_NOWAIT); - if (buf == NULL) - return ENOMEM; + if (sc->cfg->nvm_hw_section_num >= IWM_NVM_MAX_NUM_SECTIONS) + return EINVAL; - for (i = 0; i < nitems(nvm_to_read); i++) { - section = nvm_to_read[i]; - KASSERT(section <= nitems(nvm_sections), - ("too many sections")); + /* load NVM values from nic */ + /* Read From FW NVM */ + IWM_DPRINTF(sc, IWM_DEBUG_EEPROM, "Read from NVM\n"); - error = iwm_nvm_read_section(sc, section, buf, &len, bufsz); - if (error) { - error = 0; + nvm_buffer = malloc(sc->cfg->eeprom_size, M_DEVBUF, M_NOWAIT | M_ZERO); + if (!nvm_buffer) + return ENOMEM; + for (section = 0; section < IWM_NVM_MAX_NUM_SECTIONS; section++) { + /* we override the constness for initial read */ + ret = iwm_nvm_read_section(sc, section, nvm_buffer, + &len, size_read); + if (ret) continue; - } - nvm_sections[section].data = malloc(len, M_DEVBUF, M_NOWAIT); - if (nvm_sections[section].data == NULL) { - error = ENOMEM; + size_read += len; + temp = malloc(len, M_DEVBUF, M_NOWAIT); + if (!temp) { + ret = ENOMEM; break; } - memcpy(nvm_sections[section].data, buf, len); + memcpy(temp, nvm_buffer, len); + + nvm_sections[section].data = temp; nvm_sections[section].length = len; } - free(buf, M_DEVBUF); - if (error == 0) - error = iwm_parse_nvm_sections(sc, nvm_sections); + if (!size_read) + device_printf(sc->sc_dev, "OTP is blank\n"); + free(nvm_buffer, M_DEVBUF); - for (i = 0; i < IWM_NVM_NUM_OF_SECTIONS; i++) { + sc->nvm_data = iwm_parse_nvm_sections(sc, nvm_sections); + if (!sc->nvm_data) + return EINVAL; + IWM_DPRINTF(sc, IWM_DEBUG_EEPROM | IWM_DEBUG_RESET, + "nvm version = %x\n", sc->nvm_data->nvm_version); + + for (i = 0; i < IWM_NVM_MAX_NUM_SECTIONS; i++) { if (nvm_sections[i].data != NULL) free(nvm_sections[i].data, M_DEVBUF); } - return error; + return 0; } /* * Firmware loading gunk. This is kind of a weird hybrid between the * iwn driver and the Linux iwlwifi driver. */ static int iwm_firmware_load_sect(struct iwm_softc *sc, uint32_t dst_addr, const uint8_t *section, uint32_t byte_cnt) { int error = EINVAL; uint32_t chunk_sz, offset; chunk_sz = MIN(IWM_FH_MEM_TB_MAX_LENGTH, byte_cnt); for (offset = 0; offset < byte_cnt; offset += chunk_sz) { uint32_t addr, len; const uint8_t *data; addr = dst_addr + offset; len = MIN(chunk_sz, byte_cnt - offset); data = section + offset; error = iwm_firmware_load_chunk(sc, addr, data, len); if (error) break; } return error; } static int iwm_firmware_load_chunk(struct iwm_softc *sc, uint32_t dst_addr, const uint8_t *chunk, uint32_t byte_cnt) { struct iwm_dma_info *dma = &sc->fw_dma; int error; /* Copy firmware chunk into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, chunk, byte_cnt); bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); if (dst_addr >= IWM_FW_MEM_EXTENDED_START && dst_addr <= IWM_FW_MEM_EXTENDED_END) { iwm_set_bits_prph(sc, IWM_LMPM_CHICK, IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE); } sc->sc_fw_chunk_done = 0; if (!iwm_nic_lock(sc)) return EBUSY; IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(IWM_FH_SRVC_CHNL), IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); IWM_WRITE(sc, IWM_FH_SRVC_CHNL_SRAM_ADDR_REG(IWM_FH_SRVC_CHNL), dst_addr); IWM_WRITE(sc, IWM_FH_TFDIB_CTRL0_REG(IWM_FH_SRVC_CHNL), dma->paddr & IWM_FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); IWM_WRITE(sc, IWM_FH_TFDIB_CTRL1_REG(IWM_FH_SRVC_CHNL), (iwm_get_dma_hi_addr(dma->paddr) << IWM_FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_BUF_STS_REG(IWM_FH_SRVC_CHNL), 1 << IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | 1 << IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(IWM_FH_SRVC_CHNL), IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); iwm_nic_unlock(sc); /* wait 1s for this segment to load */ while (!sc->sc_fw_chunk_done) if ((error = msleep(&sc->sc_fw, &sc->sc_mtx, 0, "iwmfw", hz)) != 0) break; if (!sc->sc_fw_chunk_done) { device_printf(sc->sc_dev, "fw chunk addr 0x%x len %d failed to load\n", dst_addr, byte_cnt); } if (dst_addr >= IWM_FW_MEM_EXTENDED_START && dst_addr <= IWM_FW_MEM_EXTENDED_END && iwm_nic_lock(sc)) { iwm_clear_bits_prph(sc, IWM_LMPM_CHICK, IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE); iwm_nic_unlock(sc); } return error; } int iwm_load_cpu_sections_8000(struct iwm_softc *sc, struct iwm_fw_sects *fws, int cpu, int *first_ucode_section) { int shift_param; int i, error = 0, sec_num = 0x1; uint32_t val, last_read_idx = 0; const void *data; uint32_t dlen; uint32_t offset; if (cpu == 1) { shift_param = 0; *first_ucode_section = 0; } else { shift_param = 16; (*first_ucode_section)++; } for (i = *first_ucode_section; i < IWM_UCODE_SECT_MAX; i++) { last_read_idx = i; data = fws->fw_sect[i].fws_data; dlen = fws->fw_sect[i].fws_len; offset = fws->fw_sect[i].fws_devoff; /* * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between * CPU1 to CPU2. * PAGING_SEPARATOR_SECTION delimiter - separate between * CPU2 non paged to CPU2 paging sec. */ if (!data || offset == IWM_CPU1_CPU2_SEPARATOR_SECTION || offset == IWM_PAGING_SEPARATOR_SECTION) break; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "LOAD FIRMWARE chunk %d offset 0x%x len %d for cpu %d\n", i, offset, dlen, cpu); if (dlen > sc->sc_fwdmasegsz) { IWM_DPRINTF(sc, IWM_DEBUG_RESET, "chunk %d too large (%d bytes)\n", i, dlen); error = EFBIG; } else { error = iwm_firmware_load_sect(sc, offset, data, dlen); } if (error) { device_printf(sc->sc_dev, "could not load firmware chunk %d (error %d)\n", i, error); return error; } /* Notify the ucode of the loaded section number and status */ if (iwm_nic_lock(sc)) { val = IWM_READ(sc, IWM_FH_UCODE_LOAD_STATUS); val = val | (sec_num << shift_param); IWM_WRITE(sc, IWM_FH_UCODE_LOAD_STATUS, val); sec_num = (sec_num << 1) | 0x1; iwm_nic_unlock(sc); /* * The firmware won't load correctly without this delay. */ DELAY(8000); } } *first_ucode_section = last_read_idx; if (iwm_nic_lock(sc)) { if (cpu == 1) IWM_WRITE(sc, IWM_FH_UCODE_LOAD_STATUS, 0xFFFF); else IWM_WRITE(sc, IWM_FH_UCODE_LOAD_STATUS, 0xFFFFFFFF); iwm_nic_unlock(sc); } return 0; } int iwm_load_firmware_8000(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { struct iwm_fw_sects *fws; int error = 0; int first_ucode_section; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "loading ucode type %d\n", ucode_type); fws = &sc->sc_fw.fw_sects[ucode_type]; /* configure the ucode to be ready to get the secured image */ /* release CPU reset */ iwm_write_prph(sc, IWM_RELEASE_CPU_RESET, IWM_RELEASE_CPU_RESET_BIT); /* load to FW the binary Secured sections of CPU1 */ error = iwm_load_cpu_sections_8000(sc, fws, 1, &first_ucode_section); if (error) return error; /* load to FW the binary sections of CPU2 */ return iwm_load_cpu_sections_8000(sc, fws, 2, &first_ucode_section); } static int iwm_load_firmware_7000(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { struct iwm_fw_sects *fws; int error, i; const void *data; uint32_t dlen; uint32_t offset; sc->sc_uc.uc_intr = 0; fws = &sc->sc_fw.fw_sects[ucode_type]; for (i = 0; i < fws->fw_count; i++) { data = fws->fw_sect[i].fws_data; dlen = fws->fw_sect[i].fws_len; offset = fws->fw_sect[i].fws_devoff; IWM_DPRINTF(sc, IWM_DEBUG_FIRMWARE_TLV, "LOAD FIRMWARE type %d offset %u len %d\n", ucode_type, offset, dlen); if (dlen > sc->sc_fwdmasegsz) { IWM_DPRINTF(sc, IWM_DEBUG_FIRMWARE_TLV, "chunk %d too large (%d bytes)\n", i, dlen); error = EFBIG; } else { error = iwm_firmware_load_sect(sc, offset, data, dlen); } if (error) { device_printf(sc->sc_dev, "could not load firmware chunk %u of %u " "(error=%d)\n", i, fws->fw_count, error); return error; } } IWM_WRITE(sc, IWM_CSR_RESET, 0); return 0; } static int iwm_load_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { int error, w; - if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) error = iwm_load_firmware_8000(sc, ucode_type); else error = iwm_load_firmware_7000(sc, ucode_type); if (error) return error; /* wait for the firmware to load */ for (w = 0; !sc->sc_uc.uc_intr && w < 10; w++) { error = msleep(&sc->sc_uc, &sc->sc_mtx, 0, "iwmuc", hz/10); } if (error || !sc->sc_uc.uc_ok) { device_printf(sc->sc_dev, "could not load firmware\n"); - if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) { device_printf(sc->sc_dev, "cpu1 status: 0x%x\n", iwm_read_prph(sc, IWM_SB_CPU_1_STATUS)); device_printf(sc->sc_dev, "cpu2 status: 0x%x\n", iwm_read_prph(sc, IWM_SB_CPU_2_STATUS)); } } /* * Give the firmware some time to initialize. * Accessing it too early causes errors. */ msleep(&w, &sc->sc_mtx, 0, "iwmfwinit", hz); return error; } /* iwlwifi: pcie/trans.c */ static int iwm_start_fw(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { int error; IWM_WRITE(sc, IWM_CSR_INT, ~0); if ((error = iwm_nic_init(sc)) != 0) { device_printf(sc->sc_dev, "unable to init nic\n"); return error; } /* make sure rfkill handshake bits are cleared */ IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL); IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); /* clear (again), then enable host interrupts */ IWM_WRITE(sc, IWM_CSR_INT, ~0); iwm_enable_interrupts(sc); /* really make sure rfkill handshake bits are cleared */ /* maybe we should write a few times more? just to make sure */ IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL); IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL); /* Load the given image to the HW */ return iwm_load_firmware(sc, ucode_type); } static int iwm_send_tx_ant_cfg(struct iwm_softc *sc, uint8_t valid_tx_ant) { struct iwm_tx_ant_cfg_cmd tx_ant_cmd = { .valid = htole32(valid_tx_ant), }; return iwm_mvm_send_cmd_pdu(sc, IWM_TX_ANT_CONFIGURATION_CMD, IWM_CMD_SYNC, sizeof(tx_ant_cmd), &tx_ant_cmd); } /* iwlwifi: mvm/fw.c */ static int iwm_send_phy_cfg_cmd(struct iwm_softc *sc) { struct iwm_phy_cfg_cmd phy_cfg_cmd; enum iwm_ucode_type ucode_type = sc->sc_uc_current; /* Set parameters */ phy_cfg_cmd.phy_cfg = htole32(sc->sc_fw_phy_config); phy_cfg_cmd.calib_control.event_trigger = sc->sc_default_calib[ucode_type].event_trigger; phy_cfg_cmd.calib_control.flow_trigger = sc->sc_default_calib[ucode_type].flow_trigger; IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, "Sending Phy CFG command: 0x%x\n", phy_cfg_cmd.phy_cfg); return iwm_mvm_send_cmd_pdu(sc, IWM_PHY_CONFIGURATION_CMD, IWM_CMD_SYNC, sizeof(phy_cfg_cmd), &phy_cfg_cmd); } static int iwm_mvm_load_ucode_wait_alive(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { enum iwm_ucode_type old_type = sc->sc_uc_current; int error; if ((error = iwm_read_firmware(sc, ucode_type)) != 0) { device_printf(sc->sc_dev, "iwm_read_firmware: failed %d\n", error); return error; } sc->sc_uc_current = ucode_type; error = iwm_start_fw(sc, ucode_type); if (error) { device_printf(sc->sc_dev, "iwm_start_fw: failed %d\n", error); sc->sc_uc_current = old_type; return error; } error = iwm_post_alive(sc); if (error) { device_printf(sc->sc_dev, "iwm_fw_alive: failed %d\n", error); } return error; } /* * mvm misc bits */ /* * follows iwlwifi/fw.c */ static int iwm_run_init_mvm_ucode(struct iwm_softc *sc, int justnvm) { int error; /* do not operate with rfkill switch turned on */ if ((sc->sc_flags & IWM_FLAG_RFKILL) && !justnvm) { device_printf(sc->sc_dev, "radio is disabled by hardware switch\n"); return EPERM; } sc->sc_init_complete = 0; if ((error = iwm_mvm_load_ucode_wait_alive(sc, IWM_UCODE_TYPE_INIT)) != 0) { device_printf(sc->sc_dev, "failed to load init firmware\n"); return error; } if (justnvm) { if ((error = iwm_nvm_init(sc)) != 0) { device_printf(sc->sc_dev, "failed to read nvm\n"); return error; } - IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, sc->sc_nvm.hw_addr); + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, sc->nvm_data->hw_addr); return 0; } if ((error = iwm_send_bt_init_conf(sc)) != 0) { device_printf(sc->sc_dev, "failed to send bt coex configuration: %d\n", error); return error; } /* Init Smart FIFO. */ error = iwm_mvm_sf_config(sc, IWM_SF_INIT_OFF); if (error != 0) return error; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "%s: phy_txant=0x%08x, nvm_valid_tx_ant=0x%02x, valid=0x%02x\n", __func__, ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_TX_CHAIN) >> IWM_FW_PHY_CFG_TX_CHAIN_POS), - sc->sc_nvm.valid_tx_ant, + sc->nvm_data->valid_tx_ant, iwm_fw_valid_tx_ant(sc)); /* Send TX valid antennas before triggering calibrations */ if ((error = iwm_send_tx_ant_cfg(sc, iwm_fw_valid_tx_ant(sc))) != 0) { device_printf(sc->sc_dev, "failed to send antennas before calibration: %d\n", error); return error; } /* * Send phy configurations command to init uCode * to start the 16.0 uCode init image internal calibrations. */ if ((error = iwm_send_phy_cfg_cmd(sc)) != 0 ) { device_printf(sc->sc_dev, "%s: failed to run internal calibration: %d\n", __func__, error); return error; } /* * Nothing to do but wait for the init complete notification * from the firmware */ while (!sc->sc_init_complete) { error = msleep(&sc->sc_init_complete, &sc->sc_mtx, 0, "iwminit", 2*hz); if (error) { device_printf(sc->sc_dev, "init complete failed: %d\n", sc->sc_init_complete); break; } } IWM_DPRINTF(sc, IWM_DEBUG_RESET, "init %scomplete\n", sc->sc_init_complete ? "" : "not "); return error; } /* * receive side */ /* (re)stock rx ring, called at init-time and at runtime */ static int iwm_rx_addbuf(struct iwm_softc *sc, int size, int idx) { struct iwm_rx_ring *ring = &sc->rxq; struct iwm_rx_data *data = &ring->data[idx]; struct mbuf *m; bus_dmamap_t dmamap = NULL; bus_dma_segment_t seg; int nsegs, error; m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, IWM_RBUF_SIZE); if (m == NULL) return ENOBUFS; m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; error = bus_dmamap_load_mbuf_sg(ring->data_dmat, ring->spare_map, m, &seg, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, "%s: can't map mbuf, error %d\n", __func__, error); goto fail; } if (data->m != NULL) bus_dmamap_unload(ring->data_dmat, data->map); /* Swap ring->spare_map with data->map */ dmamap = data->map; data->map = ring->spare_map; ring->spare_map = dmamap; bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREREAD); data->m = m; /* Update RX descriptor. */ KASSERT((seg.ds_addr & 255) == 0, ("seg.ds_addr not aligned")); ring->desc[idx] = htole32(seg.ds_addr >> 8); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); return 0; fail: m_freem(m); return error; } /* iwlwifi: mvm/rx.c */ #define IWM_RSSI_OFFSET 50 static int iwm_mvm_calc_rssi(struct iwm_softc *sc, struct iwm_rx_phy_info *phy_info) { int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; uint32_t agc_a, agc_b; uint32_t val; val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_AGC_IDX]); agc_a = (val & IWM_OFDM_AGC_A_MSK) >> IWM_OFDM_AGC_A_POS; agc_b = (val & IWM_OFDM_AGC_B_MSK) >> IWM_OFDM_AGC_B_POS; val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_RSSI_AB_IDX]); rssi_a = (val & IWM_OFDM_RSSI_INBAND_A_MSK) >> IWM_OFDM_RSSI_A_POS; rssi_b = (val & IWM_OFDM_RSSI_INBAND_B_MSK) >> IWM_OFDM_RSSI_B_POS; /* * dBm = rssi dB - agc dB - constant. * Higher AGC (higher radio gain) means lower signal. */ rssi_a_dbm = rssi_a - IWM_RSSI_OFFSET - agc_a; rssi_b_dbm = rssi_b - IWM_RSSI_OFFSET - agc_b; max_rssi_dbm = MAX(rssi_a_dbm, rssi_b_dbm); IWM_DPRINTF(sc, IWM_DEBUG_RECV, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); return max_rssi_dbm; } /* iwlwifi: mvm/rx.c */ /* * iwm_mvm_get_signal_strength - use new rx PHY INFO API * values are reported by the fw as positive values - need to negate * to obtain their dBM. Account for missing antennas by replacing 0 * values by -256dBm: practically 0 power and a non-feasible 8 bit value. */ static int iwm_mvm_get_signal_strength(struct iwm_softc *sc, struct iwm_rx_phy_info *phy_info) { int energy_a, energy_b, energy_c, max_energy; uint32_t val; val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_ENERGY_ANT_ABC_IDX]); energy_a = (val & IWM_RX_INFO_ENERGY_ANT_A_MSK) >> IWM_RX_INFO_ENERGY_ANT_A_POS; energy_a = energy_a ? -energy_a : -256; energy_b = (val & IWM_RX_INFO_ENERGY_ANT_B_MSK) >> IWM_RX_INFO_ENERGY_ANT_B_POS; energy_b = energy_b ? -energy_b : -256; energy_c = (val & IWM_RX_INFO_ENERGY_ANT_C_MSK) >> IWM_RX_INFO_ENERGY_ANT_C_POS; energy_c = energy_c ? -energy_c : -256; max_energy = MAX(energy_a, energy_b); max_energy = MAX(max_energy, energy_c); IWM_DPRINTF(sc, IWM_DEBUG_RECV, "energy In A %d B %d C %d , and max %d\n", energy_a, energy_b, energy_c, max_energy); return max_energy; } static void iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_rx_data *data) { struct iwm_rx_phy_info *phy_info = (void *)pkt->data; IWM_DPRINTF(sc, IWM_DEBUG_RECV, "received PHY stats\n"); bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); memcpy(&sc->sc_last_phy_info, phy_info, sizeof(sc->sc_last_phy_info)); } /* * Retrieve the average noise (in dBm) among receivers. */ static int iwm_get_noise(struct iwm_softc *sc, const struct iwm_mvm_statistics_rx_non_phy *stats) { int i, total, nbant, noise; total = nbant = noise = 0; for (i = 0; i < 3; i++) { noise = le32toh(stats->beacon_silence_rssi[i]) & 0xff; IWM_DPRINTF(sc, IWM_DEBUG_RECV, "%s: i=%d, noise=%d\n", __func__, i, noise); if (noise) { total += noise; nbant++; } } IWM_DPRINTF(sc, IWM_DEBUG_RECV, "%s: nbant=%d, total=%d\n", __func__, nbant, total); #if 0 /* There should be at least one antenna but check anyway. */ return (nbant == 0) ? -127 : (total / nbant) - 107; #else /* For now, just hard-code it to -96 to be safe */ return (-96); #endif } /* * iwm_mvm_rx_rx_mpdu - IWM_REPLY_RX_MPDU_CMD handler * * Handles the actual data of the Rx packet from the fw */ static void iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_rx_data *data) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_frame *wh; struct ieee80211_node *ni; struct ieee80211_rx_stats rxs; struct mbuf *m; struct iwm_rx_phy_info *phy_info; struct iwm_rx_mpdu_res_start *rx_res; uint32_t len; uint32_t rx_pkt_status; int rssi; bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); phy_info = &sc->sc_last_phy_info; rx_res = (struct iwm_rx_mpdu_res_start *)pkt->data; wh = (struct ieee80211_frame *)(pkt->data + sizeof(*rx_res)); len = le16toh(rx_res->byte_count); rx_pkt_status = le32toh(*(uint32_t *)(pkt->data + sizeof(*rx_res) + len)); m = data->m; m->m_data = pkt->data + sizeof(*rx_res); m->m_pkthdr.len = m->m_len = len; if (__predict_false(phy_info->cfg_phy_cnt > 20)) { device_printf(sc->sc_dev, "dsp size out of range [0,20]: %d\n", phy_info->cfg_phy_cnt); goto fail; } if (!(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_CRC_OK) || !(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_OVERRUN_OK)) { IWM_DPRINTF(sc, IWM_DEBUG_RECV, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); goto fail; } if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_RX_ENERGY_API) { rssi = iwm_mvm_get_signal_strength(sc, phy_info); } else { rssi = iwm_mvm_calc_rssi(sc, phy_info); } /* Note: RSSI is absolute (ie a -ve value) */ if (rssi < IWM_MIN_DBM) rssi = IWM_MIN_DBM; else if (rssi > IWM_MAX_DBM) rssi = IWM_MAX_DBM; /* Map it to relative value */ rssi = rssi - sc->sc_noise; /* replenish ring for the buffer we're going to feed to the sharks */ if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0) { device_printf(sc->sc_dev, "%s: unable to add more buffers\n", __func__); goto fail; } IWM_DPRINTF(sc, IWM_DEBUG_RECV, "%s: rssi=%d, noise=%d\n", __func__, rssi, sc->sc_noise); ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); IWM_DPRINTF(sc, IWM_DEBUG_RECV, "%s: phy_info: channel=%d, flags=0x%08x\n", __func__, le16toh(phy_info->channel), le16toh(phy_info->phy_flags)); /* * Populate an RX state struct with the provided information. */ bzero(&rxs, sizeof(rxs)); rxs.r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ; rxs.r_flags |= IEEE80211_R_NF | IEEE80211_R_RSSI; rxs.c_ieee = le16toh(phy_info->channel); if (le16toh(phy_info->phy_flags & IWM_RX_RES_PHY_FLAGS_BAND_24)) { rxs.c_freq = ieee80211_ieee2mhz(rxs.c_ieee, IEEE80211_CHAN_2GHZ); } else { rxs.c_freq = ieee80211_ieee2mhz(rxs.c_ieee, IEEE80211_CHAN_5GHZ); } /* rssi is in 1/2db units */ rxs.c_rssi = rssi * 2; rxs.c_nf = sc->sc_noise; - if (ieee80211_add_rx_params(m, &rxs) == 0) + if (ieee80211_add_rx_params(m, &rxs) == 0) { + if (ni) + ieee80211_free_node(ni); goto fail; + } if (ieee80211_radiotap_active_vap(vap)) { struct iwm_rx_radiotap_header *tap = &sc->sc_rxtap; tap->wr_flags = 0; if (phy_info->phy_flags & htole16(IWM_PHY_INFO_FLAG_SHPREAMBLE)) tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; tap->wr_chan_freq = htole16(rxs.c_freq); /* XXX only if ic->ic_curchan->ic_ieee == rxs.c_ieee */ tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); tap->wr_dbm_antsignal = (int8_t)rssi; tap->wr_dbm_antnoise = (int8_t)sc->sc_noise; tap->wr_tsft = phy_info->system_timestamp; switch (phy_info->rate) { /* CCK rates. */ case 10: tap->wr_rate = 2; break; case 20: tap->wr_rate = 4; break; case 55: tap->wr_rate = 11; break; case 110: tap->wr_rate = 22; break; /* OFDM rates. */ case 0xd: tap->wr_rate = 12; break; case 0xf: tap->wr_rate = 18; break; case 0x5: tap->wr_rate = 24; break; case 0x7: tap->wr_rate = 36; break; case 0x9: tap->wr_rate = 48; break; case 0xb: tap->wr_rate = 72; break; case 0x1: tap->wr_rate = 96; break; case 0x3: tap->wr_rate = 108; break; /* Unknown rate: should not happen. */ default: tap->wr_rate = 0; } } IWM_UNLOCK(sc); if (ni != NULL) { IWM_DPRINTF(sc, IWM_DEBUG_RECV, "input m %p\n", m); ieee80211_input_mimo(ni, m); ieee80211_free_node(ni); } else { IWM_DPRINTF(sc, IWM_DEBUG_RECV, "inputall m %p\n", m); ieee80211_input_mimo_all(ic, m); } IWM_LOCK(sc); return; -fail: counter_u64_add(ic->ic_ierrors, 1); +fail: + counter_u64_add(ic->ic_ierrors, 1); } static int iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_node *in) { struct iwm_mvm_tx_resp *tx_resp = (void *)pkt->data; struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs; struct ieee80211_node *ni = &in->in_ni; int status = le16toh(tx_resp->status.status) & IWM_TX_STATUS_MSK; KASSERT(tx_resp->frame_count == 1, ("too many frames")); /* Update rate control statistics. */ IWM_DPRINTF(sc, IWM_DEBUG_XMIT, "%s: status=0x%04x, seq=%d, fc=%d, btc=%d, frts=%d, ff=%d, irate=%08x, wmt=%d\n", __func__, (int) le16toh(tx_resp->status.status), (int) le16toh(tx_resp->status.sequence), tx_resp->frame_count, tx_resp->bt_kill_count, tx_resp->failure_rts, tx_resp->failure_frame, le32toh(tx_resp->initial_rate), (int) le16toh(tx_resp->wireless_media_time)); txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY | IEEE80211_RATECTL_STATUS_LONG_RETRY; txs->short_retries = tx_resp->failure_rts; txs->long_retries = tx_resp->failure_frame; if (status != IWM_TX_STATUS_SUCCESS && status != IWM_TX_STATUS_DIRECT_DONE) { switch (status) { case IWM_TX_STATUS_FAIL_SHORT_LIMIT: txs->status = IEEE80211_RATECTL_TX_FAIL_SHORT; break; case IWM_TX_STATUS_FAIL_LONG_LIMIT: txs->status = IEEE80211_RATECTL_TX_FAIL_LONG; break; case IWM_TX_STATUS_FAIL_LIFE_EXPIRE: txs->status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; break; default: txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED; break; } } else { txs->status = IEEE80211_RATECTL_TX_SUCCESS; } ieee80211_ratectl_tx_complete(ni, txs); return (txs->status != IEEE80211_RATECTL_TX_SUCCESS); } static void iwm_mvm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_rx_data *data) { struct iwm_cmd_header *cmd_hdr = &pkt->hdr; int idx = cmd_hdr->idx; int qid = cmd_hdr->qid; struct iwm_tx_ring *ring = &sc->txq[qid]; struct iwm_tx_data *txd = &ring->data[idx]; struct iwm_node *in = txd->in; struct mbuf *m = txd->m; int status; KASSERT(txd->done == 0, ("txd not done")); KASSERT(txd->in != NULL, ("txd without node")); KASSERT(txd->m != NULL, ("txd without mbuf")); bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); sc->sc_tx_timer = 0; status = iwm_mvm_rx_tx_cmd_single(sc, pkt, in); /* Unmap and free mbuf. */ bus_dmamap_sync(ring->data_dmat, txd->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, txd->map); IWM_DPRINTF(sc, IWM_DEBUG_XMIT, "free txd %p, in %p\n", txd, txd->in); txd->done = 1; txd->m = NULL; txd->in = NULL; ieee80211_tx_complete(&in->in_ni, m, status); if (--ring->queued < IWM_TX_RING_LOMARK) { sc->qfullmsk &= ~(1 << ring->qid); if (sc->qfullmsk == 0) { /* * Well, we're in interrupt context, but then again * I guess net80211 does all sorts of stunts in * interrupt context, so maybe this is no biggie. */ iwm_start(sc); } } } /* * transmit side */ /* * Process a "command done" firmware notification. This is where we wakeup * processes waiting for a synchronous command completion. * from if_iwn */ static void iwm_cmd_done(struct iwm_softc *sc, struct iwm_rx_packet *pkt) { struct iwm_tx_ring *ring = &sc->txq[IWM_MVM_CMD_QUEUE]; struct iwm_tx_data *data; if (pkt->hdr.qid != IWM_MVM_CMD_QUEUE) { return; /* Not a command ack. */ } /* XXX wide commands? */ IWM_DPRINTF(sc, IWM_DEBUG_CMD, "cmd notification type 0x%x qid %d idx %d\n", pkt->hdr.code, pkt->hdr.qid, pkt->hdr.idx); data = &ring->data[pkt->hdr.idx]; /* If the command was mapped in an mbuf, free it. */ if (data->m != NULL) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; } wakeup(&ring->desc[pkt->hdr.idx]); } #if 0 /* * necessary only for block ack mode */ void iwm_update_sched(struct iwm_softc *sc, int qid, int idx, uint8_t sta_id, uint16_t len) { struct iwm_agn_scd_bc_tbl *scd_bc_tbl; uint16_t w_val; scd_bc_tbl = sc->sched_dma.vaddr; len += 8; /* magic numbers came naturally from paris */ if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_DW_BC_TABLE) len = roundup(len, 4) / 4; w_val = htole16(sta_id << 12 | len); /* Update TX scheduler. */ scd_bc_tbl[qid].tfd_offset[idx] = w_val; bus_dmamap_sync(sc->sched_dma.tag, sc->sched_dma.map, BUS_DMASYNC_PREWRITE); /* I really wonder what this is ?!? */ if (idx < IWM_TFD_QUEUE_SIZE_BC_DUP) { scd_bc_tbl[qid].tfd_offset[IWM_TFD_QUEUE_SIZE_MAX + idx] = w_val; bus_dmamap_sync(sc->sched_dma.tag, sc->sched_dma.map, BUS_DMASYNC_PREWRITE); } } #endif /* * Take an 802.11 (non-n) rate, find the relevant rate * table entry. return the index into in_ridx[]. * * The caller then uses that index back into in_ridx * to figure out the rate index programmed /into/ * the firmware for this given node. */ static int iwm_tx_rateidx_lookup(struct iwm_softc *sc, struct iwm_node *in, uint8_t rate) { int i; uint8_t r; for (i = 0; i < nitems(in->in_ridx); i++) { r = iwm_rates[in->in_ridx[i]].rate; if (rate == r) return (i); } IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE, "%s: couldn't find an entry for rate=%d\n", __func__, rate); /* XXX Return the first */ /* XXX TODO: have it return the /lowest/ */ return (0); } static int iwm_tx_rateidx_global_lookup(struct iwm_softc *sc, uint8_t rate) { int i; for (i = 0; i < nitems(iwm_rates); i++) { if (iwm_rates[i].rate == rate) return (i); } /* XXX error? */ IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE, "%s: couldn't find an entry for rate=%d\n", __func__, rate); return (0); } /* * Fill in the rate related information for a transmit command. */ static const struct iwm_rate * iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in, struct mbuf *m, struct iwm_tx_cmd *tx) { struct ieee80211_node *ni = &in->in_ni; struct ieee80211_frame *wh; const struct ieee80211_txparam *tp = ni->ni_txparms; const struct iwm_rate *rinfo; int type; int ridx, rate_flags; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; tx->rts_retry_limit = IWM_RTS_DFAULT_RETRY_LIMIT; tx->data_retry_limit = IWM_DEFAULT_TX_RETRY; if (type == IEEE80211_FC0_TYPE_MGT) { ridx = iwm_tx_rateidx_global_lookup(sc, tp->mgmtrate); IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: MGT (%d)\n", __func__, tp->mgmtrate); } else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { ridx = iwm_tx_rateidx_global_lookup(sc, tp->mcastrate); IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: MCAST (%d)\n", __func__, tp->mcastrate); } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { ridx = iwm_tx_rateidx_global_lookup(sc, tp->ucastrate); IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: FIXED_RATE (%d)\n", __func__, tp->ucastrate); } else if (m->m_flags & M_EAPOL) { ridx = iwm_tx_rateidx_global_lookup(sc, tp->mgmtrate); IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: EAPOL\n", __func__); } else if (type == IEEE80211_FC0_TYPE_DATA) { int i; /* for data frames, use RS table */ IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: DATA\n", __func__); /* XXX pass pktlen */ (void) ieee80211_ratectl_rate(ni, NULL, 0); i = iwm_tx_rateidx_lookup(sc, in, ni->ni_txrate); ridx = in->in_ridx[i]; /* This is the index into the programmed table */ tx->initial_rate_index = i; tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE); IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE, "%s: start with i=%d, txrate %d\n", __func__, i, iwm_rates[ridx].rate); } else { ridx = iwm_tx_rateidx_global_lookup(sc, tp->mgmtrate); IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: DEFAULT (%d)\n", __func__, tp->mgmtrate); } IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE, "%s: frame type=%d txrate %d\n", __func__, type, iwm_rates[ridx].rate); rinfo = &iwm_rates[ridx]; IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: ridx=%d; rate=%d, CCK=%d\n", __func__, ridx, rinfo->rate, !! (IWM_RIDX_IS_CCK(ridx)) ); /* XXX TODO: hard-coded TX antenna? */ rate_flags = 1 << IWM_RATE_MCS_ANT_POS; if (IWM_RIDX_IS_CCK(ridx)) rate_flags |= IWM_RATE_MCS_CCK_MSK; tx->rate_n_flags = htole32(rate_flags | rinfo->plcp); return rinfo; } #define TB0_SIZE 16 static int iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwm_node *in = IWM_NODE(ni); struct iwm_tx_ring *ring; struct iwm_tx_data *data; struct iwm_tfd *desc; struct iwm_device_cmd *cmd; struct iwm_tx_cmd *tx; struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; struct mbuf *m1; const struct iwm_rate *rinfo; uint32_t flags; u_int hdrlen; bus_dma_segment_t *seg, segs[IWM_MAX_SCATTER]; int nsegs; uint8_t tid, type; int i, totlen, error, pad; wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_anyhdrsize(wh); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; tid = 0; ring = &sc->txq[ac]; desc = &ring->desc[ring->cur]; memset(desc, 0, sizeof(*desc)); data = &ring->data[ring->cur]; /* Fill out iwm_tx_cmd to send to the firmware */ cmd = &ring->cmd[ring->cur]; cmd->hdr.code = IWM_TX_CMD; cmd->hdr.flags = 0; cmd->hdr.qid = ring->qid; cmd->hdr.idx = ring->cur; tx = (void *)cmd->data; memset(tx, 0, sizeof(*tx)); rinfo = iwm_tx_fill_cmd(sc, in, m, tx); /* Encrypt the frame if need be. */ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { /* Retrieve key for TX && do software encryption. */ k = ieee80211_crypto_encap(ni, m); if (k == NULL) { m_freem(m); return (ENOBUFS); } /* 802.11 header may have moved. */ wh = mtod(m, struct ieee80211_frame *); } if (ieee80211_radiotap_active_vap(vap)) { struct iwm_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags); tap->wt_rate = rinfo->rate; if (k != NULL) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; ieee80211_radiotap_tx(vap, m); } totlen = m->m_pkthdr.len; flags = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= IWM_TX_CMD_FLG_ACK; } if (type == IEEE80211_FC0_TYPE_DATA && (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= IWM_TX_CMD_FLG_PROT_REQUIRE; } if (IEEE80211_IS_MULTICAST(wh->i_addr1) || type != IEEE80211_FC0_TYPE_DATA) tx->sta_id = sc->sc_aux_sta.sta_id; else tx->sta_id = IWM_STATION_ID; if (type == IEEE80211_FC0_TYPE_MGT) { uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { tx->pm_frame_timeout = htole16(IWM_PM_FRAME_ASSOC); } else if (subtype == IEEE80211_FC0_SUBTYPE_ACTION) { tx->pm_frame_timeout = htole16(IWM_PM_FRAME_NONE); } else { tx->pm_frame_timeout = htole16(IWM_PM_FRAME_MGMT); } } else { tx->pm_frame_timeout = htole16(IWM_PM_FRAME_NONE); } if (hdrlen & 3) { /* First segment length must be a multiple of 4. */ flags |= IWM_TX_CMD_FLG_MH_PAD; pad = 4 - (hdrlen & 3); } else pad = 0; tx->driver_txop = 0; tx->next_frame_len = 0; tx->len = htole16(totlen); tx->tid_tspec = tid; tx->life_time = htole32(IWM_TX_CMD_LIFE_TIME_INFINITE); /* Set physical address of "scratch area". */ tx->dram_lsb_ptr = htole32(data->scratch_paddr); tx->dram_msb_ptr = iwm_get_dma_hi_addr(data->scratch_paddr); /* Copy 802.11 header in TX command. */ memcpy(((uint8_t *)tx) + sizeof(*tx), wh, hdrlen); flags |= IWM_TX_CMD_FLG_BT_DIS | IWM_TX_CMD_FLG_SEQ_CTL; tx->sec_ctl = 0; tx->tx_flags |= htole32(flags); /* Trim 802.11 header. */ m_adj(m, hdrlen); error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { if (error != EFBIG) { device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", error); m_freem(m); return error; } /* Too many DMA segments, linearize mbuf. */ m1 = m_collapse(m, M_NOWAIT, IWM_MAX_SCATTER - 2); if (m1 == NULL) { device_printf(sc->sc_dev, "%s: could not defrag mbuf\n", __func__); m_freem(m); return (ENOBUFS); } m = m1; error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", error); m_freem(m); return error; } } data->m = m; data->in = in; data->done = 0; IWM_DPRINTF(sc, IWM_DEBUG_XMIT, "sending txd %p, in %p\n", data, data->in); KASSERT(data->in != NULL, ("node is NULL")); IWM_DPRINTF(sc, IWM_DEBUG_XMIT, "sending data: qid=%d idx=%d len=%d nsegs=%d txflags=0x%08x rate_n_flags=0x%08x rateidx=%u\n", ring->qid, ring->cur, totlen, nsegs, le32toh(tx->tx_flags), le32toh(tx->rate_n_flags), tx->initial_rate_index ); /* Fill TX descriptor. */ desc->num_tbs = 2 + nsegs; desc->tbs[0].lo = htole32(data->cmd_paddr); desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr)) | (TB0_SIZE << 4); desc->tbs[1].lo = htole32(data->cmd_paddr + TB0_SIZE); desc->tbs[1].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr)) | ((sizeof(struct iwm_cmd_header) + sizeof(*tx) + hdrlen + pad - TB0_SIZE) << 4); /* Other DMA segments are for data payload. */ for (i = 0; i < nsegs; i++) { seg = &segs[i]; desc->tbs[i+2].lo = htole32(seg->ds_addr); desc->tbs[i+2].hi_n_len = \ htole16(iwm_get_dma_hi_addr(seg->ds_addr)) | ((seg->ds_len) << 4); } bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(ring->cmd_dma.tag, ring->cmd_dma.map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); #if 0 iwm_update_sched(sc, ring->qid, ring->cur, tx->sta_id, le16toh(tx->len)); #endif /* Kick TX ring. */ ring->cur = (ring->cur + 1) % IWM_TX_RING_COUNT; IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); /* Mark TX ring as full if we reach a certain threshold. */ if (++ring->queued > IWM_TX_RING_HIMARK) { sc->qfullmsk |= 1 << ring->qid; } return 0; } static int iwm_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; struct iwm_softc *sc = ic->ic_softc; int error = 0; IWM_DPRINTF(sc, IWM_DEBUG_XMIT, "->%s begin\n", __func__); if ((sc->sc_flags & IWM_FLAG_HW_INITED) == 0) { m_freem(m); IWM_DPRINTF(sc, IWM_DEBUG_XMIT, "<-%s not RUNNING\n", __func__); return (ENETDOWN); } IWM_LOCK(sc); /* XXX fix this */ if (params == NULL) { error = iwm_tx(sc, m, ni, 0); } else { error = iwm_tx(sc, m, ni, 0); } sc->sc_tx_timer = 5; IWM_UNLOCK(sc); return (error); } /* * mvm/tx.c */ /* * Note that there are transports that buffer frames before they reach * the firmware. This means that after flush_tx_path is called, the * queue might not be empty. The race-free way to handle this is to: * 1) set the station as draining * 2) flush the Tx path * 3) wait for the transport queues to be empty */ int iwm_mvm_flush_tx_path(struct iwm_softc *sc, uint32_t tfd_msk, uint32_t flags) { int ret; struct iwm_tx_path_flush_cmd flush_cmd = { .queues_ctl = htole32(tfd_msk), .flush_ctl = htole16(IWM_DUMP_TX_FIFO_FLUSH), }; ret = iwm_mvm_send_cmd_pdu(sc, IWM_TXPATH_FLUSH, flags, sizeof(flush_cmd), &flush_cmd); if (ret) device_printf(sc->sc_dev, "Flushing tx queue failed: %d\n", ret); return ret; } /* * BEGIN mvm/sta.c */ static int iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *sc, struct iwm_mvm_add_sta_cmd_v7 *cmd, int *status) { return iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, sizeof(*cmd), cmd, status); } /* send station add/update command to firmware */ static int iwm_mvm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in, int update) { struct iwm_mvm_add_sta_cmd_v7 add_sta_cmd; int ret; uint32_t status; memset(&add_sta_cmd, 0, sizeof(add_sta_cmd)); add_sta_cmd.sta_id = IWM_STATION_ID; add_sta_cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_DEFAULT_MACID, IWM_DEFAULT_COLOR)); if (!update) { int ac; for (ac = 0; ac < WME_NUM_AC; ac++) { add_sta_cmd.tfd_queue_msk |= htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]); } IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid); } add_sta_cmd.add_modify = update ? 1 : 0; add_sta_cmd.station_flags_msk |= htole32(IWM_STA_FLG_FAT_EN_MSK | IWM_STA_FLG_MIMO_EN_MSK); add_sta_cmd.tid_disable_tx = htole16(0xffff); if (update) add_sta_cmd.modify_mask |= (IWM_STA_MODIFY_TID_DISABLE_TX); status = IWM_ADD_STA_SUCCESS; ret = iwm_mvm_send_add_sta_cmd_status(sc, &add_sta_cmd, &status); if (ret) return ret; switch (status) { case IWM_ADD_STA_SUCCESS: break; default: ret = EIO; device_printf(sc->sc_dev, "IWM_ADD_STA failed\n"); break; } return ret; } static int iwm_mvm_add_sta(struct iwm_softc *sc, struct iwm_node *in) { return iwm_mvm_sta_send_to_fw(sc, in, 0); } static int iwm_mvm_update_sta(struct iwm_softc *sc, struct iwm_node *in) { return iwm_mvm_sta_send_to_fw(sc, in, 1); } static int iwm_mvm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta, const uint8_t *addr, uint16_t mac_id, uint16_t color) { struct iwm_mvm_add_sta_cmd_v7 cmd; int ret; uint32_t status; memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = sta->sta_id; cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(mac_id, color)); cmd.tfd_queue_msk = htole32(sta->tfd_queue_msk); cmd.tid_disable_tx = htole16(0xffff); if (addr) IEEE80211_ADDR_COPY(cmd.addr, addr); ret = iwm_mvm_send_add_sta_cmd_status(sc, &cmd, &status); if (ret) return ret; switch (status) { case IWM_ADD_STA_SUCCESS: IWM_DPRINTF(sc, IWM_DEBUG_RESET, "%s: Internal station added.\n", __func__); return 0; default: device_printf(sc->sc_dev, "%s: Add internal station failed, status=0x%x\n", __func__, status); ret = EIO; break; } return ret; } static int iwm_mvm_add_aux_sta(struct iwm_softc *sc) { int ret; sc->sc_aux_sta.sta_id = IWM_AUX_STA_ID; sc->sc_aux_sta.tfd_queue_msk = (1 << IWM_MVM_AUX_QUEUE); ret = iwm_enable_txq(sc, 0, IWM_MVM_AUX_QUEUE, IWM_MVM_TX_FIFO_MCAST); if (ret) return ret; ret = iwm_mvm_add_int_sta_common(sc, &sc->sc_aux_sta, NULL, IWM_MAC_INDEX_AUX, 0); if (ret) memset(&sc->sc_aux_sta, 0, sizeof(sc->sc_aux_sta)); return ret; } /* * END mvm/sta.c */ /* * BEGIN mvm/quota.c */ static int iwm_mvm_update_quotas(struct iwm_softc *sc, struct iwm_node *in) { struct iwm_time_quota_cmd cmd; int i, idx, ret, num_active_macs, quota, quota_rem; int colors[IWM_MAX_BINDINGS] = { -1, -1, -1, -1, }; int n_ifs[IWM_MAX_BINDINGS] = {0, }; uint16_t id; memset(&cmd, 0, sizeof(cmd)); /* currently, PHY ID == binding ID */ if (in) { id = in->in_phyctxt->id; KASSERT(id < IWM_MAX_BINDINGS, ("invalid id")); colors[id] = in->in_phyctxt->color; if (1) n_ifs[id] = 1; } /* * The FW's scheduling session consists of * IWM_MVM_MAX_QUOTA fragments. Divide these fragments * equally between all the bindings that require quota */ num_active_macs = 0; for (i = 0; i < IWM_MAX_BINDINGS; i++) { cmd.quotas[i].id_and_color = htole32(IWM_FW_CTXT_INVALID); num_active_macs += n_ifs[i]; } quota = 0; quota_rem = 0; if (num_active_macs) { quota = IWM_MVM_MAX_QUOTA / num_active_macs; quota_rem = IWM_MVM_MAX_QUOTA % num_active_macs; } for (idx = 0, i = 0; i < IWM_MAX_BINDINGS; i++) { if (colors[i] < 0) continue; cmd.quotas[idx].id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(i, colors[i])); if (n_ifs[i] <= 0) { cmd.quotas[idx].quota = htole32(0); cmd.quotas[idx].max_duration = htole32(0); } else { cmd.quotas[idx].quota = htole32(quota * n_ifs[i]); cmd.quotas[idx].max_duration = htole32(0); } idx++; } /* Give the remainder of the session to the first binding */ cmd.quotas[0].quota = htole32(le32toh(cmd.quotas[0].quota) + quota_rem); ret = iwm_mvm_send_cmd_pdu(sc, IWM_TIME_QUOTA_CMD, IWM_CMD_SYNC, sizeof(cmd), &cmd); if (ret) device_printf(sc->sc_dev, "%s: Failed to send quota: %d\n", __func__, ret); return ret; } /* * END mvm/quota.c */ /* * ieee80211 routines */ /* * Change to AUTH state in 80211 state machine. Roughly matches what * Linux does in bss_info_changed(). */ static int iwm_auth(struct ieee80211vap *vap, struct iwm_softc *sc) { struct ieee80211_node *ni; struct iwm_node *in; struct iwm_vap *iv = IWM_VAP(vap); uint32_t duration; int error; /* * XXX i have a feeling that the vap node is being * freed from underneath us. Grr. */ ni = ieee80211_ref_node(vap->iv_bss); in = IWM_NODE(ni); IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_STATE, "%s: called; vap=%p, bss ni=%p\n", __func__, vap, ni); in->in_assoc = 0; error = iwm_mvm_sf_config(sc, IWM_SF_FULL_ON); if (error != 0) return error; error = iwm_allow_mcast(vap, sc); if (error) { device_printf(sc->sc_dev, "%s: failed to set multicast\n", __func__); goto out; } /* * This is where it deviates from what Linux does. * * Linux iwlwifi doesn't reset the nic each time, nor does it * call ctxt_add() here. Instead, it adds it during vap creation, * and always does a mac_ctx_changed(). * * The openbsd port doesn't attempt to do that - it reset things * at odd states and does the add here. * * So, until the state handling is fixed (ie, we never reset * the NIC except for a firmware failure, which should drag * the NIC back to IDLE, re-setup and re-add all the mac/phy * contexts that are required), let's do a dirty hack here. */ if (iv->is_uploaded) { if ((error = iwm_mvm_mac_ctxt_changed(sc, vap)) != 0) { device_printf(sc->sc_dev, "%s: failed to update MAC\n", __func__); goto out; } if ((error = iwm_mvm_phy_ctxt_changed(sc, &sc->sc_phyctxt[0], in->in_ni.ni_chan, 1, 1)) != 0) { device_printf(sc->sc_dev, "%s: failed update phy ctxt\n", __func__); goto out; } in->in_phyctxt = &sc->sc_phyctxt[0]; if ((error = iwm_mvm_binding_update(sc, in)) != 0) { device_printf(sc->sc_dev, "%s: binding update cmd\n", __func__); goto out; } if ((error = iwm_mvm_update_sta(sc, in)) != 0) { device_printf(sc->sc_dev, "%s: failed to update sta\n", __func__); goto out; } } else { if ((error = iwm_mvm_mac_ctxt_add(sc, vap)) != 0) { device_printf(sc->sc_dev, "%s: failed to add MAC\n", __func__); goto out; } if ((error = iwm_mvm_phy_ctxt_changed(sc, &sc->sc_phyctxt[0], in->in_ni.ni_chan, 1, 1)) != 0) { device_printf(sc->sc_dev, "%s: failed add phy ctxt!\n", __func__); error = ETIMEDOUT; goto out; } in->in_phyctxt = &sc->sc_phyctxt[0]; if ((error = iwm_mvm_binding_add_vif(sc, in)) != 0) { device_printf(sc->sc_dev, "%s: binding add cmd\n", __func__); goto out; } if ((error = iwm_mvm_add_sta(sc, in)) != 0) { device_printf(sc->sc_dev, "%s: failed to add sta\n", __func__); goto out; } } /* * Prevent the FW from wandering off channel during association * by "protecting" the session with a time event. */ /* XXX duration is in units of TU, not MS */ duration = IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS; iwm_mvm_protect_session(sc, in, duration, 500 /* XXX magic number */); DELAY(100); error = 0; out: ieee80211_free_node(ni); return (error); } static int iwm_assoc(struct ieee80211vap *vap, struct iwm_softc *sc) { struct iwm_node *in = IWM_NODE(vap->iv_bss); int error; if ((error = iwm_mvm_update_sta(sc, in)) != 0) { device_printf(sc->sc_dev, "%s: failed to update STA\n", __func__); return error; } in->in_assoc = 1; if ((error = iwm_mvm_mac_ctxt_changed(sc, vap)) != 0) { device_printf(sc->sc_dev, "%s: failed to update MAC\n", __func__); return error; } return 0; } static int iwm_release(struct iwm_softc *sc, struct iwm_node *in) { uint32_t tfd_msk; /* * Ok, so *technically* the proper set of calls for going * from RUN back to SCAN is: * * iwm_mvm_power_mac_disable(sc, in); * iwm_mvm_mac_ctxt_changed(sc, in); * iwm_mvm_rm_sta(sc, in); * iwm_mvm_update_quotas(sc, NULL); * iwm_mvm_mac_ctxt_changed(sc, in); * iwm_mvm_binding_remove_vif(sc, in); * iwm_mvm_mac_ctxt_remove(sc, in); * * However, that freezes the device not matter which permutations * and modifications are attempted. Obviously, this driver is missing * something since it works in the Linux driver, but figuring out what * is missing is a little more complicated. Now, since we're going * back to nothing anyway, we'll just do a complete device reset. * Up your's, device! */ /* * Just using 0xf for the queues mask is fine as long as we only * get here from RUN state. */ tfd_msk = 0xf; mbufq_drain(&sc->sc_snd); iwm_mvm_flush_tx_path(sc, tfd_msk, IWM_CMD_SYNC); /* * We seem to get away with just synchronously sending the * IWM_TXPATH_FLUSH command. */ // iwm_trans_wait_tx_queue_empty(sc, tfd_msk); iwm_stop_device(sc); iwm_init_hw(sc); if (in) in->in_assoc = 0; return 0; #if 0 int error; iwm_mvm_power_mac_disable(sc, in); if ((error = iwm_mvm_mac_ctxt_changed(sc, in)) != 0) { device_printf(sc->sc_dev, "mac ctxt change fail 1 %d\n", error); return error; } if ((error = iwm_mvm_rm_sta(sc, in)) != 0) { device_printf(sc->sc_dev, "sta remove fail %d\n", error); return error; } error = iwm_mvm_rm_sta(sc, in); in->in_assoc = 0; iwm_mvm_update_quotas(sc, NULL); if ((error = iwm_mvm_mac_ctxt_changed(sc, in)) != 0) { device_printf(sc->sc_dev, "mac ctxt change fail 2 %d\n", error); return error; } iwm_mvm_binding_remove_vif(sc, in); iwm_mvm_mac_ctxt_remove(sc, in); return error; #endif } static struct ieee80211_node * iwm_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) { return malloc(sizeof (struct iwm_node), M_80211_NODE, M_NOWAIT | M_ZERO); } static void iwm_setrates(struct iwm_softc *sc, struct iwm_node *in) { struct ieee80211_node *ni = &in->in_ni; struct iwm_lq_cmd *lq = &in->in_lq; int nrates = ni->ni_rates.rs_nrates; int i, ridx, tab = 0; // int txant = 0; if (nrates > nitems(lq->rs_table)) { device_printf(sc->sc_dev, "%s: node supports %d rates, driver handles " "only %zu\n", __func__, nrates, nitems(lq->rs_table)); return; } if (nrates == 0) { device_printf(sc->sc_dev, "%s: node supports 0 rates, odd!\n", __func__); return; } /* * XXX .. and most of iwm_node is not initialised explicitly; * it's all just 0x0 passed to the firmware. */ /* first figure out which rates we should support */ /* XXX TODO: this isn't 11n aware /at all/ */ memset(&in->in_ridx, -1, sizeof(in->in_ridx)); IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: nrates=%d\n", __func__, nrates); /* * Loop over nrates and populate in_ridx from the highest * rate to the lowest rate. Remember, in_ridx[] has * IEEE80211_RATE_MAXSIZE entries! */ for (i = 0; i < min(nrates, IEEE80211_RATE_MAXSIZE); i++) { int rate = ni->ni_rates.rs_rates[(nrates - 1) - i] & IEEE80211_RATE_VAL; /* Map 802.11 rate to HW rate index. */ for (ridx = 0; ridx <= IWM_RIDX_MAX; ridx++) if (iwm_rates[ridx].rate == rate) break; if (ridx > IWM_RIDX_MAX) { device_printf(sc->sc_dev, "%s: WARNING: device rate for %d not found!\n", __func__, rate); } else { IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: rate: i: %d, rate=%d, ridx=%d\n", __func__, i, rate, ridx); in->in_ridx[i] = ridx; } } /* then construct a lq_cmd based on those */ memset(lq, 0, sizeof(*lq)); lq->sta_id = IWM_STATION_ID; /* For HT, always enable RTS/CTS to avoid excessive retries. */ if (ni->ni_flags & IEEE80211_NODE_HT) lq->flags |= IWM_LQ_FLAG_USE_RTS_MSK; /* * are these used? (we don't do SISO or MIMO) * need to set them to non-zero, though, or we get an error. */ lq->single_stream_ant_msk = 1; lq->dual_stream_ant_msk = 1; /* * Build the actual rate selection table. * The lowest bits are the rates. Additionally, * CCK needs bit 9 to be set. The rest of the bits * we add to the table select the tx antenna * Note that we add the rates in the highest rate first * (opposite of ni_rates). */ /* * XXX TODO: this should be looping over the min of nrates * and LQ_MAX_RETRY_NUM. Sigh. */ for (i = 0; i < nrates; i++) { int nextant; #if 0 if (txant == 0) txant = iwm_fw_valid_tx_ant(sc); nextant = 1<<(ffs(txant)-1); txant &= ~nextant; #else nextant = iwm_fw_valid_tx_ant(sc); #endif /* * Map the rate id into a rate index into * our hardware table containing the * configuration to use for this rate. */ ridx = in->in_ridx[i]; tab = iwm_rates[ridx].plcp; tab |= nextant << IWM_RATE_MCS_ANT_POS; if (IWM_RIDX_IS_CCK(ridx)) tab |= IWM_RATE_MCS_CCK_MSK; IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "station rate i=%d, rate=%d, hw=%x\n", i, iwm_rates[ridx].rate, tab); lq->rs_table[i] = htole32(tab); } /* then fill the rest with the lowest possible rate */ for (i = nrates; i < nitems(lq->rs_table); i++) { KASSERT(tab != 0, ("invalid tab")); lq->rs_table[i] = htole32(tab); } } static int iwm_media_change(struct ifnet *ifp) { struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; struct iwm_softc *sc = ic->ic_softc; int error; error = ieee80211_media_change(ifp); if (error != ENETRESET) return error; IWM_LOCK(sc); if (ic->ic_nrunning > 0) { iwm_stop(sc); iwm_init(sc); } IWM_UNLOCK(sc); return error; } static int iwm_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct iwm_vap *ivp = IWM_VAP(vap); struct ieee80211com *ic = vap->iv_ic; struct iwm_softc *sc = ic->ic_softc; struct iwm_node *in; int error; IWM_DPRINTF(sc, IWM_DEBUG_STATE, "switching state %s -> %s\n", ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate]); IEEE80211_UNLOCK(ic); IWM_LOCK(sc); if (vap->iv_state == IEEE80211_S_SCAN && nstate != vap->iv_state) iwm_led_blink_stop(sc); /* disable beacon filtering if we're hopping out of RUN */ if (vap->iv_state == IEEE80211_S_RUN && nstate != vap->iv_state) { iwm_mvm_disable_beacon_filter(sc); if (((in = IWM_NODE(vap->iv_bss)) != NULL)) in->in_assoc = 0; if (nstate == IEEE80211_S_INIT) { IWM_UNLOCK(sc); IEEE80211_LOCK(ic); error = ivp->iv_newstate(vap, nstate, arg); IEEE80211_UNLOCK(ic); IWM_LOCK(sc); iwm_release(sc, NULL); IWM_UNLOCK(sc); IEEE80211_LOCK(ic); return error; } /* * It's impossible to directly go RUN->SCAN. If we iwm_release() * above then the card will be completely reinitialized, * so the driver must do everything necessary to bring the card * from INIT to SCAN. * * Additionally, upon receiving deauth frame from AP, * OpenBSD 802.11 stack puts the driver in IEEE80211_S_AUTH * state. This will also fail with this driver, so bring the FSM * from IEEE80211_S_RUN to IEEE80211_S_SCAN in this case as well. * * XXX TODO: fix this for FreeBSD! */ if (nstate == IEEE80211_S_SCAN || nstate == IEEE80211_S_AUTH || nstate == IEEE80211_S_ASSOC) { IWM_DPRINTF(sc, IWM_DEBUG_STATE, "Force transition to INIT; MGT=%d\n", arg); IWM_UNLOCK(sc); IEEE80211_LOCK(ic); /* Always pass arg as -1 since we can't Tx right now. */ /* * XXX arg is just ignored anyway when transitioning * to IEEE80211_S_INIT. */ vap->iv_newstate(vap, IEEE80211_S_INIT, -1); IWM_DPRINTF(sc, IWM_DEBUG_STATE, "Going INIT->SCAN\n"); nstate = IEEE80211_S_SCAN; IEEE80211_UNLOCK(ic); IWM_LOCK(sc); } } switch (nstate) { case IEEE80211_S_INIT: break; case IEEE80211_S_AUTH: if ((error = iwm_auth(vap, sc)) != 0) { device_printf(sc->sc_dev, "%s: could not move to auth state: %d\n", __func__, error); break; } break; case IEEE80211_S_ASSOC: if ((error = iwm_assoc(vap, sc)) != 0) { device_printf(sc->sc_dev, "%s: failed to associate: %d\n", __func__, error); break; } break; case IEEE80211_S_RUN: { struct iwm_host_cmd cmd = { .id = IWM_LQ_CMD, .len = { sizeof(in->in_lq), }, .flags = IWM_CMD_SYNC, }; /* Update the association state, now we have it all */ /* (eg associd comes in at this point */ error = iwm_assoc(vap, sc); if (error != 0) { device_printf(sc->sc_dev, "%s: failed to update association state: %d\n", __func__, error); break; } in = IWM_NODE(vap->iv_bss); iwm_mvm_power_mac_update_mode(sc, in); iwm_mvm_enable_beacon_filter(sc, in); iwm_mvm_update_quotas(sc, in); iwm_setrates(sc, in); cmd.data[0] = &in->in_lq; if ((error = iwm_send_cmd(sc, &cmd)) != 0) { device_printf(sc->sc_dev, "%s: IWM_LQ_CMD failed\n", __func__); } iwm_mvm_led_enable(sc); break; } default: break; } IWM_UNLOCK(sc); IEEE80211_LOCK(ic); return (ivp->iv_newstate(vap, nstate, arg)); } void iwm_endscan_cb(void *arg, int pending) { struct iwm_softc *sc = arg; struct ieee80211com *ic = &sc->sc_ic; IWM_DPRINTF(sc, IWM_DEBUG_SCAN | IWM_DEBUG_TRACE, "%s: scan ended\n", __func__); ieee80211_scan_done(TAILQ_FIRST(&ic->ic_vaps)); } /* * Aging and idle timeouts for the different possible scenarios * in default configuration */ static const uint32_t iwm_sf_full_timeout_def[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = { { htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER_DEF), htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER_DEF) }, { htole32(IWM_SF_AGG_UNICAST_AGING_TIMER_DEF), htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER_DEF) }, { htole32(IWM_SF_MCAST_AGING_TIMER_DEF), htole32(IWM_SF_MCAST_IDLE_TIMER_DEF) }, { htole32(IWM_SF_BA_AGING_TIMER_DEF), htole32(IWM_SF_BA_IDLE_TIMER_DEF) }, { htole32(IWM_SF_TX_RE_AGING_TIMER_DEF), htole32(IWM_SF_TX_RE_IDLE_TIMER_DEF) }, }; /* * Aging and idle timeouts for the different possible scenarios * in single BSS MAC configuration. */ static const uint32_t iwm_sf_full_timeout[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = { { htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER), htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER) }, { htole32(IWM_SF_AGG_UNICAST_AGING_TIMER), htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER) }, { htole32(IWM_SF_MCAST_AGING_TIMER), htole32(IWM_SF_MCAST_IDLE_TIMER) }, { htole32(IWM_SF_BA_AGING_TIMER), htole32(IWM_SF_BA_IDLE_TIMER) }, { htole32(IWM_SF_TX_RE_AGING_TIMER), htole32(IWM_SF_TX_RE_IDLE_TIMER) }, }; static void iwm_mvm_fill_sf_command(struct iwm_softc *sc, struct iwm_sf_cfg_cmd *sf_cmd, struct ieee80211_node *ni) { int i, j, watermark; sf_cmd->watermark[IWM_SF_LONG_DELAY_ON] = htole32(IWM_SF_W_MARK_SCAN); /* * If we are in association flow - check antenna configuration * capabilities of the AP station, and choose the watermark accordingly. */ if (ni) { if (ni->ni_flags & IEEE80211_NODE_HT) { #ifdef notyet if (ni->ni_rxmcs[2] != 0) watermark = IWM_SF_W_MARK_MIMO3; else if (ni->ni_rxmcs[1] != 0) watermark = IWM_SF_W_MARK_MIMO2; else #endif watermark = IWM_SF_W_MARK_SISO; } else { watermark = IWM_SF_W_MARK_LEGACY; } /* default watermark value for unassociated mode. */ } else { watermark = IWM_SF_W_MARK_MIMO2; } sf_cmd->watermark[IWM_SF_FULL_ON] = htole32(watermark); for (i = 0; i < IWM_SF_NUM_SCENARIO; i++) { for (j = 0; j < IWM_SF_NUM_TIMEOUT_TYPES; j++) { sf_cmd->long_delay_timeouts[i][j] = htole32(IWM_SF_LONG_DELAY_AGING_TIMER); } } if (ni) { memcpy(sf_cmd->full_on_timeouts, iwm_sf_full_timeout, sizeof(iwm_sf_full_timeout)); } else { memcpy(sf_cmd->full_on_timeouts, iwm_sf_full_timeout_def, sizeof(iwm_sf_full_timeout_def)); } } static int iwm_mvm_sf_config(struct iwm_softc *sc, enum iwm_sf_state new_state) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwm_sf_cfg_cmd sf_cmd = { .state = htole32(IWM_SF_FULL_ON), }; int ret = 0; - if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) sf_cmd.state |= htole32(IWM_SF_CFG_DUMMY_NOTIF_OFF); switch (new_state) { case IWM_SF_UNINIT: case IWM_SF_INIT_OFF: iwm_mvm_fill_sf_command(sc, &sf_cmd, NULL); break; case IWM_SF_FULL_ON: iwm_mvm_fill_sf_command(sc, &sf_cmd, vap->iv_bss); break; default: IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE, "Invalid state: %d. not sending Smart Fifo cmd\n", new_state); return EINVAL; } ret = iwm_mvm_send_cmd_pdu(sc, IWM_REPLY_SF_CFG_CMD, IWM_CMD_ASYNC, sizeof(sf_cmd), &sf_cmd); return ret; } static int iwm_send_bt_init_conf(struct iwm_softc *sc) { struct iwm_bt_coex_cmd bt_cmd; bt_cmd.mode = htole32(IWM_BT_COEX_WIFI); bt_cmd.enabled_modules = htole32(IWM_BT_COEX_HIGH_BAND_RET); return iwm_mvm_send_cmd_pdu(sc, IWM_BT_CONFIG, 0, sizeof(bt_cmd), &bt_cmd); } static int iwm_send_update_mcc_cmd(struct iwm_softc *sc, const char *alpha2) { struct iwm_mcc_update_cmd mcc_cmd; struct iwm_host_cmd hcmd = { .id = IWM_MCC_UPDATE_CMD, .flags = (IWM_CMD_SYNC | IWM_CMD_WANT_SKB), .data = { &mcc_cmd }, }; int ret; #ifdef IWM_DEBUG struct iwm_rx_packet *pkt; struct iwm_mcc_update_resp_v1 *mcc_resp_v1 = NULL; struct iwm_mcc_update_resp *mcc_resp; int n_channels; uint16_t mcc; #endif int resp_v2 = isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2); memset(&mcc_cmd, 0, sizeof(mcc_cmd)); mcc_cmd.mcc = htole16(alpha2[0] << 8 | alpha2[1]); if ((sc->sc_ucode_api & IWM_UCODE_TLV_API_WIFI_MCC_UPDATE) || isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC)) mcc_cmd.source_id = IWM_MCC_SOURCE_GET_CURRENT; else mcc_cmd.source_id = IWM_MCC_SOURCE_OLD_FW; if (resp_v2) hcmd.len[0] = sizeof(struct iwm_mcc_update_cmd); else hcmd.len[0] = sizeof(struct iwm_mcc_update_cmd_v1); IWM_DPRINTF(sc, IWM_DEBUG_NODE, "send MCC update to FW with '%c%c' src = %d\n", alpha2[0], alpha2[1], mcc_cmd.source_id); ret = iwm_send_cmd(sc, &hcmd); if (ret) return ret; #ifdef IWM_DEBUG pkt = hcmd.resp_pkt; /* Extract MCC response */ if (resp_v2) { mcc_resp = (void *)pkt->data; mcc = mcc_resp->mcc; n_channels = le32toh(mcc_resp->n_channels); } else { mcc_resp_v1 = (void *)pkt->data; mcc = mcc_resp_v1->mcc; n_channels = le32toh(mcc_resp_v1->n_channels); } /* W/A for a FW/NVM issue - returns 0x00 for the world domain */ if (mcc == 0) mcc = 0x3030; /* "00" - world */ IWM_DPRINTF(sc, IWM_DEBUG_NODE, "regulatory domain '%c%c' (%d channels available)\n", mcc >> 8, mcc & 0xff, n_channels); #endif iwm_free_resp(sc, &hcmd); return 0; } static void iwm_mvm_tt_tx_backoff(struct iwm_softc *sc, uint32_t backoff) { struct iwm_host_cmd cmd = { .id = IWM_REPLY_THERMAL_MNG_BACKOFF, .len = { sizeof(uint32_t), }, .data = { &backoff, }, }; if (iwm_send_cmd(sc, &cmd) != 0) { device_printf(sc->sc_dev, "failed to change thermal tx backoff\n"); } } static int iwm_init_hw(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; int error, i, ac; if ((error = iwm_start_hw(sc)) != 0) { printf("iwm_start_hw: failed %d\n", error); return error; } if ((error = iwm_run_init_mvm_ucode(sc, 0)) != 0) { printf("iwm_run_init_mvm_ucode: failed %d\n", error); return error; } /* * should stop and start HW since that INIT * image just loaded */ iwm_stop_device(sc); if ((error = iwm_start_hw(sc)) != 0) { device_printf(sc->sc_dev, "could not initialize hardware\n"); return error; } /* omstart, this time with the regular firmware */ error = iwm_mvm_load_ucode_wait_alive(sc, IWM_UCODE_TYPE_REGULAR); if (error) { device_printf(sc->sc_dev, "could not load firmware\n"); goto error; } if ((error = iwm_send_bt_init_conf(sc)) != 0) { device_printf(sc->sc_dev, "bt init conf failed\n"); goto error; } if ((error = iwm_send_tx_ant_cfg(sc, iwm_fw_valid_tx_ant(sc))) != 0) { device_printf(sc->sc_dev, "antenna config failed\n"); goto error; } - /* Send phy db control command and then phy db calibration*/ - if ((error = iwm_send_phy_db_data(sc)) != 0) { - device_printf(sc->sc_dev, "phy_db_data failed\n"); + /* Send phy db control command and then phy db calibration */ + if ((error = iwm_send_phy_db_data(sc->sc_phy_db)) != 0) goto error; - } if ((error = iwm_send_phy_cfg_cmd(sc)) != 0) { device_printf(sc->sc_dev, "phy_cfg_cmd failed\n"); goto error; } /* Add auxiliary station for scanning */ if ((error = iwm_mvm_add_aux_sta(sc)) != 0) { device_printf(sc->sc_dev, "add_aux_sta failed\n"); goto error; } for (i = 0; i < IWM_NUM_PHY_CTX; i++) { /* * The channel used here isn't relevant as it's * going to be overwritten in the other flows. * For now use the first channel we have. */ if ((error = iwm_mvm_phy_ctxt_add(sc, &sc->sc_phyctxt[i], &ic->ic_channels[1], 1, 1)) != 0) goto error; } /* Initialize tx backoffs to the minimum. */ - if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) iwm_mvm_tt_tx_backoff(sc, 0); error = iwm_mvm_power_update_device(sc); if (error) goto error; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_SUPPORT)) { if ((error = iwm_send_update_mcc_cmd(sc, "ZZ")) != 0) goto error; } if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) { if ((error = iwm_mvm_config_umac_scan(sc)) != 0) goto error; } /* Enable Tx queues. */ for (ac = 0; ac < WME_NUM_AC; ac++) { error = iwm_enable_txq(sc, IWM_STATION_ID, ac, iwm_mvm_ac_to_tx_fifo[ac]); if (error) goto error; } if ((error = iwm_mvm_disable_beacon_filter(sc)) != 0) { device_printf(sc->sc_dev, "failed to disable beacon filter\n"); goto error; } return 0; error: iwm_stop_device(sc); return error; } /* Allow multicast from our BSSID. */ static int iwm_allow_mcast(struct ieee80211vap *vap, struct iwm_softc *sc) { struct ieee80211_node *ni = vap->iv_bss; struct iwm_mcast_filter_cmd *cmd; size_t size; int error; size = roundup(sizeof(*cmd), 4); cmd = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); if (cmd == NULL) return ENOMEM; cmd->filter_own = 1; cmd->port_id = 0; cmd->count = 0; cmd->pass_all = 1; IEEE80211_ADDR_COPY(cmd->bssid, ni->ni_bssid); error = iwm_mvm_send_cmd_pdu(sc, IWM_MCAST_FILTER_CMD, IWM_CMD_SYNC, size, cmd); free(cmd, M_DEVBUF); return (error); } /* * ifnet interfaces */ static void iwm_init(struct iwm_softc *sc) { int error; if (sc->sc_flags & IWM_FLAG_HW_INITED) { return; } sc->sc_generation++; sc->sc_flags &= ~IWM_FLAG_STOPPED; if ((error = iwm_init_hw(sc)) != 0) { printf("iwm_init_hw failed %d\n", error); iwm_stop(sc); return; } /* * Ok, firmware loaded and we are jogging */ sc->sc_flags |= IWM_FLAG_HW_INITED; callout_reset(&sc->sc_watchdog_to, hz, iwm_watchdog, sc); } static int iwm_transmit(struct ieee80211com *ic, struct mbuf *m) { struct iwm_softc *sc; int error; sc = ic->ic_softc; IWM_LOCK(sc); if ((sc->sc_flags & IWM_FLAG_HW_INITED) == 0) { IWM_UNLOCK(sc); return (ENXIO); } error = mbufq_enqueue(&sc->sc_snd, m); if (error) { IWM_UNLOCK(sc); return (error); } iwm_start(sc); IWM_UNLOCK(sc); return (0); } /* * Dequeue packets from sendq and call send. */ static void iwm_start(struct iwm_softc *sc) { struct ieee80211_node *ni; struct mbuf *m; int ac = 0; IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TRACE, "->%s\n", __func__); while (sc->qfullmsk == 0 && (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; if (iwm_tx(sc, m, ni, ac) != 0) { if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); ieee80211_free_node(ni); continue; } sc->sc_tx_timer = 15; } IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TRACE, "<-%s\n", __func__); } static void iwm_stop(struct iwm_softc *sc) { sc->sc_flags &= ~IWM_FLAG_HW_INITED; sc->sc_flags |= IWM_FLAG_STOPPED; sc->sc_generation++; iwm_led_blink_stop(sc); sc->sc_tx_timer = 0; iwm_stop_device(sc); } static void iwm_watchdog(void *arg) { struct iwm_softc *sc = arg; struct ieee80211com *ic = &sc->sc_ic; if (sc->sc_tx_timer > 0) { if (--sc->sc_tx_timer == 0) { device_printf(sc->sc_dev, "device timeout\n"); #ifdef IWM_DEBUG iwm_nic_error(sc); #endif ieee80211_restart_all(ic); counter_u64_add(sc->sc_ic.ic_oerrors, 1); return; } } callout_reset(&sc->sc_watchdog_to, hz, iwm_watchdog, sc); } static void iwm_parent(struct ieee80211com *ic) { struct iwm_softc *sc = ic->ic_softc; int startall = 0; IWM_LOCK(sc); if (ic->ic_nrunning > 0) { if (!(sc->sc_flags & IWM_FLAG_HW_INITED)) { iwm_init(sc); startall = 1; } } else if (sc->sc_flags & IWM_FLAG_HW_INITED) iwm_stop(sc); IWM_UNLOCK(sc); if (startall) ieee80211_start_all(ic); } /* * The interrupt side of things */ /* * error dumping routines are from iwlwifi/mvm/utils.c */ /* * Note: This structure is read from the device with IO accesses, * and the reading already does the endian conversion. As it is * read with uint32_t-sized accesses, any members with a different size * need to be ordered correctly though! */ struct iwm_error_event_table { uint32_t valid; /* (nonzero) valid, (0) log is empty */ uint32_t error_id; /* type of error */ uint32_t trm_hw_status0; /* TRM HW status */ uint32_t trm_hw_status1; /* TRM HW status */ uint32_t blink2; /* branch link */ uint32_t ilink1; /* interrupt link */ uint32_t ilink2; /* interrupt link */ uint32_t data1; /* error-specific data */ uint32_t data2; /* error-specific data */ uint32_t data3; /* error-specific data */ uint32_t bcon_time; /* beacon timer */ uint32_t tsf_low; /* network timestamp function timer */ uint32_t tsf_hi; /* network timestamp function timer */ uint32_t gp1; /* GP1 timer register */ uint32_t gp2; /* GP2 timer register */ uint32_t fw_rev_type; /* firmware revision type */ uint32_t major; /* uCode version major */ uint32_t minor; /* uCode version minor */ uint32_t hw_ver; /* HW Silicon version */ uint32_t brd_ver; /* HW board version */ uint32_t log_pc; /* log program counter */ uint32_t frame_ptr; /* frame pointer */ uint32_t stack_ptr; /* stack pointer */ uint32_t hcmd; /* last host command header */ uint32_t isr0; /* isr status register LMPM_NIC_ISR0: * rxtx_flag */ uint32_t isr1; /* isr status register LMPM_NIC_ISR1: * host_flag */ uint32_t isr2; /* isr status register LMPM_NIC_ISR2: * enc_flag */ uint32_t isr3; /* isr status register LMPM_NIC_ISR3: * time_flag */ uint32_t isr4; /* isr status register LMPM_NIC_ISR4: * wico interrupt */ uint32_t last_cmd_id; /* last HCMD id handled by the firmware */ uint32_t wait_event; /* wait event() caller address */ uint32_t l2p_control; /* L2pControlField */ uint32_t l2p_duration; /* L2pDurationField */ uint32_t l2p_mhvalid; /* L2pMhValidBits */ uint32_t l2p_addr_match; /* L2pAddrMatchStat */ uint32_t lmpm_pmg_sel; /* indicate which clocks are turned on * (LMPM_PMG_SEL) */ uint32_t u_timestamp; /* indicate when the date and time of the * compilation */ uint32_t flow_handler; /* FH read/write pointers, RX credit */ } __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; /* * UMAC error struct - relevant starting from family 8000 chip. * Note: This structure is read from the device with IO accesses, * and the reading already does the endian conversion. As it is * read with u32-sized accesses, any members with a different size * need to be ordered correctly though! */ struct iwm_umac_error_event_table { uint32_t valid; /* (nonzero) valid, (0) log is empty */ uint32_t error_id; /* type of error */ uint32_t blink1; /* branch link */ uint32_t blink2; /* branch link */ uint32_t ilink1; /* interrupt link */ uint32_t ilink2; /* interrupt link */ uint32_t data1; /* error-specific data */ uint32_t data2; /* error-specific data */ uint32_t data3; /* error-specific data */ uint32_t umac_major; uint32_t umac_minor; uint32_t frame_pointer; /* core register 27*/ uint32_t stack_pointer; /* core register 28 */ uint32_t cmd_header; /* latest host cmd sent to UMAC */ uint32_t nic_isr_pref; /* ISR status register */ } __packed; #define ERROR_START_OFFSET (1 * sizeof(uint32_t)) #define ERROR_ELEM_SIZE (7 * sizeof(uint32_t)) #ifdef IWM_DEBUG struct { const char *name; uint8_t num; } advanced_lookup[] = { { "NMI_INTERRUPT_WDG", 0x34 }, { "SYSASSERT", 0x35 }, { "UCODE_VERSION_MISMATCH", 0x37 }, { "BAD_COMMAND", 0x38 }, { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, { "FATAL_ERROR", 0x3D }, { "NMI_TRM_HW_ERR", 0x46 }, { "NMI_INTERRUPT_TRM", 0x4C }, { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, { "NMI_INTERRUPT_HOST", 0x66 }, { "NMI_INTERRUPT_ACTION_PT", 0x7C }, { "NMI_INTERRUPT_UNKNOWN", 0x84 }, { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, { "ADVANCED_SYSASSERT", 0 }, }; static const char * iwm_desc_lookup(uint32_t num) { int i; for (i = 0; i < nitems(advanced_lookup) - 1; i++) if (advanced_lookup[i].num == num) return advanced_lookup[i].name; /* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */ return advanced_lookup[i].name; } static void iwm_nic_umac_error(struct iwm_softc *sc) { struct iwm_umac_error_event_table table; uint32_t base; base = sc->sc_uc.uc_umac_error_event_table; if (base < 0x800000) { device_printf(sc->sc_dev, "Invalid error log pointer 0x%08x\n", base); return; } if (iwm_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t))) { device_printf(sc->sc_dev, "reading errlog failed\n"); return; } if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { device_printf(sc->sc_dev, "Start UMAC Error Log Dump:\n"); device_printf(sc->sc_dev, "Status: 0x%x, count: %d\n", sc->sc_flags, table.valid); } device_printf(sc->sc_dev, "0x%08X | %s\n", table.error_id, iwm_desc_lookup(table.error_id)); device_printf(sc->sc_dev, "0x%08X | umac branchlink1\n", table.blink1); device_printf(sc->sc_dev, "0x%08X | umac branchlink2\n", table.blink2); device_printf(sc->sc_dev, "0x%08X | umac interruptlink1\n", table.ilink1); device_printf(sc->sc_dev, "0x%08X | umac interruptlink2\n", table.ilink2); device_printf(sc->sc_dev, "0x%08X | umac data1\n", table.data1); device_printf(sc->sc_dev, "0x%08X | umac data2\n", table.data2); device_printf(sc->sc_dev, "0x%08X | umac data3\n", table.data3); device_printf(sc->sc_dev, "0x%08X | umac major\n", table.umac_major); device_printf(sc->sc_dev, "0x%08X | umac minor\n", table.umac_minor); device_printf(sc->sc_dev, "0x%08X | frame pointer\n", table.frame_pointer); device_printf(sc->sc_dev, "0x%08X | stack pointer\n", table.stack_pointer); device_printf(sc->sc_dev, "0x%08X | last host cmd\n", table.cmd_header); device_printf(sc->sc_dev, "0x%08X | isr status reg\n", table.nic_isr_pref); } /* * Support for dumping the error log seemed like a good idea ... * but it's mostly hex junk and the only sensible thing is the * hw/ucode revision (which we know anyway). Since it's here, * I'll just leave it in, just in case e.g. the Intel guys want to * help us decipher some "ADVANCED_SYSASSERT" later. */ static void iwm_nic_error(struct iwm_softc *sc) { struct iwm_error_event_table table; uint32_t base; device_printf(sc->sc_dev, "dumping device error log\n"); base = sc->sc_uc.uc_error_event_table; if (base < 0x800000) { device_printf(sc->sc_dev, "Invalid error log pointer 0x%08x\n", base); return; } if (iwm_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t))) { device_printf(sc->sc_dev, "reading errlog failed\n"); return; } if (!table.valid) { device_printf(sc->sc_dev, "errlog not found, skipping\n"); return; } if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { device_printf(sc->sc_dev, "Start Error Log Dump:\n"); device_printf(sc->sc_dev, "Status: 0x%x, count: %d\n", sc->sc_flags, table.valid); } device_printf(sc->sc_dev, "0x%08X | %-28s\n", table.error_id, iwm_desc_lookup(table.error_id)); device_printf(sc->sc_dev, "%08X | trm_hw_status0\n", table.trm_hw_status0); device_printf(sc->sc_dev, "%08X | trm_hw_status1\n", table.trm_hw_status1); device_printf(sc->sc_dev, "%08X | branchlink2\n", table.blink2); device_printf(sc->sc_dev, "%08X | interruptlink1\n", table.ilink1); device_printf(sc->sc_dev, "%08X | interruptlink2\n", table.ilink2); device_printf(sc->sc_dev, "%08X | data1\n", table.data1); device_printf(sc->sc_dev, "%08X | data2\n", table.data2); device_printf(sc->sc_dev, "%08X | data3\n", table.data3); device_printf(sc->sc_dev, "%08X | beacon time\n", table.bcon_time); device_printf(sc->sc_dev, "%08X | tsf low\n", table.tsf_low); device_printf(sc->sc_dev, "%08X | tsf hi\n", table.tsf_hi); device_printf(sc->sc_dev, "%08X | time gp1\n", table.gp1); device_printf(sc->sc_dev, "%08X | time gp2\n", table.gp2); device_printf(sc->sc_dev, "%08X | uCode revision type\n", table.fw_rev_type); device_printf(sc->sc_dev, "%08X | uCode version major\n", table.major); device_printf(sc->sc_dev, "%08X | uCode version minor\n", table.minor); device_printf(sc->sc_dev, "%08X | hw version\n", table.hw_ver); device_printf(sc->sc_dev, "%08X | board version\n", table.brd_ver); device_printf(sc->sc_dev, "%08X | hcmd\n", table.hcmd); device_printf(sc->sc_dev, "%08X | isr0\n", table.isr0); device_printf(sc->sc_dev, "%08X | isr1\n", table.isr1); device_printf(sc->sc_dev, "%08X | isr2\n", table.isr2); device_printf(sc->sc_dev, "%08X | isr3\n", table.isr3); device_printf(sc->sc_dev, "%08X | isr4\n", table.isr4); device_printf(sc->sc_dev, "%08X | last cmd Id\n", table.last_cmd_id); device_printf(sc->sc_dev, "%08X | wait_event\n", table.wait_event); device_printf(sc->sc_dev, "%08X | l2p_control\n", table.l2p_control); device_printf(sc->sc_dev, "%08X | l2p_duration\n", table.l2p_duration); device_printf(sc->sc_dev, "%08X | l2p_mhvalid\n", table.l2p_mhvalid); device_printf(sc->sc_dev, "%08X | l2p_addr_match\n", table.l2p_addr_match); device_printf(sc->sc_dev, "%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); device_printf(sc->sc_dev, "%08X | timestamp\n", table.u_timestamp); device_printf(sc->sc_dev, "%08X | flow_handler\n", table.flow_handler); if (sc->sc_uc.uc_umac_error_event_table) iwm_nic_umac_error(sc); } #endif #define ADVANCE_RXQ(sc) (sc->rxq.cur = (sc->rxq.cur + 1) % IWM_RX_RING_COUNT); /* * Process an IWM_CSR_INT_BIT_FH_RX or IWM_CSR_INT_BIT_SW_RX interrupt. * Basic structure from if_iwn */ static void iwm_notif_intr(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; uint16_t hw; bus_dmamap_sync(sc->rxq.stat_dma.tag, sc->rxq.stat_dma.map, BUS_DMASYNC_POSTREAD); hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff; /* * Process responses */ while (sc->rxq.cur != hw) { struct iwm_rx_ring *ring = &sc->rxq; struct iwm_rx_data *data = &ring->data[ring->cur]; struct iwm_rx_packet *pkt; struct iwm_cmd_response *cresp; int qid, idx, code; bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); pkt = mtod(data->m, struct iwm_rx_packet *); qid = pkt->hdr.qid & ~0x80; idx = pkt->hdr.idx; code = IWM_WIDE_ID(pkt->hdr.flags, pkt->hdr.code); IWM_DPRINTF(sc, IWM_DEBUG_INTR, "rx packet qid=%d idx=%d type=%x %d %d\n", pkt->hdr.qid & ~0x80, pkt->hdr.idx, code, ring->cur, hw); /* * randomly get these from the firmware, no idea why. * they at least seem harmless, so just ignore them for now */ if (__predict_false((pkt->hdr.code == 0 && qid == 0 && idx == 0) || pkt->len_n_flags == htole32(0x55550000))) { ADVANCE_RXQ(sc); continue; } switch (code) { case IWM_REPLY_RX_PHY_CMD: iwm_mvm_rx_rx_phy_cmd(sc, pkt, data); break; case IWM_REPLY_RX_MPDU_CMD: iwm_mvm_rx_rx_mpdu(sc, pkt, data); break; case IWM_TX_CMD: iwm_mvm_rx_tx_cmd(sc, pkt, data); break; case IWM_MISSED_BEACONS_NOTIFICATION: { struct iwm_missed_beacons_notif *resp; int missed; /* XXX look at mac_id to determine interface ID */ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); resp = (void *)pkt->data; missed = le32toh(resp->consec_missed_beacons); IWM_DPRINTF(sc, IWM_DEBUG_BEACON | IWM_DEBUG_STATE, "%s: MISSED_BEACON: mac_id=%d, " "consec_since_last_rx=%d, consec=%d, num_expect=%d " "num_rx=%d\n", __func__, le32toh(resp->mac_id), le32toh(resp->consec_missed_beacons_since_last_rx), le32toh(resp->consec_missed_beacons), le32toh(resp->num_expected_beacons), le32toh(resp->num_recvd_beacons)); /* Be paranoid */ if (vap == NULL) break; /* XXX no net80211 locking? */ if (vap->iv_state == IEEE80211_S_RUN && (ic->ic_flags & IEEE80211_F_SCAN) == 0) { if (missed > vap->iv_bmissthreshold) { /* XXX bad locking; turn into task */ IWM_UNLOCK(sc); ieee80211_beacon_miss(ic); IWM_LOCK(sc); } } break; } case IWM_MFUART_LOAD_NOTIFICATION: break; case IWM_MVM_ALIVE: { struct iwm_mvm_alive_resp_v1 *resp1; struct iwm_mvm_alive_resp_v2 *resp2; struct iwm_mvm_alive_resp_v3 *resp3; if (iwm_rx_packet_payload_len(pkt) == sizeof(*resp1)) { resp1 = (void *)pkt->data; sc->sc_uc.uc_error_event_table = le32toh(resp1->error_event_table_ptr); sc->sc_uc.uc_log_event_table = le32toh(resp1->log_event_table_ptr); sc->sched_base = le32toh(resp1->scd_base_ptr); if (resp1->status == IWM_ALIVE_STATUS_OK) sc->sc_uc.uc_ok = 1; else sc->sc_uc.uc_ok = 0; } if (iwm_rx_packet_payload_len(pkt) == sizeof(*resp2)) { resp2 = (void *)pkt->data; sc->sc_uc.uc_error_event_table = le32toh(resp2->error_event_table_ptr); sc->sc_uc.uc_log_event_table = le32toh(resp2->log_event_table_ptr); sc->sched_base = le32toh(resp2->scd_base_ptr); sc->sc_uc.uc_umac_error_event_table = le32toh(resp2->error_info_addr); if (resp2->status == IWM_ALIVE_STATUS_OK) sc->sc_uc.uc_ok = 1; else sc->sc_uc.uc_ok = 0; } if (iwm_rx_packet_payload_len(pkt) == sizeof(*resp3)) { resp3 = (void *)pkt->data; sc->sc_uc.uc_error_event_table = le32toh(resp3->error_event_table_ptr); sc->sc_uc.uc_log_event_table = le32toh(resp3->log_event_table_ptr); sc->sched_base = le32toh(resp3->scd_base_ptr); sc->sc_uc.uc_umac_error_event_table = le32toh(resp3->error_info_addr); if (resp3->status == IWM_ALIVE_STATUS_OK) sc->sc_uc.uc_ok = 1; else sc->sc_uc.uc_ok = 0; } sc->sc_uc.uc_intr = 1; wakeup(&sc->sc_uc); break; } case IWM_CALIB_RES_NOTIF_PHY_DB: { struct iwm_calib_res_notif_phy_db *phy_db_notif; phy_db_notif = (void *)pkt->data; - iwm_phy_db_set_section(sc, phy_db_notif); + iwm_phy_db_set_section(sc->sc_phy_db, phy_db_notif); break; } case IWM_STATISTICS_NOTIFICATION: { struct iwm_notif_statistics *stats; stats = (void *)pkt->data; memcpy(&sc->sc_stats, stats, sizeof(sc->sc_stats)); sc->sc_noise = iwm_get_noise(sc, &stats->rx.general); break; } case IWM_NVM_ACCESS_CMD: case IWM_MCC_UPDATE_CMD: if (sc->sc_wantresp == ((qid << 16) | idx)) { memcpy(sc->sc_cmd_resp, pkt, sizeof(sc->sc_cmd_resp)); } break; case IWM_MCC_CHUB_UPDATE_CMD: { struct iwm_mcc_chub_notif *notif; notif = (void *)pkt->data; sc->sc_fw_mcc[0] = (notif->mcc & 0xff00) >> 8; sc->sc_fw_mcc[1] = notif->mcc & 0xff; sc->sc_fw_mcc[2] = '\0'; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "fw source %d sent CC '%s'\n", notif->source_id, sc->sc_fw_mcc); break; } case IWM_DTS_MEASUREMENT_NOTIFICATION: break; case IWM_PHY_CONFIGURATION_CMD: case IWM_TX_ANT_CONFIGURATION_CMD: case IWM_ADD_STA: case IWM_MAC_CONTEXT_CMD: case IWM_REPLY_SF_CFG_CMD: case IWM_POWER_TABLE_CMD: case IWM_PHY_CONTEXT_CMD: case IWM_BINDING_CONTEXT_CMD: case IWM_TIME_EVENT_CMD: case IWM_WIDE_ID(IWM_ALWAYS_LONG_GROUP, IWM_SCAN_CFG_CMD): case IWM_WIDE_ID(IWM_ALWAYS_LONG_GROUP, IWM_SCAN_REQ_UMAC): case IWM_SCAN_OFFLOAD_REQUEST_CMD: case IWM_REPLY_BEACON_FILTERING_CMD: case IWM_MAC_PM_POWER_TABLE: case IWM_TIME_QUOTA_CMD: case IWM_REMOVE_STA: case IWM_TXPATH_FLUSH: case IWM_LQ_CMD: case IWM_BT_CONFIG: case IWM_REPLY_THERMAL_MNG_BACKOFF: cresp = (void *)pkt->data; if (sc->sc_wantresp == ((qid << 16) | idx)) { memcpy(sc->sc_cmd_resp, pkt, sizeof(*pkt)+sizeof(*cresp)); } break; /* ignore */ case 0x6c: /* IWM_PHY_DB_CMD, no idea why it's not in fw-api.h */ break; case IWM_INIT_COMPLETE_NOTIF: sc->sc_init_complete = 1; wakeup(&sc->sc_init_complete); break; case IWM_SCAN_OFFLOAD_COMPLETE: { struct iwm_periodic_scan_complete *notif; notif = (void *)pkt->data; break; } case IWM_SCAN_ITERATION_COMPLETE: { struct iwm_lmac_scan_complete_notif *notif; notif = (void *)pkt->data; ieee80211_runtask(&sc->sc_ic, &sc->sc_es_task); break; } case IWM_SCAN_COMPLETE_UMAC: { struct iwm_umac_scan_complete *notif; notif = (void *)pkt->data; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "UMAC scan complete, status=0x%x\n", notif->status); #if 0 /* XXX This would be a duplicate scan end call */ taskqueue_enqueue(sc->sc_tq, &sc->sc_es_task); #endif break; } case IWM_SCAN_ITERATION_COMPLETE_UMAC: { struct iwm_umac_scan_iter_complete_notif *notif; notif = (void *)pkt->data; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "UMAC scan iteration " "complete, status=0x%x, %d channels scanned\n", notif->status, notif->scanned_channels); ieee80211_runtask(&sc->sc_ic, &sc->sc_es_task); break; } case IWM_REPLY_ERROR: { struct iwm_error_resp *resp; resp = (void *)pkt->data; device_printf(sc->sc_dev, "firmware error 0x%x, cmd 0x%x\n", le32toh(resp->error_type), resp->cmd_id); break; } case IWM_TIME_EVENT_NOTIFICATION: { struct iwm_time_event_notif *notif; notif = (void *)pkt->data; IWM_DPRINTF(sc, IWM_DEBUG_INTR, "TE notif status = 0x%x action = 0x%x\n", notif->status, notif->action); break; } case IWM_MCAST_FILTER_CMD: break; case IWM_SCD_QUEUE_CFG: { struct iwm_scd_txq_cfg_rsp *rsp; rsp = (void *)pkt->data; IWM_DPRINTF(sc, IWM_DEBUG_CMD, "queue cfg token=0x%x sta_id=%d " "tid=%d scd_queue=%d\n", rsp->token, rsp->sta_id, rsp->tid, rsp->scd_queue); break; } default: device_printf(sc->sc_dev, "frame %d/%d %x UNHANDLED (this should " "not happen)\n", qid, idx, pkt->len_n_flags); break; } /* * Why test bit 0x80? The Linux driver: * * There is one exception: uCode sets bit 15 when it * originates the response/notification, i.e. when the * response/notification is not a direct response to a * command sent by the driver. For example, uCode issues * IWM_REPLY_RX when it sends a received frame to the driver; * it is not a direct response to any driver command. * * Ok, so since when is 7 == 15? Well, the Linux driver * uses a slightly different format for pkt->hdr, and "qid" * is actually the upper byte of a two-byte field. */ if (!(pkt->hdr.qid & (1 << 7))) { iwm_cmd_done(sc, pkt); } ADVANCE_RXQ(sc); } IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* * Tell the firmware what we have processed. * Seems like the hardware gets upset unless we align * the write by 8?? */ hw = (hw == 0) ? IWM_RX_RING_COUNT - 1 : hw - 1; IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, hw & ~7); } static void iwm_intr(void *arg) { struct iwm_softc *sc = arg; int handled = 0; int r1, r2, rv = 0; int isperiodic = 0; IWM_LOCK(sc); IWM_WRITE(sc, IWM_CSR_INT_MASK, 0); if (sc->sc_flags & IWM_FLAG_USE_ICT) { uint32_t *ict = sc->ict_dma.vaddr; int tmp; tmp = htole32(ict[sc->ict_cur]); if (!tmp) goto out_ena; /* * ok, there was something. keep plowing until we have all. */ r1 = r2 = 0; while (tmp) { r1 |= tmp; ict[sc->ict_cur] = 0; sc->ict_cur = (sc->ict_cur+1) % IWM_ICT_COUNT; tmp = htole32(ict[sc->ict_cur]); } /* this is where the fun begins. don't ask */ if (r1 == 0xffffffff) r1 = 0; /* i am not expected to understand this */ if (r1 & 0xc0000) r1 |= 0x8000; r1 = (0xff & r1) | ((0xff00 & r1) << 16); } else { r1 = IWM_READ(sc, IWM_CSR_INT); /* "hardware gone" (where, fishing?) */ if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) goto out; r2 = IWM_READ(sc, IWM_CSR_FH_INT_STATUS); } if (r1 == 0 && r2 == 0) { goto out_ena; } IWM_WRITE(sc, IWM_CSR_INT, r1 | ~sc->sc_intmask); /* ignored */ handled |= (r1 & (IWM_CSR_INT_BIT_ALIVE /*| IWM_CSR_INT_BIT_SCD*/)); if (r1 & IWM_CSR_INT_BIT_SW_ERR) { int i; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); #ifdef IWM_DEBUG iwm_nic_error(sc); #endif /* Dump driver status (TX and RX rings) while we're here. */ device_printf(sc->sc_dev, "driver status:\n"); for (i = 0; i < IWM_MVM_MAX_QUEUES; i++) { struct iwm_tx_ring *ring = &sc->txq[i]; device_printf(sc->sc_dev, " tx ring %2d: qid=%-2d cur=%-3d " "queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); } device_printf(sc->sc_dev, " rx ring: cur=%d\n", sc->rxq.cur); device_printf(sc->sc_dev, " 802.11 state %d\n", (vap == NULL) ? -1 : vap->iv_state); /* Don't stop the device; just do a VAP restart */ IWM_UNLOCK(sc); if (vap == NULL) { printf("%s: null vap\n", __func__); return; } device_printf(sc->sc_dev, "%s: controller panicked, iv_state = %d; " "restarting\n", __func__, vap->iv_state); /* XXX TODO: turn this into a callout/taskqueue */ ieee80211_restart_all(ic); return; } if (r1 & IWM_CSR_INT_BIT_HW_ERR) { handled |= IWM_CSR_INT_BIT_HW_ERR; device_printf(sc->sc_dev, "hardware error, stopping device\n"); iwm_stop(sc); rv = 1; goto out; } /* firmware chunk loaded */ if (r1 & IWM_CSR_INT_BIT_FH_TX) { IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_TX_MASK); handled |= IWM_CSR_INT_BIT_FH_TX; sc->sc_fw_chunk_done = 1; wakeup(&sc->sc_fw); } if (r1 & IWM_CSR_INT_BIT_RF_KILL) { handled |= IWM_CSR_INT_BIT_RF_KILL; if (iwm_check_rfkill(sc)) { device_printf(sc->sc_dev, "%s: rfkill switch, disabling interface\n", __func__); iwm_stop(sc); } } /* * The Linux driver uses periodic interrupts to avoid races. * We cargo-cult like it's going out of fashion. */ if (r1 & IWM_CSR_INT_BIT_RX_PERIODIC) { handled |= IWM_CSR_INT_BIT_RX_PERIODIC; IWM_WRITE(sc, IWM_CSR_INT, IWM_CSR_INT_BIT_RX_PERIODIC); if ((r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) == 0) IWM_WRITE_1(sc, IWM_CSR_INT_PERIODIC_REG, IWM_CSR_INT_PERIODIC_DIS); isperiodic = 1; } if ((r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) || isperiodic) { handled |= (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX); IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_RX_MASK); iwm_notif_intr(sc); /* enable periodic interrupt, see above */ if (r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX) && !isperiodic) IWM_WRITE_1(sc, IWM_CSR_INT_PERIODIC_REG, IWM_CSR_INT_PERIODIC_ENA); } if (__predict_false(r1 & ~handled)) IWM_DPRINTF(sc, IWM_DEBUG_INTR, "%s: unhandled interrupts: %x\n", __func__, r1); rv = 1; out_ena: iwm_restore_interrupts(sc); out: IWM_UNLOCK(sc); return; } /* * Autoconf glue-sniffing */ #define PCI_VENDOR_INTEL 0x8086 #define PCI_PRODUCT_INTEL_WL_3160_1 0x08b3 #define PCI_PRODUCT_INTEL_WL_3160_2 0x08b4 #define PCI_PRODUCT_INTEL_WL_3165_1 0x3165 #define PCI_PRODUCT_INTEL_WL_3165_2 0x3166 #define PCI_PRODUCT_INTEL_WL_7260_1 0x08b1 #define PCI_PRODUCT_INTEL_WL_7260_2 0x08b2 #define PCI_PRODUCT_INTEL_WL_7265_1 0x095a #define PCI_PRODUCT_INTEL_WL_7265_2 0x095b #define PCI_PRODUCT_INTEL_WL_8260_1 0x24f3 #define PCI_PRODUCT_INTEL_WL_8260_2 0x24f4 static const struct iwm_devices { uint16_t device; const char *name; } iwm_devices[] = { { PCI_PRODUCT_INTEL_WL_3160_1, "Intel Dual Band Wireless AC 3160" }, { PCI_PRODUCT_INTEL_WL_3160_2, "Intel Dual Band Wireless AC 3160" }, { PCI_PRODUCT_INTEL_WL_3165_1, "Intel Dual Band Wireless AC 3165" }, { PCI_PRODUCT_INTEL_WL_3165_2, "Intel Dual Band Wireless AC 3165" }, { PCI_PRODUCT_INTEL_WL_7260_1, "Intel Dual Band Wireless AC 7260" }, { PCI_PRODUCT_INTEL_WL_7260_2, "Intel Dual Band Wireless AC 7260" }, { PCI_PRODUCT_INTEL_WL_7265_1, "Intel Dual Band Wireless AC 7265" }, { PCI_PRODUCT_INTEL_WL_7265_2, "Intel Dual Band Wireless AC 7265" }, { PCI_PRODUCT_INTEL_WL_8260_1, "Intel Dual Band Wireless AC 8260" }, { PCI_PRODUCT_INTEL_WL_8260_2, "Intel Dual Band Wireless AC 8260" }, }; static int iwm_probe(device_t dev) { int i; for (i = 0; i < nitems(iwm_devices); i++) { if (pci_get_vendor(dev) == PCI_VENDOR_INTEL && pci_get_device(dev) == iwm_devices[i].device) { device_set_desc(dev, iwm_devices[i].name); return (BUS_PROBE_DEFAULT); } } return (ENXIO); } static int iwm_dev_check(device_t dev) { struct iwm_softc *sc; sc = device_get_softc(dev); - sc->sc_hw_rev = IWM_READ(sc, IWM_CSR_HW_REV); switch (pci_get_device(dev)) { case PCI_PRODUCT_INTEL_WL_3160_1: case PCI_PRODUCT_INTEL_WL_3160_2: - sc->sc_fwname = "iwm3160fw"; - sc->host_interrupt_operation_mode = 1; - sc->sc_device_family = IWM_DEVICE_FAMILY_7000; + sc->cfg = &iwm3160_cfg; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; return (0); case PCI_PRODUCT_INTEL_WL_3165_1: case PCI_PRODUCT_INTEL_WL_3165_2: - sc->sc_fwname = "iwm7265fw"; - sc->host_interrupt_operation_mode = 0; - sc->sc_device_family = IWM_DEVICE_FAMILY_7000; + sc->cfg = &iwm3165_cfg; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; return (0); case PCI_PRODUCT_INTEL_WL_7260_1: case PCI_PRODUCT_INTEL_WL_7260_2: - sc->sc_fwname = "iwm7260fw"; - sc->host_interrupt_operation_mode = 1; - sc->sc_device_family = IWM_DEVICE_FAMILY_7000; + sc->cfg = &iwm7260_cfg; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; return (0); case PCI_PRODUCT_INTEL_WL_7265_1: case PCI_PRODUCT_INTEL_WL_7265_2: - sc->sc_fwname = "iwm7265fw"; - sc->host_interrupt_operation_mode = 0; - sc->sc_device_family = IWM_DEVICE_FAMILY_7000; + sc->cfg = &iwm7265_cfg; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; return (0); case PCI_PRODUCT_INTEL_WL_8260_1: case PCI_PRODUCT_INTEL_WL_8260_2: - sc->sc_fwname = "iwm8000Cfw"; - sc->host_interrupt_operation_mode = 0; - sc->sc_device_family = IWM_DEVICE_FAMILY_8000; + sc->cfg = &iwm8260_cfg; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ_8000; return (0); default: device_printf(dev, "unknown adapter type\n"); return ENXIO; } } static int iwm_pci_attach(device_t dev) { struct iwm_softc *sc; int count, error, rid; uint16_t reg; sc = device_get_softc(dev); /* Clear device-specific "PCI retry timeout" register (41h). */ reg = pci_read_config(dev, 0x40, sizeof(reg)); pci_write_config(dev, 0x40, reg & ~0xff00, sizeof(reg)); /* Enable bus-mastering and hardware bug workaround. */ pci_enable_busmaster(dev); reg = pci_read_config(dev, PCIR_STATUS, sizeof(reg)); /* if !MSI */ if (reg & PCIM_STATUS_INTxSTATE) { reg &= ~PCIM_STATUS_INTxSTATE; } pci_write_config(dev, PCIR_STATUS, reg, sizeof(reg)); rid = PCIR_BAR(0); sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_mem == NULL) { device_printf(sc->sc_dev, "can't map mem space\n"); return (ENXIO); } sc->sc_st = rman_get_bustag(sc->sc_mem); sc->sc_sh = rman_get_bushandle(sc->sc_mem); /* Install interrupt handler. */ count = 1; rid = 0; if (pci_alloc_msi(dev, &count) == 0) rid = 1; sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE)); if (sc->sc_irq == NULL) { device_printf(dev, "can't map interrupt\n"); return (ENXIO); } error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, iwm_intr, sc, &sc->sc_ih); if (sc->sc_ih == NULL) { device_printf(dev, "can't establish interrupt"); return (ENXIO); } sc->sc_dmat = bus_get_dma_tag(sc->sc_dev); return (0); } static void iwm_pci_detach(device_t dev) { struct iwm_softc *sc = device_get_softc(dev); if (sc->sc_irq != NULL) { bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih); bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq), sc->sc_irq); pci_release_msi(dev); } if (sc->sc_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_mem), sc->sc_mem); } static int iwm_attach(device_t dev) { struct iwm_softc *sc = device_get_softc(dev); struct ieee80211com *ic = &sc->sc_ic; int error; int txq_i, i; sc->sc_dev = dev; + sc->sc_attached = 1; IWM_LOCK_INIT(sc); mbufq_init(&sc->sc_snd, ifqmaxlen); callout_init_mtx(&sc->sc_watchdog_to, &sc->sc_mtx, 0); callout_init_mtx(&sc->sc_led_blink_to, &sc->sc_mtx, 0); TASK_INIT(&sc->sc_es_task, 0, iwm_endscan_cb, sc); + /* Init phy db */ + sc->sc_phy_db = iwm_phy_db_init(sc); + if (!sc->sc_phy_db) { + device_printf(dev, "Cannot init phy_db\n"); + goto fail; + } + /* PCI attach */ error = iwm_pci_attach(dev); if (error != 0) goto fail; sc->sc_wantresp = -1; /* Check device type */ error = iwm_dev_check(dev); if (error != 0) goto fail; + sc->sc_hw_rev = IWM_READ(sc, IWM_CSR_HW_REV); /* - * We now start fiddling with the hardware - */ - /* * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have * changed, and now the revision step also includes bit 0-1 (no more * "dash" value). To keep hw_rev backwards compatible - we'll store it * in the old format. */ - if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) sc->sc_hw_rev = (sc->sc_hw_rev & 0xfff0) | (IWM_CSR_HW_REV_STEP(sc->sc_hw_rev << 2) << 2); if (iwm_prepare_card_hw(sc) != 0) { device_printf(dev, "could not initialize hardware\n"); goto fail; } - if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) { int ret; uint32_t hw_step; /* * In order to recognize C step the driver should read the * chip version id located at the AUX bus MISC address. */ IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE); DELAY(2); ret = iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (!ret) { device_printf(sc->sc_dev, "Failed to wake up the nic\n"); goto fail; } if (iwm_nic_lock(sc)) { hw_step = iwm_read_prph(sc, IWM_WFPM_CTRL_REG); hw_step |= IWM_ENABLE_WFPM; iwm_write_prph(sc, IWM_WFPM_CTRL_REG, hw_step); hw_step = iwm_read_prph(sc, IWM_AUX_MISC_REG); hw_step = (hw_step >> IWM_HW_STEP_LOCATION_BITS) & 0xF; if (hw_step == 0x3) sc->sc_hw_rev = (sc->sc_hw_rev & 0xFFFFFFF3) | (IWM_SILICON_C_STEP << 2); iwm_nic_unlock(sc); } else { device_printf(sc->sc_dev, "Failed to lock the nic\n"); goto fail; } } + /* special-case 7265D, it has the same PCI IDs. */ + if (sc->cfg == &iwm7265_cfg && + (sc->sc_hw_rev & IWM_CSR_HW_REV_TYPE_MSK) == IWM_CSR_HW_REV_TYPE_7265D) { + sc->cfg = &iwm7265d_cfg; + } + /* Allocate DMA memory for firmware transfers. */ if ((error = iwm_alloc_fwmem(sc)) != 0) { device_printf(dev, "could not allocate memory for firmware\n"); goto fail; } /* Allocate "Keep Warm" page. */ if ((error = iwm_alloc_kw(sc)) != 0) { device_printf(dev, "could not allocate keep warm page\n"); goto fail; } /* We use ICT interrupts */ if ((error = iwm_alloc_ict(sc)) != 0) { device_printf(dev, "could not allocate ICT table\n"); goto fail; } /* Allocate TX scheduler "rings". */ if ((error = iwm_alloc_sched(sc)) != 0) { device_printf(dev, "could not allocate TX scheduler rings\n"); goto fail; } /* Allocate TX rings */ for (txq_i = 0; txq_i < nitems(sc->txq); txq_i++) { if ((error = iwm_alloc_tx_ring(sc, &sc->txq[txq_i], txq_i)) != 0) { device_printf(dev, "could not allocate TX ring %d\n", txq_i); goto fail; } } /* Allocate RX ring. */ if ((error = iwm_alloc_rx_ring(sc, &sc->rxq)) != 0) { device_printf(dev, "could not allocate RX ring\n"); goto fail; } /* Clear pending interrupts. */ IWM_WRITE(sc, IWM_CSR_INT, 0xffffffff); ic->ic_softc = sc; ic->ic_name = device_get_nameunit(sc->sc_dev); ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ /* Set device capabilities. */ ic->ic_caps = IEEE80211_C_STA | IEEE80211_C_WPA | /* WPA/RSN */ IEEE80211_C_WME | IEEE80211_C_SHSLOT | /* short slot time supported */ IEEE80211_C_SHPREAMBLE /* short preamble supported */ // IEEE80211_C_BGSCAN /* capable of bg scanning */ ; /* Advertise full-offload scanning */ ic->ic_flags_ext = IEEE80211_FEXT_SCAN_OFFLOAD; for (i = 0; i < nitems(sc->sc_phyctxt); i++) { sc->sc_phyctxt[i].id = i; sc->sc_phyctxt[i].color = 0; sc->sc_phyctxt[i].ref = 0; sc->sc_phyctxt[i].channel = NULL; } /* Default noise floor */ sc->sc_noise = -96; /* Max RSSI */ sc->sc_max_rssi = IWM_MAX_DBM - IWM_MIN_DBM; sc->sc_preinit_hook.ich_func = iwm_preinit; sc->sc_preinit_hook.ich_arg = sc; if (config_intrhook_establish(&sc->sc_preinit_hook) != 0) { device_printf(dev, "config_intrhook_establish failed\n"); goto fail; } #ifdef IWM_DEBUG SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "debug", CTLFLAG_RW, &sc->sc_debug, 0, "control debugging"); #endif IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_TRACE, "<-%s\n", __func__); return 0; /* Free allocated memory if something failed during attachment. */ fail: iwm_detach_local(sc, 0); return ENXIO; } static int iwm_is_valid_ether_addr(uint8_t *addr) { char zero_addr[IEEE80211_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 }; if ((addr[0] & 1) || IEEE80211_ADDR_EQ(zero_addr, addr)) return (FALSE); return (TRUE); } static int iwm_update_edca(struct ieee80211com *ic) { struct iwm_softc *sc = ic->ic_softc; device_printf(sc->sc_dev, "%s: called\n", __func__); return (0); } static void iwm_preinit(void *arg) { struct iwm_softc *sc = arg; device_t dev = sc->sc_dev; struct ieee80211com *ic = &sc->sc_ic; int error; IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_TRACE, "->%s\n", __func__); IWM_LOCK(sc); if ((error = iwm_start_hw(sc)) != 0) { device_printf(dev, "could not initialize hardware\n"); IWM_UNLOCK(sc); goto fail; } error = iwm_run_init_mvm_ucode(sc, 1); iwm_stop_device(sc); if (error) { IWM_UNLOCK(sc); goto fail; } device_printf(dev, "hw rev 0x%x, fw ver %s, address %s\n", sc->sc_hw_rev & IWM_CSR_HW_REV_TYPE_MSK, - sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr)); + sc->sc_fwver, ether_sprintf(sc->nvm_data->hw_addr)); /* not all hardware can do 5GHz band */ - if (!sc->sc_nvm.sku_cap_band_52GHz_enable) + if (!sc->nvm_data->sku_cap_band_52GHz_enable) memset(&ic->ic_sup_rates[IEEE80211_MODE_11A], 0, sizeof(ic->ic_sup_rates[IEEE80211_MODE_11A])); IWM_UNLOCK(sc); iwm_init_channel_map(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, ic->ic_channels); /* * At this point we've committed - if we fail to do setup, * we now also have to tear down the net80211 state. */ ieee80211_ifattach(ic); ic->ic_vap_create = iwm_vap_create; ic->ic_vap_delete = iwm_vap_delete; ic->ic_raw_xmit = iwm_raw_xmit; ic->ic_node_alloc = iwm_node_alloc; ic->ic_scan_start = iwm_scan_start; ic->ic_scan_end = iwm_scan_end; ic->ic_update_mcast = iwm_update_mcast; ic->ic_getradiocaps = iwm_init_channel_map; ic->ic_set_channel = iwm_set_channel; ic->ic_scan_curchan = iwm_scan_curchan; ic->ic_scan_mindwell = iwm_scan_mindwell; ic->ic_wme.wme_update = iwm_update_edca; ic->ic_parent = iwm_parent; ic->ic_transmit = iwm_transmit; iwm_radiotap_attach(sc); if (bootverbose) ieee80211_announce(ic); IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_TRACE, "<-%s\n", __func__); config_intrhook_disestablish(&sc->sc_preinit_hook); return; fail: config_intrhook_disestablish(&sc->sc_preinit_hook); iwm_detach_local(sc, 0); } /* * Attach the interface to 802.11 radiotap. */ static void iwm_radiotap_attach(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_TRACE, "->%s begin\n", __func__); ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), IWM_TX_RADIOTAP_PRESENT, &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), IWM_RX_RADIOTAP_PRESENT); IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_TRACE, "->%s end\n", __func__); } static struct ieee80211vap * iwm_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { struct iwm_vap *ivp; struct ieee80211vap *vap; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; ivp = malloc(sizeof(struct iwm_vap), M_80211_VAP, M_WAITOK | M_ZERO); vap = &ivp->iv_vap; ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); vap->iv_bmissthreshold = 10; /* override default */ /* Override with driver methods. */ ivp->iv_newstate = vap->iv_newstate; vap->iv_newstate = iwm_newstate; ieee80211_ratectl_init(vap); /* Complete setup. */ ieee80211_vap_attach(vap, iwm_media_change, ieee80211_media_status, mac); ic->ic_opmode = opmode; return vap; } static void iwm_vap_delete(struct ieee80211vap *vap) { struct iwm_vap *ivp = IWM_VAP(vap); ieee80211_ratectl_deinit(vap); ieee80211_vap_detach(vap); free(ivp, M_80211_VAP); } static void iwm_scan_start(struct ieee80211com *ic) { struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwm_softc *sc = ic->ic_softc; int error; IWM_LOCK(sc); if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) error = iwm_mvm_umac_scan(sc); else error = iwm_mvm_lmac_scan(sc); if (error != 0) { device_printf(sc->sc_dev, "could not initiate 2 GHz scan\n"); IWM_UNLOCK(sc); ieee80211_cancel_scan(vap); } else { iwm_led_blink_start(sc); IWM_UNLOCK(sc); } } static void iwm_scan_end(struct ieee80211com *ic) { struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwm_softc *sc = ic->ic_softc; IWM_LOCK(sc); iwm_led_blink_stop(sc); if (vap->iv_state == IEEE80211_S_RUN) iwm_mvm_led_enable(sc); IWM_UNLOCK(sc); } static void iwm_update_mcast(struct ieee80211com *ic) { } static void iwm_set_channel(struct ieee80211com *ic) { } static void iwm_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) { } static void iwm_scan_mindwell(struct ieee80211_scan_state *ss) { return; } void iwm_init_task(void *arg1) { struct iwm_softc *sc = arg1; IWM_LOCK(sc); while (sc->sc_flags & IWM_FLAG_BUSY) msleep(&sc->sc_flags, &sc->sc_mtx, 0, "iwmpwr", 0); sc->sc_flags |= IWM_FLAG_BUSY; iwm_stop(sc); if (sc->sc_ic.ic_nrunning > 0) iwm_init(sc); sc->sc_flags &= ~IWM_FLAG_BUSY; wakeup(&sc->sc_flags); IWM_UNLOCK(sc); } static int iwm_resume(device_t dev) { struct iwm_softc *sc = device_get_softc(dev); int do_reinit = 0; uint16_t reg; /* Clear device-specific "PCI retry timeout" register (41h). */ reg = pci_read_config(dev, 0x40, sizeof(reg)); pci_write_config(dev, 0x40, reg & ~0xff00, sizeof(reg)); iwm_init_task(device_get_softc(dev)); IWM_LOCK(sc); if (sc->sc_flags & IWM_FLAG_SCANNING) { sc->sc_flags &= ~IWM_FLAG_SCANNING; do_reinit = 1; } IWM_UNLOCK(sc); if (do_reinit) ieee80211_resume_all(&sc->sc_ic); return 0; } static int iwm_suspend(device_t dev) { int do_stop = 0; struct iwm_softc *sc = device_get_softc(dev); do_stop = !! (sc->sc_ic.ic_nrunning > 0); ieee80211_suspend_all(&sc->sc_ic); if (do_stop) { IWM_LOCK(sc); iwm_stop(sc); sc->sc_flags |= IWM_FLAG_SCANNING; IWM_UNLOCK(sc); } return (0); } static int iwm_detach_local(struct iwm_softc *sc, int do_net80211) { struct iwm_fw_info *fw = &sc->sc_fw; device_t dev = sc->sc_dev; int i; + if (!sc->sc_attached) + return 0; + sc->sc_attached = 0; + if (do_net80211) ieee80211_draintask(&sc->sc_ic, &sc->sc_es_task); callout_drain(&sc->sc_led_blink_to); callout_drain(&sc->sc_watchdog_to); iwm_stop_device(sc); if (do_net80211) { ieee80211_ifdetach(&sc->sc_ic); } - iwm_phy_db_free(sc); + iwm_phy_db_free(sc->sc_phy_db); + sc->sc_phy_db = NULL; + + iwm_free_nvm_data(sc->nvm_data); /* Free descriptor rings */ iwm_free_rx_ring(sc, &sc->rxq); for (i = 0; i < nitems(sc->txq); i++) iwm_free_tx_ring(sc, &sc->txq[i]); /* Free firmware */ if (fw->fw_fp != NULL) iwm_fw_info_free(fw); /* Free scheduler */ iwm_dma_contig_free(&sc->sched_dma); iwm_dma_contig_free(&sc->ict_dma); iwm_dma_contig_free(&sc->kw_dma); iwm_dma_contig_free(&sc->fw_dma); /* Finished with the hardware - detach things */ iwm_pci_detach(dev); mbufq_drain(&sc->sc_snd); IWM_LOCK_DESTROY(sc); return (0); } static int iwm_detach(device_t dev) { struct iwm_softc *sc = device_get_softc(dev); return (iwm_detach_local(sc, 1)); } static device_method_t iwm_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, iwm_probe), DEVMETHOD(device_attach, iwm_attach), DEVMETHOD(device_detach, iwm_detach), DEVMETHOD(device_suspend, iwm_suspend), DEVMETHOD(device_resume, iwm_resume), DEVMETHOD_END }; static driver_t iwm_pci_driver = { "iwm", iwm_pci_methods, sizeof (struct iwm_softc) }; static devclass_t iwm_devclass; DRIVER_MODULE(iwm, pci, iwm_pci_driver, iwm_devclass, NULL, NULL); MODULE_DEPEND(iwm, firmware, 1, 1, 1); MODULE_DEPEND(iwm, pci, 1, 1, 1); MODULE_DEPEND(iwm, wlan, 1, 1, 1); Index: projects/ipsec/sys/dev/iwm/if_iwm_mac_ctxt.c =================================================================== --- projects/ipsec/sys/dev/iwm/if_iwm_mac_ctxt.c (revision 313312) +++ projects/ipsec/sys/dev/iwm/if_iwm_mac_ctxt.c (revision 313313) @@ -1,537 +1,542 @@ /* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * * Driver version we are currently based off of is * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT * OWNER 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. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * BEGIN mvm/mac-ctxt.c */ static void iwm_mvm_ack_rates(struct iwm_softc *sc, int is2ghz, int *cck_rates, int *ofdm_rates) { int lowest_present_ofdm = 100; int lowest_present_cck = 100; uint8_t cck = 0; uint8_t ofdm = 0; int i; if (is2ghz) { for (i = 0; i <= IWM_LAST_CCK_RATE; i++) { cck |= (1 << i); if (lowest_present_cck > i) lowest_present_cck = i; } } for (i = IWM_FIRST_OFDM_RATE; i <= IWM_LAST_NON_HT_RATE; i++) { int adj = i - IWM_FIRST_OFDM_RATE; ofdm |= (1 << adj); if (lowest_present_ofdm > i) lowest_present_ofdm = i; } /* * Now we've got the basic rates as bitmaps in the ofdm and cck * variables. This isn't sufficient though, as there might not * be all the right rates in the bitmap. E.g. if the only basic * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps * and 6 Mbps because the 802.11-2007 standard says in 9.6: * * [...] a STA responding to a received frame shall transmit * its Control Response frame [...] at the highest rate in the * BSSBasicRateSet parameter that is less than or equal to the * rate of the immediately previous frame in the frame exchange * sequence ([...]) and that is of the same modulation class * ([...]) as the received frame. If no rate contained in the * BSSBasicRateSet parameter meets these conditions, then the * control frame sent in response to a received frame shall be * transmitted at the highest mandatory rate of the PHY that is * less than or equal to the rate of the received frame, and * that is of the same modulation class as the received frame. * * As a consequence, we need to add all mandatory rates that are * lower than all of the basic rates to these bitmaps. */ if (IWM_RATE_24M_INDEX < lowest_present_ofdm) ofdm |= IWM_RATE_BIT_MSK(24) >> IWM_FIRST_OFDM_RATE; if (IWM_RATE_12M_INDEX < lowest_present_ofdm) ofdm |= IWM_RATE_BIT_MSK(12) >> IWM_FIRST_OFDM_RATE; /* 6M already there or needed so always add */ ofdm |= IWM_RATE_BIT_MSK(6) >> IWM_FIRST_OFDM_RATE; /* * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP. * Note, however: * - if no CCK rates are basic, it must be ERP since there must * be some basic rates at all, so they're OFDM => ERP PHY * (or we're in 5 GHz, and the cck bitmap will never be used) * - if 11M is a basic rate, it must be ERP as well, so add 5.5M * - if 5.5M is basic, 1M and 2M are mandatory * - if 2M is basic, 1M is mandatory * - if 1M is basic, that's the only valid ACK rate. * As a consequence, it's not as complicated as it sounds, just add * any lower rates to the ACK rate bitmap. */ if (IWM_RATE_11M_INDEX < lowest_present_cck) cck |= IWM_RATE_BIT_MSK(11) >> IWM_FIRST_CCK_RATE; if (IWM_RATE_5M_INDEX < lowest_present_cck) cck |= IWM_RATE_BIT_MSK(5) >> IWM_FIRST_CCK_RATE; if (IWM_RATE_2M_INDEX < lowest_present_cck) cck |= IWM_RATE_BIT_MSK(2) >> IWM_FIRST_CCK_RATE; /* 1M already there or needed so always add */ cck |= IWM_RATE_BIT_MSK(1) >> IWM_FIRST_CCK_RATE; *cck_rates = cck; *ofdm_rates = ofdm; } static void iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in, struct iwm_mac_ctx_cmd *cmd, uint32_t action) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_node *ni = vap->iv_bss; int cck_ack_rates, ofdm_ack_rates; int i; int is2ghz; /* * id is the MAC address ID - something to do with MAC filtering. * color - not sure. * * These are both functions of the vap, not of the node. * So, for now, hard-code both to 0 (default). */ cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_DEFAULT_MACID, IWM_DEFAULT_COLOR)); cmd->action = htole32(action); cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA); /* * The TSF ID is one of four TSF tracking resources in the firmware. * Read the iwlwifi/mvm code for more details. * * For now, just hard-code it to TSF tracking ID 0; we only support * a single STA mode VAP. * * It's per-vap, not per-node. */ cmd->tsf_id = htole32(IWM_DEFAULT_TSFID); IEEE80211_ADDR_COPY(cmd->node_addr, vap->iv_myaddr); /* * XXX should we error out if in_assoc is 1 and ni == NULL? */ #if 0 if (in->in_assoc) { IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid); } else { /* eth broadcast address */ IEEE80211_ADDR_COPY(cmd->bssid_addr, ieee80211broadcastaddr); } #else /* * XXX This workaround makes the firmware behave more correctly once * we are associated, regularly giving us statistics notifications, * as well as signaling missed beacons to us. * Since we only call iwm_mvm_mac_ctxt_add() and * iwm_mvm_mac_ctxt_changed() when already authenticating or * associating, ni->ni_bssid should always make sense here. */ IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid); #endif /* * Default to 2ghz if no node information is given. */ if (in) { is2ghz = !! IEEE80211_IS_CHAN_2GHZ(in->in_ni.ni_chan); } else { is2ghz = 1; } iwm_mvm_ack_rates(sc, is2ghz, &cck_ack_rates, &ofdm_ack_rates); cmd->cck_rates = htole32(cck_ack_rates); cmd->ofdm_rates = htole32(ofdm_ack_rates); cmd->cck_short_preamble = htole32((ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? IWM_MAC_FLG_SHORT_PREAMBLE : 0); cmd->short_slot = htole32((ic->ic_flags & IEEE80211_F_SHSLOT) ? IWM_MAC_FLG_SHORT_SLOT : 0); + /* + * XXX TODO: if we're doing QOS.. + * cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA) + */ + /* XXX TODO: set wme parameters; also handle getting updated wme parameters */ for (i = 0; i < IWM_AC_NUM+1; i++) { int txf = i; cmd->ac[txf].cw_min = htole16(0x0f); cmd->ac[txf].cw_max = htole16(0x3f); cmd->ac[txf].aifsn = 1; cmd->ac[txf].fifos_mask = (1 << txf); cmd->ac[txf].edca_txop = 0; } if (ic->ic_flags & IEEE80211_F_USEPROT) cmd->protection_flags |= htole32(IWM_MAC_PROT_FLG_TGG_PROTECT); cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP); } static int iwm_mvm_mac_ctxt_send_cmd(struct iwm_softc *sc, struct iwm_mac_ctx_cmd *cmd) { int ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_CONTEXT_CMD, IWM_CMD_SYNC, sizeof(*cmd), cmd); if (ret) device_printf(sc->sc_dev, "%s: Failed to send MAC context (action:%d): %d\n", __func__, le32toh(cmd->action), ret); return ret; } /* * Fill the specific data for mac context of type station or p2p client */ static void iwm_mvm_mac_ctxt_cmd_fill_sta(struct iwm_softc *sc, struct iwm_node *in, struct iwm_mac_data_sta *ctxt_sta, int force_assoc_off) { struct ieee80211_node *ni = &in->in_ni; unsigned dtim_period, dtim_count; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); /* will this work? */ dtim_period = vap->iv_dtim_period; dtim_count = vap->iv_dtim_count; IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_BEACON | IWM_DEBUG_CMD, "%s: force_assoc_off=%d\n", __func__, force_assoc_off); IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_BEACON | IWM_DEBUG_CMD, "DTIM: period=%d count=%d\n", dtim_period, dtim_count); IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_BEACON | IWM_DEBUG_CMD, "BEACON: tsf: %llu, ni_intval=%d\n", (unsigned long long) le64toh(ni->ni_tstamp.tsf), ni->ni_intval); /* We need the dtim_period to set the MAC as associated */ if (in->in_assoc && dtim_period && !force_assoc_off) { uint64_t tsf; uint32_t dtim_offs; /* * The DTIM count counts down, so when it is N that means N * more beacon intervals happen until the DTIM TBTT. Therefore * add this to the current time. If that ends up being in the * future, the firmware will handle it. * * Also note that the system_timestamp (which we get here as * "sync_device_ts") and TSF timestamp aren't at exactly the * same offset in the frame -- the TSF is at the first symbol * of the TSF, the system timestamp is at signal acquisition * time. This means there's an offset between them of at most * a few hundred microseconds (24 * 8 bits + PLCP time gives * 384us in the longest case), this is currently not relevant * as the firmware wakes up around 2ms before the TBTT. */ dtim_offs = dtim_count * ni->ni_intval; /* convert TU to usecs */ dtim_offs *= 1024; /* * net80211: TSF is in 802.11 order, so convert up to local * ordering before we manipulate things. */ tsf = le64toh(ni->ni_tstamp.tsf); ctxt_sta->dtim_tsf = htole64(tsf + dtim_offs); ctxt_sta->dtim_time = htole32(tsf + dtim_offs); IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_BEACON | IWM_DEBUG_CMD, "DTIM TBTT is 0x%llx/0x%x, offset %d\n", (long long)le64toh(ctxt_sta->dtim_tsf), le32toh(ctxt_sta->dtim_time), dtim_offs); ctxt_sta->is_assoc = htole32(1); } else { ctxt_sta->is_assoc = htole32(0); } IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_CMD | IWM_DEBUG_BEACON, "%s: ni_intval: %d, bi_reciprocal: %d, dtim_interval: %d, dtim_reciprocal: %d\n", __func__, ni->ni_intval, iwm_mvm_reciprocal(ni->ni_intval), ni->ni_intval * dtim_period, iwm_mvm_reciprocal(ni->ni_intval * dtim_period)); ctxt_sta->bi = htole32(ni->ni_intval); ctxt_sta->bi_reciprocal = htole32(iwm_mvm_reciprocal(ni->ni_intval)); ctxt_sta->dtim_interval = htole32(ni->ni_intval * dtim_period); ctxt_sta->dtim_reciprocal = htole32(iwm_mvm_reciprocal(ni->ni_intval * dtim_period)); /* 10 = CONN_MAX_LISTEN_INTERVAL */ ctxt_sta->listen_interval = htole32(10); IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_CMD | IWM_DEBUG_BEACON, "%s: associd=%d\n", __func__, IEEE80211_AID(ni->ni_associd)); ctxt_sta->assoc_id = htole32(IEEE80211_AID(ni->ni_associd)); } static int iwm_mvm_mac_ctxt_cmd_station(struct iwm_softc *sc, struct ieee80211vap *vap, uint32_t action) { struct ieee80211_node *ni = vap->iv_bss; struct iwm_node *in = IWM_NODE(ni); struct iwm_mac_ctx_cmd cmd; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "%s: called; action=%d\n", __func__, action); memset(&cmd, 0, sizeof(cmd)); /* Fill the common data for all mac context types */ iwm_mvm_mac_ctxt_cmd_common(sc, in, &cmd, action); /* Allow beacons to pass through as long as we are not associated,or we * do not have dtim period information */ if (!in->in_assoc || !vap->iv_dtim_period) cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_BEACON); else cmd.filter_flags &= ~htole32(IWM_MAC_FILTER_IN_BEACON); /* Fill the data specific for station mode */ iwm_mvm_mac_ctxt_cmd_fill_sta(sc, in, &cmd.sta, action == IWM_FW_CTXT_ACTION_ADD); return iwm_mvm_mac_ctxt_send_cmd(sc, &cmd); } static int iwm_mvm_mac_ctx_send(struct iwm_softc *sc, struct ieee80211vap *vap, uint32_t action) { return iwm_mvm_mac_ctxt_cmd_station(sc, vap, action); } int iwm_mvm_mac_ctxt_add(struct iwm_softc *sc, struct ieee80211vap *vap) { struct iwm_vap *iv = IWM_VAP(vap); int ret; if (iv->is_uploaded != 0) { device_printf(sc->sc_dev, "%s: called; uploaded != 0\n", __func__); return (EIO); } ret = iwm_mvm_mac_ctx_send(sc, vap, IWM_FW_CTXT_ACTION_ADD); if (ret) return (ret); iv->is_uploaded = 1; return (0); } int iwm_mvm_mac_ctxt_changed(struct iwm_softc *sc, struct ieee80211vap *vap) { struct iwm_vap *iv = IWM_VAP(vap); if (iv->is_uploaded == 0) { device_printf(sc->sc_dev, "%s: called; uploaded = 0\n", __func__); return (EIO); } return iwm_mvm_mac_ctx_send(sc, vap, IWM_FW_CTXT_ACTION_MODIFY); } #if 0 static int iwm_mvm_mac_ctxt_remove(struct iwm_softc *sc, struct iwm_node *in) { struct iwm_mac_ctx_cmd cmd; int ret; if (!in->in_uploaded) { device_printf(sc->sc_dev, "attempt to remove !uploaded node %p", in); return EIO; } memset(&cmd, 0, sizeof(cmd)); cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_DEFAULT_MACID, IWM_DEFAULT_COLOR)); cmd.action = htole32(IWM_FW_CTXT_ACTION_REMOVE); ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_CONTEXT_CMD, IWM_CMD_SYNC, sizeof(cmd), &cmd); if (ret) { device_printf(sc->sc_dev, "Failed to remove MAC context: %d\n", ret); return ret; } in->in_uploaded = 0; return 0; } #endif Index: projects/ipsec/sys/dev/iwm/if_iwm_pcie_trans.c =================================================================== --- projects/ipsec/sys/dev/iwm/if_iwm_pcie_trans.c (revision 313312) +++ projects/ipsec/sys/dev/iwm/if_iwm_pcie_trans.c (revision 313313) @@ -1,581 +1,581 @@ /* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * * Driver version we are currently based off of is * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT * OWNER 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. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This is a subset of what's in linux iwlwifi/pcie/trans.c. * The rest can be migrated out into here once they're no longer in * if_iwm.c. */ /* * basic device access */ uint32_t iwm_read_prph(struct iwm_softc *sc, uint32_t addr) { IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_RADDR, ((addr & 0x000fffff) | (3 << 24))); IWM_BARRIER_READ_WRITE(sc); return IWM_READ(sc, IWM_HBUS_TARG_PRPH_RDAT); } void iwm_write_prph(struct iwm_softc *sc, uint32_t addr, uint32_t val) { IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_WADDR, ((addr & 0x000fffff) | (3 << 24))); IWM_BARRIER_WRITE(sc); IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_WDAT, val); } #ifdef IWM_DEBUG /* iwlwifi: pcie/trans.c */ int iwm_read_mem(struct iwm_softc *sc, uint32_t addr, void *buf, int dwords) { int offs, ret = 0; uint32_t *vals = buf; if (iwm_nic_lock(sc)) { IWM_WRITE(sc, IWM_HBUS_TARG_MEM_RADDR, addr); for (offs = 0; offs < dwords; offs++) vals[offs] = IWM_READ(sc, IWM_HBUS_TARG_MEM_RDAT); iwm_nic_unlock(sc); } else { ret = EBUSY; } return ret; } #endif /* iwlwifi: pcie/trans.c */ int iwm_write_mem(struct iwm_softc *sc, uint32_t addr, const void *buf, int dwords) { int offs; const uint32_t *vals = buf; if (iwm_nic_lock(sc)) { IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WADDR, addr); /* WADDR auto-increments */ for (offs = 0; offs < dwords; offs++) { uint32_t val = vals ? vals[offs] : 0; IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WDAT, val); } iwm_nic_unlock(sc); } else { IWM_DPRINTF(sc, IWM_DEBUG_TRANS, "%s: write_mem failed\n", __func__); return EBUSY; } return 0; } int iwm_write_mem32(struct iwm_softc *sc, uint32_t addr, uint32_t val) { return iwm_write_mem(sc, addr, &val, 1); } int iwm_poll_bit(struct iwm_softc *sc, int reg, uint32_t bits, uint32_t mask, int timo) { for (;;) { if ((IWM_READ(sc, reg) & mask) == (bits & mask)) { return 1; } if (timo < 10) { return 0; } timo -= 10; DELAY(10); } } int iwm_nic_lock(struct iwm_softc *sc) { int rv = 0; IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) DELAY(2); if (iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP, 15000)) { rv = 1; } else { /* jolt */ IWM_DPRINTF(sc, IWM_DEBUG_RESET, "%s: resetting device via NMI\n", __func__); IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_FORCE_NMI); } return rv; } void iwm_nic_unlock(struct iwm_softc *sc) { IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } void iwm_set_bits_mask_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits, uint32_t mask) { uint32_t val; /* XXX: no error path? */ if (iwm_nic_lock(sc)) { val = iwm_read_prph(sc, reg) & mask; val |= bits; iwm_write_prph(sc, reg, val); iwm_nic_unlock(sc); } } void iwm_set_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits) { iwm_set_bits_mask_prph(sc, reg, bits, ~0); } void iwm_clear_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits) { iwm_set_bits_mask_prph(sc, reg, 0, ~bits); } /* * High-level hardware frobbing routines */ void iwm_enable_rfkill_int(struct iwm_softc *sc) { sc->sc_intmask = IWM_CSR_INT_BIT_RF_KILL; IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); } int iwm_check_rfkill(struct iwm_softc *sc) { uint32_t v; int rv; /* * "documentation" is not really helpful here: * 27: HW_RF_KILL_SW * Indicates state of (platform's) hardware RF-Kill switch * * But apparently when it's off, it's on ... */ v = IWM_READ(sc, IWM_CSR_GP_CNTRL); rv = (v & IWM_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) == 0; if (rv) { sc->sc_flags |= IWM_FLAG_RFKILL; } else { sc->sc_flags &= ~IWM_FLAG_RFKILL; } return rv; } #define IWM_HW_READY_TIMEOUT 50 int iwm_set_hw_ready(struct iwm_softc *sc) { int ready; IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); ready = iwm_poll_bit(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, IWM_HW_READY_TIMEOUT); if (ready) { IWM_SETBITS(sc, IWM_CSR_MBOX_SET_REG, IWM_CSR_MBOX_SET_REG_OS_ALIVE); } return ready; } #undef IWM_HW_READY_TIMEOUT int iwm_prepare_card_hw(struct iwm_softc *sc) { int rv = 0; int t = 0; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "->%s\n", __func__); if (iwm_set_hw_ready(sc)) goto out; DELAY(100); /* If HW is not ready, prepare the conditions to check again */ IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_PREPARE); do { if (iwm_set_hw_ready(sc)) goto out; DELAY(200); t += 200; } while (t < 150000); rv = ETIMEDOUT; out: IWM_DPRINTF(sc, IWM_DEBUG_RESET, "<-%s\n", __func__); return rv; } void iwm_apm_config(struct iwm_softc *sc) { uint16_t reg; reg = pci_read_config(sc->sc_dev, PCIER_LINK_CTL, sizeof(reg)); if (reg & PCIEM_LINK_CTL_ASPMC_L1) { /* Um the Linux driver prints "Disabling L0S for this one ... */ IWM_SETBITS(sc, IWM_CSR_GIO_REG, IWM_CSR_GIO_REG_VAL_L0S_ENABLED); } else { /* ... and "Enabling" here */ IWM_CLRBITS(sc, IWM_CSR_GIO_REG, IWM_CSR_GIO_REG_VAL_L0S_ENABLED); } } /* * Start up NIC's basic functionality after it has been reset * (e.g. after platform boot, or shutdown via iwm_pcie_apm_stop()) * NOTE: This does not load uCode nor start the embedded processor */ int iwm_apm_init(struct iwm_softc *sc) { int error = 0; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "iwm apm start\n"); /* Disable L0S exit timer (platform NMI Work/Around) */ - if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS, IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); } /* * Disable L0s without affecting L1; * don't wait for ICH L0s (ICH bug W/A) */ IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS, IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); /* Set FH wait threshold to maximum (HW error during stress W/A) */ IWM_SETBITS(sc, IWM_CSR_DBG_HPET_MEM_REG, IWM_CSR_DBG_HPET_MEM_REG_VAL); /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s */ IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); iwm_apm_config(sc); #if 0 /* not for 7k/8k */ /* Configure analog phase-lock-loop before activating to D0A */ if (trans->cfg->base_params->pll_cfg_val) IWM_SETBITS(trans, IWM_CSR_ANA_PLL_CFG, trans->cfg->base_params->pll_cfg_val); #endif /* * Set "initialization complete" bit to move adapter from * D0U* --> D0A* (powered-up active) state. */ IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* * Wait for clock stabilization; once stabilized, access to * device-internal resources is supported, e.g. iwm_write_prph() * and accesses to uCode SRAM. */ if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000)) { device_printf(sc->sc_dev, "timeout waiting for clock stabilization\n"); error = ETIMEDOUT; goto out; } - if (sc->host_interrupt_operation_mode) { + if (sc->cfg->host_interrupt_operation_mode) { /* * This is a bit of an abuse - This is needed for 7260 / 3160 * only check host_interrupt_operation_mode even if this is * not related to host_interrupt_operation_mode. * * Enable the oscillator to count wake up time for L1 exit. This * consumes slightly more power (100uA) - but allows to be sure * that we wake up from L1 on time. * * This looks weird: read twice the same register, discard the * value, set a bit, and yet again, read that same register * just to discard the value. But that's the way the hardware * seems to like it. */ iwm_read_prph(sc, IWM_OSC_CLK); iwm_read_prph(sc, IWM_OSC_CLK); iwm_set_bits_prph(sc, IWM_OSC_CLK, IWM_OSC_CLK_FORCE_CONTROL); iwm_read_prph(sc, IWM_OSC_CLK); iwm_read_prph(sc, IWM_OSC_CLK); } /* * Enable DMA clock and wait for it to stabilize. * * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits * do not disable clocks. This preserves any hardware bits already * set by default in "CLK_CTRL_REG" after reset. */ - if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) { iwm_write_prph(sc, IWM_APMG_CLK_EN_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT); DELAY(20); /* Disable L1-Active */ iwm_set_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG, IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS); /* Clear the interrupt in APMG if the NIC is in RFKILL */ iwm_write_prph(sc, IWM_APMG_RTC_INT_STT_REG, IWM_APMG_RTC_INT_STT_RFKILL); } out: if (error) device_printf(sc->sc_dev, "apm init error %d\n", error); return error; } /* iwlwifi/pcie/trans.c */ void iwm_apm_stop(struct iwm_softc *sc) { /* stop device's busmaster DMA activity */ IWM_SETBITS(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_STOP_MASTER); if (!iwm_poll_bit(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, 100)) device_printf(sc->sc_dev, "timeout waiting for master\n"); IWM_DPRINTF(sc, IWM_DEBUG_TRANS, "%s: iwm apm stop\n", __func__); } /* iwlwifi pcie/trans.c */ int iwm_start_hw(struct iwm_softc *sc) { int error; if ((error = iwm_prepare_card_hw(sc)) != 0) return error; /* Reset the entire device */ IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET); DELAY(10); if ((error = iwm_apm_init(sc)) != 0) return error; iwm_enable_rfkill_int(sc); iwm_check_rfkill(sc); return 0; } /* iwlwifi pcie/trans.c (always main power) */ void iwm_set_pwr(struct iwm_softc *sc) { iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG, IWM_APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~IWM_APMG_PS_CTRL_MSK_PWR_SRC); } /* iwlwifi pcie/rx.c */ int iwm_pcie_rx_stop(struct iwm_softc *sc) { IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); return (iwm_poll_bit(sc, IWM_FH_MEM_RSSR_RX_STATUS_REG, IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000)); } Index: projects/ipsec/sys/dev/iwm/if_iwm_phy_db.c =================================================================== --- projects/ipsec/sys/dev/iwm/if_iwm_phy_db.c (revision 313312) +++ projects/ipsec/sys/dev/iwm/if_iwm_phy_db.c (revision 313313) @@ -1,483 +1,609 @@ /* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * * Driver version we are currently based off of is * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT * OWNER 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. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include -#include -#include -#include -#include +#include "if_iwmreg.h" +#include "if_iwmvar.h" +#include "if_iwm_debug.h" +#include "if_iwm_util.h" +#include "if_iwm_phy_db.h" +#define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ + +struct iwm_phy_db_entry { + uint16_t size; + uint8_t *data; +}; + +/** + * struct iwm_phy_db - stores phy configuration and calibration data. + * + * @cfg: phy configuration. + * @calib_nch: non channel specific calibration data. + * @calib_ch: channel specific calibration data. + * @n_group_papd: number of entries in papd channel group. + * @calib_ch_group_papd: calibration data related to papd channel group. + * @n_group_txp: number of entries in tx power channel group. + * @calib_ch_group_txp: calibration data related to tx power chanel group. + */ +struct iwm_phy_db { + struct iwm_phy_db_entry cfg; + struct iwm_phy_db_entry calib_nch; + int n_group_papd; + struct iwm_phy_db_entry *calib_ch_group_papd; + int n_group_txp; + struct iwm_phy_db_entry *calib_ch_group_txp; + + struct iwm_softc *sc; +}; + +enum iwm_phy_db_section_type { + IWM_PHY_DB_CFG = 1, + IWM_PHY_DB_CALIB_NCH, + IWM_PHY_DB_UNUSED, + IWM_PHY_DB_CALIB_CHG_PAPD, + IWM_PHY_DB_CALIB_CHG_TXP, + IWM_PHY_DB_MAX +}; + +#define PHY_DB_CMD 0x6c /* TEMP API - The actual is 0x8c */ + /* - * BEGIN iwl-phy-db.c + * phy db - configure operational ucode */ +struct iwm_phy_db_cmd { + uint16_t type; + uint16_t length; + uint8_t data[]; +} __packed; + +/* for parsing of tx power channel group data that comes from the firmware*/ +struct iwm_phy_db_chg_txp { + uint32_t space; + uint16_t max_channel_idx; +} __packed; + /* + * phy db - Receive phy db chunk after calibrations + */ +struct iwm_calib_res_notif_phy_db { + uint16_t type; + uint16_t length; + uint8_t data[]; +} __packed; + +struct iwm_phy_db * +iwm_phy_db_init(struct iwm_softc *sc) +{ + struct iwm_phy_db *phy_db = malloc(sizeof(struct iwm_phy_db), + M_DEVBUF, M_NOWAIT | M_ZERO); + + if (!phy_db) + return phy_db; + + phy_db->sc = sc; + + phy_db->n_group_txp = -1; + phy_db->n_group_papd = -1; + + /* TODO: add default values of the phy db. */ + return phy_db; +} + +/* * get phy db section: returns a pointer to a phy db section specified by * type and channel group id. */ static struct iwm_phy_db_entry * -iwm_phy_db_get_section(struct iwm_softc *sc, - enum iwm_phy_db_section_type type, uint16_t chg_id) +iwm_phy_db_get_section(struct iwm_phy_db *phy_db, + enum iwm_phy_db_section_type type, + uint16_t chg_id) { - struct iwm_phy_db *phy_db = &sc->sc_phy_db; - - if (type >= IWM_PHY_DB_MAX) + if (!phy_db || type >= IWM_PHY_DB_MAX) return NULL; switch (type) { case IWM_PHY_DB_CFG: return &phy_db->cfg; case IWM_PHY_DB_CALIB_NCH: return &phy_db->calib_nch; case IWM_PHY_DB_CALIB_CHG_PAPD: - if (chg_id >= IWM_NUM_PAPD_CH_GROUPS) + if (chg_id >= phy_db->n_group_papd) return NULL; return &phy_db->calib_ch_group_papd[chg_id]; case IWM_PHY_DB_CALIB_CHG_TXP: - if (chg_id >= IWM_NUM_TXP_CH_GROUPS) + if (chg_id >= phy_db->n_group_txp) return NULL; return &phy_db->calib_ch_group_txp[chg_id]; default: return NULL; } return NULL; } +static void +iwm_phy_db_free_section(struct iwm_phy_db *phy_db, + enum iwm_phy_db_section_type type, uint16_t chg_id) +{ + struct iwm_phy_db_entry *entry = + iwm_phy_db_get_section(phy_db, type, chg_id); + if (!entry) + return; + + if (entry->data != NULL) + free(entry->data, M_DEVBUF); + entry->data = NULL; + entry->size = 0; +} + +void +iwm_phy_db_free(struct iwm_phy_db *phy_db) +{ + int i; + + if (!phy_db) + return; + + iwm_phy_db_free_section(phy_db, IWM_PHY_DB_CFG, 0); + iwm_phy_db_free_section(phy_db, IWM_PHY_DB_CALIB_NCH, 0); + + for (i = 0; i < phy_db->n_group_papd; i++) + iwm_phy_db_free_section(phy_db, IWM_PHY_DB_CALIB_CHG_PAPD, i); + if (phy_db->calib_ch_group_papd != NULL) + free(phy_db->calib_ch_group_papd, M_DEVBUF); + + for (i = 0; i < phy_db->n_group_txp; i++) + iwm_phy_db_free_section(phy_db, IWM_PHY_DB_CALIB_CHG_TXP, i); + if (phy_db->calib_ch_group_txp != NULL) + free(phy_db->calib_ch_group_txp, M_DEVBUF); + + free(phy_db, M_DEVBUF); +} + int -iwm_phy_db_set_section(struct iwm_softc *sc, - struct iwm_calib_res_notif_phy_db *phy_db_notif) +iwm_phy_db_set_section(struct iwm_phy_db *phy_db, + struct iwm_calib_res_notif_phy_db *phy_db_notif) { enum iwm_phy_db_section_type type = le16toh(phy_db_notif->type); - uint16_t size = le16toh(phy_db_notif->length); - struct iwm_phy_db_entry *entry; - uint16_t chg_id = 0; + uint16_t size = le16toh(phy_db_notif->length); + struct iwm_phy_db_entry *entry; + uint16_t chg_id = 0; - if (type == IWM_PHY_DB_CALIB_CHG_PAPD || - type == IWM_PHY_DB_CALIB_CHG_TXP) + if (!phy_db) + return EINVAL; + + if (type == IWM_PHY_DB_CALIB_CHG_PAPD) { chg_id = le16toh(*(uint16_t *)phy_db_notif->data); + if (phy_db && !phy_db->calib_ch_group_papd) { + /* + * Firmware sends the largest index first, so we can use + * it to know how much we should allocate. + */ + phy_db->calib_ch_group_papd = malloc( + (chg_id + 1) * sizeof(struct iwm_phy_db_entry), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (!phy_db->calib_ch_group_papd) + return ENOMEM; + phy_db->n_group_papd = chg_id + 1; + } + } else if (type == IWM_PHY_DB_CALIB_CHG_TXP) { + chg_id = le16toh(*(uint16_t *)phy_db_notif->data); + if (phy_db && !phy_db->calib_ch_group_txp) { + /* + * Firmware sends the largest index first, so we can use + * it to know how much we should allocate. + */ + phy_db->calib_ch_group_txp = malloc( + (chg_id + 1) * sizeof(struct iwm_phy_db_entry), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (!phy_db->calib_ch_group_txp) + return ENOMEM; + phy_db->n_group_txp = chg_id + 1; + } + } - entry = iwm_phy_db_get_section(sc, type, chg_id); + entry = iwm_phy_db_get_section(phy_db, type, chg_id); if (!entry) return EINVAL; - if (entry->data) + if (entry->data != NULL) free(entry->data, M_DEVBUF); entry->data = malloc(size, M_DEVBUF, M_NOWAIT); if (!entry->data) { entry->size = 0; return ENOMEM; } memcpy(entry->data, phy_db_notif->data, size); + entry->size = size; - IWM_DPRINTF(sc, IWM_DEBUG_RESET, - "%s(%d): [PHYDB]SET: Type %d , Size: %d, data: %p\n", - __func__, __LINE__, type, size, entry->data); + IWM_DPRINTF(phy_db->sc, IWM_DEBUG_RESET, + "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", + __func__, __LINE__, type, size); return 0; } static int -iwm_is_valid_channel(uint16_t ch_id) +is_valid_channel(uint16_t ch_id) { if (ch_id <= 14 || (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) return 1; return 0; } static uint8_t -iwm_ch_id_to_ch_index(uint16_t ch_id) +ch_id_to_ch_index(uint16_t ch_id) { - if (!iwm_is_valid_channel(ch_id)) - return 0xff; + if (!is_valid_channel(ch_id)) + return 0xff; if (ch_id <= 14) return ch_id - 1; if (ch_id <= 64) return (ch_id + 20) / 4; if (ch_id <= 140) return (ch_id - 12) / 4; return (ch_id - 13) / 4; } static uint16_t -iwm_channel_id_to_papd(uint16_t ch_id) +channel_id_to_papd(uint16_t ch_id) { - if (!iwm_is_valid_channel(ch_id)) + if (!is_valid_channel(ch_id)) return 0xff; if (1 <= ch_id && ch_id <= 14) return 0; if (36 <= ch_id && ch_id <= 64) return 1; if (100 <= ch_id && ch_id <= 140) return 2; return 3; } static uint16_t -iwm_channel_id_to_txp(struct iwm_softc *sc, uint16_t ch_id) +channel_id_to_txp(struct iwm_phy_db *phy_db, uint16_t ch_id) { - struct iwm_phy_db *phy_db = &sc->sc_phy_db; struct iwm_phy_db_chg_txp *txp_chg; int i; - uint8_t ch_index = iwm_ch_id_to_ch_index(ch_id); - + uint8_t ch_index = ch_id_to_ch_index(ch_id); if (ch_index == 0xff) return 0xff; - for (i = 0; i < IWM_NUM_TXP_CH_GROUPS; i++) { + for (i = 0; i < phy_db->n_group_txp; i++) { txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; if (!txp_chg) return 0xff; /* * Looking for the first channel group that its max channel is * higher then wanted channel. */ if (le16toh(txp_chg->max_channel_idx) >= ch_index) return i; } return 0xff; } static int -iwm_phy_db_get_section_data(struct iwm_softc *sc, - uint32_t type, uint8_t **data, uint16_t *size, uint16_t ch_id) +iwm_phy_db_get_section_data(struct iwm_phy_db *phy_db, + uint32_t type, uint8_t **data, uint16_t *size, + uint16_t ch_id) { struct iwm_phy_db_entry *entry; uint16_t ch_group_id = 0; - IWM_DPRINTF(sc, IWM_DEBUG_RESET, "->%s\n", __func__); + if (!phy_db) + return EINVAL; + /* find wanted channel group */ if (type == IWM_PHY_DB_CALIB_CHG_PAPD) - ch_group_id = iwm_channel_id_to_papd(ch_id); + ch_group_id = channel_id_to_papd(ch_id); else if (type == IWM_PHY_DB_CALIB_CHG_TXP) - ch_group_id = iwm_channel_id_to_txp(sc, ch_id); + ch_group_id = channel_id_to_txp(phy_db, ch_id); - entry = iwm_phy_db_get_section(sc, type, ch_group_id); + entry = iwm_phy_db_get_section(phy_db, type, ch_group_id); if (!entry) return EINVAL; *data = entry->data; *size = entry->size; - IWM_DPRINTF(sc, IWM_DEBUG_RESET, - "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", - __func__, __LINE__, type, *size); + IWM_DPRINTF(phy_db->sc, IWM_DEBUG_RESET, + "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", + __func__, __LINE__, type, *size); return 0; } static int -iwm_send_phy_db_cmd(struct iwm_softc *sc, uint16_t type, - uint16_t length, void *data) +iwm_send_phy_db_cmd(struct iwm_phy_db *phy_db, uint16_t type, + uint16_t length, void *data) { struct iwm_phy_db_cmd phy_db_cmd; struct iwm_host_cmd cmd = { - .id = IWM_PHY_DB_CMD, - .flags = IWM_CMD_SYNC, + .id = PHY_DB_CMD, }; - IWM_DPRINTF(sc, IWM_DEBUG_CMD, - "Sending PHY-DB hcmd of type %d, of length %d\n", - type, length); + IWM_DPRINTF(phy_db->sc, IWM_DEBUG_RESET, + "Sending PHY-DB hcmd of type %d, of length %d\n", + type, length); /* Set phy db cmd variables */ - phy_db_cmd.type = le16toh(type); - phy_db_cmd.length = le16toh(length); + phy_db_cmd.type = htole16(type); + phy_db_cmd.length = htole16(length); /* Set hcmd variables */ cmd.data[0] = &phy_db_cmd; cmd.len[0] = sizeof(struct iwm_phy_db_cmd); cmd.data[1] = data; cmd.len[1] = length; +#ifdef notyet + cmd.dataflags[1] = IWM_HCMD_DFL_NOCOPY; +#endif - return iwm_send_cmd(sc, &cmd); + return iwm_send_cmd(phy_db->sc, &cmd); } static int -iwm_phy_db_send_all_channel_groups(struct iwm_softc *sc, - enum iwm_phy_db_section_type type, uint8_t max_ch_groups) +iwm_phy_db_send_all_channel_groups(struct iwm_phy_db *phy_db, + enum iwm_phy_db_section_type type, + uint8_t max_ch_groups) { uint16_t i; int err; struct iwm_phy_db_entry *entry; - /* Send all the channel-specific groups to operational fw */ + /* Send all the channel specific groups to operational fw */ for (i = 0; i < max_ch_groups; i++) { - entry = iwm_phy_db_get_section(sc, type, i); + entry = iwm_phy_db_get_section(phy_db, + type, + i); if (!entry) return EINVAL; if (!entry->size) continue; /* Send the requested PHY DB section */ - err = iwm_send_phy_db_cmd(sc, type, entry->size, entry->data); + err = iwm_send_phy_db_cmd(phy_db, + type, + entry->size, + entry->data); if (err) { - IWM_DPRINTF(sc, IWM_DEBUG_CMD, - "%s: Can't SEND phy_db section %d (%d), " - "err %d\n", __func__, type, i, err); + device_printf(phy_db->sc->sc_dev, + "Can't SEND phy_db section %d (%d), err %d\n", + type, i, err); return err; } - DELAY(1000); - IWM_DPRINTF(sc, IWM_DEBUG_CMD, + IWM_DPRINTF(phy_db->sc, IWM_DEBUG_CMD, "Sent PHY_DB HCMD, type = %d num = %d\n", type, i); } return 0; } int -iwm_send_phy_db_data(struct iwm_softc *sc) +iwm_send_phy_db_data(struct iwm_phy_db *phy_db) { uint8_t *data = NULL; uint16_t size = 0; int err; - IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, + IWM_DPRINTF(phy_db->sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, "%s: Sending phy db data and configuration to runtime image\n", __func__); /* Send PHY DB CFG section */ - err = iwm_phy_db_get_section_data(sc, IWM_PHY_DB_CFG, &data, &size, 0); + err = iwm_phy_db_get_section_data(phy_db, IWM_PHY_DB_CFG, + &data, &size, 0); if (err) { - IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, + device_printf(phy_db->sc->sc_dev, "%s: Cannot get Phy DB cfg section, %d\n", __func__, err); return err; } - err = iwm_send_phy_db_cmd(sc, IWM_PHY_DB_CFG, size, data); + err = iwm_send_phy_db_cmd(phy_db, IWM_PHY_DB_CFG, size, data); if (err) { - IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, + device_printf(phy_db->sc->sc_dev, "%s: Cannot send HCMD of Phy DB cfg section, %d\n", __func__, err); return err; } - err = iwm_phy_db_get_section_data(sc, IWM_PHY_DB_CALIB_NCH, + err = iwm_phy_db_get_section_data(phy_db, IWM_PHY_DB_CALIB_NCH, &data, &size, 0); if (err) { - IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, + device_printf(phy_db->sc->sc_dev, "%s: Cannot get Phy DB non specific channel section, " "%d\n", __func__, err); return err; } - err = iwm_send_phy_db_cmd(sc, IWM_PHY_DB_CALIB_NCH, size, data); + err = iwm_send_phy_db_cmd(phy_db, IWM_PHY_DB_CALIB_NCH, size, data); if (err) { - IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, + device_printf(phy_db->sc->sc_dev, "%s: Cannot send HCMD of Phy DB non specific channel " "sect, %d\n", __func__, err); return err; } /* Send all the TXP channel specific data */ - err = iwm_phy_db_send_all_channel_groups(sc, - IWM_PHY_DB_CALIB_CHG_PAPD, IWM_NUM_PAPD_CH_GROUPS); + err = iwm_phy_db_send_all_channel_groups(phy_db, + IWM_PHY_DB_CALIB_CHG_PAPD, phy_db->n_group_papd); if (err) { - IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, + device_printf(phy_db->sc->sc_dev, "%s: Cannot send channel specific PAPD groups, %d\n", __func__, err); return err; } /* Send all the TXP channel specific data */ - err = iwm_phy_db_send_all_channel_groups(sc, - IWM_PHY_DB_CALIB_CHG_TXP, IWM_NUM_TXP_CH_GROUPS); + err = iwm_phy_db_send_all_channel_groups(phy_db, + IWM_PHY_DB_CALIB_CHG_TXP, phy_db->n_group_txp); if (err) { - IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, + device_printf(phy_db->sc->sc_dev, "%s: Cannot send channel specific TX power groups, " "%d\n", __func__, err); return err; } - IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, + IWM_DPRINTF(phy_db->sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, "%s: Finished sending phy db non channel data\n", __func__); return 0; -} - -static void -iwm_phy_db_free_section(struct iwm_softc *sc, - enum iwm_phy_db_section_type type, uint16_t chg_id) -{ - struct iwm_phy_db_entry *entry = - iwm_phy_db_get_section(sc, type, chg_id); - if (!entry) - return; - - if (entry->data != NULL) - free(entry->data, M_DEVBUF); - entry->data = NULL; - entry->size = 0; -} - -void -iwm_phy_db_free(struct iwm_softc *sc) -{ - int i; - - iwm_phy_db_free_section(sc, IWM_PHY_DB_CFG, 0); - iwm_phy_db_free_section(sc, IWM_PHY_DB_CALIB_NCH, 0); - - for (i = 0; i < IWM_NUM_PAPD_CH_GROUPS; i++) - iwm_phy_db_free_section(sc, IWM_PHY_DB_CALIB_CHG_PAPD, i); - - for (i = 0; i < IWM_NUM_TXP_CH_GROUPS; i++) - iwm_phy_db_free_section(sc, IWM_PHY_DB_CALIB_CHG_TXP, i); } Index: projects/ipsec/sys/dev/iwm/if_iwm_phy_db.h =================================================================== --- projects/ipsec/sys/dev/iwm/if_iwm_phy_db.h (revision 313312) +++ projects/ipsec/sys/dev/iwm/if_iwm_phy_db.h (revision 313313) @@ -1,113 +1,117 @@ /* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */ /* $FreeBSD$ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * * Driver version we are currently based off of is * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT * OWNER 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. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __IF_IWM_PHY_DB_H__ #define __IF_IWM_PHY_DB_H__ -extern int iwm_phy_db_set_section(struct iwm_softc *sc, +struct iwm_calib_res_notif_phy_db; + +extern struct iwm_phy_db *iwm_phy_db_init(struct iwm_softc *sc); +extern void iwm_phy_db_free(struct iwm_phy_db *phy_db); +extern int iwm_phy_db_set_section(struct iwm_phy_db *phy_db, struct iwm_calib_res_notif_phy_db *phy_db_notif); -extern int iwm_send_phy_db_data(struct iwm_softc *sc); -extern void iwm_phy_db_free(struct iwm_softc *sc); +extern int iwm_send_phy_db_data(struct iwm_phy_db *phy_db); + #endif /* __IF_IWM_PHY_DB_H__ */ Index: projects/ipsec/sys/dev/iwm/if_iwm_scan.c =================================================================== --- projects/ipsec/sys/dev/iwm/if_iwm_scan.c (revision 313312) +++ projects/ipsec/sys/dev/iwm/if_iwm_scan.c (revision 313313) @@ -1,739 +1,739 @@ /* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * * Driver version we are currently based off of is * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT * OWNER 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. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * BEGIN mvm/scan.c */ #define IWM_PLCP_QUIET_THRESH 1 #define IWM_ACTIVE_QUIET_TIME 10 #define LONG_OUT_TIME_PERIOD (600 * IEEE80211_DUR_TU) #define SHORT_OUT_TIME_PERIOD (200 * IEEE80211_DUR_TU) #define SUSPEND_TIME_PERIOD (100 * IEEE80211_DUR_TU) static uint16_t iwm_mvm_scan_rx_chain(struct iwm_softc *sc) { uint16_t rx_chain; uint8_t rx_ant; rx_ant = iwm_fw_valid_rx_ant(sc); rx_chain = rx_ant << IWM_PHY_RX_CHAIN_VALID_POS; rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS; return htole16(rx_chain); } #if 0 static uint32_t iwm_mvm_scan_max_out_time(struct iwm_softc *sc, uint32_t flags, int is_assoc) { if (!is_assoc) return 0; if (flags & 0x1) return htole32(SHORT_OUT_TIME_PERIOD); return htole32(LONG_OUT_TIME_PERIOD); } static uint32_t iwm_mvm_scan_suspend_time(struct iwm_softc *sc, int is_assoc) { if (!is_assoc) return 0; return htole32(SUSPEND_TIME_PERIOD); } #endif static uint32_t iwm_mvm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck) { uint32_t tx_ant; int i, ind; for (i = 0, ind = sc->sc_scan_last_antenna; i < IWM_RATE_MCS_ANT_NUM; i++) { ind = (ind + 1) % IWM_RATE_MCS_ANT_NUM; if (iwm_fw_valid_tx_ant(sc) & (1 << ind)) { sc->sc_scan_last_antenna = ind; break; } } tx_ant = (1 << sc->sc_scan_last_antenna) << IWM_RATE_MCS_ANT_POS; if ((flags & IEEE80211_CHAN_2GHZ) && !no_cck) return htole32(IWM_RATE_1M_PLCP | IWM_RATE_MCS_CCK_MSK | tx_ant); else return htole32(IWM_RATE_6M_PLCP | tx_ant); } #if 0 /* * If req->n_ssids > 0, it means we should do an active scan. * In case of active scan w/o directed scan, we receive a zero-length SSID * just to notify that this scan is active and not passive. * In order to notify the FW of the number of SSIDs we wish to scan (including * the zero-length one), we need to set the corresponding bits in chan->type, * one for each SSID, and set the active bit (first). If the first SSID is * already included in the probe template, so we need to set only * req->n_ssids - 1 bits in addition to the first bit. */ static uint16_t iwm_mvm_get_active_dwell(struct iwm_softc *sc, int flags, int n_ssids) { if (flags & IEEE80211_CHAN_2GHZ) return 30 + 3 * (n_ssids + 1); return 20 + 2 * (n_ssids + 1); } static uint16_t iwm_mvm_get_passive_dwell(struct iwm_softc *sc, int flags) { return (flags & IEEE80211_CHAN_2GHZ) ? 100 + 20 : 100 + 10; } #endif static int iwm_mvm_scan_skip_channel(struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_2GHZ(c) && IEEE80211_IS_CHAN_B(c)) return 0; else if (IEEE80211_IS_CHAN_5GHZ(c) && IEEE80211_IS_CHAN_A(c)) return 0; else return 1; } static uint8_t iwm_mvm_lmac_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_channel_cfg_lmac *chan, int n_ssids) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_scan_state *ss = ic->ic_scan; struct ieee80211_channel *c; uint8_t nchan; int j; for (nchan = j = 0; j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) { c = &ic->ic_channels[j]; /* For 2GHz, only populate 11b channels */ /* For 5GHz, only populate 11a channels */ /* * Catch other channels, in case we have 900MHz channels or * something in the chanlist. */ if (iwm_mvm_scan_skip_channel(c)) { IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n", __func__, c->ic_freq, c->ic_ieee, c->ic_flags); continue; } IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "Adding channel %d (%d Mhz) to the list\n", nchan, c->ic_freq); chan->channel_num = htole16(ieee80211_mhz2ieee(c->ic_freq, 0)); chan->iter_count = htole16(1); chan->iter_interval = htole32(0); chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL); chan->flags |= htole32(IWM_SCAN_CHANNEL_NSSIDS(n_ssids)); /* XXX IEEE80211_SCAN_NOBCAST flag is never set. */ if (!IEEE80211_IS_CHAN_PASSIVE(c) && (!(ss->ss_flags & IEEE80211_SCAN_NOBCAST) || n_ssids != 0)) chan->flags |= htole32(IWM_SCAN_CHANNEL_TYPE_ACTIVE); chan++; nchan++; } return nchan; } static uint8_t iwm_mvm_umac_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_channel_cfg_umac *chan, int n_ssids) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_channel *c; uint8_t nchan; int j; for (nchan = j = 0; j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) { c = &ic->ic_channels[j]; /* For 2GHz, only populate 11b channels */ /* For 5GHz, only populate 11a channels */ /* * Catch other channels, in case we have 900MHz channels or * something in the chanlist. */ if (iwm_mvm_scan_skip_channel(c)) { IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n", __func__, c->ic_freq, c->ic_ieee, c->ic_flags); continue; } IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM, "Adding channel %d (%d Mhz) to the list\n", nchan, c->ic_freq); chan->channel_num = ieee80211_mhz2ieee(c->ic_freq, 0); chan->iter_count = 1; chan->iter_interval = htole16(0); chan->flags = htole32(IWM_SCAN_CHANNEL_UMAC_NSSIDS(n_ssids)); chan++; nchan++; } return nchan; } static int iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req *preq) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf; struct ieee80211_rateset *rs; size_t remain = sizeof(preq->buf); uint8_t *frm, *pos; memset(preq, 0, sizeof(*preq)); /* Ensure enough space for header and SSID IE. */ if (remain < sizeof(*wh) + 2) return ENOBUFS; /* * Build a probe request frame. Most of the following code is a * copy & paste of what is done in net80211. */ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, vap ? vap->iv_myaddr : ic->ic_macaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr); *(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */ *(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */ frm = (uint8_t *)(wh + 1); frm = ieee80211_add_ssid(frm, NULL, 0); /* Tell the firmware where the MAC header is. */ preq->mac_header.offset = 0; preq->mac_header.len = htole16(frm - (uint8_t *)wh); remain -= frm - (uint8_t *)wh; /* Fill in 2GHz IEs and tell firmware where they are. */ rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; if (rs->rs_nrates > IEEE80211_RATE_SIZE) { if (remain < 4 + rs->rs_nrates) return ENOBUFS; } else if (remain < 2 + rs->rs_nrates) { return ENOBUFS; } preq->band_data[0].offset = htole16(frm - (uint8_t *)wh); pos = frm; frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); preq->band_data[0].len = htole16(frm - pos); remain -= frm - pos; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)) { if (remain < 3) return ENOBUFS; *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = 0; remain -= 3; } - if (sc->sc_nvm.sku_cap_band_52GHz_enable) { + if (sc->nvm_data->sku_cap_band_52GHz_enable) { /* Fill in 5GHz IEs. */ rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; if (rs->rs_nrates > IEEE80211_RATE_SIZE) { if (remain < 4 + rs->rs_nrates) return ENOBUFS; } else if (remain < 2 + rs->rs_nrates) { return ENOBUFS; } preq->band_data[1].offset = htole16(frm - (uint8_t *)wh); pos = frm; frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); preq->band_data[1].len = htole16(frm - pos); remain -= frm - pos; } /* Send 11n IEs on both 2GHz and 5GHz bands. */ preq->common_data.offset = htole16(frm - (uint8_t *)wh); pos = frm; #if 0 if (ic->ic_flags & IEEE80211_F_HTON) { if (remain < 28) return ENOBUFS; frm = ieee80211_add_htcaps(frm, ic); /* XXX add WME info? */ } #endif preq->common_data.len = htole16(frm - pos); return 0; } int iwm_mvm_config_umac_scan(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwm_scan_config *scan_config; int ret, j, nchan; size_t cmd_size; struct ieee80211_channel *c; struct iwm_host_cmd hcmd = { .id = iwm_cmd_id(IWM_SCAN_CFG_CMD, IWM_ALWAYS_LONG_GROUP, 0), .flags = IWM_CMD_SYNC, }; static const uint32_t rates = (IWM_SCAN_CONFIG_RATE_1M | IWM_SCAN_CONFIG_RATE_2M | IWM_SCAN_CONFIG_RATE_5M | IWM_SCAN_CONFIG_RATE_11M | IWM_SCAN_CONFIG_RATE_6M | IWM_SCAN_CONFIG_RATE_9M | IWM_SCAN_CONFIG_RATE_12M | IWM_SCAN_CONFIG_RATE_18M | IWM_SCAN_CONFIG_RATE_24M | IWM_SCAN_CONFIG_RATE_36M | IWM_SCAN_CONFIG_RATE_48M | IWM_SCAN_CONFIG_RATE_54M); cmd_size = sizeof(*scan_config) + sc->sc_capa_n_scan_channels; scan_config = malloc(cmd_size, M_DEVBUF, M_NOWAIT | M_ZERO); if (scan_config == NULL) return ENOMEM; scan_config->tx_chains = htole32(iwm_fw_valid_tx_ant(sc)); scan_config->rx_chains = htole32(iwm_fw_valid_rx_ant(sc)); scan_config->legacy_rates = htole32(rates | IWM_SCAN_CONFIG_SUPPORTED_RATE(rates)); /* These timings correspond to iwlwifi's UNASSOC scan. */ scan_config->dwell_active = 10; scan_config->dwell_passive = 110; scan_config->dwell_fragmented = 44; scan_config->dwell_extended = 90; scan_config->out_of_channel_time = htole32(0); scan_config->suspend_time = htole32(0); IEEE80211_ADDR_COPY(scan_config->mac_addr, vap ? vap->iv_myaddr : ic->ic_macaddr); scan_config->bcast_sta_id = sc->sc_aux_sta.sta_id; scan_config->channel_flags = IWM_CHANNEL_FLAG_EBS | IWM_CHANNEL_FLAG_ACCURATE_EBS | IWM_CHANNEL_FLAG_EBS_ADD | IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; for (nchan = j = 0; j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) { c = &ic->ic_channels[j]; /* For 2GHz, only populate 11b channels */ /* For 5GHz, only populate 11a channels */ /* * Catch other channels, in case we have 900MHz channels or * something in the chanlist. */ if (iwm_mvm_scan_skip_channel(c)) continue; scan_config->channel_array[nchan++] = ieee80211_mhz2ieee(c->ic_freq, 0); } scan_config->flags = htole32(IWM_SCAN_CONFIG_FLAG_ACTIVATE | IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS | IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS | IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID | IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES | IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES | IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR | IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| IWM_SCAN_CONFIG_N_CHANNELS(nchan) | IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED); hcmd.data[0] = scan_config; hcmd.len[0] = cmd_size; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Sending UMAC scan config\n"); ret = iwm_send_cmd(sc, &hcmd); if (!ret) IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "UMAC scan config was sent successfully\n"); free(scan_config, M_DEVBUF); return ret; } int iwm_mvm_umac_scan(struct iwm_softc *sc) { struct iwm_host_cmd hcmd = { .id = iwm_cmd_id(IWM_SCAN_REQ_UMAC, IWM_ALWAYS_LONG_GROUP, 0), .len = { 0, }, .data = { NULL, }, .flags = IWM_CMD_SYNC, }; struct ieee80211_scan_state *ss = sc->sc_ic.ic_scan; struct iwm_scan_req_umac *req; struct iwm_scan_req_umac_tail *tail; size_t req_len; uint8_t i, nssid; int ret; req_len = sizeof(struct iwm_scan_req_umac) + (sizeof(struct iwm_scan_channel_cfg_umac) * sc->sc_capa_n_scan_channels) + sizeof(struct iwm_scan_req_umac_tail); if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ENOMEM; req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO); if (req == NULL) return ENOMEM; hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n"); /* These timings correspond to iwlwifi's UNASSOC scan. */ req->active_dwell = 10; req->passive_dwell = 110; req->fragmented_dwell = 44; req->extended_dwell = 90; req->max_out_time = 0; req->suspend_time = 0; req->scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH); req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH); nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX); req->n_channels = iwm_mvm_umac_scan_fill_channels(sc, (struct iwm_scan_channel_cfg_umac *)req->data, nssid); req->general_flags = htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL | IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE | IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL); tail = (void *)((char *)&req->data + sizeof(struct iwm_scan_channel_cfg_umac) * sc->sc_capa_n_scan_channels); /* Check if we're doing an active directed scan. */ for (i = 0; i < nssid; i++) { tail->direct_scan[i].id = IEEE80211_ELEMID_SSID; tail->direct_scan[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); memcpy(tail->direct_scan[i].ssid, ss->ss_ssid[i].ssid, tail->direct_scan[i].len); /* XXX debug */ } if (nssid != 0) { req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT); } else req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE); if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)) req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED); ret = iwm_mvm_fill_probe_req(sc, &tail->preq); if (ret) { free(req, M_DEVBUF); return ret; } /* Specify the scan plan: We'll do one iteration. */ tail->schedule[0].interval = 0; tail->schedule[0].iter_count = 1; ret = iwm_send_cmd(sc, &hcmd); if (!ret) IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Scan request was sent successfully\n"); free(req, M_DEVBUF); return ret; } int iwm_mvm_lmac_scan(struct iwm_softc *sc) { struct iwm_host_cmd hcmd = { .id = IWM_SCAN_OFFLOAD_REQUEST_CMD, .len = { 0, }, .data = { NULL, }, .flags = IWM_CMD_SYNC, }; struct ieee80211_scan_state *ss = sc->sc_ic.ic_scan; struct iwm_scan_req_lmac *req; size_t req_len; uint8_t i, nssid; int ret; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n"); req_len = sizeof(struct iwm_scan_req_lmac) + (sizeof(struct iwm_scan_channel_cfg_lmac) * sc->sc_capa_n_scan_channels) + sizeof(struct iwm_scan_probe_req); if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ENOMEM; req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO); if (req == NULL) return ENOMEM; hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; /* These timings correspond to iwlwifi's UNASSOC scan. */ req->active_dwell = 10; req->passive_dwell = 110; req->fragmented_dwell = 44; req->extended_dwell = 90; req->max_out_time = 0; req->suspend_time = 0; req->scan_prio = htole32(IWM_SCAN_PRIORITY_HIGH); req->rx_chain_select = iwm_mvm_scan_rx_chain(sc); req->iter_num = htole32(1); req->delay = 0; req->scan_flags = htole32(IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL | IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE | IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL); if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)) req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED); req->flags = htole32(IWM_PHY_BAND_24); - if (sc->sc_nvm.sku_cap_band_52GHz_enable) + if (sc->nvm_data->sku_cap_band_52GHz_enable) req->flags |= htole32(IWM_PHY_BAND_5); req->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON); /* Tx flags 2 GHz. */ req->tx_cmd[0].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL | IWM_TX_CMD_FLG_BT_DIS); req->tx_cmd[0].rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_2GHZ, 1/*XXX*/); req->tx_cmd[0].sta_id = sc->sc_aux_sta.sta_id; /* Tx flags 5 GHz. */ req->tx_cmd[1].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL | IWM_TX_CMD_FLG_BT_DIS); req->tx_cmd[1].rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_5GHZ, 1/*XXX*/); req->tx_cmd[1].sta_id = sc->sc_aux_sta.sta_id; /* Check if we're doing an active directed scan. */ nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX); for (i = 0; i < nssid; i++) { req->direct_scan[i].id = IEEE80211_ELEMID_SSID; req->direct_scan[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); memcpy(req->direct_scan[i].ssid, ss->ss_ssid[i].ssid, req->direct_scan[i].len); /* XXX debug */ } if (nssid != 0) { req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION); } else req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAG_PASSIVE); req->n_channels = iwm_mvm_lmac_scan_fill_channels(sc, (struct iwm_scan_channel_cfg_lmac *)req->data, nssid); ret = iwm_mvm_fill_probe_req(sc, (struct iwm_scan_probe_req *)(req->data + (sizeof(struct iwm_scan_channel_cfg_lmac) * sc->sc_capa_n_scan_channels))); if (ret) { free(req, M_DEVBUF); return ret; } /* Specify the scan plan: We'll do one iteration. */ req->schedule[0].iterations = 1; req->schedule[0].full_scan_mul = 1; /* Disable EBS. */ req->channel_opt[0].non_ebs_ratio = 1; req->channel_opt[1].non_ebs_ratio = 1; ret = iwm_send_cmd(sc, &hcmd); if (!ret) { IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Scan request was sent successfully\n"); } free(req, M_DEVBUF); return ret; } Index: projects/ipsec/sys/dev/iwm/if_iwm_util.c =================================================================== --- projects/ipsec/sys/dev/iwm/if_iwm_util.c (revision 313312) +++ projects/ipsec/sys/dev/iwm/if_iwm_util.c (revision 313313) @@ -1,458 +1,458 @@ /* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * * Driver version we are currently based off of is * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT * OWNER 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. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Send a command to the firmware. We try to implement the Linux * driver interface for the routine. * mostly from if_iwn (iwn_cmd()). * * For now, we always copy the first part and map the second one (if it exists). */ int iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd) { struct iwm_tx_ring *ring = &sc->txq[IWM_MVM_CMD_QUEUE]; struct iwm_tfd *desc; struct iwm_tx_data *txdata = NULL; struct iwm_device_cmd *cmd; struct mbuf *m; bus_dma_segment_t seg; bus_addr_t paddr; uint32_t addr_lo; int error = 0, i, paylen, off; int code; int async, wantresp; int group_id; int nsegs; size_t hdrlen, datasz; uint8_t *data; code = hcmd->id; async = hcmd->flags & IWM_CMD_ASYNC; wantresp = hcmd->flags & IWM_CMD_WANT_SKB; data = NULL; for (i = 0, paylen = 0; i < nitems(hcmd->len); i++) { paylen += hcmd->len[i]; } /* if the command wants an answer, busy sc_cmd_resp */ if (wantresp) { KASSERT(!async, ("invalid async parameter")); while (sc->sc_wantresp != -1) msleep(&sc->sc_wantresp, &sc->sc_mtx, 0, "iwmcmdsl", 0); sc->sc_wantresp = ring->qid << 16 | ring->cur; IWM_DPRINTF(sc, IWM_DEBUG_CMD, "wantresp is %x\n", sc->sc_wantresp); } /* * Is the hardware still available? (after e.g. above wait). */ if (sc->sc_flags & IWM_FLAG_STOPPED) { error = ENXIO; goto out; } desc = &ring->desc[ring->cur]; txdata = &ring->data[ring->cur]; group_id = iwm_cmd_groupid(code); if (group_id != 0) { hdrlen = sizeof(cmd->hdr_wide); datasz = sizeof(cmd->data_wide); } else { hdrlen = sizeof(cmd->hdr); datasz = sizeof(cmd->data); } if (paylen > datasz) { IWM_DPRINTF(sc, IWM_DEBUG_CMD, "large command paylen=%u len0=%u\n", paylen, hcmd->len[0]); /* Command is too large */ size_t totlen = hdrlen + paylen; if (paylen > IWM_MAX_CMD_PAYLOAD_SIZE) { device_printf(sc->sc_dev, "firmware command too long (%zd bytes)\n", totlen); error = EINVAL; goto out; } m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, IWM_RBUF_SIZE); if (m == NULL) { error = ENOBUFS; goto out; } m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; error = bus_dmamap_load_mbuf_sg(ring->data_dmat, txdata->map, m, &seg, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, "%s: can't map mbuf, error %d\n", __func__, error); m_freem(m); goto out; } txdata->m = m; /* mbuf will be freed in iwm_cmd_done() */ cmd = mtod(m, struct iwm_device_cmd *); paddr = seg.ds_addr; } else { cmd = &ring->cmd[ring->cur]; paddr = txdata->cmd_paddr; } if (group_id != 0) { cmd->hdr_wide.opcode = iwm_cmd_opcode(code); cmd->hdr_wide.group_id = group_id; cmd->hdr_wide.qid = ring->qid; cmd->hdr_wide.idx = ring->cur; cmd->hdr_wide.length = htole16(paylen); cmd->hdr_wide.version = iwm_cmd_version(code); data = cmd->data_wide; } else { cmd->hdr.code = iwm_cmd_opcode(code); cmd->hdr.flags = 0; cmd->hdr.qid = ring->qid; cmd->hdr.idx = ring->cur; data = cmd->data; } for (i = 0, off = 0; i < nitems(hcmd->data); i++) { if (hcmd->len[i] == 0) continue; memcpy(data + off, hcmd->data[i], hcmd->len[i]); off += hcmd->len[i]; } KASSERT(off == paylen, ("off %d != paylen %d", off, paylen)); /* lo field is not aligned */ addr_lo = htole32((uint32_t)paddr); memcpy(&desc->tbs[0].lo, &addr_lo, sizeof(uint32_t)); desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(paddr) | ((hdrlen + paylen) << 4)); desc->num_tbs = 1; IWM_DPRINTF(sc, IWM_DEBUG_CMD, "iwm_send_cmd 0x%x size=%lu %s\n", code, (unsigned long) (hcmd->len[0] + hcmd->len[1] + hdrlen), async ? " (async)" : ""); if (paylen > datasz) { bus_dmamap_sync(ring->data_dmat, txdata->map, BUS_DMASYNC_PREWRITE); } else { bus_dmamap_sync(ring->cmd_dma.tag, ring->cmd_dma.map, BUS_DMASYNC_PREWRITE); } bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, (IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000)) { device_printf(sc->sc_dev, "%s: acquiring device failed\n", __func__); error = EBUSY; goto out; } #if 0 iwm_update_sched(sc, ring->qid, ring->cur, 0, 0); #endif IWM_DPRINTF(sc, IWM_DEBUG_CMD, "sending command 0x%x qid %d, idx %d\n", code, ring->qid, ring->cur); /* Kick command ring. */ ring->cur = (ring->cur + 1) % IWM_TX_RING_COUNT; IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); if (!async) { /* m..m-mmyy-mmyyyy-mym-ym m-my generation */ int generation = sc->sc_generation; error = msleep(desc, &sc->sc_mtx, PCATCH, "iwmcmd", hz); if (error == 0) { /* if hardware is no longer up, return error */ if (generation != sc->sc_generation) { error = ENXIO; } else { hcmd->resp_pkt = (void *)sc->sc_cmd_resp; } } } out: if (wantresp && error != 0) { iwm_free_resp(sc, hcmd); } return error; } /* iwlwifi: mvm/utils.c */ int iwm_mvm_send_cmd_pdu(struct iwm_softc *sc, uint8_t id, uint32_t flags, uint16_t len, const void *data) { struct iwm_host_cmd cmd = { .id = id, .len = { len, }, .data = { data, }, .flags = flags, }; return iwm_send_cmd(sc, &cmd); } /* iwlwifi: mvm/utils.c */ int iwm_mvm_send_cmd_status(struct iwm_softc *sc, struct iwm_host_cmd *cmd, uint32_t *status) { struct iwm_rx_packet *pkt; struct iwm_cmd_response *resp; int error, resp_len; KASSERT((cmd->flags & IWM_CMD_WANT_SKB) == 0, ("invalid command")); cmd->flags |= IWM_CMD_SYNC | IWM_CMD_WANT_SKB; if ((error = iwm_send_cmd(sc, cmd)) != 0) return error; pkt = cmd->resp_pkt; /* Can happen if RFKILL is asserted */ if (!pkt) { error = 0; goto out_free_resp; } if (pkt->hdr.flags & IWM_CMD_FAILED_MSK) { error = EIO; goto out_free_resp; } resp_len = iwm_rx_packet_payload_len(pkt); if (resp_len != sizeof(*resp)) { error = EIO; goto out_free_resp; } resp = (void *)pkt->data; *status = le32toh(resp->status); out_free_resp: iwm_free_resp(sc, cmd); return error; } /* iwlwifi/mvm/utils.c */ int iwm_mvm_send_cmd_pdu_status(struct iwm_softc *sc, uint8_t id, uint16_t len, const void *data, uint32_t *status) { struct iwm_host_cmd cmd = { .id = id, .len = { len, }, .data = { data, }, }; return iwm_mvm_send_cmd_status(sc, &cmd, status); } void iwm_free_resp(struct iwm_softc *sc, struct iwm_host_cmd *hcmd) { KASSERT(sc->sc_wantresp != -1, ("already freed")); KASSERT((hcmd->flags & (IWM_CMD_WANT_SKB|IWM_CMD_SYNC)) == (IWM_CMD_WANT_SKB|IWM_CMD_SYNC), ("invalid flags")); sc->sc_wantresp = -1; wakeup(&sc->sc_wantresp); } uint8_t iwm_fw_valid_tx_ant(struct iwm_softc *sc) { uint8_t tx_ant; tx_ant = ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_TX_CHAIN) >> IWM_FW_PHY_CFG_TX_CHAIN_POS); - if (sc->sc_nvm.valid_tx_ant) - tx_ant &= sc->sc_nvm.valid_tx_ant; + if (sc->nvm_data->valid_tx_ant) + tx_ant &= sc->nvm_data->valid_tx_ant; return tx_ant; } uint8_t iwm_fw_valid_rx_ant(struct iwm_softc *sc) { uint8_t rx_ant; rx_ant = ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RX_CHAIN) >> IWM_FW_PHY_CFG_RX_CHAIN_POS); - if (sc->sc_nvm.valid_rx_ant) - rx_ant &= sc->sc_nvm.valid_rx_ant; + if (sc->nvm_data->valid_rx_ant) + rx_ant &= sc->nvm_data->valid_rx_ant; return rx_ant; } Index: projects/ipsec/sys/dev/iwm/if_iwmreg.h =================================================================== --- projects/ipsec/sys/dev/iwm/if_iwmreg.h (revision 313312) +++ projects/ipsec/sys/dev/iwm/if_iwmreg.h (revision 313313) @@ -1,6149 +1,6115 @@ /* $OpenBSD: if_iwmreg.h,v 1.4 2015/06/15 08:06:11 stsp Exp $ */ /* $FreeBSD$ */ /****************************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT * OWNER 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. * *****************************************************************************/ #ifndef __IF_IWM_REG_H__ #define __IF_IWM_REG_H__ #define le16_to_cpup(_a_) (le16toh(*(const uint16_t *)(_a_))) #define le32_to_cpup(_a_) (le32toh(*(const uint32_t *)(_a_))) /* * BEGIN iwl-csr.h */ /* * CSR (control and status registers) * * CSR registers are mapped directly into PCI bus space, and are accessible * whenever platform supplies power to device, even when device is in * low power states due to driver-invoked device resets * (e.g. IWM_CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes. * * Use iwl_write32() and iwl_read32() family to access these registers; * these provide simple PCI bus access, without waking up the MAC. * Do not use iwl_write_direct32() family for these registers; * no need to "grab nic access" via IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ. * The MAC (uCode processor, etc.) does not need to be powered up for accessing * the CSR registers. * * NOTE: Device does need to be awake in order to read this memory * via IWM_CSR_EEPROM and IWM_CSR_OTP registers */ #define IWM_CSR_HW_IF_CONFIG_REG (0x000) /* hardware interface config */ #define IWM_CSR_INT_COALESCING (0x004) /* accum ints, 32-usec units */ #define IWM_CSR_INT (0x008) /* host interrupt status/ack */ #define IWM_CSR_INT_MASK (0x00c) /* host interrupt enable */ #define IWM_CSR_FH_INT_STATUS (0x010) /* busmaster int status/ack*/ #define IWM_CSR_GPIO_IN (0x018) /* read external chip pins */ #define IWM_CSR_RESET (0x020) /* busmaster enable, NMI, etc*/ #define IWM_CSR_GP_CNTRL (0x024) /* 2nd byte of IWM_CSR_INT_COALESCING, not accessible via iwl_write32()! */ #define IWM_CSR_INT_PERIODIC_REG (0x005) /* * Hardware revision info * Bit fields: * 31-16: Reserved * 15-4: Type of device: see IWM_CSR_HW_REV_TYPE_xxx definitions * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D * 1-0: "Dash" (-) value, as in A-1, etc. */ #define IWM_CSR_HW_REV (0x028) /* * EEPROM and OTP (one-time-programmable) memory reads * * NOTE: Device must be awake, initialized via apm_ops.init(), * in order to read. */ #define IWM_CSR_EEPROM_REG (0x02c) #define IWM_CSR_EEPROM_GP (0x030) #define IWM_CSR_OTP_GP_REG (0x034) #define IWM_CSR_GIO_REG (0x03C) #define IWM_CSR_GP_UCODE_REG (0x048) #define IWM_CSR_GP_DRIVER_REG (0x050) /* * UCODE-DRIVER GP (general purpose) mailbox registers. * SET/CLR registers set/clear bit(s) if "1" is written. */ #define IWM_CSR_UCODE_DRV_GP1 (0x054) #define IWM_CSR_UCODE_DRV_GP1_SET (0x058) #define IWM_CSR_UCODE_DRV_GP1_CLR (0x05c) #define IWM_CSR_UCODE_DRV_GP2 (0x060) #define IWM_CSR_MBOX_SET_REG (0x088) #define IWM_CSR_MBOX_SET_REG_OS_ALIVE 0x20 #define IWM_CSR_LED_REG (0x094) #define IWM_CSR_DRAM_INT_TBL_REG (0x0A0) #define IWM_CSR_MAC_SHADOW_REG_CTRL (0x0A8) /* 6000 and up */ /* GIO Chicken Bits (PCI Express bus link power management) */ #define IWM_CSR_GIO_CHICKEN_BITS (0x100) /* Analog phase-lock-loop configuration */ #define IWM_CSR_ANA_PLL_CFG (0x20c) /* * CSR Hardware Revision Workaround Register. Indicates hardware rev; * "step" determines CCK backoff for txpower calculation. Used for 4965 only. * See also IWM_CSR_HW_REV register. * Bit fields: * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step * 1-0: "Dash" (-) value, as in C-1, etc. */ #define IWM_CSR_HW_REV_WA_REG (0x22C) #define IWM_CSR_DBG_HPET_MEM_REG (0x240) #define IWM_CSR_DBG_LINK_PWR_MGMT_REG (0x250) /* Bits for IWM_CSR_HW_IF_CONFIG_REG */ #define IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH (0x00000003) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP (0x0000000C) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x000000C0) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE (0x00000C00) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH (0x00003000) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP (0x0000C000) #define IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_DASH (0) #define IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_STEP (2) #define IWM_CSR_HW_IF_CONFIG_REG_POS_BOARD_VER (6) #define IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE (10) #define IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH (12) #define IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP (14) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ #define IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ #define IWM_CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ #define IWM_CSR_HW_IF_CONFIG_REG_ENABLE_PME (0x10000000) #define IWM_CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ #define IWM_CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ #define IWM_CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), * acknowledged (reset) by host writing "1" to flagged bits. */ #define IWM_CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ #define IWM_CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ #define IWM_CSR_INT_BIT_RX_PERIODIC (1 << 28) /* Rx periodic */ #define IWM_CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ #define IWM_CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ #define IWM_CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ #define IWM_CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ #define IWM_CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ #define IWM_CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ #define IWM_CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ #define IWM_CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ #define IWM_CSR_INI_SET_MASK (IWM_CSR_INT_BIT_FH_RX | \ IWM_CSR_INT_BIT_HW_ERR | \ IWM_CSR_INT_BIT_FH_TX | \ IWM_CSR_INT_BIT_SW_ERR | \ IWM_CSR_INT_BIT_RF_KILL | \ IWM_CSR_INT_BIT_SW_RX | \ IWM_CSR_INT_BIT_WAKEUP | \ IWM_CSR_INT_BIT_ALIVE | \ IWM_CSR_INT_BIT_RX_PERIODIC) /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ #define IWM_CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ #define IWM_CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ #define IWM_CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ #define IWM_CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ #define IWM_CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ #define IWM_CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ #define IWM_CSR_FH_INT_RX_MASK (IWM_CSR_FH_INT_BIT_HI_PRIOR | \ IWM_CSR_FH_INT_BIT_RX_CHNL1 | \ IWM_CSR_FH_INT_BIT_RX_CHNL0) #define IWM_CSR_FH_INT_TX_MASK (IWM_CSR_FH_INT_BIT_TX_CHNL1 | \ IWM_CSR_FH_INT_BIT_TX_CHNL0) /* GPIO */ #define IWM_CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) #define IWM_CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) #define IWM_CSR_GPIO_IN_VAL_VMAIN_PWR_SRC (0x00000200) /* RESET */ #define IWM_CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) #define IWM_CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) #define IWM_CSR_RESET_REG_FLAG_SW_RESET (0x00000080) #define IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) #define IWM_CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) #define IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000) /* * GP (general purpose) CONTROL REGISTER * Bit fields: * 27: HW_RF_KILL_SW * Indicates state of (platform's) hardware RF-Kill switch * 26-24: POWER_SAVE_TYPE * Indicates current power-saving mode: * 000 -- No power saving * 001 -- MAC power-down * 010 -- PHY (radio) power-down * 011 -- Error * 9-6: SYS_CONFIG * Indicates current system configuration, reflecting pins on chip * as forced high/low by device circuit board. * 4: GOING_TO_SLEEP * Indicates MAC is entering a power-saving sleep power-down. * Not a good time to access device-internal resources. * 3: MAC_ACCESS_REQ * Host sets this to request and maintain MAC wakeup, to allow host * access to device-internal resources. Host must wait for * MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR * device registers. * 2: INIT_DONE * Host sets this to put device into fully operational D0 power mode. * Host resets this after SW_RESET to put device into low power mode. * 0: MAC_CLOCK_READY * Indicates MAC (ucode processor, etc.) is powered up and can run. * Internal resources are accessible. * NOTE: This does not indicate that the processor is actually running. * NOTE: This does not indicate that device has completed * init or post-power-down restore of internal SRAM memory. * Use IWM_CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that * SRAM is restored and uCode is in normal operation mode. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and * do not need to save/restore it. * NOTE: After device reset, this bit remains "0" until host sets * INIT_DONE */ #define IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) #define IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) #define IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) #define IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) #define IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) #define IWM_CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) #define IWM_CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) #define IWM_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) /* HW REV */ #define IWM_CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) #define IWM_CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) +/** + * hw_rev values + */ +enum { + IWM_SILICON_A_STEP = 0, + IWM_SILICON_B_STEP, + IWM_SILICON_C_STEP, +}; + + #define IWM_CSR_HW_REV_TYPE_MSK (0x000FFF0) #define IWM_CSR_HW_REV_TYPE_5300 (0x0000020) #define IWM_CSR_HW_REV_TYPE_5350 (0x0000030) #define IWM_CSR_HW_REV_TYPE_5100 (0x0000050) #define IWM_CSR_HW_REV_TYPE_5150 (0x0000040) #define IWM_CSR_HW_REV_TYPE_1000 (0x0000060) #define IWM_CSR_HW_REV_TYPE_6x00 (0x0000070) #define IWM_CSR_HW_REV_TYPE_6x50 (0x0000080) #define IWM_CSR_HW_REV_TYPE_6150 (0x0000084) #define IWM_CSR_HW_REV_TYPE_6x05 (0x00000B0) #define IWM_CSR_HW_REV_TYPE_6x30 IWM_CSR_HW_REV_TYPE_6x05 #define IWM_CSR_HW_REV_TYPE_6x35 IWM_CSR_HW_REV_TYPE_6x05 #define IWM_CSR_HW_REV_TYPE_2x30 (0x00000C0) #define IWM_CSR_HW_REV_TYPE_2x00 (0x0000100) #define IWM_CSR_HW_REV_TYPE_105 (0x0000110) #define IWM_CSR_HW_REV_TYPE_135 (0x0000120) #define IWM_CSR_HW_REV_TYPE_7265D (0x0000210) #define IWM_CSR_HW_REV_TYPE_NONE (0x00001F0) /* EEPROM REG */ #define IWM_CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) #define IWM_CSR_EEPROM_REG_BIT_CMD (0x00000002) #define IWM_CSR_EEPROM_REG_MSK_ADDR (0x0000FFFC) #define IWM_CSR_EEPROM_REG_MSK_DATA (0xFFFF0000) /* EEPROM GP */ #define IWM_CSR_EEPROM_GP_VALID_MSK (0x00000007) /* signature */ #define IWM_CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) #define IWM_CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) #define IWM_CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001) #define IWM_CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002) #define IWM_CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004) /* One-time-programmable memory general purpose reg */ #define IWM_CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */ #define IWM_CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ #define IWM_CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ #define IWM_CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ /* GP REG */ #define IWM_CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */ #define IWM_CSR_GP_REG_NO_POWER_SAVE (0x00000000) #define IWM_CSR_GP_REG_MAC_POWER_SAVE (0x01000000) #define IWM_CSR_GP_REG_PHY_POWER_SAVE (0x02000000) #define IWM_CSR_GP_REG_POWER_SAVE_ERROR (0x03000000) /* CSR GIO */ #define IWM_CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) /* * UCODE-DRIVER GP (general purpose) mailbox register 1 * Host driver and uCode write and/or read this register to communicate with * each other. * Bit fields: * 4: UCODE_DISABLE * Host sets this to request permanent halt of uCode, same as * sending CARD_STATE command with "halt" bit set. * 3: CT_KILL_EXIT * Host sets this to request exit from CT_KILL state, i.e. host thinks * device temperature is low enough to continue normal operation. * 2: CMD_BLOCKED * Host sets this during RF KILL power-down sequence (HW, SW, CT KILL) * to release uCode to clear all Tx and command queues, enter * unassociated mode, and power down. * NOTE: Some devices also use HBUS_TARG_MBX_C register for this bit. * 1: SW_BIT_RFKILL * Host sets this when issuing CARD_STATE command to request * device sleep. * 0: MAC_SLEEP * uCode sets this when preparing a power-saving power-down. * uCode resets this when power-up is complete and SRAM is sane. * NOTE: device saves internal SRAM data to host when powering down, * and must restore this data after powering back up. * MAC_SLEEP is the best indication that restore is complete. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and * do not need to save/restore it. */ #define IWM_CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) #define IWM_CSR_UCODE_SW_BIT_RFKILL (0x00000002) #define IWM_CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) #define IWM_CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) #define IWM_CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE (0x00000020) /* GP Driver */ #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_SKU_MSK (0x00000003) #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000) #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001) #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002) #define IWM_CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004) #define IWM_CSR_GP_DRIVER_REG_BIT_6050_1x2 (0x00000008) #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER (0x00000080) /* GIO Chicken Bits (PCI Express bus link power management) */ #define IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) /* LED */ #define IWM_CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF) #define IWM_CSR_LED_REG_TURN_ON (0x60) #define IWM_CSR_LED_REG_TURN_OFF (0x20) /* ANA_PLL */ #define IWM_CSR50_ANA_PLL_CFG_VAL (0x00880300) /* HPET MEM debug */ #define IWM_CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) /* DRAM INT TABLE */ #define IWM_CSR_DRAM_INT_TBL_ENABLE (1 << 31) #define IWM_CSR_DRAM_INIT_TBL_WRITE_POINTER (1 << 28) #define IWM_CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) /* SECURE boot registers */ #define IWM_CSR_SECURE_BOOT_CONFIG_ADDR (0x100) enum iwm_secure_boot_config_reg { IWM_CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001, IWM_CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, }; #define IWM_CSR_SECURE_BOOT_CPU1_STATUS_ADDR (0x100) #define IWM_CSR_SECURE_BOOT_CPU2_STATUS_ADDR (0x100) enum iwm_secure_boot_status_reg { IWM_CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000003, IWM_CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002, IWM_CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004, IWM_CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008, IWM_CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010, }; #define IWM_FH_UCODE_LOAD_STATUS 0x1af0 #define IWM_CSR_UCODE_LOAD_STATUS_ADDR 0x1e70 enum iwm_secure_load_status_reg { IWM_LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001, IWM_LMPM_CPU_HDRS_LOADING_COMPLETED = 0x00000003, IWM_LMPM_CPU_UCODE_LOADING_COMPLETED = 0x00000007, IWM_LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8, IWM_LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00, }; #define IWM_FH_MEM_TB_MAX_LENGTH 0x20000 #define IWM_LMPM_SECURE_INSPECTOR_CODE_ADDR 0x1e38 #define IWM_LMPM_SECURE_INSPECTOR_DATA_ADDR 0x1e3c #define IWM_LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR 0x1e78 #define IWM_LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR 0x1e7c #define IWM_LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE 0x400000 #define IWM_LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE 0x402000 #define IWM_LMPM_SECURE_CPU1_HDR_MEM_SPACE 0x420000 #define IWM_LMPM_SECURE_CPU2_HDR_MEM_SPACE 0x420400 #define IWM_CSR_SECURE_TIME_OUT (100) /* extended range in FW SRAM */ #define IWM_FW_MEM_EXTENDED_START 0x40000 #define IWM_FW_MEM_EXTENDED_END 0x57FFF /* FW chicken bits */ #define IWM_LMPM_CHICK 0xa01ff8 #define IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE 0x01 #define IWM_FH_TCSR_0_REG0 (0x1D00) /* * HBUS (Host-side Bus) * * HBUS registers are mapped directly into PCI bus space, but are used * to indirectly access device's internal memory or registers that * may be powered-down. * * Use iwl_write_direct32()/iwl_read_direct32() family for these registers; * host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ * to make sure the MAC (uCode processor, etc.) is powered up for accessing * internal resources. * * Do not use iwl_write32()/iwl_read32() family to access these registers; * these provide only simple PCI bus access, without waking up the MAC. */ #define IWM_HBUS_BASE (0x400) /* * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM * structures, error log, event log, verifying uCode load). * First write to address register, then read from or write to data register * to complete the job. Once the address register is set up, accesses to * data registers auto-increment the address by one dword. * Bit usage for address registers (read or write): * 0-31: memory address within device */ #define IWM_HBUS_TARG_MEM_RADDR (IWM_HBUS_BASE+0x00c) #define IWM_HBUS_TARG_MEM_WADDR (IWM_HBUS_BASE+0x010) #define IWM_HBUS_TARG_MEM_WDAT (IWM_HBUS_BASE+0x018) #define IWM_HBUS_TARG_MEM_RDAT (IWM_HBUS_BASE+0x01c) /* Mailbox C, used as workaround alternative to CSR_UCODE_DRV_GP1 mailbox */ #define IWM_HBUS_TARG_MBX_C (IWM_HBUS_BASE+0x030) #define IWM_HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) /* * Registers for accessing device's internal peripheral registers * (e.g. SCD, BSM, etc.). First write to address register, * then read from or write to data register to complete the job. * Bit usage for address registers (read or write): * 0-15: register address (offset) within device * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) */ #define IWM_HBUS_TARG_PRPH_WADDR (IWM_HBUS_BASE+0x044) #define IWM_HBUS_TARG_PRPH_RADDR (IWM_HBUS_BASE+0x048) #define IWM_HBUS_TARG_PRPH_WDAT (IWM_HBUS_BASE+0x04c) #define IWM_HBUS_TARG_PRPH_RDAT (IWM_HBUS_BASE+0x050) /* enable the ID buf for read */ #define IWM_WFPM_PS_CTL_CLR 0xa0300c #define IWM_WFMP_MAC_ADDR_0 0xa03080 #define IWM_WFMP_MAC_ADDR_1 0xa03084 #define IWM_LMPM_PMG_EN 0xa01cec #define IWM_RADIO_REG_SYS_MANUAL_DFT_0 0xad4078 #define IWM_RFIC_REG_RD 0xad0470 #define IWM_WFPM_CTRL_REG 0xa03030 #define IWM_WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK 0x08000000 #define IWM_ENABLE_WFPM 0x80000000 #define IWM_AUX_MISC_REG 0xa200b0 #define IWM_HW_STEP_LOCATION_BITS 24 #define IWM_AUX_MISC_MASTER1_EN 0xa20818 #define IWM_AUX_MISC_MASTER1_EN_SBE_MSK 0x1 #define IWM_AUX_MISC_MASTER1_SMPHR_STATUS 0xa20800 #define IWM_RSA_ENABLE 0xa24b08 #define IWM_PREG_AUX_BUS_WPROT_0 0xa04cc0 #define IWM_SB_CFG_OVERRIDE_ADDR 0xa26c78 #define IWM_SB_CFG_OVERRIDE_ENABLE 0x8000 #define IWM_SB_CFG_BASE_OVERRIDE 0xa20000 #define IWM_SB_MODIFY_CFG_FLAG 0xa03088 #define IWM_SB_CPU_1_STATUS 0xa01e30 #define IWM_SB_CPU_2_STATUS 0Xa01e34 /* Used to enable DBGM */ #define IWM_HBUS_TARG_TEST_REG (IWM_HBUS_BASE+0x05c) /* * Per-Tx-queue write pointer (index, really!) * Indicates index to next TFD that driver will fill (1 past latest filled). * Bit usage: * 0-7: queue write index * 11-8: queue selector */ #define IWM_HBUS_TARG_WRPTR (IWM_HBUS_BASE+0x060) /********************************************************** * CSR values **********************************************************/ /* * host interrupt timeout value * used with setting interrupt coalescing timer * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit * * default interrupt coalescing timer is 64 x 32 = 2048 usecs */ #define IWM_HOST_INT_TIMEOUT_MAX (0xFF) #define IWM_HOST_INT_TIMEOUT_DEF (0x40) #define IWM_HOST_INT_TIMEOUT_MIN (0x0) #define IWM_HOST_INT_OPER_MODE (1 << 31) /***************************************************************************** * 7000/3000 series SHR DTS addresses * *****************************************************************************/ /* Diode Results Register Structure: */ enum iwm_dtd_diode_reg { IWM_DTS_DIODE_REG_DIG_VAL = 0x000000FF, /* bits [7:0] */ IWM_DTS_DIODE_REG_VREF_LOW = 0x0000FF00, /* bits [15:8] */ IWM_DTS_DIODE_REG_VREF_HIGH = 0x00FF0000, /* bits [23:16] */ IWM_DTS_DIODE_REG_VREF_ID = 0x03000000, /* bits [25:24] */ IWM_DTS_DIODE_REG_PASS_ONCE = 0x80000000, /* bits [31:31] */ IWM_DTS_DIODE_REG_FLAGS_MSK = 0xFF000000, /* bits [31:24] */ /* Those are the masks INSIDE the flags bit-field: */ IWM_DTS_DIODE_REG_FLAGS_VREFS_ID_POS = 0, IWM_DTS_DIODE_REG_FLAGS_VREFS_ID = 0x00000003, /* bits [1:0] */ IWM_DTS_DIODE_REG_FLAGS_PASS_ONCE_POS = 7, IWM_DTS_DIODE_REG_FLAGS_PASS_ONCE = 0x00000080, /* bits [7:7] */ }; /* * END iwl-csr.h */ /* * BEGIN iwl-fw.h */ /** * enum iwm_ucode_tlv_flag - ucode API flags * @IWM_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * was a separate TLV but moved here to save space. * @IWM_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, * treats good CRC threshold as a boolean * @IWM_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). * @IWM_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. * @IWM_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS * @IWM_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD * @IWM_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan * offload profile config command. * @IWM_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api * @IWM_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API. * @IWM_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six * (rather than two) IPv6 addresses * @IWM_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API * @IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element * from the probe request template. * @IWM_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping * connection when going back to D0 * @IWM_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) * @IWM_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) * @IWM_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan. * @IWM_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API * @IWM_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command * containing CAM (Continuous Active Mode) indication. * @IWM_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a * single bound interface). * @IWM_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD * @IWM_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. * @IWM_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save * @IWM_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. * @IWM_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients * */ enum iwm_ucode_tlv_flag { IWM_UCODE_TLV_FLAGS_PAN = (1 << 0), IWM_UCODE_TLV_FLAGS_NEWSCAN = (1 << 1), IWM_UCODE_TLV_FLAGS_MFP = (1 << 2), IWM_UCODE_TLV_FLAGS_P2P = (1 << 3), IWM_UCODE_TLV_FLAGS_DW_BC_TABLE = (1 << 4), IWM_UCODE_TLV_FLAGS_NEWBT_COEX = (1 << 5), IWM_UCODE_TLV_FLAGS_PM_CMD_SUPPORT = (1 << 6), IWM_UCODE_TLV_FLAGS_SHORT_BL = (1 << 7), IWM_UCODE_TLV_FLAGS_RX_ENERGY_API = (1 << 8), IWM_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = (1 << 9), IWM_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = (1 << 10), IWM_UCODE_TLV_FLAGS_BF_UPDATED = (1 << 11), IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID = (1 << 12), IWM_UCODE_TLV_FLAGS_D3_CONTINUITY_API = (1 << 14), IWM_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = (1 << 15), IWM_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = (1 << 16), IWM_UCODE_TLV_FLAGS_SCHED_SCAN = (1 << 17), IWM_UCODE_TLV_FLAGS_STA_KEY_CMD = (1 << 19), IWM_UCODE_TLV_FLAGS_DEVICE_PS_CMD = (1 << 20), IWM_UCODE_TLV_FLAGS_P2P_PS = (1 << 21), IWM_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = (1 << 22), IWM_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM = (1 << 23), IWM_UCODE_TLV_FLAGS_UAPSD_SUPPORT = (1 << 24), IWM_UCODE_TLV_FLAGS_EBS_SUPPORT = (1 << 25), IWM_UCODE_TLV_FLAGS_P2P_PS_UAPSD = (1 << 26), IWM_UCODE_TLV_FLAGS_BCAST_FILTERING = (1 << 29), IWM_UCODE_TLV_FLAGS_GO_UAPSD = (1 << 30), IWM_UCODE_TLV_FLAGS_LTE_COEX = (1 << 31), }; #define IWM_UCODE_TLV_FLAG_BITS \ "\020\1PAN\2NEWSCAN\3MFP\4P2P\5DW_BC_TABLE\6NEWBT_COEX\7PM_CMD\10SHORT_BL\11RX_ENERG \ Y\12TIME_EVENT_V2\13D3_6_IPV6\14BF_UPDATED\15NO_BASIC_SSID\17D3_CONTINUITY\20NEW_NSOFF \ L_S\21NEW_NSOFFL_L\22SCHED_SCAN\24STA_KEY_CMD\25DEVICE_PS_CMD\26P2P_PS\27P2P_PS_DCM\30 \ P2P_PS_SCM\31UAPSD_SUPPORT\32EBS\33P2P_PS_UAPSD\36BCAST_FILTERING\37GO_UAPSD\40LTE_COEX" /** * enum iwm_ucode_tlv_api - ucode api * @IWM_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. * @IWM_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * @IWM_UCODE_TLV_API_WIDE_CMD_HDR: ucode supports wide command header * @IWM_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params * @IWM_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority * instead of 3. * @IWM_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size * (command version 3) that supports per-chain limits * * @IWM_NUM_UCODE_TLV_API: number of bits used */ enum iwm_ucode_tlv_api { IWM_UCODE_TLV_API_FRAGMENTED_SCAN = (1 << 8), IWM_UCODE_TLV_API_WIFI_MCC_UPDATE = (1 << 9), IWM_UCODE_TLV_API_WIDE_CMD_HDR = (1 << 14), IWM_UCODE_TLV_API_LQ_SS_PARAMS = (1 << 18), IWM_UCODE_TLV_API_EXT_SCAN_PRIORITY = (1 << 24), IWM_UCODE_TLV_API_TX_POWER_CHAIN = (1 << 27), IWM_NUM_UCODE_TLV_API = 32 }; #define IWM_UCODE_TLV_API_BITS \ "\020\10FRAGMENTED_SCAN\11WIFI_MCC_UPDATE\16WIDE_CMD_HDR\22LQ_SS_PARAMS\30EXT_SCAN_PRIO\33TX_POWER_CHAIN" /** * enum iwm_ucode_tlv_capa - ucode capabilities * @IWM_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 * @IWM_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory * @IWM_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. * @IWM_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer * @IWM_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM) * @IWM_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality * @IWM_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current * tx power value into TPC Report action frame and Link Measurement Report * action frame * @IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports updating current * channel in DS parameter set element in probe requests. * @IWM_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in * probe requests. * @IWM_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests * @IWM_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), * which also implies support for the scheduler configuration command * @IWM_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching * @IWM_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG: Consolidated D3-D0 image * @IWM_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command * @IWM_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command * @IWM_UCODE_TLV_CAPA_2G_COEX_SUPPORT: supports 2G coex Command * @IWM_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload * @IWM_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics * @IWM_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD * @IWM_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running * @IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different * sources for the MCC. This TLV bit is a future replacement to * IWM_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR * is supported. * @IWM_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC * @IWM_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan * @IWM_UCODE_TLV_CAPA_NAN_SUPPORT: supports NAN * @IWM_UCODE_TLV_CAPA_UMAC_UPLOAD: supports upload mode in umac (1=supported, * 0=no support) * @IWM_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement * @IWM_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts * @IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT * @IWM_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what * antenna the beacon should be transmitted * @IWM_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon * from AP and will send it upon d0i3 exit. * @IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2 * @IWM_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill * @IWM_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature * thresholds reporting * @IWM_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command * @IWM_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in * regular image. * @IWM_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared * memory addresses from the firmware. * @IWM_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement * @IWM_UCODE_TLV_CAPA_LMAC_UPLOAD: supports upload mode in lmac (1=supported, * 0=no support) * * @IWM_NUM_UCODE_TLV_CAPA: number of bits used */ enum iwm_ucode_tlv_capa { IWM_UCODE_TLV_CAPA_D0I3_SUPPORT = 0, IWM_UCODE_TLV_CAPA_LAR_SUPPORT = 1, IWM_UCODE_TLV_CAPA_UMAC_SCAN = 2, IWM_UCODE_TLV_CAPA_BEAMFORMER = 3, IWM_UCODE_TLV_CAPA_TOF_SUPPORT = 5, IWM_UCODE_TLV_CAPA_TDLS_SUPPORT = 6, IWM_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = 8, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = 9, IWM_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = 10, IWM_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = 11, IWM_UCODE_TLV_CAPA_DQA_SUPPORT = 12, IWM_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = 13, IWM_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG = 17, IWM_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = 18, IWM_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = 19, IWM_UCODE_TLV_CAPA_2G_COEX_SUPPORT = 20, IWM_UCODE_TLV_CAPA_CSUM_SUPPORT = 21, IWM_UCODE_TLV_CAPA_RADIO_BEACON_STATS = 22, IWM_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD = 26, IWM_UCODE_TLV_CAPA_BT_COEX_PLCR = 28, IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC = 29, IWM_UCODE_TLV_CAPA_BT_COEX_RRC = 30, IWM_UCODE_TLV_CAPA_GSCAN_SUPPORT = 31, IWM_UCODE_TLV_CAPA_NAN_SUPPORT = 34, IWM_UCODE_TLV_CAPA_UMAC_UPLOAD = 35, IWM_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = 64, IWM_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = 65, IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = 67, IWM_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT = 68, IWM_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = 71, IWM_UCODE_TLV_CAPA_BEACON_STORING = 72, IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = 73, IWM_UCODE_TLV_CAPA_CT_KILL_BY_FW = 74, IWM_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = 75, IWM_UCODE_TLV_CAPA_CTDP_SUPPORT = 76, IWM_UCODE_TLV_CAPA_USNIFFER_UNIFIED = 77, IWM_UCODE_TLV_CAPA_LMAC_UPLOAD = 79, IWM_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = 80, IWM_UCODE_TLV_CAPA_LQM_SUPPORT = 81, IWM_NUM_UCODE_TLV_CAPA = 128 }; /* The default calibrate table size if not specified by firmware file */ #define IWM_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 #define IWM_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 #define IWM_MAX_PHY_CALIBRATE_TBL_SIZE 253 /* The default max probe length if not specified by the firmware file */ #define IWM_DEFAULT_MAX_PROBE_LENGTH 200 /* * enumeration of ucode section. * This enumeration is used directly for older firmware (before 16.0). * For new firmware, there can be up to 4 sections (see below) but the * first one packaged into the firmware file is the DATA section and * some debugging code accesses that. */ enum iwm_ucode_sec { IWM_UCODE_SECTION_DATA, IWM_UCODE_SECTION_INST, }; /* * For 16.0 uCode and above, there is no differentiation between sections, * just an offset to the HW address. */ #define IWM_CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC #define IWM_PAGING_SEPARATOR_SECTION 0xAAAABBBB /* uCode version contains 4 values: Major/Minor/API/Serial */ #define IWM_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) #define IWM_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) #define IWM_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) #define IWM_UCODE_SERIAL(ver) ((ver) & 0x000000FF) /* * Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to * flow triggers. * @event_trigger: bitmap for which calibrations to perform according to * event triggers. */ struct iwm_tlv_calib_ctrl { uint32_t flow_trigger; uint32_t event_trigger; } __packed; enum iwm_fw_phy_cfg { IWM_FW_PHY_CFG_RADIO_TYPE_POS = 0, IWM_FW_PHY_CFG_RADIO_TYPE = 0x3 << IWM_FW_PHY_CFG_RADIO_TYPE_POS, IWM_FW_PHY_CFG_RADIO_STEP_POS = 2, IWM_FW_PHY_CFG_RADIO_STEP = 0x3 << IWM_FW_PHY_CFG_RADIO_STEP_POS, IWM_FW_PHY_CFG_RADIO_DASH_POS = 4, IWM_FW_PHY_CFG_RADIO_DASH = 0x3 << IWM_FW_PHY_CFG_RADIO_DASH_POS, IWM_FW_PHY_CFG_TX_CHAIN_POS = 16, IWM_FW_PHY_CFG_TX_CHAIN = 0xf << IWM_FW_PHY_CFG_TX_CHAIN_POS, IWM_FW_PHY_CFG_RX_CHAIN_POS = 20, IWM_FW_PHY_CFG_RX_CHAIN = 0xf << IWM_FW_PHY_CFG_RX_CHAIN_POS, }; #define IWM_UCODE_MAX_CS 1 /** * struct iwm_fw_cipher_scheme - a cipher scheme supported by FW. * @cipher: a cipher suite selector * @flags: cipher scheme flags (currently reserved for a future use) * @hdr_len: a size of MPDU security header * @pn_len: a size of PN * @pn_off: an offset of pn from the beginning of the security header * @key_idx_off: an offset of key index byte in the security header * @key_idx_mask: a bit mask of key_idx bits * @key_idx_shift: bit shift needed to get key_idx * @mic_len: mic length in bytes * @hw_cipher: a HW cipher index used in host commands */ struct iwm_fw_cipher_scheme { uint32_t cipher; uint8_t flags; uint8_t hdr_len; uint8_t pn_len; uint8_t pn_off; uint8_t key_idx_off; uint8_t key_idx_mask; uint8_t key_idx_shift; uint8_t mic_len; uint8_t hw_cipher; } __packed; /** * struct iwm_fw_cscheme_list - a cipher scheme list * @size: a number of entries * @cs: cipher scheme entries */ struct iwm_fw_cscheme_list { uint8_t size; struct iwm_fw_cipher_scheme cs[]; } __packed; /* * END iwl-fw.h */ /* * BEGIN iwl-fw-file.h */ /* v1/v2 uCode file layout */ struct iwm_ucode_header { uint32_t ver; /* major/minor/API/serial */ union { struct { uint32_t inst_size; /* bytes of runtime code */ uint32_t data_size; /* bytes of runtime data */ uint32_t init_size; /* bytes of init code */ uint32_t init_data_size; /* bytes of init data */ uint32_t boot_size; /* bytes of bootstrap code */ uint8_t data[0]; /* in same order as sizes */ } v1; struct { uint32_t build; /* build number */ uint32_t inst_size; /* bytes of runtime code */ uint32_t data_size; /* bytes of runtime data */ uint32_t init_size; /* bytes of init code */ uint32_t init_data_size; /* bytes of init data */ uint32_t boot_size; /* bytes of bootstrap code */ uint8_t data[0]; /* in same order as sizes */ } v2; } u; }; /* * new TLV uCode file layout * * The new TLV file format contains TLVs, that each specify * some piece of data. */ enum iwm_ucode_tlv_type { IWM_UCODE_TLV_INVALID = 0, /* unused */ IWM_UCODE_TLV_INST = 1, IWM_UCODE_TLV_DATA = 2, IWM_UCODE_TLV_INIT = 3, IWM_UCODE_TLV_INIT_DATA = 4, IWM_UCODE_TLV_BOOT = 5, IWM_UCODE_TLV_PROBE_MAX_LEN = 6, /* a uint32_t value */ IWM_UCODE_TLV_PAN = 7, IWM_UCODE_TLV_RUNT_EVTLOG_PTR = 8, IWM_UCODE_TLV_RUNT_EVTLOG_SIZE = 9, IWM_UCODE_TLV_RUNT_ERRLOG_PTR = 10, IWM_UCODE_TLV_INIT_EVTLOG_PTR = 11, IWM_UCODE_TLV_INIT_EVTLOG_SIZE = 12, IWM_UCODE_TLV_INIT_ERRLOG_PTR = 13, IWM_UCODE_TLV_ENHANCE_SENS_TBL = 14, IWM_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, IWM_UCODE_TLV_WOWLAN_INST = 16, IWM_UCODE_TLV_WOWLAN_DATA = 17, IWM_UCODE_TLV_FLAGS = 18, IWM_UCODE_TLV_SEC_RT = 19, IWM_UCODE_TLV_SEC_INIT = 20, IWM_UCODE_TLV_SEC_WOWLAN = 21, IWM_UCODE_TLV_DEF_CALIB = 22, IWM_UCODE_TLV_PHY_SKU = 23, IWM_UCODE_TLV_SECURE_SEC_RT = 24, IWM_UCODE_TLV_SECURE_SEC_INIT = 25, IWM_UCODE_TLV_SECURE_SEC_WOWLAN = 26, IWM_UCODE_TLV_NUM_OF_CPU = 27, IWM_UCODE_TLV_CSCHEME = 28, /* * Following two are not in our base tag, but allow * handling ucode version 9. */ IWM_UCODE_TLV_API_CHANGES_SET = 29, IWM_UCODE_TLV_ENABLED_CAPABILITIES = 30, IWM_UCODE_TLV_N_SCAN_CHANNELS = 31, IWM_UCODE_TLV_PAGING = 32, IWM_UCODE_TLV_SEC_RT_USNIFFER = 34, IWM_UCODE_TLV_SDIO_ADMA_ADDR = 35, IWM_UCODE_TLV_FW_VERSION = 36, IWM_UCODE_TLV_FW_DBG_DEST = 38, IWM_UCODE_TLV_FW_DBG_CONF = 39, IWM_UCODE_TLV_FW_DBG_TRIGGER = 40, IWM_UCODE_TLV_FW_GSCAN_CAPA = 50, }; struct iwm_ucode_tlv { uint32_t type; /* see above */ uint32_t length; /* not including type/length fields */ uint8_t data[0]; }; struct iwm_ucode_api { uint32_t api_index; uint32_t api_flags; } __packed; struct iwm_ucode_capa { uint32_t api_index; uint32_t api_capa; } __packed; #define IWM_TLV_UCODE_MAGIC 0x0a4c5749 struct iwm_tlv_ucode_header { /* * The TLV style ucode header is distinguished from * the v1/v2 style header by first four bytes being * zero, as such is an invalid combination of * major/minor/API/serial versions. */ uint32_t zero; uint32_t magic; uint8_t human_readable[64]; uint32_t ver; /* major/minor/API/serial */ uint32_t build; uint64_t ignore; /* * The data contained herein has a TLV layout, * see above for the TLV header and types. * Note that each TLV is padded to a length * that is a multiple of 4 for alignment. */ uint8_t data[0]; }; /* * END iwl-fw-file.h */ /* * BEGIN iwl-prph.h */ /* * Registers in this file are internal, not PCI bus memory mapped. * Driver accesses these via IWM_HBUS_TARG_PRPH_* registers. */ #define IWM_PRPH_BASE (0x00000) #define IWM_PRPH_END (0xFFFFF) /* APMG (power management) constants */ #define IWM_APMG_BASE (IWM_PRPH_BASE + 0x3000) #define IWM_APMG_CLK_CTRL_REG (IWM_APMG_BASE + 0x0000) #define IWM_APMG_CLK_EN_REG (IWM_APMG_BASE + 0x0004) #define IWM_APMG_CLK_DIS_REG (IWM_APMG_BASE + 0x0008) #define IWM_APMG_PS_CTRL_REG (IWM_APMG_BASE + 0x000c) #define IWM_APMG_PCIDEV_STT_REG (IWM_APMG_BASE + 0x0010) #define IWM_APMG_RFKILL_REG (IWM_APMG_BASE + 0x0014) #define IWM_APMG_RTC_INT_STT_REG (IWM_APMG_BASE + 0x001c) #define IWM_APMG_RTC_INT_MSK_REG (IWM_APMG_BASE + 0x0020) #define IWM_APMG_DIGITAL_SVR_REG (IWM_APMG_BASE + 0x0058) #define IWM_APMG_ANALOG_SVR_REG (IWM_APMG_BASE + 0x006C) #define IWM_APMS_CLK_VAL_MRB_FUNC_MODE (0x00000001) #define IWM_APMG_CLK_VAL_DMA_CLK_RQT (0x00000200) #define IWM_APMG_CLK_VAL_BSM_CLK_RQT (0x00000800) #define IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS (0x00400000) #define IWM_APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) #define IWM_APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) #define IWM_APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) #define IWM_APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) #define IWM_APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ #define IWM_APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) #define IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) #define IWM_APMG_RTC_INT_STT_RFKILL (0x10000000) /* Device system time */ #define IWM_DEVICE_SYSTEM_TIME_REG 0xA0206C /* Device NMI register */ #define IWM_DEVICE_SET_NMI_REG 0x00a01c30 #define IWM_DEVICE_SET_NMI_VAL_HW 0x01 #define IWM_DEVICE_SET_NMI_VAL_DRV 0x80 #define IWM_DEVICE_SET_NMI_8000_REG 0x00a01c24 #define IWM_DEVICE_SET_NMI_8000_VAL 0x1000000 /* * Device reset for family 8000 * write to bit 24 in order to reset the CPU */ #define IWM_RELEASE_CPU_RESET 0x300c #define IWM_RELEASE_CPU_RESET_BIT 0x1000000 /***************************************************************************** * 7000/3000 series SHR DTS addresses * *****************************************************************************/ #define IWM_SHR_MISC_WFM_DTS_EN (0x00a10024) #define IWM_DTSC_CFG_MODE (0x00a10604) #define IWM_DTSC_VREF_AVG (0x00a10648) #define IWM_DTSC_VREF5_AVG (0x00a1064c) #define IWM_DTSC_CFG_MODE_PERIODIC (0x2) #define IWM_DTSC_PTAT_AVG (0x00a10650) /** * Tx Scheduler * * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in * host DRAM. It steers each frame's Tx command (which contains the frame * data) into one of up to 7 prioritized Tx DMA FIFO channels within the * device. A queue maps to only one (selectable by driver) Tx DMA channel, * but one DMA channel may take input from several queues. * * Tx DMA FIFOs have dedicated purposes. * * For 5000 series and up, they are used differently * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): * * 0 -- EDCA BK (background) frames, lowest priority * 1 -- EDCA BE (best effort) frames, normal priority * 2 -- EDCA VI (video) frames, higher priority * 3 -- EDCA VO (voice) and management frames, highest priority * 4 -- unused * 5 -- unused * 6 -- unused * 7 -- Commands * * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. * In addition, driver can map the remaining queues to Tx DMA/FIFO * channels 0-3 to support 11n aggregation via EDCA DMA channels. * * The driver sets up each queue to work in one of two modes: * * 1) Scheduler-Ack, in which the scheduler automatically supports a * block-ack (BA) window of up to 64 TFDs. In this mode, each queue * contains TFDs for a unique combination of Recipient Address (RA) * and Traffic Identifier (TID), that is, traffic of a given * Quality-Of-Service (QOS) priority, destined for a single station. * * In scheduler-ack mode, the scheduler keeps track of the Tx status of * each frame within the BA window, including whether it's been transmitted, * and whether it's been acknowledged by the receiving station. The device * automatically processes block-acks received from the receiving STA, * and reschedules un-acked frames to be retransmitted (successful * Tx completion may end up being out-of-order). * * The driver must maintain the queue's Byte Count table in host DRAM * for this mode. * This mode does not support fragmentation. * * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. * The device may automatically retry Tx, but will retry only one frame * at a time, until receiving ACK from receiving station, or reaching * retry limit and giving up. * * The command queue (#4/#9) must use this mode! * This mode does not require use of the Byte Count table in host DRAM. * * Driver controls scheduler operation via 3 means: * 1) Scheduler registers * 2) Shared scheduler data base in internal SRAM * 3) Shared data in host DRAM * * Initialization: * * When loading, driver should allocate memory for: * 1) 16 TFD circular buffers, each with space for (typically) 256 TFDs. * 2) 16 Byte Count circular buffers in 16 KBytes contiguous memory * (1024 bytes for each queue). * * After receiving "Alive" response from uCode, driver must initialize * the scheduler (especially for queue #4/#9, the command queue, otherwise * the driver can't issue commands!): */ #define IWM_SCD_MEM_LOWER_BOUND (0x0000) /** * Max Tx window size is the max number of contiguous TFDs that the scheduler * can keep track of at one time when creating block-ack chains of frames. * Note that "64" matches the number of ack bits in a block-ack packet. */ #define IWM_SCD_WIN_SIZE 64 #define IWM_SCD_FRAME_LIMIT 64 #define IWM_SCD_TXFIFO_POS_TID (0) #define IWM_SCD_TXFIFO_POS_RA (4) #define IWM_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) /* agn SCD */ #define IWM_SCD_QUEUE_STTS_REG_POS_TXF (0) #define IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE (3) #define IWM_SCD_QUEUE_STTS_REG_POS_WSL (4) #define IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19) #define IWM_SCD_QUEUE_STTS_REG_MSK (0x017F0000) #define IWM_SCD_QUEUE_CTX_REG1_CREDIT_POS (8) #define IWM_SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) #define IWM_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) #define IWM_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) #define IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0) #define IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) #define IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) #define IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) #define IWM_SCD_GP_CTRL_ENABLE_31_QUEUES (1 << 0) #define IWM_SCD_GP_CTRL_AUTO_ACTIVE_MODE (1 << 18) /* Context Data */ #define IWM_SCD_CONTEXT_MEM_LOWER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x600) #define IWM_SCD_CONTEXT_MEM_UPPER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x6A0) /* Tx status */ #define IWM_SCD_TX_STTS_MEM_LOWER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x6A0) #define IWM_SCD_TX_STTS_MEM_UPPER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x7E0) /* Translation Data */ #define IWM_SCD_TRANS_TBL_MEM_LOWER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x7E0) #define IWM_SCD_TRANS_TBL_MEM_UPPER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x808) #define IWM_SCD_CONTEXT_QUEUE_OFFSET(x)\ (IWM_SCD_CONTEXT_MEM_LOWER_BOUND + ((x) * 8)) #define IWM_SCD_TX_STTS_QUEUE_OFFSET(x)\ (IWM_SCD_TX_STTS_MEM_LOWER_BOUND + ((x) * 16)) #define IWM_SCD_TRANS_TBL_OFFSET_QUEUE(x) \ ((IWM_SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc) #define IWM_SCD_BASE (IWM_PRPH_BASE + 0xa02c00) #define IWM_SCD_SRAM_BASE_ADDR (IWM_SCD_BASE + 0x0) #define IWM_SCD_DRAM_BASE_ADDR (IWM_SCD_BASE + 0x8) #define IWM_SCD_AIT (IWM_SCD_BASE + 0x0c) #define IWM_SCD_TXFACT (IWM_SCD_BASE + 0x10) #define IWM_SCD_ACTIVE (IWM_SCD_BASE + 0x14) #define IWM_SCD_QUEUECHAIN_SEL (IWM_SCD_BASE + 0xe8) #define IWM_SCD_CHAINEXT_EN (IWM_SCD_BASE + 0x244) #define IWM_SCD_AGGR_SEL (IWM_SCD_BASE + 0x248) #define IWM_SCD_INTERRUPT_MASK (IWM_SCD_BASE + 0x108) #define IWM_SCD_GP_CTRL (IWM_SCD_BASE + 0x1a8) #define IWM_SCD_EN_CTRL (IWM_SCD_BASE + 0x254) static inline unsigned int IWM_SCD_QUEUE_WRPTR(unsigned int chnl) { if (chnl < 20) return IWM_SCD_BASE + 0x18 + chnl * 4; return IWM_SCD_BASE + 0x284 + (chnl - 20) * 4; } static inline unsigned int IWM_SCD_QUEUE_RDPTR(unsigned int chnl) { if (chnl < 20) return IWM_SCD_BASE + 0x68 + chnl * 4; return IWM_SCD_BASE + 0x2B4 + (chnl - 20) * 4; } static inline unsigned int IWM_SCD_QUEUE_STATUS_BITS(unsigned int chnl) { if (chnl < 20) return IWM_SCD_BASE + 0x10c + chnl * 4; return IWM_SCD_BASE + 0x384 + (chnl - 20) * 4; } /*********************** END TX SCHEDULER *************************************/ /* Oscillator clock */ #define IWM_OSC_CLK (0xa04068) #define IWM_OSC_CLK_FORCE_CONTROL (0x8) /* * END iwl-prph.h */ /* * BEGIN iwl-fh.h */ /****************************/ /* Flow Handler Definitions */ /****************************/ /** * This I/O area is directly read/writable by driver (e.g. Linux uses writel()) * Addresses are offsets from device's PCI hardware base address. */ #define IWM_FH_MEM_LOWER_BOUND (0x1000) #define IWM_FH_MEM_UPPER_BOUND (0x2000) /** * Keep-Warm (KW) buffer base address. * * Driver must allocate a 4KByte buffer that is for keeping the * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency * DRAM access when doing Txing or Rxing. The dummy accesses prevent host * from going into a power-savings mode that would cause higher DRAM latency, * and possible data over/under-runs, before all Tx/Rx is complete. * * Driver loads IWM_FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) * of the buffer, which must be 4K aligned. Once this is set up, the device * automatically invokes keep-warm accesses when normal accesses might not * be sufficient to maintain fast DRAM response. * * Bit fields: * 31-0: Keep-warm buffer physical base address [35:4], must be 4K aligned */ #define IWM_FH_KW_MEM_ADDR_REG (IWM_FH_MEM_LOWER_BOUND + 0x97C) /** * TFD Circular Buffers Base (CBBC) addresses * * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) * (see struct iwm_tfd_frame). These 16 pointer registers are offset by 0x04 * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte * aligned (address bits 0-7 must be 0). * Later devices have 20 (5000 series) or 30 (higher) queues, but the registers * for them are in different places. * * Bit fields in each pointer register: * 27-0: TFD CB physical base address [35:8], must be 256-byte aligned */ #define IWM_FH_MEM_CBBC_0_15_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x9D0) #define IWM_FH_MEM_CBBC_0_15_UPPER_BOUN (IWM_FH_MEM_LOWER_BOUND + 0xA10) #define IWM_FH_MEM_CBBC_16_19_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xBF0) #define IWM_FH_MEM_CBBC_16_19_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xC00) #define IWM_FH_MEM_CBBC_20_31_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xB20) #define IWM_FH_MEM_CBBC_20_31_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xB80) /* Find TFD CB base pointer for given queue */ static inline unsigned int IWM_FH_MEM_CBBC_QUEUE(unsigned int chnl) { if (chnl < 16) return IWM_FH_MEM_CBBC_0_15_LOWER_BOUND + 4 * chnl; if (chnl < 20) return IWM_FH_MEM_CBBC_16_19_LOWER_BOUND + 4 * (chnl - 16); return IWM_FH_MEM_CBBC_20_31_LOWER_BOUND + 4 * (chnl - 20); } /** * Rx SRAM Control and Status Registers (RSCSR) * * These registers provide handshake between driver and device for the Rx queue * (this queue handles *all* command responses, notifications, Rx data, etc. * sent from uCode to host driver). Unlike Tx, there is only one Rx * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 * mapping between RBDs and RBs. * * Driver must allocate host DRAM memory for the following, and set the * physical address of each into device registers: * * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 * entries (although any power of 2, up to 4096, is selectable by driver). * Each entry (1 dword) points to a receive buffer (RB) of consistent size * (typically 4K, although 8K or 16K are also selectable by driver). * Driver sets up RB size and number of RBDs in the CB via Rx config * register IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG. * * Bit fields within one RBD: * 27-0: Receive Buffer physical address bits [35:8], 256-byte aligned * * Driver sets physical address [35:8] of base of RBD circular buffer * into IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. * * 2) Rx status buffer, 8 bytes, in which uCode indicates which Rx Buffers * (RBs) have been filled, via a "write pointer", actually the index of * the RB's corresponding RBD within the circular buffer. Driver sets * physical address [35:4] into IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. * * Bit fields in lower dword of Rx status buffer (upper dword not used * by driver: * 31-12: Not used by driver * 11- 0: Index of last filled Rx buffer descriptor * (device writes, driver reads this value) * * As the driver prepares Receive Buffers (RBs) for device to fill, driver must * enter pointers to these RBs into contiguous RBD circular buffer entries, * and update the device's "write" index register, * IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG. * * This "write" index corresponds to the *next* RBD that the driver will make * available, i.e. one RBD past the tail of the ready-to-fill RBDs within * the circular buffer. This value should initially be 0 (before preparing any * RBs), should be 8 after preparing the first 8 RBs (for example), and must * wrap back to 0 at the end of the circular buffer (but don't wrap before * "read" index has advanced past 1! See below). * NOTE: DEVICE EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. * * As the device fills RBs (referenced from contiguous RBDs within the circular * buffer), it updates the Rx status buffer in host DRAM, 2) described above, * to tell the driver the index of the latest filled RBD. The driver must * read this "read" index from DRAM after receiving an Rx interrupt from device * * The driver must also internally keep track of a third index, which is the * next RBD to process. When receiving an Rx interrupt, driver should process * all filled but unprocessed RBs up to, but not including, the RB * corresponding to the "read" index. For example, if "read" index becomes "1", * driver may process the RB pointed to by RBD 0. Depending on volume of * traffic, there may be many RBs to process. * * If read index == write index, device thinks there is no room to put new data. * Due to this, the maximum number of filled RBs is 255, instead of 256. To * be safe, make sure that there is a gap of at least 2 RBDs between "write" * and "read" indexes; that is, make sure that there are no more than 254 * buffers waiting to be filled. */ #define IWM_FH_MEM_RSCSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xBC0) #define IWM_FH_MEM_RSCSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xC00) #define IWM_FH_MEM_RSCSR_CHNL0 (IWM_FH_MEM_RSCSR_LOWER_BOUND) /** * Physical base address of 8-byte Rx Status buffer. * Bit fields: * 31-0: Rx status buffer physical base address [35:4], must 16-byte aligned. */ #define IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG (IWM_FH_MEM_RSCSR_CHNL0) /** * Physical base address of Rx Buffer Descriptor Circular Buffer. * Bit fields: * 27-0: RBD CD physical base address [35:8], must be 256-byte aligned. */ #define IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG (IWM_FH_MEM_RSCSR_CHNL0 + 0x004) /** * Rx write pointer (index, really!). * Bit fields: * 11-0: Index of driver's most recent prepared-to-be-filled RBD, + 1. * NOTE: For 256-entry circular buffer, use only bits [7:0]. */ #define IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG (IWM_FH_MEM_RSCSR_CHNL0 + 0x008) #define IWM_FH_RSCSR_CHNL0_WPTR (IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG) #define IWM_FW_RSCSR_CHNL0_RXDCB_RDPTR_REG (IWM_FH_MEM_RSCSR_CHNL0 + 0x00c) #define IWM_FH_RSCSR_CHNL0_RDPTR IWM_FW_RSCSR_CHNL0_RXDCB_RDPTR_REG /** * Rx Config/Status Registers (RCSR) * Rx Config Reg for channel 0 (only channel used) * * Driver must initialize IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for * normal operation (see bit fields). * * Clearing IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA. * Driver should poll IWM_FH_MEM_RSSR_RX_STATUS_REG for * IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing. * * Bit fields: * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame, * '10' operate normally * 29-24: reserved * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal), * min "5" for 32 RBDs, max "12" for 4096 RBDs. * 19-18: reserved * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K, * '10' 12K, '11' 16K. * 15-14: reserved * 13-12: IRQ destination; '00' none, '01' host driver (normal operation) * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec) * typical value 0x10 (about 1/2 msec) * 3- 0: reserved */ #define IWM_FH_MEM_RCSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xC00) #define IWM_FH_MEM_RCSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xCC0) #define IWM_FH_MEM_RCSR_CHNL0 (IWM_FH_MEM_RCSR_LOWER_BOUND) #define IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG (IWM_FH_MEM_RCSR_CHNL0) #define IWM_FH_MEM_RCSR_CHNL0_RBDCB_WPTR (IWM_FH_MEM_RCSR_CHNL0 + 0x8) #define IWM_FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ (IWM_FH_MEM_RCSR_CHNL0 + 0x10) #define IWM_FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK (0x00001000) /* bits 12 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK (0x00008000) /* bit 15 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MSK (0x00030000) /* bits 16-17 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MSK (0x00F00000) /* bits 20-23 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MSK (0xC0000000) /* bits 30-31*/ #define IWM_FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS (20) #define IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS (4) #define IWM_RX_RB_TIMEOUT (0x11) #define IWM_FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) #define IWM_FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) #define IWM_FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) #define IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) #define IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K (0x00010000) #define IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000) #define IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000) #define IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY (0x00000004) #define IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) #define IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) /** * Rx Shared Status Registers (RSSR) * * After stopping Rx DMA channel (writing 0 to * IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG), driver must poll * IWM_FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle. * * Bit fields: * 24: 1 = Channel 0 is idle * * IWM_FH_MEM_RSSR_SHARED_CTRL_REG and IWM_FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV * contain default values that should not be altered by the driver. */ #define IWM_FH_MEM_RSSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xC40) #define IWM_FH_MEM_RSSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xD00) #define IWM_FH_MEM_RSSR_SHARED_CTRL_REG (IWM_FH_MEM_RSSR_LOWER_BOUND) #define IWM_FH_MEM_RSSR_RX_STATUS_REG (IWM_FH_MEM_RSSR_LOWER_BOUND + 0x004) #define IWM_FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV\ (IWM_FH_MEM_RSSR_LOWER_BOUND + 0x008) #define IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) #define IWM_FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 /* TFDB Area - TFDs buffer table */ #define IWM_FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) #define IWM_FH_TFDIB_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x900) #define IWM_FH_TFDIB_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x958) #define IWM_FH_TFDIB_CTRL0_REG(_chnl) (IWM_FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) #define IWM_FH_TFDIB_CTRL1_REG(_chnl) (IWM_FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) /** * Transmit DMA Channel Control/Status Registers (TCSR) * * Device has one configuration register for each of 8 Tx DMA/FIFO channels * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. * * To use a Tx DMA channel, driver must initialize its * IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with: * * IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | * IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL * * All other bits should be 0. * * Bit fields: * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame, * '10' operate normally * 29- 4: Reserved, set to "0" * 3: Enable internal DMA requests (1, normal operation), disable (0) * 2- 0: Reserved, set to "0" */ #define IWM_FH_TCSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xD00) #define IWM_FH_TCSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xE60) /* Find Control/Status reg for given Tx DMA/FIFO channel */ #define IWM_FH_TCSR_CHNL_NUM (8) /* TCSR: tx_config register values */ #define IWM_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ (IWM_FH_TCSR_LOWER_BOUND + 0x20 * (_chnl)) #define IWM_FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ (IWM_FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ (IWM_FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV (0x00000001) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE (0x00000008) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) /** * Tx Shared Status Registers (TSSR) * * After stopping Tx DMA channel (writing 0 to * IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll * IWM_FH_TSSR_TX_STATUS_REG until selected Tx channel is idle * (channel's buffers empty | no pending requests). * * Bit fields: * 31-24: 1 = Channel buffers empty (channel 7:0) * 23-16: 1 = No pending requests (channel 7:0) */ #define IWM_FH_TSSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xEA0) #define IWM_FH_TSSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xEC0) #define IWM_FH_TSSR_TX_STATUS_REG (IWM_FH_TSSR_LOWER_BOUND + 0x010) /** * Bit fields for TSSR(Tx Shared Status & Control) error status register: * 31: Indicates an address error when accessed to internal memory * uCode/driver must write "1" in order to clear this flag * 30: Indicates that Host did not send the expected number of dwords to FH * uCode/driver must write "1" in order to clear this flag * 16-9:Each status bit is for one channel. Indicates that an (Error) ActDMA * command was received from the scheduler while the TRB was already full * with previous command * uCode/driver must write "1" in order to clear this flag * 7-0: Each status bit indicates a channel's TxCredit error. When an error * bit is set, it indicates that the FH has received a full indication * from the RTC TxFIFO and the current value of the TxCredit counter was * not equal to zero. This mean that the credit mechanism was not * synchronized to the TxFIFO status * uCode/driver must write "1" in order to clear this flag */ #define IWM_FH_TSSR_TX_ERROR_REG (IWM_FH_TSSR_LOWER_BOUND + 0x018) #define IWM_FH_TSSR_TX_MSG_CONFIG_REG (IWM_FH_TSSR_LOWER_BOUND + 0x008) #define IWM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16) /* Tx service channels */ #define IWM_FH_SRVC_CHNL (9) #define IWM_FH_SRVC_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x9C8) #define IWM_FH_SRVC_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x9D0) #define IWM_FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ (IWM_FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4) #define IWM_FH_TX_CHICKEN_BITS_REG (IWM_FH_MEM_LOWER_BOUND + 0xE98) #define IWM_FH_TX_TRB_REG(_chan) (IWM_FH_MEM_LOWER_BOUND + 0x958 + \ (_chan) * 4) /* Instruct FH to increment the retry count of a packet when * it is brought from the memory to TX-FIFO */ #define IWM_FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002) #define IWM_RX_QUEUE_SIZE 256 #define IWM_RX_QUEUE_MASK 255 #define IWM_RX_QUEUE_SIZE_LOG 8 /* * RX related structures and functions */ #define IWM_RX_FREE_BUFFERS 64 #define IWM_RX_LOW_WATERMARK 8 /** * struct iwm_rb_status - reseve buffer status * host memory mapped FH registers * @closed_rb_num [0:11] - Indicates the index of the RB which was closed * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed * @finished_rb_num [0:11] - Indicates the index of the current RB * in which the last frame was written to * @finished_fr_num [0:11] - Indicates the index of the RX Frame * which was transferred */ struct iwm_rb_status { uint16_t closed_rb_num; uint16_t closed_fr_num; uint16_t finished_rb_num; uint16_t finished_fr_nam; uint32_t unused; } __packed; #define IWM_TFD_QUEUE_SIZE_MAX (256) #define IWM_TFD_QUEUE_SIZE_BC_DUP (64) #define IWM_TFD_QUEUE_BC_SIZE (IWM_TFD_QUEUE_SIZE_MAX + \ IWM_TFD_QUEUE_SIZE_BC_DUP) #define IWM_TX_DMA_MASK DMA_BIT_MASK(36) #define IWM_NUM_OF_TBS 20 static inline uint8_t iwm_get_dma_hi_addr(bus_addr_t addr) { return (sizeof(addr) > sizeof(uint32_t) ? (addr >> 16) >> 16 : 0) & 0xF; } /** * struct iwm_tfd_tb transmit buffer descriptor within transmit frame descriptor * * This structure contains dma address and length of transmission address * * @lo: low [31:0] portion of the dma address of TX buffer * every even is unaligned on 16 bit boundary * @hi_n_len 0-3 [35:32] portion of dma * 4-15 length of the tx buffer */ struct iwm_tfd_tb { uint32_t lo; uint16_t hi_n_len; } __packed; /** * struct iwm_tfd * * Transmit Frame Descriptor (TFD) * * @ __reserved1[3] reserved * @ num_tbs 0-4 number of active tbs * 5 reserved * 6-7 padding (not used) * @ tbs[20] transmit frame buffer descriptors * @ __pad padding * * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. * Both driver and device share these circular buffers, each of which must be * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes * * Driver must indicate the physical address of the base of each * circular buffer via the IWM_FH_MEM_CBBC_QUEUE registers. * * Each TFD contains pointer/size information for up to 20 data buffers * in host DRAM. These buffers collectively contain the (one) frame described * by the TFD. Each buffer must be a single contiguous block of memory within * itself, but buffers may be scattered in host DRAM. Each buffer has max size * of (4K - 4). The concatenates all of a TFD's buffers into a single * Tx frame, up to 8 KBytes in size. * * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. */ struct iwm_tfd { uint8_t __reserved1[3]; uint8_t num_tbs; struct iwm_tfd_tb tbs[IWM_NUM_OF_TBS]; uint32_t __pad; } __packed; /* Keep Warm Size */ #define IWM_KW_SIZE 0x1000 /* 4k */ /* Fixed (non-configurable) rx data from phy */ /** * struct iwm_agn_schedq_bc_tbl scheduler byte count table * base physical address provided by IWM_SCD_DRAM_BASE_ADDR * @tfd_offset 0-12 - tx command byte count * 12-16 - station index */ struct iwm_agn_scd_bc_tbl { uint16_t tfd_offset[IWM_TFD_QUEUE_BC_SIZE]; } __packed; /* * END iwl-fh.h */ /* * BEGIN mvm/fw-api.h */ /* Maximum number of Tx queues. */ #define IWM_MVM_MAX_QUEUES 31 /* Tx queue numbers */ enum { IWM_MVM_OFFCHANNEL_QUEUE = 8, IWM_MVM_CMD_QUEUE = 9, IWM_MVM_AUX_QUEUE = 15, }; enum iwm_mvm_tx_fifo { IWM_MVM_TX_FIFO_BK = 0, IWM_MVM_TX_FIFO_BE, IWM_MVM_TX_FIFO_VI, IWM_MVM_TX_FIFO_VO, IWM_MVM_TX_FIFO_MCAST = 5, IWM_MVM_TX_FIFO_CMD = 7, }; #define IWM_MVM_STATION_COUNT 16 /* commands */ enum { IWM_MVM_ALIVE = 0x1, IWM_REPLY_ERROR = 0x2, IWM_INIT_COMPLETE_NOTIF = 0x4, /* PHY context commands */ IWM_PHY_CONTEXT_CMD = 0x8, IWM_DBG_CFG = 0x9, /* UMAC scan commands */ IWM_SCAN_ITERATION_COMPLETE_UMAC = 0xb5, IWM_SCAN_CFG_CMD = 0xc, IWM_SCAN_REQ_UMAC = 0xd, IWM_SCAN_ABORT_UMAC = 0xe, IWM_SCAN_COMPLETE_UMAC = 0xf, /* station table */ IWM_ADD_STA_KEY = 0x17, IWM_ADD_STA = 0x18, IWM_REMOVE_STA = 0x19, /* TX */ IWM_TX_CMD = 0x1c, IWM_TXPATH_FLUSH = 0x1e, IWM_MGMT_MCAST_KEY = 0x1f, /* scheduler config */ IWM_SCD_QUEUE_CFG = 0x1d, /* global key */ IWM_WEP_KEY = 0x20, /* MAC and Binding commands */ IWM_MAC_CONTEXT_CMD = 0x28, IWM_TIME_EVENT_CMD = 0x29, /* both CMD and response */ IWM_TIME_EVENT_NOTIFICATION = 0x2a, IWM_BINDING_CONTEXT_CMD = 0x2b, IWM_TIME_QUOTA_CMD = 0x2c, IWM_NON_QOS_TX_COUNTER_CMD = 0x2d, IWM_LQ_CMD = 0x4e, /* Calibration */ IWM_TEMPERATURE_NOTIFICATION = 0x62, IWM_CALIBRATION_CFG_CMD = 0x65, IWM_CALIBRATION_RES_NOTIFICATION = 0x66, IWM_CALIBRATION_COMPLETE_NOTIFICATION = 0x67, IWM_RADIO_VERSION_NOTIFICATION = 0x68, /* Scan offload */ IWM_SCAN_OFFLOAD_REQUEST_CMD = 0x51, IWM_SCAN_OFFLOAD_ABORT_CMD = 0x52, IWM_HOT_SPOT_CMD = 0x53, IWM_SCAN_OFFLOAD_COMPLETE = 0x6d, IWM_SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6e, IWM_SCAN_OFFLOAD_CONFIG_CMD = 0x6f, IWM_MATCH_FOUND_NOTIFICATION = 0xd9, IWM_SCAN_ITERATION_COMPLETE = 0xe7, /* Phy */ IWM_PHY_CONFIGURATION_CMD = 0x6a, IWM_CALIB_RES_NOTIF_PHY_DB = 0x6b, /* IWM_PHY_DB_CMD = 0x6c, */ /* Power - legacy power table command */ IWM_POWER_TABLE_CMD = 0x77, IWM_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, /* Thermal Throttling*/ IWM_REPLY_THERMAL_MNG_BACKOFF = 0x7e, /* Scanning */ IWM_SCAN_ABORT_CMD = 0x81, IWM_SCAN_START_NOTIFICATION = 0x82, IWM_SCAN_RESULTS_NOTIFICATION = 0x83, /* NVM */ IWM_NVM_ACCESS_CMD = 0x88, IWM_SET_CALIB_DEFAULT_CMD = 0x8e, IWM_BEACON_NOTIFICATION = 0x90, IWM_BEACON_TEMPLATE_CMD = 0x91, IWM_TX_ANT_CONFIGURATION_CMD = 0x98, IWM_BT_CONFIG = 0x9b, IWM_STATISTICS_NOTIFICATION = 0x9d, IWM_REDUCE_TX_POWER_CMD = 0x9f, /* RF-KILL commands and notifications */ IWM_CARD_STATE_CMD = 0xa0, IWM_CARD_STATE_NOTIFICATION = 0xa1, IWM_MISSED_BEACONS_NOTIFICATION = 0xa2, IWM_MFUART_LOAD_NOTIFICATION = 0xb1, /* Power - new power table command */ IWM_MAC_PM_POWER_TABLE = 0xa9, IWM_REPLY_RX_PHY_CMD = 0xc0, IWM_REPLY_RX_MPDU_CMD = 0xc1, IWM_BA_NOTIF = 0xc5, /* Location Aware Regulatory */ IWM_MCC_UPDATE_CMD = 0xc8, IWM_MCC_CHUB_UPDATE_CMD = 0xc9, /* BT Coex */ IWM_BT_COEX_PRIO_TABLE = 0xcc, IWM_BT_COEX_PROT_ENV = 0xcd, IWM_BT_PROFILE_NOTIFICATION = 0xce, IWM_BT_COEX_CI = 0x5d, IWM_REPLY_SF_CFG_CMD = 0xd1, IWM_REPLY_BEACON_FILTERING_CMD = 0xd2, /* DTS measurements */ IWM_CMD_DTS_MEASUREMENT_TRIGGER = 0xdc, IWM_DTS_MEASUREMENT_NOTIFICATION = 0xdd, IWM_REPLY_DEBUG_CMD = 0xf0, IWM_DEBUG_LOG_MSG = 0xf7, IWM_MCAST_FILTER_CMD = 0xd0, /* D3 commands/notifications */ IWM_D3_CONFIG_CMD = 0xd3, IWM_PROT_OFFLOAD_CONFIG_CMD = 0xd4, IWM_OFFLOADS_QUERY_CMD = 0xd5, IWM_REMOTE_WAKE_CONFIG_CMD = 0xd6, /* for WoWLAN in particular */ IWM_WOWLAN_PATTERNS = 0xe0, IWM_WOWLAN_CONFIGURATION = 0xe1, IWM_WOWLAN_TSC_RSC_PARAM = 0xe2, IWM_WOWLAN_TKIP_PARAM = 0xe3, IWM_WOWLAN_KEK_KCK_MATERIAL = 0xe4, IWM_WOWLAN_GET_STATUSES = 0xe5, IWM_WOWLAN_TX_POWER_PER_DB = 0xe6, /* and for NetDetect */ IWM_NET_DETECT_CONFIG_CMD = 0x54, IWM_NET_DETECT_PROFILES_QUERY_CMD = 0x56, IWM_NET_DETECT_PROFILES_CMD = 0x57, IWM_NET_DETECT_HOTSPOTS_CMD = 0x58, IWM_NET_DETECT_HOTSPOTS_QUERY_CMD = 0x59, IWM_REPLY_MAX = 0xff, }; /** * struct iwm_cmd_response - generic response struct for most commands * @status: status of the command asked, changes for each one */ struct iwm_cmd_response { uint32_t status; }; /* * struct iwm_tx_ant_cfg_cmd * @valid: valid antenna configuration */ struct iwm_tx_ant_cfg_cmd { uint32_t valid; } __packed; /** * struct iwm_reduce_tx_power_cmd - TX power reduction command * IWM_REDUCE_TX_POWER_CMD = 0x9f * @flags: (reserved for future implementation) * @mac_context_id: id of the mac ctx for which we are reducing TX power. * @pwr_restriction: TX power restriction in dBms. */ struct iwm_reduce_tx_power_cmd { uint8_t flags; uint8_t mac_context_id; uint16_t pwr_restriction; } __packed; /* IWM_TX_REDUCED_POWER_API_S_VER_1 */ /* * Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to * flow triggers. * @event_trigger: bitmap for which calibrations to perform according to * event triggers. */ struct iwm_calib_ctrl { uint32_t flow_trigger; uint32_t event_trigger; } __packed; /* This enum defines the bitmap of various calibrations to enable in both * init ucode and runtime ucode through IWM_CALIBRATION_CFG_CMD. */ enum iwm_calib_cfg { IWM_CALIB_CFG_XTAL_IDX = (1 << 0), IWM_CALIB_CFG_TEMPERATURE_IDX = (1 << 1), IWM_CALIB_CFG_VOLTAGE_READ_IDX = (1 << 2), IWM_CALIB_CFG_PAPD_IDX = (1 << 3), IWM_CALIB_CFG_TX_PWR_IDX = (1 << 4), IWM_CALIB_CFG_DC_IDX = (1 << 5), IWM_CALIB_CFG_BB_FILTER_IDX = (1 << 6), IWM_CALIB_CFG_LO_LEAKAGE_IDX = (1 << 7), IWM_CALIB_CFG_TX_IQ_IDX = (1 << 8), IWM_CALIB_CFG_TX_IQ_SKEW_IDX = (1 << 9), IWM_CALIB_CFG_RX_IQ_IDX = (1 << 10), IWM_CALIB_CFG_RX_IQ_SKEW_IDX = (1 << 11), IWM_CALIB_CFG_SENSITIVITY_IDX = (1 << 12), IWM_CALIB_CFG_CHAIN_NOISE_IDX = (1 << 13), IWM_CALIB_CFG_DISCONNECTED_ANT_IDX = (1 << 14), IWM_CALIB_CFG_ANT_COUPLING_IDX = (1 << 15), IWM_CALIB_CFG_DAC_IDX = (1 << 16), IWM_CALIB_CFG_ABS_IDX = (1 << 17), IWM_CALIB_CFG_AGC_IDX = (1 << 18), }; /* * Phy configuration command. */ struct iwm_phy_cfg_cmd { uint32_t phy_cfg; struct iwm_calib_ctrl calib_control; } __packed; #define IWM_PHY_CFG_RADIO_TYPE ((1 << 0) | (1 << 1)) #define IWM_PHY_CFG_RADIO_STEP ((1 << 2) | (1 << 3)) #define IWM_PHY_CFG_RADIO_DASH ((1 << 4) | (1 << 5)) #define IWM_PHY_CFG_PRODUCT_NUMBER ((1 << 6) | (1 << 7)) #define IWM_PHY_CFG_TX_CHAIN_A (1 << 8) #define IWM_PHY_CFG_TX_CHAIN_B (1 << 9) #define IWM_PHY_CFG_TX_CHAIN_C (1 << 10) #define IWM_PHY_CFG_RX_CHAIN_A (1 << 12) #define IWM_PHY_CFG_RX_CHAIN_B (1 << 13) #define IWM_PHY_CFG_RX_CHAIN_C (1 << 14) -/* - * PHY db - */ -enum iwm_phy_db_section_type { - IWM_PHY_DB_CFG = 1, - IWM_PHY_DB_CALIB_NCH, - IWM_PHY_DB_UNUSED, - IWM_PHY_DB_CALIB_CHG_PAPD, - IWM_PHY_DB_CALIB_CHG_TXP, - IWM_PHY_DB_MAX -}; - -#define IWM_PHY_DB_CMD 0x6c /* TEMP API - The actual is 0x8c */ - -/* - * phy db - configure operational ucode - */ -struct iwm_phy_db_cmd { - uint16_t type; - uint16_t length; - uint8_t data[]; -} __packed; - -/* for parsing of tx power channel group data that comes from the firmware */ -struct iwm_phy_db_chg_txp { - uint32_t space; - uint16_t max_channel_idx; -} __packed; - -/* - * phy db - Receive phy db chunk after calibrations - */ -struct iwm_calib_res_notif_phy_db { - uint16_t type; - uint16_t length; - uint8_t data[]; -} __packed; - - /* Target of the IWM_NVM_ACCESS_CMD */ enum { IWM_NVM_ACCESS_TARGET_CACHE = 0, IWM_NVM_ACCESS_TARGET_OTP = 1, IWM_NVM_ACCESS_TARGET_EEPROM = 2, }; /* Section types for IWM_NVM_ACCESS_CMD */ enum { - IWM_NVM_SECTION_TYPE_HW = 0, - IWM_NVM_SECTION_TYPE_SW, - IWM_NVM_SECTION_TYPE_PAPD, - IWM_NVM_SECTION_TYPE_REGULATORY, - IWM_NVM_SECTION_TYPE_CALIBRATION, - IWM_NVM_SECTION_TYPE_PRODUCTION, - IWM_NVM_SECTION_TYPE_POST_FCS_CALIB, - /* 7, 8, 9 unknown */ - IWM_NVM_SECTION_TYPE_HW_8000 = 10, - IWM_NVM_SECTION_TYPE_MAC_OVERRIDE, - IWM_NVM_SECTION_TYPE_PHY_SKU, - IWM_NVM_NUM_OF_SECTIONS, + IWM_NVM_SECTION_TYPE_SW = 1, + IWM_NVM_SECTION_TYPE_REGULATORY = 3, + IWM_NVM_SECTION_TYPE_CALIBRATION = 4, + IWM_NVM_SECTION_TYPE_PRODUCTION = 5, + IWM_NVM_SECTION_TYPE_MAC_OVERRIDE = 11, + IWM_NVM_SECTION_TYPE_PHY_SKU = 12, + IWM_NVM_MAX_NUM_SECTIONS = 13, }; /** * struct iwm_nvm_access_cmd_ver2 - Request the device to send an NVM section * @op_code: 0 - read, 1 - write * @target: IWM_NVM_ACCESS_TARGET_* * @type: IWM_NVM_SECTION_TYPE_* * @offset: offset in bytes into the section * @length: in bytes, to read/write * @data: if write operation, the data to write. On read its empty */ struct iwm_nvm_access_cmd { uint8_t op_code; uint8_t target; uint16_t type; uint16_t offset; uint16_t length; uint8_t data[]; } __packed; /* IWM_NVM_ACCESS_CMD_API_S_VER_2 */ /** * struct iwm_nvm_access_resp_ver2 - response to IWM_NVM_ACCESS_CMD * @offset: offset in bytes into the section * @length: in bytes, either how much was written or read * @type: IWM_NVM_SECTION_TYPE_* * @status: 0 for success, fail otherwise * @data: if read operation, the data returned. Empty on write. */ struct iwm_nvm_access_resp { uint16_t offset; uint16_t length; uint16_t type; uint16_t status; uint8_t data[]; } __packed; /* IWM_NVM_ACCESS_CMD_RESP_API_S_VER_2 */ /* IWM_MVM_ALIVE 0x1 */ /* alive response is_valid values */ #define IWM_ALIVE_RESP_UCODE_OK (1 << 0) #define IWM_ALIVE_RESP_RFKILL (1 << 1) /* alive response ver_type values */ enum { IWM_FW_TYPE_HW = 0, IWM_FW_TYPE_PROT = 1, IWM_FW_TYPE_AP = 2, IWM_FW_TYPE_WOWLAN = 3, IWM_FW_TYPE_TIMING = 4, IWM_FW_TYPE_WIPAN = 5 }; /* alive response ver_subtype values */ enum { IWM_FW_SUBTYPE_FULL_FEATURE = 0, IWM_FW_SUBTYPE_BOOTSRAP = 1, /* Not valid */ IWM_FW_SUBTYPE_REDUCED = 2, IWM_FW_SUBTYPE_ALIVE_ONLY = 3, IWM_FW_SUBTYPE_WOWLAN = 4, IWM_FW_SUBTYPE_AP_SUBTYPE = 5, IWM_FW_SUBTYPE_WIPAN = 6, IWM_FW_SUBTYPE_INITIALIZE = 9 }; #define IWM_ALIVE_STATUS_ERR 0xDEAD #define IWM_ALIVE_STATUS_OK 0xCAFE #define IWM_ALIVE_FLG_RFKILL (1 << 0) struct iwm_mvm_alive_resp_v1 { uint16_t status; uint16_t flags; uint8_t ucode_minor; uint8_t ucode_major; uint16_t id; uint8_t api_minor; uint8_t api_major; uint8_t ver_subtype; uint8_t ver_type; uint8_t mac; uint8_t opt; uint16_t reserved2; uint32_t timestamp; uint32_t error_event_table_ptr; /* SRAM address for error log */ uint32_t log_event_table_ptr; /* SRAM address for event log */ uint32_t cpu_register_ptr; uint32_t dbgm_config_ptr; uint32_t alive_counter_ptr; uint32_t scd_base_ptr; /* SRAM address for SCD */ } __packed; /* IWM_ALIVE_RES_API_S_VER_1 */ struct iwm_mvm_alive_resp_v2 { uint16_t status; uint16_t flags; uint8_t ucode_minor; uint8_t ucode_major; uint16_t id; uint8_t api_minor; uint8_t api_major; uint8_t ver_subtype; uint8_t ver_type; uint8_t mac; uint8_t opt; uint16_t reserved2; uint32_t timestamp; uint32_t error_event_table_ptr; /* SRAM address for error log */ uint32_t log_event_table_ptr; /* SRAM address for LMAC event log */ uint32_t cpu_register_ptr; uint32_t dbgm_config_ptr; uint32_t alive_counter_ptr; uint32_t scd_base_ptr; /* SRAM address for SCD */ uint32_t st_fwrd_addr; /* pointer to Store and forward */ uint32_t st_fwrd_size; uint8_t umac_minor; /* UMAC version: minor */ uint8_t umac_major; /* UMAC version: major */ uint16_t umac_id; /* UMAC version: id */ uint32_t error_info_addr; /* SRAM address for UMAC error log */ uint32_t dbg_print_buff_addr; } __packed; /* ALIVE_RES_API_S_VER_2 */ struct iwm_mvm_alive_resp_v3 { uint16_t status; uint16_t flags; uint32_t ucode_minor; uint32_t ucode_major; uint8_t ver_subtype; uint8_t ver_type; uint8_t mac; uint8_t opt; uint32_t timestamp; uint32_t error_event_table_ptr; /* SRAM address for error log */ uint32_t log_event_table_ptr; /* SRAM address for LMAC event log */ uint32_t cpu_register_ptr; uint32_t dbgm_config_ptr; uint32_t alive_counter_ptr; uint32_t scd_base_ptr; /* SRAM address for SCD */ uint32_t st_fwrd_addr; /* pointer to Store and forward */ uint32_t st_fwrd_size; uint32_t umac_minor; /* UMAC version: minor */ uint32_t umac_major; /* UMAC version: major */ uint32_t error_info_addr; /* SRAM address for UMAC error log */ uint32_t dbg_print_buff_addr; } __packed; /* ALIVE_RES_API_S_VER_3 */ /* Error response/notification */ enum { IWM_FW_ERR_UNKNOWN_CMD = 0x0, IWM_FW_ERR_INVALID_CMD_PARAM = 0x1, IWM_FW_ERR_SERVICE = 0x2, IWM_FW_ERR_ARC_MEMORY = 0x3, IWM_FW_ERR_ARC_CODE = 0x4, IWM_FW_ERR_WATCH_DOG = 0x5, IWM_FW_ERR_WEP_GRP_KEY_INDX = 0x10, IWM_FW_ERR_WEP_KEY_SIZE = 0x11, IWM_FW_ERR_OBSOLETE_FUNC = 0x12, IWM_FW_ERR_UNEXPECTED = 0xFE, IWM_FW_ERR_FATAL = 0xFF }; /** * struct iwm_error_resp - FW error indication * ( IWM_REPLY_ERROR = 0x2 ) * @error_type: one of IWM_FW_ERR_* * @cmd_id: the command ID for which the error occurred * @bad_cmd_seq_num: sequence number of the erroneous command * @error_service: which service created the error, applicable only if * error_type = 2, otherwise 0 * @timestamp: TSF in usecs. */ struct iwm_error_resp { uint32_t error_type; uint8_t cmd_id; uint8_t reserved1; uint16_t bad_cmd_seq_num; uint32_t error_service; uint64_t timestamp; } __packed; /* Common PHY, MAC and Bindings definitions */ #define IWM_MAX_MACS_IN_BINDING (3) #define IWM_MAX_BINDINGS (4) #define IWM_AUX_BINDING_INDEX (3) #define IWM_MAX_PHYS (4) /* Used to extract ID and color from the context dword */ #define IWM_FW_CTXT_ID_POS (0) #define IWM_FW_CTXT_ID_MSK (0xff << IWM_FW_CTXT_ID_POS) #define IWM_FW_CTXT_COLOR_POS (8) #define IWM_FW_CTXT_COLOR_MSK (0xff << IWM_FW_CTXT_COLOR_POS) #define IWM_FW_CTXT_INVALID (0xffffffff) #define IWM_FW_CMD_ID_AND_COLOR(_id, _color) ((_id << IWM_FW_CTXT_ID_POS) |\ (_color << IWM_FW_CTXT_COLOR_POS)) /* Possible actions on PHYs, MACs and Bindings */ enum { IWM_FW_CTXT_ACTION_STUB = 0, IWM_FW_CTXT_ACTION_ADD, IWM_FW_CTXT_ACTION_MODIFY, IWM_FW_CTXT_ACTION_REMOVE, IWM_FW_CTXT_ACTION_NUM }; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ /* Time Events */ /* Time Event types, according to MAC type */ enum iwm_time_event_type { /* BSS Station Events */ IWM_TE_BSS_STA_AGGRESSIVE_ASSOC, IWM_TE_BSS_STA_ASSOC, IWM_TE_BSS_EAP_DHCP_PROT, IWM_TE_BSS_QUIET_PERIOD, /* P2P Device Events */ IWM_TE_P2P_DEVICE_DISCOVERABLE, IWM_TE_P2P_DEVICE_LISTEN, IWM_TE_P2P_DEVICE_ACTION_SCAN, IWM_TE_P2P_DEVICE_FULL_SCAN, /* P2P Client Events */ IWM_TE_P2P_CLIENT_AGGRESSIVE_ASSOC, IWM_TE_P2P_CLIENT_ASSOC, IWM_TE_P2P_CLIENT_QUIET_PERIOD, /* P2P GO Events */ IWM_TE_P2P_GO_ASSOC_PROT, IWM_TE_P2P_GO_REPETITIVE_NOA, IWM_TE_P2P_GO_CT_WINDOW, /* WiDi Sync Events */ IWM_TE_WIDI_TX_SYNC, IWM_TE_MAX }; /* IWM_MAC_EVENT_TYPE_API_E_VER_1 */ /* Time event - defines for command API v1 */ /* * @IWM_TE_V1_FRAG_NONE: fragmentation of the time event is NOT allowed. * @IWM_TE_V1_FRAG_SINGLE: fragmentation of the time event is allowed, but only * the first fragment is scheduled. * @IWM_TE_V1_FRAG_DUAL: fragmentation of the time event is allowed, but only * the first 2 fragments are scheduled. * @IWM_TE_V1_FRAG_ENDLESS: fragmentation of the time event is allowed, and any * number of fragments are valid. * * Other than the constant defined above, specifying a fragmentation value 'x' * means that the event can be fragmented but only the first 'x' will be * scheduled. */ enum { IWM_TE_V1_FRAG_NONE = 0, IWM_TE_V1_FRAG_SINGLE = 1, IWM_TE_V1_FRAG_DUAL = 2, IWM_TE_V1_FRAG_ENDLESS = 0xffffffff }; /* If a Time Event can be fragmented, this is the max number of fragments */ #define IWM_TE_V1_FRAG_MAX_MSK 0x0fffffff /* Repeat the time event endlessly (until removed) */ #define IWM_TE_V1_REPEAT_ENDLESS 0xffffffff /* If a Time Event has bounded repetitions, this is the maximal value */ #define IWM_TE_V1_REPEAT_MAX_MSK_V1 0x0fffffff /* Time Event dependencies: none, on another TE, or in a specific time */ enum { IWM_TE_V1_INDEPENDENT = 0, IWM_TE_V1_DEP_OTHER = (1 << 0), IWM_TE_V1_DEP_TSF = (1 << 1), IWM_TE_V1_EVENT_SOCIOPATHIC = (1 << 2), }; /* IWM_MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ /* * @IWM_TE_V1_NOTIF_NONE: no notifications * @IWM_TE_V1_NOTIF_HOST_EVENT_START: request/receive notification on event start * @IWM_TE_V1_NOTIF_HOST_EVENT_END:request/receive notification on event end * @IWM_TE_V1_NOTIF_INTERNAL_EVENT_START: internal FW use * @IWM_TE_V1_NOTIF_INTERNAL_EVENT_END: internal FW use. * @IWM_TE_V1_NOTIF_HOST_FRAG_START: request/receive notification on frag start * @IWM_TE_V1_NOTIF_HOST_FRAG_END:request/receive notification on frag end * @IWM_TE_V1_NOTIF_INTERNAL_FRAG_START: internal FW use. * @IWM_TE_V1_NOTIF_INTERNAL_FRAG_END: internal FW use. * * Supported Time event notifications configuration. * A notification (both event and fragment) includes a status indicating weather * the FW was able to schedule the event or not. For fragment start/end * notification the status is always success. There is no start/end fragment * notification for monolithic events. */ enum { IWM_TE_V1_NOTIF_NONE = 0, IWM_TE_V1_NOTIF_HOST_EVENT_START = (1 << 0), IWM_TE_V1_NOTIF_HOST_EVENT_END = (1 << 1), IWM_TE_V1_NOTIF_INTERNAL_EVENT_START = (1 << 2), IWM_TE_V1_NOTIF_INTERNAL_EVENT_END = (1 << 3), IWM_TE_V1_NOTIF_HOST_FRAG_START = (1 << 4), IWM_TE_V1_NOTIF_HOST_FRAG_END = (1 << 5), IWM_TE_V1_NOTIF_INTERNAL_FRAG_START = (1 << 6), IWM_TE_V1_NOTIF_INTERNAL_FRAG_END = (1 << 7), IWM_T2_V2_START_IMMEDIATELY = (1 << 11), }; /* IWM_MAC_EVENT_ACTION_API_E_VER_2 */ /** * struct iwm_time_event_cmd_api_v1 - configuring Time Events * with struct IWM_MAC_TIME_EVENT_DATA_API_S_VER_1 (see also * with version 2. determined by IWM_UCODE_TLV_FLAGS) * ( IWM_TIME_EVENT_CMD = 0x29 ) * @id_and_color: ID and color of the relevant MAC * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @id: this field has two meanings, depending on the action: * If the action is ADD, then it means the type of event to add. * For all other actions it is the unique event ID assigned when the * event was added by the FW. * @apply_time: When to start the Time Event (in GP2) * @max_delay: maximum delay to event's start (apply time), in TU * @depends_on: the unique ID of the event we depend on (if any) * @interval: interval between repetitions, in TU * @interval_reciprocal: 2^32 / interval * @duration: duration of event in TU * @repeat: how many repetitions to do, can be IWM_TE_REPEAT_ENDLESS * @dep_policy: one of IWM_TE_V1_INDEPENDENT, IWM_TE_V1_DEP_OTHER, IWM_TE_V1_DEP_TSF * and IWM_TE_V1_EVENT_SOCIOPATHIC * @is_present: 0 or 1, are we present or absent during the Time Event * @max_frags: maximal number of fragments the Time Event can be divided to * @notify: notifications using IWM_TE_V1_NOTIF_* (whom to notify when) */ struct iwm_time_event_cmd_v1 { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; uint32_t id; /* IWM_MAC_TIME_EVENT_DATA_API_S_VER_1 */ uint32_t apply_time; uint32_t max_delay; uint32_t dep_policy; uint32_t depends_on; uint32_t is_present; uint32_t max_frags; uint32_t interval; uint32_t interval_reciprocal; uint32_t duration; uint32_t repeat; uint32_t notify; } __packed; /* IWM_MAC_TIME_EVENT_CMD_API_S_VER_1 */ /* Time event - defines for command API v2 */ /* * @IWM_TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed. * @IWM_TE_V2_FRAG_SINGLE: fragmentation of the time event is allowed, but only * the first fragment is scheduled. * @IWM_TE_V2_FRAG_DUAL: fragmentation of the time event is allowed, but only * the first 2 fragments are scheduled. * @IWM_TE_V2_FRAG_ENDLESS: fragmentation of the time event is allowed, and any * number of fragments are valid. * * Other than the constant defined above, specifying a fragmentation value 'x' * means that the event can be fragmented but only the first 'x' will be * scheduled. */ enum { IWM_TE_V2_FRAG_NONE = 0, IWM_TE_V2_FRAG_SINGLE = 1, IWM_TE_V2_FRAG_DUAL = 2, IWM_TE_V2_FRAG_MAX = 0xfe, IWM_TE_V2_FRAG_ENDLESS = 0xff }; /* Repeat the time event endlessly (until removed) */ #define IWM_TE_V2_REPEAT_ENDLESS 0xff /* If a Time Event has bounded repetitions, this is the maximal value */ #define IWM_TE_V2_REPEAT_MAX 0xfe #define IWM_TE_V2_PLACEMENT_POS 12 #define IWM_TE_V2_ABSENCE_POS 15 /* Time event policy values (for time event cmd api v2) * A notification (both event and fragment) includes a status indicating weather * the FW was able to schedule the event or not. For fragment start/end * notification the status is always success. There is no start/end fragment * notification for monolithic events. * * @IWM_TE_V2_DEFAULT_POLICY: independent, social, present, unoticable * @IWM_TE_V2_NOTIF_HOST_EVENT_START: request/receive notification on event start * @IWM_TE_V2_NOTIF_HOST_EVENT_END:request/receive notification on event end * @IWM_TE_V2_NOTIF_INTERNAL_EVENT_START: internal FW use * @IWM_TE_V2_NOTIF_INTERNAL_EVENT_END: internal FW use. * @IWM_TE_V2_NOTIF_HOST_FRAG_START: request/receive notification on frag start * @IWM_TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end * @IWM_TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. * @IWM_TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. * @IWM_TE_V2_DEP_OTHER: depends on another time event * @IWM_TE_V2_DEP_TSF: depends on a specific time * @IWM_TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC * @IWM_TE_V2_ABSENCE: are we present or absent during the Time Event. */ enum { IWM_TE_V2_DEFAULT_POLICY = 0x0, /* notifications (event start/stop, fragment start/stop) */ IWM_TE_V2_NOTIF_HOST_EVENT_START = (1 << 0), IWM_TE_V2_NOTIF_HOST_EVENT_END = (1 << 1), IWM_TE_V2_NOTIF_INTERNAL_EVENT_START = (1 << 2), IWM_TE_V2_NOTIF_INTERNAL_EVENT_END = (1 << 3), IWM_TE_V2_NOTIF_HOST_FRAG_START = (1 << 4), IWM_TE_V2_NOTIF_HOST_FRAG_END = (1 << 5), IWM_TE_V2_NOTIF_INTERNAL_FRAG_START = (1 << 6), IWM_TE_V2_NOTIF_INTERNAL_FRAG_END = (1 << 7), IWM_TE_V2_NOTIF_MSK = 0xff, /* placement characteristics */ IWM_TE_V2_DEP_OTHER = (1 << IWM_TE_V2_PLACEMENT_POS), IWM_TE_V2_DEP_TSF = (1 << (IWM_TE_V2_PLACEMENT_POS + 1)), IWM_TE_V2_EVENT_SOCIOPATHIC = (1 << (IWM_TE_V2_PLACEMENT_POS + 2)), /* are we present or absent during the Time Event. */ IWM_TE_V2_ABSENCE = (1 << IWM_TE_V2_ABSENCE_POS), }; /** * struct iwm_time_event_cmd_api_v2 - configuring Time Events * with struct IWM_MAC_TIME_EVENT_DATA_API_S_VER_2 (see also * with version 1. determined by IWM_UCODE_TLV_FLAGS) * ( IWM_TIME_EVENT_CMD = 0x29 ) * @id_and_color: ID and color of the relevant MAC * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @id: this field has two meanings, depending on the action: * If the action is ADD, then it means the type of event to add. * For all other actions it is the unique event ID assigned when the * event was added by the FW. * @apply_time: When to start the Time Event (in GP2) * @max_delay: maximum delay to event's start (apply time), in TU * @depends_on: the unique ID of the event we depend on (if any) * @interval: interval between repetitions, in TU * @duration: duration of event in TU * @repeat: how many repetitions to do, can be IWM_TE_REPEAT_ENDLESS * @max_frags: maximal number of fragments the Time Event can be divided to * @policy: defines whether uCode shall notify the host or other uCode modules * on event and/or fragment start and/or end * using one of IWM_TE_INDEPENDENT, IWM_TE_DEP_OTHER, IWM_TE_DEP_TSF * IWM_TE_EVENT_SOCIOPATHIC * using IWM_TE_ABSENCE and using IWM_TE_NOTIF_* */ struct iwm_time_event_cmd_v2 { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; uint32_t id; /* IWM_MAC_TIME_EVENT_DATA_API_S_VER_2 */ uint32_t apply_time; uint32_t max_delay; uint32_t depends_on; uint32_t interval; uint32_t duration; uint8_t repeat; uint8_t max_frags; uint16_t policy; } __packed; /* IWM_MAC_TIME_EVENT_CMD_API_S_VER_2 */ /** * struct iwm_time_event_resp - response structure to iwm_time_event_cmd * @status: bit 0 indicates success, all others specify errors * @id: the Time Event type * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE * @id_and_color: ID and color of the relevant MAC */ struct iwm_time_event_resp { uint32_t status; uint32_t id; uint32_t unique_id; uint32_t id_and_color; } __packed; /* IWM_MAC_TIME_EVENT_RSP_API_S_VER_1 */ /** * struct iwm_time_event_notif - notifications of time event start/stop * ( IWM_TIME_EVENT_NOTIFICATION = 0x2a ) * @timestamp: action timestamp in GP2 * @session_id: session's unique id * @unique_id: unique id of the Time Event itself * @id_and_color: ID and color of the relevant MAC * @action: one of IWM_TE_NOTIF_START or IWM_TE_NOTIF_END * @status: true if scheduled, false otherwise (not executed) */ struct iwm_time_event_notif { uint32_t timestamp; uint32_t session_id; uint32_t unique_id; uint32_t id_and_color; uint32_t action; uint32_t status; } __packed; /* IWM_MAC_TIME_EVENT_NTFY_API_S_VER_1 */ /* Bindings and Time Quota */ /** * struct iwm_binding_cmd - configuring bindings * ( IWM_BINDING_CONTEXT_CMD = 0x2b ) * @id_and_color: ID and color of the relevant Binding * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @macs: array of MAC id and colors which belong to the binding * @phy: PHY id and color which belongs to the binding */ struct iwm_binding_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWM_BINDING_DATA_API_S_VER_1 */ uint32_t macs[IWM_MAX_MACS_IN_BINDING]; uint32_t phy; } __packed; /* IWM_BINDING_CMD_API_S_VER_1 */ /* The maximal number of fragments in the FW's schedule session */ #define IWM_MVM_MAX_QUOTA 128 /** * struct iwm_time_quota_data - configuration of time quota per binding * @id_and_color: ID and color of the relevant Binding * @quota: absolute time quota in TU. The scheduler will try to divide the * remainig quota (after Time Events) according to this quota. * @max_duration: max uninterrupted context duration in TU */ struct iwm_time_quota_data { uint32_t id_and_color; uint32_t quota; uint32_t max_duration; } __packed; /* IWM_TIME_QUOTA_DATA_API_S_VER_1 */ /** * struct iwm_time_quota_cmd - configuration of time quota between bindings * ( IWM_TIME_QUOTA_CMD = 0x2c ) * @quotas: allocations per binding */ struct iwm_time_quota_cmd { struct iwm_time_quota_data quotas[IWM_MAX_BINDINGS]; } __packed; /* IWM_TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */ /* PHY context */ /* Supported bands */ #define IWM_PHY_BAND_5 (0) #define IWM_PHY_BAND_24 (1) /* Supported channel width, vary if there is VHT support */ #define IWM_PHY_VHT_CHANNEL_MODE20 (0x0) #define IWM_PHY_VHT_CHANNEL_MODE40 (0x1) #define IWM_PHY_VHT_CHANNEL_MODE80 (0x2) #define IWM_PHY_VHT_CHANNEL_MODE160 (0x3) /* * Control channel position: * For legacy set bit means upper channel, otherwise lower. * For VHT - bit-2 marks if the control is lower/upper relative to center-freq * bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0. * center_freq * | * 40Mhz |_______|_______| * 80Mhz |_______|_______|_______|_______| * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______| * code 011 010 001 000 | 100 101 110 111 */ #define IWM_PHY_VHT_CTRL_POS_1_BELOW (0x0) #define IWM_PHY_VHT_CTRL_POS_2_BELOW (0x1) #define IWM_PHY_VHT_CTRL_POS_3_BELOW (0x2) #define IWM_PHY_VHT_CTRL_POS_4_BELOW (0x3) #define IWM_PHY_VHT_CTRL_POS_1_ABOVE (0x4) #define IWM_PHY_VHT_CTRL_POS_2_ABOVE (0x5) #define IWM_PHY_VHT_CTRL_POS_3_ABOVE (0x6) #define IWM_PHY_VHT_CTRL_POS_4_ABOVE (0x7) /* * @band: IWM_PHY_BAND_* * @channel: channel number * @width: PHY_[VHT|LEGACY]_CHANNEL_* * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* */ struct iwm_fw_channel_info { uint8_t band; uint8_t channel; uint8_t width; uint8_t ctrl_pos; } __packed; #define IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS (0) #define IWM_PHY_RX_CHAIN_DRIVER_FORCE_MSK \ (0x1 << IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS) #define IWM_PHY_RX_CHAIN_VALID_POS (1) #define IWM_PHY_RX_CHAIN_VALID_MSK \ (0x7 << IWM_PHY_RX_CHAIN_VALID_POS) #define IWM_PHY_RX_CHAIN_FORCE_SEL_POS (4) #define IWM_PHY_RX_CHAIN_FORCE_SEL_MSK \ (0x7 << IWM_PHY_RX_CHAIN_FORCE_SEL_POS) #define IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS (7) #define IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK \ (0x7 << IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS) #define IWM_PHY_RX_CHAIN_CNT_POS (10) #define IWM_PHY_RX_CHAIN_CNT_MSK \ (0x3 << IWM_PHY_RX_CHAIN_CNT_POS) #define IWM_PHY_RX_CHAIN_MIMO_CNT_POS (12) #define IWM_PHY_RX_CHAIN_MIMO_CNT_MSK \ (0x3 << IWM_PHY_RX_CHAIN_MIMO_CNT_POS) #define IWM_PHY_RX_CHAIN_MIMO_FORCE_POS (14) #define IWM_PHY_RX_CHAIN_MIMO_FORCE_MSK \ (0x1 << IWM_PHY_RX_CHAIN_MIMO_FORCE_POS) /* TODO: fix the value, make it depend on firmware at runtime? */ #define IWM_NUM_PHY_CTX 3 /* TODO: complete missing documentation */ /** * struct iwm_phy_context_cmd - config of the PHY context * ( IWM_PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @apply_time: 0 means immediate apply and context switch. * other value means apply new params after X usecs * @tx_param_color: ??? * @channel_info: * @txchain_info: ??? * @rxchain_info: ??? * @acquisition_data: ??? * @dsp_cfg_flags: set to 0 */ struct iwm_phy_context_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWM_PHY_CONTEXT_DATA_API_S_VER_1 */ uint32_t apply_time; uint32_t tx_param_color; struct iwm_fw_channel_info ci; uint32_t txchain_info; uint32_t rxchain_info; uint32_t acquisition_data; uint32_t dsp_cfg_flags; } __packed; /* IWM_PHY_CONTEXT_CMD_API_VER_1 */ #define IWM_RX_INFO_PHY_CNT 8 #define IWM_RX_INFO_ENERGY_ANT_ABC_IDX 1 #define IWM_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff #define IWM_RX_INFO_ENERGY_ANT_B_MSK 0x0000ff00 #define IWM_RX_INFO_ENERGY_ANT_C_MSK 0x00ff0000 #define IWM_RX_INFO_ENERGY_ANT_A_POS 0 #define IWM_RX_INFO_ENERGY_ANT_B_POS 8 #define IWM_RX_INFO_ENERGY_ANT_C_POS 16 #define IWM_RX_INFO_AGC_IDX 1 #define IWM_RX_INFO_RSSI_AB_IDX 2 #define IWM_OFDM_AGC_A_MSK 0x0000007f #define IWM_OFDM_AGC_A_POS 0 #define IWM_OFDM_AGC_B_MSK 0x00003f80 #define IWM_OFDM_AGC_B_POS 7 #define IWM_OFDM_AGC_CODE_MSK 0x3fe00000 #define IWM_OFDM_AGC_CODE_POS 20 #define IWM_OFDM_RSSI_INBAND_A_MSK 0x00ff #define IWM_OFDM_RSSI_A_POS 0 #define IWM_OFDM_RSSI_ALLBAND_A_MSK 0xff00 #define IWM_OFDM_RSSI_ALLBAND_A_POS 8 #define IWM_OFDM_RSSI_INBAND_B_MSK 0xff0000 #define IWM_OFDM_RSSI_B_POS 16 #define IWM_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 #define IWM_OFDM_RSSI_ALLBAND_B_POS 24 /** * struct iwm_rx_phy_info - phy info * (IWM_REPLY_RX_PHY_CMD = 0xc0) * @non_cfg_phy_cnt: non configurable DSP phy data byte count * @cfg_phy_cnt: configurable DSP phy data byte count * @stat_id: configurable DSP phy data set ID * @reserved1: * @system_timestamp: GP2 at on air rise * @timestamp: TSF at on air rise * @beacon_time_stamp: beacon at on-air rise * @phy_flags: general phy flags: band, modulation, ... * @channel: channel number * @non_cfg_phy_buf: for various implementations of non_cfg_phy * @rate_n_flags: IWM_RATE_MCS_* * @byte_count: frame's byte-count * @frame_time: frame's time on the air, based on byte count and frame rate * calculation * @mac_active_msk: what MACs were active when the frame was received * * Before each Rx, the device sends this data. It contains PHY information * about the reception of the packet. */ struct iwm_rx_phy_info { uint8_t non_cfg_phy_cnt; uint8_t cfg_phy_cnt; uint8_t stat_id; uint8_t reserved1; uint32_t system_timestamp; uint64_t timestamp; uint32_t beacon_time_stamp; uint16_t phy_flags; #define IWM_PHY_INFO_FLAG_SHPREAMBLE (1 << 2) uint16_t channel; uint32_t non_cfg_phy[IWM_RX_INFO_PHY_CNT]; uint8_t rate; uint8_t rflags; uint16_t xrflags; uint32_t byte_count; uint16_t mac_active_msk; uint16_t frame_time; } __packed; struct iwm_rx_mpdu_res_start { uint16_t byte_count; uint16_t reserved; } __packed; /** * enum iwm_rx_phy_flags - to parse %iwm_rx_phy_info phy_flags * @IWM_RX_RES_PHY_FLAGS_BAND_24: true if the packet was received on 2.4 band * @IWM_RX_RES_PHY_FLAGS_MOD_CCK: * @IWM_RX_RES_PHY_FLAGS_SHORT_PREAMBLE: true if packet's preamble was short * @IWM_RX_RES_PHY_FLAGS_NARROW_BAND: * @IWM_RX_RES_PHY_FLAGS_ANTENNA: antenna on which the packet was received * @IWM_RX_RES_PHY_FLAGS_AGG: set if the packet was part of an A-MPDU * @IWM_RX_RES_PHY_FLAGS_OFDM_HT: The frame was an HT frame * @IWM_RX_RES_PHY_FLAGS_OFDM_GF: The frame used GF preamble * @IWM_RX_RES_PHY_FLAGS_OFDM_VHT: The frame was a VHT frame */ enum iwm_rx_phy_flags { IWM_RX_RES_PHY_FLAGS_BAND_24 = (1 << 0), IWM_RX_RES_PHY_FLAGS_MOD_CCK = (1 << 1), IWM_RX_RES_PHY_FLAGS_SHORT_PREAMBLE = (1 << 2), IWM_RX_RES_PHY_FLAGS_NARROW_BAND = (1 << 3), IWM_RX_RES_PHY_FLAGS_ANTENNA = (0x7 << 4), IWM_RX_RES_PHY_FLAGS_ANTENNA_POS = 4, IWM_RX_RES_PHY_FLAGS_AGG = (1 << 7), IWM_RX_RES_PHY_FLAGS_OFDM_HT = (1 << 8), IWM_RX_RES_PHY_FLAGS_OFDM_GF = (1 << 9), IWM_RX_RES_PHY_FLAGS_OFDM_VHT = (1 << 10), }; /** * enum iwm_mvm_rx_status - written by fw for each Rx packet * @IWM_RX_MPDU_RES_STATUS_CRC_OK: CRC is fine * @IWM_RX_MPDU_RES_STATUS_OVERRUN_OK: there was no RXE overflow * @IWM_RX_MPDU_RES_STATUS_SRC_STA_FOUND: * @IWM_RX_MPDU_RES_STATUS_KEY_VALID: * @IWM_RX_MPDU_RES_STATUS_KEY_PARAM_OK: * @IWM_RX_MPDU_RES_STATUS_ICV_OK: ICV is fine, if not, the packet is destroyed * @IWM_RX_MPDU_RES_STATUS_MIC_OK: used for CCM alg only. TKIP MIC is checked * in the driver. * @IWM_RX_MPDU_RES_STATUS_TTAK_OK: TTAK is fine * @IWM_RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR: valid for alg = CCM_CMAC or * alg = CCM only. Checks replay attack for 11w frames. Relevant only if * %IWM_RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME is set. * @IWM_RX_MPDU_RES_STATUS_SEC_NO_ENC: this frame is not encrypted * @IWM_RX_MPDU_RES_STATUS_SEC_WEP_ENC: this frame is encrypted using WEP * @IWM_RX_MPDU_RES_STATUS_SEC_CCM_ENC: this frame is encrypted using CCM * @IWM_RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP * @IWM_RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC * @IWM_RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted * @IWM_RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm * @IWM_RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted * @IWM_RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP: * @IWM_RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: * @IWM_RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: * @IWM_RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame * @IWM_RX_MPDU_RES_STATUS_HASH_INDEX_MSK: * @IWM_RX_MPDU_RES_STATUS_STA_ID_MSK: * @IWM_RX_MPDU_RES_STATUS_RRF_KILL: * @IWM_RX_MPDU_RES_STATUS_FILTERING_MSK: * @IWM_RX_MPDU_RES_STATUS2_FILTERING_MSK: */ enum iwm_mvm_rx_status { IWM_RX_MPDU_RES_STATUS_CRC_OK = (1 << 0), IWM_RX_MPDU_RES_STATUS_OVERRUN_OK = (1 << 1), IWM_RX_MPDU_RES_STATUS_SRC_STA_FOUND = (1 << 2), IWM_RX_MPDU_RES_STATUS_KEY_VALID = (1 << 3), IWM_RX_MPDU_RES_STATUS_KEY_PARAM_OK = (1 << 4), IWM_RX_MPDU_RES_STATUS_ICV_OK = (1 << 5), IWM_RX_MPDU_RES_STATUS_MIC_OK = (1 << 6), IWM_RX_MPDU_RES_STATUS_TTAK_OK = (1 << 7), IWM_RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR = (1 << 7), IWM_RX_MPDU_RES_STATUS_SEC_NO_ENC = (0 << 8), IWM_RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8), IWM_RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8), IWM_RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8), IWM_RX_MPDU_RES_STATUS_SEC_EXT_ENC = (4 << 8), IWM_RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8), IWM_RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8), IWM_RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8), IWM_RX_MPDU_RES_STATUS_DEC_DONE = (1 << 11), IWM_RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP = (1 << 12), IWM_RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP = (1 << 13), IWM_RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT = (1 << 14), IWM_RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME = (1 << 15), IWM_RX_MPDU_RES_STATUS_HASH_INDEX_MSK = (0x3F0000), IWM_RX_MPDU_RES_STATUS_STA_ID_MSK = (0x1f000000), IWM_RX_MPDU_RES_STATUS_RRF_KILL = (1 << 29), IWM_RX_MPDU_RES_STATUS_FILTERING_MSK = (0xc00000), IWM_RX_MPDU_RES_STATUS2_FILTERING_MSK = (0xc0000000), }; /** * struct iwm_radio_version_notif - information on the radio version * ( IWM_RADIO_VERSION_NOTIFICATION = 0x68 ) * @radio_flavor: * @radio_step: * @radio_dash: */ struct iwm_radio_version_notif { uint32_t radio_flavor; uint32_t radio_step; uint32_t radio_dash; } __packed; /* IWM_RADIO_VERSION_NOTOFICATION_S_VER_1 */ enum iwm_card_state_flags { IWM_CARD_ENABLED = 0x00, IWM_HW_CARD_DISABLED = 0x01, IWM_SW_CARD_DISABLED = 0x02, IWM_CT_KILL_CARD_DISABLED = 0x04, IWM_HALT_CARD_DISABLED = 0x08, IWM_CARD_DISABLED_MSK = 0x0f, IWM_CARD_IS_RX_ON = 0x10, }; /** * struct iwm_radio_version_notif - information on the radio version * (IWM_CARD_STATE_NOTIFICATION = 0xa1 ) * @flags: %iwm_card_state_flags */ struct iwm_card_state_notif { uint32_t flags; } __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ /** * struct iwm_missed_beacons_notif - information on missed beacons * ( IWM_MISSED_BEACONS_NOTIFICATION = 0xa2 ) * @mac_id: interface ID * @consec_missed_beacons_since_last_rx: number of consecutive missed * beacons since last RX. * @consec_missed_beacons: number of consecutive missed beacons * @num_expected_beacons: * @num_recvd_beacons: */ struct iwm_missed_beacons_notif { uint32_t mac_id; uint32_t consec_missed_beacons_since_last_rx; uint32_t consec_missed_beacons; uint32_t num_expected_beacons; uint32_t num_recvd_beacons; } __packed; /* IWM_MISSED_BEACON_NTFY_API_S_VER_3 */ /** * struct iwm_mfuart_load_notif - mfuart image version & status * ( IWM_MFUART_LOAD_NOTIFICATION = 0xb1 ) * @installed_ver: installed image version * @external_ver: external image version * @status: MFUART loading status * @duration: MFUART loading time */ struct iwm_mfuart_load_notif { uint32_t installed_ver; uint32_t external_ver; uint32_t status; uint32_t duration; } __packed; /*MFU_LOADER_NTFY_API_S_VER_1*/ /** * struct iwm_set_calib_default_cmd - set default value for calibration. * ( IWM_SET_CALIB_DEFAULT_CMD = 0x8e ) * @calib_index: the calibration to set value for * @length: of data * @data: the value to set for the calibration result */ struct iwm_set_calib_default_cmd { uint16_t calib_index; uint16_t length; uint8_t data[0]; } __packed; /* IWM_PHY_CALIB_OVERRIDE_VALUES_S */ #define IWM_MAX_PORT_ID_NUM 2 #define IWM_MAX_MCAST_FILTERING_ADDRESSES 256 /** * struct iwm_mcast_filter_cmd - configure multicast filter. * @filter_own: Set 1 to filter out multicast packets sent by station itself * @port_id: Multicast MAC addresses array specifier. This is a strange way * to identify network interface adopted in host-device IF. * It is used by FW as index in array of addresses. This array has * IWM_MAX_PORT_ID_NUM members. * @count: Number of MAC addresses in the array * @pass_all: Set 1 to pass all multicast packets. * @bssid: current association BSSID. * @addr_list: Place holder for array of MAC addresses. * IMPORTANT: add padding if necessary to ensure DWORD alignment. */ struct iwm_mcast_filter_cmd { uint8_t filter_own; uint8_t port_id; uint8_t count; uint8_t pass_all; uint8_t bssid[6]; uint8_t reserved[2]; uint8_t addr_list[0]; } __packed; /* IWM_MCAST_FILTERING_CMD_API_S_VER_1 */ struct iwm_mvm_statistics_dbg { uint32_t burst_check; uint32_t burst_count; uint32_t wait_for_silence_timeout_cnt; uint32_t reserved[3]; } __packed; /* IWM_STATISTICS_DEBUG_API_S_VER_2 */ struct iwm_mvm_statistics_div { uint32_t tx_on_a; uint32_t tx_on_b; uint32_t exec_time; uint32_t probe_time; uint32_t rssi_ant; uint32_t reserved2; } __packed; /* IWM_STATISTICS_SLOW_DIV_API_S_VER_2 */ struct iwm_mvm_statistics_general_common { uint32_t temperature; /* radio temperature */ uint32_t temperature_m; /* radio voltage */ struct iwm_mvm_statistics_dbg dbg; uint32_t sleep_time; uint32_t slots_out; uint32_t slots_idle; uint32_t ttl_timestamp; struct iwm_mvm_statistics_div div; uint32_t rx_enable_counter; /* * num_of_sos_states: * count the number of times we have to re-tune * in order to get out of bad PHY status */ uint32_t num_of_sos_states; } __packed; /* IWM_STATISTICS_GENERAL_API_S_VER_5 */ struct iwm_mvm_statistics_rx_non_phy { uint32_t bogus_cts; /* CTS received when not expecting CTS */ uint32_t bogus_ack; /* ACK received when not expecting ACK */ uint32_t non_bssid_frames; /* number of frames with BSSID that * doesn't belong to the STA BSSID */ uint32_t filtered_frames; /* count frames that were dumped in the * filtering process */ uint32_t non_channel_beacons; /* beacons with our bss id but not on * our serving channel */ uint32_t channel_beacons; /* beacons with our bss id and in our * serving channel */ uint32_t num_missed_bcon; /* number of missed beacons */ uint32_t adc_rx_saturation_time; /* count in 0.8us units the time the * ADC was in saturation */ uint32_t ina_detection_search_time;/* total time (in 0.8us) searched * for INA */ uint32_t beacon_silence_rssi[3];/* RSSI silence after beacon frame */ uint32_t interference_data_flag; /* flag for interference data * availability. 1 when data is * available. */ uint32_t channel_load; /* counts RX Enable time in uSec */ uint32_t dsp_false_alarms; /* DSP false alarm (both OFDM * and CCK) counter */ uint32_t beacon_rssi_a; uint32_t beacon_rssi_b; uint32_t beacon_rssi_c; uint32_t beacon_energy_a; uint32_t beacon_energy_b; uint32_t beacon_energy_c; uint32_t num_bt_kills; uint32_t mac_id; uint32_t directed_data_mpdu; } __packed; /* IWM_STATISTICS_RX_NON_PHY_API_S_VER_3 */ struct iwm_mvm_statistics_rx_phy { uint32_t ina_cnt; uint32_t fina_cnt; uint32_t plcp_err; uint32_t crc32_err; uint32_t overrun_err; uint32_t early_overrun_err; uint32_t crc32_good; uint32_t false_alarm_cnt; uint32_t fina_sync_err_cnt; uint32_t sfd_timeout; uint32_t fina_timeout; uint32_t unresponded_rts; uint32_t rxe_frame_limit_overrun; uint32_t sent_ack_cnt; uint32_t sent_cts_cnt; uint32_t sent_ba_rsp_cnt; uint32_t dsp_self_kill; uint32_t mh_format_err; uint32_t re_acq_main_rssi_sum; uint32_t reserved; } __packed; /* IWM_STATISTICS_RX_PHY_API_S_VER_2 */ struct iwm_mvm_statistics_rx_ht_phy { uint32_t plcp_err; uint32_t overrun_err; uint32_t early_overrun_err; uint32_t crc32_good; uint32_t crc32_err; uint32_t mh_format_err; uint32_t agg_crc32_good; uint32_t agg_mpdu_cnt; uint32_t agg_cnt; uint32_t unsupport_mcs; } __packed; /* IWM_STATISTICS_HT_RX_PHY_API_S_VER_1 */ #define IWM_MAX_CHAINS 3 struct iwm_mvm_statistics_tx_non_phy_agg { uint32_t ba_timeout; uint32_t ba_reschedule_frames; uint32_t scd_query_agg_frame_cnt; uint32_t scd_query_no_agg; uint32_t scd_query_agg; uint32_t scd_query_mismatch; uint32_t frame_not_ready; uint32_t underrun; uint32_t bt_prio_kill; uint32_t rx_ba_rsp_cnt; int8_t txpower[IWM_MAX_CHAINS]; int8_t reserved; uint32_t reserved2; } __packed; /* IWM_STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */ struct iwm_mvm_statistics_tx_channel_width { uint32_t ext_cca_narrow_ch20[1]; uint32_t ext_cca_narrow_ch40[2]; uint32_t ext_cca_narrow_ch80[3]; uint32_t ext_cca_narrow_ch160[4]; uint32_t last_tx_ch_width_indx; uint32_t rx_detected_per_ch_width[4]; uint32_t success_per_ch_width[4]; uint32_t fail_per_ch_width[4]; }; /* IWM_STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ struct iwm_mvm_statistics_tx { uint32_t preamble_cnt; uint32_t rx_detected_cnt; uint32_t bt_prio_defer_cnt; uint32_t bt_prio_kill_cnt; uint32_t few_bytes_cnt; uint32_t cts_timeout; uint32_t ack_timeout; uint32_t expected_ack_cnt; uint32_t actual_ack_cnt; uint32_t dump_msdu_cnt; uint32_t burst_abort_next_frame_mismatch_cnt; uint32_t burst_abort_missing_next_frame_cnt; uint32_t cts_timeout_collision; uint32_t ack_or_ba_timeout_collision; struct iwm_mvm_statistics_tx_non_phy_agg agg; struct iwm_mvm_statistics_tx_channel_width channel_width; } __packed; /* IWM_STATISTICS_TX_API_S_VER_4 */ struct iwm_mvm_statistics_bt_activity { uint32_t hi_priority_tx_req_cnt; uint32_t hi_priority_tx_denied_cnt; uint32_t lo_priority_tx_req_cnt; uint32_t lo_priority_tx_denied_cnt; uint32_t hi_priority_rx_req_cnt; uint32_t hi_priority_rx_denied_cnt; uint32_t lo_priority_rx_req_cnt; uint32_t lo_priority_rx_denied_cnt; } __packed; /* IWM_STATISTICS_BT_ACTIVITY_API_S_VER_1 */ struct iwm_mvm_statistics_general { struct iwm_mvm_statistics_general_common common; uint32_t beacon_filtered; uint32_t missed_beacons; int8_t beacon_filter_average_energy; int8_t beacon_filter_reason; int8_t beacon_filter_current_energy; int8_t beacon_filter_reserved; uint32_t beacon_filter_delta_time; struct iwm_mvm_statistics_bt_activity bt_activity; } __packed; /* IWM_STATISTICS_GENERAL_API_S_VER_5 */ struct iwm_mvm_statistics_rx { struct iwm_mvm_statistics_rx_phy ofdm; struct iwm_mvm_statistics_rx_phy cck; struct iwm_mvm_statistics_rx_non_phy general; struct iwm_mvm_statistics_rx_ht_phy ofdm_ht; } __packed; /* IWM_STATISTICS_RX_API_S_VER_3 */ /* * IWM_STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) * * By default, uCode issues this notification after receiving a beacon * while associated. To disable this behavior, set DISABLE_NOTIF flag in the * IWM_REPLY_STATISTICS_CMD 0x9c, above. * * Statistics counters continue to increment beacon after beacon, but are * cleared when changing channels or when driver issues IWM_REPLY_STATISTICS_CMD * 0x9c with CLEAR_STATS bit set (see above). * * uCode also issues this notification during scans. uCode clears statistics * appropriately so that each notification contains statistics for only the * one channel that has just been scanned. */ struct iwm_notif_statistics { /* IWM_STATISTICS_NTFY_API_S_VER_8 */ uint32_t flag; struct iwm_mvm_statistics_rx rx; struct iwm_mvm_statistics_tx tx; struct iwm_mvm_statistics_general general; } __packed; /*********************************** * Smart Fifo API ***********************************/ /* Smart Fifo state */ enum iwm_sf_state { IWM_SF_LONG_DELAY_ON = 0, /* should never be called by driver */ IWM_SF_FULL_ON, IWM_SF_UNINIT, IWM_SF_INIT_OFF, IWM_SF_HW_NUM_STATES }; /* Smart Fifo possible scenario */ enum iwm_sf_scenario { IWM_SF_SCENARIO_SINGLE_UNICAST, IWM_SF_SCENARIO_AGG_UNICAST, IWM_SF_SCENARIO_MULTICAST, IWM_SF_SCENARIO_BA_RESP, IWM_SF_SCENARIO_TX_RESP, IWM_SF_NUM_SCENARIO }; #define IWM_SF_TRANSIENT_STATES_NUMBER 2 /* IWM_SF_LONG_DELAY_ON and IWM_SF_FULL_ON */ #define IWM_SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */ /* smart FIFO default values */ #define IWM_SF_W_MARK_SISO 4096 #define IWM_SF_W_MARK_MIMO2 8192 #define IWM_SF_W_MARK_MIMO3 6144 #define IWM_SF_W_MARK_LEGACY 4096 #define IWM_SF_W_MARK_SCAN 4096 /* SF Scenarios timers for default configuration (aligned to 32 uSec) */ #define IWM_SF_SINGLE_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWM_SF_SINGLE_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWM_SF_AGG_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWM_SF_AGG_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWM_SF_MCAST_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWM_SF_MCAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWM_SF_BA_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWM_SF_BA_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWM_SF_TX_RE_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWM_SF_TX_RE_AGING_TIMER_DEF 400 /* 0.4 mSec */ /* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */ #define IWM_SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */ #define IWM_SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */ #define IWM_SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */ #define IWM_SF_AGG_UNICAST_AGING_TIMER 2016 /* 2 mSec */ #define IWM_SF_MCAST_IDLE_TIMER 2016 /* 2 mSec */ #define IWM_SF_MCAST_AGING_TIMER 10016 /* 10 mSec */ #define IWM_SF_BA_IDLE_TIMER 320 /* 300 uSec */ #define IWM_SF_BA_AGING_TIMER 2016 /* 2 mSec */ #define IWM_SF_TX_RE_IDLE_TIMER 320 /* 300 uSec */ #define IWM_SF_TX_RE_AGING_TIMER 2016 /* 2 mSec */ #define IWM_SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ #define IWM_SF_CFG_DUMMY_NOTIF_OFF (1 << 16) /** * Smart Fifo configuration command. * @state: smart fifo state, types listed in iwm_sf_state. * @watermark: Minimum allowed available free space in RXF for transient state. * @long_delay_timeouts: aging and idle timer values for each scenario * in long delay state. * @full_on_timeouts: timer values for each scenario in full on state. */ struct iwm_sf_cfg_cmd { uint32_t state; uint32_t watermark[IWM_SF_TRANSIENT_STATES_NUMBER]; uint32_t long_delay_timeouts[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES]; uint32_t full_on_timeouts[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES]; } __packed; /* IWM_SF_CFG_API_S_VER_2 */ /* * END mvm/fw-api.h */ /* * BEGIN mvm/fw-api-mac.h */ /* * The first MAC indices (starting from 0) * are available to the driver, AUX follows */ #define IWM_MAC_INDEX_AUX 4 #define IWM_MAC_INDEX_MIN_DRIVER 0 #define IWM_NUM_MAC_INDEX_DRIVER IWM_MAC_INDEX_AUX enum iwm_ac { IWM_AC_BK, IWM_AC_BE, IWM_AC_VI, IWM_AC_VO, IWM_AC_NUM, }; /** * enum iwm_mac_protection_flags - MAC context flags * @IWM_MAC_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames, * this will require CCK RTS/CTS2self. * RTS/CTS will protect full burst time. * @IWM_MAC_PROT_FLG_HT_PROT: enable HT protection * @IWM_MAC_PROT_FLG_FAT_PROT: protect 40 MHz transmissions * @IWM_MAC_PROT_FLG_SELF_CTS_EN: allow CTS2self */ enum iwm_mac_protection_flags { IWM_MAC_PROT_FLG_TGG_PROTECT = (1 << 3), IWM_MAC_PROT_FLG_HT_PROT = (1 << 23), IWM_MAC_PROT_FLG_FAT_PROT = (1 << 24), IWM_MAC_PROT_FLG_SELF_CTS_EN = (1 << 30), }; #define IWM_MAC_FLG_SHORT_SLOT (1 << 4) #define IWM_MAC_FLG_SHORT_PREAMBLE (1 << 5) /** * enum iwm_mac_types - Supported MAC types * @IWM_FW_MAC_TYPE_FIRST: lowest supported MAC type * @IWM_FW_MAC_TYPE_AUX: Auxiliary MAC (internal) * @IWM_FW_MAC_TYPE_LISTENER: monitor MAC type (?) * @IWM_FW_MAC_TYPE_PIBSS: Pseudo-IBSS * @IWM_FW_MAC_TYPE_IBSS: IBSS * @IWM_FW_MAC_TYPE_BSS_STA: BSS (managed) station * @IWM_FW_MAC_TYPE_P2P_DEVICE: P2P Device * @IWM_FW_MAC_TYPE_P2P_STA: P2P client * @IWM_FW_MAC_TYPE_GO: P2P GO * @IWM_FW_MAC_TYPE_TEST: ? * @IWM_FW_MAC_TYPE_MAX: highest support MAC type */ enum iwm_mac_types { IWM_FW_MAC_TYPE_FIRST = 1, IWM_FW_MAC_TYPE_AUX = IWM_FW_MAC_TYPE_FIRST, IWM_FW_MAC_TYPE_LISTENER, IWM_FW_MAC_TYPE_PIBSS, IWM_FW_MAC_TYPE_IBSS, IWM_FW_MAC_TYPE_BSS_STA, IWM_FW_MAC_TYPE_P2P_DEVICE, IWM_FW_MAC_TYPE_P2P_STA, IWM_FW_MAC_TYPE_GO, IWM_FW_MAC_TYPE_TEST, IWM_FW_MAC_TYPE_MAX = IWM_FW_MAC_TYPE_TEST }; /* IWM_MAC_CONTEXT_TYPE_API_E_VER_1 */ /** * enum iwm_tsf_id - TSF hw timer ID * @IWM_TSF_ID_A: use TSF A * @IWM_TSF_ID_B: use TSF B * @IWM_TSF_ID_C: use TSF C * @IWM_TSF_ID_D: use TSF D * @IWM_NUM_TSF_IDS: number of TSF timers available */ enum iwm_tsf_id { IWM_TSF_ID_A = 0, IWM_TSF_ID_B = 1, IWM_TSF_ID_C = 2, IWM_TSF_ID_D = 3, IWM_NUM_TSF_IDS = 4, }; /* IWM_TSF_ID_API_E_VER_1 */ /** * struct iwm_mac_data_ap - configuration data for AP MAC context * @beacon_time: beacon transmit time in system time * @beacon_tsf: beacon transmit time in TSF * @bi: beacon interval in TU * @bi_reciprocal: 2^32 / bi * @dtim_interval: dtim transmit time in TU * @dtim_reciprocal: 2^32 / dtim_interval * @mcast_qid: queue ID for multicast traffic * @beacon_template: beacon template ID */ struct iwm_mac_data_ap { uint32_t beacon_time; uint64_t beacon_tsf; uint32_t bi; uint32_t bi_reciprocal; uint32_t dtim_interval; uint32_t dtim_reciprocal; uint32_t mcast_qid; uint32_t beacon_template; } __packed; /* AP_MAC_DATA_API_S_VER_1 */ /** * struct iwm_mac_data_ibss - configuration data for IBSS MAC context * @beacon_time: beacon transmit time in system time * @beacon_tsf: beacon transmit time in TSF * @bi: beacon interval in TU * @bi_reciprocal: 2^32 / bi * @beacon_template: beacon template ID */ struct iwm_mac_data_ibss { uint32_t beacon_time; uint64_t beacon_tsf; uint32_t bi; uint32_t bi_reciprocal; uint32_t beacon_template; } __packed; /* IBSS_MAC_DATA_API_S_VER_1 */ /** * struct iwm_mac_data_sta - configuration data for station MAC context * @is_assoc: 1 for associated state, 0 otherwise * @dtim_time: DTIM arrival time in system time * @dtim_tsf: DTIM arrival time in TSF * @bi: beacon interval in TU, applicable only when associated * @bi_reciprocal: 2^32 / bi , applicable only when associated * @dtim_interval: DTIM interval in TU, applicable only when associated * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated * @listen_interval: in beacon intervals, applicable only when associated * @assoc_id: unique ID assigned by the AP during association */ struct iwm_mac_data_sta { uint32_t is_assoc; uint32_t dtim_time; uint64_t dtim_tsf; uint32_t bi; uint32_t bi_reciprocal; uint32_t dtim_interval; uint32_t dtim_reciprocal; uint32_t listen_interval; uint32_t assoc_id; uint32_t assoc_beacon_arrive_time; } __packed; /* IWM_STA_MAC_DATA_API_S_VER_1 */ /** * struct iwm_mac_data_go - configuration data for P2P GO MAC context * @ap: iwm_mac_data_ap struct with most config data * @ctwin: client traffic window in TU (period after TBTT when GO is present). * 0 indicates that there is no CT window. * @opp_ps_enabled: indicate that opportunistic PS allowed */ struct iwm_mac_data_go { struct iwm_mac_data_ap ap; uint32_t ctwin; uint32_t opp_ps_enabled; } __packed; /* GO_MAC_DATA_API_S_VER_1 */ /** * struct iwm_mac_data_p2p_sta - configuration data for P2P client MAC context * @sta: iwm_mac_data_sta struct with most config data * @ctwin: client traffic window in TU (period after TBTT when GO is present). * 0 indicates that there is no CT window. */ struct iwm_mac_data_p2p_sta { struct iwm_mac_data_sta sta; uint32_t ctwin; } __packed; /* P2P_STA_MAC_DATA_API_S_VER_1 */ /** * struct iwm_mac_data_pibss - Pseudo IBSS config data * @stats_interval: interval in TU between statistics notifications to host. */ struct iwm_mac_data_pibss { uint32_t stats_interval; } __packed; /* PIBSS_MAC_DATA_API_S_VER_1 */ /* * struct iwm_mac_data_p2p_dev - configuration data for the P2P Device MAC * context. * @is_disc_extended: if set to true, P2P Device discoverability is enabled on * other channels as well. This should be to true only in case that the * device is discoverable and there is an active GO. Note that setting this * field when not needed, will increase the number of interrupts and have * effect on the platform power, as this setting opens the Rx filters on * all macs. */ struct iwm_mac_data_p2p_dev { uint32_t is_disc_extended; } __packed; /* _P2P_DEV_MAC_DATA_API_S_VER_1 */ /** * enum iwm_mac_filter_flags - MAC context filter flags * @IWM_MAC_FILTER_IN_PROMISC: accept all data frames * @IWM_MAC_FILTER_IN_CONTROL_AND_MGMT: pass all mangement and * control frames to the host * @IWM_MAC_FILTER_ACCEPT_GRP: accept multicast frames * @IWM_MAC_FILTER_DIS_DECRYPT: don't decrypt unicast frames * @IWM_MAC_FILTER_DIS_GRP_DECRYPT: don't decrypt multicast frames * @IWM_MAC_FILTER_IN_BEACON: transfer foreign BSS's beacons to host * (in station mode when associated) * @IWM_MAC_FILTER_OUT_BCAST: filter out all broadcast frames * @IWM_MAC_FILTER_IN_CRC32: extract FCS and append it to frames * @IWM_MAC_FILTER_IN_PROBE_REQUEST: pass probe requests to host */ enum iwm_mac_filter_flags { IWM_MAC_FILTER_IN_PROMISC = (1 << 0), IWM_MAC_FILTER_IN_CONTROL_AND_MGMT = (1 << 1), IWM_MAC_FILTER_ACCEPT_GRP = (1 << 2), IWM_MAC_FILTER_DIS_DECRYPT = (1 << 3), IWM_MAC_FILTER_DIS_GRP_DECRYPT = (1 << 4), IWM_MAC_FILTER_IN_BEACON = (1 << 6), IWM_MAC_FILTER_OUT_BCAST = (1 << 8), IWM_MAC_FILTER_IN_CRC32 = (1 << 11), IWM_MAC_FILTER_IN_PROBE_REQUEST = (1 << 12), }; /** * enum iwm_mac_qos_flags - QoS flags * @IWM_MAC_QOS_FLG_UPDATE_EDCA: ? * @IWM_MAC_QOS_FLG_TGN: HT is enabled * @IWM_MAC_QOS_FLG_TXOP_TYPE: ? * */ enum iwm_mac_qos_flags { IWM_MAC_QOS_FLG_UPDATE_EDCA = (1 << 0), IWM_MAC_QOS_FLG_TGN = (1 << 1), IWM_MAC_QOS_FLG_TXOP_TYPE = (1 << 4), }; /** * struct iwm_ac_qos - QOS timing params for IWM_MAC_CONTEXT_CMD * @cw_min: Contention window, start value in numbers of slots. * Should be a power-of-2, minus 1. Device's default is 0x0f. * @cw_max: Contention window, max value in numbers of slots. * Should be a power-of-2, minus 1. Device's default is 0x3f. * @aifsn: Number of slots in Arbitration Interframe Space (before * performing random backoff timing prior to Tx). Device default 1. * @fifos_mask: FIFOs used by this MAC for this AC * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0. * * One instance of this config struct for each of 4 EDCA access categories * in struct iwm_qosparam_cmd. * * Device will automatically increase contention window by (2*CW) + 1 for each * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW * value, to cap the CW value. */ struct iwm_ac_qos { uint16_t cw_min; uint16_t cw_max; uint8_t aifsn; uint8_t fifos_mask; uint16_t edca_txop; } __packed; /* IWM_AC_QOS_API_S_VER_2 */ /** * struct iwm_mac_ctx_cmd - command structure to configure MAC contexts * ( IWM_MAC_CONTEXT_CMD = 0x28 ) * @id_and_color: ID and color of the MAC * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @mac_type: one of IWM_FW_MAC_TYPE_* * @tsd_id: TSF HW timer, one of IWM_TSF_ID_* * @node_addr: MAC address * @bssid_addr: BSSID * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM * @protection_flags: combination of IWM_MAC_PROT_FLG_FLAG_* * @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise * @short_slot: 0x10 for enabling short slots, 0 otherwise * @filter_flags: combination of IWM_MAC_FILTER_* * @qos_flags: from IWM_MAC_QOS_FLG_* * @ac: one iwm_mac_qos configuration for each AC * @mac_specific: one of struct iwm_mac_data_*, according to mac_type */ struct iwm_mac_ctx_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWM_MAC_CONTEXT_COMMON_DATA_API_S_VER_1 */ uint32_t mac_type; uint32_t tsf_id; uint8_t node_addr[6]; uint16_t reserved_for_node_addr; uint8_t bssid_addr[6]; uint16_t reserved_for_bssid_addr; uint32_t cck_rates; uint32_t ofdm_rates; uint32_t protection_flags; uint32_t cck_short_preamble; uint32_t short_slot; uint32_t filter_flags; /* IWM_MAC_QOS_PARAM_API_S_VER_1 */ uint32_t qos_flags; struct iwm_ac_qos ac[IWM_AC_NUM+1]; /* IWM_MAC_CONTEXT_COMMON_DATA_API_S */ union { struct iwm_mac_data_ap ap; struct iwm_mac_data_go go; struct iwm_mac_data_sta sta; struct iwm_mac_data_p2p_sta p2p_sta; struct iwm_mac_data_p2p_dev p2p_dev; struct iwm_mac_data_pibss pibss; struct iwm_mac_data_ibss ibss; }; } __packed; /* IWM_MAC_CONTEXT_CMD_API_S_VER_1 */ static inline uint32_t iwm_mvm_reciprocal(uint32_t v) { if (!v) return 0; return 0xFFFFFFFF / v; } #define IWM_NONQOS_SEQ_GET 0x1 #define IWM_NONQOS_SEQ_SET 0x2 struct iwm_nonqos_seq_query_cmd { uint32_t get_set_flag; uint32_t mac_id_n_color; uint16_t value; uint16_t reserved; } __packed; /* IWM_NON_QOS_TX_COUNTER_GET_SET_API_S_VER_1 */ /* * END mvm/fw-api-mac.h */ /* * BEGIN mvm/fw-api-power.h */ /* Power Management Commands, Responses, Notifications */ /* Radio LP RX Energy Threshold measured in dBm */ #define IWM_POWER_LPRX_RSSI_THRESHOLD 75 #define IWM_POWER_LPRX_RSSI_THRESHOLD_MAX 94 #define IWM_POWER_LPRX_RSSI_THRESHOLD_MIN 30 /** * enum iwm_scan_flags - masks for power table command flags * @IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off * receiver and transmitter. '0' - does not allow. * @IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, * '1' Driver enables PM (use rest of parameters) * @IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, * '1' PM could sleep over DTIM till listen Interval. * @IWM_POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all * access categories are both delivery and trigger enabled. * @IWM_POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and * PBW Snoozing enabled * @IWM_POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask * @IWM_POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. * @IWM_POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving * detection enablement */ enum iwm_power_flags { IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK = (1 << 0), IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = (1 << 1), IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK = (1 << 2), IWM_POWER_FLAGS_SNOOZE_ENA_MSK = (1 << 5), IWM_POWER_FLAGS_BT_SCO_ENA = (1 << 8), IWM_POWER_FLAGS_ADVANCE_PM_ENA_MSK = (1 << 9), IWM_POWER_FLAGS_LPRX_ENA_MSK = (1 << 11), IWM_POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK = (1 << 12), }; #define IWM_POWER_VEC_SIZE 5 /** * struct iwm_powertable_cmd - legacy power command. Beside old API support this * is used also with a new power API for device wide power settings. * IWM_POWER_TABLE_CMD = 0x77 (command, has simple generic response) * * @flags: Power table command flags from IWM_POWER_FLAGS_* * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. * Minimum allowed:- 3 * DTIM. Keep alive period must be * set regardless of power scheme or current power state. * FW use this value also when PM is disabled. * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to * PSM transition - legacy PM * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to * PSM transition - legacy PM * @sleep_interval: not in use * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag * is set. For example, if it is required to skip over * one DTIM, this value need to be set to 2 (DTIM periods). * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. * Default: 80dbm */ struct iwm_powertable_cmd { /* PM_POWER_TABLE_CMD_API_S_VER_6 */ uint16_t flags; uint8_t keep_alive_seconds; uint8_t debug_flags; uint32_t rx_data_timeout; uint32_t tx_data_timeout; uint32_t sleep_interval[IWM_POWER_VEC_SIZE]; uint32_t skip_dtim_periods; uint32_t lprx_rssi_threshold; } __packed; /** * enum iwm_device_power_flags - masks for device power command flags * @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off * receiver and transmitter. '0' - does not allow. This flag should be * always set to '1' unless one need to disable actual power down for debug * purposes. * @IWM_DEVICE_POWER_FLAGS_CAM_MSK: '1' CAM (Continuous Active Mode) is set, meaning * that power management is disabled. '0' Power management is enabled, one * of power schemes is applied. */ enum iwm_device_power_flags { IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK = (1 << 0), IWM_DEVICE_POWER_FLAGS_CAM_MSK = (1 << 13), }; /** * struct iwm_device_power_cmd - device wide power command. * IWM_DEVICE_POWER_CMD = 0x77 (command, has simple generic response) * * @flags: Power table command flags from IWM_DEVICE_POWER_FLAGS_* */ struct iwm_device_power_cmd { /* PM_POWER_TABLE_CMD_API_S_VER_6 */ uint16_t flags; uint16_t reserved; } __packed; /** * struct iwm_mac_power_cmd - New power command containing uAPSD support * IWM_MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) * @id_and_color: MAC contex identifier * @flags: Power table command flags from POWER_FLAGS_* * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. * Minimum allowed:- 3 * DTIM. Keep alive period must be * set regardless of power scheme or current power state. * FW use this value also when PM is disabled. * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to * PSM transition - legacy PM * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to * PSM transition - legacy PM * @sleep_interval: not in use * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag * is set. For example, if it is required to skip over * one DTIM, this value need to be set to 2 (DTIM periods). * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to * PSM transition - uAPSD * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to * PSM transition - uAPSD * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. * Default: 80dbm * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set * @snooze_interval: Maximum time between attempts to retrieve buffered data * from the AP [msec] * @snooze_window: A window of time in which PBW snoozing insures that all * packets received. It is also the minimum time from last * received unicast RX packet, before client stops snoozing * for data. [msec] * @snooze_step: TBD * @qndp_tid: TID client shall use for uAPSD QNDP triggers * @uapsd_ac_flags: Set trigger-enabled and delivery-enabled indication for * each corresponding AC. * Use IEEE80211_WMM_IE_STA_QOSINFO_AC* for correct values. * @uapsd_max_sp: Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct * values. * @heavy_tx_thld_packets: TX threshold measured in number of packets * @heavy_rx_thld_packets: RX threshold measured in number of packets * @heavy_tx_thld_percentage: TX threshold measured in load's percentage * @heavy_rx_thld_percentage: RX threshold measured in load's percentage * @limited_ps_threshold: */ struct iwm_mac_power_cmd { /* CONTEXT_DESC_API_T_VER_1 */ uint32_t id_and_color; /* CLIENT_PM_POWER_TABLE_S_VER_1 */ uint16_t flags; uint16_t keep_alive_seconds; uint32_t rx_data_timeout; uint32_t tx_data_timeout; uint32_t rx_data_timeout_uapsd; uint32_t tx_data_timeout_uapsd; uint8_t lprx_rssi_threshold; uint8_t skip_dtim_periods; uint16_t snooze_interval; uint16_t snooze_window; uint8_t snooze_step; uint8_t qndp_tid; uint8_t uapsd_ac_flags; uint8_t uapsd_max_sp; uint8_t heavy_tx_thld_packets; uint8_t heavy_rx_thld_packets; uint8_t heavy_tx_thld_percentage; uint8_t heavy_rx_thld_percentage; uint8_t limited_ps_threshold; uint8_t reserved; } __packed; /* * struct iwm_uapsd_misbehaving_ap_notif - FW sends this notification when * associated AP is identified as improperly implementing uAPSD protocol. * IWM_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78 * @sta_id: index of station in uCode's station table - associated AP ID in * this context. */ struct iwm_uapsd_misbehaving_ap_notif { uint32_t sta_id; uint8_t mac_id; uint8_t reserved[3]; } __packed; /** * struct iwm_beacon_filter_cmd * IWM_REPLY_BEACON_FILTERING_CMD = 0xd2 (command) * @id_and_color: MAC contex identifier * @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon * to driver if delta in Energy values calculated for this and last * passed beacon is greater than this threshold. Zero value means that * the Energy change is ignored for beacon filtering, and beacon will * not be forced to be sent to driver regardless of this delta. Typical * energy delta 5dB. * @bf_roaming_energy_delta: Used for RSSI filtering, if in 'roaming' state. * Send beacon to driver if delta in Energy values calculated for this * and last passed beacon is greater than this threshold. Zero value * means that the Energy change is ignored for beacon filtering while in * Roaming state, typical energy delta 1dB. * @bf_roaming_state: Used for RSSI filtering. If absolute Energy values * calculated for current beacon is less than the threshold, use * Roaming Energy Delta Threshold, otherwise use normal Energy Delta * Threshold. Typical energy threshold is -72dBm. * @bf_temp_threshold: This threshold determines the type of temperature * filtering (Slow or Fast) that is selected (Units are in Celsuis): * If the current temperature is above this threshold - Fast filter * will be used, If the current temperature is below this threshold - * Slow filter will be used. * @bf_temp_fast_filter: Send Beacon to driver if delta in temperature values * calculated for this and the last passed beacon is greater than this * threshold. Zero value means that the temperature change is ignored for * beacon filtering; beacons will not be forced to be sent to driver * regardless of whether its temperature has been changed. * @bf_temp_slow_filter: Send Beacon to driver if delta in temperature values * calculated for this and the last passed beacon is greater than this * threshold. Zero value means that the temperature change is ignored for * beacon filtering; beacons will not be forced to be sent to driver * regardless of whether its temperature has been changed. * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled. * @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed * for a specific period of time. Units: Beacons. * @ba_escape_timer: Fully receive and parse beacon if no beacons were passed * for a longer period of time then this escape-timeout. Units: Beacons. * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled. */ struct iwm_beacon_filter_cmd { uint32_t bf_energy_delta; uint32_t bf_roaming_energy_delta; uint32_t bf_roaming_state; uint32_t bf_temp_threshold; uint32_t bf_temp_fast_filter; uint32_t bf_temp_slow_filter; uint32_t bf_enable_beacon_filter; uint32_t bf_debug_flag; uint32_t bf_escape_timer; uint32_t ba_escape_timer; uint32_t ba_enable_beacon_abort; } __packed; /* Beacon filtering and beacon abort */ #define IWM_BF_ENERGY_DELTA_DEFAULT 5 #define IWM_BF_ENERGY_DELTA_MAX 255 #define IWM_BF_ENERGY_DELTA_MIN 0 #define IWM_BF_ROAMING_ENERGY_DELTA_DEFAULT 1 #define IWM_BF_ROAMING_ENERGY_DELTA_MAX 255 #define IWM_BF_ROAMING_ENERGY_DELTA_MIN 0 #define IWM_BF_ROAMING_STATE_DEFAULT 72 #define IWM_BF_ROAMING_STATE_MAX 255 #define IWM_BF_ROAMING_STATE_MIN 0 #define IWM_BF_TEMP_THRESHOLD_DEFAULT 112 #define IWM_BF_TEMP_THRESHOLD_MAX 255 #define IWM_BF_TEMP_THRESHOLD_MIN 0 #define IWM_BF_TEMP_FAST_FILTER_DEFAULT 1 #define IWM_BF_TEMP_FAST_FILTER_MAX 255 #define IWM_BF_TEMP_FAST_FILTER_MIN 0 #define IWM_BF_TEMP_SLOW_FILTER_DEFAULT 5 #define IWM_BF_TEMP_SLOW_FILTER_MAX 255 #define IWM_BF_TEMP_SLOW_FILTER_MIN 0 #define IWM_BF_ENABLE_BEACON_FILTER_DEFAULT 1 #define IWM_BF_DEBUG_FLAG_DEFAULT 0 #define IWM_BF_ESCAPE_TIMER_DEFAULT 50 #define IWM_BF_ESCAPE_TIMER_MAX 1024 #define IWM_BF_ESCAPE_TIMER_MIN 0 #define IWM_BA_ESCAPE_TIMER_DEFAULT 6 #define IWM_BA_ESCAPE_TIMER_D3 9 #define IWM_BA_ESCAPE_TIMER_MAX 1024 #define IWM_BA_ESCAPE_TIMER_MIN 0 #define IWM_BA_ENABLE_BEACON_ABORT_DEFAULT 1 #define IWM_BF_CMD_CONFIG_DEFAULTS \ .bf_energy_delta = htole32(IWM_BF_ENERGY_DELTA_DEFAULT), \ .bf_roaming_energy_delta = \ htole32(IWM_BF_ROAMING_ENERGY_DELTA_DEFAULT), \ .bf_roaming_state = htole32(IWM_BF_ROAMING_STATE_DEFAULT), \ .bf_temp_threshold = htole32(IWM_BF_TEMP_THRESHOLD_DEFAULT), \ .bf_temp_fast_filter = htole32(IWM_BF_TEMP_FAST_FILTER_DEFAULT), \ .bf_temp_slow_filter = htole32(IWM_BF_TEMP_SLOW_FILTER_DEFAULT), \ .bf_debug_flag = htole32(IWM_BF_DEBUG_FLAG_DEFAULT), \ .bf_escape_timer = htole32(IWM_BF_ESCAPE_TIMER_DEFAULT), \ .ba_escape_timer = htole32(IWM_BA_ESCAPE_TIMER_DEFAULT) /* * END mvm/fw-api-power.h */ /* * BEGIN mvm/fw-api-rs.h */ /* * These serve as indexes into * struct iwm_rate_info fw_rate_idx_to_plcp[IWM_RATE_COUNT]; * TODO: avoid overlap between legacy and HT rates */ enum { IWM_RATE_1M_INDEX = 0, IWM_FIRST_CCK_RATE = IWM_RATE_1M_INDEX, IWM_RATE_2M_INDEX, IWM_RATE_5M_INDEX, IWM_RATE_11M_INDEX, IWM_LAST_CCK_RATE = IWM_RATE_11M_INDEX, IWM_RATE_6M_INDEX, IWM_FIRST_OFDM_RATE = IWM_RATE_6M_INDEX, IWM_RATE_MCS_0_INDEX = IWM_RATE_6M_INDEX, IWM_FIRST_HT_RATE = IWM_RATE_MCS_0_INDEX, IWM_FIRST_VHT_RATE = IWM_RATE_MCS_0_INDEX, IWM_RATE_9M_INDEX, IWM_RATE_12M_INDEX, IWM_RATE_MCS_1_INDEX = IWM_RATE_12M_INDEX, IWM_RATE_18M_INDEX, IWM_RATE_MCS_2_INDEX = IWM_RATE_18M_INDEX, IWM_RATE_24M_INDEX, IWM_RATE_MCS_3_INDEX = IWM_RATE_24M_INDEX, IWM_RATE_36M_INDEX, IWM_RATE_MCS_4_INDEX = IWM_RATE_36M_INDEX, IWM_RATE_48M_INDEX, IWM_RATE_MCS_5_INDEX = IWM_RATE_48M_INDEX, IWM_RATE_54M_INDEX, IWM_RATE_MCS_6_INDEX = IWM_RATE_54M_INDEX, IWM_LAST_NON_HT_RATE = IWM_RATE_54M_INDEX, IWM_RATE_60M_INDEX, IWM_RATE_MCS_7_INDEX = IWM_RATE_60M_INDEX, IWM_LAST_HT_RATE = IWM_RATE_MCS_7_INDEX, IWM_RATE_MCS_8_INDEX, IWM_RATE_MCS_9_INDEX, IWM_LAST_VHT_RATE = IWM_RATE_MCS_9_INDEX, IWM_RATE_COUNT_LEGACY = IWM_LAST_NON_HT_RATE + 1, IWM_RATE_COUNT = IWM_LAST_VHT_RATE + 1, }; #define IWM_RATE_BIT_MSK(r) (1 << (IWM_RATE_##r##M_INDEX)) /* fw API values for legacy bit rates, both OFDM and CCK */ enum { IWM_RATE_6M_PLCP = 13, IWM_RATE_9M_PLCP = 15, IWM_RATE_12M_PLCP = 5, IWM_RATE_18M_PLCP = 7, IWM_RATE_24M_PLCP = 9, IWM_RATE_36M_PLCP = 11, IWM_RATE_48M_PLCP = 1, IWM_RATE_54M_PLCP = 3, IWM_RATE_1M_PLCP = 10, IWM_RATE_2M_PLCP = 20, IWM_RATE_5M_PLCP = 55, IWM_RATE_11M_PLCP = 110, IWM_RATE_INVM_PLCP = -1, }; /* * rate_n_flags bit fields * * The 32-bit value has different layouts in the low 8 bites depending on the * format. There are three formats, HT, VHT and legacy (11abg, with subformats * for CCK and OFDM). * * High-throughput (HT) rate format * bit 8 is 1, bit 26 is 0, bit 9 is 0 (OFDM) * Very High-throughput (VHT) rate format * bit 8 is 0, bit 26 is 1, bit 9 is 0 (OFDM) * Legacy OFDM rate format for bits 7:0 * bit 8 is 0, bit 26 is 0, bit 9 is 0 (OFDM) * Legacy CCK rate format for bits 7:0: * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK) */ /* Bit 8: (1) HT format, (0) legacy or VHT format */ #define IWM_RATE_MCS_HT_POS 8 #define IWM_RATE_MCS_HT_MSK (1 << IWM_RATE_MCS_HT_POS) /* Bit 9: (1) CCK, (0) OFDM. HT (bit 8) must be "0" for this bit to be valid */ #define IWM_RATE_MCS_CCK_POS 9 #define IWM_RATE_MCS_CCK_MSK (1 << IWM_RATE_MCS_CCK_POS) /* Bit 26: (1) VHT format, (0) legacy format in bits 8:0 */ #define IWM_RATE_MCS_VHT_POS 26 #define IWM_RATE_MCS_VHT_MSK (1 << IWM_RATE_MCS_VHT_POS) /* * High-throughput (HT) rate format for bits 7:0 * * 2-0: MCS rate base * 0) 6 Mbps * 1) 12 Mbps * 2) 18 Mbps * 3) 24 Mbps * 4) 36 Mbps * 5) 48 Mbps * 6) 54 Mbps * 7) 60 Mbps * 4-3: 0) Single stream (SISO) * 1) Dual stream (MIMO) * 2) Triple stream (MIMO) * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data * (bits 7-6 are zero) * * Together the low 5 bits work out to the MCS index because we don't * support MCSes above 15/23, and 0-7 have one stream, 8-15 have two * streams and 16-23 have three streams. We could also support MCS 32 * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.) */ #define IWM_RATE_HT_MCS_RATE_CODE_MSK 0x7 #define IWM_RATE_HT_MCS_NSS_POS 3 #define IWM_RATE_HT_MCS_NSS_MSK (3 << IWM_RATE_HT_MCS_NSS_POS) /* Bit 10: (1) Use Green Field preamble */ #define IWM_RATE_HT_MCS_GF_POS 10 #define IWM_RATE_HT_MCS_GF_MSK (1 << IWM_RATE_HT_MCS_GF_POS) #define IWM_RATE_HT_MCS_INDEX_MSK 0x3f /* * Very High-throughput (VHT) rate format for bits 7:0 * * 3-0: VHT MCS (0-9) * 5-4: number of streams - 1: * 0) Single stream (SISO) * 1) Dual stream (MIMO) * 2) Triple stream (MIMO) */ /* Bit 4-5: (0) SISO, (1) MIMO2 (2) MIMO3 */ #define IWM_RATE_VHT_MCS_RATE_CODE_MSK 0xf #define IWM_RATE_VHT_MCS_NSS_POS 4 #define IWM_RATE_VHT_MCS_NSS_MSK (3 << IWM_RATE_VHT_MCS_NSS_POS) /* * Legacy OFDM rate format for bits 7:0 * * 3-0: 0xD) 6 Mbps * 0xF) 9 Mbps * 0x5) 12 Mbps * 0x7) 18 Mbps * 0x9) 24 Mbps * 0xB) 36 Mbps * 0x1) 48 Mbps * 0x3) 54 Mbps * (bits 7-4 are 0) * * Legacy CCK rate format for bits 7:0: * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK): * * 6-0: 10) 1 Mbps * 20) 2 Mbps * 55) 5.5 Mbps * 110) 11 Mbps * (bit 7 is 0) */ #define IWM_RATE_LEGACY_RATE_MSK 0xff /* * Bit 11-12: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz * 0 and 1 are valid for HT and VHT, 2 and 3 only for VHT */ #define IWM_RATE_MCS_CHAN_WIDTH_POS 11 #define IWM_RATE_MCS_CHAN_WIDTH_MSK (3 << IWM_RATE_MCS_CHAN_WIDTH_POS) #define IWM_RATE_MCS_CHAN_WIDTH_20 (0 << IWM_RATE_MCS_CHAN_WIDTH_POS) #define IWM_RATE_MCS_CHAN_WIDTH_40 (1 << IWM_RATE_MCS_CHAN_WIDTH_POS) #define IWM_RATE_MCS_CHAN_WIDTH_80 (2 << IWM_RATE_MCS_CHAN_WIDTH_POS) #define IWM_RATE_MCS_CHAN_WIDTH_160 (3 << IWM_RATE_MCS_CHAN_WIDTH_POS) /* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */ #define IWM_RATE_MCS_SGI_POS 13 #define IWM_RATE_MCS_SGI_MSK (1 << IWM_RATE_MCS_SGI_POS) /* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C */ #define IWM_RATE_MCS_ANT_POS 14 #define IWM_RATE_MCS_ANT_A_MSK (1 << IWM_RATE_MCS_ANT_POS) #define IWM_RATE_MCS_ANT_B_MSK (2 << IWM_RATE_MCS_ANT_POS) #define IWM_RATE_MCS_ANT_C_MSK (4 << IWM_RATE_MCS_ANT_POS) #define IWM_RATE_MCS_ANT_AB_MSK (IWM_RATE_MCS_ANT_A_MSK | \ IWM_RATE_MCS_ANT_B_MSK) #define IWM_RATE_MCS_ANT_ABC_MSK (IWM_RATE_MCS_ANT_AB_MSK | \ IWM_RATE_MCS_ANT_C_MSK) #define IWM_RATE_MCS_ANT_MSK IWM_RATE_MCS_ANT_ABC_MSK #define IWM_RATE_MCS_ANT_NUM 3 /* Bit 17-18: (0) SS, (1) SS*2 */ #define IWM_RATE_MCS_STBC_POS 17 #define IWM_RATE_MCS_STBC_MSK (1 << IWM_RATE_MCS_STBC_POS) /* Bit 19: (0) Beamforming is off, (1) Beamforming is on */ #define IWM_RATE_MCS_BF_POS 19 #define IWM_RATE_MCS_BF_MSK (1 << IWM_RATE_MCS_BF_POS) /* Bit 20: (0) ZLF is off, (1) ZLF is on */ #define IWM_RATE_MCS_ZLF_POS 20 #define IWM_RATE_MCS_ZLF_MSK (1 << IWM_RATE_MCS_ZLF_POS) /* Bit 24-25: (0) 20MHz (no dup), (1) 2x20MHz, (2) 4x20MHz, 3 8x20MHz */ #define IWM_RATE_MCS_DUP_POS 24 #define IWM_RATE_MCS_DUP_MSK (3 << IWM_RATE_MCS_DUP_POS) /* Bit 27: (1) LDPC enabled, (0) LDPC disabled */ #define IWM_RATE_MCS_LDPC_POS 27 #define IWM_RATE_MCS_LDPC_MSK (1 << IWM_RATE_MCS_LDPC_POS) /* Link Quality definitions */ /* # entries in rate scale table to support Tx retries */ #define IWM_LQ_MAX_RETRY_NUM 16 /* Link quality command flags bit fields */ /* Bit 0: (0) Don't use RTS (1) Use RTS */ #define IWM_LQ_FLAG_USE_RTS_POS 0 #define IWM_LQ_FLAG_USE_RTS_MSK (1 << IWM_LQ_FLAG_USE_RTS_POS) /* Bit 1-3: LQ command color. Used to match responses to LQ commands */ #define IWM_LQ_FLAG_COLOR_POS 1 #define IWM_LQ_FLAG_COLOR_MSK (7 << IWM_LQ_FLAG_COLOR_POS) /* Bit 4-5: Tx RTS BW Signalling * (0) No RTS BW signalling * (1) Static BW signalling * (2) Dynamic BW signalling */ #define IWM_LQ_FLAG_RTS_BW_SIG_POS 4 #define IWM_LQ_FLAG_RTS_BW_SIG_NONE (0 << IWM_LQ_FLAG_RTS_BW_SIG_POS) #define IWM_LQ_FLAG_RTS_BW_SIG_STATIC (1 << IWM_LQ_FLAG_RTS_BW_SIG_POS) #define IWM_LQ_FLAG_RTS_BW_SIG_DYNAMIC (2 << IWM_LQ_FLAG_RTS_BW_SIG_POS) /* Bit 6: (0) No dynamic BW selection (1) Allow dynamic BW selection * Dyanmic BW selection allows Tx with narrower BW then requested in rates */ #define IWM_LQ_FLAG_DYNAMIC_BW_POS 6 #define IWM_LQ_FLAG_DYNAMIC_BW_MSK (1 << IWM_LQ_FLAG_DYNAMIC_BW_POS) /** * struct iwm_lq_cmd - link quality command * @sta_id: station to update * @control: not used * @flags: combination of IWM_LQ_FLAG_* * @mimo_delim: the first SISO index in rs_table, which separates MIMO * and SISO rates * @single_stream_ant_msk: best antenna for SISO (can be dual in CDD). * Should be ANT_[ABC] * @dual_stream_ant_msk: best antennas for MIMO, combination of ANT_[ABC] * @initial_rate_index: first index from rs_table per AC category * @agg_time_limit: aggregation max time threshold in usec/100, meaning * value of 100 is one usec. Range is 100 to 8000 * @agg_disable_start_th: try-count threshold for starting aggregation. * If a frame has higher try-count, it should not be selected for * starting an aggregation sequence. * @agg_frame_cnt_limit: max frame count in an aggregation. * 0: no limit * 1: no aggregation (one frame per aggregation) * 2 - 0x3f: maximal number of frames (up to 3f == 63) * @rs_table: array of rates for each TX try, each is rate_n_flags, * meaning it is a combination of IWM_RATE_MCS_* and IWM_RATE_*_PLCP * @bf_params: beam forming params, currently not used */ struct iwm_lq_cmd { uint8_t sta_id; uint8_t reserved1; uint16_t control; /* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */ uint8_t flags; uint8_t mimo_delim; uint8_t single_stream_ant_msk; uint8_t dual_stream_ant_msk; uint8_t initial_rate_index[IWM_AC_NUM]; /* LINK_QUAL_AGG_PARAMS_API_S_VER_1 */ uint16_t agg_time_limit; uint8_t agg_disable_start_th; uint8_t agg_frame_cnt_limit; uint32_t reserved2; uint32_t rs_table[IWM_LQ_MAX_RETRY_NUM]; uint32_t bf_params; }; /* LINK_QUALITY_CMD_API_S_VER_1 */ /* * END mvm/fw-api-rs.h */ /* * BEGIN mvm/fw-api-tx.h */ /** * enum iwm_tx_flags - bitmasks for tx_flags in TX command * @IWM_TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame * @IWM_TX_CMD_FLG_ACK: expect ACK from receiving station * @IWM_TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command. * Otherwise, use rate_n_flags from the TX command * @IWM_TX_CMD_FLG_BA: this frame is a block ack * @IWM_TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected * Must set IWM_TX_CMD_FLG_ACK with this flag. * @IWM_TX_CMD_FLG_TXOP_PROT: protect frame with full TXOP protection * @IWM_TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence * @IWM_TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence * @IWM_TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) * @IWM_TX_CMD_FLG_BT_DIS: disable BT priority for this frame * @IWM_TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control. * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command * @IWM_TX_CMD_FLG_MORE_FRAG: this frame is non-last MPDU * @IWM_TX_CMD_FLG_NEXT_FRAME: this frame includes information of the next frame * @IWM_TX_CMD_FLG_TSF: FW should calculate and insert TSF in the frame * Should be set for beacons and probe responses * @IWM_TX_CMD_FLG_CALIB: activate PA TX power calibrations * @IWM_TX_CMD_FLG_KEEP_SEQ_CTL: if seq_ctl is set, don't increase inner seq count * @IWM_TX_CMD_FLG_AGG_START: allow this frame to start aggregation * @IWM_TX_CMD_FLG_MH_PAD: driver inserted 2 byte padding after MAC header. * Should be set for 26/30 length MAC headers * @IWM_TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW * @IWM_TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration * @IWM_TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation * @IWM_TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id * @IWM_TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped * @IWM_TX_CMD_FLG_EXEC_PAPD: execute PAPD * @IWM_TX_CMD_FLG_PAPD_TYPE: 0 for reference power, 1 for nominal power * @IWM_TX_CMD_FLG_HCCA_CHUNK: mark start of TSPEC chunk */ enum iwm_tx_flags { IWM_TX_CMD_FLG_PROT_REQUIRE = (1 << 0), IWM_TX_CMD_FLG_ACK = (1 << 3), IWM_TX_CMD_FLG_STA_RATE = (1 << 4), IWM_TX_CMD_FLG_BA = (1 << 5), IWM_TX_CMD_FLG_BAR = (1 << 6), IWM_TX_CMD_FLG_TXOP_PROT = (1 << 7), IWM_TX_CMD_FLG_VHT_NDPA = (1 << 8), IWM_TX_CMD_FLG_HT_NDPA = (1 << 9), IWM_TX_CMD_FLG_CSI_FDBK2HOST = (1 << 10), IWM_TX_CMD_FLG_BT_DIS = (1 << 12), IWM_TX_CMD_FLG_SEQ_CTL = (1 << 13), IWM_TX_CMD_FLG_MORE_FRAG = (1 << 14), IWM_TX_CMD_FLG_NEXT_FRAME = (1 << 15), IWM_TX_CMD_FLG_TSF = (1 << 16), IWM_TX_CMD_FLG_CALIB = (1 << 17), IWM_TX_CMD_FLG_KEEP_SEQ_CTL = (1 << 18), IWM_TX_CMD_FLG_AGG_START = (1 << 19), IWM_TX_CMD_FLG_MH_PAD = (1 << 20), IWM_TX_CMD_FLG_RESP_TO_DRV = (1 << 21), IWM_TX_CMD_FLG_CCMP_AGG = (1 << 22), IWM_TX_CMD_FLG_TKIP_MIC_DONE = (1 << 23), IWM_TX_CMD_FLG_DUR = (1 << 25), IWM_TX_CMD_FLG_FW_DROP = (1 << 26), IWM_TX_CMD_FLG_EXEC_PAPD = (1 << 27), IWM_TX_CMD_FLG_PAPD_TYPE = (1 << 28), IWM_TX_CMD_FLG_HCCA_CHUNK = (1 << 31) }; /* IWM_TX_FLAGS_BITS_API_S_VER_1 */ /** * enum iwm_tx_pm_timeouts - pm timeout values in TX command * @IWM_PM_FRAME_NONE: no need to suspend sleep mode * @IWM_PM_FRAME_MGMT: fw suspend sleep mode for 100TU * @IWM_PM_FRAME_ASSOC: fw suspend sleep mode for 10sec */ enum iwm_tx_pm_timeouts { IWM_PM_FRAME_NONE = 0, IWM_PM_FRAME_MGMT = 2, IWM_PM_FRAME_ASSOC = 3, }; /* * TX command security control */ #define IWM_TX_CMD_SEC_WEP 0x01 #define IWM_TX_CMD_SEC_CCM 0x02 #define IWM_TX_CMD_SEC_TKIP 0x03 #define IWM_TX_CMD_SEC_EXT 0x04 #define IWM_TX_CMD_SEC_MSK 0x07 #define IWM_TX_CMD_SEC_WEP_KEY_IDX_POS 6 #define IWM_TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 #define IWM_TX_CMD_SEC_KEY128 0x08 /* TODO: how does these values are OK with only 16 bit variable??? */ /* * TX command next frame info * * bits 0:2 - security control (IWM_TX_CMD_SEC_*) * bit 3 - immediate ACK required * bit 4 - rate is taken from STA table * bit 5 - frame belongs to BA stream * bit 6 - immediate BA response expected * bit 7 - unused * bits 8:15 - Station ID * bits 16:31 - rate */ #define IWM_TX_CMD_NEXT_FRAME_ACK_MSK (0x8) #define IWM_TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10) #define IWM_TX_CMD_NEXT_FRAME_BA_MSK (0x20) #define IWM_TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40) #define IWM_TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8) #define IWM_TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00) #define IWM_TX_CMD_NEXT_FRAME_STA_ID_POS (8) #define IWM_TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000) #define IWM_TX_CMD_NEXT_FRAME_RATE_POS (16) /* * TX command Frame life time in us - to be written in pm_frame_timeout */ #define IWM_TX_CMD_LIFE_TIME_INFINITE 0xFFFFFFFF #define IWM_TX_CMD_LIFE_TIME_DEFAULT 2000000 /* 2000 ms*/ #define IWM_TX_CMD_LIFE_TIME_PROBE_RESP 40000 /* 40 ms */ #define IWM_TX_CMD_LIFE_TIME_EXPIRED_FRAME 0 /* * TID for non QoS frames - to be written in tid_tspec */ #define IWM_TID_NON_QOS IWM_MAX_TID_COUNT /* * Limits on the retransmissions - to be written in {data,rts}_retry_limit */ #define IWM_DEFAULT_TX_RETRY 15 #define IWM_MGMT_DFAULT_RETRY_LIMIT 3 #define IWM_RTS_DFAULT_RETRY_LIMIT 60 #define IWM_BAR_DFAULT_RETRY_LIMIT 60 #define IWM_LOW_RETRY_LIMIT 7 /* TODO: complete documentation for try_cnt and btkill_cnt */ /** * struct iwm_tx_cmd - TX command struct to FW * ( IWM_TX_CMD = 0x1c ) * @len: in bytes of the payload, see below for details * @next_frame_len: same as len, but for next frame (0 if not applicable) * Used for fragmentation and bursting, but not in 11n aggregation. * @tx_flags: combination of IWM_TX_CMD_FLG_* * @rate_n_flags: rate for *all* Tx attempts, if IWM_TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of IWM_RATE_MCS_* * @sta_id: index of destination station in FW station table * @sec_ctl: security control, IWM_TX_CMD_SEC_* * @initial_rate_index: index into the rate table for initial TX attempt. * Applied if IWM_TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames. * @key: security key * @next_frame_flags: IWM_TX_CMD_SEC_* and IWM_TX_CMD_NEXT_FRAME_* * @life_time: frame life time (usecs??) * @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt + * btkill_cnd + reserved), first 32 bits. "0" disables usage. * @dram_msb_ptr: upper bits of the scratch physical address * @rts_retry_limit: max attempts for RTS * @data_retry_limit: max attempts to send the data packet * @tid_spec: TID/tspec * @pm_frame_timeout: PM TX frame timeout * @driver_txop: duration od EDCA TXOP, in 32-usec units. Set this if not * specified by HCCA protocol * * The byte count (both len and next_frame_len) includes MAC header * (24/26/30/32 bytes) * + 2 bytes pad if 26/30 header size * + 8 byte IV for CCM or TKIP (not used for WEP) * + Data payload * + 8-byte MIC (not used for CCM/WEP) * It does not include post-MAC padding, i.e., * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes. * Range of len: 14-2342 bytes. * * After the struct fields the MAC header is placed, plus any padding, * and then the actial payload. */ struct iwm_tx_cmd { uint16_t len; uint16_t next_frame_len; uint32_t tx_flags; struct { uint8_t try_cnt; uint8_t btkill_cnt; uint16_t reserved; } scratch; /* DRAM_SCRATCH_API_U_VER_1 */ uint32_t rate_n_flags; uint8_t sta_id; uint8_t sec_ctl; uint8_t initial_rate_index; uint8_t reserved2; uint8_t key[16]; uint16_t next_frame_flags; uint16_t reserved3; uint32_t life_time; uint32_t dram_lsb_ptr; uint8_t dram_msb_ptr; uint8_t rts_retry_limit; uint8_t data_retry_limit; uint8_t tid_tspec; uint16_t pm_frame_timeout; uint16_t driver_txop; uint8_t payload[0]; struct ieee80211_frame hdr[0]; } __packed; /* IWM_TX_CMD_API_S_VER_3 */ /* * TX response related data */ /* * enum iwm_tx_status - status that is returned by the fw after attempts to Tx * @IWM_TX_STATUS_SUCCESS: * @IWM_TX_STATUS_DIRECT_DONE: * @IWM_TX_STATUS_POSTPONE_DELAY: * @IWM_TX_STATUS_POSTPONE_FEW_BYTES: * @IWM_TX_STATUS_POSTPONE_BT_PRIO: * @IWM_TX_STATUS_POSTPONE_QUIET_PERIOD: * @IWM_TX_STATUS_POSTPONE_CALC_TTAK: * @IWM_TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY: * @IWM_TX_STATUS_FAIL_SHORT_LIMIT: * @IWM_TX_STATUS_FAIL_LONG_LIMIT: * @IWM_TX_STATUS_FAIL_UNDERRUN: * @IWM_TX_STATUS_FAIL_DRAIN_FLOW: * @IWM_TX_STATUS_FAIL_RFKILL_FLUSH: * @IWM_TX_STATUS_FAIL_LIFE_EXPIRE: * @IWM_TX_STATUS_FAIL_DEST_PS: * @IWM_TX_STATUS_FAIL_HOST_ABORTED: * @IWM_TX_STATUS_FAIL_BT_RETRY: * @IWM_TX_STATUS_FAIL_STA_INVALID: * @IWM_TX_TATUS_FAIL_FRAG_DROPPED: * @IWM_TX_STATUS_FAIL_TID_DISABLE: * @IWM_TX_STATUS_FAIL_FIFO_FLUSHED: * @IWM_TX_STATUS_FAIL_SMALL_CF_POLL: * @IWM_TX_STATUS_FAIL_FW_DROP: * @IWM_TX_STATUS_FAIL_STA_COLOR_MISMATCH: mismatch between color of Tx cmd and * STA table * @IWM_TX_FRAME_STATUS_INTERNAL_ABORT: * @IWM_TX_MODE_MSK: * @IWM_TX_MODE_NO_BURST: * @IWM_TX_MODE_IN_BURST_SEQ: * @IWM_TX_MODE_FIRST_IN_BURST: * @IWM_TX_QUEUE_NUM_MSK: * * Valid only if frame_count =1 * TODO: complete documentation */ enum iwm_tx_status { IWM_TX_STATUS_MSK = 0x000000ff, IWM_TX_STATUS_SUCCESS = 0x01, IWM_TX_STATUS_DIRECT_DONE = 0x02, /* postpone TX */ IWM_TX_STATUS_POSTPONE_DELAY = 0x40, IWM_TX_STATUS_POSTPONE_FEW_BYTES = 0x41, IWM_TX_STATUS_POSTPONE_BT_PRIO = 0x42, IWM_TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43, IWM_TX_STATUS_POSTPONE_CALC_TTAK = 0x44, /* abort TX */ IWM_TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81, IWM_TX_STATUS_FAIL_SHORT_LIMIT = 0x82, IWM_TX_STATUS_FAIL_LONG_LIMIT = 0x83, IWM_TX_STATUS_FAIL_UNDERRUN = 0x84, IWM_TX_STATUS_FAIL_DRAIN_FLOW = 0x85, IWM_TX_STATUS_FAIL_RFKILL_FLUSH = 0x86, IWM_TX_STATUS_FAIL_LIFE_EXPIRE = 0x87, IWM_TX_STATUS_FAIL_DEST_PS = 0x88, IWM_TX_STATUS_FAIL_HOST_ABORTED = 0x89, IWM_TX_STATUS_FAIL_BT_RETRY = 0x8a, IWM_TX_STATUS_FAIL_STA_INVALID = 0x8b, IWM_TX_STATUS_FAIL_FRAG_DROPPED = 0x8c, IWM_TX_STATUS_FAIL_TID_DISABLE = 0x8d, IWM_TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e, IWM_TX_STATUS_FAIL_SMALL_CF_POLL = 0x8f, IWM_TX_STATUS_FAIL_FW_DROP = 0x90, IWM_TX_STATUS_FAIL_STA_COLOR_MISMATCH = 0x91, IWM_TX_STATUS_INTERNAL_ABORT = 0x92, IWM_TX_MODE_MSK = 0x00000f00, IWM_TX_MODE_NO_BURST = 0x00000000, IWM_TX_MODE_IN_BURST_SEQ = 0x00000100, IWM_TX_MODE_FIRST_IN_BURST = 0x00000200, IWM_TX_QUEUE_NUM_MSK = 0x0001f000, IWM_TX_NARROW_BW_MSK = 0x00060000, IWM_TX_NARROW_BW_1DIV2 = 0x00020000, IWM_TX_NARROW_BW_1DIV4 = 0x00040000, IWM_TX_NARROW_BW_1DIV8 = 0x00060000, }; /* * enum iwm_tx_agg_status - TX aggregation status * @IWM_AGG_TX_STATE_STATUS_MSK: * @IWM_AGG_TX_STATE_TRANSMITTED: * @IWM_AGG_TX_STATE_UNDERRUN: * @IWM_AGG_TX_STATE_BT_PRIO: * @IWM_AGG_TX_STATE_FEW_BYTES: * @IWM_AGG_TX_STATE_ABORT: * @IWM_AGG_TX_STATE_LAST_SENT_TTL: * @IWM_AGG_TX_STATE_LAST_SENT_TRY_CNT: * @IWM_AGG_TX_STATE_LAST_SENT_BT_KILL: * @IWM_AGG_TX_STATE_SCD_QUERY: * @IWM_AGG_TX_STATE_TEST_BAD_CRC32: * @IWM_AGG_TX_STATE_RESPONSE: * @IWM_AGG_TX_STATE_DUMP_TX: * @IWM_AGG_TX_STATE_DELAY_TX: * @IWM_AGG_TX_STATE_TRY_CNT_MSK: Retry count for 1st frame in aggregation (retries * occur if tx failed for this frame when it was a member of a previous * aggregation block). If rate scaling is used, retry count indicates the * rate table entry used for all frames in the new agg. *@ IWM_AGG_TX_STATE_SEQ_NUM_MSK: Command ID and sequence number of Tx command for * this frame * * TODO: complete documentation */ enum iwm_tx_agg_status { IWM_AGG_TX_STATE_STATUS_MSK = 0x00fff, IWM_AGG_TX_STATE_TRANSMITTED = 0x000, IWM_AGG_TX_STATE_UNDERRUN = 0x001, IWM_AGG_TX_STATE_BT_PRIO = 0x002, IWM_AGG_TX_STATE_FEW_BYTES = 0x004, IWM_AGG_TX_STATE_ABORT = 0x008, IWM_AGG_TX_STATE_LAST_SENT_TTL = 0x010, IWM_AGG_TX_STATE_LAST_SENT_TRY_CNT = 0x020, IWM_AGG_TX_STATE_LAST_SENT_BT_KILL = 0x040, IWM_AGG_TX_STATE_SCD_QUERY = 0x080, IWM_AGG_TX_STATE_TEST_BAD_CRC32 = 0x0100, IWM_AGG_TX_STATE_RESPONSE = 0x1ff, IWM_AGG_TX_STATE_DUMP_TX = 0x200, IWM_AGG_TX_STATE_DELAY_TX = 0x400, IWM_AGG_TX_STATE_TRY_CNT_POS = 12, IWM_AGG_TX_STATE_TRY_CNT_MSK = 0xf << IWM_AGG_TX_STATE_TRY_CNT_POS, }; #define IWM_AGG_TX_STATE_LAST_SENT_MSK (IWM_AGG_TX_STATE_LAST_SENT_TTL| \ IWM_AGG_TX_STATE_LAST_SENT_TRY_CNT| \ IWM_AGG_TX_STATE_LAST_SENT_BT_KILL) /* * The mask below describes a status where we are absolutely sure that the MPDU * wasn't sent. For BA/Underrun we cannot be that sure. All we know that we've * written the bytes to the TXE, but we know nothing about what the DSP did. */ #define IWM_AGG_TX_STAT_FRAME_NOT_SENT (IWM_AGG_TX_STATE_FEW_BYTES | \ IWM_AGG_TX_STATE_ABORT | \ IWM_AGG_TX_STATE_SCD_QUERY) /* * IWM_REPLY_TX = 0x1c (response) * * This response may be in one of two slightly different formats, indicated * by the frame_count field: * * 1) No aggregation (frame_count == 1). This reports Tx results for a single * frame. Multiple attempts, at various bit rates, may have been made for * this frame. * * 2) Aggregation (frame_count > 1). This reports Tx results for two or more * frames that used block-acknowledge. All frames were transmitted at * same rate. Rate scaling may have been used if first frame in this new * agg block failed in previous agg block(s). * * Note that, for aggregation, ACK (block-ack) status is not delivered * here; block-ack has not been received by the time the device records * this status. * This status relates to reasons the tx might have been blocked or aborted * within the device, rather than whether it was received successfully by * the destination station. */ /** * struct iwm_agg_tx_status - per packet TX aggregation status * @status: enum iwm_tx_agg_status * @sequence: Sequence # for this frame's Tx cmd (not SSN!) */ struct iwm_agg_tx_status { uint16_t status; uint16_t sequence; } __packed; /* * definitions for initial rate index field * bits [3:0] initial rate index * bits [6:4] rate table color, used for the initial rate * bit-7 invalid rate indication */ #define IWM_TX_RES_INIT_RATE_INDEX_MSK 0x0f #define IWM_TX_RES_RATE_TABLE_COLOR_MSK 0x70 #define IWM_TX_RES_INV_RATE_INDEX_MSK 0x80 #define IWM_MVM_TX_RES_GET_TID(_ra_tid) ((_ra_tid) & 0x0f) #define IWM_MVM_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4) /** * struct iwm_mvm_tx_resp - notifies that fw is TXing a packet * ( IWM_REPLY_TX = 0x1c ) * @frame_count: 1 no aggregation, >1 aggregation * @bt_kill_count: num of times blocked by bluetooth (unused for agg) * @failure_rts: num of failures due to unsuccessful RTS * @failure_frame: num failures due to no ACK (unused for agg) * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the * Tx of all the batch. IWM_RATE_MCS_* * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK. * for agg: RTS + CTS + aggregation tx time + block-ack time. * in usec. * @pa_status: tx power info * @pa_integ_res_a: tx power info * @pa_integ_res_b: tx power info * @pa_integ_res_c: tx power info * @measurement_req_id: tx power info * @tfd_info: TFD information set by the FH * @seq_ctl: sequence control from the Tx cmd * @byte_cnt: byte count from the Tx cmd * @tlc_info: TLC rate info * @ra_tid: bits [3:0] = ra, bits [7:4] = tid * @frame_ctrl: frame control * @status: for non-agg: frame status IWM_TX_STATUS_* * for agg: status of 1st frame, IWM_AGG_TX_STATE_*; other frame status fields * follow this one, up to frame_count. * * After the array of statuses comes the SSN of the SCD. Look at * %iwm_mvm_get_scd_ssn for more details. */ struct iwm_mvm_tx_resp { uint8_t frame_count; uint8_t bt_kill_count; uint8_t failure_rts; uint8_t failure_frame; uint32_t initial_rate; uint16_t wireless_media_time; uint8_t pa_status; uint8_t pa_integ_res_a[3]; uint8_t pa_integ_res_b[3]; uint8_t pa_integ_res_c[3]; uint16_t measurement_req_id; uint16_t reserved; uint32_t tfd_info; uint16_t seq_ctl; uint16_t byte_cnt; uint8_t tlc_info; uint8_t ra_tid; uint16_t frame_ctrl; struct iwm_agg_tx_status status; } __packed; /* IWM_TX_RSP_API_S_VER_3 */ /** * struct iwm_mvm_ba_notif - notifies about reception of BA * ( IWM_BA_NOTIF = 0xc5 ) * @sta_addr_lo32: lower 32 bits of the MAC address * @sta_addr_hi16: upper 16 bits of the MAC address * @sta_id: Index of recipient (BA-sending) station in fw's station table * @tid: tid of the session * @seq_ctl: * @bitmap: the bitmap of the BA notification as seen in the air * @scd_flow: the tx queue this BA relates to * @scd_ssn: the index of the last contiguously sent packet * @txed: number of Txed frames in this batch * @txed_2_done: number of Acked frames in this batch */ struct iwm_mvm_ba_notif { uint32_t sta_addr_lo32; uint16_t sta_addr_hi16; uint16_t reserved; uint8_t sta_id; uint8_t tid; uint16_t seq_ctl; uint64_t bitmap; uint16_t scd_flow; uint16_t scd_ssn; uint8_t txed; uint8_t txed_2_done; uint16_t reserved1; } __packed; /* * struct iwm_mac_beacon_cmd - beacon template command * @tx: the tx commands associated with the beacon frame * @template_id: currently equal to the mac context id of the coresponding * mac. * @tim_idx: the offset of the tim IE in the beacon * @tim_size: the length of the tim IE * @frame: the template of the beacon frame */ struct iwm_mac_beacon_cmd { struct iwm_tx_cmd tx; uint32_t template_id; uint32_t tim_idx; uint32_t tim_size; struct ieee80211_frame frame[0]; } __packed; struct iwm_beacon_notif { struct iwm_mvm_tx_resp beacon_notify_hdr; uint64_t tsf; uint32_t ibss_mgr_status; } __packed; /** * enum iwm_dump_control - dump (flush) control flags * @IWM_DUMP_TX_FIFO_FLUSH: Dump MSDUs until the FIFO is empty * and the TFD queues are empty. */ enum iwm_dump_control { IWM_DUMP_TX_FIFO_FLUSH = (1 << 1), }; /** * struct iwm_tx_path_flush_cmd -- queue/FIFO flush command * @queues_ctl: bitmap of queues to flush * @flush_ctl: control flags * @reserved: reserved */ struct iwm_tx_path_flush_cmd { uint32_t queues_ctl; uint16_t flush_ctl; uint16_t reserved; } __packed; /* IWM_TX_PATH_FLUSH_CMD_API_S_VER_1 */ /** * iwm_mvm_get_scd_ssn - returns the SSN of the SCD * @tx_resp: the Tx response from the fw (agg or non-agg) * * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since * it can't know that everything will go well until the end of the AMPDU, it * can't know in advance the number of MPDUs that will be sent in the current * batch. This is why it writes the agg Tx response while it fetches the MPDUs. * Hence, it can't know in advance what the SSN of the SCD will be at the end * of the batch. This is why the SSN of the SCD is written at the end of the * whole struct at a variable offset. This function knows how to cope with the * variable offset and returns the SSN of the SCD. */ static inline uint32_t iwm_mvm_get_scd_ssn(struct iwm_mvm_tx_resp *tx_resp) { return le32_to_cpup((uint32_t *)&tx_resp->status + tx_resp->frame_count) & 0xfff; } /* * END mvm/fw-api-tx.h */ /* * BEGIN mvm/fw-api-scan.h */ /** * struct iwm_scd_txq_cfg_cmd - New txq hw scheduler config command * @token: * @sta_id: station id * @tid: * @scd_queue: scheduler queue to confiug * @enable: 1 queue enable, 0 queue disable * @aggregate: 1 aggregated queue, 0 otherwise * @tx_fifo: %enum iwm_mvm_tx_fifo * @window: BA window size * @ssn: SSN for the BA agreement */ struct iwm_scd_txq_cfg_cmd { uint8_t token; uint8_t sta_id; uint8_t tid; uint8_t scd_queue; uint8_t enable; uint8_t aggregate; uint8_t tx_fifo; uint8_t window; uint16_t ssn; uint16_t reserved; } __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */ /** * struct iwm_scd_txq_cfg_rsp * @token: taken from the command * @sta_id: station id from the command * @tid: tid from the command * @scd_queue: scd_queue from the command */ struct iwm_scd_txq_cfg_rsp { uint8_t token; uint8_t sta_id; uint8_t tid; uint8_t scd_queue; } __packed; /* SCD_QUEUE_CFG_RSP_API_S_VER_1 */ /* Scan Commands, Responses, Notifications */ /* Masks for iwm_scan_channel.type flags */ #define IWM_SCAN_CHANNEL_TYPE_ACTIVE (1 << 0) #define IWM_SCAN_CHANNEL_NSSIDS(x) (((1 << (x)) - 1) << 1) /* Max number of IEs for direct SSID scans in a command */ #define IWM_PROBE_OPTION_MAX 20 /** * struct iwm_ssid_ie - directed scan network information element * * Up to 20 of these may appear in IWM_REPLY_SCAN_CMD, * selected by "type" bit field in struct iwm_scan_channel; * each channel may select different ssids from among the 20 entries. * SSID IEs get transmitted in reverse order of entry. */ struct iwm_ssid_ie { uint8_t id; uint8_t len; uint8_t ssid[IEEE80211_NWID_LEN]; } __packed; /* IWM_SCAN_DIRECT_SSID_IE_API_S_VER_1 */ /* scan offload */ #define IWM_SCAN_MAX_BLACKLIST_LEN 64 #define IWM_SCAN_SHORT_BLACKLIST_LEN 16 #define IWM_SCAN_MAX_PROFILES 11 #define IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE 512 /* Default watchdog (in MS) for scheduled scan iteration */ #define IWM_SCHED_SCAN_WATCHDOG cpu_to_le16(15000) #define IWM_GOOD_CRC_TH_DEFAULT cpu_to_le16(1) #define IWM_CAN_ABORT_STATUS 1 #define IWM_FULL_SCAN_MULTIPLIER 5 #define IWM_FAST_SCHED_SCAN_ITERATIONS 3 #define IWM_MAX_SCHED_SCAN_PLANS 2 /** * iwm_scan_schedule_lmac - schedule of scan offload * @delay: delay between iterations, in seconds. * @iterations: num of scan iterations * @full_scan_mul: number of partial scans before each full scan */ struct iwm_scan_schedule_lmac { uint16_t delay; uint8_t iterations; uint8_t full_scan_mul; } __packed; /* SCAN_SCHEDULE_API_S */ /** * iwm_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S * @tx_flags: combination of TX_CMD_FLG_* * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* * @sta_id: index of destination station in FW station table * @reserved: for alignment and future use */ struct iwm_scan_req_tx_cmd { uint32_t tx_flags; uint32_t rate_n_flags; uint8_t sta_id; uint8_t reserved[3]; } __packed; enum iwm_scan_channel_flags_lmac { IWM_UNIFIED_SCAN_CHANNEL_FULL = (1 << 27), IWM_UNIFIED_SCAN_CHANNEL_PARTIAL = (1 << 28), }; /** * iwm_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2 * @flags: bits 1-20: directed scan to i'th ssid * other bits &enum iwm_scan_channel_flags_lmac * @channel_number: channel number 1-13 etc * @iter_count: scan iteration on this channel * @iter_interval: interval in seconds between iterations on one channel */ struct iwm_scan_channel_cfg_lmac { uint32_t flags; uint16_t channel_num; uint16_t iter_count; uint32_t iter_interval; } __packed; /* * iwm_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1 * @offset: offset in the data block * @len: length of the segment */ struct iwm_scan_probe_segment { uint16_t offset; uint16_t len; } __packed; /* iwm_scan_probe_req - PROBE_REQUEST_FRAME_API_S_VER_2 * @mac_header: first (and common) part of the probe * @band_data: band specific data * @common_data: last (and common) part of the probe * @buf: raw data block */ struct iwm_scan_probe_req { struct iwm_scan_probe_segment mac_header; struct iwm_scan_probe_segment band_data[2]; struct iwm_scan_probe_segment common_data; uint8_t buf[IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE]; } __packed; enum iwm_scan_channel_flags { IWM_SCAN_CHANNEL_FLAG_EBS = (1 << 0), IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE = (1 << 1), IWM_SCAN_CHANNEL_FLAG_CACHE_ADD = (1 << 2), }; /* iwm_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S * @flags: enum iwm_scan_channel_flags * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is * involved. * 1 - EBS is disabled. * 2 - every second scan will be full scan(and so on). */ struct iwm_scan_channel_opt { uint16_t flags; uint16_t non_ebs_ratio; } __packed; /** * iwm_mvm_lmac_scan_flags * @IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL: pass all beacons and probe responses * without filtering. * @IWM_MVM_LMAC_SCAN_FLAG_PASSIVE: force passive scan on all channels * @IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION: single channel scan * @IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification * @IWM_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching * @IWM_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented * @IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report * and DS parameter set IEs into probe requests. * @IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL: use extended dwell time on channels * 1, 6 and 11. * @IWM_MVM_LMAC_SCAN_FLAG_MATCH: Send match found notification on matches */ enum iwm_mvm_lmac_scan_flags { IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL = (1 << 0), IWM_MVM_LMAC_SCAN_FLAG_PASSIVE = (1 << 1), IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION = (1 << 2), IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE = (1 << 3), IWM_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS = (1 << 4), IWM_MVM_LMAC_SCAN_FLAG_FRAGMENTED = (1 << 5), IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED = (1 << 6), IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL = (1 << 7), IWM_MVM_LMAC_SCAN_FLAG_MATCH = (1 << 9), }; enum iwm_scan_priority { IWM_SCAN_PRIORITY_LOW, IWM_SCAN_PRIORITY_MEDIUM, IWM_SCAN_PRIORITY_HIGH, }; /** * iwm_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1 * @reserved1: for alignment and future use * @channel_num: num of channels to scan * @active-dwell: dwell time for active channels * @passive-dwell: dwell time for passive channels * @fragmented-dwell: dwell time for fragmented passive scan * @extended_dwell: dwell time for channels 1, 6 and 11 (in certain cases) * @reserved2: for alignment and future use * @rx_chain_selct: PHY_RX_CHAIN_* flags * @scan_flags: &enum iwm_mvm_lmac_scan_flags * @max_out_time: max time (in TU) to be out of associated channel * @suspend_time: pause scan this long (TUs) when returning to service channel * @flags: RXON flags * @filter_flags: RXON filter * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz * @direct_scan: list of SSIDs for directed active scan * @scan_prio: enum iwm_scan_priority * @iter_num: number of scan iterations * @delay: delay in seconds before first iteration * @schedule: two scheduling plans. The first one is finite, the second one can * be infinite. * @channel_opt: channel optimization options, for full and partial scan * @data: channel configuration and probe request packet. */ struct iwm_scan_req_lmac { /* SCAN_REQUEST_FIXED_PART_API_S_VER_7 */ uint32_t reserved1; uint8_t n_channels; uint8_t active_dwell; uint8_t passive_dwell; uint8_t fragmented_dwell; uint8_t extended_dwell; uint8_t reserved2; uint16_t rx_chain_select; uint32_t scan_flags; uint32_t max_out_time; uint32_t suspend_time; /* RX_ON_FLAGS_API_S_VER_1 */ uint32_t flags; uint32_t filter_flags; struct iwm_scan_req_tx_cmd tx_cmd[2]; struct iwm_ssid_ie direct_scan[IWM_PROBE_OPTION_MAX]; uint32_t scan_prio; /* SCAN_REQ_PERIODIC_PARAMS_API_S */ uint32_t iter_num; uint32_t delay; struct iwm_scan_schedule_lmac schedule[IWM_MAX_SCHED_SCAN_PLANS]; struct iwm_scan_channel_opt channel_opt[2]; uint8_t data[]; } __packed; /** * iwm_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 * @last_schedule_line: last schedule line executed (fast or regular) * @last_schedule_iteration: last scan iteration executed before scan abort * @status: enum iwm_scan_offload_complete_status * @ebs_status: EBS success status &enum iwm_scan_ebs_status * @time_after_last_iter; time in seconds elapsed after last iteration */ struct iwm_periodic_scan_complete { uint8_t last_schedule_line; uint8_t last_schedule_iteration; uint8_t status; uint8_t ebs_status; uint32_t time_after_last_iter; uint32_t reserved; } __packed; /* How many statistics are gathered for each channel */ #define IWM_SCAN_RESULTS_STATISTICS 1 /** * enum iwm_scan_complete_status - status codes for scan complete notifications * @IWM_SCAN_COMP_STATUS_OK: scan completed successfully * @IWM_SCAN_COMP_STATUS_ABORT: scan was aborted by user * @IWM_SCAN_COMP_STATUS_ERR_SLEEP: sending null sleep packet failed * @IWM_SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT: timeout before channel is ready * @IWM_SCAN_COMP_STATUS_ERR_PROBE: sending probe request failed * @IWM_SCAN_COMP_STATUS_ERR_WAKEUP: sending null wakeup packet failed * @IWM_SCAN_COMP_STATUS_ERR_ANTENNAS: invalid antennas chosen at scan command * @IWM_SCAN_COMP_STATUS_ERR_INTERNAL: internal error caused scan abort * @IWM_SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax * @IWM_SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful * (not an error!) * @IWM_SCAN_COMP_STATUS_ITERATION_END: indicates end of one repeatition the driver * asked for * @IWM_SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events */ enum iwm_scan_complete_status { IWM_SCAN_COMP_STATUS_OK = 0x1, IWM_SCAN_COMP_STATUS_ABORT = 0x2, IWM_SCAN_COMP_STATUS_ERR_SLEEP = 0x3, IWM_SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT = 0x4, IWM_SCAN_COMP_STATUS_ERR_PROBE = 0x5, IWM_SCAN_COMP_STATUS_ERR_WAKEUP = 0x6, IWM_SCAN_COMP_STATUS_ERR_ANTENNAS = 0x7, IWM_SCAN_COMP_STATUS_ERR_INTERNAL = 0x8, IWM_SCAN_COMP_STATUS_ERR_COEX = 0x9, IWM_SCAN_COMP_STATUS_P2P_ACTION_OK = 0xA, IWM_SCAN_COMP_STATUS_ITERATION_END = 0x0B, IWM_SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C, }; /** * struct iwm_scan_results_notif - scan results for one channel * ( IWM_SCAN_RESULTS_NOTIFICATION = 0x83 ) * @channel: which channel the results are from * @band: 0 for 5.2 GHz, 1 for 2.4 GHz * @probe_status: IWM_SCAN_PROBE_STATUS_*, indicates success of probe request * @num_probe_not_sent: # of request that weren't sent due to not enough time * @duration: duration spent in channel, in usecs * @statistics: statistics gathered for this channel */ struct iwm_scan_results_notif { uint8_t channel; uint8_t band; uint8_t probe_status; uint8_t num_probe_not_sent; uint32_t duration; uint32_t statistics[IWM_SCAN_RESULTS_STATISTICS]; } __packed; /* IWM_SCAN_RESULT_NTF_API_S_VER_2 */ enum iwm_scan_framework_client { IWM_SCAN_CLIENT_SCHED_SCAN = (1 << 0), IWM_SCAN_CLIENT_NETDETECT = (1 << 1), IWM_SCAN_CLIENT_ASSET_TRACKING = (1 << 2), }; /** * iwm_scan_offload_blacklist - IWM_SCAN_OFFLOAD_BLACKLIST_S * @ssid: MAC address to filter out * @reported_rssi: AP rssi reported to the host * @client_bitmap: clients ignore this entry - enum scan_framework_client */ struct iwm_scan_offload_blacklist { uint8_t ssid[IEEE80211_ADDR_LEN]; uint8_t reported_rssi; uint8_t client_bitmap; } __packed; enum iwm_scan_offload_network_type { IWM_NETWORK_TYPE_BSS = 1, IWM_NETWORK_TYPE_IBSS = 2, IWM_NETWORK_TYPE_ANY = 3, }; enum iwm_scan_offload_band_selection { IWM_SCAN_OFFLOAD_SELECT_2_4 = 0x4, IWM_SCAN_OFFLOAD_SELECT_5_2 = 0x8, IWM_SCAN_OFFLOAD_SELECT_ANY = 0xc, }; /** * iwm_scan_offload_profile - IWM_SCAN_OFFLOAD_PROFILE_S * @ssid_index: index to ssid list in fixed part * @unicast_cipher: encryption olgorithm to match - bitmap * @aut_alg: authentication olgorithm to match - bitmap * @network_type: enum iwm_scan_offload_network_type * @band_selection: enum iwm_scan_offload_band_selection * @client_bitmap: clients waiting for match - enum scan_framework_client */ struct iwm_scan_offload_profile { uint8_t ssid_index; uint8_t unicast_cipher; uint8_t auth_alg; uint8_t network_type; uint8_t band_selection; uint8_t client_bitmap; uint8_t reserved[2]; } __packed; /** * iwm_scan_offload_profile_cfg - IWM_SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1 * @blaclist: AP list to filter off from scan results * @profiles: profiles to search for match * @blacklist_len: length of blacklist * @num_profiles: num of profiles in the list * @match_notify: clients waiting for match found notification * @pass_match: clients waiting for the results * @active_clients: active clients bitmap - enum scan_framework_client * @any_beacon_notify: clients waiting for match notification without match */ struct iwm_scan_offload_profile_cfg { struct iwm_scan_offload_profile profiles[IWM_SCAN_MAX_PROFILES]; uint8_t blacklist_len; uint8_t num_profiles; uint8_t match_notify; uint8_t pass_match; uint8_t active_clients; uint8_t any_beacon_notify; uint8_t reserved[2]; } __packed; enum iwm_scan_offload_complete_status { IWM_SCAN_OFFLOAD_COMPLETED = 1, IWM_SCAN_OFFLOAD_ABORTED = 2, }; /** * struct iwm_lmac_scan_complete_notif - notifies end of scanning (all channels) * SCAN_COMPLETE_NTF_API_S_VER_3 * @scanned_channels: number of channels scanned (and number of valid results) * @status: one of SCAN_COMP_STATUS_* * @bt_status: BT on/off status * @last_channel: last channel that was scanned * @tsf_low: TSF timer (lower half) in usecs * @tsf_high: TSF timer (higher half) in usecs * @results: an array of scan results, only "scanned_channels" of them are valid */ struct iwm_lmac_scan_complete_notif { uint8_t scanned_channels; uint8_t status; uint8_t bt_status; uint8_t last_channel; uint32_t tsf_low; uint32_t tsf_high; struct iwm_scan_results_notif results[]; } __packed; /* * END mvm/fw-api-scan.h */ /* * BEGIN mvm/fw-api-sta.h */ /* UMAC Scan API */ /* The maximum of either of these cannot exceed 8, because we use an * 8-bit mask (see IWM_MVM_SCAN_MASK). */ #define IWM_MVM_MAX_UMAC_SCANS 8 #define IWM_MVM_MAX_LMAC_SCANS 1 enum iwm_scan_config_flags { IWM_SCAN_CONFIG_FLAG_ACTIVATE = (1 << 0), IWM_SCAN_CONFIG_FLAG_DEACTIVATE = (1 << 1), IWM_SCAN_CONFIG_FLAG_FORBID_CHUB_REQS = (1 << 2), IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS = (1 << 3), IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS = (1 << 8), IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS = (1 << 9), IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID = (1 << 10), IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES = (1 << 11), IWM_SCAN_CONFIG_FLAG_SET_EFFECTIVE_TIMES = (1 << 12), IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS = (1 << 13), IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES = (1 << 14), IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR = (1 << 15), IWM_SCAN_CONFIG_FLAG_SET_FRAGMENTED = (1 << 16), IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED = (1 << 17), IWM_SCAN_CONFIG_FLAG_SET_CAM_MODE = (1 << 18), IWM_SCAN_CONFIG_FLAG_CLEAR_CAM_MODE = (1 << 19), IWM_SCAN_CONFIG_FLAG_SET_PROMISC_MODE = (1 << 20), IWM_SCAN_CONFIG_FLAG_CLEAR_PROMISC_MODE = (1 << 21), /* Bits 26-31 are for num of channels in channel_array */ #define IWM_SCAN_CONFIG_N_CHANNELS(n) ((n) << 26) }; enum iwm_scan_config_rates { /* OFDM basic rates */ IWM_SCAN_CONFIG_RATE_6M = (1 << 0), IWM_SCAN_CONFIG_RATE_9M = (1 << 1), IWM_SCAN_CONFIG_RATE_12M = (1 << 2), IWM_SCAN_CONFIG_RATE_18M = (1 << 3), IWM_SCAN_CONFIG_RATE_24M = (1 << 4), IWM_SCAN_CONFIG_RATE_36M = (1 << 5), IWM_SCAN_CONFIG_RATE_48M = (1 << 6), IWM_SCAN_CONFIG_RATE_54M = (1 << 7), /* CCK basic rates */ IWM_SCAN_CONFIG_RATE_1M = (1 << 8), IWM_SCAN_CONFIG_RATE_2M = (1 << 9), IWM_SCAN_CONFIG_RATE_5M = (1 << 10), IWM_SCAN_CONFIG_RATE_11M = (1 << 11), /* Bits 16-27 are for supported rates */ #define IWM_SCAN_CONFIG_SUPPORTED_RATE(rate) ((rate) << 16) }; enum iwm_channel_flags { IWM_CHANNEL_FLAG_EBS = (1 << 0), IWM_CHANNEL_FLAG_ACCURATE_EBS = (1 << 1), IWM_CHANNEL_FLAG_EBS_ADD = (1 << 2), IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE = (1 << 3), }; /** * struct iwm_scan_config * @flags: enum scan_config_flags * @tx_chains: valid_tx antenna - ANT_* definitions * @rx_chains: valid_rx antenna - ANT_* definitions * @legacy_rates: default legacy rates - enum scan_config_rates * @out_of_channel_time: default max out of serving channel time * @suspend_time: default max suspend time * @dwell_active: default dwell time for active scan * @dwell_passive: default dwell time for passive scan * @dwell_fragmented: default dwell time for fragmented scan * @dwell_extended: default dwell time for channels 1, 6 and 11 * @mac_addr: default mac address to be used in probes * @bcast_sta_id: the index of the station in the fw * @channel_flags: default channel flags - enum iwm_channel_flags * scan_config_channel_flag * @channel_array: default supported channels */ struct iwm_scan_config { uint32_t flags; uint32_t tx_chains; uint32_t rx_chains; uint32_t legacy_rates; uint32_t out_of_channel_time; uint32_t suspend_time; uint8_t dwell_active; uint8_t dwell_passive; uint8_t dwell_fragmented; uint8_t dwell_extended; uint8_t mac_addr[IEEE80211_ADDR_LEN]; uint8_t bcast_sta_id; uint8_t channel_flags; uint8_t channel_array[]; } __packed; /* SCAN_CONFIG_DB_CMD_API_S */ /** * iwm_umac_scan_flags *@IWM_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request * can be preempted by other scan requests with higher priority. * The low priority scan will be resumed when the higher proirity scan is * completed. *@IWM_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver * when scan starts. */ enum iwm_umac_scan_flags { IWM_UMAC_SCAN_FLAG_PREEMPTIVE = (1 << 0), IWM_UMAC_SCAN_FLAG_START_NOTIF = (1 << 1), }; enum iwm_umac_scan_uid_offsets { IWM_UMAC_SCAN_UID_TYPE_OFFSET = 0, IWM_UMAC_SCAN_UID_SEQ_OFFSET = 8, }; enum iwm_umac_scan_general_flags { IWM_UMAC_SCAN_GEN_FLAGS_PERIODIC = (1 << 0), IWM_UMAC_SCAN_GEN_FLAGS_OVER_BT = (1 << 1), IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL = (1 << 2), IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE = (1 << 3), IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT = (1 << 4), IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE = (1 << 5), IWM_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID = (1 << 6), IWM_UMAC_SCAN_GEN_FLAGS_FRAGMENTED = (1 << 7), IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED = (1 << 8), IWM_UMAC_SCAN_GEN_FLAGS_MATCH = (1 << 9), IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL = (1 << 10), }; /** * struct iwm_scan_channel_cfg_umac * @flags: bitmap - 0-19: directed scan to i'th ssid. * @channel_num: channel number 1-13 etc. * @iter_count: repetition count for the channel. * @iter_interval: interval between two scan iterations on one channel. */ struct iwm_scan_channel_cfg_umac { uint32_t flags; #define IWM_SCAN_CHANNEL_UMAC_NSSIDS(x) ((1 << (x)) - 1) uint8_t channel_num; uint8_t iter_count; uint16_t iter_interval; } __packed; /* SCAN_CHANNEL_CFG_S_VER2 */ /** * struct iwm_scan_umac_schedule * @interval: interval in seconds between scan iterations * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop * @reserved: for alignment and future use */ struct iwm_scan_umac_schedule { uint16_t interval; uint8_t iter_count; uint8_t reserved; } __packed; /* SCAN_SCHED_PARAM_API_S_VER_1 */ /** * struct iwm_scan_req_umac_tail - the rest of the UMAC scan request command * parameters following channels configuration array. * @schedule: two scheduling plans. * @delay: delay in TUs before starting the first scan iteration * @reserved: for future use and alignment * @preq: probe request with IEs blocks * @direct_scan: list of SSIDs for directed active scan */ struct iwm_scan_req_umac_tail { /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ struct iwm_scan_umac_schedule schedule[IWM_MAX_SCHED_SCAN_PLANS]; uint16_t delay; uint16_t reserved; /* SCAN_PROBE_PARAMS_API_S_VER_1 */ struct iwm_scan_probe_req preq; struct iwm_ssid_ie direct_scan[IWM_PROBE_OPTION_MAX]; } __packed; /** * struct iwm_scan_req_umac * @flags: &enum iwm_umac_scan_flags * @uid: scan id, &enum iwm_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwm_scan_priority * @general_flags: &enum iwm_umac_scan_general_flags * @extended_dwell: dwell time for channels 1, 6 and 11 * @active_dwell: dwell time for active scan * @passive_dwell: dwell time for passive scan * @fragmented_dwell: dwell time for fragmented passive scan * @max_out_time: max out of serving channel time * @suspend_time: max suspend time * @scan_priority: scan internal prioritization &enum iwm_scan_priority * @channel_flags: &enum iwm_scan_channel_flags * @n_channels: num of channels in scan request * @reserved: for future use and alignment * @data: &struct iwm_scan_channel_cfg_umac and * &struct iwm_scan_req_umac_tail */ struct iwm_scan_req_umac { uint32_t flags; uint32_t uid; uint32_t ooc_priority; /* SCAN_GENERAL_PARAMS_API_S_VER_1 */ uint32_t general_flags; uint8_t extended_dwell; uint8_t active_dwell; uint8_t passive_dwell; uint8_t fragmented_dwell; uint32_t max_out_time; uint32_t suspend_time; uint32_t scan_priority; /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ uint8_t channel_flags; uint8_t n_channels; uint16_t reserved; uint8_t data[]; } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ /** * struct iwm_umac_scan_abort * @uid: scan id, &enum iwm_umac_scan_uid_offsets * @flags: reserved */ struct iwm_umac_scan_abort { uint32_t uid; uint32_t flags; } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ /** * struct iwm_umac_scan_complete * @uid: scan id, &enum iwm_umac_scan_uid_offsets * @last_schedule: last scheduling line * @last_iter: last scan iteration number * @scan status: &enum iwm_scan_offload_complete_status * @ebs_status: &enum iwm_scan_ebs_status * @time_from_last_iter: time elapsed from last iteration * @reserved: for future use */ struct iwm_umac_scan_complete { uint32_t uid; uint8_t last_schedule; uint8_t last_iter; uint8_t status; uint8_t ebs_status; uint32_t time_from_last_iter; uint32_t reserved; } __packed; /* SCAN_COMPLETE_NTF_UMAC_API_S_VER_1 */ #define IWM_SCAN_OFFLOAD_MATCHING_CHANNELS_LEN 5 /** * struct iwm_scan_offload_profile_match - match information * @bssid: matched bssid * @channel: channel where the match occurred * @energy: * @matching_feature: * @matching_channels: bitmap of channels that matched, referencing * the channels passed in tue scan offload request */ struct iwm_scan_offload_profile_match { uint8_t bssid[IEEE80211_ADDR_LEN]; uint16_t reserved; uint8_t channel; uint8_t energy; uint8_t matching_feature; uint8_t matching_channels[IWM_SCAN_OFFLOAD_MATCHING_CHANNELS_LEN]; } __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_1 */ /** * struct iwm_scan_offload_profiles_query - match results query response * @matched_profiles: bitmap of matched profiles, referencing the * matches passed in the scan offload request * @last_scan_age: age of the last offloaded scan * @n_scans_done: number of offloaded scans done * @gp2_d0u: GP2 when D0U occurred * @gp2_invoked: GP2 when scan offload was invoked * @resume_while_scanning: not used * @self_recovery: obsolete * @reserved: reserved * @matches: array of match information, one for each match */ struct iwm_scan_offload_profiles_query { uint32_t matched_profiles; uint32_t last_scan_age; uint32_t n_scans_done; uint32_t gp2_d0u; uint32_t gp2_invoked; uint8_t resume_while_scanning; uint8_t self_recovery; uint16_t reserved; struct iwm_scan_offload_profile_match matches[IWM_SCAN_MAX_PROFILES]; } __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */ /** * struct iwm_umac_scan_iter_complete_notif - notifies end of scanning iteration * @uid: scan id, &enum iwm_umac_scan_uid_offsets * @scanned_channels: number of channels scanned and number of valid elements in * results array * @status: one of SCAN_COMP_STATUS_* * @bt_status: BT on/off status * @last_channel: last channel that was scanned * @tsf_low: TSF timer (lower half) in usecs * @tsf_high: TSF timer (higher half) in usecs * @results: array of scan results, only "scanned_channels" of them are valid */ struct iwm_umac_scan_iter_complete_notif { uint32_t uid; uint8_t scanned_channels; uint8_t status; uint8_t bt_status; uint8_t last_channel; uint32_t tsf_low; uint32_t tsf_high; struct iwm_scan_results_notif results[]; } __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_1 */ /* Please keep this enum *SORTED* by hex value. * Needed for binary search, otherwise a warning will be triggered. */ enum iwm_scan_subcmd_ids { IWM_GSCAN_START_CMD = 0x0, IWM_GSCAN_STOP_CMD = 0x1, IWM_GSCAN_SET_HOTLIST_CMD = 0x2, IWM_GSCAN_RESET_HOTLIST_CMD = 0x3, IWM_GSCAN_SET_SIGNIFICANT_CHANGE_CMD = 0x4, IWM_GSCAN_RESET_SIGNIFICANT_CHANGE_CMD = 0x5, IWM_GSCAN_SIGNIFICANT_CHANGE_EVENT = 0xFD, IWM_GSCAN_HOTLIST_CHANGE_EVENT = 0xFE, IWM_GSCAN_RESULTS_AVAILABLE_EVENT = 0xFF, }; /* STA API */ /** * enum iwm_sta_flags - flags for the ADD_STA host command * @IWM_STA_FLG_REDUCED_TX_PWR_CTRL: * @IWM_STA_FLG_REDUCED_TX_PWR_DATA: * @IWM_STA_FLG_DISABLE_TX: set if TX should be disabled * @IWM_STA_FLG_PS: set if STA is in Power Save * @IWM_STA_FLG_INVALID: set if STA is invalid * @IWM_STA_FLG_DLP_EN: Direct Link Protocol is enabled * @IWM_STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs * @IWM_STA_FLG_DRAIN_FLOW: drain flow * @IWM_STA_FLG_PAN: STA is for PAN interface * @IWM_STA_FLG_CLASS_AUTH: * @IWM_STA_FLG_CLASS_ASSOC: * @IWM_STA_FLG_CLASS_MIMO_PROT: * @IWM_STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU * @IWM_STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation * @IWM_STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is * initialised by driver and can be updated by fw upon reception of * action frames that can change the channel width. When cleared the fw * will send all the frames in 20MHz even when FAT channel is requested. * @IWM_STA_FLG_MIMO_EN_MSK: support for MIMO. This flag is initialised by the * driver and can be updated by fw upon reception of action frames. * @IWM_STA_FLG_MFP_EN: Management Frame Protection */ enum iwm_sta_flags { IWM_STA_FLG_REDUCED_TX_PWR_CTRL = (1 << 3), IWM_STA_FLG_REDUCED_TX_PWR_DATA = (1 << 6), IWM_STA_FLG_DISABLE_TX = (1 << 4), IWM_STA_FLG_PS = (1 << 8), IWM_STA_FLG_DRAIN_FLOW = (1 << 12), IWM_STA_FLG_PAN = (1 << 13), IWM_STA_FLG_CLASS_AUTH = (1 << 14), IWM_STA_FLG_CLASS_ASSOC = (1 << 15), IWM_STA_FLG_RTS_MIMO_PROT = (1 << 17), IWM_STA_FLG_MAX_AGG_SIZE_SHIFT = 19, IWM_STA_FLG_MAX_AGG_SIZE_8K = (0 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT), IWM_STA_FLG_MAX_AGG_SIZE_16K = (1 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT), IWM_STA_FLG_MAX_AGG_SIZE_32K = (2 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT), IWM_STA_FLG_MAX_AGG_SIZE_64K = (3 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT), IWM_STA_FLG_MAX_AGG_SIZE_128K = (4 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT), IWM_STA_FLG_MAX_AGG_SIZE_256K = (5 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT), IWM_STA_FLG_MAX_AGG_SIZE_512K = (6 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT), IWM_STA_FLG_MAX_AGG_SIZE_1024K = (7 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT), IWM_STA_FLG_MAX_AGG_SIZE_MSK = (7 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT), IWM_STA_FLG_AGG_MPDU_DENS_SHIFT = 23, IWM_STA_FLG_AGG_MPDU_DENS_2US = (4 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT), IWM_STA_FLG_AGG_MPDU_DENS_4US = (5 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT), IWM_STA_FLG_AGG_MPDU_DENS_8US = (6 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT), IWM_STA_FLG_AGG_MPDU_DENS_16US = (7 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT), IWM_STA_FLG_AGG_MPDU_DENS_MSK = (7 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT), IWM_STA_FLG_FAT_EN_20MHZ = (0 << 26), IWM_STA_FLG_FAT_EN_40MHZ = (1 << 26), IWM_STA_FLG_FAT_EN_80MHZ = (2 << 26), IWM_STA_FLG_FAT_EN_160MHZ = (3 << 26), IWM_STA_FLG_FAT_EN_MSK = (3 << 26), IWM_STA_FLG_MIMO_EN_SISO = (0 << 28), IWM_STA_FLG_MIMO_EN_MIMO2 = (1 << 28), IWM_STA_FLG_MIMO_EN_MIMO3 = (2 << 28), IWM_STA_FLG_MIMO_EN_MSK = (3 << 28), }; /** * enum iwm_sta_key_flag - key flags for the ADD_STA host command * @IWM_STA_KEY_FLG_NO_ENC: no encryption * @IWM_STA_KEY_FLG_WEP: WEP encryption algorithm * @IWM_STA_KEY_FLG_CCM: CCMP encryption algorithm * @IWM_STA_KEY_FLG_TKIP: TKIP encryption algorithm * @IWM_STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support) * @IWM_STA_KEY_FLG_CMAC: CMAC encryption algorithm * @IWM_STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm * @IWM_STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value * @IWM_STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from * station info array (1 - n 1X mode) * @IWM_STA_KEY_FLG_KEYID_MSK: the index of the key * @IWM_STA_KEY_NOT_VALID: key is invalid * @IWM_STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key * @IWM_STA_KEY_MULTICAST: set for multical key * @IWM_STA_KEY_MFP: key is used for Management Frame Protection */ enum iwm_sta_key_flag { IWM_STA_KEY_FLG_NO_ENC = (0 << 0), IWM_STA_KEY_FLG_WEP = (1 << 0), IWM_STA_KEY_FLG_CCM = (2 << 0), IWM_STA_KEY_FLG_TKIP = (3 << 0), IWM_STA_KEY_FLG_EXT = (4 << 0), IWM_STA_KEY_FLG_CMAC = (6 << 0), IWM_STA_KEY_FLG_ENC_UNKNOWN = (7 << 0), IWM_STA_KEY_FLG_EN_MSK = (7 << 0), IWM_STA_KEY_FLG_WEP_KEY_MAP = (1 << 3), IWM_STA_KEY_FLG_KEYID_POS = 8, IWM_STA_KEY_FLG_KEYID_MSK = (3 << IWM_STA_KEY_FLG_KEYID_POS), IWM_STA_KEY_NOT_VALID = (1 << 11), IWM_STA_KEY_FLG_WEP_13BYTES = (1 << 12), IWM_STA_KEY_MULTICAST = (1 << 14), IWM_STA_KEY_MFP = (1 << 15), }; /** * enum iwm_sta_modify_flag - indicate to the fw what flag are being changed * @IWM_STA_MODIFY_QUEUE_REMOVAL: this command removes a queue * @IWM_STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx * @IWM_STA_MODIFY_TX_RATE: unused * @IWM_STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid * @IWM_STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid * @IWM_STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count * @IWM_STA_MODIFY_PROT_TH: * @IWM_STA_MODIFY_QUEUES: modify the queues used by this station */ enum iwm_sta_modify_flag { IWM_STA_MODIFY_QUEUE_REMOVAL = (1 << 0), IWM_STA_MODIFY_TID_DISABLE_TX = (1 << 1), IWM_STA_MODIFY_TX_RATE = (1 << 2), IWM_STA_MODIFY_ADD_BA_TID = (1 << 3), IWM_STA_MODIFY_REMOVE_BA_TID = (1 << 4), IWM_STA_MODIFY_SLEEPING_STA_TX_COUNT = (1 << 5), IWM_STA_MODIFY_PROT_TH = (1 << 6), IWM_STA_MODIFY_QUEUES = (1 << 7), }; #define IWM_STA_MODE_MODIFY 1 /** * enum iwm_sta_sleep_flag - type of sleep of the station * @IWM_STA_SLEEP_STATE_AWAKE: * @IWM_STA_SLEEP_STATE_PS_POLL: * @IWM_STA_SLEEP_STATE_UAPSD: * @IWM_STA_SLEEP_STATE_MOREDATA: set more-data bit on * (last) released frame */ enum iwm_sta_sleep_flag { IWM_STA_SLEEP_STATE_AWAKE = 0, IWM_STA_SLEEP_STATE_PS_POLL = (1 << 0), IWM_STA_SLEEP_STATE_UAPSD = (1 << 1), IWM_STA_SLEEP_STATE_MOREDATA = (1 << 2), }; /* STA ID and color bits definitions */ #define IWM_STA_ID_SEED (0x0f) #define IWM_STA_ID_POS (0) #define IWM_STA_ID_MSK (IWM_STA_ID_SEED << IWM_STA_ID_POS) #define IWM_STA_COLOR_SEED (0x7) #define IWM_STA_COLOR_POS (4) #define IWM_STA_COLOR_MSK (IWM_STA_COLOR_SEED << IWM_STA_COLOR_POS) #define IWM_STA_ID_N_COLOR_GET_COLOR(id_n_color) \ (((id_n_color) & IWM_STA_COLOR_MSK) >> IWM_STA_COLOR_POS) #define IWM_STA_ID_N_COLOR_GET_ID(id_n_color) \ (((id_n_color) & IWM_STA_ID_MSK) >> IWM_STA_ID_POS) #define IWM_STA_KEY_MAX_NUM (16) #define IWM_STA_KEY_IDX_INVALID (0xff) #define IWM_STA_KEY_MAX_DATA_KEY_NUM (4) #define IWM_MAX_GLOBAL_KEYS (4) #define IWM_STA_KEY_LEN_WEP40 (5) #define IWM_STA_KEY_LEN_WEP104 (13) /** * struct iwm_mvm_keyinfo - key information * @key_flags: type %iwm_sta_key_flag * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx * @key_offset: key offset in the fw's key table * @key: 16-byte unicast decryption key * @tx_secur_seq_cnt: initial RSC / PN needed for replay check * @hw_tkip_mic_rx_key: byte: MIC Rx Key - used for TKIP only * @hw_tkip_mic_tx_key: byte: MIC Tx Key - used for TKIP only */ struct iwm_mvm_keyinfo { uint16_t key_flags; uint8_t tkip_rx_tsc_byte2; uint8_t reserved1; uint16_t tkip_rx_ttak[5]; uint8_t key_offset; uint8_t reserved2; uint8_t key[16]; uint64_t tx_secur_seq_cnt; uint64_t hw_tkip_mic_rx_key; uint64_t hw_tkip_mic_tx_key; } __packed; #define IWM_ADD_STA_STATUS_MASK 0xFF #define IWM_ADD_STA_BAID_VALID_MASK 0x8000 #define IWM_ADD_STA_BAID_MASK 0x7F00 #define IWM_ADD_STA_BAID_SHIFT 8 /** * struct iwm_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) * @add_modify: 1: modify existing, 0: add new station * @awake_acs: * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %IWM_STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to * @addr[IEEE80211_ADDR_LEN]: station's MAC address * @sta_id: index of station in uCode's station table * @modify_mask: IWM_STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. * @station_flags: look at %iwm_sta_flags * @station_flags_msk: what of %station_flags have changed * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) * Set %IWM_STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx) * Set %IWM_STA_MODIFY_REMOVE_BA_TID to use this field * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with * add_immediate_ba_tid. * @sleep_tx_count: number of packets to transmit to station even though it is * asleep. Used to synchronise PS-poll and u-APSD responses while ucode * keeps track of STA sleep state. * @sleep_state_flags: Look at %iwm_sta_sleep_flag. * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP * mac-addr. * @beamform_flags: beam forming controls * @tfd_queue_msk: tfd queues used by this station * * The device contains an internal table of per-station information, with info * on security keys, aggregation parameters, and Tx rates for initial Tx * attempt and any retries (set by IWM_REPLY_TX_LINK_QUALITY_CMD). * * ADD_STA sets up the table entry for one station, either creating a new * entry, or modifying a pre-existing one. */ struct iwm_mvm_add_sta_cmd_v7 { uint8_t add_modify; uint8_t awake_acs; uint16_t tid_disable_tx; uint32_t mac_id_n_color; uint8_t addr[IEEE80211_ADDR_LEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ uint16_t reserved2; uint8_t sta_id; uint8_t modify_mask; uint16_t reserved3; uint32_t station_flags; uint32_t station_flags_msk; uint8_t add_immediate_ba_tid; uint8_t remove_immediate_ba_tid; uint16_t add_immediate_ba_ssn; uint16_t sleep_tx_count; uint16_t sleep_state_flags; uint16_t assoc_id; uint16_t beamform_flags; uint32_t tfd_queue_msk; } __packed; /* ADD_STA_CMD_API_S_VER_7 */ /** * struct iwm_mvm_add_sta_key_cmd - add/modify sta key * ( IWM_REPLY_ADD_STA_KEY = 0x17 ) * @sta_id: index of station in uCode's station table * @key_offset: key offset in key storage * @key_flags: type %iwm_sta_key_flag * @key: key material data * @key2: key material data * @rx_secur_seq_cnt: RX security sequence counter for the key * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx */ struct iwm_mvm_add_sta_key_cmd { uint8_t sta_id; uint8_t key_offset; uint16_t key_flags; uint8_t key[16]; uint8_t key2[16]; uint8_t rx_secur_seq_cnt[16]; uint8_t tkip_rx_tsc_byte2; uint8_t reserved; uint16_t tkip_rx_ttak[5]; } __packed; /* IWM_ADD_MODIFY_STA_KEY_API_S_VER_1 */ /** * enum iwm_mvm_add_sta_rsp_status - status in the response to ADD_STA command * @IWM_ADD_STA_SUCCESS: operation was executed successfully * @IWM_ADD_STA_STATIONS_OVERLOAD: no room left in the fw's station table * @IWM_ADD_STA_IMMEDIATE_BA_FAILURE: can't add Rx block ack session * @IWM_ADD_STA_MODIFY_NON_EXISTING_STA: driver requested to modify a station * that doesn't exist. */ enum iwm_mvm_add_sta_rsp_status { IWM_ADD_STA_SUCCESS = 0x1, IWM_ADD_STA_STATIONS_OVERLOAD = 0x2, IWM_ADD_STA_IMMEDIATE_BA_FAILURE = 0x4, IWM_ADD_STA_MODIFY_NON_EXISTING_STA = 0x8, }; /** * struct iwm_mvm_rm_sta_cmd - Add / modify a station in the fw's station table * ( IWM_REMOVE_STA = 0x19 ) * @sta_id: the station id of the station to be removed */ struct iwm_mvm_rm_sta_cmd { uint8_t sta_id; uint8_t reserved[3]; } __packed; /* IWM_REMOVE_STA_CMD_API_S_VER_2 */ /** * struct iwm_mvm_mgmt_mcast_key_cmd * ( IWM_MGMT_MCAST_KEY = 0x1f ) * @ctrl_flags: %iwm_sta_key_flag * @IGTK: * @K1: IGTK master key * @K2: IGTK sub key * @sta_id: station ID that support IGTK * @key_id: * @receive_seq_cnt: initial RSC/PN needed for replay check */ struct iwm_mvm_mgmt_mcast_key_cmd { uint32_t ctrl_flags; uint8_t IGTK[16]; uint8_t K1[16]; uint8_t K2[16]; uint32_t key_id; uint32_t sta_id; uint64_t receive_seq_cnt; } __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */ struct iwm_mvm_wep_key { uint8_t key_index; uint8_t key_offset; uint16_t reserved1; uint8_t key_size; uint8_t reserved2[3]; uint8_t key[16]; } __packed; struct iwm_mvm_wep_key_cmd { uint32_t mac_id_n_color; uint8_t num_keys; uint8_t decryption_type; uint8_t flags; uint8_t reserved; struct iwm_mvm_wep_key wep_key[0]; } __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */ /* * END mvm/fw-api-sta.h */ /* * BT coex */ enum iwm_bt_coex_mode { IWM_BT_COEX_DISABLE = 0x0, IWM_BT_COEX_NW = 0x1, IWM_BT_COEX_BT = 0x2, IWM_BT_COEX_WIFI = 0x3, }; /* BT_COEX_MODES_E */ enum iwm_bt_coex_enabled_modules { IWM_BT_COEX_MPLUT_ENABLED = (1 << 0), IWM_BT_COEX_MPLUT_BOOST_ENABLED = (1 << 1), IWM_BT_COEX_SYNC2SCO_ENABLED = (1 << 2), IWM_BT_COEX_CORUN_ENABLED = (1 << 3), IWM_BT_COEX_HIGH_BAND_RET = (1 << 4), }; /* BT_COEX_MODULES_ENABLE_E_VER_1 */ /** * struct iwm_bt_coex_cmd - bt coex configuration command * @mode: enum %iwm_bt_coex_mode * @enabled_modules: enum %iwm_bt_coex_enabled_modules * * The structure is used for the BT_COEX command. */ struct iwm_bt_coex_cmd { uint32_t mode; uint32_t enabled_modules; } __packed; /* BT_COEX_CMD_API_S_VER_6 */ /* * Location Aware Regulatory (LAR) API - MCC updates */ /** * struct iwm_mcc_update_cmd_v1 - Request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the * MCC in the cmd response will be the relevant MCC in the NVM. * @mcc: given mobile country code * @source_id: the source from where we got the MCC, see iwm_mcc_source * @reserved: reserved for alignment */ struct iwm_mcc_update_cmd_v1 { uint16_t mcc; uint8_t source_id; uint8_t reserved; } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */ /** * struct iwm_mcc_update_cmd - Request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the * MCC in the cmd response will be the relevant MCC in the NVM. * @mcc: given mobile country code * @source_id: the source from where we got the MCC, see iwm_mcc_source * @reserved: reserved for alignment * @key: integrity key for MCC API OEM testing * @reserved2: reserved */ struct iwm_mcc_update_cmd { uint16_t mcc; uint8_t source_id; uint8_t reserved; uint32_t key; uint32_t reserved2[5]; } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */ /** * iwm_mcc_update_resp_v1 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. * @status: see &enum iwm_mcc_update_status * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC * @source_id: the MCC source, see iwm_mcc_source * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 * channels, depending on platform) * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ struct iwm_mcc_update_resp_v1 { uint32_t status; uint16_t mcc; uint8_t cap; uint8_t source_id; uint32_t n_channels; uint32_t channels[0]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */ /** * iwm_mcc_update_resp - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. * @status: see &enum iwm_mcc_update_status * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC * @source_id: the MCC source, see iwm_mcc_source * @time: time elapsed from the MCC test start (in 30 seconds TU) * @reserved: reserved. * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 * channels, depending on platform) * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ struct iwm_mcc_update_resp { uint32_t status; uint16_t mcc; uint8_t cap; uint8_t source_id; uint16_t time; uint16_t reserved; uint32_t n_channels; uint32_t channels[0]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */ /** * struct iwm_mcc_chub_notif - chub notifies of mcc change * (MCC_CHUB_UPDATE_CMD = 0xc9) * The Chub (Communication Hub, CommsHUB) is a HW component that connects to * the cellular and connectivity cores that gets updates of the mcc, and * notifies the ucode directly of any mcc change. * The ucode requests the driver to request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the * MCC in the cmd response will be the relevant MCC in the NVM. * @mcc: given mobile country code * @source_id: identity of the change originator, see iwm_mcc_source * @reserved1: reserved for alignment */ struct iwm_mcc_chub_notif { uint16_t mcc; uint8_t source_id; uint8_t reserved1; } __packed; /* LAR_MCC_NOTIFY_S */ enum iwm_mcc_update_status { IWM_MCC_RESP_NEW_CHAN_PROFILE, IWM_MCC_RESP_SAME_CHAN_PROFILE, IWM_MCC_RESP_INVALID, IWM_MCC_RESP_NVM_DISABLED, IWM_MCC_RESP_ILLEGAL, IWM_MCC_RESP_LOW_PRIORITY, IWM_MCC_RESP_TEST_MODE_ACTIVE, IWM_MCC_RESP_TEST_MODE_NOT_ACTIVE, IWM_MCC_RESP_TEST_MODE_DENIAL_OF_SERVICE, }; enum iwm_mcc_source { IWM_MCC_SOURCE_OLD_FW = 0, IWM_MCC_SOURCE_ME = 1, IWM_MCC_SOURCE_BIOS = 2, IWM_MCC_SOURCE_3G_LTE_HOST = 3, IWM_MCC_SOURCE_3G_LTE_DEVICE = 4, IWM_MCC_SOURCE_WIFI = 5, IWM_MCC_SOURCE_RESERVED = 6, IWM_MCC_SOURCE_DEFAULT = 7, IWM_MCC_SOURCE_UNINITIALIZED = 8, IWM_MCC_SOURCE_MCC_API = 9, IWM_MCC_SOURCE_GET_CURRENT = 0x10, IWM_MCC_SOURCE_GETTING_MCC_TEST_MODE = 0x11, }; /* * Some cherry-picked definitions */ #define IWM_FRAME_LIMIT 64 /* * From Linux commit ab02165ccec4c78162501acedeef1a768acdb811: * As the firmware is slowly running out of command IDs and grouping of * commands is desirable anyway, the firmware is extending the command * header from 4 bytes to 8 bytes to introduce a group (in place of the * former flags field, since that's always 0 on commands and thus can * be easily used to distinguish between the two). * * These functions retrieve specific information from the id field in * the iwm_host_cmd struct which contains the command id, the group id, * and the version of the command. */ static inline uint8_t iwm_cmd_opcode(uint32_t cmdid) { return cmdid & 0xff; } static inline uint8_t iwm_cmd_groupid(uint32_t cmdid) { return ((cmdid & 0Xff00) >> 8); } static inline uint8_t iwm_cmd_version(uint32_t cmdid) { return ((cmdid & 0xff0000) >> 16); } static inline uint32_t iwm_cmd_id(uint8_t opcode, uint8_t groupid, uint8_t version) { return opcode + (groupid << 8) + (version << 16); } /* make uint16_t wide id out of uint8_t group and opcode */ #define IWM_WIDE_ID(grp, opcode) ((grp << 8) | opcode) /* due to the conversion, this group is special */ #define IWM_ALWAYS_LONG_GROUP 1 struct iwm_cmd_header { uint8_t code; uint8_t flags; uint8_t idx; uint8_t qid; } __packed; struct iwm_cmd_header_wide { uint8_t opcode; uint8_t group_id; uint8_t idx; uint8_t qid; uint16_t length; uint8_t reserved; uint8_t version; } __packed; enum iwm_power_scheme { IWM_POWER_SCHEME_CAM = 1, IWM_POWER_SCHEME_BPS, IWM_POWER_SCHEME_LP }; #define IWM_DEF_CMD_PAYLOAD_SIZE 320 #define IWM_MAX_CMD_PAYLOAD_SIZE ((4096 - 4) - sizeof(struct iwm_cmd_header)) #define IWM_CMD_FAILED_MSK 0x40 /** * struct iwm_device_cmd * * For allocation of the command and tx queues, this establishes the overall * size of the largest command we send to uCode, except for commands that * aren't fully copied and use other TFD space. */ struct iwm_device_cmd { union { struct { struct iwm_cmd_header hdr; uint8_t data[IWM_DEF_CMD_PAYLOAD_SIZE]; }; struct { struct iwm_cmd_header_wide hdr_wide; uint8_t data_wide[IWM_DEF_CMD_PAYLOAD_SIZE - sizeof(struct iwm_cmd_header_wide) + sizeof(struct iwm_cmd_header)]; }; }; } __packed; struct iwm_rx_packet { /* * The first 4 bytes of the RX frame header contain both the RX frame * size and some flags. * Bit fields: * 31: flag flush RB request * 30: flag ignore TC (terminal counter) request * 29: flag fast IRQ request * 28-14: Reserved * 13-00: RX frame size */ uint32_t len_n_flags; struct iwm_cmd_header hdr; uint8_t data[]; } __packed; #define IWM_FH_RSCSR_FRAME_SIZE_MSK 0x00003fff static inline uint32_t iwm_rx_packet_len(const struct iwm_rx_packet *pkt) { return le32toh(pkt->len_n_flags) & IWM_FH_RSCSR_FRAME_SIZE_MSK; } static inline uint32_t iwm_rx_packet_payload_len(const struct iwm_rx_packet *pkt) { return iwm_rx_packet_len(pkt) - sizeof(pkt->hdr); } #define IWM_MIN_DBM -100 #define IWM_MAX_DBM -33 /* realistic guess */ #define IWM_READ(sc, reg) \ bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg)) #define IWM_WRITE(sc, reg, val) \ bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val)) #define IWM_WRITE_1(sc, reg, val) \ bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val)) #define IWM_SETBITS(sc, reg, mask) \ IWM_WRITE(sc, reg, IWM_READ(sc, reg) | (mask)) #define IWM_CLRBITS(sc, reg, mask) \ IWM_WRITE(sc, reg, IWM_READ(sc, reg) & ~(mask)) #define IWM_BARRIER_WRITE(sc) \ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ BUS_SPACE_BARRIER_WRITE) #define IWM_BARRIER_READ_WRITE(sc) \ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) #endif /* __IF_IWM_REG_H__ */ Index: projects/ipsec/sys/dev/iwm/if_iwmvar.h =================================================================== --- projects/ipsec/sys/dev/iwm/if_iwmvar.h (revision 313312) +++ projects/ipsec/sys/dev/iwm/if_iwmvar.h (revision 313313) @@ -1,525 +1,515 @@ /* $OpenBSD: if_iwmvar.h,v 1.7 2015/03/02 13:51:10 jsg Exp $ */ /* $FreeBSD$ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * * Driver version we are currently based off of is * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT * OWNER 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. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct iwm_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; uint64_t wr_tsft; uint8_t wr_flags; uint8_t wr_rate; uint16_t wr_chan_freq; uint16_t wr_chan_flags; int8_t wr_dbm_antsignal; int8_t wr_dbm_antnoise; } __packed; #define IWM_RX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_TSFT) | \ (1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL) | \ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)) struct iwm_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; uint8_t wt_flags; uint8_t wt_rate; uint16_t wt_chan_freq; uint16_t wt_chan_flags; } __packed; #define IWM_TX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL)) #define IWM_UCODE_SECT_MAX 16 #define IWM_FWDMASEGSZ (192*1024) #define IWM_FWDMASEGSZ_8000 (320*1024) /* sanity check value */ #define IWM_FWMAXSIZE (2*1024*1024) /* * fw_status is used to determine if we've already parsed the firmware file * * In addition to the following, status < 0 ==> -error */ #define IWM_FW_STATUS_NONE 0 #define IWM_FW_STATUS_INPROGRESS 1 #define IWM_FW_STATUS_DONE 2 enum iwm_ucode_type { IWM_UCODE_TYPE_REGULAR, IWM_UCODE_TYPE_INIT, IWM_UCODE_TYPE_WOW, IWM_UCODE_TYPE_REGULAR_USNIFFER, IWM_UCODE_TYPE_MAX }; struct iwm_fw_info { const struct firmware *fw_fp; int fw_status; struct iwm_fw_sects { struct iwm_fw_onesect { const void *fws_data; uint32_t fws_len; uint32_t fws_devoff; } fw_sect[IWM_UCODE_SECT_MAX]; int fw_count; } fw_sects[IWM_UCODE_TYPE_MAX]; }; struct iwm_nvm_data { int n_hw_addrs; uint8_t hw_addr[IEEE80211_ADDR_LEN]; int sku_cap_band_24GHz_enable; int sku_cap_band_52GHz_enable; int sku_cap_11n_enable; int sku_cap_amt_enable; int sku_cap_ipan_enable; uint8_t radio_cfg_type; uint8_t radio_cfg_step; uint8_t radio_cfg_dash; uint8_t radio_cfg_pnum; uint8_t valid_tx_ant, valid_rx_ant; #define IWM_NUM_CHANNELS 39 #define IWM_NUM_CHANNELS_8000 51 - uint16_t nvm_ch_flags[IWM_NUM_CHANNELS_8000]; - uint16_t nvm_version; uint8_t max_tx_pwr_half_dbm; + + uint16_t nvm_ch_flags[]; }; /* max bufs per tfd the driver will use */ #define IWM_MAX_CMD_TBS_PER_TFD 2 struct iwm_rx_packet; struct iwm_host_cmd { const void *data[IWM_MAX_CMD_TBS_PER_TFD]; struct iwm_rx_packet *resp_pkt; unsigned long _rx_page_addr; uint32_t _rx_page_order; int handler_status; uint32_t flags; uint32_t id; uint16_t len[IWM_MAX_CMD_TBS_PER_TFD]; uint8_t dataflags[IWM_MAX_CMD_TBS_PER_TFD]; }; /* * DMA glue is from iwn */ typedef caddr_t iwm_caddr_t; typedef void *iwm_hookarg_t; struct iwm_dma_info { bus_dma_tag_t tag; bus_dmamap_t map; bus_dma_segment_t seg; bus_addr_t paddr; void *vaddr; bus_size_t size; }; #define IWM_TX_RING_COUNT 256 #define IWM_TX_RING_LOMARK 192 #define IWM_TX_RING_HIMARK 224 struct iwm_tx_data { bus_dmamap_t map; bus_addr_t cmd_paddr; bus_addr_t scratch_paddr; struct mbuf *m; struct iwm_node *in; int done; }; struct iwm_tx_ring { struct iwm_dma_info desc_dma; struct iwm_dma_info cmd_dma; struct iwm_tfd *desc; struct iwm_device_cmd *cmd; bus_dma_tag_t data_dmat; struct iwm_tx_data data[IWM_TX_RING_COUNT]; int qid; int queued; int cur; }; #define IWM_RX_RING_COUNT 256 #define IWM_RBUF_COUNT (IWM_RX_RING_COUNT + 32) /* Linux driver optionally uses 8k buffer */ #define IWM_RBUF_SIZE 4096 #define IWM_MAX_SCATTER 20 struct iwm_rx_data { struct mbuf *m; bus_dmamap_t map; }; struct iwm_rx_ring { struct iwm_dma_info desc_dma; struct iwm_dma_info stat_dma; struct iwm_dma_info buf_dma; uint32_t *desc; struct iwm_rb_status *stat; struct iwm_rx_data data[IWM_RX_RING_COUNT]; bus_dmamap_t spare_map; /* for iwm_rx_addbuf() */ bus_dma_tag_t data_dmat; int cur; }; struct iwm_ucode_status { uint32_t uc_error_event_table; uint32_t uc_umac_error_event_table; uint32_t uc_log_event_table; int uc_ok; int uc_intr; }; #define IWM_CMD_RESP_MAX PAGE_SIZE -/* lower blocks contain EEPROM image and calibration data */ -#define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_7000 16384 -#define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_8000 32768 - #define IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 500 #define IWM_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400 /* * Command headers are in iwl-trans.h, which is full of all * kinds of other junk, so we just replicate the structures here. * First the software bits: */ enum IWM_CMD_MODE { IWM_CMD_SYNC = 0, IWM_CMD_ASYNC = (1 << 0), IWM_CMD_WANT_SKB = (1 << 1), IWM_CMD_SEND_IN_RFKILL = (1 << 2), }; enum iwm_hcmd_dataflag { IWM_HCMD_DFL_NOCOPY = (1 << 0), IWM_HCMD_DFL_DUP = (1 << 1), }; -/* - * iwlwifi/iwl-phy-db - */ - -#define IWM_NUM_PAPD_CH_GROUPS 9 -#define IWM_NUM_TXP_CH_GROUPS 9 - -struct iwm_phy_db_entry { - uint16_t size; - uint8_t *data; -}; - -struct iwm_phy_db { - struct iwm_phy_db_entry cfg; - struct iwm_phy_db_entry calib_nch; - struct iwm_phy_db_entry calib_ch_group_papd[IWM_NUM_PAPD_CH_GROUPS]; - struct iwm_phy_db_entry calib_ch_group_txp[IWM_NUM_TXP_CH_GROUPS]; -}; - struct iwm_int_sta { uint32_t sta_id; uint32_t tfd_queue_msk; }; struct iwm_mvm_phy_ctxt { uint16_t id; uint16_t color; uint32_t ref; struct ieee80211_channel *channel; }; struct iwm_bf_data { int bf_enabled; /* filtering */ int ba_enabled; /* abort */ int ave_beacon_signal; int last_cqm_event; }; struct iwm_vap { struct ieee80211vap iv_vap; int is_uploaded; int (*iv_newstate)(struct ieee80211vap *, enum ieee80211_state, int); }; #define IWM_VAP(_vap) ((struct iwm_vap *)(_vap)) struct iwm_node { struct ieee80211_node in_ni; struct iwm_mvm_phy_ctxt *in_phyctxt; /* status "bits" */ int in_assoc; struct iwm_lq_cmd in_lq; uint8_t in_ridx[IEEE80211_RATE_MAXSIZE]; }; #define IWM_NODE(_ni) ((struct iwm_node *)(_ni)) #define IWM_STATION_ID 0 #define IWM_AUX_STA_ID 1 #define IWM_DEFAULT_MACID 0 #define IWM_DEFAULT_COLOR 0 #define IWM_DEFAULT_TSFID 0 #define IWM_ICT_SIZE 4096 #define IWM_ICT_COUNT (IWM_ICT_SIZE / sizeof (uint32_t)) #define IWM_ICT_PADDR_SHIFT 12 +enum iwm_device_family { + IWM_DEVICE_FAMILY_UNDEFINED, + IWM_DEVICE_FAMILY_7000, + IWM_DEVICE_FAMILY_8000, +}; + +/** + * struct iwm_cfg + * @fw_name: Firmware filename. + * @host_interrupt_operation_mode: device needs host interrupt operation + * mode set + * @nvm_hw_section_num: the ID of the HW NVM section + */ +struct iwm_cfg { + const char *fw_name; + uint16_t eeprom_size; + enum iwm_device_family device_family; + int host_interrupt_operation_mode; + uint8_t nvm_hw_section_num; +}; + struct iwm_softc { device_t sc_dev; uint32_t sc_debug; + int sc_attached; struct mtx sc_mtx; struct mbufq sc_snd; struct ieee80211com sc_ic; struct ieee80211_ratectl_tx_status sc_txs; int sc_flags; #define IWM_FLAG_USE_ICT (1 << 0) #define IWM_FLAG_HW_INITED (1 << 1) #define IWM_FLAG_STOPPED (1 << 2) #define IWM_FLAG_RFKILL (1 << 3) #define IWM_FLAG_BUSY (1 << 4) #define IWM_FLAG_SCANNING (1 << 5) struct intr_config_hook sc_preinit_hook; struct callout sc_watchdog_to; struct callout sc_led_blink_to; struct task init_task; struct resource *sc_irq; struct resource *sc_mem; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; bus_size_t sc_sz; bus_dma_tag_t sc_dmat; void *sc_ih; /* TX scheduler rings. */ struct iwm_dma_info sched_dma; uint32_t sched_base; /* TX/RX rings. */ struct iwm_tx_ring txq[IWM_MVM_MAX_QUEUES]; struct iwm_rx_ring rxq; int qfullmsk; int sc_sf_state; /* ICT table. */ struct iwm_dma_info ict_dma; int ict_cur; int sc_hw_rev; -#define IWM_SILICON_A_STEP 0 -#define IWM_SILICON_B_STEP 1 -#define IWM_SILICON_C_STEP 2 -#define IWM_SILICON_D_STEP 3 int sc_hw_id; - int sc_device_family; -#define IWM_DEVICE_FAMILY_7000 1 -#define IWM_DEVICE_FAMILY_8000 2 struct iwm_dma_info kw_dma; struct iwm_dma_info fw_dma; int sc_fw_chunk_done; int sc_init_complete; struct iwm_ucode_status sc_uc; enum iwm_ucode_type sc_uc_current; char sc_fwver[32]; int sc_capaflags; int sc_capa_max_probe_len; int sc_capa_n_scan_channels; uint32_t sc_ucode_api; uint8_t sc_enabled_capa[howmany(IWM_NUM_UCODE_TLV_CAPA, NBBY)]; char sc_fw_mcc[3]; int sc_intmask; /* * So why do we need a separate stopped flag and a generation? * the former protects the device from issuing commands when it's * stopped (duh). The latter protects against race from a very * fast stop/unstop cycle where threads waiting for responses do * not have a chance to run in between. Notably: we want to stop * the device from interrupt context when it craps out, so we * don't have the luxury of waiting for quiescense. */ int sc_generation; - const char *sc_fwname; bus_size_t sc_fwdmasegsz; struct iwm_fw_info sc_fw; int sc_fw_phy_config; struct iwm_tlv_calib_ctrl sc_default_calib[IWM_UCODE_TYPE_MAX]; - struct iwm_nvm_data sc_nvm; - struct iwm_phy_db sc_phy_db; + const struct iwm_cfg *cfg; + struct iwm_nvm_data *nvm_data; + struct iwm_phy_db *sc_phy_db; struct iwm_bf_data sc_bf; int sc_tx_timer; int sc_scan_last_antenna; int sc_fixed_ridx; int sc_staid; int sc_nodecolor; uint8_t sc_cmd_resp[IWM_CMD_RESP_MAX]; int sc_wantresp; struct task sc_es_task; struct iwm_rx_phy_info sc_last_phy_info; int sc_ampdu_ref; struct iwm_int_sta sc_aux_sta; /* phy contexts. we only use the first one */ struct iwm_mvm_phy_ctxt sc_phyctxt[IWM_NUM_PHY_CTX]; struct iwm_notif_statistics sc_stats; int sc_noise; - - int host_interrupt_operation_mode; caddr_t sc_drvbpf; struct iwm_rx_radiotap_header sc_rxtap; struct iwm_tx_radiotap_header sc_txtap; int sc_max_rssi; }; #define IWM_LOCK_INIT(_sc) \ mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ MTX_NETWORK_LOCK, MTX_DEF); #define IWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define IWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define IWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) Index: projects/ipsec/sys/dev/mmc/mmc.c =================================================================== --- projects/ipsec/sys/dev/mmc/mmc.c (revision 313312) +++ projects/ipsec/sys/dev/mmc/mmc.c (revision 313313) @@ -1,1829 +1,1829 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. * Copyright (c) 2006 M. Warner Losh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mmcbr_if.h" #include "mmcbus_if.h" struct mmc_softc { device_t dev; struct mtx sc_mtx; struct intr_config_hook config_intrhook; device_t owner; uint32_t last_rca; int squelched; /* suppress reporting of (expected) errors */ int log_count; struct timeval log_time; }; #define LOG_PPS 5 /* Log no more than 5 errors per second. */ /* * Per-card data */ struct mmc_ivars { uint32_t raw_cid[4]; /* Raw bits of the CID */ uint32_t raw_csd[4]; /* Raw bits of the CSD */ uint32_t raw_scr[2]; /* Raw bits of the SCR */ uint8_t raw_ext_csd[512]; /* Raw bits of the EXT_CSD */ uint32_t raw_sd_status[16]; /* Raw bits of the SD_STATUS */ uint16_t rca; enum mmc_card_mode mode; struct mmc_cid cid; /* cid decoded */ struct mmc_csd csd; /* csd decoded */ struct mmc_scr scr; /* scr decoded */ struct mmc_sd_status sd_status; /* SD_STATUS decoded */ u_char read_only; /* True when the device is read-only */ u_char bus_width; /* Bus width to use */ u_char timing; /* Bus timing support */ u_char high_cap; /* High Capacity card (block addressed) */ uint32_t sec_count; /* Card capacity in 512byte blocks */ uint32_t tran_speed; /* Max speed in normal mode */ uint32_t hs_tran_speed; /* Max speed in high speed mode */ uint32_t erase_sector; /* Card native erase sector size */ char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */ char card_sn_string[16];/* Formatted serial # for disk->d_ident */ }; -#define CMD_RETRIES 3 +#define CMD_RETRIES 3 #define CARD_ID_FREQUENCY 400000 /* Spec requires 400kHz max during ID phase. */ static SYSCTL_NODE(_hw, OID_AUTO, mmc, CTLFLAG_RD, NULL, "mmc driver"); static int mmc_debug; -SYSCTL_INT(_hw_mmc, OID_AUTO, debug, CTLFLAG_RWTUN, &mmc_debug, 0, "Debug level"); +SYSCTL_INT(_hw_mmc, OID_AUTO, debug, CTLFLAG_RWTUN, &mmc_debug, 0, + "Debug level"); /* bus entry points */ static int mmc_acquire_bus(device_t busdev, device_t dev); static int mmc_attach(device_t dev); static int mmc_child_location_str(device_t dev, device_t child, char *buf, size_t buflen); static int mmc_detach(device_t dev); static int mmc_probe(device_t dev); static int mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result); static int mmc_release_bus(device_t busdev, device_t dev); static int mmc_resume(device_t dev); static int mmc_suspend(device_t dev); static int mmc_wait_for_request(device_t brdev, device_t reqdev, struct mmc_request *req); static int mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value); -#define MMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define MMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define MMC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) -#define MMC_LOCK_INIT(_sc) \ - mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ +#define MMC_LOCK_INIT(_sc) \ + mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->dev), \ "mmc", MTX_DEF) -#define MMC_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); -#define MMC_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); -#define MMC_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); +#define MMC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx); +#define MMC_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED); +#define MMC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED); static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid); static void mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr); static void mmc_app_decode_sd_status(uint32_t *raw_sd_status, struct mmc_sd_status *sd_status); static int mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus); static int mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr); static int mmc_calculate_clock(struct mmc_softc *sc); static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid); static void mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid); static void mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd); static void mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd); static void mmc_delayed_attach(void *xsc); static int mmc_delete_cards(struct mmc_softc *sc); static void mmc_discover_cards(struct mmc_softc *sc); static void mmc_format_card_id_string(struct mmc_ivars *ivar); static void mmc_go_discovery(struct mmc_softc *sc); static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start, int size); static int mmc_highest_voltage(uint32_t ocr); static void mmc_idle_cards(struct mmc_softc *sc); static void mmc_ms_delay(int ms); static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard); static void mmc_power_down(struct mmc_softc *sc); static void mmc_power_up(struct mmc_softc *sc); static void mmc_rescan_cards(struct mmc_softc *sc); static void mmc_scan(struct mmc_softc *sc); static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value, uint8_t *res); static int mmc_select_card(struct mmc_softc *sc, uint16_t rca); static uint32_t mmc_select_vdd(struct mmc_softc *sc, uint32_t ocr); static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr); static int mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcsd); static int mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd); static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs); static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr); static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp); static int mmc_send_status(struct mmc_softc *sc, uint16_t rca, uint32_t *status); static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len); static int mmc_set_card_bus_width(struct mmc_softc *sc, uint16_t rca, int width); static int mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp); static int mmc_set_timing(struct mmc_softc *sc, int timing); static int mmc_switch(struct mmc_softc *sc, uint8_t set, uint8_t index, uint8_t value); static int mmc_test_bus_width(struct mmc_softc *sc); static int mmc_wait_for_app_cmd(struct mmc_softc *sc, uint32_t rca, struct mmc_command *cmd, int retries); static int mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd, int retries); static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, uint32_t arg, uint32_t flags, uint32_t *resp, int retries); static int mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req); static void mmc_wakeup(struct mmc_request *req); static void mmc_ms_delay(int ms) { DELAY(1000 * ms); /* XXX BAD */ } static int mmc_probe(device_t dev) { device_set_desc(dev, "MMC/SD bus"); return (0); } static int mmc_attach(device_t dev) { struct mmc_softc *sc; sc = device_get_softc(dev); sc->dev = dev; MMC_LOCK_INIT(sc); /* We'll probe and attach our children later, but before / mount */ sc->config_intrhook.ich_func = mmc_delayed_attach; sc->config_intrhook.ich_arg = sc; if (config_intrhook_establish(&sc->config_intrhook) != 0) device_printf(dev, "config_intrhook_establish failed\n"); return (0); } static int mmc_detach(device_t dev) { struct mmc_softc *sc = device_get_softc(dev); int err; if ((err = mmc_delete_cards(sc)) != 0) return (err); mmc_power_down(sc); MMC_LOCK_DESTROY(sc); return (0); } static int mmc_suspend(device_t dev) { struct mmc_softc *sc = device_get_softc(dev); int err; err = bus_generic_suspend(dev); if (err) return (err); mmc_power_down(sc); return (0); } static int mmc_resume(device_t dev) { struct mmc_softc *sc = device_get_softc(dev); mmc_scan(sc); return (bus_generic_resume(dev)); } static int mmc_acquire_bus(device_t busdev, device_t dev) { struct mmc_softc *sc; struct mmc_ivars *ivar; int err; int rca; err = MMCBR_ACQUIRE_HOST(device_get_parent(busdev), busdev); if (err) return (err); sc = device_get_softc(busdev); MMC_LOCK(sc); if (sc->owner) panic("mmc: host bridge didn't serialize us."); sc->owner = dev; MMC_UNLOCK(sc); if (busdev != dev) { /* * Keep track of the last rca that we've selected. If * we're asked to do it again, don't. We never * unselect unless the bus code itself wants the mmc * bus, and constantly reselecting causes problems. */ rca = mmc_get_rca(dev); if (sc->last_rca != rca) { mmc_select_card(sc, rca); sc->last_rca = rca; /* Prepare bus width for the new card. */ ivar = device_get_ivars(dev); if (bootverbose || mmc_debug) { device_printf(busdev, "setting bus width to %d bits\n", (ivar->bus_width == bus_width_4) ? 4 : (ivar->bus_width == bus_width_8) ? 8 : 1); } mmc_set_card_bus_width(sc, rca, ivar->bus_width); mmcbr_set_bus_width(busdev, ivar->bus_width); mmcbr_update_ios(busdev); } } else { /* * If there's a card selected, stand down. */ if (sc->last_rca != 0) { mmc_select_card(sc, 0); sc->last_rca = 0; } } return (0); } static int mmc_release_bus(device_t busdev, device_t dev) { struct mmc_softc *sc; int err; sc = device_get_softc(busdev); MMC_LOCK(sc); if (!sc->owner) panic("mmc: releasing unowned bus."); if (sc->owner != dev) panic("mmc: you don't own the bus. game over."); MMC_UNLOCK(sc); err = MMCBR_RELEASE_HOST(device_get_parent(busdev), busdev); if (err) return (err); MMC_LOCK(sc); sc->owner = NULL; MMC_UNLOCK(sc); return (0); } static uint32_t mmc_select_vdd(struct mmc_softc *sc, uint32_t ocr) { return (ocr & MMC_OCR_VOLTAGE); } static int mmc_highest_voltage(uint32_t ocr) { int i; for (i = MMC_OCR_MAX_VOLTAGE_SHIFT; i >= MMC_OCR_MIN_VOLTAGE_SHIFT; i--) if (ocr & (1 << i)) return (i); return (-1); } static void mmc_wakeup(struct mmc_request *req) { struct mmc_softc *sc; sc = (struct mmc_softc *)req->done_data; MMC_LOCK(sc); req->flags |= MMC_REQ_DONE; MMC_UNLOCK(sc); wakeup(req); } static int mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req) { req->done = mmc_wakeup; req->done_data = sc; if (mmc_debug > 1) { device_printf(sc->dev, "REQUEST: CMD%d arg %#x flags %#x", req->cmd->opcode, req->cmd->arg, req->cmd->flags); if (req->cmd->data) { printf(" data %d\n", (int)req->cmd->data->len); } else printf("\n"); } MMCBR_REQUEST(device_get_parent(sc->dev), sc->dev, req); MMC_LOCK(sc); while ((req->flags & MMC_REQ_DONE) == 0) msleep(req, &sc->sc_mtx, 0, "mmcreq", 0); MMC_UNLOCK(sc); if (mmc_debug > 2 || (mmc_debug > 0 && req->cmd->error != MMC_ERR_NONE)) device_printf(sc->dev, "CMD%d RESULT: %d\n", req->cmd->opcode, req->cmd->error); return (0); } static int mmc_wait_for_request(device_t brdev, device_t reqdev, struct mmc_request *req) { struct mmc_softc *sc = device_get_softc(brdev); return (mmc_wait_for_req(sc, req)); } static int mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd, int retries) { struct mmc_request mreq; int err; do { memset(&mreq, 0, sizeof(mreq)); memset(cmd->resp, 0, sizeof(cmd->resp)); cmd->retries = 0; /* Retries done here, not in hardware. */ cmd->mrq = &mreq; mreq.cmd = cmd; if (mmc_wait_for_req(sc, &mreq) != 0) err = MMC_ERR_FAILED; else err = cmd->error; } while (err != MMC_ERR_NONE && retries-- > 0); if (err != MMC_ERR_NONE && sc->squelched == 0) { if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) { device_printf(sc->dev, "CMD%d failed, RESULT: %d\n", cmd->opcode, err); } } return (err); } static int mmc_wait_for_app_cmd(struct mmc_softc *sc, uint32_t rca, struct mmc_command *cmd, int retries) { struct mmc_command appcmd; int err; /* Squelch error reporting at lower levels, we report below. */ sc->squelched++; do { memset(&appcmd, 0, sizeof(appcmd)); appcmd.opcode = MMC_APP_CMD; appcmd.arg = rca << 16; appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC; appcmd.data = NULL; if (mmc_wait_for_cmd(sc, &appcmd, 0) != 0) err = MMC_ERR_FAILED; else err = appcmd.error; if (err == MMC_ERR_NONE) { if (!(appcmd.resp[0] & R1_APP_CMD)) err = MMC_ERR_FAILED; else if (mmc_wait_for_cmd(sc, cmd, 0) != 0) err = MMC_ERR_FAILED; else err = cmd->error; } } while (err != MMC_ERR_NONE && retries-- > 0); sc->squelched--; if (err != MMC_ERR_NONE && sc->squelched == 0) { if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) { device_printf(sc->dev, "ACMD%d failed, RESULT: %d\n", cmd->opcode, err); } } return (err); } static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, uint32_t arg, uint32_t flags, uint32_t *resp, int retries) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = opcode; cmd.arg = arg; cmd.flags = flags; cmd.data = NULL; err = mmc_wait_for_cmd(sc, &cmd, retries); if (err) return (err); if (resp) { if (flags & MMC_RSP_136) memcpy(resp, cmd.resp, 4 * sizeof(uint32_t)); else *resp = cmd.resp[0]; } return (0); } static void mmc_idle_cards(struct mmc_softc *sc) { device_t dev; struct mmc_command cmd; dev = sc->dev; mmcbr_set_chip_select(dev, cs_high); mmcbr_update_ios(dev); mmc_ms_delay(1); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; cmd.data = NULL; mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); mmc_ms_delay(1); mmcbr_set_chip_select(dev, cs_dontcare); mmcbr_update_ios(dev); mmc_ms_delay(1); } static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { struct mmc_command cmd; int err = MMC_ERR_NONE, i; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = ACMD_SD_SEND_OP_COND; cmd.arg = ocr; cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; cmd.data = NULL; for (i = 0; i < 1000; i++) { err = mmc_wait_for_app_cmd(sc, 0, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) break; if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || (ocr & MMC_OCR_VOLTAGE) == 0) break; err = MMC_ERR_TIMEOUT; mmc_ms_delay(10); } if (rocr && err == MMC_ERR_NONE) *rocr = cmd.resp[0]; return (err); } static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { struct mmc_command cmd; int err = MMC_ERR_NONE, i; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SEND_OP_COND; cmd.arg = ocr; cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; cmd.data = NULL; for (i = 0; i < 1000; i++) { err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) break; if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || (ocr & MMC_OCR_VOLTAGE) == 0) break; err = MMC_ERR_TIMEOUT; mmc_ms_delay(10); } if (rocr && err == MMC_ERR_NONE) *rocr = cmd.resp[0]; return (err); } static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SD_SEND_IF_COND; cmd.arg = (vhs << 8) + 0xAA; cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); return (err); } static void mmc_power_up(struct mmc_softc *sc) { device_t dev; dev = sc->dev; mmcbr_set_vdd(dev, mmc_highest_voltage(mmcbr_get_host_ocr(dev))); mmcbr_set_bus_mode(dev, opendrain); mmcbr_set_chip_select(dev, cs_dontcare); mmcbr_set_bus_width(dev, bus_width_1); mmcbr_set_power_mode(dev, power_up); mmcbr_set_clock(dev, 0); mmcbr_update_ios(dev); mmc_ms_delay(1); mmcbr_set_clock(dev, CARD_ID_FREQUENCY); mmcbr_set_timing(dev, bus_timing_normal); mmcbr_set_power_mode(dev, power_on); mmcbr_update_ios(dev); mmc_ms_delay(2); } static void mmc_power_down(struct mmc_softc *sc) { device_t dev = sc->dev; mmcbr_set_bus_mode(dev, opendrain); mmcbr_set_chip_select(dev, cs_dontcare); mmcbr_set_bus_width(dev, bus_width_1); mmcbr_set_power_mode(dev, power_off); mmcbr_set_clock(dev, 0); mmcbr_set_timing(dev, bus_timing_normal); mmcbr_update_ios(dev); } static int mmc_select_card(struct mmc_softc *sc, uint16_t rca) { int flags; flags = (rca ? MMC_RSP_R1B : MMC_RSP_NONE) | MMC_CMD_AC; return (mmc_wait_for_command(sc, MMC_SELECT_CARD, (uint32_t)rca << 16, flags, NULL, CMD_RETRIES)); } static int mmc_switch(struct mmc_softc *sc, uint8_t set, uint8_t index, uint8_t value) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SWITCH_FUNC; cmd.arg = (MMC_SWITCH_FUNC_WR << 24) | (index << 16) | (value << 8) | set; cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; cmd.data = NULL; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); return (err); } static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value, uint8_t *res) { int err; struct mmc_command cmd; struct mmc_data data; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(res, 0, 64); cmd.opcode = SD_SWITCH_FUNC; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = mode << 31; /* 0 - check, 1 - set */ cmd.arg |= 0x00FFFFFF; cmd.arg &= ~(0xF << (grp * 4)); cmd.arg |= value << (grp * 4); cmd.data = &data; data.data = res; data.len = 64; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); return (err); } static int mmc_set_card_bus_width(struct mmc_softc *sc, uint16_t rca, int width) { struct mmc_command cmd; int err; uint8_t value; if (mmcbr_get_mode(sc->dev) == mode_sd) { memset(&cmd, 0, sizeof(cmd)); cmd.opcode = ACMD_SET_CLR_CARD_DETECT; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.arg = SD_CLR_CARD_DETECT; err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); if (err != 0) return (err); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = ACMD_SET_BUS_WIDTH; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; switch (width) { case bus_width_1: cmd.arg = SD_BUS_WIDTH_1; break; case bus_width_4: cmd.arg = SD_BUS_WIDTH_4; break; default: return (MMC_ERR_INVALID); } err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); } else { switch (width) { case bus_width_1: value = EXT_CSD_BUS_WIDTH_1; break; case bus_width_4: value = EXT_CSD_BUS_WIDTH_4; break; case bus_width_8: value = EXT_CSD_BUS_WIDTH_8; break; default: return (MMC_ERR_INVALID); } err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, value); } return (err); } static int mmc_set_timing(struct mmc_softc *sc, int timing) { + u_char switch_res[64]; int err; uint8_t value; - u_char switch_res[64]; switch (timing) { case bus_timing_normal: value = 0; break; case bus_timing_hs: value = 1; break; default: return (MMC_ERR_INVALID); } if (mmcbr_get_mode(sc->dev) == mode_sd) err = mmc_sd_switch(sc, SD_SWITCH_MODE_SET, SD_SWITCH_GROUP1, value, switch_res); else err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, value); return (err); } static int mmc_test_bus_width(struct mmc_softc *sc) { struct mmc_command cmd; struct mmc_data data; int err; uint8_t buf[8]; uint8_t p8[8] = { 0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t p8ok[8] = { 0xAA, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t p4[4] = { 0x5A, 0x00, 0x00, 0x00, }; uint8_t p4ok[4] = { 0xA5, 0x00, 0x00, 0x00, }; if (mmcbr_get_caps(sc->dev) & MMC_CAP_8_BIT_DATA) { mmcbr_set_bus_width(sc->dev, bus_width_8); mmcbr_update_ios(sc->dev); sc->squelched++; /* Errors are expected, squelch reporting. */ memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_W; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = p8; data.len = 8; data.flags = MMC_DATA_WRITE; mmc_wait_for_cmd(sc, &cmd, 0); memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_R; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = buf; data.len = 8; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(sc, &cmd, 0); sc->squelched--; mmcbr_set_bus_width(sc->dev, bus_width_1); mmcbr_update_ios(sc->dev); if (err == MMC_ERR_NONE && memcmp(buf, p8ok, 8) == 0) return (bus_width_8); } if (mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) { mmcbr_set_bus_width(sc->dev, bus_width_4); mmcbr_update_ios(sc->dev); sc->squelched++; /* Errors are expected, squelch reporting. */ memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_W; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = p4; data.len = 4; data.flags = MMC_DATA_WRITE; mmc_wait_for_cmd(sc, &cmd, 0); memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = MMC_BUSTEST_R; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.data = buf; data.len = 4; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(sc, &cmd, 0); sc->squelched--; mmcbr_set_bus_width(sc->dev, bus_width_1); mmcbr_update_ios(sc->dev); if (err == MMC_ERR_NONE && memcmp(buf, p4ok, 4) == 0) return (bus_width_4); } return (bus_width_1); } static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start, int size) { const int i = (bit_len / 32) - (start / 32) - 1; const int shift = start & 31; uint32_t retval = bits[i] >> shift; if (size + shift > 32) retval |= bits[i - 1] << (32 - shift); return (retval & ((1llu << size) - 1)); } static void mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid) { int i; /* There's no version info, so we take it on faith */ memset(cid, 0, sizeof(*cid)); cid->mid = mmc_get_bits(raw_cid, 128, 120, 8); cid->oid = mmc_get_bits(raw_cid, 128, 104, 16); for (i = 0; i < 5; i++) cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8); cid->pnm[5] = 0; cid->prv = mmc_get_bits(raw_cid, 128, 56, 8); cid->psn = mmc_get_bits(raw_cid, 128, 24, 32); cid->mdt_year = mmc_get_bits(raw_cid, 128, 12, 8) + 2000; cid->mdt_month = mmc_get_bits(raw_cid, 128, 8, 4); } static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid) { int i; /* There's no version info, so we take it on faith */ memset(cid, 0, sizeof(*cid)); cid->mid = mmc_get_bits(raw_cid, 128, 120, 8); cid->oid = mmc_get_bits(raw_cid, 128, 104, 8); for (i = 0; i < 6; i++) cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8); cid->pnm[6] = 0; cid->prv = mmc_get_bits(raw_cid, 128, 48, 8); cid->psn = mmc_get_bits(raw_cid, 128, 16, 32); cid->mdt_month = mmc_get_bits(raw_cid, 128, 12, 4); cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4) + 1997; } static void mmc_format_card_id_string(struct mmc_ivars *ivar) { char oidstr[8]; uint8_t c1; uint8_t c2; /* * Format a card ID string for use by the mmcsd driver, it's what * appears between the <> in the following: * mmcsd0: 968MB at mmc0 * 22.5MHz/4bit/128-block * * Also format just the card serial number, which the mmcsd driver will * use as the disk->d_ident string. * * The card_id_string in mmc_ivars is currently allocated as 64 bytes, * and our max formatted length is currently 55 bytes if every field * contains the largest value. * * Sometimes the oid is two printable ascii chars; when it's not, * format it as 0xnnnn instead. */ c1 = (ivar->cid.oid >> 8) & 0x0ff; c2 = ivar->cid.oid & 0x0ff; if (c1 > 0x1f && c1 < 0x7f && c2 > 0x1f && c2 < 0x7f) snprintf(oidstr, sizeof(oidstr), "%c%c", c1, c2); else snprintf(oidstr, sizeof(oidstr), "0x%04x", ivar->cid.oid); snprintf(ivar->card_sn_string, sizeof(ivar->card_sn_string), "%08X", ivar->cid.psn); snprintf(ivar->card_id_string, sizeof(ivar->card_id_string), "%s%s %s %d.%d SN %08X MFG %02d/%04d by %d %s", ivar->mode == mode_sd ? "SD" : "MMC", ivar->high_cap ? "HC" : "", ivar->cid.pnm, ivar->cid.prv >> 4, ivar->cid.prv & 0x0f, ivar->cid.psn, ivar->cid.mdt_month, ivar->cid.mdt_year, ivar->cid.mid, oidstr); } static const int exp[8] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; static const int mant[16] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; static const int cur_min[8] = { 500, 1000, 5000, 10000, 25000, 35000, 60000, 100000 }; static const int cur_max[8] = { 1000, 5000, 10000, 25000, 35000, 45000, 800000, 200000 }; static void mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd) { int v; int m; int e; memset(csd, 0, sizeof(*csd)); csd->csd_structure = v = mmc_get_bits(raw_csd, 128, 126, 2); if (v == 0) { m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = (exp[e] * mant[m] + 9) / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)]; csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)]; csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)]; csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)]; m = mmc_get_bits(raw_csd, 128, 62, 12); e = mmc_get_bits(raw_csd, 128, 47, 3); csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len; csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1); csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1; csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); } else if (v == 1) { m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = (exp[e] * mant[m] + 9) / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); csd->capacity = ((uint64_t)mmc_get_bits(raw_csd, 128, 48, 22) + 1) * 512 * 1024; csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1); csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1; csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); } else panic("unknown SD CSD version"); } static void mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd) { int m; int e; memset(csd, 0, sizeof(*csd)); csd->csd_structure = mmc_get_bits(raw_csd, 128, 126, 2); csd->spec_vers = mmc_get_bits(raw_csd, 128, 122, 4); m = mmc_get_bits(raw_csd, 128, 115, 4); e = mmc_get_bits(raw_csd, 128, 112, 3); csd->tacc = exp[e] * mant[m] + 9 / 10; csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100; m = mmc_get_bits(raw_csd, 128, 99, 4); e = mmc_get_bits(raw_csd, 128, 96, 3); csd->tran_speed = exp[e] * 10000 * mant[m]; csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12); csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4); csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1); csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1); csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1); csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1); csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)]; csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)]; csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)]; csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)]; m = mmc_get_bits(raw_csd, 128, 62, 12); e = mmc_get_bits(raw_csd, 128, 47, 3); csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len; csd->erase_blk_en = 0; csd->erase_sector = (mmc_get_bits(raw_csd, 128, 42, 5) + 1) * (mmc_get_bits(raw_csd, 128, 37, 5) + 1); csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 5); csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1); csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3); csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4); csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1); } static void mmc_app_decode_scr(uint32_t *raw_scr, struct mmc_scr *scr) { unsigned int scr_struct; memset(scr, 0, sizeof(*scr)); scr_struct = mmc_get_bits(raw_scr, 64, 60, 4); if (scr_struct != 0) { printf("Unrecognised SCR structure version %d\n", scr_struct); return; } scr->sda_vsn = mmc_get_bits(raw_scr, 64, 56, 4); scr->bus_widths = mmc_get_bits(raw_scr, 64, 48, 4); } static void mmc_app_decode_sd_status(uint32_t *raw_sd_status, struct mmc_sd_status *sd_status) { memset(sd_status, 0, sizeof(*sd_status)); sd_status->bus_width = mmc_get_bits(raw_sd_status, 512, 510, 2); sd_status->secured_mode = mmc_get_bits(raw_sd_status, 512, 509, 1); sd_status->card_type = mmc_get_bits(raw_sd_status, 512, 480, 16); sd_status->prot_area = mmc_get_bits(raw_sd_status, 512, 448, 12); sd_status->speed_class = mmc_get_bits(raw_sd_status, 512, 440, 8); sd_status->perf_move = mmc_get_bits(raw_sd_status, 512, 432, 8); sd_status->au_size = mmc_get_bits(raw_sd_status, 512, 428, 4); sd_status->erase_size = mmc_get_bits(raw_sd_status, 512, 408, 16); sd_status->erase_timeout = mmc_get_bits(raw_sd_status, 512, 402, 6); sd_status->erase_offset = mmc_get_bits(raw_sd_status, 512, 400, 2); } static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t)); return (err); } static int mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcsd) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SEND_CSD; cmd.arg = rca << 16; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); memcpy(rawcsd, cmd.resp, 4 * sizeof(uint32_t)); return (err); } static int mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr) { int err; struct mmc_command cmd; struct mmc_data data; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(rawscr, 0, 8); cmd.opcode = ACMD_SEND_SCR; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = 0; cmd.data = &data; data.data = rawscr; data.len = 8; data.flags = MMC_DATA_READ; err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); rawscr[0] = be32toh(rawscr[0]); rawscr[1] = be32toh(rawscr[1]); return (err); } static int mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd) { - int err; struct mmc_command cmd; struct mmc_data data; + int err; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(rawextcsd, 0, 512); cmd.opcode = MMC_SEND_EXT_CSD; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = 0; cmd.data = &data; data.data = rawextcsd; data.len = 512; data.flags = MMC_DATA_READ; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); return (err); } static int mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus) { - int err, i; struct mmc_command cmd; struct mmc_data data; + int err, i; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); memset(rawsdstatus, 0, 64); cmd.opcode = ACMD_SD_STATUS; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.arg = 0; cmd.data = &data; data.data = rawsdstatus; data.len = 64; data.flags = MMC_DATA_READ; err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); for (i = 0; i < 16; i++) rawsdstatus[i] = be32toh(rawsdstatus[i]); return (err); } static int mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = resp << 16; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); return (err); } static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; cmd.data = NULL; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); *resp = cmd.resp[0]; return (err); } static int mmc_send_status(struct mmc_softc *sc, uint16_t rca, uint32_t *status) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SEND_STATUS; cmd.arg = rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.data = NULL; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); *status = cmd.resp[0]; return (err); } static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len) { struct mmc_command cmd; int err; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = len; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.data = NULL; err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); return (err); } static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard) { device_printf(dev, "Card at relative address 0x%04x%s:\n", ivar->rca, newcard ? " added" : ""); device_printf(dev, " card: %s\n", ivar->card_id_string); device_printf(dev, " bus: %ubit, %uMHz%s\n", (ivar->bus_width == bus_width_1 ? 1 : (ivar->bus_width == bus_width_4 ? 4 : 8)), (ivar->timing == bus_timing_hs ? ivar->hs_tran_speed : ivar->tran_speed) / 1000000, ivar->timing == bus_timing_hs ? ", high speed timing" : ""); device_printf(dev, " memory: %u blocks, erase sector %u blocks%s\n", ivar->sec_count, ivar->erase_sector, ivar->read_only ? ", read-only" : ""); } static void mmc_discover_cards(struct mmc_softc *sc) { struct mmc_ivars *ivar = NULL; device_t *devlist; int err, i, devcount, newcard; uint32_t raw_cid[4], resp, sec_count, status; device_t child; uint16_t rca = 2; u_char switch_res[64]; if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing cards\n"); while (1) { sc->squelched++; /* Errors are expected, squelch reporting. */ err = mmc_all_send_cid(sc, raw_cid); sc->squelched--; if (err == MMC_ERR_TIMEOUT) break; if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading CID %d\n", err); break; } newcard = 1; if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) return; for (i = 0; i < devcount; i++) { ivar = device_get_ivars(devlist[i]); if (memcmp(ivar->raw_cid, raw_cid, sizeof(raw_cid)) == 0) { newcard = 0; break; } } free(devlist, M_TEMP); if (bootverbose || mmc_debug) { device_printf(sc->dev, "%sard detected (CID %08x%08x%08x%08x)\n", newcard ? "New c" : "C", raw_cid[0], raw_cid[1], raw_cid[2], raw_cid[3]); } if (newcard) { ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF, M_WAITOK | M_ZERO); memcpy(ivar->raw_cid, raw_cid, sizeof(raw_cid)); } if (mmcbr_get_ro(sc->dev)) ivar->read_only = 1; ivar->bus_width = bus_width_1; ivar->timing = bus_timing_normal; ivar->mode = mmcbr_get_mode(sc->dev); if (ivar->mode == mode_sd) { mmc_decode_cid_sd(ivar->raw_cid, &ivar->cid); mmc_send_relative_addr(sc, &resp); ivar->rca = resp >> 16; /* Get card CSD. */ mmc_send_csd(sc, ivar->rca, ivar->raw_csd); if (bootverbose || mmc_debug) device_printf(sc->dev, "%sard detected (CSD %08x%08x%08x%08x)\n", newcard ? "New c" : "C", ivar->raw_csd[0], ivar->raw_csd[1], ivar->raw_csd[2], ivar->raw_csd[3]); mmc_decode_csd_sd(ivar->raw_csd, &ivar->csd); ivar->sec_count = ivar->csd.capacity / MMC_SECTOR_SIZE; if (ivar->csd.csd_structure > 0) ivar->high_cap = 1; ivar->tran_speed = ivar->csd.tran_speed; ivar->erase_sector = ivar->csd.erase_sector * ivar->csd.write_bl_len / MMC_SECTOR_SIZE; err = mmc_send_status(sc, ivar->rca, &status); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading card status %d\n", err); break; } if ((status & R1_CARD_IS_LOCKED) != 0) { device_printf(sc->dev, "Card is password protected, skipping.\n"); break; } /* Get card SCR. Card must be selected to fetch it. */ mmc_select_card(sc, ivar->rca); mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr); mmc_app_decode_scr(ivar->raw_scr, &ivar->scr); /* Get card switch capabilities (command class 10). */ if ((ivar->scr.sda_vsn >= 1) && (ivar->csd.ccc & (1 << 10))) { mmc_sd_switch(sc, SD_SWITCH_MODE_CHECK, SD_SWITCH_GROUP1, SD_SWITCH_NOCHANGE, switch_res); if (switch_res[13] & 2) { ivar->timing = bus_timing_hs; ivar->hs_tran_speed = SD_MAX_HS; } } /* * We deselect then reselect the card here. Some cards * become unselected and timeout with the above two * commands, although the state tables / diagrams in the * standard suggest they go back to the transfer state. * Other cards don't become deselected, and if we - * atttempt to blindly re-select them, we get timeout + * attempt to blindly re-select them, we get timeout * errors from some controllers. So we deselect then * reselect to handle all situations. The only thing we * use from the sd_status is the erase sector size, but * it is still nice to get that right. */ mmc_select_card(sc, 0); mmc_select_card(sc, ivar->rca); mmc_app_sd_status(sc, ivar->rca, ivar->raw_sd_status); mmc_app_decode_sd_status(ivar->raw_sd_status, &ivar->sd_status); if (ivar->sd_status.au_size != 0) { ivar->erase_sector = 16 << ivar->sd_status.au_size; } /* Find max supported bus width. */ if ((mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) && (ivar->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) ivar->bus_width = bus_width_4; /* * Some cards that report maximum I/O block sizes * greater than 512 require the block length to be * set to 512, even though that is supposed to be * the default. Example: * * Transcend 2GB SDSC card, CID: * mid=0x1b oid=0x534d pnm="00000" prv=1.0 mdt=00.2000 */ if (ivar->csd.read_bl_len != MMC_SECTOR_SIZE || ivar->csd.write_bl_len != MMC_SECTOR_SIZE) mmc_set_blocklen(sc, MMC_SECTOR_SIZE); mmc_format_card_id_string(ivar); if (bootverbose || mmc_debug) mmc_log_card(sc->dev, ivar, newcard); if (newcard) { /* Add device. */ child = device_add_child(sc->dev, NULL, -1); device_set_ivars(child, ivar); } mmc_select_card(sc, 0); return; } mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid); ivar->rca = rca++; mmc_set_relative_addr(sc, ivar->rca); /* Get card CSD. */ mmc_send_csd(sc, ivar->rca, ivar->raw_csd); if (bootverbose || mmc_debug) device_printf(sc->dev, "%sard detected (CSD %08x%08x%08x%08x)\n", newcard ? "New c" : "C", ivar->raw_csd[0], ivar->raw_csd[1], ivar->raw_csd[2], ivar->raw_csd[3]); mmc_decode_csd_mmc(ivar->raw_csd, &ivar->csd); ivar->sec_count = ivar->csd.capacity / MMC_SECTOR_SIZE; ivar->tran_speed = ivar->csd.tran_speed; ivar->erase_sector = ivar->csd.erase_sector * ivar->csd.write_bl_len / MMC_SECTOR_SIZE; err = mmc_send_status(sc, ivar->rca, &status); if (err != MMC_ERR_NONE) { device_printf(sc->dev, "Error reading card status %d\n", err); break; } if ((status & R1_CARD_IS_LOCKED) != 0) { device_printf(sc->dev, "Card is password protected, skipping.\n"); break; } mmc_select_card(sc, ivar->rca); /* Only MMC >= 4.x cards support EXT_CSD. */ if (ivar->csd.spec_vers >= 4) { mmc_send_ext_csd(sc, ivar->raw_ext_csd); /* Handle extended capacity from EXT_CSD */ sec_count = ivar->raw_ext_csd[EXT_CSD_SEC_CNT] + (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 1] << 8) + (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 2] << 16) + (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 3] << 24); if (sec_count != 0) { ivar->sec_count = sec_count; ivar->high_cap = 1; } /* Get card speed in high speed mode. */ ivar->timing = bus_timing_hs; if (ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_52) ivar->hs_tran_speed = MMC_TYPE_52_MAX_HS; else if (ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_26) ivar->hs_tran_speed = MMC_TYPE_26_MAX_HS; else ivar->hs_tran_speed = ivar->tran_speed; /* Find max supported bus width. */ ivar->bus_width = mmc_test_bus_width(sc); /* Handle HC erase sector size. */ if (ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) { ivar->erase_sector = 1024 * ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE]; mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_ERASE_GRP_DEF, 1); } } else { ivar->bus_width = bus_width_1; ivar->timing = bus_timing_normal; } /* * Some cards that report maximum I/O block sizes greater * than 512 require the block length to be set to 512, even * though that is supposed to be the default. Example: * * Transcend 2GB SDSC card, CID: * mid=0x1b oid=0x534d pnm="00000" prv=1.0 mdt=00.2000 */ if (ivar->csd.read_bl_len != MMC_SECTOR_SIZE || ivar->csd.write_bl_len != MMC_SECTOR_SIZE) mmc_set_blocklen(sc, MMC_SECTOR_SIZE); mmc_format_card_id_string(ivar); if (bootverbose || mmc_debug) mmc_log_card(sc->dev, ivar, newcard); if (newcard) { /* Add device. */ child = device_add_child(sc->dev, NULL, -1); device_set_ivars(child, ivar); } mmc_select_card(sc, 0); } } static void mmc_rescan_cards(struct mmc_softc *sc) { - struct mmc_ivars *ivar = NULL; + struct mmc_ivars *ivar; device_t *devlist; int err, i, devcount; if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) return; for (i = 0; i < devcount; i++) { ivar = device_get_ivars(devlist[i]); if (mmc_select_card(sc, ivar->rca)) { if (bootverbose || mmc_debug) device_printf(sc->dev, "Card at relative address %d lost.\n", ivar->rca); device_delete_child(sc->dev, devlist[i]); free(ivar, M_DEVBUF); } } free(devlist, M_TEMP); mmc_select_card(sc, 0); } static int mmc_delete_cards(struct mmc_softc *sc) { struct mmc_ivars *ivar; device_t *devlist; int err, i, devcount; if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) return (err); for (i = 0; i < devcount; i++) { ivar = device_get_ivars(devlist[i]); if (bootverbose || mmc_debug) device_printf(sc->dev, "Card at relative address %d deleted.\n", ivar->rca); device_delete_child(sc->dev, devlist[i]); free(ivar, M_DEVBUF); } free(devlist, M_TEMP); return (0); } static void mmc_go_discovery(struct mmc_softc *sc) { uint32_t ocr; device_t dev; int err; dev = sc->dev; if (mmcbr_get_power_mode(dev) != power_on) { /* * First, try SD modes */ sc->squelched++; /* Errors are expected, squelch reporting. */ mmcbr_set_mode(dev, mode_sd); mmc_power_up(sc); mmcbr_set_bus_mode(dev, pushpull); if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing bus\n"); mmc_idle_cards(sc); err = mmc_send_if_cond(sc, 1); if ((bootverbose || mmc_debug) && err == 0) device_printf(sc->dev, "SD 2.0 interface conditions: OK\n"); if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { if (bootverbose || mmc_debug) device_printf(sc->dev, "SD probe: failed\n"); /* * Failed, try MMC */ mmcbr_set_mode(dev, mode_mmc); if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { if (bootverbose || mmc_debug) device_printf(sc->dev, "MMC probe: failed\n"); ocr = 0; /* Failed both, powerdown. */ } else if (bootverbose || mmc_debug) device_printf(sc->dev, "MMC probe: OK (OCR: 0x%08x)\n", ocr); } else if (bootverbose || mmc_debug) device_printf(sc->dev, "SD probe: OK (OCR: 0x%08x)\n", ocr); sc->squelched--; mmcbr_set_ocr(dev, mmc_select_vdd(sc, ocr)); if (mmcbr_get_ocr(dev) != 0) mmc_idle_cards(sc); } else { mmcbr_set_bus_mode(dev, opendrain); mmcbr_set_clock(dev, CARD_ID_FREQUENCY); mmcbr_update_ios(dev); /* XXX recompute vdd based on new cards? */ } /* * Make sure that we have a mutually agreeable voltage to at least * one card on the bus. */ if (bootverbose || mmc_debug) device_printf(sc->dev, "Current OCR: 0x%08x\n", mmcbr_get_ocr(dev)); if (mmcbr_get_ocr(dev) == 0) { device_printf(sc->dev, "No compatible cards found on bus\n"); mmc_delete_cards(sc); mmc_power_down(sc); return; } /* * Reselect the cards after we've idled them above. */ if (mmcbr_get_mode(dev) == mode_sd) { err = mmc_send_if_cond(sc, 1); mmc_send_app_op_cond(sc, (err ? 0 : MMC_OCR_CCS) | mmcbr_get_ocr(dev), NULL); } else mmc_send_op_cond(sc, MMC_OCR_CCS | mmcbr_get_ocr(dev), NULL); mmc_discover_cards(sc); mmc_rescan_cards(sc); mmcbr_set_bus_mode(dev, pushpull); mmcbr_update_ios(dev); mmc_calculate_clock(sc); bus_generic_attach(dev); /* mmc_update_children_sysctl(dev);*/ } static int mmc_calculate_clock(struct mmc_softc *sc) { - int max_dtr, max_hs_dtr, max_timing; - int nkid, i, f_max; device_t *kids; struct mmc_ivars *ivar; + int i, f_max, max_dtr, max_hs_dtr, max_timing, nkid; f_max = mmcbr_get_f_max(sc->dev); max_dtr = max_hs_dtr = f_max; - if ((mmcbr_get_caps(sc->dev) & MMC_CAP_HSPEED)) + if (mmcbr_get_caps(sc->dev) & MMC_CAP_HSPEED) max_timing = bus_timing_hs; else max_timing = bus_timing_normal; if (device_get_children(sc->dev, &kids, &nkid) != 0) panic("can't get children"); for (i = 0; i < nkid; i++) { ivar = device_get_ivars(kids[i]); if (ivar->timing < max_timing) max_timing = ivar->timing; if (ivar->tran_speed < max_dtr) max_dtr = ivar->tran_speed; if (ivar->hs_tran_speed < max_hs_dtr) max_hs_dtr = ivar->hs_tran_speed; } for (i = 0; i < nkid; i++) { ivar = device_get_ivars(kids[i]); if (ivar->timing == bus_timing_normal) continue; mmc_select_card(sc, ivar->rca); mmc_set_timing(sc, max_timing); } mmc_select_card(sc, 0); free(kids, M_TEMP); if (max_timing == bus_timing_hs) max_dtr = max_hs_dtr; if (bootverbose || mmc_debug) { device_printf(sc->dev, "setting transfer rate to %d.%03dMHz%s\n", max_dtr / 1000000, (max_dtr / 1000) % 1000, max_timing == bus_timing_hs ? " (high speed timing)" : ""); } mmcbr_set_timing(sc->dev, max_timing); mmcbr_set_clock(sc->dev, max_dtr); mmcbr_update_ios(sc->dev); return max_dtr; } static void mmc_scan(struct mmc_softc *sc) { device_t dev = sc->dev; mmc_acquire_bus(dev, dev); mmc_go_discovery(sc); mmc_release_bus(dev, dev); } static int mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) { struct mmc_ivars *ivar = device_get_ivars(child); switch (which) { default: return (EINVAL); case MMC_IVAR_DSR_IMP: *result = ivar->csd.dsr_imp; break; case MMC_IVAR_MEDIA_SIZE: *result = ivar->sec_count; break; case MMC_IVAR_RCA: *result = ivar->rca; break; case MMC_IVAR_SECTOR_SIZE: *result = MMC_SECTOR_SIZE; break; case MMC_IVAR_TRAN_SPEED: *result = mmcbr_get_clock(bus); break; case MMC_IVAR_READ_ONLY: *result = ivar->read_only; break; case MMC_IVAR_HIGH_CAP: *result = ivar->high_cap; break; case MMC_IVAR_CARD_TYPE: *result = ivar->mode; break; case MMC_IVAR_BUS_WIDTH: *result = ivar->bus_width; break; case MMC_IVAR_ERASE_SECTOR: *result = ivar->erase_sector; break; case MMC_IVAR_MAX_DATA: *result = mmcbr_get_max_data(bus); break; case MMC_IVAR_CARD_ID_STRING: *(char **)result = ivar->card_id_string; break; case MMC_IVAR_CARD_SN_STRING: *(char **)result = ivar->card_sn_string; break; } return (0); } static int mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) { /* * None are writable ATM */ return (EINVAL); } static void mmc_delayed_attach(void *xsc) { struct mmc_softc *sc = xsc; mmc_scan(sc); config_intrhook_disestablish(&sc->config_intrhook); } static int mmc_child_location_str(device_t dev, device_t child, char *buf, size_t buflen) { snprintf(buf, buflen, "rca=0x%04x", mmc_get_rca(child)); return (0); } static device_method_t mmc_methods[] = { /* device_if */ DEVMETHOD(device_probe, mmc_probe), DEVMETHOD(device_attach, mmc_attach), DEVMETHOD(device_detach, mmc_detach), DEVMETHOD(device_suspend, mmc_suspend), DEVMETHOD(device_resume, mmc_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, mmc_read_ivar), DEVMETHOD(bus_write_ivar, mmc_write_ivar), DEVMETHOD(bus_child_location_str, mmc_child_location_str), /* MMC Bus interface */ DEVMETHOD(mmcbus_wait_for_request, mmc_wait_for_request), DEVMETHOD(mmcbus_acquire_bus, mmc_acquire_bus), DEVMETHOD(mmcbus_release_bus, mmc_release_bus), DEVMETHOD_END }; driver_t mmc_driver = { "mmc", mmc_methods, sizeof(struct mmc_softc), }; devclass_t mmc_devclass; MODULE_VERSION(mmc, 1); Index: projects/ipsec/sys/dev/mmc/mmcreg.h =================================================================== --- projects/ipsec/sys/dev/mmc/mmcreg.h (revision 313312) +++ projects/ipsec/sys/dev/mmc/mmcreg.h (revision 313313) @@ -1,448 +1,448 @@ /*- * Copyright (c) 2006 M. Warner Losh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * Portions of this software may have been developed with reference to * the SD Simplified Specification. The following disclaimer may apply: * * The following conditions apply to the release of the simplified * specification ("Simplified Specification") by the SD Card Association and * the SD Group. The Simplified Specification is a subset of the complete SD * Specification which is owned by the SD Card Association and the SD * Group. This Simplified Specification is provided on a non-confidential * basis subject to the disclaimers below. Any implementation of the * Simplified Specification may require a license from the SD Card * Association, SD Group, SD-3C LLC or other third parties. * * Disclaimers: * * The information contained in the Simplified Specification is presented only * as a standard specification for SD Cards and SD Host/Ancillary products and * is provided "AS-IS" without any representations or warranties of any * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD * Card Association for any damages, any infringements of patents or other * right of the SD Group, SD-3C LLC, the SD Card Association or any third * parties, which may result from its use. No license is granted by * implication, estoppel or otherwise under any patent or other rights of the * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing * herein shall be construed as an obligation by the SD Group, the SD-3C LLC * or the SD Card Association to disclose or distribute any technical * information, know-how or other confidential information to any third party. * * $FreeBSD$ */ #ifndef DEV_MMC_MMCREG_H #define DEV_MMC_MMCREG_H /* * This file contains the register definitions for the mmc and sd buses. * They are taken from publicly available sources. */ struct mmc_data; struct mmc_request; struct mmc_command { uint32_t opcode; uint32_t arg; uint32_t resp[4]; uint32_t flags; /* Expected responses */ #define MMC_RSP_PRESENT (1ul << 0) /* Response */ #define MMC_RSP_136 (1ul << 1) /* 136 bit response */ #define MMC_RSP_CRC (1ul << 2) /* Expect valid crc */ #define MMC_RSP_BUSY (1ul << 3) /* Card may send busy */ #define MMC_RSP_OPCODE (1ul << 4) /* Response include opcode */ #define MMC_RSP_MASK 0x1ful #define MMC_CMD_AC (0ul << 5) /* Addressed Command, no data */ #define MMC_CMD_ADTC (1ul << 5) /* Addressed Data transfer cmd */ #define MMC_CMD_BC (2ul << 5) /* Broadcast command, no response */ #define MMC_CMD_BCR (3ul << 5) /* Broadcast command with response */ #define MMC_CMD_MASK (3ul << 5) /* Possible response types defined in the standard: */ #define MMC_RSP_NONE (0) #define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) #define MMC_RSP_R4 (MMC_RSP_PRESENT) #define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R5B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) #define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP(x) ((x) & MMC_RSP_MASK) uint32_t retries; uint32_t error; #define MMC_ERR_NONE 0 #define MMC_ERR_TIMEOUT 1 #define MMC_ERR_BADCRC 2 #define MMC_ERR_FIFO 3 #define MMC_ERR_FAILED 4 #define MMC_ERR_INVALID 5 #define MMC_ERR_NO_MEMORY 6 -#define MMC_ERR_MAX 6 +#define MMC_ERR_MAX 6 struct mmc_data *data; /* Data segment with cmd */ struct mmc_request *mrq; /* backpointer to request */ }; /* * R1 responses * * Types (per SD 2.0 standard) * e : error bit * s : status bit * r : detected and set for the actual command response * x : Detected and set during command execution. The host can get * the status by issuing a command with R1 response. * * Clear Condition (per SD 2.0 standard) * a : according to the card current state. * b : always related to the previous command. reception of a valid * command will clear it (with a delay of one command). * c : clear by read */ #define R1_OUT_OF_RANGE (1u << 31) /* erx, c */ #define R1_ADDRESS_ERROR (1u << 30) /* erx, c */ #define R1_BLOCK_LEN_ERROR (1u << 29) /* erx, c */ #define R1_ERASE_SEQ_ERROR (1u << 28) /* er, c */ #define R1_ERASE_PARAM (1u << 27) /* erx, c */ #define R1_WP_VIOLATION (1u << 26) /* erx, c */ #define R1_CARD_IS_LOCKED (1u << 25) /* sx, a */ #define R1_LOCK_UNLOCK_FAILED (1u << 24) /* erx, c */ #define R1_COM_CRC_ERROR (1u << 23) /* er, b */ #define R1_ILLEGAL_COMMAND (1u << 22) /* er, b */ #define R1_CARD_ECC_FAILED (1u << 21) /* erx, c */ #define R1_CC_ERROR (1u << 20) /* erx, c */ #define R1_ERROR (1u << 19) /* erx, c */ #define R1_CSD_OVERWRITE (1u << 16) /* erx, c */ #define R1_WP_ERASE_SKIP (1u << 15) /* erx, c */ #define R1_CARD_ECC_DISABLED (1u << 14) /* sx, a */ #define R1_ERASE_RESET (1u << 13) /* sr, c */ #define R1_CURRENT_STATE_MASK (0xfu << 9) /* sx, b */ #define R1_READY_FOR_DATA (1u << 8) /* sx, a */ #define R1_APP_CMD (1u << 5) /* sr, c */ #define R1_AKE_SEQ_ERROR (1u << 3) /* er, c */ #define R1_STATUS(x) ((x) & 0xFFFFE000) #define R1_CURRENT_STATE(x) (((x) & R1_CURRENT_STATE_MASK) >> 9) #define R1_STATE_IDLE 0 #define R1_STATE_READY 1 #define R1_STATE_IDENT 2 #define R1_STATE_STBY 3 #define R1_STATE_TRAN 4 #define R1_STATE_DATA 5 #define R1_STATE_RCV 6 #define R1_STATE_PRG 7 #define R1_STATE_DIS 8 struct mmc_data { size_t len; /* size of the data */ size_t xfer_len; void *data; /* data buffer */ uint32_t flags; #define MMC_DATA_WRITE (1UL << 0) #define MMC_DATA_READ (1UL << 1) #define MMC_DATA_STREAM (1UL << 2) #define MMC_DATA_MULTI (1UL << 3) struct mmc_request *mrq; }; struct mmc_request { struct mmc_command *cmd; struct mmc_command *stop; void (*done)(struct mmc_request *); /* Completion function */ void *done_data; /* requestor set data */ uint32_t flags; #define MMC_REQ_DONE 1 }; /* Command definitions */ /* Class 0 and 1: Basic commands & read stream commands */ #define MMC_GO_IDLE_STATE 0 #define MMC_SEND_OP_COND 1 #define MMC_ALL_SEND_CID 2 #define MMC_SET_RELATIVE_ADDR 3 #define SD_SEND_RELATIVE_ADDR 3 #define MMC_SET_DSR 4 /* reserved: 5 */ #define MMC_SWITCH_FUNC 6 #define MMC_SWITCH_FUNC_CMDS 0 #define MMC_SWITCH_FUNC_SET 1 #define MMC_SWITCH_FUNC_CLR 2 #define MMC_SWITCH_FUNC_WR 3 #define MMC_SELECT_CARD 7 #define MMC_DESELECT_CARD 7 #define MMC_SEND_EXT_CSD 8 #define SD_SEND_IF_COND 8 #define MMC_SEND_CSD 9 #define MMC_SEND_CID 10 #define MMC_READ_DAT_UNTIL_STOP 11 #define MMC_STOP_TRANSMISSION 12 #define MMC_SEND_STATUS 13 #define MMC_BUSTEST_R 14 #define MMC_GO_INACTIVE_STATE 15 #define MMC_BUSTEST_W 19 /* Class 2: Block oriented read commands */ #define MMC_SET_BLOCKLEN 16 #define MMC_READ_SINGLE_BLOCK 17 #define MMC_READ_MULTIPLE_BLOCK 18 /* reserved: 19 */ /* Class 3: Stream write commands */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* reserved: 21 */ /* reserved: 22 */ /* Class 4: Block oriented write commands */ #define MMC_SET_BLOCK_COUNT 23 #define MMC_WRITE_BLOCK 24 #define MMC_WRITE_MULTIPLE_BLOCK 25 #define MMC_PROGARM_CID 26 #define MMC_PROGRAM_CSD 27 /* Class 6: Block oriented write protection commands */ #define MMC_SET_WRITE_PROT 28 #define MMC_CLR_WRITE_PROT 29 #define MMC_SEND_WRITE_PROT 30 /* reserved: 31 */ /* Class 5: Erase commands */ #define SD_ERASE_WR_BLK_START 32 #define SD_ERASE_WR_BLK_END 33 /* 34 -- reserved old command */ #define MMC_ERASE_GROUP_START 35 #define MMC_ERASE_GROUP_END 36 /* 37 -- reserved old command */ #define MMC_ERASE 38 /* Class 9: I/O mode commands */ #define MMC_FAST_IO 39 #define MMC_GO_IRQ_STATE 40 /* reserved: 41 */ /* Class 7: Lock card */ #define MMC_LOCK_UNLOCK 42 /* reserved: 43 */ /* reserved: 44 */ /* reserved: 45 */ /* reserved: 46 */ /* reserved: 47 */ /* reserved: 48 */ /* reserved: 49 */ /* reserved: 50 */ /* reserved: 51 */ /* reserved: 54 */ /* Class 8: Application specific commands */ #define MMC_APP_CMD 55 #define MMC_GEN_CMD 56 /* reserved: 57 */ /* reserved: 58 */ /* reserved: 59 */ /* reserved for mfg: 60 */ /* reserved for mfg: 61 */ /* reserved for mfg: 62 */ /* reserved for mfg: 63 */ /* Class 9: I/O cards (sd) */ #define SD_IO_RW_DIRECT 52 #define SD_IO_RW_EXTENDED 53 /* Class 10: Switch function commands */ #define SD_SWITCH_FUNC 6 /* reserved: 34 */ /* reserved: 35 */ /* reserved: 36 */ /* reserved: 37 */ /* reserved: 50 */ /* reserved: 57 */ /* Application specific commands for SD */ #define ACMD_SET_BUS_WIDTH 6 #define ACMD_SD_STATUS 13 #define ACMD_SEND_NUM_WR_BLOCKS 22 #define ACMD_SET_WR_BLK_ERASE_COUNT 23 #define ACMD_SD_SEND_OP_COND 41 #define ACMD_SET_CLR_CARD_DETECT 42 #define ACMD_SEND_SCR 51 /* * EXT_CSD fields */ -#define EXT_CSD_ERASE_GRP_DEF 175 /* R/W */ -#define EXT_CSD_BUS_WIDTH 183 /* R/W */ -#define EXT_CSD_HS_TIMING 185 /* R/W */ -#define EXT_CSD_CARD_TYPE 196 /* RO */ -#define EXT_CSD_REV 192 /* RO */ -#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ -#define EXT_CSD_ERASE_TO_MULT 223 /* RO */ -#define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */ +#define EXT_CSD_ERASE_GRP_DEF 175 /* R/W */ +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define EXT_CSD_ERASE_TO_MULT 223 /* RO */ +#define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */ /* * EXT_CSD field definitions */ -#define EXT_CSD_CMD_SET_NORMAL 1 -#define EXT_CSD_CMD_SET_SECURE 2 -#define EXT_CSD_CMD_SET_CPSECURE 4 +#define EXT_CSD_CMD_SET_NORMAL 1 +#define EXT_CSD_CMD_SET_SECURE 2 +#define EXT_CSD_CMD_SET_CPSECURE 4 -#define EXT_CSD_CARD_TYPE_26 1 -#define EXT_CSD_CARD_TYPE_52 2 +#define EXT_CSD_CARD_TYPE_26 1 +#define EXT_CSD_CARD_TYPE_52 2 -#define EXT_CSD_BUS_WIDTH_1 0 -#define EXT_CSD_BUS_WIDTH_4 1 -#define EXT_CSD_BUS_WIDTH_8 2 +#define EXT_CSD_BUS_WIDTH_1 0 +#define EXT_CSD_BUS_WIDTH_4 1 +#define EXT_CSD_BUS_WIDTH_8 2 -#define MMC_TYPE_26_MAX_HS 26000000 -#define MMC_TYPE_52_MAX_HS 52000000 +#define MMC_TYPE_26_MAX_HS 26000000 +#define MMC_TYPE_52_MAX_HS 52000000 /* * SD bus widths */ -#define SD_BUS_WIDTH_1 0 -#define SD_BUS_WIDTH_4 2 +#define SD_BUS_WIDTH_1 0 +#define SD_BUS_WIDTH_4 2 /* * SD Switch */ -#define SD_SWITCH_MODE_CHECK 0 -#define SD_SWITCH_MODE_SET 1 -#define SD_SWITCH_GROUP1 0 -#define SD_SWITCH_NORMAL_MODE 0 -#define SD_SWITCH_HS_MODE 1 -#define SD_SWITCH_NOCHANGE 0xF +#define SD_SWITCH_MODE_CHECK 0 +#define SD_SWITCH_MODE_SET 1 +#define SD_SWITCH_GROUP1 0 +#define SD_SWITCH_NORMAL_MODE 0 +#define SD_SWITCH_HS_MODE 1 +#define SD_SWITCH_NOCHANGE 0xF #define SD_CLR_CARD_DETECT 0 #define SD_SET_CARD_DETECT 1 #define SD_MAX_HS 50000000 /* OCR bits */ /* * in SD 2.0 spec, bits 8-14 are now marked reserved * Low voltage in SD2.0 spec is bit 7, TBD voltage * Low voltage in MC 3.31 spec is bit 7, 1.65-1.95V * Specs prior to MMC 3.31 defined bits 0-7 as voltages down to 1.5V. * 3.31 redefined them to be reserved and also said that cards had to * support the 2.7-3.6V and fixed the OCR to be 0xfff8000 for high voltage * cards. MMC 4.0 says that a dual voltage card responds with 0xfff8080. * Looks like the fine-grained control of the voltage tolerance ranges * was abandoned. * * The MMC_OCR_CCS appears to be valid for only SD cards. */ #define MMC_OCR_VOLTAGE 0x3fffffffU /* Vdd Voltage mask */ #define MMC_OCR_LOW_VOLTAGE (1u << 7) /* Low Voltage Range -- tbd */ #define MMC_OCR_MIN_VOLTAGE_SHIFT 7 #define MMC_OCR_200_210 (1U << 8) /* Vdd voltage 2.00 ~ 2.10 */ #define MMC_OCR_210_220 (1U << 9) /* Vdd voltage 2.10 ~ 2.20 */ #define MMC_OCR_220_230 (1U << 10) /* Vdd voltage 2.20 ~ 2.30 */ #define MMC_OCR_230_240 (1U << 11) /* Vdd voltage 2.30 ~ 2.40 */ #define MMC_OCR_240_250 (1U << 12) /* Vdd voltage 2.40 ~ 2.50 */ #define MMC_OCR_250_260 (1U << 13) /* Vdd voltage 2.50 ~ 2.60 */ #define MMC_OCR_260_270 (1U << 14) /* Vdd voltage 2.60 ~ 2.70 */ #define MMC_OCR_270_280 (1U << 15) /* Vdd voltage 2.70 ~ 2.80 */ #define MMC_OCR_280_290 (1U << 16) /* Vdd voltage 2.80 ~ 2.90 */ #define MMC_OCR_290_300 (1U << 17) /* Vdd voltage 2.90 ~ 3.00 */ #define MMC_OCR_300_310 (1U << 18) /* Vdd voltage 3.00 ~ 3.10 */ #define MMC_OCR_310_320 (1U << 19) /* Vdd voltage 3.10 ~ 3.20 */ #define MMC_OCR_320_330 (1U << 20) /* Vdd voltage 3.20 ~ 3.30 */ #define MMC_OCR_330_340 (1U << 21) /* Vdd voltage 3.30 ~ 3.40 */ #define MMC_OCR_340_350 (1U << 22) /* Vdd voltage 3.40 ~ 3.50 */ #define MMC_OCR_350_360 (1U << 23) /* Vdd voltage 3.50 ~ 3.60 */ #define MMC_OCR_MAX_VOLTAGE_SHIFT 23 #define MMC_OCR_CCS (1u << 30) /* Card Capacity status (SD vs SDHC) */ #define MMC_OCR_CARD_BUSY (1U << 31) /* Card Power up status */ /* CSD -- decoded structure */ struct mmc_cid { uint32_t mid; char pnm[8]; uint32_t psn; uint16_t oid; uint16_t mdt_year; uint8_t mdt_month; uint8_t prv; uint8_t fwrev; }; struct mmc_csd { uint8_t csd_structure; uint8_t spec_vers; uint16_t ccc; uint16_t tacc; uint32_t nsac; uint32_t r2w_factor; uint32_t tran_speed; uint32_t read_bl_len; uint32_t write_bl_len; uint32_t vdd_r_curr_min; uint32_t vdd_r_curr_max; uint32_t vdd_w_curr_min; uint32_t vdd_w_curr_max; uint32_t wp_grp_size; uint32_t erase_sector; uint64_t capacity; unsigned int read_bl_partial:1, read_blk_misalign:1, write_bl_partial:1, write_blk_misalign:1, dsr_imp:1, erase_blk_en:1, wp_grp_enable:1; }; struct mmc_scr { unsigned char sda_vsn; unsigned char bus_widths; -#define SD_SCR_BUS_WIDTH_1 (1<<0) -#define SD_SCR_BUS_WIDTH_4 (1<<2) +#define SD_SCR_BUS_WIDTH_1 (1 << 0) +#define SD_SCR_BUS_WIDTH_4 (1 << 2) }; struct mmc_sd_status { uint8_t bus_width; uint8_t secured_mode; uint16_t card_type; uint16_t prot_area; uint8_t speed_class; uint8_t perf_move; uint8_t au_size; uint16_t erase_size; uint8_t erase_timeout; uint8_t erase_offset; }; /* * Older versions of the MMC standard had a variable sector size. However, * I've been able to find no old MMC or SD cards that have a non 512 * byte sector size anywhere, so we assume that such cards are very rare * and only note their existence in passing here... */ -#define MMC_SECTOR_SIZE 512 +#define MMC_SECTOR_SIZE 512 #endif /* DEV_MMCREG_H */ Index: projects/ipsec/sys/dev/sdhci/sdhci.c =================================================================== --- projects/ipsec/sys/dev/sdhci/sdhci.c (revision 313312) +++ projects/ipsec/sys/dev/sdhci/sdhci.c (revision 313313) @@ -1,1594 +1,1602 @@ /*- * Copyright (c) 2008 Alexander Motin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mmcbr_if.h" #include "sdhci.h" #include "sdhci_if.h" SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver"); static int sdhci_debug; -SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0, "Debug level"); +SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0, + "Debug level"); -#define RD1(slot, off) SDHCI_READ_1((slot)->bus, (slot), (off)) -#define RD2(slot, off) SDHCI_READ_2((slot)->bus, (slot), (off)) -#define RD4(slot, off) SDHCI_READ_4((slot)->bus, (slot), (off)) -#define RD_MULTI_4(slot, off, ptr, count) \ +#define RD1(slot, off) SDHCI_READ_1((slot)->bus, (slot), (off)) +#define RD2(slot, off) SDHCI_READ_2((slot)->bus, (slot), (off)) +#define RD4(slot, off) SDHCI_READ_4((slot)->bus, (slot), (off)) +#define RD_MULTI_4(slot, off, ptr, count) \ SDHCI_READ_MULTI_4((slot)->bus, (slot), (off), (ptr), (count)) -#define WR1(slot, off, val) SDHCI_WRITE_1((slot)->bus, (slot), (off), (val)) -#define WR2(slot, off, val) SDHCI_WRITE_2((slot)->bus, (slot), (off), (val)) -#define WR4(slot, off, val) SDHCI_WRITE_4((slot)->bus, (slot), (off), (val)) -#define WR_MULTI_4(slot, off, ptr, count) \ +#define WR1(slot, off, val) SDHCI_WRITE_1((slot)->bus, (slot), (off), (val)) +#define WR2(slot, off, val) SDHCI_WRITE_2((slot)->bus, (slot), (off), (val)) +#define WR4(slot, off, val) SDHCI_WRITE_4((slot)->bus, (slot), (off), (val)) +#define WR_MULTI_4(slot, off, ptr, count) \ SDHCI_WRITE_MULTI_4((slot)->bus, (slot), (off), (ptr), (count)) static void sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock); static void sdhci_start(struct sdhci_slot *slot); static void sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data); static void sdhci_card_poll(void *); static void sdhci_card_task(void *, int); /* helper routines */ -#define SDHCI_LOCK(_slot) mtx_lock(&(_slot)->mtx) +#define SDHCI_LOCK(_slot) mtx_lock(&(_slot)->mtx) #define SDHCI_UNLOCK(_slot) mtx_unlock(&(_slot)->mtx) -#define SDHCI_LOCK_INIT(_slot) \ +#define SDHCI_LOCK_INIT(_slot) \ mtx_init(&_slot->mtx, "SD slot mtx", "sdhci", MTX_DEF) -#define SDHCI_LOCK_DESTROY(_slot) mtx_destroy(&_slot->mtx); -#define SDHCI_ASSERT_LOCKED(_slot) mtx_assert(&_slot->mtx, MA_OWNED); -#define SDHCI_ASSERT_UNLOCKED(_slot) mtx_assert(&_slot->mtx, MA_NOTOWNED); +#define SDHCI_LOCK_DESTROY(_slot) mtx_destroy(&_slot->mtx); +#define SDHCI_ASSERT_LOCKED(_slot) mtx_assert(&_slot->mtx, MA_OWNED); +#define SDHCI_ASSERT_UNLOCKED(_slot) mtx_assert(&_slot->mtx, MA_NOTOWNED); #define SDHCI_DEFAULT_MAX_FREQ 50 #define SDHCI_200_MAX_DIVIDER 256 #define SDHCI_300_MAX_DIVIDER 2046 #define SDHCI_CARD_PRESENT_TICKS (hz / 5) #define SDHCI_INSERT_DELAY_TICKS (hz / 2) /* * Broadcom BCM577xx Controller Constants */ /* Maximum divider supported by the default clock source. */ -#define BCM577XX_DEFAULT_MAX_DIVIDER 256 +#define BCM577XX_DEFAULT_MAX_DIVIDER 256 /* Alternative clock's base frequency. */ -#define BCM577XX_ALT_CLOCK_BASE 63000000 +#define BCM577XX_ALT_CLOCK_BASE 63000000 -#define BCM577XX_HOST_CONTROL 0x198 -#define BCM577XX_CTRL_CLKSEL_MASK 0xFFFFCFFF -#define BCM577XX_CTRL_CLKSEL_SHIFT 12 -#define BCM577XX_CTRL_CLKSEL_DEFAULT 0x0 -#define BCM577XX_CTRL_CLKSEL_64MHZ 0x3 +#define BCM577XX_HOST_CONTROL 0x198 +#define BCM577XX_CTRL_CLKSEL_MASK 0xFFFFCFFF +#define BCM577XX_CTRL_CLKSEL_SHIFT 12 +#define BCM577XX_CTRL_CLKSEL_DEFAULT 0x0 +#define BCM577XX_CTRL_CLKSEL_64MHZ 0x3 - static void sdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { + if (error != 0) { printf("getaddr: error %d\n", error); return; } *(bus_addr_t *)arg = segs[0].ds_addr; } static int slot_printf(struct sdhci_slot *slot, const char * fmt, ...) { va_list ap; int retval; retval = printf("%s-slot%d: ", device_get_nameunit(slot->bus), slot->num); va_start(ap, fmt); retval += vprintf(fmt, ap); va_end(ap); return (retval); } static void sdhci_dumpregs(struct sdhci_slot *slot) { + slot_printf(slot, "============== REGISTER DUMP ==============\n"); slot_printf(slot, "Sys addr: 0x%08x | Version: 0x%08x\n", RD4(slot, SDHCI_DMA_ADDRESS), RD2(slot, SDHCI_HOST_VERSION)); slot_printf(slot, "Blk size: 0x%08x | Blk cnt: 0x%08x\n", RD2(slot, SDHCI_BLOCK_SIZE), RD2(slot, SDHCI_BLOCK_COUNT)); slot_printf(slot, "Argument: 0x%08x | Trn mode: 0x%08x\n", RD4(slot, SDHCI_ARGUMENT), RD2(slot, SDHCI_TRANSFER_MODE)); slot_printf(slot, "Present: 0x%08x | Host ctl: 0x%08x\n", RD4(slot, SDHCI_PRESENT_STATE), RD1(slot, SDHCI_HOST_CONTROL)); slot_printf(slot, "Power: 0x%08x | Blk gap: 0x%08x\n", RD1(slot, SDHCI_POWER_CONTROL), RD1(slot, SDHCI_BLOCK_GAP_CONTROL)); slot_printf(slot, "Wake-up: 0x%08x | Clock: 0x%08x\n", RD1(slot, SDHCI_WAKE_UP_CONTROL), RD2(slot, SDHCI_CLOCK_CONTROL)); slot_printf(slot, "Timeout: 0x%08x | Int stat: 0x%08x\n", RD1(slot, SDHCI_TIMEOUT_CONTROL), RD4(slot, SDHCI_INT_STATUS)); slot_printf(slot, "Int enab: 0x%08x | Sig enab: 0x%08x\n", RD4(slot, SDHCI_INT_ENABLE), RD4(slot, SDHCI_SIGNAL_ENABLE)); slot_printf(slot, "AC12 err: 0x%08x | Slot int: 0x%08x\n", RD2(slot, SDHCI_ACMD12_ERR), RD2(slot, SDHCI_SLOT_INT_STATUS)); slot_printf(slot, "Caps: 0x%08x | Max curr: 0x%08x\n", RD4(slot, SDHCI_CAPABILITIES), RD4(slot, SDHCI_MAX_CURRENT)); slot_printf(slot, "===========================================\n"); } static void sdhci_reset(struct sdhci_slot *slot, uint8_t mask) { int timeout; if (slot->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { if (!SDHCI_GET_CARD_PRESENT(slot->bus, slot)) return; } /* Some controllers need this kick or reset won't work. */ if ((mask & SDHCI_RESET_ALL) == 0 && (slot->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)) { uint32_t clock; /* This is to force an update */ clock = slot->clock; slot->clock = 0; sdhci_set_clock(slot, clock); } if (mask & SDHCI_RESET_ALL) { slot->clock = 0; slot->power = 0; } WR1(slot, SDHCI_SOFTWARE_RESET, mask); if (slot->quirks & SDHCI_QUIRK_WAITFOR_RESET_ASSERTED) { /* * Resets on TI OMAPs and AM335x are incompatible with SDHCI * specification. The reset bit has internal propagation delay, * so a fast read after write returns 0 even if reset process is * in progress. The workaround is to poll for 1 before polling * for 0. In the worst case, if we miss seeing it asserted the * time we spent waiting is enough to ensure the reset finishes. */ timeout = 10000; while ((RD1(slot, SDHCI_SOFTWARE_RESET) & mask) != mask) { if (timeout <= 0) break; timeout--; DELAY(1); } } /* Wait max 100 ms */ timeout = 10000; /* Controller clears the bits when it's done */ while (RD1(slot, SDHCI_SOFTWARE_RESET) & mask) { if (timeout <= 0) { slot_printf(slot, "Reset 0x%x never completed.\n", mask); sdhci_dumpregs(slot); return; } timeout--; DELAY(10); } } static void sdhci_init(struct sdhci_slot *slot) { sdhci_reset(slot, SDHCI_RESET_ALL); /* Enable interrupts. */ slot->intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE | SDHCI_INT_ACMD12ERR; if (!(slot->quirks & SDHCI_QUIRK_POLL_CARD_PRESENT) && !(slot->opt & SDHCI_NON_REMOVABLE)) { slot->intmask |= SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT; } WR4(slot, SDHCI_INT_ENABLE, slot->intmask); WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); } static void sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock) { uint32_t clk_base; uint32_t clk_sel; uint32_t res; uint16_t clk; uint16_t div; int timeout; if (clock == slot->clock) return; slot->clock = clock; /* Turn off the clock. */ clk = RD2(slot, SDHCI_CLOCK_CONTROL); WR2(slot, SDHCI_CLOCK_CONTROL, clk & ~SDHCI_CLOCK_CARD_EN); /* If no clock requested - left it so. */ if (clock == 0) return; /* Determine the clock base frequency */ clk_base = slot->max_clk; if (slot->quirks & SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC) { clk_sel = RD2(slot, BCM577XX_HOST_CONTROL) & BCM577XX_CTRL_CLKSEL_MASK; /* * Select clock source appropriate for the requested frequency. */ if ((clk_base / BCM577XX_DEFAULT_MAX_DIVIDER) > clock) { clk_base = BCM577XX_ALT_CLOCK_BASE; clk_sel |= (BCM577XX_CTRL_CLKSEL_64MHZ << BCM577XX_CTRL_CLKSEL_SHIFT); } else { clk_sel |= (BCM577XX_CTRL_CLKSEL_DEFAULT << BCM577XX_CTRL_CLKSEL_SHIFT); } WR2(slot, BCM577XX_HOST_CONTROL, clk_sel); } /* Recalculate timeout clock frequency based on the new sd clock. */ if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) slot->timeout_clk = slot->clock / 1000; if (slot->version < SDHCI_SPEC_300) { /* Looking for highest freq <= clock. */ res = clk_base; for (div = 1; div < SDHCI_200_MAX_DIVIDER; div <<= 1) { if (res <= clock) break; res >>= 1; } /* Divider 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ... */ div >>= 1; } else { /* Version 3.0 divisors are multiples of two up to 1023*2 */ if (clock >= clk_base) div = 0; else { for (div = 2; div < SDHCI_300_MAX_DIVIDER; div += 2) { if ((clk_base / div) <= clock) break; } } div >>= 1; } if (bootverbose || sdhci_debug) slot_printf(slot, "Divider %d for freq %d (base %d)\n", div, clock, clk_base); /* Now we have got divider, set it. */ clk = (div & SDHCI_DIVIDER_MASK) << SDHCI_DIVIDER_SHIFT; clk |= ((div >> SDHCI_DIVIDER_MASK_LEN) & SDHCI_DIVIDER_HI_MASK) << SDHCI_DIVIDER_HI_SHIFT; WR2(slot, SDHCI_CLOCK_CONTROL, clk); /* Enable clock. */ clk |= SDHCI_CLOCK_INT_EN; WR2(slot, SDHCI_CLOCK_CONTROL, clk); /* Wait up to 10 ms until it stabilize. */ timeout = 10; while (!((clk = RD2(slot, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { slot_printf(slot, "Internal clock never stabilised.\n"); sdhci_dumpregs(slot); return; } timeout--; DELAY(1000); } /* Pass clock signal to the bus. */ clk |= SDHCI_CLOCK_CARD_EN; WR2(slot, SDHCI_CLOCK_CONTROL, clk); } static void sdhci_set_power(struct sdhci_slot *slot, u_char power) { uint8_t pwr; if (slot->power == power) return; slot->power = power; /* Turn off the power. */ pwr = 0; WR1(slot, SDHCI_POWER_CONTROL, pwr); /* If power down requested - left it so. */ if (power == 0) return; /* Set voltage. */ switch (1 << power) { case MMC_OCR_LOW_VOLTAGE: pwr |= SDHCI_POWER_180; break; case MMC_OCR_290_300: case MMC_OCR_300_310: pwr |= SDHCI_POWER_300; break; case MMC_OCR_320_330: case MMC_OCR_330_340: pwr |= SDHCI_POWER_330; break; } WR1(slot, SDHCI_POWER_CONTROL, pwr); /* Turn on the power. */ pwr |= SDHCI_POWER_ON; WR1(slot, SDHCI_POWER_CONTROL, pwr); if (slot->quirks & SDHCI_QUIRK_INTEL_POWER_UP_RESET) { WR1(slot, SDHCI_POWER_CONTROL, pwr | 0x10); DELAY(10); WR1(slot, SDHCI_POWER_CONTROL, pwr); DELAY(300); } } static void sdhci_read_block_pio(struct sdhci_slot *slot) { uint32_t data; char *buffer; size_t left; buffer = slot->curcmd->data->data; buffer += slot->offset; /* Transfer one block at a time. */ left = min(512, slot->curcmd->data->len - slot->offset); slot->offset += left; /* If we are too fast, broken controllers return zeroes. */ if (slot->quirks & SDHCI_QUIRK_BROKEN_TIMINGS) DELAY(10); /* Handle unaligned and aligned buffer cases. */ if ((intptr_t)buffer & 3) { while (left > 3) { data = RD4(slot, SDHCI_BUFFER); buffer[0] = data; buffer[1] = (data >> 8); buffer[2] = (data >> 16); buffer[3] = (data >> 24); buffer += 4; left -= 4; } } else { RD_MULTI_4(slot, SDHCI_BUFFER, (uint32_t *)buffer, left >> 2); left &= 3; } /* Handle uneven size case. */ if (left > 0) { data = RD4(slot, SDHCI_BUFFER); while (left > 0) { *(buffer++) = data; data >>= 8; left--; } } } static void sdhci_write_block_pio(struct sdhci_slot *slot) { uint32_t data = 0; char *buffer; size_t left; buffer = slot->curcmd->data->data; buffer += slot->offset; /* Transfer one block at a time. */ left = min(512, slot->curcmd->data->len - slot->offset); slot->offset += left; /* Handle unaligned and aligned buffer cases. */ if ((intptr_t)buffer & 3) { while (left > 3) { data = buffer[0] + (buffer[1] << 8) + (buffer[2] << 16) + (buffer[3] << 24); left -= 4; buffer += 4; WR4(slot, SDHCI_BUFFER, data); } } else { WR_MULTI_4(slot, SDHCI_BUFFER, (uint32_t *)buffer, left >> 2); left &= 3; } /* Handle uneven size case. */ if (left > 0) { while (left > 0) { data <<= 8; data += *(buffer++); left--; } WR4(slot, SDHCI_BUFFER, data); } } static void sdhci_transfer_pio(struct sdhci_slot *slot) { /* Read as many blocks as possible. */ if (slot->curcmd->data->flags & MMC_DATA_READ) { while (RD4(slot, SDHCI_PRESENT_STATE) & SDHCI_DATA_AVAILABLE) { sdhci_read_block_pio(slot); if (slot->offset >= slot->curcmd->data->len) break; } } else { while (RD4(slot, SDHCI_PRESENT_STATE) & SDHCI_SPACE_AVAILABLE) { sdhci_write_block_pio(slot); if (slot->offset >= slot->curcmd->data->len) break; } } } static void -sdhci_card_task(void *arg, int pending) +sdhci_card_task(void *arg, int pending __unused) { struct sdhci_slot *slot = arg; + device_t d; SDHCI_LOCK(slot); if (SDHCI_GET_CARD_PRESENT(slot->bus, slot)) { if (slot->dev == NULL) { /* If card is present - attach mmc bus. */ if (bootverbose || sdhci_debug) slot_printf(slot, "Card inserted\n"); slot->dev = device_add_child(slot->bus, "mmc", -1); device_set_ivars(slot->dev, slot); SDHCI_UNLOCK(slot); device_probe_and_attach(slot->dev); } else SDHCI_UNLOCK(slot); } else { if (slot->dev != NULL) { /* If no card present - detach mmc bus. */ if (bootverbose || sdhci_debug) slot_printf(slot, "Card removed\n"); - device_t d = slot->dev; + d = slot->dev; slot->dev = NULL; SDHCI_UNLOCK(slot); device_delete_child(slot->bus, d); } else SDHCI_UNLOCK(slot); } } static void sdhci_handle_card_present_locked(struct sdhci_slot *slot, bool is_present) { bool was_present; /* * If there was no card and now there is one, schedule the task to * create the child device after a short delay. The delay is to * debounce the card insert (sometimes the card detect pin stabilizes * before the other pins have made good contact). * * If there was a card present and now it's gone, immediately schedule * the task to delete the child device. No debouncing -- gone is gone, * because once power is removed, a full card re-init is needed, and * that happens by deleting and recreating the child device. */ was_present = slot->dev != NULL; if (!was_present && is_present) { taskqueue_enqueue_timeout(taskqueue_swi_giant, &slot->card_delayed_task, -SDHCI_INSERT_DELAY_TICKS); } else if (was_present && !is_present) { taskqueue_enqueue(taskqueue_swi_giant, &slot->card_task); } } void sdhci_handle_card_present(struct sdhci_slot *slot, bool is_present) { SDHCI_LOCK(slot); sdhci_handle_card_present_locked(slot, is_present); SDHCI_UNLOCK(slot); } static void sdhci_card_poll(void *arg) { struct sdhci_slot *slot = arg; sdhci_handle_card_present(slot, SDHCI_GET_CARD_PRESENT(slot->bus, slot)); callout_reset(&slot->card_poll_callout, SDHCI_CARD_PRESENT_TICKS, sdhci_card_poll, slot); } int sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) { uint32_t caps, freq; int err; SDHCI_LOCK_INIT(slot); slot->num = num; slot->bus = dev; /* Allocate DMA tag. */ err = bus_dma_tag_create(bus_get_dma_tag(dev), DMA_BLOCK_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, DMA_BLOCK_SIZE, 1, DMA_BLOCK_SIZE, BUS_DMA_ALLOCNOW, NULL, NULL, &slot->dmatag); if (err != 0) { device_printf(dev, "Can't create DMA tag\n"); SDHCI_LOCK_DESTROY(slot); return (err); } /* Allocate DMA memory. */ err = bus_dmamem_alloc(slot->dmatag, (void **)&slot->dmamem, BUS_DMA_NOWAIT, &slot->dmamap); if (err != 0) { device_printf(dev, "Can't alloc DMA memory\n"); SDHCI_LOCK_DESTROY(slot); return (err); } /* Map the memory. */ err = bus_dmamap_load(slot->dmatag, slot->dmamap, (void *)slot->dmamem, DMA_BLOCK_SIZE, sdhci_getaddr, &slot->paddr, 0); if (err != 0 || slot->paddr == 0) { device_printf(dev, "Can't load DMA memory\n"); SDHCI_LOCK_DESTROY(slot); if(err) return (err); else return (EFAULT); } /* Initialize slot. */ sdhci_init(slot); slot->version = (RD2(slot, SDHCI_HOST_VERSION) >> SDHCI_SPEC_VER_SHIFT) & SDHCI_SPEC_VER_MASK; if (slot->quirks & SDHCI_QUIRK_MISSING_CAPS) caps = slot->caps; else caps = RD4(slot, SDHCI_CAPABILITIES); /* Calculate base clock frequency. */ if (slot->version >= SDHCI_SPEC_300) freq = (caps & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; else freq = (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; if (freq != 0) slot->max_clk = freq * 1000000; /* * If the frequency wasn't in the capabilities and the hardware driver * hasn't already set max_clk we're probably not going to work right * with an assumption, so complain about it. */ if (slot->max_clk == 0) { slot->max_clk = SDHCI_DEFAULT_MAX_FREQ * 1000000; device_printf(dev, "Hardware doesn't specify base clock " "frequency, using %dMHz as default.\n", SDHCI_DEFAULT_MAX_FREQ); } /* Calculate/set timeout clock frequency. */ if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) { slot->timeout_clk = slot->max_clk / 1000; } else if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_1MHZ) { slot->timeout_clk = 1000; } else { slot->timeout_clk = (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; if (caps & SDHCI_TIMEOUT_CLK_UNIT) slot->timeout_clk *= 1000; } /* * If the frequency wasn't in the capabilities and the hardware driver * hasn't already set timeout_clk we'll probably work okay using the * max timeout, but still mention it. */ if (slot->timeout_clk == 0) { device_printf(dev, "Hardware doesn't specify timeout clock " "frequency, setting BROKEN_TIMEOUT quirk.\n"); slot->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; } slot->host.f_min = SDHCI_MIN_FREQ(slot->bus, slot); slot->host.f_max = slot->max_clk; slot->host.host_ocr = 0; if (caps & SDHCI_CAN_VDD_330) slot->host.host_ocr |= MMC_OCR_320_330 | MMC_OCR_330_340; if (caps & SDHCI_CAN_VDD_300) slot->host.host_ocr |= MMC_OCR_290_300 | MMC_OCR_300_310; if (caps & SDHCI_CAN_VDD_180) slot->host.host_ocr |= MMC_OCR_LOW_VOLTAGE; if (slot->host.host_ocr == 0) { device_printf(dev, "Hardware doesn't report any " "support voltages.\n"); } slot->host.caps = MMC_CAP_4_BIT_DATA; if (caps & SDHCI_CAN_DO_8BITBUS) slot->host.caps |= MMC_CAP_8_BIT_DATA; if (caps & SDHCI_CAN_DO_HISPD) slot->host.caps |= MMC_CAP_HSPEED; /* Decide if we have usable DMA. */ if (caps & SDHCI_CAN_DO_DMA) slot->opt |= SDHCI_HAVE_DMA; if (slot->quirks & SDHCI_QUIRK_BROKEN_DMA) slot->opt &= ~SDHCI_HAVE_DMA; if (slot->quirks & SDHCI_QUIRK_FORCE_DMA) slot->opt |= SDHCI_HAVE_DMA; if (slot->quirks & SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE) slot->opt |= SDHCI_NON_REMOVABLE; /* * Use platform-provided transfer backend * with PIO as a fallback mechanism */ if (slot->opt & SDHCI_PLATFORM_TRANSFER) slot->opt &= ~SDHCI_HAVE_DMA; if (bootverbose || sdhci_debug) { slot_printf(slot, "%uMHz%s %s%s%s%s %s\n", slot->max_clk / 1000000, (caps & SDHCI_CAN_DO_HISPD) ? " HS" : "", (slot->host.caps & MMC_CAP_8_BIT_DATA) ? "8bits" : ((slot->host.caps & MMC_CAP_4_BIT_DATA) ? "4bits" : "1bit"), (caps & SDHCI_CAN_VDD_330) ? " 3.3V" : "", (caps & SDHCI_CAN_VDD_300) ? " 3.0V" : "", (caps & SDHCI_CAN_VDD_180) ? " 1.8V" : "", (slot->opt & SDHCI_HAVE_DMA) ? "DMA" : "PIO"); sdhci_dumpregs(slot); } slot->timeout = 10; SYSCTL_ADD_INT(device_get_sysctl_ctx(slot->bus), SYSCTL_CHILDREN(device_get_sysctl_tree(slot->bus)), OID_AUTO, "timeout", CTLFLAG_RW, &slot->timeout, 0, "Maximum timeout for SDHCI transfers (in secs)"); TASK_INIT(&slot->card_task, 0, sdhci_card_task, slot); TIMEOUT_TASK_INIT(taskqueue_swi_giant, &slot->card_delayed_task, 0, sdhci_card_task, slot); callout_init(&slot->card_poll_callout, 1); callout_init_mtx(&slot->timeout_callout, &slot->mtx, 0); if ((slot->quirks & SDHCI_QUIRK_POLL_CARD_PRESENT) && !(slot->opt & SDHCI_NON_REMOVABLE)) { callout_reset(&slot->card_poll_callout, SDHCI_CARD_PRESENT_TICKS, sdhci_card_poll, slot); } return (0); } void sdhci_start_slot(struct sdhci_slot *slot) { + sdhci_card_task(slot, 0); } int sdhci_cleanup_slot(struct sdhci_slot *slot) { device_t d; callout_drain(&slot->timeout_callout); callout_drain(&slot->card_poll_callout); taskqueue_drain(taskqueue_swi_giant, &slot->card_task); taskqueue_drain_timeout(taskqueue_swi_giant, &slot->card_delayed_task); SDHCI_LOCK(slot); d = slot->dev; slot->dev = NULL; SDHCI_UNLOCK(slot); if (d != NULL) device_delete_child(slot->bus, d); SDHCI_LOCK(slot); sdhci_reset(slot, SDHCI_RESET_ALL); SDHCI_UNLOCK(slot); bus_dmamap_unload(slot->dmatag, slot->dmamap); bus_dmamem_free(slot->dmatag, slot->dmamem, slot->dmamap); bus_dma_tag_destroy(slot->dmatag); SDHCI_LOCK_DESTROY(slot); return (0); } int sdhci_generic_suspend(struct sdhci_slot *slot) { + sdhci_reset(slot, SDHCI_RESET_ALL); return (0); } int sdhci_generic_resume(struct sdhci_slot *slot) { + sdhci_init(slot); return (0); } uint32_t sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot) { + if (slot->version >= SDHCI_SPEC_300) return (slot->max_clk / SDHCI_300_MAX_DIVIDER); else return (slot->max_clk / SDHCI_200_MAX_DIVIDER); } bool sdhci_generic_get_card_present(device_t brdev, struct sdhci_slot *slot) { if (slot->opt & SDHCI_NON_REMOVABLE) return true; return (RD4(slot, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); } int sdhci_generic_update_ios(device_t brdev, device_t reqdev) { struct sdhci_slot *slot = device_get_ivars(reqdev); struct mmc_ios *ios = &slot->host.ios; SDHCI_LOCK(slot); /* Do full reset on bus power down to clear from any state. */ if (ios->power_mode == power_off) { WR4(slot, SDHCI_SIGNAL_ENABLE, 0); sdhci_init(slot); } /* Configure the bus. */ sdhci_set_clock(slot, ios->clock); sdhci_set_power(slot, (ios->power_mode == power_off) ? 0 : ios->vdd); if (ios->bus_width == bus_width_8) { slot->hostctrl |= SDHCI_CTRL_8BITBUS; slot->hostctrl &= ~SDHCI_CTRL_4BITBUS; } else if (ios->bus_width == bus_width_4) { slot->hostctrl &= ~SDHCI_CTRL_8BITBUS; slot->hostctrl |= SDHCI_CTRL_4BITBUS; } else if (ios->bus_width == bus_width_1) { slot->hostctrl &= ~SDHCI_CTRL_8BITBUS; slot->hostctrl &= ~SDHCI_CTRL_4BITBUS; } else { panic("Invalid bus width: %d", ios->bus_width); } if (ios->timing == bus_timing_hs && !(slot->quirks & SDHCI_QUIRK_DONT_SET_HISPD_BIT)) slot->hostctrl |= SDHCI_CTRL_HISPD; else slot->hostctrl &= ~SDHCI_CTRL_HISPD; WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl); /* Some controllers like reset after bus changes. */ if(slot->quirks & SDHCI_QUIRK_RESET_ON_IOS) sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA); SDHCI_UNLOCK(slot); return (0); } static void sdhci_req_done(struct sdhci_slot *slot) { struct mmc_request *req; if (slot->req != NULL && slot->curcmd != NULL) { callout_stop(&slot->timeout_callout); req = slot->req; slot->req = NULL; slot->curcmd = NULL; req->done(req); } } static void sdhci_timeout(void *arg) { struct sdhci_slot *slot = arg; if (slot->curcmd != NULL) { slot_printf(slot, " Controller timeout\n"); sdhci_dumpregs(slot); - sdhci_reset(slot, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA); slot->curcmd->error = MMC_ERR_TIMEOUT; sdhci_req_done(slot); } else { slot_printf(slot, " Spurious timeout - no active command\n"); } } static void sdhci_set_transfer_mode(struct sdhci_slot *slot, struct mmc_data *data) { uint16_t mode; if (data == NULL) return; mode = SDHCI_TRNS_BLK_CNT_EN; if (data->len > 512) mode |= SDHCI_TRNS_MULTI; if (data->flags & MMC_DATA_READ) mode |= SDHCI_TRNS_READ; if (slot->req->stop) mode |= SDHCI_TRNS_ACMD12; if (slot->flags & SDHCI_USE_DMA) mode |= SDHCI_TRNS_DMA; WR2(slot, SDHCI_TRANSFER_MODE, mode); } static void sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd) { int flags, timeout; uint32_t mask; slot->curcmd = cmd; slot->cmd_done = 0; cmd->error = MMC_ERR_NONE; /* This flags combination is not supported by controller. */ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { slot_printf(slot, "Unsupported response type!\n"); cmd->error = MMC_ERR_FAILED; sdhci_req_done(slot); return; } /* Do not issue command if there is no card, clock or power. * Controller will not detect timeout without clock active. */ if (!SDHCI_GET_CARD_PRESENT(slot->bus, slot) || slot->power == 0 || slot->clock == 0) { cmd->error = MMC_ERR_FAILED; sdhci_req_done(slot); return; } /* Always wait for free CMD bus. */ mask = SDHCI_CMD_INHIBIT; /* Wait for free DAT if we have data or busy signal. */ if (cmd->data || (cmd->flags & MMC_RSP_BUSY)) mask |= SDHCI_DAT_INHIBIT; /* We shouldn't wait for DAT for stop commands. */ if (cmd == slot->req->stop) mask &= ~SDHCI_DAT_INHIBIT; /* * Wait for bus no more then 250 ms. Typically there will be no wait * here at all, but when writing a crash dump we may be bypassing the * host platform's interrupt handler, and in some cases that handler * may be working around hardware quirks such as not respecting r1b * busy indications. In those cases, this wait-loop serves the purpose * of waiting for the prior command and data transfers to be done, and * SD cards are allowed to take up to 250ms for write and erase ops. * (It's usually more like 20-30ms in the real world.) */ timeout = 250; while (mask & RD4(slot, SDHCI_PRESENT_STATE)) { if (timeout == 0) { slot_printf(slot, "Controller never released " "inhibit bit(s).\n"); sdhci_dumpregs(slot); cmd->error = MMC_ERR_FAILED; sdhci_req_done(slot); return; } timeout--; DELAY(1000); } /* Prepare command flags. */ if (!(cmd->flags & MMC_RSP_PRESENT)) flags = SDHCI_CMD_RESP_NONE; else if (cmd->flags & MMC_RSP_136) flags = SDHCI_CMD_RESP_LONG; else if (cmd->flags & MMC_RSP_BUSY) flags = SDHCI_CMD_RESP_SHORT_BUSY; else flags = SDHCI_CMD_RESP_SHORT; if (cmd->flags & MMC_RSP_CRC) flags |= SDHCI_CMD_CRC; if (cmd->flags & MMC_RSP_OPCODE) flags |= SDHCI_CMD_INDEX; if (cmd->data) flags |= SDHCI_CMD_DATA; if (cmd->opcode == MMC_STOP_TRANSMISSION) flags |= SDHCI_CMD_TYPE_ABORT; /* Prepare data. */ sdhci_start_data(slot, cmd->data); /* * Interrupt aggregation: To reduce total number of interrupts * group response interrupt with data interrupt when possible. * If there going to be data interrupt, mask response one. */ if (slot->data_done == 0) { WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask &= ~SDHCI_INT_RESPONSE); } /* Set command argument. */ WR4(slot, SDHCI_ARGUMENT, cmd->arg); /* Set data transfer mode. */ sdhci_set_transfer_mode(slot, cmd->data); /* Start command. */ WR2(slot, SDHCI_COMMAND_FLAGS, (cmd->opcode << 8) | (flags & 0xff)); /* Start timeout callout. */ callout_reset(&slot->timeout_callout, slot->timeout * hz, sdhci_timeout, slot); } static void sdhci_finish_command(struct sdhci_slot *slot) { int i; uint32_t val; uint8_t extra; slot->cmd_done = 1; /* Interrupt aggregation: Restore command interrupt. * Main restore point for the case when command interrupt * happened first. */ WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask |= SDHCI_INT_RESPONSE); /* In case of error - reset host and return. */ if (slot->curcmd->error) { sdhci_reset(slot, SDHCI_RESET_CMD); sdhci_reset(slot, SDHCI_RESET_DATA); sdhci_start(slot); return; } /* If command has response - fetch it. */ if (slot->curcmd->flags & MMC_RSP_PRESENT) { if (slot->curcmd->flags & MMC_RSP_136) { /* CRC is stripped so we need one byte shift. */ extra = 0; for (i = 0; i < 4; i++) { val = RD4(slot, SDHCI_RESPONSE + i * 4); if (slot->quirks & SDHCI_QUIRK_DONT_SHIFT_RESPONSE) slot->curcmd->resp[3 - i] = val; else { slot->curcmd->resp[3 - i] = (val << 8) | extra; extra = val >> 24; } } } else slot->curcmd->resp[0] = RD4(slot, SDHCI_RESPONSE); } /* If data ready - finish. */ if (slot->data_done) sdhci_start(slot); } static void sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data) { uint32_t target_timeout, current_timeout; uint8_t div; if (data == NULL && (slot->curcmd->flags & MMC_RSP_BUSY) == 0) { slot->data_done = 1; return; } slot->data_done = 0; /* Calculate and set data timeout.*/ /* XXX: We should have this from mmc layer, now assume 1 sec. */ if (slot->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) { div = 0xE; } else { target_timeout = 1000000; div = 0; current_timeout = (1 << 13) * 1000 / slot->timeout_clk; while (current_timeout < target_timeout && div < 0xE) { ++div; current_timeout <<= 1; } /* Compensate for an off-by-one error in the CaFe chip.*/ if (div < 0xE && (slot->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL)) { ++div; } } WR1(slot, SDHCI_TIMEOUT_CONTROL, div); if (data == NULL) return; /* Use DMA if possible. */ if ((slot->opt & SDHCI_HAVE_DMA)) slot->flags |= SDHCI_USE_DMA; /* If data is small, broken DMA may return zeroes instead of data, */ if ((slot->quirks & SDHCI_QUIRK_BROKEN_TIMINGS) && (data->len <= 512)) slot->flags &= ~SDHCI_USE_DMA; /* Some controllers require even block sizes. */ if ((slot->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) && ((data->len) & 0x3)) slot->flags &= ~SDHCI_USE_DMA; /* Load DMA buffer. */ if (slot->flags & SDHCI_USE_DMA) { if (data->flags & MMC_DATA_READ) bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_PREREAD); else { memcpy(slot->dmamem, data->data, (data->len < DMA_BLOCK_SIZE) ? data->len : DMA_BLOCK_SIZE); bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_PREWRITE); } WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); /* Interrupt aggregation: Mask border interrupt * for the last page and unmask else. */ if (data->len == DMA_BLOCK_SIZE) slot->intmask &= ~SDHCI_INT_DMA_END; else slot->intmask |= SDHCI_INT_DMA_END; WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); } /* Current data offset for both PIO and DMA. */ slot->offset = 0; /* Set block size and request IRQ on 4K border. */ WR2(slot, SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, (data->len < 512) ? data->len : 512)); /* Set block count. */ WR2(slot, SDHCI_BLOCK_COUNT, (data->len + 511) / 512); } void sdhci_finish_data(struct sdhci_slot *slot) { struct mmc_data *data = slot->curcmd->data; + size_t left; /* Interrupt aggregation: Restore command interrupt. * Auxiliary restore point for the case when data interrupt * happened first. */ if (!slot->cmd_done) { WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask |= SDHCI_INT_RESPONSE); } /* Unload rest of data from DMA buffer. */ if (!slot->data_done && (slot->flags & SDHCI_USE_DMA)) { if (data->flags & MMC_DATA_READ) { - size_t left = data->len - slot->offset; + left = data->len - slot->offset; bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTREAD); memcpy((u_char*)data->data + slot->offset, slot->dmamem, (left < DMA_BLOCK_SIZE) ? left : DMA_BLOCK_SIZE); } else bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTWRITE); } slot->data_done = 1; /* If there was error - reset the host. */ if (slot->curcmd->error) { sdhci_reset(slot, SDHCI_RESET_CMD); sdhci_reset(slot, SDHCI_RESET_DATA); sdhci_start(slot); return; } /* If we already have command response - finish. */ if (slot->cmd_done) sdhci_start(slot); } static void sdhci_start(struct sdhci_slot *slot) { struct mmc_request *req; req = slot->req; if (req == NULL) return; if (!(slot->flags & CMD_STARTED)) { slot->flags |= CMD_STARTED; sdhci_start_command(slot, req->cmd); return; } /* We don't need this until using Auto-CMD12 feature if (!(slot->flags & STOP_STARTED) && req->stop) { slot->flags |= STOP_STARTED; sdhci_start_command(slot, req->stop); return; } */ if (sdhci_debug > 1) slot_printf(slot, "result: %d\n", req->cmd->error); if (!req->cmd->error && (slot->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) { sdhci_reset(slot, SDHCI_RESET_CMD); sdhci_reset(slot, SDHCI_RESET_DATA); } sdhci_req_done(slot); } int sdhci_generic_request(device_t brdev, device_t reqdev, struct mmc_request *req) { struct sdhci_slot *slot = device_get_ivars(reqdev); SDHCI_LOCK(slot); if (slot->req != NULL) { SDHCI_UNLOCK(slot); return (EBUSY); } if (sdhci_debug > 1) { slot_printf(slot, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", req->cmd->opcode, req->cmd->arg, req->cmd->flags, (req->cmd->data)?(u_int)req->cmd->data->len:0, (req->cmd->data)?req->cmd->data->flags:0); } slot->req = req; slot->flags = 0; sdhci_start(slot); SDHCI_UNLOCK(slot); if (dumping) { while (slot->req != NULL) { sdhci_generic_intr(slot); DELAY(10); } } return (0); } int sdhci_generic_get_ro(device_t brdev, device_t reqdev) { struct sdhci_slot *slot = device_get_ivars(reqdev); uint32_t val; SDHCI_LOCK(slot); val = RD4(slot, SDHCI_PRESENT_STATE); SDHCI_UNLOCK(slot); return (!(val & SDHCI_WRITE_PROTECT)); } int sdhci_generic_acquire_host(device_t brdev, device_t reqdev) { struct sdhci_slot *slot = device_get_ivars(reqdev); int err = 0; SDHCI_LOCK(slot); while (slot->bus_busy) msleep(slot, &slot->mtx, 0, "sdhciah", 0); slot->bus_busy++; /* Activate led. */ WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl |= SDHCI_CTRL_LED); SDHCI_UNLOCK(slot); return (err); } int sdhci_generic_release_host(device_t brdev, device_t reqdev) { struct sdhci_slot *slot = device_get_ivars(reqdev); SDHCI_LOCK(slot); /* Deactivate led. */ WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl &= ~SDHCI_CTRL_LED); slot->bus_busy--; SDHCI_UNLOCK(slot); wakeup(slot); return (0); } static void sdhci_cmd_irq(struct sdhci_slot *slot, uint32_t intmask) { if (!slot->curcmd) { slot_printf(slot, "Got command interrupt 0x%08x, but " "there is no active command.\n", intmask); sdhci_dumpregs(slot); return; } if (intmask & SDHCI_INT_TIMEOUT) slot->curcmd->error = MMC_ERR_TIMEOUT; else if (intmask & SDHCI_INT_CRC) slot->curcmd->error = MMC_ERR_BADCRC; else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) slot->curcmd->error = MMC_ERR_FIFO; sdhci_finish_command(slot); } static void sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) { struct mmc_data *data; size_t left; if (!slot->curcmd) { slot_printf(slot, "Got data interrupt 0x%08x, but " "there is no active command.\n", intmask); sdhci_dumpregs(slot); return; } if (slot->curcmd->data == NULL && (slot->curcmd->flags & MMC_RSP_BUSY) == 0) { slot_printf(slot, "Got data interrupt 0x%08x, but " "there is no active data operation.\n", intmask); sdhci_dumpregs(slot); return; } if (intmask & SDHCI_INT_DATA_TIMEOUT) slot->curcmd->error = MMC_ERR_TIMEOUT; else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) slot->curcmd->error = MMC_ERR_BADCRC; if (slot->curcmd->data == NULL && (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DMA_END))) { slot_printf(slot, "Got data interrupt 0x%08x, but " "there is busy-only command.\n", intmask); sdhci_dumpregs(slot); slot->curcmd->error = MMC_ERR_INVALID; } if (slot->curcmd->error) { /* No need to continue after any error. */ goto done; } /* Handle PIO interrupt. */ if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) { if ((slot->opt & SDHCI_PLATFORM_TRANSFER) && SDHCI_PLATFORM_WILL_HANDLE(slot->bus, slot)) { SDHCI_PLATFORM_START_TRANSFER(slot->bus, slot, &intmask); slot->flags |= PLATFORM_DATA_STARTED; } else sdhci_transfer_pio(slot); } /* Handle DMA border. */ if (intmask & SDHCI_INT_DMA_END) { data = slot->curcmd->data; /* Unload DMA buffer... */ left = data->len - slot->offset; if (data->flags & MMC_DATA_READ) { bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTREAD); memcpy((u_char*)data->data + slot->offset, slot->dmamem, (left < DMA_BLOCK_SIZE) ? left : DMA_BLOCK_SIZE); } else { bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTWRITE); } /* ... and reload it again. */ slot->offset += DMA_BLOCK_SIZE; left = data->len - slot->offset; if (data->flags & MMC_DATA_READ) { bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_PREREAD); } else { memcpy(slot->dmamem, (u_char*)data->data + slot->offset, (left < DMA_BLOCK_SIZE)? left : DMA_BLOCK_SIZE); bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_PREWRITE); } /* Interrupt aggregation: Mask border interrupt * for the last page. */ if (left == DMA_BLOCK_SIZE) { slot->intmask &= ~SDHCI_INT_DMA_END; WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); } /* Restart DMA. */ WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); } /* We have got all data. */ if (intmask & SDHCI_INT_DATA_END) { if (slot->flags & PLATFORM_DATA_STARTED) { slot->flags &= ~PLATFORM_DATA_STARTED; SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot); } else sdhci_finish_data(slot); } done: if (slot->curcmd != NULL && slot->curcmd->error != 0) { if (slot->flags & PLATFORM_DATA_STARTED) { slot->flags &= ~PLATFORM_DATA_STARTED; SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot); } else sdhci_finish_data(slot); } } static void sdhci_acmd_irq(struct sdhci_slot *slot) { uint16_t err; err = RD4(slot, SDHCI_ACMD12_ERR); if (!slot->curcmd) { slot_printf(slot, "Got AutoCMD12 error 0x%04x, but " "there is no active command.\n", err); sdhci_dumpregs(slot); return; } slot_printf(slot, "Got AutoCMD12 error 0x%04x\n", err); sdhci_reset(slot, SDHCI_RESET_CMD); } void sdhci_generic_intr(struct sdhci_slot *slot) { uint32_t intmask, present; SDHCI_LOCK(slot); /* Read slot interrupt status. */ intmask = RD4(slot, SDHCI_INT_STATUS); if (intmask == 0 || intmask == 0xffffffff) { SDHCI_UNLOCK(slot); return; } if (sdhci_debug > 2) slot_printf(slot, "Interrupt %#x\n", intmask); /* Handle card presence interrupts. */ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { present = (intmask & SDHCI_INT_CARD_INSERT) != 0; slot->intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); slot->intmask |= present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; WR4(slot, SDHCI_INT_ENABLE, slot->intmask); WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); WR4(slot, SDHCI_INT_STATUS, intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)); sdhci_handle_card_present_locked(slot, present); intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); } /* Handle command interrupts. */ if (intmask & SDHCI_INT_CMD_MASK) { WR4(slot, SDHCI_INT_STATUS, intmask & SDHCI_INT_CMD_MASK); sdhci_cmd_irq(slot, intmask & SDHCI_INT_CMD_MASK); } /* Handle data interrupts. */ if (intmask & SDHCI_INT_DATA_MASK) { WR4(slot, SDHCI_INT_STATUS, intmask & SDHCI_INT_DATA_MASK); - /* Dont call data_irq in case of errored command */ + /* Don't call data_irq in case of errored command. */ if ((intmask & SDHCI_INT_CMD_ERROR_MASK) == 0) sdhci_data_irq(slot, intmask & SDHCI_INT_DATA_MASK); } /* Handle AutoCMD12 error interrupt. */ if (intmask & SDHCI_INT_ACMD12ERR) { WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_ACMD12ERR); sdhci_acmd_irq(slot); } intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); intmask &= ~SDHCI_INT_ACMD12ERR; intmask &= ~SDHCI_INT_ERROR; /* Handle bus power interrupt. */ if (intmask & SDHCI_INT_BUS_POWER) { WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_BUS_POWER); slot_printf(slot, "Card is consuming too much power!\n"); intmask &= ~SDHCI_INT_BUS_POWER; } /* The rest is unknown. */ if (intmask) { WR4(slot, SDHCI_INT_STATUS, intmask); slot_printf(slot, "Unexpected interrupt 0x%08x.\n", intmask); sdhci_dumpregs(slot); } SDHCI_UNLOCK(slot); } int sdhci_generic_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) { struct sdhci_slot *slot = device_get_ivars(child); switch (which) { default: return (EINVAL); case MMCBR_IVAR_BUS_MODE: *result = slot->host.ios.bus_mode; break; case MMCBR_IVAR_BUS_WIDTH: *result = slot->host.ios.bus_width; break; case MMCBR_IVAR_CHIP_SELECT: *result = slot->host.ios.chip_select; break; case MMCBR_IVAR_CLOCK: *result = slot->host.ios.clock; break; case MMCBR_IVAR_F_MIN: *result = slot->host.f_min; break; case MMCBR_IVAR_F_MAX: *result = slot->host.f_max; break; case MMCBR_IVAR_HOST_OCR: *result = slot->host.host_ocr; break; case MMCBR_IVAR_MODE: *result = slot->host.mode; break; case MMCBR_IVAR_OCR: *result = slot->host.ocr; break; case MMCBR_IVAR_POWER_MODE: *result = slot->host.ios.power_mode; break; case MMCBR_IVAR_VDD: *result = slot->host.ios.vdd; break; case MMCBR_IVAR_CAPS: *result = slot->host.caps; break; case MMCBR_IVAR_TIMING: *result = slot->host.ios.timing; break; case MMCBR_IVAR_MAX_DATA: *result = 65535; break; } return (0); } int sdhci_generic_write_ivar(device_t bus, device_t child, int which, uintptr_t value) { struct sdhci_slot *slot = device_get_ivars(child); switch (which) { default: return (EINVAL); case MMCBR_IVAR_BUS_MODE: slot->host.ios.bus_mode = value; break; case MMCBR_IVAR_BUS_WIDTH: slot->host.ios.bus_width = value; break; case MMCBR_IVAR_CHIP_SELECT: slot->host.ios.chip_select = value; break; case MMCBR_IVAR_CLOCK: if (value > 0) { uint32_t max_clock; uint32_t clock; int i; max_clock = slot->max_clk; clock = max_clock; if (slot->version < SDHCI_SPEC_300) { for (i = 0; i < SDHCI_200_MAX_DIVIDER; i <<= 1) { if (clock <= value) break; clock >>= 1; } } else { for (i = 0; i < SDHCI_300_MAX_DIVIDER; i += 2) { if (clock <= value) break; clock = max_clock / (i + 2); } } slot->host.ios.clock = clock; } else slot->host.ios.clock = 0; break; case MMCBR_IVAR_MODE: slot->host.mode = value; break; case MMCBR_IVAR_OCR: slot->host.ocr = value; break; case MMCBR_IVAR_POWER_MODE: slot->host.ios.power_mode = value; break; case MMCBR_IVAR_VDD: slot->host.ios.vdd = value; break; case MMCBR_IVAR_TIMING: slot->host.ios.timing = value; break; case MMCBR_IVAR_CAPS: case MMCBR_IVAR_HOST_OCR: case MMCBR_IVAR_F_MIN: case MMCBR_IVAR_F_MAX: case MMCBR_IVAR_MAX_DATA: return (EINVAL); } return (0); } MODULE_VERSION(sdhci, 1); Index: projects/ipsec/sys/dev/sdhci/sdhci.h =================================================================== --- projects/ipsec/sys/dev/sdhci/sdhci.h (revision 313312) +++ projects/ipsec/sys/dev/sdhci/sdhci.h (revision 313313) @@ -1,342 +1,342 @@ /*- * Copyright (c) 2008 Alexander Motin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * $FreeBSD$ */ #ifndef __SDHCI_H__ #define __SDHCI_H__ -#define DMA_BLOCK_SIZE 4096 -#define DMA_BOUNDARY 0 /* DMA reload every 4K */ +#define DMA_BLOCK_SIZE 4096 +#define DMA_BOUNDARY 0 /* DMA reload every 4K */ /* Controller doesn't honor resets unless we touch the clock register */ -#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) +#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1 << 0) /* Controller really supports DMA */ -#define SDHCI_QUIRK_FORCE_DMA (1<<1) +#define SDHCI_QUIRK_FORCE_DMA (1 << 1) /* Controller has unusable DMA engine */ -#define SDHCI_QUIRK_BROKEN_DMA (1<<2) +#define SDHCI_QUIRK_BROKEN_DMA (1 << 2) /* Controller doesn't like to be reset when there is no card inserted. */ -#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<3) +#define SDHCI_QUIRK_NO_CARD_NO_RESET (1 << 3) /* Controller has flaky internal state so reset it on each ios change */ -#define SDHCI_QUIRK_RESET_ON_IOS (1<<4) +#define SDHCI_QUIRK_RESET_ON_IOS (1 << 4) /* Controller can only DMA chunk sizes that are a multiple of 32 bits */ -#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<5) +#define SDHCI_QUIRK_32BIT_DMA_SIZE (1 << 5) /* Controller needs to be reset after each request to stay stable */ -#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<6) +#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1 << 6) /* Controller has an off-by-one issue with timeout value */ -#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1<<7) +#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1 << 7) /* Controller has broken read timings */ -#define SDHCI_QUIRK_BROKEN_TIMINGS (1<<8) +#define SDHCI_QUIRK_BROKEN_TIMINGS (1 << 8) /* Controller needs lowered frequency */ -#define SDHCI_QUIRK_LOWER_FREQUENCY (1<<9) +#define SDHCI_QUIRK_LOWER_FREQUENCY (1 << 9) /* Data timeout is invalid, should use SD clock */ -#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<10) +#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1 << 10) /* Timeout value is invalid, should be overriden */ -#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<11) +#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1 << 11) /* SDHCI_CAPABILITIES is invalid */ -#define SDHCI_QUIRK_MISSING_CAPS (1<<12) +#define SDHCI_QUIRK_MISSING_CAPS (1 << 12) /* Hardware shifts the 136-bit response, don't do it in software. */ -#define SDHCI_QUIRK_DONT_SHIFT_RESPONSE (1<<13) +#define SDHCI_QUIRK_DONT_SHIFT_RESPONSE (1 << 13) /* Wait to see reset bit asserted before waiting for de-asserted */ -#define SDHCI_QUIRK_WAITFOR_RESET_ASSERTED (1<<14) +#define SDHCI_QUIRK_WAITFOR_RESET_ASSERTED (1 << 14) /* Leave controller in standard mode when putting card in HS mode. */ -#define SDHCI_QUIRK_DONT_SET_HISPD_BIT (1<<15) +#define SDHCI_QUIRK_DONT_SET_HISPD_BIT (1 << 15) /* Alternate clock source is required when supplying a 400 KHz clock. */ -#define SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC (1<<16) +#define SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC (1 << 16) /* Card insert/remove interrupts don't work, polling required. */ -#define SDHCI_QUIRK_POLL_CARD_PRESENT (1<<17) +#define SDHCI_QUIRK_POLL_CARD_PRESENT (1 << 17) /* All controller slots are non-removable. */ -#define SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE (1<<18) +#define SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE (1 << 18) /* Issue custom Intel controller reset sequence after power-up. */ -#define SDHCI_QUIRK_INTEL_POWER_UP_RESET (1<<19) +#define SDHCI_QUIRK_INTEL_POWER_UP_RESET (1 << 19) /* Data timeout is invalid, use 1 MHz clock instead. */ -#define SDHCI_QUIRK_DATA_TIMEOUT_1MHZ (1<<20) +#define SDHCI_QUIRK_DATA_TIMEOUT_1MHZ (1 << 20) /* * Controller registers */ -#define SDHCI_DMA_ADDRESS 0x00 +#define SDHCI_DMA_ADDRESS 0x00 -#define SDHCI_BLOCK_SIZE 0x04 -#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) +#define SDHCI_BLOCK_SIZE 0x04 +#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) -#define SDHCI_BLOCK_COUNT 0x06 +#define SDHCI_BLOCK_COUNT 0x06 -#define SDHCI_ARGUMENT 0x08 +#define SDHCI_ARGUMENT 0x08 -#define SDHCI_TRANSFER_MODE 0x0C -#define SDHCI_TRNS_DMA 0x01 -#define SDHCI_TRNS_BLK_CNT_EN 0x02 -#define SDHCI_TRNS_ACMD12 0x04 -#define SDHCI_TRNS_READ 0x10 -#define SDHCI_TRNS_MULTI 0x20 +#define SDHCI_TRANSFER_MODE 0x0C +#define SDHCI_TRNS_DMA 0x01 +#define SDHCI_TRNS_BLK_CNT_EN 0x02 +#define SDHCI_TRNS_ACMD12 0x04 +#define SDHCI_TRNS_READ 0x10 +#define SDHCI_TRNS_MULTI 0x20 -#define SDHCI_COMMAND_FLAGS 0x0E -#define SDHCI_CMD_RESP_NONE 0x00 -#define SDHCI_CMD_RESP_LONG 0x01 -#define SDHCI_CMD_RESP_SHORT 0x02 -#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 -#define SDHCI_CMD_RESP_MASK 0x03 -#define SDHCI_CMD_CRC 0x08 -#define SDHCI_CMD_INDEX 0x10 -#define SDHCI_CMD_DATA 0x20 -#define SDHCI_CMD_TYPE_NORMAL 0x00 -#define SDHCI_CMD_TYPE_SUSPEND 0x40 -#define SDHCI_CMD_TYPE_RESUME 0x80 -#define SDHCI_CMD_TYPE_ABORT 0xc0 -#define SDHCI_CMD_TYPE_MASK 0xc0 +#define SDHCI_COMMAND_FLAGS 0x0E +#define SDHCI_CMD_RESP_NONE 0x00 +#define SDHCI_CMD_RESP_LONG 0x01 +#define SDHCI_CMD_RESP_SHORT 0x02 +#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 +#define SDHCI_CMD_RESP_MASK 0x03 +#define SDHCI_CMD_CRC 0x08 +#define SDHCI_CMD_INDEX 0x10 +#define SDHCI_CMD_DATA 0x20 +#define SDHCI_CMD_TYPE_NORMAL 0x00 +#define SDHCI_CMD_TYPE_SUSPEND 0x40 +#define SDHCI_CMD_TYPE_RESUME 0x80 +#define SDHCI_CMD_TYPE_ABORT 0xc0 +#define SDHCI_CMD_TYPE_MASK 0xc0 -#define SDHCI_COMMAND 0x0F +#define SDHCI_COMMAND 0x0F -#define SDHCI_RESPONSE 0x10 +#define SDHCI_RESPONSE 0x10 -#define SDHCI_BUFFER 0x20 +#define SDHCI_BUFFER 0x20 -#define SDHCI_PRESENT_STATE 0x24 -#define SDHCI_CMD_INHIBIT 0x00000001 -#define SDHCI_DAT_INHIBIT 0x00000002 -#define SDHCI_DAT_ACTIVE 0x00000004 -#define SDHCI_RETUNE_REQUEST 0x00000008 -#define SDHCI_DOING_WRITE 0x00000100 -#define SDHCI_DOING_READ 0x00000200 -#define SDHCI_SPACE_AVAILABLE 0x00000400 -#define SDHCI_DATA_AVAILABLE 0x00000800 -#define SDHCI_CARD_PRESENT 0x00010000 -#define SDHCI_CARD_STABLE 0x00020000 -#define SDHCI_CARD_PIN 0x00040000 -#define SDHCI_WRITE_PROTECT 0x00080000 -#define SDHCI_STATE_DAT_MASK 0x00f00000 -#define SDHCI_STATE_CMD 0x01000000 +#define SDHCI_PRESENT_STATE 0x24 +#define SDHCI_CMD_INHIBIT 0x00000001 +#define SDHCI_DAT_INHIBIT 0x00000002 +#define SDHCI_DAT_ACTIVE 0x00000004 +#define SDHCI_RETUNE_REQUEST 0x00000008 +#define SDHCI_DOING_WRITE 0x00000100 +#define SDHCI_DOING_READ 0x00000200 +#define SDHCI_SPACE_AVAILABLE 0x00000400 +#define SDHCI_DATA_AVAILABLE 0x00000800 +#define SDHCI_CARD_PRESENT 0x00010000 +#define SDHCI_CARD_STABLE 0x00020000 +#define SDHCI_CARD_PIN 0x00040000 +#define SDHCI_WRITE_PROTECT 0x00080000 +#define SDHCI_STATE_DAT_MASK 0x00f00000 +#define SDHCI_STATE_CMD 0x01000000 -#define SDHCI_HOST_CONTROL 0x28 -#define SDHCI_CTRL_LED 0x01 -#define SDHCI_CTRL_4BITBUS 0x02 -#define SDHCI_CTRL_HISPD 0x04 -#define SDHCI_CTRL_SDMA 0x08 -#define SDHCI_CTRL_ADMA2 0x10 -#define SDHCI_CTRL_ADMA264 0x18 -#define SDHCI_CTRL_DMA_MASK 0x18 -#define SDHCI_CTRL_8BITBUS 0x20 -#define SDHCI_CTRL_CARD_DET 0x40 -#define SDHCI_CTRL_FORCE_CARD 0x80 +#define SDHCI_HOST_CONTROL 0x28 +#define SDHCI_CTRL_LED 0x01 +#define SDHCI_CTRL_4BITBUS 0x02 +#define SDHCI_CTRL_HISPD 0x04 +#define SDHCI_CTRL_SDMA 0x08 +#define SDHCI_CTRL_ADMA2 0x10 +#define SDHCI_CTRL_ADMA264 0x18 +#define SDHCI_CTRL_DMA_MASK 0x18 +#define SDHCI_CTRL_8BITBUS 0x20 +#define SDHCI_CTRL_CARD_DET 0x40 +#define SDHCI_CTRL_FORCE_CARD 0x80 -#define SDHCI_POWER_CONTROL 0x29 -#define SDHCI_POWER_ON 0x01 -#define SDHCI_POWER_180 0x0A -#define SDHCI_POWER_300 0x0C -#define SDHCI_POWER_330 0x0E +#define SDHCI_POWER_CONTROL 0x29 +#define SDHCI_POWER_ON 0x01 +#define SDHCI_POWER_180 0x0A +#define SDHCI_POWER_300 0x0C +#define SDHCI_POWER_330 0x0E -#define SDHCI_BLOCK_GAP_CONTROL 0x2A +#define SDHCI_BLOCK_GAP_CONTROL 0x2A -#define SDHCI_WAKE_UP_CONTROL 0x2B +#define SDHCI_WAKE_UP_CONTROL 0x2B -#define SDHCI_CLOCK_CONTROL 0x2C -#define SDHCI_DIVIDER_MASK 0xff -#define SDHCI_DIVIDER_MASK_LEN 8 -#define SDHCI_DIVIDER_SHIFT 8 -#define SDHCI_DIVIDER_HI_MASK 3 -#define SDHCI_DIVIDER_HI_SHIFT 6 -#define SDHCI_CLOCK_CARD_EN 0x0004 -#define SDHCI_CLOCK_INT_STABLE 0x0002 -#define SDHCI_CLOCK_INT_EN 0x0001 -#define SDHCI_DIVIDERS_MASK \ +#define SDHCI_CLOCK_CONTROL 0x2C +#define SDHCI_DIVIDER_MASK 0xff +#define SDHCI_DIVIDER_MASK_LEN 8 +#define SDHCI_DIVIDER_SHIFT 8 +#define SDHCI_DIVIDER_HI_MASK 3 +#define SDHCI_DIVIDER_HI_SHIFT 6 +#define SDHCI_CLOCK_CARD_EN 0x0004 +#define SDHCI_CLOCK_INT_STABLE 0x0002 +#define SDHCI_CLOCK_INT_EN 0x0001 +#define SDHCI_DIVIDERS_MASK \ ((SDHCI_DIVIDER_MASK << SDHCI_DIVIDER_SHIFT) | \ (SDHCI_DIVIDER_HI_MASK << SDHCI_DIVIDER_HI_SHIFT)) -#define SDHCI_TIMEOUT_CONTROL 0x2E +#define SDHCI_TIMEOUT_CONTROL 0x2E -#define SDHCI_SOFTWARE_RESET 0x2F -#define SDHCI_RESET_ALL 0x01 -#define SDHCI_RESET_CMD 0x02 -#define SDHCI_RESET_DATA 0x04 +#define SDHCI_SOFTWARE_RESET 0x2F +#define SDHCI_RESET_ALL 0x01 +#define SDHCI_RESET_CMD 0x02 +#define SDHCI_RESET_DATA 0x04 -#define SDHCI_INT_STATUS 0x30 -#define SDHCI_INT_ENABLE 0x34 -#define SDHCI_SIGNAL_ENABLE 0x38 -#define SDHCI_INT_RESPONSE 0x00000001 -#define SDHCI_INT_DATA_END 0x00000002 -#define SDHCI_INT_BLOCK_GAP 0x00000004 -#define SDHCI_INT_DMA_END 0x00000008 -#define SDHCI_INT_SPACE_AVAIL 0x00000010 -#define SDHCI_INT_DATA_AVAIL 0x00000020 -#define SDHCI_INT_CARD_INSERT 0x00000040 -#define SDHCI_INT_CARD_REMOVE 0x00000080 -#define SDHCI_INT_CARD_INT 0x00000100 -#define SDHCI_INT_INT_A 0x00000200 -#define SDHCI_INT_INT_B 0x00000400 -#define SDHCI_INT_INT_C 0x00000800 -#define SDHCI_INT_RETUNE 0x00001000 -#define SDHCI_INT_ERROR 0x00008000 -#define SDHCI_INT_TIMEOUT 0x00010000 -#define SDHCI_INT_CRC 0x00020000 -#define SDHCI_INT_END_BIT 0x00040000 -#define SDHCI_INT_INDEX 0x00080000 -#define SDHCI_INT_DATA_TIMEOUT 0x00100000 -#define SDHCI_INT_DATA_CRC 0x00200000 -#define SDHCI_INT_DATA_END_BIT 0x00400000 -#define SDHCI_INT_BUS_POWER 0x00800000 -#define SDHCI_INT_ACMD12ERR 0x01000000 -#define SDHCI_INT_ADMAERR 0x02000000 -#define SDHCI_INT_TUNEERR 0x04000000 +#define SDHCI_INT_STATUS 0x30 +#define SDHCI_INT_ENABLE 0x34 +#define SDHCI_SIGNAL_ENABLE 0x38 +#define SDHCI_INT_RESPONSE 0x00000001 +#define SDHCI_INT_DATA_END 0x00000002 +#define SDHCI_INT_BLOCK_GAP 0x00000004 +#define SDHCI_INT_DMA_END 0x00000008 +#define SDHCI_INT_SPACE_AVAIL 0x00000010 +#define SDHCI_INT_DATA_AVAIL 0x00000020 +#define SDHCI_INT_CARD_INSERT 0x00000040 +#define SDHCI_INT_CARD_REMOVE 0x00000080 +#define SDHCI_INT_CARD_INT 0x00000100 +#define SDHCI_INT_INT_A 0x00000200 +#define SDHCI_INT_INT_B 0x00000400 +#define SDHCI_INT_INT_C 0x00000800 +#define SDHCI_INT_RETUNE 0x00001000 +#define SDHCI_INT_ERROR 0x00008000 +#define SDHCI_INT_TIMEOUT 0x00010000 +#define SDHCI_INT_CRC 0x00020000 +#define SDHCI_INT_END_BIT 0x00040000 +#define SDHCI_INT_INDEX 0x00080000 +#define SDHCI_INT_DATA_TIMEOUT 0x00100000 +#define SDHCI_INT_DATA_CRC 0x00200000 +#define SDHCI_INT_DATA_END_BIT 0x00400000 +#define SDHCI_INT_BUS_POWER 0x00800000 +#define SDHCI_INT_ACMD12ERR 0x01000000 +#define SDHCI_INT_ADMAERR 0x02000000 +#define SDHCI_INT_TUNEERR 0x04000000 -#define SDHCI_INT_NORMAL_MASK 0x00007FFF -#define SDHCI_INT_ERROR_MASK 0xFFFF8000 +#define SDHCI_INT_NORMAL_MASK 0x00007FFF +#define SDHCI_INT_ERROR_MASK 0xFFFF8000 -#define SDHCI_INT_CMD_ERROR_MASK (SDHCI_INT_TIMEOUT | \ +#define SDHCI_INT_CMD_ERROR_MASK (SDHCI_INT_TIMEOUT | \ SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX) -#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_CMD_ERROR_MASK) +#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_CMD_ERROR_MASK) -#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ +#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ SDHCI_INT_DATA_END_BIT) -#define SDHCI_ACMD12_ERR 0x3C -#define SDHCI_HOST_CONTROL2 0x3E +#define SDHCI_ACMD12_ERR 0x3C +#define SDHCI_HOST_CONTROL2 0x3E -#define SDHCI_CAPABILITIES 0x40 -#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F -#define SDHCI_TIMEOUT_CLK_SHIFT 0 -#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 -#define SDHCI_CLOCK_BASE_MASK 0x00003F00 -#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00 -#define SDHCI_CLOCK_BASE_SHIFT 8 -#define SDHCI_MAX_BLOCK_MASK 0x00030000 -#define SDHCI_MAX_BLOCK_SHIFT 16 -#define SDHCI_CAN_DO_8BITBUS 0x00040000 -#define SDHCI_CAN_DO_ADMA2 0x00080000 -#define SDHCI_CAN_DO_HISPD 0x00200000 -#define SDHCI_CAN_DO_DMA 0x00400000 -#define SDHCI_CAN_DO_SUSPEND 0x00800000 -#define SDHCI_CAN_VDD_330 0x01000000 -#define SDHCI_CAN_VDD_300 0x02000000 -#define SDHCI_CAN_VDD_180 0x04000000 -#define SDHCI_CAN_DO_64BIT 0x10000000 -#define SDHCI_CAN_ASYNC_INTR 0x20000000 +#define SDHCI_CAPABILITIES 0x40 +#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F +#define SDHCI_TIMEOUT_CLK_SHIFT 0 +#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 +#define SDHCI_CLOCK_BASE_MASK 0x00003F00 +#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00 +#define SDHCI_CLOCK_BASE_SHIFT 8 +#define SDHCI_MAX_BLOCK_MASK 0x00030000 +#define SDHCI_MAX_BLOCK_SHIFT 16 +#define SDHCI_CAN_DO_8BITBUS 0x00040000 +#define SDHCI_CAN_DO_ADMA2 0x00080000 +#define SDHCI_CAN_DO_HISPD 0x00200000 +#define SDHCI_CAN_DO_DMA 0x00400000 +#define SDHCI_CAN_DO_SUSPEND 0x00800000 +#define SDHCI_CAN_VDD_330 0x01000000 +#define SDHCI_CAN_VDD_300 0x02000000 +#define SDHCI_CAN_VDD_180 0x04000000 +#define SDHCI_CAN_DO_64BIT 0x10000000 +#define SDHCI_CAN_ASYNC_INTR 0x20000000 -#define SDHCI_CAPABILITIES2 0x44 -#define SDHCI_CAN_SDR50 0x00000001 -#define SDHCI_CAN_SDR104 0x00000002 -#define SDHCI_CAN_DDR50 0x00000004 -#define SDHCI_CAN_DRIVE_TYPE_A 0x00000010 -#define SDHCI_CAN_DRIVE_TYPE_B 0x00000020 -#define SDHCI_CAN_DRIVE_TYPE_C 0x00000040 -#define SDHCI_RETUNE_CNT_MASK 0x00000F00 -#define SDHCI_RETUNE_CNT_SHIFT 8 -#define SDHCI_TUNE_SDR50 0x00002000 -#define SDHCI_RETUNE_MODES_MASK 0x0000C000 -#define SDHCI_RETUNE_MODES_SHIFT 14 -#define SDHCI_CLOCK_MULT_MASK 0x00FF0000 -#define SDHCI_CLOCK_MULT_SHIFT 16 +#define SDHCI_CAPABILITIES2 0x44 +#define SDHCI_CAN_SDR50 0x00000001 +#define SDHCI_CAN_SDR104 0x00000002 +#define SDHCI_CAN_DDR50 0x00000004 +#define SDHCI_CAN_DRIVE_TYPE_A 0x00000010 +#define SDHCI_CAN_DRIVE_TYPE_B 0x00000020 +#define SDHCI_CAN_DRIVE_TYPE_C 0x00000040 +#define SDHCI_RETUNE_CNT_MASK 0x00000F00 +#define SDHCI_RETUNE_CNT_SHIFT 8 +#define SDHCI_TUNE_SDR50 0x00002000 +#define SDHCI_RETUNE_MODES_MASK 0x0000C000 +#define SDHCI_RETUNE_MODES_SHIFT 14 +#define SDHCI_CLOCK_MULT_MASK 0x00FF0000 +#define SDHCI_CLOCK_MULT_SHIFT 16 -#define SDHCI_MAX_CURRENT 0x48 -#define SDHCI_FORCE_AUTO_EVENT 0x50 -#define SDHCI_FORCE_INTR_EVENT 0x52 -#define SDHCI_ADMA_ERR 0x54 -#define SDHCI_ADMA_ADDRESS_LOW 0x58 -#define SDHCI_ADMA_ADDRESS_HI 0x5C -#define SDHCI_PRESET_VALUE 0x60 -#define SDHCI_SHARED_BUS_CTRL 0xE0 +#define SDHCI_MAX_CURRENT 0x48 +#define SDHCI_FORCE_AUTO_EVENT 0x50 +#define SDHCI_FORCE_INTR_EVENT 0x52 +#define SDHCI_ADMA_ERR 0x54 +#define SDHCI_ADMA_ADDRESS_LOW 0x58 +#define SDHCI_ADMA_ADDRESS_HI 0x5C +#define SDHCI_PRESET_VALUE 0x60 +#define SDHCI_SHARED_BUS_CTRL 0xE0 -#define SDHCI_SLOT_INT_STATUS 0xFC +#define SDHCI_SLOT_INT_STATUS 0xFC -#define SDHCI_HOST_VERSION 0xFE -#define SDHCI_VENDOR_VER_MASK 0xFF00 -#define SDHCI_VENDOR_VER_SHIFT 8 -#define SDHCI_SPEC_VER_MASK 0x00FF -#define SDHCI_SPEC_VER_SHIFT 0 +#define SDHCI_HOST_VERSION 0xFE +#define SDHCI_VENDOR_VER_MASK 0xFF00 +#define SDHCI_VENDOR_VER_SHIFT 8 +#define SDHCI_SPEC_VER_MASK 0x00FF +#define SDHCI_SPEC_VER_SHIFT 0 #define SDHCI_SPEC_100 0 #define SDHCI_SPEC_200 1 #define SDHCI_SPEC_300 2 SYSCTL_DECL(_hw_sdhci); struct sdhci_slot { u_int quirks; /* Chip specific quirks */ u_int caps; /* Override SDHCI_CAPABILITIES */ device_t bus; /* Bus device */ device_t dev; /* Slot device */ u_char num; /* Slot number */ u_char opt; /* Slot options */ #define SDHCI_HAVE_DMA 0x01 #define SDHCI_PLATFORM_TRANSFER 0x02 #define SDHCI_NON_REMOVABLE 0x04 u_char version; int timeout; /* Transfer timeout */ uint32_t max_clk; /* Max possible freq */ uint32_t timeout_clk; /* Timeout freq */ bus_dma_tag_t dmatag; bus_dmamap_t dmamap; u_char *dmamem; bus_addr_t paddr; /* DMA buffer address */ struct task card_task; /* Card presence check task */ struct timeout_task card_delayed_task;/* Card insert delayed task */ struct callout card_poll_callout;/* Card present polling callout */ struct callout timeout_callout;/* Card command/data response timeout */ struct mmc_host host; /* Host parameters */ struct mmc_request *req; /* Current request */ struct mmc_command *curcmd; /* Current command of current request */ uint32_t intmask; /* Current interrupt mask */ uint32_t clock; /* Current clock freq. */ size_t offset; /* Data buffer offset */ uint8_t hostctrl; /* Current host control register */ u_char power; /* Current power */ u_char bus_busy; /* Bus busy status */ u_char cmd_done; /* CMD command part done flag */ u_char data_done; /* DAT command part done flag */ u_char flags; /* Request execution flags */ -#define CMD_STARTED 1 -#define STOP_STARTED 2 -#define SDHCI_USE_DMA 4 /* Use DMA for this req. */ -#define PLATFORM_DATA_STARTED 8 /* Data xfer is handled by platform */ +#define CMD_STARTED 1 +#define STOP_STARTED 2 +#define SDHCI_USE_DMA 4 /* Use DMA for this req. */ +#define PLATFORM_DATA_STARTED 8 /* Data xfer is handled by platform */ struct mtx mtx; /* Slot mutex */ }; int sdhci_generic_read_ivar(device_t bus, device_t child, int which, uintptr_t *result); int sdhci_generic_write_ivar(device_t bus, device_t child, int which, uintptr_t value); int sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num); void sdhci_start_slot(struct sdhci_slot *slot); /* performs generic clean-up for platform transfers */ void sdhci_finish_data(struct sdhci_slot *slot); int sdhci_cleanup_slot(struct sdhci_slot *slot); int sdhci_generic_suspend(struct sdhci_slot *slot); int sdhci_generic_resume(struct sdhci_slot *slot); int sdhci_generic_update_ios(device_t brdev, device_t reqdev); int sdhci_generic_request(device_t brdev, device_t reqdev, struct mmc_request *req); int sdhci_generic_get_ro(device_t brdev, device_t reqdev); int sdhci_generic_acquire_host(device_t brdev, device_t reqdev); int sdhci_generic_release_host(device_t brdev, device_t reqdev); void sdhci_generic_intr(struct sdhci_slot *slot); uint32_t sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot); bool sdhci_generic_get_card_present(device_t brdev, struct sdhci_slot *slot); void sdhci_handle_card_present(struct sdhci_slot *slot, bool is_present); #endif /* __SDHCI_H__ */ Index: projects/ipsec/sys/dev/sdhci/sdhci_fdt.c =================================================================== --- projects/ipsec/sys/dev/sdhci/sdhci_fdt.c (revision 313312) +++ projects/ipsec/sys/dev/sdhci/sdhci_fdt.c (revision 313313) @@ -1,311 +1,313 @@ /*- * Copyright (c) 2012 Thomas Skibo * Copyright (c) 2008 Alexander Motin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ /* Generic driver to attach sdhci controllers on simplebus. * Derived mainly from sdhci_pci.c */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mmcbr_if.h" #include "sdhci_if.h" -#define MAX_SLOTS 6 +#define MAX_SLOTS 6 struct sdhci_fdt_softc { device_t dev; /* Controller device */ u_int quirks; /* Chip specific quirks */ u_int caps; /* If we override SDHCI_CAPABILITIES */ uint32_t max_clk; /* Max possible freq */ struct resource *irq_res; /* IRQ resource */ - void *intrhand; /* Interrupt handle */ + void *intrhand; /* Interrupt handle */ int num_slots; /* Number of slots on this controller*/ struct sdhci_slot slots[MAX_SLOTS]; struct resource *mem_res[MAX_SLOTS]; /* Memory resource */ }; static uint8_t sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + return (bus_read_1(sc->mem_res[slot->num], off)); } static void sdhci_fdt_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, - uint8_t val) + uint8_t val) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_write_1(sc->mem_res[slot->num], off, val); } static uint16_t sdhci_fdt_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + return (bus_read_2(sc->mem_res[slot->num], off)); } static void sdhci_fdt_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, - uint16_t val) + uint16_t val) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_write_2(sc->mem_res[slot->num], off, val); } static uint32_t sdhci_fdt_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + return (bus_read_4(sc->mem_res[slot->num], off)); } static void sdhci_fdt_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, - uint32_t val) + uint32_t val) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_write_4(sc->mem_res[slot->num], off, val); } static void sdhci_fdt_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_read_multi_4(sc->mem_res[slot->num], off, data, count); } static void sdhci_fdt_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + bus_write_multi_4(sc->mem_res[slot->num], off, data, count); } static void sdhci_fdt_intr(void *arg) { struct sdhci_fdt_softc *sc = (struct sdhci_fdt_softc *)arg; int i; - for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - sdhci_generic_intr(slot); - } + for (i = 0; i < sc->num_slots; i++) + sdhci_generic_intr(&sc->slots[i]); } static int sdhci_fdt_probe(device_t dev) { struct sdhci_fdt_softc *sc = device_get_softc(dev); phandle_t node; pcell_t cid; sc->quirks = 0; sc->num_slots = 1; sc->max_clk = 0; if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_is_compatible(dev, "sdhci_generic")) { device_set_desc(dev, "generic fdt SDHCI controller"); } else if (ofw_bus_is_compatible(dev, "xlnx,zy7_sdhci")) { sc->quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; device_set_desc(dev, "Zynq-7000 generic fdt SDHCI controller"); } else return (ENXIO); node = ofw_bus_get_node(dev); /* Allow dts to patch quirks, slots, and max-frequency. */ if ((OF_getencprop(node, "quirks", &cid, sizeof(cid))) > 0) sc->quirks = cid; if ((OF_getencprop(node, "num-slots", &cid, sizeof(cid))) > 0) sc->num_slots = cid; if ((OF_getencprop(node, "max-frequency", &cid, sizeof(cid))) > 0) sc->max_clk = cid; return (0); } static int sdhci_fdt_attach(device_t dev) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + struct sdhci_slot *slot; int err, slots, rid, i; sc->dev = dev; /* Allocate IRQ. */ rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE); + RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "Can't allocate IRQ\n"); return (ENOMEM); } /* Scan all slots. */ slots = sc->num_slots; /* number of slots determined in probe(). */ sc->num_slots = 0; for (i = 0; i < slots; i++) { - struct sdhci_slot *slot = &sc->slots[sc->num_slots]; + slot = &sc->slots[sc->num_slots]; /* Allocate memory. */ rid = 0; sc->mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res[i] == NULL) { - device_printf(dev, "Can't allocate memory for " - "slot %d\n", i); + device_printf(dev, + "Can't allocate memory for slot %d\n", i); continue; } slot->quirks = sc->quirks; slot->caps = sc->caps; slot->max_clk = sc->max_clk; if (sdhci_init_slot(dev, slot, i) != 0) continue; sc->num_slots++; } device_printf(dev, "%d slot(s) allocated\n", sc->num_slots); /* Activate the interrupt */ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, sdhci_fdt_intr, sc, &sc->intrhand); if (err) { device_printf(dev, "Cannot setup IRQ\n"); return (err); } /* Process cards detection. */ - for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - sdhci_start_slot(slot); - } + for (i = 0; i < sc->num_slots; i++) + sdhci_start_slot(&sc->slots[i]); return (0); } static int sdhci_fdt_detach(device_t dev) { struct sdhci_fdt_softc *sc = device_get_softc(dev); int i; bus_generic_detach(dev); bus_teardown_intr(dev, sc->irq_res, sc->intrhand); bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), - sc->irq_res); + sc->irq_res); for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - - sdhci_cleanup_slot(slot); + sdhci_cleanup_slot(&sc->slots[i]); bus_release_resource(dev, SYS_RES_MEMORY, - rman_get_rid(sc->mem_res[i]), - sc->mem_res[i]); + rman_get_rid(sc->mem_res[i]), sc->mem_res[i]); } return (0); } static device_method_t sdhci_fdt_methods[] = { /* device_if */ - DEVMETHOD(device_probe, sdhci_fdt_probe), - DEVMETHOD(device_attach, sdhci_fdt_attach), - DEVMETHOD(device_detach, sdhci_fdt_detach), + DEVMETHOD(device_probe, sdhci_fdt_probe), + DEVMETHOD(device_attach, sdhci_fdt_attach), + DEVMETHOD(device_detach, sdhci_fdt_detach), /* Bus interface */ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), /* mmcbr_if */ - DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), - DEVMETHOD(mmcbr_request, sdhci_generic_request), - DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), - DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), - DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), + DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), + DEVMETHOD(mmcbr_request, sdhci_generic_request), + DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), + DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), + DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), /* SDHCI registers accessors */ DEVMETHOD(sdhci_read_1, sdhci_fdt_read_1), DEVMETHOD(sdhci_read_2, sdhci_fdt_read_2), DEVMETHOD(sdhci_read_4, sdhci_fdt_read_4), DEVMETHOD(sdhci_read_multi_4, sdhci_fdt_read_multi_4), DEVMETHOD(sdhci_write_1, sdhci_fdt_write_1), DEVMETHOD(sdhci_write_2, sdhci_fdt_write_2), DEVMETHOD(sdhci_write_4, sdhci_fdt_write_4), DEVMETHOD(sdhci_write_multi_4, sdhci_fdt_write_multi_4), DEVMETHOD_END }; static driver_t sdhci_fdt_driver = { "sdhci_fdt", sdhci_fdt_methods, sizeof(struct sdhci_fdt_softc), }; static devclass_t sdhci_fdt_devclass; DRIVER_MODULE(sdhci_fdt, simplebus, sdhci_fdt_driver, sdhci_fdt_devclass, NULL, NULL); MODULE_DEPEND(sdhci_fdt, sdhci, 1, 1, 1); DRIVER_MODULE(mmc, sdhci_fdt, mmc_driver, mmc_devclass, NULL, NULL); MODULE_DEPEND(sdhci_fdt, mmc, 1, 1, 1); Index: projects/ipsec/sys/dev/sdhci/sdhci_pci.c =================================================================== --- projects/ipsec/sys/dev/sdhci/sdhci_pci.c (revision 313312) +++ projects/ipsec/sys/dev/sdhci/sdhci_pci.c (revision 313313) @@ -1,500 +1,494 @@ /*- * Copyright (c) 2008 Alexander Motin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sdhci.h" #include "mmcbr_if.h" #include "sdhci_if.h" /* * PCI registers */ -#define PCI_SDHCI_IFPIO 0x00 -#define PCI_SDHCI_IFDMA 0x01 -#define PCI_SDHCI_IFVENDOR 0x02 +#define PCI_SDHCI_IFPIO 0x00 +#define PCI_SDHCI_IFDMA 0x01 +#define PCI_SDHCI_IFVENDOR 0x02 -#define PCI_SLOT_INFO 0x40 /* 8 bits */ -#define PCI_SLOT_INFO_SLOTS(x) (((x >> 4) & 7) + 1) -#define PCI_SLOT_INFO_FIRST_BAR(x) ((x) & 7) +#define PCI_SLOT_INFO 0x40 /* 8 bits */ +#define PCI_SLOT_INFO_SLOTS(x) (((x >> 4) & 7) + 1) +#define PCI_SLOT_INFO_FIRST_BAR(x) ((x) & 7) /* * RICOH specific PCI registers */ #define SDHC_PCI_MODE_KEY 0xf9 #define SDHC_PCI_MODE 0x150 #define SDHC_PCI_MODE_SD20 0x10 #define SDHC_PCI_BASE_FREQ_KEY 0xfc #define SDHC_PCI_BASE_FREQ 0xe1 static const struct sdhci_device { uint32_t model; uint16_t subvendor; const char *desc; u_int quirks; } sdhci_devices[] = { { 0x08221180, 0xffff, "RICOH R5C822 SD", SDHCI_QUIRK_FORCE_DMA }, { 0xe8221180, 0xffff, "RICOH R5CE822 SD", SDHCI_QUIRK_FORCE_DMA | SDHCI_QUIRK_LOWER_FREQUENCY }, { 0xe8231180, 0xffff, "RICOH R5CE823 SD", SDHCI_QUIRK_LOWER_FREQUENCY }, { 0x8034104c, 0xffff, "TI XX21/XX11 SD", SDHCI_QUIRK_FORCE_DMA }, { 0x05501524, 0xffff, "ENE CB712 SD", SDHCI_QUIRK_BROKEN_TIMINGS }, { 0x05511524, 0xffff, "ENE CB712 SD 2", SDHCI_QUIRK_BROKEN_TIMINGS }, { 0x07501524, 0xffff, "ENE CB714 SD", SDHCI_QUIRK_RESET_ON_IOS | SDHCI_QUIRK_BROKEN_TIMINGS }, { 0x07511524, 0xffff, "ENE CB714 SD 2", SDHCI_QUIRK_RESET_ON_IOS | SDHCI_QUIRK_BROKEN_TIMINGS }, { 0x410111ab, 0xffff, "Marvell CaFe SD", SDHCI_QUIRK_INCR_TIMEOUT_CONTROL }, { 0x2381197B, 0xffff, "JMicron JMB38X SD", SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_RESET_AFTER_REQUEST }, { 0x16bc14e4, 0xffff, "Broadcom BCM577xx SDXC/MMC Card Reader", SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC }, { 0x0f148086, 0xffff, "Intel Bay Trail eMMC 4.5 Controller", SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE | SDHCI_QUIRK_INTEL_POWER_UP_RESET }, { 0x0f508086, 0xffff, "Intel Bay Trail eMMC 4.5 Controller", SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE | SDHCI_QUIRK_INTEL_POWER_UP_RESET }, { 0x22948086, 0xffff, "Intel Braswell eMMC 4.5.1 Controller", SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE | SDHCI_QUIRK_DATA_TIMEOUT_1MHZ | SDHCI_QUIRK_INTEL_POWER_UP_RESET }, { 0x5acc8086, 0xffff, "Intel Apollo Lake eMMC 5.0 Controller", SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE | SDHCI_QUIRK_INTEL_POWER_UP_RESET }, { 0, 0xffff, NULL, 0 } }; struct sdhci_pci_softc { u_int quirks; /* Chip specific quirks */ struct resource *irq_res; /* IRQ resource */ void *intrhand; /* Interrupt handle */ int num_slots; /* Number of slots on this controller */ struct sdhci_slot slots[6]; struct resource *mem_res[6]; /* Memory resource */ uint8_t cfg_freq; /* Saved frequency */ uint8_t cfg_mode; /* Saved mode */ }; static int sdhci_enable_msi = 1; SYSCTL_INT(_hw_sdhci, OID_AUTO, enable_msi, CTLFLAG_RDTUN, &sdhci_enable_msi, 0, "Enable MSI interrupts"); static uint8_t sdhci_pci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_pci_softc *sc = device_get_softc(dev); bus_barrier(sc->mem_res[slot->num], 0, 0xFF, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); return bus_read_1(sc->mem_res[slot->num], off); } static void sdhci_pci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val) { struct sdhci_pci_softc *sc = device_get_softc(dev); bus_barrier(sc->mem_res[slot->num], 0, 0xFF, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); bus_write_1(sc->mem_res[slot->num], off, val); } static uint16_t sdhci_pci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_pci_softc *sc = device_get_softc(dev); bus_barrier(sc->mem_res[slot->num], 0, 0xFF, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); return bus_read_2(sc->mem_res[slot->num], off); } static void sdhci_pci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val) { struct sdhci_pci_softc *sc = device_get_softc(dev); bus_barrier(sc->mem_res[slot->num], 0, 0xFF, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); bus_write_2(sc->mem_res[slot->num], off, val); } static uint32_t sdhci_pci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_pci_softc *sc = device_get_softc(dev); bus_barrier(sc->mem_res[slot->num], 0, 0xFF, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); return bus_read_4(sc->mem_res[slot->num], off); } static void sdhci_pci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val) { struct sdhci_pci_softc *sc = device_get_softc(dev); bus_barrier(sc->mem_res[slot->num], 0, 0xFF, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); bus_write_4(sc->mem_res[slot->num], off, val); } static void sdhci_pci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_pci_softc *sc = device_get_softc(dev); bus_read_multi_stream_4(sc->mem_res[slot->num], off, data, count); } static void sdhci_pci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_pci_softc *sc = device_get_softc(dev); bus_write_multi_stream_4(sc->mem_res[slot->num], off, data, count); } static void sdhci_pci_intr(void *arg); static void sdhci_lower_frequency(device_t dev) { struct sdhci_pci_softc *sc = device_get_softc(dev); /* * Enable SD2.0 mode. * NB: for RICOH R5CE823, this changes the PCI device ID to 0xe822. */ pci_write_config(dev, SDHC_PCI_MODE_KEY, 0xfc, 1); sc->cfg_mode = pci_read_config(dev, SDHC_PCI_MODE, 1); pci_write_config(dev, SDHC_PCI_MODE, SDHC_PCI_MODE_SD20, 1); pci_write_config(dev, SDHC_PCI_MODE_KEY, 0x00, 1); /* * Some SD/MMC cards don't work with the default base * clock frequency of 200 MHz. Lower it to 50 MHz. */ pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x01, 1); sc->cfg_freq = pci_read_config(dev, SDHC_PCI_BASE_FREQ, 1); pci_write_config(dev, SDHC_PCI_BASE_FREQ, 50, 1); pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x00, 1); } static void sdhci_restore_frequency(device_t dev) { struct sdhci_pci_softc *sc = device_get_softc(dev); /* Restore mode. */ pci_write_config(dev, SDHC_PCI_MODE_KEY, 0xfc, 1); pci_write_config(dev, SDHC_PCI_MODE, sc->cfg_mode, 1); pci_write_config(dev, SDHC_PCI_MODE_KEY, 0x00, 1); /* Restore frequency. */ pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x01, 1); pci_write_config(dev, SDHC_PCI_BASE_FREQ, sc->cfg_freq, 1); pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x00, 1); } static int sdhci_pci_probe(device_t dev) { uint32_t model; uint16_t subvendor; uint8_t class, subclass; int i, result; model = (uint32_t)pci_get_device(dev) << 16; model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff; subvendor = pci_get_subvendor(dev); class = pci_get_class(dev); subclass = pci_get_subclass(dev); result = ENXIO; for (i = 0; sdhci_devices[i].model != 0; i++) { if (sdhci_devices[i].model == model && (sdhci_devices[i].subvendor == 0xffff || sdhci_devices[i].subvendor == subvendor)) { device_set_desc(dev, sdhci_devices[i].desc); result = BUS_PROBE_DEFAULT; break; } } if (result == ENXIO && class == PCIC_BASEPERIPH && subclass == PCIS_BASEPERIPH_SDHC) { device_set_desc(dev, "Generic SD HCI"); result = BUS_PROBE_GENERIC; } return (result); } static int sdhci_pci_attach(device_t dev) { struct sdhci_pci_softc *sc = device_get_softc(dev); + struct sdhci_slot *slot; uint32_t model; uint16_t subvendor; int bar, err, rid, slots, i; model = (uint32_t)pci_get_device(dev) << 16; model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff; subvendor = pci_get_subvendor(dev); /* Apply chip specific quirks. */ for (i = 0; sdhci_devices[i].model != 0; i++) { if (sdhci_devices[i].model == model && (sdhci_devices[i].subvendor == 0xffff || sdhci_devices[i].subvendor == subvendor)) { sc->quirks = sdhci_devices[i].quirks; break; } } /* Some controllers need to be bumped into the right mode. */ if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY) sdhci_lower_frequency(dev); /* Read slots info from PCI registers. */ slots = pci_read_config(dev, PCI_SLOT_INFO, 1); bar = PCI_SLOT_INFO_FIRST_BAR(slots); slots = PCI_SLOT_INFO_SLOTS(slots); if (slots > 6 || bar > 5) { device_printf(dev, "Incorrect slots information (%d, %d).\n", slots, bar); return (EINVAL); } /* Allocate IRQ. */ i = 1; rid = 0; if (sdhci_enable_msi != 0 && pci_alloc_msi(dev, &i) == 0) rid = 1; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE)); if (sc->irq_res == NULL) { device_printf(dev, "Can't allocate IRQ\n"); pci_release_msi(dev); return (ENOMEM); } /* Scan all slots. */ for (i = 0; i < slots; i++) { - struct sdhci_slot *slot = &sc->slots[sc->num_slots]; + slot = &sc->slots[sc->num_slots]; /* Allocate memory. */ rid = PCIR_BAR(bar + i); sc->mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res[i] == NULL) { device_printf(dev, "Can't allocate memory for slot %d\n", i); continue; } - + slot->quirks = sc->quirks; if (sdhci_init_slot(dev, slot, i) != 0) continue; sc->num_slots++; } device_printf(dev, "%d slot(s) allocated\n", sc->num_slots); /* Activate the interrupt */ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, sdhci_pci_intr, sc, &sc->intrhand); if (err) device_printf(dev, "Can't setup IRQ\n"); pci_enable_busmaster(dev); /* Process cards detection. */ - for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; + for (i = 0; i < sc->num_slots; i++) + sdhci_start_slot(&sc->slots[i]); - sdhci_start_slot(slot); - } - return (0); } static int sdhci_pci_detach(device_t dev) { struct sdhci_pci_softc *sc = device_get_softc(dev); int i; bus_teardown_intr(dev, sc->irq_res, sc->intrhand); bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); pci_release_msi(dev); for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - - sdhci_cleanup_slot(slot); + sdhci_cleanup_slot(&sc->slots[i]); bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem_res[i]), sc->mem_res[i]); } if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY) sdhci_restore_frequency(dev); return (0); } static int sdhci_pci_shutdown(device_t dev) { struct sdhci_pci_softc *sc = device_get_softc(dev); if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY) sdhci_restore_frequency(dev); return (0); } static int sdhci_pci_suspend(device_t dev) { struct sdhci_pci_softc *sc = device_get_softc(dev); int i, err; err = bus_generic_suspend(dev); if (err) return (err); for (i = 0; i < sc->num_slots; i++) sdhci_generic_suspend(&sc->slots[i]); return (0); } static int sdhci_pci_resume(device_t dev) { struct sdhci_pci_softc *sc = device_get_softc(dev); int i, err; for (i = 0; i < sc->num_slots; i++) sdhci_generic_resume(&sc->slots[i]); err = bus_generic_resume(dev); if (err) return (err); if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY) sdhci_lower_frequency(dev); return (0); } static void sdhci_pci_intr(void *arg) { struct sdhci_pci_softc *sc = (struct sdhci_pci_softc *)arg; int i; - for (i = 0; i < sc->num_slots; i++) { - struct sdhci_slot *slot = &sc->slots[i]; - sdhci_generic_intr(slot); - } + for (i = 0; i < sc->num_slots; i++) + sdhci_generic_intr(&sc->slots[i]); } static device_method_t sdhci_methods[] = { /* device_if */ - DEVMETHOD(device_probe, sdhci_pci_probe), - DEVMETHOD(device_attach, sdhci_pci_attach), - DEVMETHOD(device_detach, sdhci_pci_detach), - DEVMETHOD(device_shutdown, sdhci_pci_shutdown), - DEVMETHOD(device_suspend, sdhci_pci_suspend), - DEVMETHOD(device_resume, sdhci_pci_resume), + DEVMETHOD(device_probe, sdhci_pci_probe), + DEVMETHOD(device_attach, sdhci_pci_attach), + DEVMETHOD(device_detach, sdhci_pci_detach), + DEVMETHOD(device_shutdown, sdhci_pci_shutdown), + DEVMETHOD(device_suspend, sdhci_pci_suspend), + DEVMETHOD(device_resume, sdhci_pci_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), /* mmcbr_if */ DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), DEVMETHOD(mmcbr_request, sdhci_generic_request), DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), /* SDHCI registers accessors */ DEVMETHOD(sdhci_read_1, sdhci_pci_read_1), DEVMETHOD(sdhci_read_2, sdhci_pci_read_2), DEVMETHOD(sdhci_read_4, sdhci_pci_read_4), DEVMETHOD(sdhci_read_multi_4, sdhci_pci_read_multi_4), DEVMETHOD(sdhci_write_1, sdhci_pci_write_1), DEVMETHOD(sdhci_write_2, sdhci_pci_write_2), DEVMETHOD(sdhci_write_4, sdhci_pci_write_4), DEVMETHOD(sdhci_write_multi_4, sdhci_pci_write_multi_4), DEVMETHOD_END }; static driver_t sdhci_pci_driver = { "sdhci_pci", sdhci_methods, sizeof(struct sdhci_pci_softc), }; static devclass_t sdhci_pci_devclass; DRIVER_MODULE(sdhci_pci, pci, sdhci_pci_driver, sdhci_pci_devclass, NULL, NULL); MODULE_DEPEND(sdhci_pci, sdhci, 1, 1, 1); DRIVER_MODULE(mmc, sdhci_pci, mmc_driver, mmc_devclass, NULL, NULL); MODULE_DEPEND(sdhci_pci, mmc, 1, 1, 1); Index: projects/ipsec/sys/dev/usb/serial/uftdi.c =================================================================== --- projects/ipsec/sys/dev/usb/serial/uftdi.c (revision 313312) +++ projects/ipsec/sys/dev/usb/serial/uftdi.c (revision 313313) @@ -1,2003 +1,2009 @@ /* $NetBSD: uftdi.c,v 1.13 2002/09/23 05:51:23 simonb Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (lennart@augustsson.net). * * 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. * * 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. */ #include __FBSDID("$FreeBSD$"); /* * NOTE: all function names beginning like "uftdi_cfg_" can only * be called from within the config thread function ! */ /* * FTDI FT232x, FT2232x, FT4232x, FT8U100AX and FT8U232xM serial adapters. * * Note that we specifically do not do a reset or otherwise alter the state of * the chip during attach, detach, open, and close, because it could be * pre-initialized (via an attached serial eeprom) to power-on into a mode such * as bitbang in which the pins are being driven to a specific state which we * must not perturb. The device gets reset at power-on, and doesn't need to be * reset again after that to function, except as directed by ioctl() calls. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "usbdevs.h" #define USB_DEBUG_VAR uftdi_debug #include #include #include #include #include static SYSCTL_NODE(_hw_usb, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi"); #ifdef USB_DEBUG static int uftdi_debug = 0; SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, debug, CTLFLAG_RWTUN, &uftdi_debug, 0, "Debug level"); #endif #define UFTDI_CONFIG_INDEX 0 /* * IO buffer sizes and FTDI device procotol sizes. * * Note that the output packet size in the following defines is not the usb * protocol packet size based on bus speed, it is the size dictated by the FTDI * device itself, and is used only on older chips. * * We allocate buffers bigger than the hardware's packet size, and process * multiple packets within each buffer. This allows the controller to make * optimal use of the usb bus by conducting multiple transfers with the device * during a single bus timeslice to fill or drain the chip's fifos. * * The output data on newer chips has no packet header, and we are able to pack * any number of output bytes into a buffer. On some older chips, each output * packet contains a 1-byte header and up to 63 bytes of payload. The size is * encoded in 6 bits of the header, hence the 64-byte limit on packet size. We * loop to fill the buffer with many of these header+payload packets. * * The input data on all chips consists of packets which contain a 2-byte header * followed by data payload. The total size of the packet is wMaxPacketSize * which can change based on the bus speed (e.g., 64 for full speed, 512 for * high speed). We loop to extract the headers and payloads from the packets * packed into an input buffer. */ #define UFTDI_IBUFSIZE 2048 #define UFTDI_IHDRSIZE 2 #define UFTDI_OBUFSIZE 2048 #define UFTDI_OPKTSIZE 64 enum { UFTDI_BULK_DT_WR, UFTDI_BULK_DT_RD, UFTDI_N_TRANSFER, }; enum { DEVT_SIO, DEVT_232A, DEVT_232B, DEVT_2232D, /* Includes 2232C */ DEVT_232R, DEVT_2232H, DEVT_4232H, DEVT_232H, DEVT_230X, }; #define DEVF_BAUDBITS_HINDEX 0x01 /* Baud bits in high byte of index. */ #define DEVF_BAUDCLK_12M 0X02 /* Base baud clock is 12MHz. */ struct uftdi_softc { struct ucom_super_softc sc_super_ucom; struct ucom_softc sc_ucom; struct usb_device *sc_udev; struct usb_xfer *sc_xfer[UFTDI_N_TRANSFER]; device_t sc_dev; struct mtx sc_mtx; uint32_t sc_unit; uint16_t sc_last_lcr; uint16_t sc_bcdDevice; uint8_t sc_devtype; uint8_t sc_devflags; uint8_t sc_hdrlen; uint8_t sc_msr; uint8_t sc_lsr; uint8_t sc_bitmode; }; struct uftdi_param_config { uint16_t baud_lobits; uint16_t baud_hibits; uint16_t lcr; uint8_t v_start; uint8_t v_stop; uint8_t v_flow; }; /* prototypes */ static device_probe_t uftdi_probe; static device_attach_t uftdi_attach; static device_detach_t uftdi_detach; static void uftdi_free_softc(struct uftdi_softc *); static usb_callback_t uftdi_write_callback; static usb_callback_t uftdi_read_callback; static void uftdi_free(struct ucom_softc *); static void uftdi_cfg_open(struct ucom_softc *); static void uftdi_cfg_close(struct ucom_softc *); static void uftdi_cfg_set_dtr(struct ucom_softc *, uint8_t); static void uftdi_cfg_set_rts(struct ucom_softc *, uint8_t); static void uftdi_cfg_set_break(struct ucom_softc *, uint8_t); static int uftdi_set_parm_soft(struct ucom_softc *, struct termios *, struct uftdi_param_config *); static int uftdi_pre_param(struct ucom_softc *, struct termios *); static void uftdi_cfg_param(struct ucom_softc *, struct termios *); static void uftdi_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *); static int uftdi_reset(struct ucom_softc *, int); static int uftdi_set_bitmode(struct ucom_softc *, uint8_t, uint8_t); static int uftdi_get_bitmode(struct ucom_softc *, uint8_t *, uint8_t *); static int uftdi_set_latency(struct ucom_softc *, int); static int uftdi_get_latency(struct ucom_softc *, int *); static int uftdi_set_event_char(struct ucom_softc *, int); static int uftdi_set_error_char(struct ucom_softc *, int); static int uftdi_ioctl(struct ucom_softc *, uint32_t, caddr_t, int, struct thread *); static void uftdi_start_read(struct ucom_softc *); static void uftdi_stop_read(struct ucom_softc *); static void uftdi_start_write(struct ucom_softc *); static void uftdi_stop_write(struct ucom_softc *); static void uftdi_poll(struct ucom_softc *ucom); static const struct usb_config uftdi_config[UFTDI_N_TRANSFER] = { [UFTDI_BULK_DT_WR] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = UFTDI_OBUFSIZE, .flags = {.pipe_bof = 1,}, .callback = &uftdi_write_callback, }, [UFTDI_BULK_DT_RD] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .bufsize = UFTDI_IBUFSIZE, .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, .callback = &uftdi_read_callback, }, }; static const struct ucom_callback uftdi_callback = { .ucom_cfg_get_status = &uftdi_cfg_get_status, .ucom_cfg_set_dtr = &uftdi_cfg_set_dtr, .ucom_cfg_set_rts = &uftdi_cfg_set_rts, .ucom_cfg_set_break = &uftdi_cfg_set_break, .ucom_cfg_param = &uftdi_cfg_param, .ucom_cfg_open = &uftdi_cfg_open, .ucom_cfg_close = &uftdi_cfg_close, .ucom_pre_param = &uftdi_pre_param, .ucom_ioctl = &uftdi_ioctl, .ucom_start_read = &uftdi_start_read, .ucom_stop_read = &uftdi_stop_read, .ucom_start_write = &uftdi_start_write, .ucom_stop_write = &uftdi_stop_write, .ucom_poll = &uftdi_poll, .ucom_free = &uftdi_free, }; static device_method_t uftdi_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uftdi_probe), DEVMETHOD(device_attach, uftdi_attach), DEVMETHOD(device_detach, uftdi_detach), DEVMETHOD_END }; static devclass_t uftdi_devclass; static driver_t uftdi_driver = { .name = "uftdi", .methods = uftdi_methods, .size = sizeof(struct uftdi_softc), }; static const STRUCT_USB_HOST_ID uftdi_devs[] = { #define UFTDI_DEV(v, p, i) \ { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } UFTDI_DEV(ACTON, SPECTRAPRO, 0), UFTDI_DEV(ALTI2, N3, 0), UFTDI_DEV(ANALOGDEVICES, GNICE, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(ANALOGDEVICES, GNICEPLUS, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(ATMEL, STK541, 0), UFTDI_DEV(BAYER, CONTOUR_CABLE, 0), UFTDI_DEV(BBELECTRONICS, 232USB9M, 0), UFTDI_DEV(BBELECTRONICS, 485USB9F_2W, 0), UFTDI_DEV(BBELECTRONICS, 485USB9F_4W, 0), UFTDI_DEV(BBELECTRONICS, 485USBTB_2W, 0), UFTDI_DEV(BBELECTRONICS, 485USBTB_4W, 0), UFTDI_DEV(BBELECTRONICS, TTL3USB9M, 0), UFTDI_DEV(BBELECTRONICS, TTL5USB9M, 0), UFTDI_DEV(BBELECTRONICS, USO9ML2, 0), UFTDI_DEV(BBELECTRONICS, USO9ML2DR, 0), UFTDI_DEV(BBELECTRONICS, USO9ML2DR_2, 0), UFTDI_DEV(BBELECTRONICS, USOPTL4, 0), UFTDI_DEV(BBELECTRONICS, USOPTL4DR, 0), UFTDI_DEV(BBELECTRONICS, USOPTL4DR2, 0), UFTDI_DEV(BBELECTRONICS, USOTL4, 0), UFTDI_DEV(BBELECTRONICS, USPTL4, 0), UFTDI_DEV(BBELECTRONICS, USTL4, 0), UFTDI_DEV(BBELECTRONICS, ZZ_PROG1_USB, 0), UFTDI_DEV(CONTEC, COM1USBH, 0), UFTDI_DEV(DRESDENELEKTRONIK, SENSORTERMINALBOARD, 0), UFTDI_DEV(DRESDENELEKTRONIK, WIRELESSHANDHELDTERMINAL, 0), UFTDI_DEV(DRESDENELEKTRONIK, DE_RFNODE, 0), UFTDI_DEV(DRESDENELEKTRONIK, LEVELSHIFTERSTICKLOWCOST, 0), UFTDI_DEV(ELEKTOR, FT323R, 0), UFTDI_DEV(EVOLUTION, ER1, 0), UFTDI_DEV(EVOLUTION, HYBRID, 0), UFTDI_DEV(EVOLUTION, RCM4, 0), UFTDI_DEV(FALCOM, SAMBA, 0), UFTDI_DEV(FALCOM, TWIST, 0), UFTDI_DEV(FIC, NEO1973_DEBUG, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FIC, NEO1973_DEBUG, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, 232EX, 0), UFTDI_DEV(FTDI, 232H, 0), UFTDI_DEV(FTDI, 232RL, 0), UFTDI_DEV(FTDI, 4N_GALAXY_DE_1, 0), UFTDI_DEV(FTDI, 4N_GALAXY_DE_2, 0), UFTDI_DEV(FTDI, 4N_GALAXY_DE_3, 0), UFTDI_DEV(FTDI, 8U232AM_ALT, 0), UFTDI_DEV(FTDI, ACCESSO, 0), UFTDI_DEV(FTDI, ACG_HFDUAL, 0), UFTDI_DEV(FTDI, ACTIVE_ROBOTS, 0), UFTDI_DEV(FTDI, ACTZWAVE, 0), UFTDI_DEV(FTDI, AMC232, 0), UFTDI_DEV(FTDI, ARTEMIS, 0), UFTDI_DEV(FTDI, ASK_RDR400, 0), UFTDI_DEV(FTDI, ATIK_ATK16, 0), UFTDI_DEV(FTDI, ATIK_ATK16C, 0), UFTDI_DEV(FTDI, ATIK_ATK16HR, 0), UFTDI_DEV(FTDI, ATIK_ATK16HRC, 0), UFTDI_DEV(FTDI, ATIK_ATK16IC, 0), UFTDI_DEV(FTDI, BCS_SE923, 0), UFTDI_DEV(FTDI, CANDAPTER, 0), UFTDI_DEV(FTDI, CANUSB, 0), UFTDI_DEV(FTDI, CCSICDU20_0, 0), UFTDI_DEV(FTDI, CCSICDU40_1, 0), UFTDI_DEV(FTDI, CCSICDU64_4, 0), UFTDI_DEV(FTDI, CCSLOAD_N_GO_3, 0), UFTDI_DEV(FTDI, CCSMACHX_2, 0), UFTDI_DEV(FTDI, CCSPRIME8_5, 0), UFTDI_DEV(FTDI, CFA_631, 0), UFTDI_DEV(FTDI, CFA_632, 0), UFTDI_DEV(FTDI, CFA_633, 0), UFTDI_DEV(FTDI, CFA_634, 0), UFTDI_DEV(FTDI, CFA_635, 0), UFTDI_DEV(FTDI, CHAMSYS_24_MASTER_WING, 0), UFTDI_DEV(FTDI, CHAMSYS_MAXI_WING, 0), UFTDI_DEV(FTDI, CHAMSYS_MEDIA_WING, 0), UFTDI_DEV(FTDI, CHAMSYS_MIDI_TIMECODE, 0), UFTDI_DEV(FTDI, CHAMSYS_MINI_WING, 0), UFTDI_DEV(FTDI, CHAMSYS_PC_WING, 0), UFTDI_DEV(FTDI, CHAMSYS_USB_DMX, 0), UFTDI_DEV(FTDI, CHAMSYS_WING, 0), UFTDI_DEV(FTDI, COM4SM, 0), UFTDI_DEV(FTDI, CONVERTER_0, 0), UFTDI_DEV(FTDI, CONVERTER_1, 0), UFTDI_DEV(FTDI, CONVERTER_2, 0), UFTDI_DEV(FTDI, CONVERTER_3, 0), UFTDI_DEV(FTDI, CONVERTER_4, 0), UFTDI_DEV(FTDI, CONVERTER_5, 0), UFTDI_DEV(FTDI, CONVERTER_6, 0), UFTDI_DEV(FTDI, CONVERTER_7, 0), UFTDI_DEV(FTDI, CTI_USB_MINI_485, 0), UFTDI_DEV(FTDI, CTI_USB_NANO_485, 0), UFTDI_DEV(FTDI, DMX4ALL, 0), UFTDI_DEV(FTDI, DOMINTELL_DGQG, 0), UFTDI_DEV(FTDI, DOMINTELL_DUSB, 0), UFTDI_DEV(FTDI, DOTEC, 0), UFTDI_DEV(FTDI, ECLO_COM_1WIRE, 0), UFTDI_DEV(FTDI, ECO_PRO_CDS, 0), UFTDI_DEV(FTDI, EISCOU, 0), UFTDI_DEV(FTDI, ELSTER_UNICOM, 0), UFTDI_DEV(FTDI, ELV_ALC8500, 0), UFTDI_DEV(FTDI, ELV_CLI7000, 0), UFTDI_DEV(FTDI, ELV_CSI8, 0), UFTDI_DEV(FTDI, ELV_EC3000, 0), UFTDI_DEV(FTDI, ELV_EM1000DL, 0), UFTDI_DEV(FTDI, ELV_EM1010PC, 0), UFTDI_DEV(FTDI, ELV_FEM, 0), UFTDI_DEV(FTDI, ELV_FHZ1000PC, 0), UFTDI_DEV(FTDI, ELV_FHZ1300PC, 0), UFTDI_DEV(FTDI, ELV_FM3RX, 0), UFTDI_DEV(FTDI, ELV_FS20SIG, 0), UFTDI_DEV(FTDI, ELV_HS485, 0), UFTDI_DEV(FTDI, ELV_KL100, 0), UFTDI_DEV(FTDI, ELV_MSM1, 0), UFTDI_DEV(FTDI, ELV_PCD200, 0), UFTDI_DEV(FTDI, ELV_PCK100, 0), UFTDI_DEV(FTDI, ELV_PPS7330, 0), UFTDI_DEV(FTDI, ELV_RFP500, 0), UFTDI_DEV(FTDI, ELV_T1100, 0), UFTDI_DEV(FTDI, ELV_TFD128, 0), UFTDI_DEV(FTDI, ELV_TFM100, 0), UFTDI_DEV(FTDI, ELV_TWS550, 0), UFTDI_DEV(FTDI, ELV_UAD8, 0), UFTDI_DEV(FTDI, ELV_UDA7, 0), UFTDI_DEV(FTDI, ELV_UDF77, 0), UFTDI_DEV(FTDI, ELV_UIO88, 0), UFTDI_DEV(FTDI, ELV_ULA200, 0), UFTDI_DEV(FTDI, ELV_UM100, 0), UFTDI_DEV(FTDI, ELV_UMS100, 0), UFTDI_DEV(FTDI, ELV_UO100, 0), UFTDI_DEV(FTDI, ELV_UR100, 0), UFTDI_DEV(FTDI, ELV_USI2, 0), UFTDI_DEV(FTDI, ELV_USR, 0), UFTDI_DEV(FTDI, ELV_UTP8, 0), UFTDI_DEV(FTDI, ELV_WS300PC, 0), UFTDI_DEV(FTDI, ELV_WS444PC, 0), UFTDI_DEV(FTDI, ELV_WS500, 0), UFTDI_DEV(FTDI, ELV_WS550, 0), UFTDI_DEV(FTDI, ELV_WS777, 0), UFTDI_DEV(FTDI, ELV_WS888, 0), UFTDI_DEV(FTDI, EMCU2D, 0), UFTDI_DEV(FTDI, EMCU2H, 0), UFTDI_DEV(FTDI, FUTURE_0, 0), UFTDI_DEV(FTDI, FUTURE_1, 0), UFTDI_DEV(FTDI, FUTURE_2, 0), UFTDI_DEV(FTDI, GAMMASCOUT, 0), UFTDI_DEV(FTDI, GENERIC, 0), UFTDI_DEV(FTDI, GUDEADS_E808, 0), UFTDI_DEV(FTDI, GUDEADS_E809, 0), UFTDI_DEV(FTDI, GUDEADS_E80A, 0), UFTDI_DEV(FTDI, GUDEADS_E80B, 0), UFTDI_DEV(FTDI, GUDEADS_E80C, 0), UFTDI_DEV(FTDI, GUDEADS_E80D, 0), UFTDI_DEV(FTDI, GUDEADS_E80E, 0), UFTDI_DEV(FTDI, GUDEADS_E80F, 0), UFTDI_DEV(FTDI, GUDEADS_E88D, 0), UFTDI_DEV(FTDI, GUDEADS_E88E, 0), UFTDI_DEV(FTDI, GUDEADS_E88F, 0), UFTDI_DEV(FTDI, HD_RADIO, 0), UFTDI_DEV(FTDI, HO720, 0), UFTDI_DEV(FTDI, HO730, 0), UFTDI_DEV(FTDI, HO820, 0), UFTDI_DEV(FTDI, HO870, 0), UFTDI_DEV(FTDI, IBS_APP70, 0), UFTDI_DEV(FTDI, IBS_PCMCIA, 0), UFTDI_DEV(FTDI, IBS_PEDO, 0), UFTDI_DEV(FTDI, IBS_PICPRO, 0), UFTDI_DEV(FTDI, IBS_PK1, 0), UFTDI_DEV(FTDI, IBS_PROD, 0), UFTDI_DEV(FTDI, IBS_RS232MON, 0), UFTDI_DEV(FTDI, IBS_US485, 0), UFTDI_DEV(FTDI, IPLUS, 0), UFTDI_DEV(FTDI, IPLUS2, 0), UFTDI_DEV(FTDI, IRTRANS, 0), UFTDI_DEV(FTDI, KBS, 0), UFTDI_DEV(FTDI, KTLINK, 0), UFTDI_DEV(FTDI, LENZ_LIUSB, 0), UFTDI_DEV(FTDI, LK202, 0), UFTDI_DEV(FTDI, LK204, 0), UFTDI_DEV(FTDI, LM3S_DEVEL_BOARD, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, LM3S_EVAL_BOARD, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, LM3S_ICDI_B_BOARD, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, MASTERDEVEL2, 0), UFTDI_DEV(FTDI, MAXSTREAM, 0), UFTDI_DEV(FTDI, MHAM_DB9, 0), UFTDI_DEV(FTDI, MHAM_IC, 0), UFTDI_DEV(FTDI, MHAM_KW, 0), UFTDI_DEV(FTDI, MHAM_RS232, 0), UFTDI_DEV(FTDI, MHAM_Y6, 0), UFTDI_DEV(FTDI, MHAM_Y8, 0), UFTDI_DEV(FTDI, MHAM_Y9, 0), UFTDI_DEV(FTDI, MHAM_YS, 0), UFTDI_DEV(FTDI, MICRO_CHAMELEON, 0), UFTDI_DEV(FTDI, MTXORB_5, 0), UFTDI_DEV(FTDI, MTXORB_6, 0), UFTDI_DEV(FTDI, MX2_3, 0), UFTDI_DEV(FTDI, MX4_5, 0), UFTDI_DEV(FTDI, NXTCAM, 0), UFTDI_DEV(FTDI, OCEANIC, 0), UFTDI_DEV(FTDI, OOCDLINK, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, OPENDCC, 0), UFTDI_DEV(FTDI, OPENDCC_GATEWAY, 0), UFTDI_DEV(FTDI, OPENDCC_GBM, 0), UFTDI_DEV(FTDI, OPENDCC_SNIFFER, 0), UFTDI_DEV(FTDI, OPENDCC_THROTTLE, 0), UFTDI_DEV(FTDI, PCDJ_DAC2, 0), UFTDI_DEV(FTDI, PCMSFU, 0), UFTDI_DEV(FTDI, PERLE_ULTRAPORT, 0), UFTDI_DEV(FTDI, PHI_FISCO, 0), UFTDI_DEV(FTDI, PIEGROUP, 0), UFTDI_DEV(FTDI, PROPOX_JTAGCABLEII, 0), UFTDI_DEV(FTDI, R2000KU_TRUE_RNG, 0), UFTDI_DEV(FTDI, R2X0, 0), UFTDI_DEV(FTDI, RELAIS, 0), UFTDI_DEV(FTDI, REU_TINY, 0), UFTDI_DEV(FTDI, RMP200, 0), UFTDI_DEV(FTDI, RM_CANVIEW, 0), UFTDI_DEV(FTDI, RRCIRKITS_LOCOBUFFER, 0), UFTDI_DEV(FTDI, SCIENCESCOPE_HS_LOGBOOK, 0), UFTDI_DEV(FTDI, SCIENCESCOPE_LOGBOOKML, 0), UFTDI_DEV(FTDI, SCIENCESCOPE_LS_LOGBOOK, 0), UFTDI_DEV(FTDI, SCS_DEVICE_0, 0), UFTDI_DEV(FTDI, SCS_DEVICE_1, 0), UFTDI_DEV(FTDI, SCS_DEVICE_2, 0), UFTDI_DEV(FTDI, SCS_DEVICE_3, 0), UFTDI_DEV(FTDI, SCS_DEVICE_4, 0), UFTDI_DEV(FTDI, SCS_DEVICE_5, 0), UFTDI_DEV(FTDI, SCS_DEVICE_6, 0), UFTDI_DEV(FTDI, SCS_DEVICE_7, 0), UFTDI_DEV(FTDI, SCX8_USB_PHOENIX, 0), UFTDI_DEV(FTDI, SDMUSBQSS, 0), UFTDI_DEV(FTDI, SEMC_DSS20, 0), UFTDI_DEV(FTDI, SERIAL_2232C, UFTDI_JTAG_CHECK_STRING), UFTDI_DEV(FTDI, SERIAL_2232D, 0), UFTDI_DEV(FTDI, SERIAL_232RL, 0), UFTDI_DEV(FTDI, SERIAL_4232H, 0), UFTDI_DEV(FTDI, SERIAL_8U100AX, 0), UFTDI_DEV(FTDI, SERIAL_8U232AM, 0), UFTDI_DEV(FTDI, SERIAL_8U232AM4, 0), UFTDI_DEV(FTDI, SIGNALYZER_SH2, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, SIGNALYZER_SH4, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, SIGNALYZER_SLITE, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, SIGNALYZER_ST, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, SPECIAL_1, 0), UFTDI_DEV(FTDI, SPECIAL_3, 0), UFTDI_DEV(FTDI, SPECIAL_4, 0), UFTDI_DEV(FTDI, SPROG_II, 0), UFTDI_DEV(FTDI, SR_RADIO, 0), UFTDI_DEV(FTDI, SUUNTO_SPORTS, 0), UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13M, 0), UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13S, 0), UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13U, 0), UFTDI_DEV(FTDI, TAVIR_STK500, 0), UFTDI_DEV(FTDI, TERATRONIK_D2XX, 0), UFTDI_DEV(FTDI, TERATRONIK_VCP, 0), UFTDI_DEV(FTDI, THORLABS, 0), UFTDI_DEV(FTDI, TNC_X, 0), UFTDI_DEV(FTDI, TTUSB, 0), UFTDI_DEV(FTDI, TURTELIZER2, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, UOPTBR, 0), UFTDI_DEV(FTDI, USBSERIAL, 0), UFTDI_DEV(FTDI, USBX_707, 0), UFTDI_DEV(FTDI, USB_UIRT, 0), UFTDI_DEV(FTDI, USINT_CAT, 0), UFTDI_DEV(FTDI, USINT_RS232, 0), UFTDI_DEV(FTDI, USINT_WKEY, 0), UFTDI_DEV(FTDI, VARDAAN, 0), UFTDI_DEV(FTDI, VNHCPCUSB_D, 0), UFTDI_DEV(FTDI, WESTREX_MODEL_777, 0), UFTDI_DEV(FTDI, WESTREX_MODEL_8900F, 0), UFTDI_DEV(FTDI, XDS100V2, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, XDS100V3, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(FTDI, XF_547, 0), UFTDI_DEV(FTDI, XF_640, 0), UFTDI_DEV(FTDI, XF_642, 0), UFTDI_DEV(FTDI, XM_RADIO, 0), UFTDI_DEV(FTDI, YEI_SERVOCENTER31, 0), UFTDI_DEV(GNOTOMETRICS, USB, 0), UFTDI_DEV(ICOM, SP1, 0), UFTDI_DEV(ICOM, OPC_U_UC, 0), UFTDI_DEV(ICOM, RP2C1, 0), UFTDI_DEV(ICOM, RP2C2, 0), UFTDI_DEV(ICOM, RP2D, 0), UFTDI_DEV(ICOM, RP2KVR, 0), UFTDI_DEV(ICOM, RP2KVT, 0), UFTDI_DEV(ICOM, RP2VR, 0), UFTDI_DEV(ICOM, RP2VT, 0), UFTDI_DEV(ICOM, RP4KVR, 0), UFTDI_DEV(ICOM, RP4KVT, 0), UFTDI_DEV(IDTECH, IDT1221U, 0), UFTDI_DEV(INTERBIOMETRICS, IOBOARD, 0), UFTDI_DEV(INTERBIOMETRICS, MINI_IOBOARD, 0), UFTDI_DEV(INTREPIDCS, NEOVI, 0), UFTDI_DEV(INTREPIDCS, VALUECAN, 0), UFTDI_DEV(IONICS, PLUGCOMPUTER, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(JETI, SPC1201, 0), UFTDI_DEV(KOBIL, CONV_B1, 0), UFTDI_DEV(KOBIL, CONV_KAAN, 0), UFTDI_DEV(LARSENBRUSGAARD, ALTITRACK, 0), UFTDI_DEV(MARVELL, SHEEVAPLUG, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0100, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0101, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0102, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0103, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0104, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0105, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0106, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0107, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0108, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0109, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010C, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0110, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0111, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0112, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0113, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0114, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0115, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0116, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0117, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0118, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0119, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011C, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0120, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0121, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0122, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0123, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0124, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0125, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0126, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0128, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0129, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0130, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0131, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0132, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0133, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0134, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0135, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0136, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0137, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0138, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0139, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013C, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0140, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0141, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0142, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0143, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0144, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0145, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0146, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0147, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0148, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0149, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014C, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0150, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0151, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0152, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0159, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015C, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0160, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0161, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0162, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0163, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0164, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0165, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0166, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0167, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0168, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0169, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016C, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0170, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0171, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0172, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0173, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0174, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0175, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0176, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0177, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0178, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0179, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017C, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0180, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0181, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0182, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0183, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0184, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0185, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0186, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0187, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0188, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0189, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018C, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0190, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0191, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0192, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0193, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0194, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0195, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0196, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0197, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0198, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0199, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019A, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019B, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019C, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019D, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019E, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019F, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A0, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A1, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A2, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A3, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A4, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A5, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A6, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A7, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A8, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A9, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AA, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AB, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AC, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AD, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AE, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AF, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B0, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B1, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B2, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B3, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B4, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B5, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B6, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B7, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B8, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B9, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BA, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BB, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BC, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BD, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BE, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BF, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C0, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C1, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C2, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C3, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C4, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C5, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C6, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C7, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C8, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C9, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CA, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CB, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CC, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CD, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CE, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CF, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D0, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D1, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D2, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D3, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D4, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D5, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D6, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D7, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D8, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D9, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DA, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DB, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DC, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DD, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DE, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DF, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E0, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E1, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E2, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E3, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E4, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E5, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E6, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E7, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E8, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E9, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EA, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EB, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EC, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01ED, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EE, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EF, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F0, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F1, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F2, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F3, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F4, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F5, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F6, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F7, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F8, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F9, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FA, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FB, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FC, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FD, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FE, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FF, 0), UFTDI_DEV(MATRIXORBITAL, MOUA, 0), UFTDI_DEV(MELCO, PCOPRS1, 0), UFTDI_DEV(METAGEEK, TELLSTICK, 0), UFTDI_DEV(MOBILITY, USB_SERIAL, 0), UFTDI_DEV(OLIMEX, ARM_USB_OCD, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(OLIMEX, ARM_USB_OCD_H, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(OPTO, CRD7734, 0), UFTDI_DEV(OPTO, CRD7734_1, 0), UFTDI_DEV(PAPOUCH, AD4USB, 0), UFTDI_DEV(PAPOUCH, AP485, 0), UFTDI_DEV(PAPOUCH, AP485_2, 0), UFTDI_DEV(PAPOUCH, DRAK5, 0), UFTDI_DEV(PAPOUCH, DRAK6, 0), UFTDI_DEV(PAPOUCH, GMSR, 0), UFTDI_DEV(PAPOUCH, GMUX, 0), UFTDI_DEV(PAPOUCH, IRAMP, 0), UFTDI_DEV(PAPOUCH, LEC, 0), UFTDI_DEV(PAPOUCH, MU, 0), UFTDI_DEV(PAPOUCH, QUIDO10X1, 0), UFTDI_DEV(PAPOUCH, QUIDO2X16, 0), UFTDI_DEV(PAPOUCH, QUIDO2X2, 0), UFTDI_DEV(PAPOUCH, QUIDO30X3, 0), UFTDI_DEV(PAPOUCH, QUIDO3X32, 0), UFTDI_DEV(PAPOUCH, QUIDO4X4, 0), UFTDI_DEV(PAPOUCH, QUIDO60X3, 0), UFTDI_DEV(PAPOUCH, QUIDO8X8, 0), UFTDI_DEV(PAPOUCH, SB232, 0), UFTDI_DEV(PAPOUCH, SB422, 0), UFTDI_DEV(PAPOUCH, SB422_2, 0), UFTDI_DEV(PAPOUCH, SB485, 0), UFTDI_DEV(PAPOUCH, SB485C, 0), UFTDI_DEV(PAPOUCH, SB485S, 0), UFTDI_DEV(PAPOUCH, SB485_2, 0), UFTDI_DEV(PAPOUCH, SIMUKEY, 0), UFTDI_DEV(PAPOUCH, TMU, 0), UFTDI_DEV(PAPOUCH, UPSUSB, 0), UFTDI_DEV(POSIFLEX, PP7000, 0), UFTDI_DEV(QIHARDWARE, JTAGSERIAL, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(RATOC, REXUSB60F, 0), UFTDI_DEV(RTSYSTEMS, CT29B, 0), UFTDI_DEV(RTSYSTEMS, SERIAL_VX7, 0), UFTDI_DEV(SEALEVEL, 2101, 0), UFTDI_DEV(SEALEVEL, 2102, 0), UFTDI_DEV(SEALEVEL, 2103, 0), UFTDI_DEV(SEALEVEL, 2104, 0), UFTDI_DEV(SEALEVEL, 2106, 0), UFTDI_DEV(SEALEVEL, 2201_1, 0), UFTDI_DEV(SEALEVEL, 2201_2, 0), UFTDI_DEV(SEALEVEL, 2202_1, 0), UFTDI_DEV(SEALEVEL, 2202_2, 0), UFTDI_DEV(SEALEVEL, 2203_1, 0), UFTDI_DEV(SEALEVEL, 2203_2, 0), UFTDI_DEV(SEALEVEL, 2401_1, 0), UFTDI_DEV(SEALEVEL, 2401_2, 0), UFTDI_DEV(SEALEVEL, 2401_3, 0), UFTDI_DEV(SEALEVEL, 2401_4, 0), UFTDI_DEV(SEALEVEL, 2402_1, 0), UFTDI_DEV(SEALEVEL, 2402_2, 0), UFTDI_DEV(SEALEVEL, 2402_3, 0), UFTDI_DEV(SEALEVEL, 2402_4, 0), UFTDI_DEV(SEALEVEL, 2403_1, 0), UFTDI_DEV(SEALEVEL, 2403_2, 0), UFTDI_DEV(SEALEVEL, 2403_3, 0), UFTDI_DEV(SEALEVEL, 2403_4, 0), UFTDI_DEV(SEALEVEL, 2801_1, 0), UFTDI_DEV(SEALEVEL, 2801_2, 0), UFTDI_DEV(SEALEVEL, 2801_3, 0), UFTDI_DEV(SEALEVEL, 2801_4, 0), UFTDI_DEV(SEALEVEL, 2801_5, 0), UFTDI_DEV(SEALEVEL, 2801_6, 0), UFTDI_DEV(SEALEVEL, 2801_7, 0), UFTDI_DEV(SEALEVEL, 2801_8, 0), UFTDI_DEV(SEALEVEL, 2802_1, 0), UFTDI_DEV(SEALEVEL, 2802_2, 0), UFTDI_DEV(SEALEVEL, 2802_3, 0), UFTDI_DEV(SEALEVEL, 2802_4, 0), UFTDI_DEV(SEALEVEL, 2802_5, 0), UFTDI_DEV(SEALEVEL, 2802_6, 0), UFTDI_DEV(SEALEVEL, 2802_7, 0), UFTDI_DEV(SEALEVEL, 2802_8, 0), UFTDI_DEV(SEALEVEL, 2803_1, 0), UFTDI_DEV(SEALEVEL, 2803_2, 0), UFTDI_DEV(SEALEVEL, 2803_3, 0), UFTDI_DEV(SEALEVEL, 2803_4, 0), UFTDI_DEV(SEALEVEL, 2803_5, 0), UFTDI_DEV(SEALEVEL, 2803_6, 0), UFTDI_DEV(SEALEVEL, 2803_7, 0), UFTDI_DEV(SEALEVEL, 2803_8, 0), UFTDI_DEV(SIIG2, DK201, 0), UFTDI_DEV(SIIG2, US2308, 0), UFTDI_DEV(TESTO, USB_INTERFACE, 0), UFTDI_DEV(TML, USB_SERIAL, 0), UFTDI_DEV(TTI, QL355P, 0), UFTDI_DEV(UNKNOWN4, NF_RIC, 0), #undef UFTDI_DEV }; DRIVER_MODULE(uftdi, uhub, uftdi_driver, uftdi_devclass, NULL, NULL); MODULE_DEPEND(uftdi, ucom, 1, 1, 1); MODULE_DEPEND(uftdi, usb, 1, 1, 1); MODULE_VERSION(uftdi, 1); USB_PNP_HOST_INFO(uftdi_devs); /* * Jtag product name strings table. Some products have one or more interfaces * dedicated to jtag or gpio, but use a product ID that's the same as other * products which don't. They are marked with a flag in the table above, and * the following string table is checked for flagged products. The string check * is done with strstr(); in effect there is an implicit wildcard at the * beginning and end of each product name string in table. */ static const struct jtag_by_name { const char * product_name; uint32_t jtag_interfaces; } jtag_products_by_name[] = { /* TI Beaglebone and TI XDS100Vn jtag product line. */ {"XDS100V", UFTDI_JTAG_IFACE(0)}, }; /* * Set up a sysctl and tunable to en/disable the feature of skipping the * creation of tty devices for jtag interfaces. Enabled by default. */ static int skip_jtag_interfaces = 1; SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, skip_jtag_interfaces, CTLFLAG_RWTUN, &skip_jtag_interfaces, 1, "Skip creating tty devices for jtag interfaces"); static boolean_t is_jtag_interface(struct usb_attach_arg *uaa, const struct usb_device_id *id) { int i, iface_bit; const char * product_name; const struct jtag_by_name *jbn; /* We only allocate 8 flag bits for jtag interface flags. */ if (uaa->info.bIfaceIndex >= UFTDI_JTAG_IFACES_MAX) return (0); iface_bit = UFTDI_JTAG_IFACE(uaa->info.bIfaceIndex); /* * If requested, search the name strings table and use the interface * bits from that table when the product name string matches, else use * the jtag interface bits from the main ID table. */ if ((id->driver_info & UFTDI_JTAG_MASK) == UFTDI_JTAG_CHECK_STRING) { product_name = usb_get_product(uaa->device); for (i = 0; i < nitems(jtag_products_by_name); i++) { jbn = &jtag_products_by_name[i]; if (strstr(product_name, jbn->product_name) != NULL && (jbn->jtag_interfaces & iface_bit) != 0) return (1); } } else if ((id->driver_info & iface_bit) != 0) return (1); return (0); } /* * Set up softc fields whose value depends on the device type. * * Note that the 2232C and 2232D devices are the same for our purposes. In the * silicon the difference is that the D series has CPU FIFO mode and C doesn't. * I haven't found any way of determining the C/D difference from info provided * by the chip other than trying to set CPU FIFO mode and having it work or not. * * Due to a hardware bug, a 232B chip without an eeprom reports itself as a * 232A, but if the serial number is also zero we know it's really a 232B. */ static void uftdi_devtype_setup(struct uftdi_softc *sc, struct usb_attach_arg *uaa) { struct usb_device_descriptor *dd; sc->sc_bcdDevice = uaa->info.bcdDevice; switch (uaa->info.bcdDevice) { case 0x200: dd = usbd_get_device_descriptor(sc->sc_udev); if (dd->iSerialNumber == 0) { sc->sc_devtype = DEVT_232B; } else { sc->sc_devtype = DEVT_232A; } sc->sc_ucom.sc_portno = 0; break; case 0x400: sc->sc_devtype = DEVT_232B; sc->sc_ucom.sc_portno = 0; break; case 0x500: sc->sc_devtype = DEVT_2232D; sc->sc_devflags |= DEVF_BAUDBITS_HINDEX; sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum; break; case 0x600: sc->sc_devtype = DEVT_232R; sc->sc_ucom.sc_portno = 0; break; case 0x700: sc->sc_devtype = DEVT_2232H; sc->sc_devflags |= DEVF_BAUDBITS_HINDEX | DEVF_BAUDCLK_12M; sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum; break; case 0x800: sc->sc_devtype = DEVT_4232H; sc->sc_devflags |= DEVF_BAUDBITS_HINDEX | DEVF_BAUDCLK_12M; sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum; break; case 0x900: sc->sc_devtype = DEVT_232H; sc->sc_devflags |= DEVF_BAUDBITS_HINDEX | DEVF_BAUDCLK_12M; sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum; break; case 0x1000: sc->sc_devtype = DEVT_230X; sc->sc_devflags |= DEVF_BAUDBITS_HINDEX; sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum; break; default: if (uaa->info.bcdDevice < 0x200) { sc->sc_devtype = DEVT_SIO; sc->sc_hdrlen = 1; } else { sc->sc_devtype = DEVT_232R; device_printf(sc->sc_dev, "Warning: unknown FTDI " "device type, bcdDevice=0x%04x, assuming 232R\n", uaa->info.bcdDevice); } sc->sc_ucom.sc_portno = 0; break; } } static int uftdi_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); const struct usb_device_id *id; if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UFTDI_CONFIG_INDEX) { return (ENXIO); } /* * Attach to all present interfaces unless this is a JTAG one, which * we leave for userland. */ id = usbd_lookup_id_by_info(uftdi_devs, sizeof(uftdi_devs), &uaa->info); if (id == NULL) return (ENXIO); if (skip_jtag_interfaces && is_jtag_interface(uaa, id)) { printf("%s: skipping JTAG interface #%d for '%s' at %u.%u\n", device_get_name(dev), uaa->info.bIfaceIndex, usb_get_product(uaa->device), usbd_get_bus_index(uaa->device), usbd_get_device_index(uaa->device)); return (ENXIO); } uaa->driver_info = id->driver_info; return (BUS_PROBE_SPECIFIC); } static int uftdi_attach(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct uftdi_softc *sc = device_get_softc(dev); int error; DPRINTF("\n"); sc->sc_udev = uaa->device; sc->sc_dev = dev; sc->sc_unit = device_get_unit(dev); sc->sc_bitmode = UFTDI_BITMODE_NONE; device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, "uftdi", NULL, MTX_DEF); ucom_ref(&sc->sc_super_ucom); uftdi_devtype_setup(sc, uaa); error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, sc->sc_xfer, uftdi_config, UFTDI_N_TRANSFER, sc, &sc->sc_mtx); if (error) { device_printf(dev, "allocating USB " "transfers failed\n"); goto detach; } /* clear stall at first run */ mtx_lock(&sc->sc_mtx); usbd_xfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_WR]); usbd_xfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_RD]); mtx_unlock(&sc->sc_mtx); /* set a valid "lcr" value */ sc->sc_last_lcr = (FTDI_SIO_SET_DATA_STOP_BITS_2 | FTDI_SIO_SET_DATA_PARITY_NONE | FTDI_SIO_SET_DATA_BITS(8)); + /* Indicate tx bits in sc_lsr can be used to determine busy vs idle. */ + ucom_use_lsr_txbits(&sc->sc_ucom); + error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, &uftdi_callback, &sc->sc_mtx); if (error) { goto detach; } ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); return (0); /* success */ detach: uftdi_detach(dev); return (ENXIO); } static int uftdi_detach(device_t dev) { struct uftdi_softc *sc = device_get_softc(dev); ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); usbd_transfer_unsetup(sc->sc_xfer, UFTDI_N_TRANSFER); device_claim_softc(dev); uftdi_free_softc(sc); return (0); } UCOM_UNLOAD_DRAIN(uftdi); static void uftdi_free_softc(struct uftdi_softc *sc) { if (ucom_unref(&sc->sc_super_ucom)) { mtx_destroy(&sc->sc_mtx); device_free_softc(sc); } } static void uftdi_free(struct ucom_softc *ucom) { uftdi_free_softc(ucom->sc_parent); } static void uftdi_cfg_open(struct ucom_softc *ucom) { /* * This do-nothing open routine exists for the sole purpose of this * DPRINTF() so that you can see the point at which open gets called * when debugging is enabled. */ DPRINTF("\n"); } static void uftdi_cfg_close(struct ucom_softc *ucom) { /* * This do-nothing close routine exists for the sole purpose of this * DPRINTF() so that you can see the point at which close gets called * when debugging is enabled. */ DPRINTF("\n"); } static void uftdi_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct uftdi_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; uint32_t pktlen; uint32_t buflen; uint8_t buf[1]; DPRINTFN(3, "\n"); switch (USB_GET_STATE(xfer)) { default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); } /* FALLTHROUGH */ case USB_ST_SETUP: case USB_ST_TRANSFERRED: /* * If output packets don't require headers (the common case) we * can just load the buffer up with payload bytes all at once. * Otherwise, loop to format packets into the buffer while there * is data available, and room for a packet header and at least * one byte of payload. * * NOTE: The FTDI chip doesn't accept zero length * packets. This cannot happen because the "pktlen" * will always be non-zero when "ucom_get_data()" * returns non-zero which we check below. */ pc = usbd_xfer_get_frame(xfer, 0); if (sc->sc_hdrlen == 0) { if (ucom_get_data(&sc->sc_ucom, pc, 0, UFTDI_OBUFSIZE, &buflen) == 0) break; } else { buflen = 0; while (buflen < UFTDI_OBUFSIZE - sc->sc_hdrlen - 1 && ucom_get_data(&sc->sc_ucom, pc, buflen + sc->sc_hdrlen, UFTDI_OPKTSIZE - sc->sc_hdrlen, &pktlen) != 0) { buf[0] = FTDI_OUT_TAG(pktlen, sc->sc_ucom.sc_portno); usbd_copy_in(pc, buflen, buf, 1); buflen += pktlen + sc->sc_hdrlen; } } if (buflen != 0) { usbd_xfer_set_frame_len(xfer, 0, buflen); usbd_transfer_submit(xfer); } break; } } static void uftdi_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct uftdi_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; uint8_t buf[2]; uint8_t ftdi_msr; uint8_t msr; uint8_t lsr; int buflen; int pktlen; int pktmax; int offset; DPRINTFN(3, "\n"); usbd_xfer_status(xfer, &buflen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: if (buflen < UFTDI_IHDRSIZE) goto tr_setup; pc = usbd_xfer_get_frame(xfer, 0); pktmax = xfer->max_packet_size - UFTDI_IHDRSIZE; lsr = 0; msr = 0; offset = 0; /* * Extract packet headers and payload bytes from the buffer. - * Feed payload bytes to ucom/tty layer; OR-accumulate header - * status bits which are transient and could toggle with each - * packet. After processing all packets in the buffer, process - * the accumulated transient MSR and LSR values along with the + * Feed payload bytes to ucom/tty layer; OR-accumulate the + * receiver-related header status bits which are transient and + * could toggle with each packet, but for transmitter-related + * bits keep only the ones from the last packet. + * + * After processing all packets in the buffer, process the + * accumulated transient MSR and LSR values along with the * non-transient bits from the last packet header. */ while (buflen >= UFTDI_IHDRSIZE) { usbd_copy_out(pc, offset, buf, UFTDI_IHDRSIZE); offset += UFTDI_IHDRSIZE; buflen -= UFTDI_IHDRSIZE; + lsr &= ~(ULSR_TXRDY | ULSR_TSRE); lsr |= FTDI_GET_LSR(buf); if (FTDI_GET_MSR(buf) & FTDI_SIO_RI_MASK) msr |= SER_RI; pktlen = min(buflen, pktmax); if (pktlen != 0) { ucom_put_data(&sc->sc_ucom, pc, offset, pktlen); offset += pktlen; buflen -= pktlen; } } ftdi_msr = FTDI_GET_MSR(buf); if (ftdi_msr & FTDI_SIO_CTS_MASK) msr |= SER_CTS; if (ftdi_msr & FTDI_SIO_DSR_MASK) msr |= SER_DSR; if (ftdi_msr & FTDI_SIO_RI_MASK) msr |= SER_RI; if (ftdi_msr & FTDI_SIO_RLSD_MASK) msr |= SER_DCD; - if ((sc->sc_msr != msr) || - ((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) { + if (sc->sc_msr != msr || sc->sc_lsr != lsr) { DPRINTF("status change msr=0x%02x (0x%02x) " "lsr=0x%02x (0x%02x)\n", msr, sc->sc_msr, lsr, sc->sc_lsr); sc->sc_msr = msr; sc->sc_lsr = lsr; ucom_status_change(&sc->sc_ucom); } /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); return; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } return; } } static void uftdi_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) { struct uftdi_softc *sc = ucom->sc_parent; uint16_t wIndex = ucom->sc_portno; uint16_t wValue; struct usb_device_request req; DPRINTFN(2, "DTR=%u\n", onoff); wValue = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW; req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_MODEM_CTRL; USETW(req.wValue, wValue); USETW(req.wIndex, wIndex); USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } static void uftdi_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) { struct uftdi_softc *sc = ucom->sc_parent; uint16_t wIndex = ucom->sc_portno; uint16_t wValue; struct usb_device_request req; DPRINTFN(2, "RTS=%u\n", onoff); wValue = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW; req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_MODEM_CTRL; USETW(req.wValue, wValue); USETW(req.wIndex, wIndex); USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } static void uftdi_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) { struct uftdi_softc *sc = ucom->sc_parent; uint16_t wIndex = ucom->sc_portno; uint16_t wValue; struct usb_device_request req; DPRINTFN(2, "BREAK=%u\n", onoff); if (onoff) { sc->sc_last_lcr |= FTDI_SIO_SET_BREAK; } else { sc->sc_last_lcr &= ~FTDI_SIO_SET_BREAK; } wValue = sc->sc_last_lcr; req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_SET_DATA; USETW(req.wValue, wValue); USETW(req.wIndex, wIndex); USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } /* * Return true if the given speed is within operational tolerance of the target * speed. FTDI recommends that the hardware speed be within 3% of nominal. */ static inline boolean_t uftdi_baud_within_tolerance(uint64_t speed, uint64_t target) { return ((speed >= (target * 100) / 103) && (speed <= (target * 100) / 97)); } static int uftdi_sio_encode_baudrate(struct uftdi_softc *sc, speed_t speed, struct uftdi_param_config *cfg) { u_int i; const speed_t sio_speeds[] = { 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 }; /* * The original SIO chips were limited to a small choice of speeds * listed in an internal table of speeds chosen by an index value. */ for (i = 0; i < nitems(sio_speeds); ++i) { if (speed == sio_speeds[i]) { cfg->baud_lobits = i; cfg->baud_hibits = 0; return (0); } } return (ERANGE); } static int uftdi_encode_baudrate(struct uftdi_softc *sc, speed_t speed, struct uftdi_param_config *cfg) { static const uint8_t encoded_fraction[8] = {0, 3, 2, 4, 1, 5, 6, 7}; static const uint8_t roundoff_232a[16] = { 0, 1, 0, 1, 0, -1, 2, 1, 0, -1, -2, -3, 4, 3, 2, 1, }; uint32_t clk, divisor, fastclk_flag, frac, hwspeed; /* * If this chip has the fast clock capability and the speed is within * range, use the 12MHz clock, otherwise the standard clock is 3MHz. */ if ((sc->sc_devflags & DEVF_BAUDCLK_12M) && speed >= 1200) { clk = 12000000; fastclk_flag = (1 << 17); } else { clk = 3000000; fastclk_flag = 0; } /* * Make sure the requested speed is reachable with the available clock * and a 14-bit divisor. */ if (speed < (clk >> 14) || speed > clk) return (ERANGE); /* * Calculate the divisor, initially yielding a fixed point number with a * 4-bit (1/16ths) fraction, then round it to the nearest fraction the * hardware can handle. When the integral part of the divisor is * greater than one, the fractional part is in 1/8ths of the base clock. * The FT8U232AM chips can handle only 0.125, 0.250, and 0.5 fractions. * Later chips can handle all 1/8th fractions. * * If the integral part of the divisor is 1, a special rule applies: the * fractional part can only be .0 or .5 (this is a limitation of the * hardware). We handle this by truncating the fraction rather than * rounding, because this only applies to the two fastest speeds the * chip can achieve and rounding doesn't matter, either you've asked for * that exact speed or you've asked for something the chip can't do. * * For the FT8U232AM chips, use a roundoff table to adjust the result * to the nearest 1/8th fraction that is supported by the hardware, * leaving a fixed-point number with a 3-bit fraction which exactly * represents the math the hardware divider will do. For later-series * chips that support all 8 fractional divisors, just round 16ths to * 8ths by adding 1 and dividing by 2. */ divisor = (clk << 4) / speed; if ((divisor & 0xf) == 1) divisor &= 0xfffffff8; else if (sc->sc_devtype == DEVT_232A) divisor += roundoff_232a[divisor & 0x0f]; else divisor += 1; /* Rounds odd 16ths up to next 8th. */ divisor >>= 1; /* * Ensure the resulting hardware speed will be within operational * tolerance (within 3% of nominal). */ hwspeed = (clk << 3) / divisor; if (!uftdi_baud_within_tolerance(hwspeed, speed)) return (ERANGE); /* * Re-pack the divisor into hardware format. The lower 14-bits hold the * integral part, while the upper bits specify the fraction by indexing * a table of fractions within the hardware which is laid out as: * {0.0, 0.5, 0.25, 0.125, 0.325, 0.625, 0.725, 0.875} * The A-series chips only have the first four table entries; the * roundoff table logic above ensures that the fractional part for those * chips will be one of the first four values. * * When the divisor is 1 a special encoding applies: 1.0 is encoded as * 0.0, and 1.5 is encoded as 1.0. The rounding logic above has already * ensured that the fraction is either .0 or .5 if the integral is 1. */ frac = divisor & 0x07; divisor >>= 3; if (divisor == 1) { if (frac == 0) divisor = 0; /* 1.0 becomes 0.0 */ else frac = 0; /* 1.5 becomes 1.0 */ } divisor |= (encoded_fraction[frac] << 14) | fastclk_flag; cfg->baud_lobits = (uint16_t)divisor; cfg->baud_hibits = (uint16_t)(divisor >> 16); /* * If this chip requires the baud bits to be in the high byte of the * index word, move the bits up to that location. */ if (sc->sc_devflags & DEVF_BAUDBITS_HINDEX) { cfg->baud_hibits <<= 8; } return (0); } static int uftdi_set_parm_soft(struct ucom_softc *ucom, struct termios *t, struct uftdi_param_config *cfg) { struct uftdi_softc *sc = ucom->sc_parent; int err; memset(cfg, 0, sizeof(*cfg)); if (sc->sc_devtype == DEVT_SIO) err = uftdi_sio_encode_baudrate(sc, t->c_ospeed, cfg); else err = uftdi_encode_baudrate(sc, t->c_ospeed, cfg); if (err != 0) return (err); if (t->c_cflag & CSTOPB) cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_2; else cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_1; if (t->c_cflag & PARENB) { if (t->c_cflag & PARODD) { cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_ODD; } else { cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_EVEN; } } else { cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_NONE; } switch (t->c_cflag & CSIZE) { case CS5: cfg->lcr |= FTDI_SIO_SET_DATA_BITS(5); break; case CS6: cfg->lcr |= FTDI_SIO_SET_DATA_BITS(6); break; case CS7: cfg->lcr |= FTDI_SIO_SET_DATA_BITS(7); break; case CS8: cfg->lcr |= FTDI_SIO_SET_DATA_BITS(8); break; } if (t->c_cflag & CRTSCTS) { cfg->v_flow = FTDI_SIO_RTS_CTS_HS; } else if (t->c_iflag & (IXON | IXOFF)) { cfg->v_flow = FTDI_SIO_XON_XOFF_HS; cfg->v_start = t->c_cc[VSTART]; cfg->v_stop = t->c_cc[VSTOP]; } else { cfg->v_flow = FTDI_SIO_DISABLE_FLOW_CTRL; } return (0); } static int uftdi_pre_param(struct ucom_softc *ucom, struct termios *t) { struct uftdi_param_config cfg; DPRINTF("\n"); return (uftdi_set_parm_soft(ucom, t, &cfg)); } static void uftdi_cfg_param(struct ucom_softc *ucom, struct termios *t) { struct uftdi_softc *sc = ucom->sc_parent; uint16_t wIndex = ucom->sc_portno; struct uftdi_param_config cfg; struct usb_device_request req; DPRINTF("\n"); if (uftdi_set_parm_soft(ucom, t, &cfg)) { /* should not happen */ return; } sc->sc_last_lcr = cfg.lcr; req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_SET_BAUD_RATE; USETW(req.wValue, cfg.baud_lobits); USETW(req.wIndex, cfg.baud_hibits | wIndex); USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_SET_DATA; USETW(req.wValue, cfg.lcr); USETW(req.wIndex, wIndex); USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_SET_FLOW_CTRL; USETW2(req.wValue, cfg.v_stop, cfg.v_start); USETW2(req.wIndex, cfg.v_flow, wIndex); USETW(req.wLength, 0); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } static void uftdi_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) { struct uftdi_softc *sc = ucom->sc_parent; DPRINTFN(3, "msr=0x%02x lsr=0x%02x\n", sc->sc_msr, sc->sc_lsr); *msr = sc->sc_msr; *lsr = sc->sc_lsr; } static int uftdi_reset(struct ucom_softc *ucom, int reset_type) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; DPRINTFN(2, "\n"); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_RESET; USETW(req.wIndex, sc->sc_ucom.sc_portno); USETW(req.wLength, 0); USETW(req.wValue, reset_type); return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); } static int uftdi_set_bitmode(struct ucom_softc *ucom, uint8_t bitmode, uint8_t iomask) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; int rv; DPRINTFN(2, "\n"); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_SET_BITMODE; USETW(req.wIndex, sc->sc_ucom.sc_portno); USETW(req.wLength, 0); if (bitmode == UFTDI_BITMODE_NONE) USETW2(req.wValue, 0, 0); else USETW2(req.wValue, (1 << bitmode), iomask); rv = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL); if (rv == USB_ERR_NORMAL_COMPLETION) sc->sc_bitmode = bitmode; return (rv); } static int uftdi_get_bitmode(struct ucom_softc *ucom, uint8_t *bitmode, uint8_t *iomask) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; DPRINTFN(2, "\n"); req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = FTDI_SIO_GET_BITMODE; USETW(req.wIndex, sc->sc_ucom.sc_portno); USETW(req.wLength, 1); USETW(req.wValue, 0); *bitmode = sc->sc_bitmode; return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, iomask)); } static int uftdi_set_latency(struct ucom_softc *ucom, int latency) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; DPRINTFN(2, "\n"); if (latency < 0 || latency > 255) return (USB_ERR_INVAL); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_SET_LATENCY; USETW(req.wIndex, sc->sc_ucom.sc_portno); USETW(req.wLength, 0); USETW2(req.wValue, 0, latency); return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); } static int uftdi_get_latency(struct ucom_softc *ucom, int *latency) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; usb_error_t err; uint8_t buf; DPRINTFN(2, "\n"); req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = FTDI_SIO_GET_LATENCY; USETW(req.wIndex, sc->sc_ucom.sc_portno); USETW(req.wLength, 1); USETW(req.wValue, 0); err = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &buf); *latency = buf; return (err); } static int uftdi_set_event_char(struct ucom_softc *ucom, int echar) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; uint8_t enable; DPRINTFN(2, "\n"); enable = (echar == -1) ? 0 : 1; req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_SET_EVENT_CHAR; USETW(req.wIndex, sc->sc_ucom.sc_portno); USETW(req.wLength, 0); USETW2(req.wValue, enable, echar & 0xff); return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); } static int uftdi_set_error_char(struct ucom_softc *ucom, int echar) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; uint8_t enable; DPRINTFN(2, "\n"); enable = (echar == -1) ? 0 : 1; req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_SET_ERROR_CHAR; USETW(req.wIndex, sc->sc_ucom.sc_portno); USETW(req.wLength, 0); USETW2(req.wValue, enable, echar & 0xff); return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); } static int uftdi_read_eeprom(struct ucom_softc *ucom, struct uftdi_eeio *eeio) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; usb_error_t err; uint16_t widx, wlength, woffset; DPRINTFN(3, "\n"); /* Offset and length must both be evenly divisible by two. */ if ((eeio->offset | eeio->length) & 0x01) return (EINVAL); woffset = eeio->offset / 2U; wlength = eeio->length / 2U; for (widx = 0; widx < wlength; widx++) { req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = FTDI_SIO_READ_EEPROM; USETW(req.wIndex, widx + woffset); USETW(req.wLength, 2); USETW(req.wValue, 0); err = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &eeio->data[widx]); if (err != USB_ERR_NORMAL_COMPLETION) return (err); } return (USB_ERR_NORMAL_COMPLETION); } static int uftdi_write_eeprom(struct ucom_softc *ucom, struct uftdi_eeio *eeio) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; usb_error_t err; uint16_t widx, wlength, woffset; DPRINTFN(3, "\n"); /* Offset and length must both be evenly divisible by two. */ if ((eeio->offset | eeio->length) & 0x01) return (EINVAL); woffset = eeio->offset / 2U; wlength = eeio->length / 2U; for (widx = 0; widx < wlength; widx++) { req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_WRITE_EEPROM; USETW(req.wIndex, widx + woffset); USETW(req.wLength, 0); USETW(req.wValue, eeio->data[widx]); err = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL); if (err != USB_ERR_NORMAL_COMPLETION) return (err); } return (USB_ERR_NORMAL_COMPLETION); } static int uftdi_erase_eeprom(struct ucom_softc *ucom, int confirmation) { struct uftdi_softc *sc = ucom->sc_parent; usb_device_request_t req; usb_error_t err; DPRINTFN(2, "\n"); /* Small effort to prevent accidental erasure. */ if (confirmation != UFTDI_CONFIRM_ERASE) return (EINVAL); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_ERASE_EEPROM; USETW(req.wIndex, 0); USETW(req.wLength, 0); USETW(req.wValue, 0); err = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL); return (err); } static int uftdi_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data, int flag, struct thread *td) { struct uftdi_softc *sc = ucom->sc_parent; int err; struct uftdi_bitmode * mode; switch (cmd) { case UFTDIIOC_RESET_IO: case UFTDIIOC_RESET_RX: case UFTDIIOC_RESET_TX: err = uftdi_reset(ucom, cmd == UFTDIIOC_RESET_IO ? FTDI_SIO_RESET_SIO : (cmd == UFTDIIOC_RESET_RX ? FTDI_SIO_RESET_PURGE_RX : FTDI_SIO_RESET_PURGE_TX)); break; case UFTDIIOC_SET_BITMODE: mode = (struct uftdi_bitmode *)data; err = uftdi_set_bitmode(ucom, mode->mode, mode->iomask); break; case UFTDIIOC_GET_BITMODE: mode = (struct uftdi_bitmode *)data; err = uftdi_get_bitmode(ucom, &mode->mode, &mode->iomask); break; case UFTDIIOC_SET_LATENCY: err = uftdi_set_latency(ucom, *((int *)data)); break; case UFTDIIOC_GET_LATENCY: err = uftdi_get_latency(ucom, (int *)data); break; case UFTDIIOC_SET_ERROR_CHAR: err = uftdi_set_error_char(ucom, *(int *)data); break; case UFTDIIOC_SET_EVENT_CHAR: err = uftdi_set_event_char(ucom, *(int *)data); break; case UFTDIIOC_GET_HWREV: *(int *)data = sc->sc_bcdDevice; err = 0; break; case UFTDIIOC_READ_EEPROM: err = uftdi_read_eeprom(ucom, (struct uftdi_eeio *)data); break; case UFTDIIOC_WRITE_EEPROM: err = uftdi_write_eeprom(ucom, (struct uftdi_eeio *)data); break; case UFTDIIOC_ERASE_EEPROM: err = uftdi_erase_eeprom(ucom, *(int *)data); break; default: return (ENOIOCTL); } if (err != USB_ERR_NORMAL_COMPLETION) return (EIO); return (0); } static void uftdi_start_read(struct ucom_softc *ucom) { struct uftdi_softc *sc = ucom->sc_parent; usbd_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_RD]); } static void uftdi_stop_read(struct ucom_softc *ucom) { struct uftdi_softc *sc = ucom->sc_parent; usbd_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_RD]); } static void uftdi_start_write(struct ucom_softc *ucom) { struct uftdi_softc *sc = ucom->sc_parent; usbd_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_WR]); } static void uftdi_stop_write(struct ucom_softc *ucom) { struct uftdi_softc *sc = ucom->sc_parent; usbd_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_WR]); } static void uftdi_poll(struct ucom_softc *ucom) { struct uftdi_softc *sc = ucom->sc_parent; usbd_transfer_poll(sc->sc_xfer, UFTDI_N_TRANSFER); } Index: projects/ipsec/sys/dev/usb/serial/usb_serial.c =================================================================== --- projects/ipsec/sys/dev/usb/serial/usb_serial.c (revision 313312) +++ projects/ipsec/sys/dev/usb/serial/usb_serial.c (revision 313313) @@ -1,1717 +1,1740 @@ /* $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $ */ /*- * Copyright (c) 2001-2003, 2005, 2008 * Shunsuke Akiyama . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); /*- * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (lennart@augustsson.net) at * Carlstedt Research & Technology. * * 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. * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define USB_DEBUG_VAR ucom_debug #include #include #include #include #include "opt_gdb.h" static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom"); static int ucom_pps_mode; SYSCTL_INT(_hw_usb_ucom, OID_AUTO, pps_mode, CTLFLAG_RWTUN, &ucom_pps_mode, 0, "pulse capture mode: 0/1/2=disabled/CTS/DCD; add 0x10 to invert"); #ifdef USB_DEBUG static int ucom_debug = 0; SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RWTUN, &ucom_debug, 0, "ucom debug level"); #endif #define UCOM_CONS_BUFSIZE 1024 static uint8_t ucom_cons_rx_buf[UCOM_CONS_BUFSIZE]; static uint8_t ucom_cons_tx_buf[UCOM_CONS_BUFSIZE]; static unsigned int ucom_cons_rx_low = 0; static unsigned int ucom_cons_rx_high = 0; static unsigned int ucom_cons_tx_low = 0; static unsigned int ucom_cons_tx_high = 0; static int ucom_cons_unit = -1; static int ucom_cons_subunit = 0; static int ucom_cons_baud = 9600; static struct ucom_softc *ucom_cons_softc = NULL; SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RWTUN, &ucom_cons_unit, 0, "console unit number"); SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RWTUN, &ucom_cons_subunit, 0, "console subunit number"); SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RWTUN, &ucom_cons_baud, 0, "console baud rate"); static usb_proc_callback_t ucom_cfg_start_transfers; static usb_proc_callback_t ucom_cfg_open; static usb_proc_callback_t ucom_cfg_close; static usb_proc_callback_t ucom_cfg_line_state; static usb_proc_callback_t ucom_cfg_status_change; static usb_proc_callback_t ucom_cfg_param; static int ucom_unit_alloc(void); static void ucom_unit_free(int); static int ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *); static void ucom_detach_tty(struct ucom_super_softc *, struct ucom_softc *); static void ucom_queue_command(struct ucom_softc *, usb_proc_callback_t *, struct termios *pt, struct usb_proc_msg *t0, struct usb_proc_msg *t1); static void ucom_shutdown(struct ucom_softc *); static void ucom_ring(struct ucom_softc *, uint8_t); static void ucom_break(struct ucom_softc *, uint8_t); static void ucom_dtr(struct ucom_softc *, uint8_t); static void ucom_rts(struct ucom_softc *, uint8_t); static tsw_open_t ucom_open; static tsw_close_t ucom_close; static tsw_ioctl_t ucom_ioctl; static tsw_modem_t ucom_modem; static tsw_param_t ucom_param; static tsw_outwakeup_t ucom_outwakeup; static tsw_inwakeup_t ucom_inwakeup; static tsw_free_t ucom_free; +static tsw_busy_t ucom_busy; static struct ttydevsw ucom_class = { .tsw_flags = TF_INITLOCK | TF_CALLOUT, .tsw_open = ucom_open, .tsw_close = ucom_close, .tsw_outwakeup = ucom_outwakeup, .tsw_inwakeup = ucom_inwakeup, .tsw_ioctl = ucom_ioctl, .tsw_param = ucom_param, .tsw_modem = ucom_modem, .tsw_free = ucom_free, + .tsw_busy = ucom_busy, }; MODULE_DEPEND(ucom, usb, 1, 1, 1); MODULE_VERSION(ucom, 1); #define UCOM_UNIT_MAX 128 /* maximum number of units */ #define UCOM_TTY_PREFIX "U" static struct unrhdr *ucom_unrhdr; static struct mtx ucom_mtx; static int ucom_close_refs; static void ucom_init(void *arg) { DPRINTF("\n"); ucom_unrhdr = new_unrhdr(0, UCOM_UNIT_MAX - 1, NULL); mtx_init(&ucom_mtx, "UCOM MTX", NULL, MTX_DEF); } SYSINIT(ucom_init, SI_SUB_KLD - 1, SI_ORDER_ANY, ucom_init, NULL); static void ucom_uninit(void *arg) { struct unrhdr *hdr; hdr = ucom_unrhdr; ucom_unrhdr = NULL; DPRINTF("\n"); if (hdr != NULL) delete_unrhdr(hdr); mtx_destroy(&ucom_mtx); } SYSUNINIT(ucom_uninit, SI_SUB_KLD - 3, SI_ORDER_ANY, ucom_uninit, NULL); /* * Mark a unit number (the X in cuaUX) as in use. * * Note that devices using a different naming scheme (see ucom_tty_name() * callback) still use this unit allocation. */ static int ucom_unit_alloc(void) { int unit; /* sanity checks */ if (ucom_unrhdr == NULL) { DPRINTF("ucom_unrhdr is NULL\n"); return (-1); } unit = alloc_unr(ucom_unrhdr); DPRINTF("unit %d is allocated\n", unit); return (unit); } /* * Mark the unit number as not in use. */ static void ucom_unit_free(int unit) { /* sanity checks */ if (unit < 0 || unit >= UCOM_UNIT_MAX || ucom_unrhdr == NULL) { DPRINTF("cannot free unit number\n"); return; } DPRINTF("unit %d is freed\n", unit); free_unr(ucom_unrhdr, unit); } /* * Setup a group of one or more serial ports. * * The mutex pointed to by "mtx" is applied before all * callbacks are called back. Also "mtx" must be applied * before calling into the ucom-layer! */ int ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc, int subunits, void *parent, const struct ucom_callback *callback, struct mtx *mtx) { int subunit; int error = 0; if ((sc == NULL) || (subunits <= 0) || (callback == NULL) || (mtx == NULL)) { return (EINVAL); } /* allocate a uniq unit number */ ssc->sc_unit = ucom_unit_alloc(); if (ssc->sc_unit == -1) return (ENOMEM); /* generate TTY name string */ snprintf(ssc->sc_ttyname, sizeof(ssc->sc_ttyname), UCOM_TTY_PREFIX "%d", ssc->sc_unit); /* create USB request handling process */ error = usb_proc_create(&ssc->sc_tq, mtx, "ucom", USB_PRI_MED); if (error) { ucom_unit_free(ssc->sc_unit); return (error); } ssc->sc_subunits = subunits; ssc->sc_flag = UCOM_FLAG_ATTACHED | UCOM_FLAG_FREE_UNIT; if (callback->ucom_free == NULL) ssc->sc_flag |= UCOM_FLAG_WAIT_REFS; /* increment reference count */ ucom_ref(ssc); for (subunit = 0; subunit < ssc->sc_subunits; subunit++) { sc[subunit].sc_subunit = subunit; sc[subunit].sc_super = ssc; sc[subunit].sc_mtx = mtx; sc[subunit].sc_parent = parent; sc[subunit].sc_callback = callback; error = ucom_attach_tty(ssc, &sc[subunit]); if (error) { ucom_detach(ssc, &sc[0]); return (error); } /* increment reference count */ ucom_ref(ssc); /* set subunit attached */ sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED; } DPRINTF("tp = %p, unit = %d, subunits = %d\n", sc->sc_tty, ssc->sc_unit, ssc->sc_subunits); return (0); } /* * The following function will do nothing if the structure pointed to * by "ssc" and "sc" is zero or has already been detached. */ void ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc) { int subunit; if (!(ssc->sc_flag & UCOM_FLAG_ATTACHED)) return; /* not initialized */ if (ssc->sc_sysctl_ttyname != NULL) { sysctl_remove_oid(ssc->sc_sysctl_ttyname, 1, 0); ssc->sc_sysctl_ttyname = NULL; } if (ssc->sc_sysctl_ttyports != NULL) { sysctl_remove_oid(ssc->sc_sysctl_ttyports, 1, 0); ssc->sc_sysctl_ttyports = NULL; } usb_proc_drain(&ssc->sc_tq); for (subunit = 0; subunit < ssc->sc_subunits; subunit++) { if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) { ucom_detach_tty(ssc, &sc[subunit]); /* avoid duplicate detach */ sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED; } } usb_proc_free(&ssc->sc_tq); ucom_unref(ssc); if (ssc->sc_flag & UCOM_FLAG_WAIT_REFS) ucom_drain(ssc); /* make sure we don't detach twice */ ssc->sc_flag &= ~UCOM_FLAG_ATTACHED; } void ucom_drain(struct ucom_super_softc *ssc) { mtx_lock(&ucom_mtx); while (ssc->sc_refs > 0) { printf("ucom: Waiting for a TTY device to close.\n"); usb_pause_mtx(&ucom_mtx, hz); } mtx_unlock(&ucom_mtx); } void ucom_drain_all(void *arg) { mtx_lock(&ucom_mtx); while (ucom_close_refs > 0) { printf("ucom: Waiting for all detached TTY " "devices to have open fds closed.\n"); usb_pause_mtx(&ucom_mtx, hz); } mtx_unlock(&ucom_mtx); } static int ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) { struct tty *tp; char buf[32]; /* temporary TTY device name buffer */ tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx); if (tp == NULL) return (ENOMEM); /* Check if the client has a custom TTY name */ buf[0] = '\0'; if (sc->sc_callback->ucom_tty_name) { sc->sc_callback->ucom_tty_name(sc, buf, sizeof(buf), ssc->sc_unit, sc->sc_subunit); } if (buf[0] == 0) { /* Use default TTY name */ if (ssc->sc_subunits > 1) { /* multiple modems in one */ snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u", ssc->sc_unit, sc->sc_subunit); } else { /* single modem */ snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u", ssc->sc_unit); } } tty_makedev(tp, NULL, "%s", buf); sc->sc_tty = tp; sc->sc_pps.ppscap = PPS_CAPTUREBOTH; sc->sc_pps.driver_abi = PPS_ABI_VERSION; sc->sc_pps.driver_mtx = sc->sc_mtx; pps_init_abi(&sc->sc_pps); DPRINTF("ttycreate: %s\n", buf); /* Check if this device should be a console */ if ((ucom_cons_softc == NULL) && (ssc->sc_unit == ucom_cons_unit) && (sc->sc_subunit == ucom_cons_subunit)) { DPRINTF("unit %d subunit %d is console", ssc->sc_unit, sc->sc_subunit); ucom_cons_softc = sc; tty_init_console(tp, ucom_cons_baud); UCOM_MTX_LOCK(ucom_cons_softc); ucom_cons_rx_low = 0; ucom_cons_rx_high = 0; ucom_cons_tx_low = 0; ucom_cons_tx_high = 0; sc->sc_flag |= UCOM_FLAG_CONSOLE; ucom_open(ucom_cons_softc->sc_tty); ucom_param(ucom_cons_softc->sc_tty, &tp->t_termios_init_in); UCOM_MTX_UNLOCK(ucom_cons_softc); } return (0); } static void ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) { struct tty *tp = sc->sc_tty; DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty); if (sc->sc_flag & UCOM_FLAG_CONSOLE) { UCOM_MTX_LOCK(ucom_cons_softc); ucom_close(ucom_cons_softc->sc_tty); sc->sc_flag &= ~UCOM_FLAG_CONSOLE; UCOM_MTX_UNLOCK(ucom_cons_softc); ucom_cons_softc = NULL; } /* the config thread has been stopped when we get here */ UCOM_MTX_LOCK(sc); sc->sc_flag |= UCOM_FLAG_GONE; sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY); UCOM_MTX_UNLOCK(sc); if (tp) { mtx_lock(&ucom_mtx); ucom_close_refs++; mtx_unlock(&ucom_mtx); tty_lock(tp); ucom_close(tp); /* close, if any */ tty_rel_gone(tp); UCOM_MTX_LOCK(sc); /* * make sure that read and write transfers are stopped */ if (sc->sc_callback->ucom_stop_read) (sc->sc_callback->ucom_stop_read) (sc); if (sc->sc_callback->ucom_stop_write) (sc->sc_callback->ucom_stop_write) (sc); UCOM_MTX_UNLOCK(sc); } } void ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev) { char buf[64]; uint8_t iface_index; struct usb_attach_arg *uaa; snprintf(buf, sizeof(buf), "ttyname=" UCOM_TTY_PREFIX "%d ttyports=%d", ssc->sc_unit, ssc->sc_subunits); /* Store the PNP info in the first interface for the device */ uaa = device_get_ivars(dev); iface_index = uaa->info.bIfaceIndex; if (usbd_set_pnpinfo(uaa->device, iface_index, buf) != 0) device_printf(dev, "Could not set PNP info\n"); /* * The following information is also replicated in the PNP-info * string which is registered above: */ if (ssc->sc_sysctl_ttyname == NULL) { ssc->sc_sysctl_ttyname = SYSCTL_ADD_STRING(NULL, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "ttyname", CTLFLAG_RD, ssc->sc_ttyname, 0, "TTY device basename"); } if (ssc->sc_sysctl_ttyports == NULL) { ssc->sc_sysctl_ttyports = SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "ttyports", CTLFLAG_RD, NULL, ssc->sc_subunits, "Number of ports"); } } static void ucom_queue_command(struct ucom_softc *sc, usb_proc_callback_t *fn, struct termios *pt, struct usb_proc_msg *t0, struct usb_proc_msg *t1) { struct ucom_super_softc *ssc = sc->sc_super; struct ucom_param_task *task; UCOM_MTX_ASSERT(sc, MA_OWNED); if (usb_proc_is_gone(&ssc->sc_tq)) { DPRINTF("proc is gone\n"); return; /* nothing to do */ } /* * NOTE: The task cannot get executed before we drop the * "sc_mtx" mutex. It is safe to update fields in the message * structure after that the message got queued. */ task = (struct ucom_param_task *) usb_proc_msignal(&ssc->sc_tq, t0, t1); /* Setup callback and softc pointers */ task->hdr.pm_callback = fn; task->sc = sc; /* * Make a copy of the termios. This field is only present if * the "pt" field is not NULL. */ if (pt != NULL) task->termios_copy = *pt; /* * Closing the device should be synchronous. */ if (fn == ucom_cfg_close) usb_proc_mwait(&ssc->sc_tq, t0, t1); /* * In case of multiple configure requests, * keep track of the last one! */ if (fn == ucom_cfg_start_transfers) sc->sc_last_start_xfer = &task->hdr; } static void ucom_shutdown(struct ucom_softc *sc) { struct tty *tp = sc->sc_tty; UCOM_MTX_ASSERT(sc, MA_OWNED); DPRINTF("\n"); /* * Hang up if necessary: */ if (tp->t_termios.c_cflag & HUPCL) { ucom_modem(tp, 0, SER_DTR); } } /* * Return values: * 0: normal * else: taskqueue is draining or gone */ uint8_t ucom_cfg_is_gone(struct ucom_softc *sc) { struct ucom_super_softc *ssc = sc->sc_super; return (usb_proc_is_gone(&ssc->sc_tq)); } static void ucom_cfg_start_transfers(struct usb_proc_msg *_task) { struct ucom_cfg_task *task = (struct ucom_cfg_task *)_task; struct ucom_softc *sc = task->sc; if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { return; } if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { /* TTY device closed */ return; } if (_task == sc->sc_last_start_xfer) sc->sc_flag |= UCOM_FLAG_GP_DATA; if (sc->sc_callback->ucom_start_read) { (sc->sc_callback->ucom_start_read) (sc); } if (sc->sc_callback->ucom_start_write) { (sc->sc_callback->ucom_start_write) (sc); } } static void ucom_start_transfers(struct ucom_softc *sc) { if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { return; } /* * Make sure that data transfers are started in both * directions: */ if (sc->sc_callback->ucom_start_read) { (sc->sc_callback->ucom_start_read) (sc); } if (sc->sc_callback->ucom_start_write) { (sc->sc_callback->ucom_start_write) (sc); } } static void ucom_cfg_open(struct usb_proc_msg *_task) { struct ucom_cfg_task *task = (struct ucom_cfg_task *)_task; struct ucom_softc *sc = task->sc; DPRINTF("\n"); if (sc->sc_flag & UCOM_FLAG_LL_READY) { /* already opened */ } else { sc->sc_flag |= UCOM_FLAG_LL_READY; if (sc->sc_callback->ucom_cfg_open) { (sc->sc_callback->ucom_cfg_open) (sc); /* wait a little */ usb_pause_mtx(sc->sc_mtx, hz / 10); } } } static int ucom_open(struct tty *tp) { struct ucom_softc *sc = tty_softc(tp); int error; UCOM_MTX_ASSERT(sc, MA_OWNED); if (sc->sc_flag & UCOM_FLAG_GONE) { return (ENXIO); } if (sc->sc_flag & UCOM_FLAG_HL_READY) { /* already opened */ return (0); } DPRINTF("tp = %p\n", tp); if (sc->sc_callback->ucom_pre_open) { /* * give the lower layer a chance to disallow TTY open, for * example if the device is not present: */ error = (sc->sc_callback->ucom_pre_open) (sc); if (error) { return (error); } } sc->sc_flag |= UCOM_FLAG_HL_READY; /* Disable transfers */ sc->sc_flag &= ~UCOM_FLAG_GP_DATA; sc->sc_lsr = 0; sc->sc_msr = 0; sc->sc_mcr = 0; /* reset programmed line state */ sc->sc_pls_curr = 0; sc->sc_pls_set = 0; sc->sc_pls_clr = 0; /* reset jitter buffer */ sc->sc_jitterbuf_in = 0; sc->sc_jitterbuf_out = 0; ucom_queue_command(sc, ucom_cfg_open, NULL, &sc->sc_open_task[0].hdr, &sc->sc_open_task[1].hdr); /* Queue transfer enable command last */ ucom_queue_command(sc, ucom_cfg_start_transfers, NULL, &sc->sc_start_task[0].hdr, &sc->sc_start_task[1].hdr); ucom_modem(tp, SER_DTR | SER_RTS, 0); ucom_ring(sc, 0); ucom_break(sc, 0); ucom_status_change(sc); return (0); } static void ucom_cfg_close(struct usb_proc_msg *_task) { struct ucom_cfg_task *task = (struct ucom_cfg_task *)_task; struct ucom_softc *sc = task->sc; DPRINTF("\n"); if (sc->sc_flag & UCOM_FLAG_LL_READY) { sc->sc_flag &= ~UCOM_FLAG_LL_READY; if (sc->sc_callback->ucom_cfg_close) (sc->sc_callback->ucom_cfg_close) (sc); } else { /* already closed */ } } static void ucom_close(struct tty *tp) { struct ucom_softc *sc = tty_softc(tp); UCOM_MTX_ASSERT(sc, MA_OWNED); DPRINTF("tp=%p\n", tp); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { DPRINTF("tp=%p already closed\n", tp); return; } ucom_shutdown(sc); ucom_queue_command(sc, ucom_cfg_close, NULL, &sc->sc_close_task[0].hdr, &sc->sc_close_task[1].hdr); sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW); if (sc->sc_callback->ucom_stop_read) { (sc->sc_callback->ucom_stop_read) (sc); } } static void ucom_inwakeup(struct tty *tp) { struct ucom_softc *sc = tty_softc(tp); uint16_t pos; if (sc == NULL) return; UCOM_MTX_ASSERT(sc, MA_OWNED); DPRINTF("tp=%p\n", tp); if (ttydisc_can_bypass(tp) != 0 || (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 || (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) { return; } /* prevent recursion */ sc->sc_flag |= UCOM_FLAG_INWAKEUP; pos = sc->sc_jitterbuf_out; while (sc->sc_jitterbuf_in != pos) { int c; c = (char)sc->sc_jitterbuf[pos]; if (ttydisc_rint(tp, c, 0) == -1) break; pos++; if (pos >= UCOM_JITTERBUF_SIZE) pos -= UCOM_JITTERBUF_SIZE; } sc->sc_jitterbuf_out = pos; /* clear RTS in async fashion */ if ((sc->sc_jitterbuf_in == pos) && (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)) ucom_rts(sc, 0); sc->sc_flag &= ~UCOM_FLAG_INWAKEUP; } static int ucom_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) { struct ucom_softc *sc = tty_softc(tp); int error; UCOM_MTX_ASSERT(sc, MA_OWNED); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { return (EIO); } DPRINTF("cmd = 0x%08lx\n", cmd); switch (cmd) { #if 0 case TIOCSRING: ucom_ring(sc, 1); error = 0; break; case TIOCCRING: ucom_ring(sc, 0); error = 0; break; #endif case TIOCSBRK: ucom_break(sc, 1); error = 0; break; case TIOCCBRK: ucom_break(sc, 0); error = 0; break; default: if (sc->sc_callback->ucom_ioctl) { error = (sc->sc_callback->ucom_ioctl) (sc, cmd, data, 0, td); } else { error = ENOIOCTL; } if (error == ENOIOCTL) error = pps_ioctl(cmd, data, &sc->sc_pps); break; } return (error); } static int ucom_modem(struct tty *tp, int sigon, int sigoff) { struct ucom_softc *sc = tty_softc(tp); uint8_t onoff; UCOM_MTX_ASSERT(sc, MA_OWNED); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { return (0); } if ((sigon == 0) && (sigoff == 0)) { if (sc->sc_mcr & SER_DTR) { sigon |= SER_DTR; } if (sc->sc_mcr & SER_RTS) { sigon |= SER_RTS; } if (sc->sc_msr & SER_CTS) { sigon |= SER_CTS; } if (sc->sc_msr & SER_DCD) { sigon |= SER_DCD; } if (sc->sc_msr & SER_DSR) { sigon |= SER_DSR; } if (sc->sc_msr & SER_RI) { sigon |= SER_RI; } return (sigon); } if (sigon & SER_DTR) { sc->sc_mcr |= SER_DTR; } if (sigoff & SER_DTR) { sc->sc_mcr &= ~SER_DTR; } if (sigon & SER_RTS) { sc->sc_mcr |= SER_RTS; } if (sigoff & SER_RTS) { sc->sc_mcr &= ~SER_RTS; } onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0; ucom_dtr(sc, onoff); onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0; ucom_rts(sc, onoff); return (0); } static void ucom_cfg_line_state(struct usb_proc_msg *_task) { struct ucom_cfg_task *task = (struct ucom_cfg_task *)_task; struct ucom_softc *sc = task->sc; uint8_t notch_bits; uint8_t any_bits; uint8_t prev_value; uint8_t last_value; uint8_t mask; if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { return; } mask = 0; /* compute callback mask */ if (sc->sc_callback->ucom_cfg_set_dtr) mask |= UCOM_LS_DTR; if (sc->sc_callback->ucom_cfg_set_rts) mask |= UCOM_LS_RTS; if (sc->sc_callback->ucom_cfg_set_break) mask |= UCOM_LS_BREAK; if (sc->sc_callback->ucom_cfg_set_ring) mask |= UCOM_LS_RING; /* compute the bits we are to program */ notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask; any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask; prev_value = sc->sc_pls_curr ^ notch_bits; last_value = sc->sc_pls_curr; /* reset programmed line state */ sc->sc_pls_curr = 0; sc->sc_pls_set = 0; sc->sc_pls_clr = 0; /* ensure that we don't lose any levels */ if (notch_bits & UCOM_LS_DTR) sc->sc_callback->ucom_cfg_set_dtr(sc, (prev_value & UCOM_LS_DTR) ? 1 : 0); if (notch_bits & UCOM_LS_RTS) sc->sc_callback->ucom_cfg_set_rts(sc, (prev_value & UCOM_LS_RTS) ? 1 : 0); if (notch_bits & UCOM_LS_BREAK) sc->sc_callback->ucom_cfg_set_break(sc, (prev_value & UCOM_LS_BREAK) ? 1 : 0); if (notch_bits & UCOM_LS_RING) sc->sc_callback->ucom_cfg_set_ring(sc, (prev_value & UCOM_LS_RING) ? 1 : 0); /* set last value */ if (any_bits & UCOM_LS_DTR) sc->sc_callback->ucom_cfg_set_dtr(sc, (last_value & UCOM_LS_DTR) ? 1 : 0); if (any_bits & UCOM_LS_RTS) sc->sc_callback->ucom_cfg_set_rts(sc, (last_value & UCOM_LS_RTS) ? 1 : 0); if (any_bits & UCOM_LS_BREAK) sc->sc_callback->ucom_cfg_set_break(sc, (last_value & UCOM_LS_BREAK) ? 1 : 0); if (any_bits & UCOM_LS_RING) sc->sc_callback->ucom_cfg_set_ring(sc, (last_value & UCOM_LS_RING) ? 1 : 0); } static void ucom_line_state(struct ucom_softc *sc, uint8_t set_bits, uint8_t clear_bits) { UCOM_MTX_ASSERT(sc, MA_OWNED); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { return; } DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits); /* update current programmed line state */ sc->sc_pls_curr |= set_bits; sc->sc_pls_curr &= ~clear_bits; sc->sc_pls_set |= set_bits; sc->sc_pls_clr |= clear_bits; /* defer driver programming */ ucom_queue_command(sc, ucom_cfg_line_state, NULL, &sc->sc_line_state_task[0].hdr, &sc->sc_line_state_task[1].hdr); } static void ucom_ring(struct ucom_softc *sc, uint8_t onoff) { DPRINTF("onoff = %d\n", onoff); if (onoff) ucom_line_state(sc, UCOM_LS_RING, 0); else ucom_line_state(sc, 0, UCOM_LS_RING); } static void ucom_break(struct ucom_softc *sc, uint8_t onoff) { DPRINTF("onoff = %d\n", onoff); if (onoff) ucom_line_state(sc, UCOM_LS_BREAK, 0); else ucom_line_state(sc, 0, UCOM_LS_BREAK); } static void ucom_dtr(struct ucom_softc *sc, uint8_t onoff) { DPRINTF("onoff = %d\n", onoff); if (onoff) ucom_line_state(sc, UCOM_LS_DTR, 0); else ucom_line_state(sc, 0, UCOM_LS_DTR); } static void ucom_rts(struct ucom_softc *sc, uint8_t onoff) { DPRINTF("onoff = %d\n", onoff); if (onoff) ucom_line_state(sc, UCOM_LS_RTS, 0); else ucom_line_state(sc, 0, UCOM_LS_RTS); } static void ucom_cfg_status_change(struct usb_proc_msg *_task) { struct ucom_cfg_task *task = (struct ucom_cfg_task *)_task; struct ucom_softc *sc = task->sc; struct tty *tp; int onoff; uint8_t new_msr; uint8_t new_lsr; uint8_t msr_delta; uint8_t lsr_delta; uint8_t pps_signal; tp = sc->sc_tty; UCOM_MTX_ASSERT(sc, MA_OWNED); if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { return; } if (sc->sc_callback->ucom_cfg_get_status == NULL) { return; } /* get status */ new_msr = 0; new_lsr = 0; (sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { /* TTY device closed */ return; } msr_delta = (sc->sc_msr ^ new_msr); lsr_delta = (sc->sc_lsr ^ new_lsr); sc->sc_msr = new_msr; sc->sc_lsr = new_lsr; /* * Time pulse counting support. */ switch(ucom_pps_mode & UART_PPS_SIGNAL_MASK) { case UART_PPS_CTS: pps_signal = SER_CTS; break; case UART_PPS_DCD: pps_signal = SER_DCD; break; default: pps_signal = 0; break; } if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) && (msr_delta & pps_signal)) { pps_capture(&sc->sc_pps); onoff = (sc->sc_msr & pps_signal) ? 1 : 0; if (ucom_pps_mode & UART_PPS_INVERT_PULSE) onoff = !onoff; pps_event(&sc->sc_pps, onoff ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); } if (msr_delta & SER_DCD) { onoff = (sc->sc_msr & SER_DCD) ? 1 : 0; DPRINTF("DCD changed to %d\n", onoff); ttydisc_modem(tp, onoff); } if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) { DPRINTF("BREAK detected\n"); ttydisc_rint(tp, 0, TRE_BREAK); ttydisc_rint_done(tp); } if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) { DPRINTF("Frame error detected\n"); ttydisc_rint(tp, 0, TRE_FRAMING); ttydisc_rint_done(tp); } if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) { DPRINTF("Parity error detected\n"); ttydisc_rint(tp, 0, TRE_PARITY); ttydisc_rint_done(tp); } } void ucom_status_change(struct ucom_softc *sc) { UCOM_MTX_ASSERT(sc, MA_OWNED); if (sc->sc_flag & UCOM_FLAG_CONSOLE) return; /* not supported */ if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { return; } DPRINTF("\n"); ucom_queue_command(sc, ucom_cfg_status_change, NULL, &sc->sc_status_task[0].hdr, &sc->sc_status_task[1].hdr); } static void ucom_cfg_param(struct usb_proc_msg *_task) { struct ucom_param_task *task = (struct ucom_param_task *)_task; struct ucom_softc *sc = task->sc; if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { return; } if (sc->sc_callback->ucom_cfg_param == NULL) { return; } (sc->sc_callback->ucom_cfg_param) (sc, &task->termios_copy); /* wait a little */ usb_pause_mtx(sc->sc_mtx, hz / 10); } static int ucom_param(struct tty *tp, struct termios *t) { struct ucom_softc *sc = tty_softc(tp); uint8_t opened; int error; UCOM_MTX_ASSERT(sc, MA_OWNED); opened = 0; error = 0; if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { /* XXX the TTY layer should call "open()" first! */ /* * Not quite: Its ordering is partly backwards, but * some parameters must be set early in ttydev_open(), * possibly before calling ttydevsw_open(). */ error = ucom_open(tp); if (error) goto done; opened = 1; } DPRINTF("sc = %p\n", sc); /* Check requested parameters. */ if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) { /* XXX c_ospeed == 0 is perfectly valid. */ DPRINTF("mismatch ispeed and ospeed\n"); error = EINVAL; goto done; } t->c_ispeed = t->c_ospeed; if (sc->sc_callback->ucom_pre_param) { /* Let the lower layer verify the parameters */ error = (sc->sc_callback->ucom_pre_param) (sc, t); if (error) { DPRINTF("callback error = %d\n", error); goto done; } } /* Disable transfers */ sc->sc_flag &= ~UCOM_FLAG_GP_DATA; /* Queue baud rate programming command first */ ucom_queue_command(sc, ucom_cfg_param, t, &sc->sc_param_task[0].hdr, &sc->sc_param_task[1].hdr); /* Queue transfer enable command last */ ucom_queue_command(sc, ucom_cfg_start_transfers, NULL, &sc->sc_start_task[0].hdr, &sc->sc_start_task[1].hdr); if (t->c_cflag & CRTS_IFLOW) { sc->sc_flag |= UCOM_FLAG_RTS_IFLOW; } else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) { sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW; ucom_modem(tp, SER_RTS, 0); } done: if (error) { if (opened) { ucom_close(tp); } } return (error); } static void ucom_outwakeup(struct tty *tp) { struct ucom_softc *sc = tty_softc(tp); UCOM_MTX_ASSERT(sc, MA_OWNED); DPRINTF("sc = %p\n", sc); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { /* The higher layer is not ready */ return; } ucom_start_transfers(sc); +} + +static bool +ucom_busy(struct tty *tp) +{ + struct ucom_softc *sc = tty_softc(tp); + const uint8_t txidle = ULSR_TXRDY | ULSR_TSRE; + + UCOM_MTX_ASSERT(sc, MA_OWNED); + + DPRINTFN(3, "sc = %p lsr 0x%02x\n", sc, sc->sc_lsr); + + /* + * If the driver maintains the txidle bits in LSR, we can use them to + * determine whether the transmitter is busy or idle. Otherwise we have + * to assume it is idle to avoid hanging forever on tcdrain(3). + */ + if (sc->sc_flag & UCOM_FLAG_LSRTXIDLE) + return ((sc->sc_lsr & txidle) != txidle); + else + return (false); } /*------------------------------------------------------------------------* * ucom_get_data * * Return values: * 0: No data is available. * Else: Data is available. *------------------------------------------------------------------------*/ uint8_t ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len, uint32_t *actlen) { struct usb_page_search res; struct tty *tp = sc->sc_tty; uint32_t cnt; uint32_t offset_orig; UCOM_MTX_ASSERT(sc, MA_OWNED); if (sc->sc_flag & UCOM_FLAG_CONSOLE) { unsigned int temp; /* get total TX length */ temp = ucom_cons_tx_high - ucom_cons_tx_low; temp %= UCOM_CONS_BUFSIZE; /* limit TX length */ if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low)) temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low); if (temp > len) temp = len; /* copy in data */ usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp); /* update counters */ ucom_cons_tx_low += temp; ucom_cons_tx_low %= UCOM_CONS_BUFSIZE; /* store actual length */ *actlen = temp; return (temp ? 1 : 0); } if (tty_gone(tp) || !(sc->sc_flag & UCOM_FLAG_GP_DATA)) { actlen[0] = 0; return (0); /* multiport device polling */ } offset_orig = offset; while (len != 0) { usbd_get_page(pc, offset, &res); if (res.length > len) { res.length = len; } /* copy data directly into USB buffer */ cnt = ttydisc_getc(tp, res.buffer, res.length); offset += cnt; len -= cnt; if (cnt < res.length) { /* end of buffer */ break; } } actlen[0] = offset - offset_orig; DPRINTF("cnt=%d\n", actlen[0]); if (actlen[0] == 0) { return (0); } return (1); } void ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len) { struct usb_page_search res; struct tty *tp = sc->sc_tty; char *buf; uint32_t cnt; UCOM_MTX_ASSERT(sc, MA_OWNED); if (sc->sc_flag & UCOM_FLAG_CONSOLE) { unsigned int temp; /* get maximum RX length */ temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low; temp %= UCOM_CONS_BUFSIZE; /* limit RX length */ if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high)) temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high); if (temp > len) temp = len; /* copy out data */ usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp); /* update counters */ ucom_cons_rx_high += temp; ucom_cons_rx_high %= UCOM_CONS_BUFSIZE; return; } if (tty_gone(tp)) return; /* multiport device polling */ if (len == 0) return; /* no data */ /* set a flag to prevent recursation ? */ while (len > 0) { usbd_get_page(pc, offset, &res); if (res.length > len) { res.length = len; } len -= res.length; offset += res.length; /* pass characters to tty layer */ buf = res.buffer; cnt = res.length; /* first check if we can pass the buffer directly */ if (ttydisc_can_bypass(tp)) { /* clear any jitter buffer */ sc->sc_jitterbuf_in = 0; sc->sc_jitterbuf_out = 0; if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) { DPRINTF("tp=%p, data lost\n", tp); } continue; } /* need to loop */ for (cnt = 0; cnt != res.length; cnt++) { if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out || ttydisc_rint(tp, buf[cnt], 0) == -1) { uint16_t end; uint16_t pos; pos = sc->sc_jitterbuf_in; end = sc->sc_jitterbuf_out + UCOM_JITTERBUF_SIZE - 1; if (end >= UCOM_JITTERBUF_SIZE) end -= UCOM_JITTERBUF_SIZE; for (; cnt != res.length; cnt++) { if (pos == end) break; sc->sc_jitterbuf[pos] = buf[cnt]; pos++; if (pos >= UCOM_JITTERBUF_SIZE) pos -= UCOM_JITTERBUF_SIZE; } sc->sc_jitterbuf_in = pos; /* set RTS in async fashion */ if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) ucom_rts(sc, 1); DPRINTF("tp=%p, lost %d " "chars\n", tp, res.length - cnt); break; } } } ttydisc_rint_done(tp); } static void ucom_free(void *xsc) { struct ucom_softc *sc = xsc; if (sc->sc_callback->ucom_free != NULL) sc->sc_callback->ucom_free(sc); else ucom_unref(sc->sc_super); mtx_lock(&ucom_mtx); ucom_close_refs--; mtx_unlock(&ucom_mtx); } static cn_probe_t ucom_cnprobe; static cn_init_t ucom_cninit; static cn_term_t ucom_cnterm; static cn_getc_t ucom_cngetc; static cn_putc_t ucom_cnputc; static cn_grab_t ucom_cngrab; static cn_ungrab_t ucom_cnungrab; CONSOLE_DRIVER(ucom); static void ucom_cnprobe(struct consdev *cp) { if (ucom_cons_unit != -1) cp->cn_pri = CN_NORMAL; else cp->cn_pri = CN_DEAD; strlcpy(cp->cn_name, "ucom", sizeof(cp->cn_name)); } static void ucom_cninit(struct consdev *cp) { } static void ucom_cnterm(struct consdev *cp) { } static void ucom_cngrab(struct consdev *cp) { } static void ucom_cnungrab(struct consdev *cp) { } static int ucom_cngetc(struct consdev *cd) { struct ucom_softc *sc = ucom_cons_softc; int c; if (sc == NULL) return (-1); UCOM_MTX_LOCK(sc); if (ucom_cons_rx_low != ucom_cons_rx_high) { c = ucom_cons_rx_buf[ucom_cons_rx_low]; ucom_cons_rx_low ++; ucom_cons_rx_low %= UCOM_CONS_BUFSIZE; } else { c = -1; } /* start USB transfers */ ucom_outwakeup(sc->sc_tty); UCOM_MTX_UNLOCK(sc); /* poll if necessary */ if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll) (sc->sc_callback->ucom_poll) (sc); return (c); } static void ucom_cnputc(struct consdev *cd, int c) { struct ucom_softc *sc = ucom_cons_softc; unsigned int temp; if (sc == NULL) return; repeat: UCOM_MTX_LOCK(sc); /* compute maximum TX length */ temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low; temp %= UCOM_CONS_BUFSIZE; if (temp) { ucom_cons_tx_buf[ucom_cons_tx_high] = c; ucom_cons_tx_high ++; ucom_cons_tx_high %= UCOM_CONS_BUFSIZE; } /* start USB transfers */ ucom_outwakeup(sc->sc_tty); UCOM_MTX_UNLOCK(sc); /* poll if necessary */ if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll) { (sc->sc_callback->ucom_poll) (sc); /* simple flow control */ if (temp == 0) goto repeat; } } /*------------------------------------------------------------------------* * ucom_ref * * This function will increment the super UCOM reference count. *------------------------------------------------------------------------*/ void ucom_ref(struct ucom_super_softc *ssc) { mtx_lock(&ucom_mtx); ssc->sc_refs++; mtx_unlock(&ucom_mtx); } /*------------------------------------------------------------------------* * ucom_free_unit * * This function will free the super UCOM's allocated unit * number. This function can be called on a zero-initialized * structure. This function can be called multiple times. *------------------------------------------------------------------------*/ static void ucom_free_unit(struct ucom_super_softc *ssc) { if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT)) return; ucom_unit_free(ssc->sc_unit); ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT; } /*------------------------------------------------------------------------* * ucom_unref * * This function will decrement the super UCOM reference count. * * Return values: * 0: UCOM structures are still referenced. * Else: UCOM structures are no longer referenced. *------------------------------------------------------------------------*/ int ucom_unref(struct ucom_super_softc *ssc) { int retval; mtx_lock(&ucom_mtx); retval = (ssc->sc_refs < 2); ssc->sc_refs--; mtx_unlock(&ucom_mtx); if (retval) ucom_free_unit(ssc); return (retval); } #if defined(GDB) #include static gdb_probe_f ucom_gdbprobe; static gdb_init_f ucom_gdbinit; static gdb_term_f ucom_gdbterm; static gdb_getc_f ucom_gdbgetc; static gdb_putc_f ucom_gdbputc; GDB_DBGPORT(sio, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc); static int ucom_gdbprobe(void) { return ((ucom_cons_softc != NULL) ? 0 : -1); } static void ucom_gdbinit(void) { } static void ucom_gdbterm(void) { } static void ucom_gdbputc(int c) { ucom_cnputc(NULL, c); } static int ucom_gdbgetc(void) { return (ucom_cngetc(NULL)); } #endif Index: projects/ipsec/sys/dev/usb/serial/usb_serial.h =================================================================== --- projects/ipsec/sys/dev/usb/serial/usb_serial.h (revision 313312) +++ projects/ipsec/sys/dev/usb/serial/usb_serial.h (revision 313313) @@ -1,221 +1,230 @@ /* $NetBSD: ucomvar.h,v 1.9 2001/01/23 21:56:17 augustss Exp $ */ /* $FreeBSD$ */ /*- * Copyright (c) 2001-2002, Shunsuke Akiyama . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (lennart@augustsson.net) at * Carlstedt Research & Technology. * * 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. * * 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. */ #ifndef _USB_SERIAL_H_ #define _USB_SERIAL_H_ #include #include #include #include #include /* Module interface related macros */ #define UCOM_MODVER 1 #define UCOM_MINVER 1 #define UCOM_PREFVER UCOM_MODVER #define UCOM_MAXVER 1 #define UCOM_JITTERBUF_SIZE 128 /* bytes */ struct usb_device; struct ucom_softc; struct usb_device_request; struct thread; /* * NOTE: There is no guarantee that "ucom_cfg_close()" will * be called after "ucom_cfg_open()" if the device is detached * while it is open! */ struct ucom_callback { void (*ucom_cfg_get_status) (struct ucom_softc *, uint8_t *plsr, uint8_t *pmsr); void (*ucom_cfg_set_dtr) (struct ucom_softc *, uint8_t); void (*ucom_cfg_set_rts) (struct ucom_softc *, uint8_t); void (*ucom_cfg_set_break) (struct ucom_softc *, uint8_t); void (*ucom_cfg_set_ring) (struct ucom_softc *, uint8_t); void (*ucom_cfg_param) (struct ucom_softc *, struct termios *); void (*ucom_cfg_open) (struct ucom_softc *); void (*ucom_cfg_close) (struct ucom_softc *); int (*ucom_pre_open) (struct ucom_softc *); int (*ucom_pre_param) (struct ucom_softc *, struct termios *); int (*ucom_ioctl) (struct ucom_softc *, uint32_t, caddr_t, int, struct thread *); void (*ucom_start_read) (struct ucom_softc *); void (*ucom_stop_read) (struct ucom_softc *); void (*ucom_start_write) (struct ucom_softc *); void (*ucom_stop_write) (struct ucom_softc *); void (*ucom_tty_name) (struct ucom_softc *, char *pbuf, uint16_t buflen, uint16_t unit, uint16_t subunit); void (*ucom_poll) (struct ucom_softc *); void (*ucom_free) (struct ucom_softc *); }; /* Line status register */ #define ULSR_RCV_FIFO 0x80 #define ULSR_TSRE 0x40 /* Transmitter empty: byte sent */ #define ULSR_TXRDY 0x20 /* Transmitter buffer empty */ #define ULSR_BI 0x10 /* Break detected */ #define ULSR_FE 0x08 /* Framing error: bad stop bit */ #define ULSR_PE 0x04 /* Parity error */ #define ULSR_OE 0x02 /* Overrun, lost incoming byte */ #define ULSR_RXRDY 0x01 /* Byte ready in Receive Buffer */ #define ULSR_RCV_MASK 0x1f /* Mask for incoming data or error */ struct ucom_cfg_task { struct usb_proc_msg hdr; struct ucom_softc *sc; }; struct ucom_param_task { struct usb_proc_msg hdr; struct ucom_softc *sc; struct termios termios_copy; }; struct ucom_super_softc { struct usb_process sc_tq; int sc_unit; int sc_subunits; int sc_refs; int sc_flag; /* see UCOM_FLAG_XXX */ struct sysctl_oid *sc_sysctl_ttyname; struct sysctl_oid *sc_sysctl_ttyports; char sc_ttyname[16]; }; struct ucom_softc { /* * NOTE: To avoid losing level change information we use two * tasks instead of one for all commands. * * Level changes are transitions like: * * ON->OFF * OFF->ON * OPEN->CLOSE * CLOSE->OPEN */ struct ucom_cfg_task sc_start_task[2]; struct ucom_cfg_task sc_open_task[2]; struct ucom_cfg_task sc_close_task[2]; struct ucom_cfg_task sc_line_state_task[2]; struct ucom_cfg_task sc_status_task[2]; struct ucom_param_task sc_param_task[2]; /* pulse capturing support, PPS */ struct pps_state sc_pps; /* Used to set "UCOM_FLAG_GP_DATA" flag: */ struct usb_proc_msg *sc_last_start_xfer; const struct ucom_callback *sc_callback; struct ucom_super_softc *sc_super; struct tty *sc_tty; struct mtx *sc_mtx; void *sc_parent; int sc_subunit; uint16_t sc_jitterbuf_in; uint16_t sc_jitterbuf_out; uint16_t sc_portno; uint16_t sc_flag; #define UCOM_FLAG_RTS_IFLOW 0x01 /* use RTS input flow control */ #define UCOM_FLAG_GONE 0x02 /* the device is gone */ #define UCOM_FLAG_ATTACHED 0x04 /* set if attached */ #define UCOM_FLAG_GP_DATA 0x08 /* set if get and put data is possible */ #define UCOM_FLAG_LL_READY 0x20 /* set if low layer is ready */ #define UCOM_FLAG_HL_READY 0x40 /* set if high layer is ready */ #define UCOM_FLAG_CONSOLE 0x80 /* set if device is a console */ #define UCOM_FLAG_WAIT_REFS 0x0100 /* set if we must wait for refs */ #define UCOM_FLAG_FREE_UNIT 0x0200 /* set if we must free the unit */ #define UCOM_FLAG_INWAKEUP 0x0400 /* set if we are in the tsw_inwakeup callback */ +#define UCOM_FLAG_LSRTXIDLE 0x0800 /* set if sc_lsr bits ULSR_TSRE+TXRDY work */ uint8_t sc_lsr; uint8_t sc_msr; uint8_t sc_mcr; /* programmed line state bits */ uint8_t sc_pls_set; /* set bits */ uint8_t sc_pls_clr; /* cleared bits */ uint8_t sc_pls_curr; /* last state */ #define UCOM_LS_DTR 0x01 #define UCOM_LS_RTS 0x02 #define UCOM_LS_BREAK 0x04 #define UCOM_LS_RING 0x08 uint8_t sc_jitterbuf[UCOM_JITTERBUF_SIZE]; }; #define UCOM_MTX_ASSERT(sc, what) USB_MTX_ASSERT((sc)->sc_mtx, what) #define UCOM_MTX_LOCK(sc) USB_MTX_LOCK((sc)->sc_mtx) #define UCOM_MTX_UNLOCK(sc) USB_MTX_UNLOCK((sc)->sc_mtx) #define UCOM_UNLOAD_DRAIN(x) \ SYSUNINIT(var, SI_SUB_KLD - 2, SI_ORDER_ANY, ucom_drain_all, 0) #define ucom_cfg_do_request(udev,com,req,ptr,flags,timo) \ usbd_do_request_proc(udev,&(com)->sc_super->sc_tq,req,ptr,flags,NULL,timo) int ucom_attach(struct ucom_super_softc *, struct ucom_softc *, int, void *, const struct ucom_callback *callback, struct mtx *); void ucom_detach(struct ucom_super_softc *, struct ucom_softc *); void ucom_set_pnpinfo_usb(struct ucom_super_softc *, device_t); void ucom_status_change(struct ucom_softc *); uint8_t ucom_get_data(struct ucom_softc *, struct usb_page_cache *, uint32_t, uint32_t, uint32_t *); void ucom_put_data(struct ucom_softc *, struct usb_page_cache *, uint32_t, uint32_t); uint8_t ucom_cfg_is_gone(struct ucom_softc *); void ucom_drain(struct ucom_super_softc *); void ucom_drain_all(void *); void ucom_ref(struct ucom_super_softc *); int ucom_unref(struct ucom_super_softc *); + +static inline void +ucom_use_lsr_txbits(struct ucom_softc *sc) +{ + + sc->sc_flag |= UCOM_FLAG_LSRTXIDLE; +} + #endif /* _USB_SERIAL_H_ */ Index: projects/ipsec/sys/i386/linux/linux_dummy.c =================================================================== --- projects/ipsec/sys/i386/linux/linux_dummy.c (revision 313312) +++ projects/ipsec/sys/i386/linux/linux_dummy.c (revision 313313) @@ -1,145 +1,178 @@ /*- * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #include #include #include #include #include #include /* DTrace init */ LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); DUMMY(stime); DUMMY(fstat); DUMMY(olduname); DUMMY(syslog); DUMMY(uname); DUMMY(vhangup); DUMMY(vm86old); DUMMY(swapoff); DUMMY(adjtimex); DUMMY(create_module); DUMMY(init_module); DUMMY(delete_module); DUMMY(get_kernel_syms); DUMMY(quotactl); DUMMY(bdflush); DUMMY(sysfs); DUMMY(vm86); DUMMY(query_module); DUMMY(nfsservctl); DUMMY(sendfile); /* different semantics */ DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(pivot_root); DUMMY(mincore); DUMMY(lookup_dcookie); DUMMY(remap_file_pages); DUMMY(mbind); DUMMY(get_mempolicy); DUMMY(set_mempolicy); DUMMY(kexec_load); /* linux 2.6.11: */ DUMMY(add_key); DUMMY(request_key); DUMMY(keyctl); /* linux 2.6.13: */ DUMMY(ioprio_set); DUMMY(ioprio_get); DUMMY(inotify_init); DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); /* linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(unshare); /* linux 2.6.17: */ DUMMY(splice); DUMMY(sync_file_range); DUMMY(tee); DUMMY(vmsplice); /* linux 2.6.18: */ DUMMY(move_pages); /* linux 2.6.19: */ DUMMY(getcpu); /* linux 2.6.22: */ DUMMY(signalfd); DUMMY(timerfd_create); /* linux 2.6.25: */ DUMMY(timerfd_settime); DUMMY(timerfd_gettime); /* linux 2.6.27: */ DUMMY(signalfd4); DUMMY(inotify_init1); /* linux 2.6.30: */ DUMMY(preadv); DUMMY(pwritev); -/* linux 2.6.31 */ -DUMMY(rt_tsigqueueinfo); +/* linux 2.6.31: */ +DUMMY(rt_tgsigqueueinfo); DUMMY(perf_event_open); /* linux 2.6.33: */ DUMMY(fanotify_init); DUMMY(fanotify_mark); -/* later: */ +/* linux 2.6.39: */ DUMMY(name_to_handle_at); DUMMY(open_by_handle_at); DUMMY(clock_adjtime); +/* linux 3.0: */ DUMMY(setns); +/* linux 3.2: */ DUMMY(process_vm_readv); DUMMY(process_vm_writev); +/* linux 3.5: */ +DUMMY(kcmp); +/* linux 3.8: */ +DUMMY(finit_module); +DUMMY(sched_setattr); +DUMMY(sched_getattr); +/* linux 3.14: */ +DUMMY(renameat2); +/* linux 3.15: */ +DUMMY(seccomp); +DUMMY(getrandom); +DUMMY(memfd_create); +/* linux 3.18: */ +DUMMY(bpf); +/* linux 3.19: */ +DUMMY(execveat); +/* linux 4.2: */ +DUMMY(userfaultfd); +/* linux 4.3: */ +DUMMY(membarrier); +/* linux 4.4: */ +DUMMY(mlock2); +/* linux 4.5: */ +DUMMY(copy_file_range); +/* linux 4.6: */ +DUMMY(preadv2); +DUMMY(pwritev2); +/* linux 4.8: */ +DUMMY(pkey_mprotect); +DUMMY(pkey_alloc); +DUMMY(pkey_free); #define DUMMY_XATTR(s) \ int \ linux_ ## s ## xattr( \ struct thread *td, struct linux_ ## s ## xattr_args *arg) \ { \ \ return (ENOATTR); \ } DUMMY_XATTR(set); DUMMY_XATTR(lset); DUMMY_XATTR(fset); DUMMY_XATTR(get); DUMMY_XATTR(lget); DUMMY_XATTR(fget); DUMMY_XATTR(list); DUMMY_XATTR(llist); DUMMY_XATTR(flist); DUMMY_XATTR(remove); DUMMY_XATTR(lremove); DUMMY_XATTR(fremove); Index: projects/ipsec/sys/i386/linux/linux_proto.h =================================================================== --- projects/ipsec/sys/i386/linux/linux_proto.h (revision 313312) +++ projects/ipsec/sys/i386/linux/linux_proto.h (revision 313313) @@ -1,1780 +1,2059 @@ /* * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/i386/linux/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/i386/linux/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ #ifndef _LINUX_SYSPROTO_H_ #define _LINUX_SYSPROTO_H_ #include #include #include #include #include #include #include #include struct proc; struct thread; #define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \ 0 : sizeof(register_t) - sizeof(t)) #if BYTE_ORDER == LITTLE_ENDIAN #define PADL_(t) 0 #define PADR_(t) PAD_(t) #else #define PADL_(t) PAD_(t) #define PADR_(t) 0 #endif #define nosys linux_nosys struct linux_exit_args { char rval_l_[PADL_(int)]; int rval; char rval_r_[PADR_(int)]; }; struct linux_fork_args { register_t dummy; }; struct linux_open_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_waitpid_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char status_l_[PADL_(l_int *)]; l_int * status; char status_r_[PADR_(l_int *)]; char options_l_[PADL_(l_int)]; l_int options; char options_r_[PADR_(l_int)]; }; struct linux_creat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_link_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; }; struct linux_unlink_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_execve_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char argp_l_[PADL_(char **)]; char ** argp; char argp_r_[PADR_(char **)]; char envp_l_[PADL_(char **)]; char ** envp; char envp_r_[PADR_(char **)]; }; struct linux_chdir_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_time_args { char tm_l_[PADL_(l_time_t *)]; l_time_t * tm; char tm_r_[PADR_(l_time_t *)]; }; struct linux_mknod_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char dev_l_[PADL_(l_dev_t)]; l_dev_t dev; char dev_r_[PADR_(l_dev_t)]; }; struct linux_chmod_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; }; struct linux_lchown16_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; }; struct linux_stat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char up_l_[PADL_(struct linux_stat *)]; struct linux_stat * up; char up_r_[PADR_(struct linux_stat *)]; }; struct linux_lseek_args { char fdes_l_[PADL_(l_uint)]; l_uint fdes; char fdes_r_[PADR_(l_uint)]; char off_l_[PADL_(l_off_t)]; l_off_t off; char off_r_[PADR_(l_off_t)]; char whence_l_[PADL_(l_int)]; l_int whence; char whence_r_[PADR_(l_int)]; }; struct linux_getpid_args { register_t dummy; }; struct linux_mount_args { char specialfile_l_[PADL_(char *)]; char * specialfile; char specialfile_r_[PADR_(char *)]; char dir_l_[PADL_(char *)]; char * dir; char dir_r_[PADR_(char *)]; char filesystemtype_l_[PADL_(char *)]; char * filesystemtype; char filesystemtype_r_[PADR_(char *)]; char rwflag_l_[PADL_(l_ulong)]; l_ulong rwflag; char rwflag_r_[PADR_(l_ulong)]; char data_l_[PADL_(void *)]; void * data; char data_r_[PADR_(void *)]; }; struct linux_oldumount_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_setuid16_args { char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; }; struct linux_getuid16_args { register_t dummy; }; struct linux_stime_args { register_t dummy; }; struct linux_ptrace_args { char req_l_[PADL_(l_long)]; l_long req; char req_r_[PADR_(l_long)]; char pid_l_[PADL_(l_long)]; l_long pid; char pid_r_[PADR_(l_long)]; char addr_l_[PADL_(l_long)]; l_long addr; char addr_r_[PADR_(l_long)]; char data_l_[PADL_(l_long)]; l_long data; char data_r_[PADR_(l_long)]; }; struct linux_alarm_args { char secs_l_[PADL_(l_uint)]; l_uint secs; char secs_r_[PADR_(l_uint)]; }; struct linux_fstat_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char up_l_[PADL_(struct linux_stat *)]; struct linux_stat * up; char up_r_[PADR_(struct linux_stat *)]; }; struct linux_pause_args { register_t dummy; }; struct linux_utime_args { char fname_l_[PADL_(char *)]; char * fname; char fname_r_[PADR_(char *)]; char times_l_[PADL_(struct l_utimbuf *)]; struct l_utimbuf * times; char times_r_[PADR_(struct l_utimbuf *)]; }; struct linux_access_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; }; struct linux_nice_args { char inc_l_[PADL_(l_int)]; l_int inc; char inc_r_[PADR_(l_int)]; }; struct linux_kill_args { char pid_l_[PADL_(l_int)]; l_int pid; char pid_r_[PADR_(l_int)]; char signum_l_[PADL_(l_int)]; l_int signum; char signum_r_[PADR_(l_int)]; }; struct linux_rename_args { char from_l_[PADL_(char *)]; char * from; char from_r_[PADR_(char *)]; char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; }; struct linux_mkdir_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_rmdir_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; }; struct linux_pipe_args { char pipefds_l_[PADL_(l_int *)]; l_int * pipefds; char pipefds_r_[PADR_(l_int *)]; }; struct linux_times_args { char buf_l_[PADL_(struct l_times_argv *)]; struct l_times_argv * buf; char buf_r_[PADR_(struct l_times_argv *)]; }; struct linux_brk_args { char dsend_l_[PADL_(l_ulong)]; l_ulong dsend; char dsend_r_[PADR_(l_ulong)]; }; struct linux_setgid16_args { char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; }; struct linux_getgid16_args { register_t dummy; }; struct linux_signal_args { char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char handler_l_[PADL_(void *)]; void * handler; char handler_r_[PADR_(void *)]; }; struct linux_geteuid16_args { register_t dummy; }; struct linux_getegid16_args { register_t dummy; }; struct linux_umount_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_ioctl_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(l_ulong)]; l_ulong arg; char arg_r_[PADR_(l_ulong)]; }; struct linux_fcntl_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(l_ulong)]; l_ulong arg; char arg_r_[PADR_(l_ulong)]; }; struct linux_olduname_args { register_t dummy; }; struct linux_ustat_args { char dev_l_[PADL_(l_dev_t)]; l_dev_t dev; char dev_r_[PADR_(l_dev_t)]; char ubuf_l_[PADL_(struct l_ustat *)]; struct l_ustat * ubuf; char ubuf_r_[PADR_(struct l_ustat *)]; }; struct linux_getppid_args { register_t dummy; }; struct linux_sigaction_args { char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char nsa_l_[PADL_(l_osigaction_t *)]; l_osigaction_t * nsa; char nsa_r_[PADR_(l_osigaction_t *)]; char osa_l_[PADL_(l_osigaction_t *)]; l_osigaction_t * osa; char osa_r_[PADR_(l_osigaction_t *)]; }; struct linux_sgetmask_args { register_t dummy; }; struct linux_ssetmask_args { char mask_l_[PADL_(l_osigset_t)]; l_osigset_t mask; char mask_r_[PADR_(l_osigset_t)]; }; struct linux_setreuid16_args { char ruid_l_[PADL_(l_uid16_t)]; l_uid16_t ruid; char ruid_r_[PADR_(l_uid16_t)]; char euid_l_[PADL_(l_uid16_t)]; l_uid16_t euid; char euid_r_[PADR_(l_uid16_t)]; }; struct linux_setregid16_args { char rgid_l_[PADL_(l_gid16_t)]; l_gid16_t rgid; char rgid_r_[PADR_(l_gid16_t)]; char egid_l_[PADL_(l_gid16_t)]; l_gid16_t egid; char egid_r_[PADR_(l_gid16_t)]; }; struct linux_sigsuspend_args { char hist0_l_[PADL_(l_int)]; l_int hist0; char hist0_r_[PADR_(l_int)]; char hist1_l_[PADL_(l_int)]; l_int hist1; char hist1_r_[PADR_(l_int)]; char mask_l_[PADL_(l_osigset_t)]; l_osigset_t mask; char mask_r_[PADR_(l_osigset_t)]; }; struct linux_sigpending_args { char mask_l_[PADL_(l_osigset_t *)]; l_osigset_t * mask; char mask_r_[PADR_(l_osigset_t *)]; }; struct linux_sethostname_args { char hostname_l_[PADL_(char *)]; char * hostname; char hostname_r_[PADR_(char *)]; char len_l_[PADL_(u_int)]; u_int len; char len_r_[PADR_(u_int)]; }; struct linux_setrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; }; struct linux_old_getrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; }; struct linux_getgroups16_args { char gidsetsize_l_[PADL_(l_uint)]; l_uint gidsetsize; char gidsetsize_r_[PADR_(l_uint)]; char gidset_l_[PADL_(l_gid16_t *)]; l_gid16_t * gidset; char gidset_r_[PADR_(l_gid16_t *)]; }; struct linux_setgroups16_args { char gidsetsize_l_[PADL_(l_uint)]; l_uint gidsetsize; char gidsetsize_r_[PADR_(l_uint)]; char gidset_l_[PADL_(l_gid16_t *)]; l_gid16_t * gidset; char gidset_r_[PADR_(l_gid16_t *)]; }; struct linux_old_select_args { char ptr_l_[PADL_(struct l_old_select_argv *)]; struct l_old_select_argv * ptr; char ptr_r_[PADR_(struct l_old_select_argv *)]; }; struct linux_symlink_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; }; struct linux_lstat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char up_l_[PADL_(struct l_stat *)]; struct l_stat * up; char up_r_[PADR_(struct l_stat *)]; }; struct linux_readlink_args { char name_l_[PADL_(char *)]; char * name; char name_r_[PADR_(char *)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char count_l_[PADL_(l_int)]; l_int count; char count_r_[PADR_(l_int)]; }; struct linux_uselib_args { char library_l_[PADL_(char *)]; char * library; char library_r_[PADR_(char *)]; }; struct linux_reboot_args { char magic1_l_[PADL_(l_int)]; l_int magic1; char magic1_r_[PADR_(l_int)]; char magic2_l_[PADL_(l_int)]; l_int magic2; char magic2_r_[PADR_(l_int)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(void *)]; void * arg; char arg_r_[PADR_(void *)]; }; struct linux_readdir_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char dent_l_[PADL_(struct l_dirent *)]; struct l_dirent * dent; char dent_r_[PADR_(struct l_dirent *)]; char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; }; struct linux_mmap_args { char ptr_l_[PADL_(struct l_mmap_argv *)]; struct l_mmap_argv * ptr; char ptr_r_[PADR_(struct l_mmap_argv *)]; }; struct linux_truncate_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char length_l_[PADL_(l_ulong)]; l_ulong length; char length_r_[PADR_(l_ulong)]; }; struct linux_ftruncate_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char length_l_[PADL_(long)]; long length; char length_r_[PADR_(long)]; }; struct linux_getpriority_args { char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)]; char who_l_[PADL_(int)]; int who; char who_r_[PADR_(int)]; }; struct linux_statfs_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; }; struct linux_fstatfs_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; }; struct linux_ioperm_args { char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; char length_l_[PADL_(l_ulong)]; l_ulong length; char length_r_[PADR_(l_ulong)]; char enable_l_[PADL_(l_int)]; l_int enable; char enable_r_[PADR_(l_int)]; }; struct linux_socketcall_args { char what_l_[PADL_(l_int)]; l_int what; char what_r_[PADR_(l_int)]; char args_l_[PADL_(l_ulong)]; l_ulong args; char args_r_[PADR_(l_ulong)]; }; struct linux_syslog_args { char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; }; struct linux_setitimer_args { char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; char oitv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * oitv; char oitv_r_[PADR_(struct l_itimerval *)]; }; struct linux_getitimer_args { char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; }; struct linux_newstat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; }; struct linux_newlstat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; }; struct linux_newfstat_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; }; struct linux_uname_args { register_t dummy; }; struct linux_iopl_args { char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; }; struct linux_vhangup_args { register_t dummy; }; struct linux_vm86old_args { register_t dummy; }; struct linux_wait4_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char status_l_[PADL_(l_int *)]; l_int * status; char status_r_[PADR_(l_int *)]; char options_l_[PADL_(l_int)]; l_int options; char options_r_[PADR_(l_int)]; char rusage_l_[PADL_(void *)]; void * rusage; char rusage_r_[PADR_(void *)]; }; struct linux_swapoff_args { register_t dummy; }; struct linux_sysinfo_args { char info_l_[PADL_(struct l_sysinfo *)]; struct l_sysinfo * info; char info_r_[PADR_(struct l_sysinfo *)]; }; struct linux_ipc_args { char what_l_[PADL_(l_uint)]; l_uint what; char what_r_[PADR_(l_uint)]; char arg1_l_[PADL_(l_int)]; l_int arg1; char arg1_r_[PADR_(l_int)]; char arg2_l_[PADL_(l_int)]; l_int arg2; char arg2_r_[PADR_(l_int)]; char arg3_l_[PADL_(l_int)]; l_int arg3; char arg3_r_[PADR_(l_int)]; char ptr_l_[PADL_(void *)]; void * ptr; char ptr_r_[PADR_(void *)]; char arg5_l_[PADL_(l_long)]; l_long arg5; char arg5_r_[PADR_(l_long)]; }; struct linux_sigreturn_args { char sfp_l_[PADL_(struct l_sigframe *)]; struct l_sigframe * sfp; char sfp_r_[PADR_(struct l_sigframe *)]; }; struct linux_clone_args { char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char stack_l_[PADL_(void *)]; void * stack; char stack_r_[PADR_(void *)]; char parent_tidptr_l_[PADL_(void *)]; void * parent_tidptr; char parent_tidptr_r_[PADR_(void *)]; char tls_l_[PADL_(void *)]; void * tls; char tls_r_[PADR_(void *)]; char child_tidptr_l_[PADL_(void *)]; void * child_tidptr; char child_tidptr_r_[PADR_(void *)]; }; struct linux_setdomainname_args { char name_l_[PADL_(char *)]; char * name; char name_r_[PADR_(char *)]; char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)]; }; struct linux_newuname_args { char buf_l_[PADL_(struct l_new_utsname *)]; struct l_new_utsname * buf; char buf_r_[PADR_(struct l_new_utsname *)]; }; struct linux_modify_ldt_args { char func_l_[PADL_(l_int)]; l_int func; char func_r_[PADR_(l_int)]; char ptr_l_[PADL_(void *)]; void * ptr; char ptr_r_[PADR_(void *)]; char bytecount_l_[PADL_(l_ulong)]; l_ulong bytecount; char bytecount_r_[PADR_(l_ulong)]; }; struct linux_adjtimex_args { register_t dummy; }; struct linux_mprotect_args { char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)]; char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)]; }; struct linux_sigprocmask_args { char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; char mask_l_[PADL_(l_osigset_t *)]; l_osigset_t * mask; char mask_r_[PADR_(l_osigset_t *)]; char omask_l_[PADL_(l_osigset_t *)]; l_osigset_t * omask; char omask_r_[PADR_(l_osigset_t *)]; }; struct linux_create_module_args { register_t dummy; }; struct linux_init_module_args { register_t dummy; }; struct linux_delete_module_args { register_t dummy; }; struct linux_get_kernel_syms_args { register_t dummy; }; struct linux_quotactl_args { register_t dummy; }; struct linux_bdflush_args { register_t dummy; }; struct linux_sysfs_args { char option_l_[PADL_(l_int)]; l_int option; char option_r_[PADR_(l_int)]; char arg1_l_[PADL_(l_ulong)]; l_ulong arg1; char arg1_r_[PADR_(l_ulong)]; char arg2_l_[PADL_(l_ulong)]; l_ulong arg2; char arg2_r_[PADR_(l_ulong)]; }; struct linux_personality_args { char per_l_[PADL_(l_uint)]; l_uint per; char per_r_[PADR_(l_uint)]; }; struct linux_setfsuid16_args { char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; }; struct linux_setfsgid16_args { char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; }; struct linux_llseek_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char ohigh_l_[PADL_(l_ulong)]; l_ulong ohigh; char ohigh_r_[PADR_(l_ulong)]; char olow_l_[PADL_(l_ulong)]; l_ulong olow; char olow_r_[PADR_(l_ulong)]; char res_l_[PADL_(l_loff_t *)]; l_loff_t * res; char res_r_[PADR_(l_loff_t *)]; char whence_l_[PADL_(l_uint)]; l_uint whence; char whence_r_[PADR_(l_uint)]; }; struct linux_getdents_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char dent_l_[PADL_(void *)]; void * dent; char dent_r_[PADR_(void *)]; char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; }; struct linux_select_args { char nfds_l_[PADL_(l_int)]; l_int nfds; char nfds_r_[PADR_(l_int)]; char readfds_l_[PADL_(l_fd_set *)]; l_fd_set * readfds; char readfds_r_[PADR_(l_fd_set *)]; char writefds_l_[PADL_(l_fd_set *)]; l_fd_set * writefds; char writefds_r_[PADR_(l_fd_set *)]; char exceptfds_l_[PADL_(l_fd_set *)]; l_fd_set * exceptfds; char exceptfds_r_[PADR_(l_fd_set *)]; char timeout_l_[PADL_(struct l_timeval *)]; struct l_timeval * timeout; char timeout_r_[PADR_(struct l_timeval *)]; }; struct linux_msync_args { char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char fl_l_[PADL_(l_int)]; l_int fl; char fl_r_[PADR_(l_int)]; }; struct linux_getsid_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; }; struct linux_fdatasync_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; }; struct linux_sysctl_args { char args_l_[PADL_(struct l___sysctl_args *)]; struct l___sysctl_args * args; char args_r_[PADR_(struct l___sysctl_args *)]; }; struct linux_sched_setparam_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; }; struct linux_sched_getparam_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; }; struct linux_sched_setscheduler_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; }; struct linux_sched_getscheduler_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; }; struct linux_sched_get_priority_max_args { char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; }; struct linux_sched_get_priority_min_args { char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; }; struct linux_sched_rr_get_interval_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char interval_l_[PADL_(struct l_timespec *)]; struct l_timespec * interval; char interval_r_[PADR_(struct l_timespec *)]; }; struct linux_nanosleep_args { char rqtp_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * rqtp; char rqtp_r_[PADR_(const struct l_timespec *)]; char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; }; struct linux_mremap_args { char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; char old_len_l_[PADL_(l_ulong)]; l_ulong old_len; char old_len_r_[PADR_(l_ulong)]; char new_len_l_[PADL_(l_ulong)]; l_ulong new_len; char new_len_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; char new_addr_l_[PADL_(l_ulong)]; l_ulong new_addr; char new_addr_r_[PADR_(l_ulong)]; }; struct linux_setresuid16_args { char ruid_l_[PADL_(l_uid16_t)]; l_uid16_t ruid; char ruid_r_[PADR_(l_uid16_t)]; char euid_l_[PADL_(l_uid16_t)]; l_uid16_t euid; char euid_r_[PADR_(l_uid16_t)]; char suid_l_[PADL_(l_uid16_t)]; l_uid16_t suid; char suid_r_[PADR_(l_uid16_t)]; }; struct linux_getresuid16_args { char ruid_l_[PADL_(l_uid16_t *)]; l_uid16_t * ruid; char ruid_r_[PADR_(l_uid16_t *)]; char euid_l_[PADL_(l_uid16_t *)]; l_uid16_t * euid; char euid_r_[PADR_(l_uid16_t *)]; char suid_l_[PADL_(l_uid16_t *)]; l_uid16_t * suid; char suid_r_[PADR_(l_uid16_t *)]; }; struct linux_vm86_args { register_t dummy; }; struct linux_query_module_args { register_t dummy; }; struct linux_nfsservctl_args { register_t dummy; }; struct linux_setresgid16_args { char rgid_l_[PADL_(l_gid16_t)]; l_gid16_t rgid; char rgid_r_[PADR_(l_gid16_t)]; char egid_l_[PADL_(l_gid16_t)]; l_gid16_t egid; char egid_r_[PADR_(l_gid16_t)]; char sgid_l_[PADL_(l_gid16_t)]; l_gid16_t sgid; char sgid_r_[PADR_(l_gid16_t)]; }; struct linux_getresgid16_args { char rgid_l_[PADL_(l_gid16_t *)]; l_gid16_t * rgid; char rgid_r_[PADR_(l_gid16_t *)]; char egid_l_[PADL_(l_gid16_t *)]; l_gid16_t * egid; char egid_r_[PADR_(l_gid16_t *)]; char sgid_l_[PADL_(l_gid16_t *)]; l_gid16_t * sgid; char sgid_r_[PADR_(l_gid16_t *)]; }; struct linux_prctl_args { char option_l_[PADL_(l_int)]; l_int option; char option_r_[PADR_(l_int)]; char arg2_l_[PADL_(l_int)]; l_int arg2; char arg2_r_[PADR_(l_int)]; char arg3_l_[PADL_(l_int)]; l_int arg3; char arg3_r_[PADR_(l_int)]; char arg4_l_[PADL_(l_int)]; l_int arg4; char arg4_r_[PADR_(l_int)]; char arg5_l_[PADL_(l_int)]; l_int arg5; char arg5_r_[PADR_(l_int)]; }; struct linux_rt_sigreturn_args { char ucp_l_[PADL_(struct l_ucontext *)]; struct l_ucontext * ucp; char ucp_r_[PADR_(struct l_ucontext *)]; }; struct linux_rt_sigaction_args { char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char act_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * act; char act_r_[PADR_(l_sigaction_t *)]; char oact_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * oact; char oact_r_[PADR_(l_sigaction_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigprocmask_args { char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; char omask_l_[PADL_(l_sigset_t *)]; l_sigset_t * omask; char omask_r_[PADR_(l_sigset_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigpending_args { char set_l_[PADL_(l_sigset_t *)]; l_sigset_t * set; char set_r_[PADR_(l_sigset_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigtimedwait_args { char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; char ptr_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * ptr; char ptr_r_[PADR_(l_siginfo_t *)]; char timeout_l_[PADL_(struct l_timeval *)]; struct l_timeval * timeout; char timeout_r_[PADR_(struct l_timeval *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigqueueinfo_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; }; struct linux_rt_sigsuspend_args { char newset_l_[PADL_(l_sigset_t *)]; l_sigset_t * newset; char newset_r_[PADR_(l_sigset_t *)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_pread_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; }; struct linux_pwrite_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; }; struct linux_chown16_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; }; struct linux_getcwd_args { char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)]; }; struct linux_capget_args { char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; }; struct linux_capset_args { char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; }; struct linux_sigaltstack_args { char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)]; char uoss_l_[PADL_(l_stack_t *)]; l_stack_t * uoss; char uoss_r_[PADR_(l_stack_t *)]; }; struct linux_sendfile_args { register_t dummy; }; struct linux_vfork_args { register_t dummy; }; struct linux_getrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; }; struct linux_mmap2_args { char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; char len_l_[PADL_(l_ulong)]; l_ulong len; char len_r_[PADR_(l_ulong)]; char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; char pgoff_l_[PADL_(l_ulong)]; l_ulong pgoff; char pgoff_r_[PADR_(l_ulong)]; }; struct linux_truncate64_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char length_l_[PADL_(l_loff_t)]; l_loff_t length; char length_r_[PADR_(l_loff_t)]; }; struct linux_ftruncate64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char length_l_[PADL_(l_loff_t)]; l_loff_t length; char length_r_[PADR_(l_loff_t)]; }; struct linux_stat64_args { char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; }; struct linux_lstat64_args { char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; }; struct linux_fstat64_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; }; struct linux_lchown_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_getuid_args { register_t dummy; }; struct linux_getgid_args { register_t dummy; }; struct linux_getgroups_args { char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; }; struct linux_setgroups_args { char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; }; struct linux_chown_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_setfsuid_args { char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; }; struct linux_setfsgid_args { char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_pivot_root_args { char new_root_l_[PADL_(char *)]; char * new_root; char new_root_r_[PADR_(char *)]; char put_old_l_[PADL_(char *)]; char * put_old; char put_old_r_[PADR_(char *)]; }; struct linux_mincore_args { char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char vec_l_[PADL_(u_char *)]; u_char * vec; char vec_r_[PADR_(u_char *)]; }; struct linux_getdents64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char dirent_l_[PADL_(void *)]; void * dirent; char dirent_r_[PADR_(void *)]; char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; }; struct linux_fcntl64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; char arg_l_[PADL_(l_ulong)]; l_ulong arg; char arg_r_[PADR_(l_ulong)]; }; struct linux_gettid_args { register_t dummy; }; struct linux_setxattr_args { register_t dummy; }; struct linux_lsetxattr_args { register_t dummy; }; struct linux_fsetxattr_args { register_t dummy; }; struct linux_getxattr_args { register_t dummy; }; struct linux_lgetxattr_args { register_t dummy; }; struct linux_fgetxattr_args { register_t dummy; }; struct linux_listxattr_args { register_t dummy; }; struct linux_llistxattr_args { register_t dummy; }; struct linux_flistxattr_args { register_t dummy; }; struct linux_removexattr_args { register_t dummy; }; struct linux_lremovexattr_args { register_t dummy; }; struct linux_fremovexattr_args { register_t dummy; }; struct linux_tkill_args { char tid_l_[PADL_(int)]; int tid; char tid_r_[PADR_(int)]; char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; struct linux_sys_futex_args { char uaddr_l_[PADL_(void *)]; void * uaddr; char uaddr_r_[PADR_(void *)]; char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)]; char val_l_[PADL_(uint32_t)]; uint32_t val; char val_r_[PADR_(uint32_t)]; char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; char uaddr2_l_[PADL_(uint32_t *)]; uint32_t * uaddr2; char uaddr2_r_[PADR_(uint32_t *)]; char val3_l_[PADL_(uint32_t)]; uint32_t val3; char val3_r_[PADR_(uint32_t)]; }; struct linux_sched_setaffinity_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; }; struct linux_sched_getaffinity_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; }; struct linux_set_thread_area_args { char desc_l_[PADL_(struct l_user_desc *)]; struct l_user_desc * desc; char desc_r_[PADR_(struct l_user_desc *)]; }; struct linux_get_thread_area_args { char desc_l_[PADL_(struct l_user_desc *)]; struct l_user_desc * desc; char desc_r_[PADR_(struct l_user_desc *)]; }; struct linux_fadvise64_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char advice_l_[PADL_(int)]; int advice; char advice_r_[PADR_(int)]; }; struct linux_exit_group_args { char error_code_l_[PADL_(int)]; int error_code; char error_code_r_[PADR_(int)]; }; struct linux_lookup_dcookie_args { register_t dummy; }; struct linux_epoll_create_args { char size_l_[PADL_(l_int)]; l_int size; char size_r_[PADR_(l_int)]; }; struct linux_epoll_ctl_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char op_l_[PADL_(l_int)]; l_int op; char op_r_[PADR_(l_int)]; char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char event_l_[PADL_(struct epoll_event *)]; struct epoll_event * event; char event_r_[PADR_(struct epoll_event *)]; }; struct linux_epoll_wait_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; char timeout_l_[PADL_(l_int)]; l_int timeout; char timeout_r_[PADR_(l_int)]; }; struct linux_remap_file_pages_args { register_t dummy; }; struct linux_set_tid_address_args { char tidptr_l_[PADL_(int *)]; int * tidptr; char tidptr_r_[PADR_(int *)]; }; struct linux_timer_create_args { char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)]; char evp_l_[PADL_(struct sigevent *)]; struct sigevent * evp; char evp_r_[PADR_(struct sigevent *)]; char timerid_l_[PADL_(l_timer_t *)]; l_timer_t * timerid; char timerid_r_[PADR_(l_timer_t *)]; }; struct linux_timer_settime_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char new_l_[PADL_(const struct itimerspec *)]; const struct itimerspec * new; char new_r_[PADR_(const struct itimerspec *)]; char old_l_[PADL_(struct itimerspec *)]; struct itimerspec * old; char old_r_[PADR_(struct itimerspec *)]; }; struct linux_timer_gettime_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; char setting_l_[PADL_(struct itimerspec *)]; struct itimerspec * setting; char setting_r_[PADR_(struct itimerspec *)]; }; struct linux_timer_getoverrun_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; }; struct linux_timer_delete_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; }; struct linux_clock_settime_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; }; struct linux_clock_gettime_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; }; struct linux_clock_getres_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; }; struct linux_clock_nanosleep_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; char rqtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rqtp; char rqtp_r_[PADR_(struct l_timespec *)]; char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; }; struct linux_statfs64_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char bufsize_l_[PADL_(size_t)]; size_t bufsize; char bufsize_r_[PADR_(size_t)]; char buf_l_[PADL_(struct l_statfs64_buf *)]; struct l_statfs64_buf * buf; char buf_r_[PADR_(struct l_statfs64_buf *)]; }; struct linux_fstatfs64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char bufsize_l_[PADL_(size_t)]; size_t bufsize; char bufsize_r_[PADR_(size_t)]; char buf_l_[PADL_(struct l_statfs64_buf *)]; struct l_statfs64_buf * buf; char buf_r_[PADR_(struct l_statfs64_buf *)]; }; struct linux_tgkill_args { char tgid_l_[PADL_(int)]; int tgid; char tgid_r_[PADR_(int)]; char pid_l_[PADL_(int)]; int pid; char pid_r_[PADR_(int)]; char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; struct linux_utimes_args { char fname_l_[PADL_(char *)]; char * fname; char fname_r_[PADR_(char *)]; char tptr_l_[PADL_(struct l_timeval *)]; struct l_timeval * tptr; char tptr_r_[PADR_(struct l_timeval *)]; }; struct linux_fadvise64_64_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; char len_l_[PADL_(l_loff_t)]; l_loff_t len; char len_r_[PADR_(l_loff_t)]; char advice_l_[PADL_(int)]; int advice; char advice_r_[PADR_(int)]; }; struct linux_mbind_args { register_t dummy; }; struct linux_get_mempolicy_args { register_t dummy; }; struct linux_set_mempolicy_args { register_t dummy; }; struct linux_mq_open_args { char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; char oflag_l_[PADL_(int)]; int oflag; char oflag_r_[PADR_(int)]; char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)]; char attr_l_[PADL_(struct mq_attr *)]; struct mq_attr * attr; char attr_r_[PADR_(struct mq_attr *)]; }; struct linux_mq_unlink_args { char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; }; struct linux_mq_timedsend_args { char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; char msg_ptr_l_[PADL_(const char *)]; const char * msg_ptr; char msg_ptr_r_[PADR_(const char *)]; char msg_len_l_[PADL_(size_t)]; size_t msg_len; char msg_len_r_[PADR_(size_t)]; char msg_prio_l_[PADL_(unsigned int)]; unsigned int msg_prio; char msg_prio_r_[PADR_(unsigned int)]; char abs_timeout_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * abs_timeout; char abs_timeout_r_[PADR_(const struct l_timespec *)]; }; struct linux_mq_timedreceive_args { char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; char msg_ptr_l_[PADL_(char *)]; char * msg_ptr; char msg_ptr_r_[PADR_(char *)]; char msg_len_l_[PADL_(size_t)]; size_t msg_len; char msg_len_r_[PADR_(size_t)]; char msg_prio_l_[PADL_(unsigned int)]; unsigned int msg_prio; char msg_prio_r_[PADR_(unsigned int)]; char abs_timeout_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * abs_timeout; char abs_timeout_r_[PADR_(const struct l_timespec *)]; }; struct linux_mq_notify_args { char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; char abs_timeout_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * abs_timeout; char abs_timeout_r_[PADR_(const struct l_timespec *)]; }; struct linux_mq_getsetattr_args { char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; char attr_l_[PADL_(const struct mq_attr *)]; const struct mq_attr * attr; char attr_r_[PADR_(const struct mq_attr *)]; char oattr_l_[PADL_(struct mq_attr *)]; struct mq_attr * oattr; char oattr_r_[PADR_(struct mq_attr *)]; }; struct linux_kexec_load_args { register_t dummy; }; struct linux_waitid_args { char idtype_l_[PADL_(int)]; int idtype; char idtype_r_[PADR_(int)]; char id_l_[PADL_(l_pid_t)]; l_pid_t id; char id_r_[PADR_(l_pid_t)]; char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)]; char rusage_l_[PADL_(void *)]; void * rusage; char rusage_r_[PADR_(void *)]; }; struct linux_add_key_args { register_t dummy; }; struct linux_request_key_args { register_t dummy; }; struct linux_keyctl_args { register_t dummy; }; struct linux_ioprio_set_args { register_t dummy; }; struct linux_ioprio_get_args { register_t dummy; }; struct linux_inotify_init_args { register_t dummy; }; struct linux_inotify_add_watch_args { register_t dummy; }; struct linux_inotify_rm_watch_args { register_t dummy; }; struct linux_migrate_pages_args { register_t dummy; }; struct linux_openat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_mkdirat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_mknodat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char dev_l_[PADL_(l_uint)]; l_uint dev; char dev_r_[PADR_(l_uint)]; }; struct linux_fchownat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)]; char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_futimesat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)]; char utimes_l_[PADL_(struct l_timeval *)]; struct l_timeval * utimes; char utimes_r_[PADR_(struct l_timeval *)]; }; struct linux_fstatat64_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)]; char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_unlinkat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_renameat_args { char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; }; struct linux_linkat_args { char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_symlinkat_args { char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; }; struct linux_readlinkat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; char bufsiz_l_[PADL_(l_int)]; l_int bufsiz; char bufsiz_r_[PADR_(l_int)]; }; struct linux_fchmodat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; }; struct linux_faccessat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; }; struct linux_pselect6_args { char nfds_l_[PADL_(l_int)]; l_int nfds; char nfds_r_[PADR_(l_int)]; char readfds_l_[PADL_(l_fd_set *)]; l_fd_set * readfds; char readfds_r_[PADR_(l_fd_set *)]; char writefds_l_[PADL_(l_fd_set *)]; l_fd_set * writefds; char writefds_r_[PADR_(l_fd_set *)]; char exceptfds_l_[PADL_(l_fd_set *)]; l_fd_set * exceptfds; char exceptfds_r_[PADR_(l_fd_set *)]; char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; char sig_l_[PADL_(l_uintptr_t *)]; l_uintptr_t * sig; char sig_r_[PADR_(l_uintptr_t *)]; }; struct linux_ppoll_args { char fds_l_[PADL_(struct pollfd *)]; struct pollfd * fds; char fds_r_[PADR_(struct pollfd *)]; char nfds_l_[PADL_(uint32_t)]; uint32_t nfds; char nfds_r_[PADR_(uint32_t)]; char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; char sset_l_[PADL_(l_sigset_t *)]; l_sigset_t * sset; char sset_r_[PADR_(l_sigset_t *)]; char ssize_l_[PADL_(l_size_t)]; l_size_t ssize; char ssize_r_[PADR_(l_size_t)]; }; struct linux_unshare_args { register_t dummy; }; struct linux_set_robust_list_args { char head_l_[PADL_(struct linux_robust_list_head *)]; struct linux_robust_list_head * head; char head_r_[PADR_(struct linux_robust_list_head *)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; }; struct linux_get_robust_list_args { char pid_l_[PADL_(l_int)]; l_int pid; char pid_r_[PADR_(l_int)]; char head_l_[PADL_(struct linux_robust_list_head **)]; struct linux_robust_list_head ** head; char head_r_[PADR_(struct linux_robust_list_head **)]; char len_l_[PADL_(l_size_t *)]; l_size_t * len; char len_r_[PADR_(l_size_t *)]; }; struct linux_splice_args { register_t dummy; }; struct linux_sync_file_range_args { register_t dummy; }; struct linux_tee_args { register_t dummy; }; struct linux_vmsplice_args { register_t dummy; }; struct linux_move_pages_args { register_t dummy; }; struct linux_getcpu_args { register_t dummy; }; struct linux_epoll_pwait_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; char timeout_l_[PADL_(l_int)]; l_int timeout; char timeout_r_[PADR_(l_int)]; char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; }; struct linux_utimensat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; char times_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * times; char times_r_[PADR_(const struct l_timespec *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_signalfd_args { register_t dummy; }; struct linux_timerfd_create_args { register_t dummy; }; struct linux_eventfd_args { char initval_l_[PADL_(l_uint)]; l_uint initval; char initval_r_[PADR_(l_uint)]; }; struct linux_fallocate_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; char len_l_[PADL_(l_loff_t)]; l_loff_t len; char len_r_[PADR_(l_loff_t)]; }; struct linux_timerfd_settime_args { register_t dummy; }; struct linux_timerfd_gettime_args { register_t dummy; }; struct linux_signalfd4_args { register_t dummy; }; struct linux_eventfd2_args { char initval_l_[PADL_(l_uint)]; l_uint initval; char initval_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_epoll_create1_args { char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_dup3_args { char oldfd_l_[PADL_(l_int)]; l_int oldfd; char oldfd_r_[PADR_(l_int)]; char newfd_l_[PADL_(l_int)]; l_int newfd; char newfd_r_[PADR_(l_int)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_pipe2_args { char pipefds_l_[PADL_(l_int *)]; l_int * pipefds; char pipefds_r_[PADR_(l_int *)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_inotify_init1_args { register_t dummy; }; struct linux_preadv_args { - register_t dummy; + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; }; struct linux_pwritev_args { - register_t dummy; + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; }; -struct linux_rt_tsigqueueinfo_args { - register_t dummy; +struct linux_rt_tgsigqueueinfo_args { + char tgid_l_[PADL_(l_pid_t)]; l_pid_t tgid; char tgid_r_[PADR_(l_pid_t)]; + char tid_l_[PADL_(l_pid_t)]; l_pid_t tid; char tid_r_[PADR_(l_pid_t)]; + char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; + char uinfo_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * uinfo; char uinfo_r_[PADR_(l_siginfo_t *)]; }; struct linux_perf_event_open_args { register_t dummy; }; struct linux_recvmmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; }; struct linux_fanotify_init_args { register_t dummy; }; struct linux_fanotify_mark_args { register_t dummy; }; struct linux_prlimit64_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; char new_l_[PADL_(struct rlimit *)]; struct rlimit * new; char new_r_[PADR_(struct rlimit *)]; char old_l_[PADL_(struct rlimit *)]; struct rlimit * old; char old_r_[PADR_(struct rlimit *)]; }; struct linux_name_to_handle_at_args { register_t dummy; }; struct linux_open_by_handle_at_args { register_t dummy; }; struct linux_clock_adjtime_args { register_t dummy; }; struct linux_syncfs_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; }; struct linux_sendmmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_setns_args { register_t dummy; }; struct linux_process_vm_readv_args { - register_t dummy; + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; + char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; }; struct linux_process_vm_writev_args { - register_t dummy; + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; + char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; }; +struct linux_kcmp_args { + char pid1_l_[PADL_(l_pid_t)]; l_pid_t pid1; char pid1_r_[PADR_(l_pid_t)]; + char pid2_l_[PADL_(l_pid_t)]; l_pid_t pid2; char pid2_r_[PADR_(l_pid_t)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char idx1_l_[PADL_(l_ulong)]; l_ulong idx1; char idx1_r_[PADR_(l_ulong)]; + char idx_l_[PADL_(l_ulong)]; l_ulong idx; char idx_r_[PADR_(l_ulong)]; +}; +struct linux_finit_module_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_sched_setattr_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_sched_getattr_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_renameat2_args { + char oldfd_l_[PADL_(l_int)]; l_int oldfd; char oldfd_r_[PADR_(l_int)]; + char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char newfd_l_[PADL_(l_int)]; l_int newfd; char newfd_r_[PADR_(l_int)]; + char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; + char flags_l_[PADL_(unsigned int)]; unsigned int flags; char flags_r_[PADR_(unsigned int)]; +}; +struct linux_seccomp_args { + char op_l_[PADL_(l_uint)]; l_uint op; char op_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; + char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; +}; +struct linux_getrandom_args { + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_memfd_create_args { + char uname_ptr_l_[PADL_(const char *)]; const char * uname_ptr; char uname_ptr_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_bpf_args { + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; +}; +struct linux_execveat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char argv_l_[PADL_(const char **)]; const char ** argv; char argv_r_[PADR_(const char **)]; + char envp_l_[PADL_(const char **)]; const char ** envp; char envp_r_[PADR_(const char **)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_socket_args { + char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char protocol_l_[PADL_(l_int)]; l_int protocol; char protocol_r_[PADR_(l_int)]; +}; +struct linux_socketpair_args { + char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char protocol_l_[PADL_(l_int)]; l_int protocol; char protocol_r_[PADR_(l_int)]; + char rsv_l_[PADL_(l_uintptr_t)]; l_uintptr_t rsv; char rsv_r_[PADR_(l_uintptr_t)]; +}; +struct linux_bind_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; +}; +struct linux_connect_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; +}; +struct linux_listen_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char backlog_l_[PADL_(l_int)]; l_int backlog; char backlog_r_[PADR_(l_int)]; +}; +struct linux_accept4_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_getsockopt_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; + char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; + char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; + char optlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t optlen; char optlen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_setsockopt_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; + char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; + char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; + char optlen_l_[PADL_(l_int)]; l_int optlen; char optlen_r_[PADR_(l_int)]; +}; +struct linux_getsockname_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_getpeername_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_sendto_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; + char to_l_[PADL_(l_uintptr_t)]; l_uintptr_t to; char to_r_[PADR_(l_uintptr_t)]; + char tolen_l_[PADL_(l_int)]; l_int tolen; char tolen_r_[PADR_(l_int)]; +}; +struct linux_sendmsg_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_recvfrom_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char buf_l_[PADL_(l_uintptr_t)]; l_uintptr_t buf; char buf_r_[PADR_(l_uintptr_t)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; + char from_l_[PADL_(l_uintptr_t)]; l_uintptr_t from; char from_r_[PADR_(l_uintptr_t)]; + char fromlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t fromlen; char fromlen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_recvmsg_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_shutdown_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; +}; +struct linux_userfaultfd_args { + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_membarrier_args { + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_mlock2_args { + char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_copy_file_range_args { + char fd_in_l_[PADL_(l_int)]; l_int fd_in; char fd_in_r_[PADR_(l_int)]; + char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char fd_out_l_[PADL_(l_int)]; l_int fd_out; char fd_out_r_[PADR_(l_int)]; + char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_preadv2_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_pwritev2_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_pkey_mprotect_args { + char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; + char pkey_l_[PADL_(l_int)]; l_int pkey; char pkey_r_[PADR_(l_int)]; +}; +struct linux_pkey_alloc_args { + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; + char init_val_l_[PADL_(l_ulong)]; l_ulong init_val; char init_val_r_[PADR_(l_ulong)]; +}; +struct linux_pkey_free_args { + char pkey_l_[PADL_(l_int)]; l_int pkey; char pkey_r_[PADR_(l_int)]; +}; #define nosys linux_nosys int linux_exit(struct thread *, struct linux_exit_args *); int linux_fork(struct thread *, struct linux_fork_args *); int linux_open(struct thread *, struct linux_open_args *); int linux_waitpid(struct thread *, struct linux_waitpid_args *); int linux_creat(struct thread *, struct linux_creat_args *); int linux_link(struct thread *, struct linux_link_args *); int linux_unlink(struct thread *, struct linux_unlink_args *); int linux_execve(struct thread *, struct linux_execve_args *); int linux_chdir(struct thread *, struct linux_chdir_args *); int linux_time(struct thread *, struct linux_time_args *); int linux_mknod(struct thread *, struct linux_mknod_args *); int linux_chmod(struct thread *, struct linux_chmod_args *); int linux_lchown16(struct thread *, struct linux_lchown16_args *); int linux_stat(struct thread *, struct linux_stat_args *); int linux_lseek(struct thread *, struct linux_lseek_args *); int linux_getpid(struct thread *, struct linux_getpid_args *); int linux_mount(struct thread *, struct linux_mount_args *); int linux_oldumount(struct thread *, struct linux_oldumount_args *); int linux_setuid16(struct thread *, struct linux_setuid16_args *); int linux_getuid16(struct thread *, struct linux_getuid16_args *); int linux_stime(struct thread *, struct linux_stime_args *); int linux_ptrace(struct thread *, struct linux_ptrace_args *); int linux_alarm(struct thread *, struct linux_alarm_args *); int linux_fstat(struct thread *, struct linux_fstat_args *); int linux_pause(struct thread *, struct linux_pause_args *); int linux_utime(struct thread *, struct linux_utime_args *); int linux_access(struct thread *, struct linux_access_args *); int linux_nice(struct thread *, struct linux_nice_args *); int linux_kill(struct thread *, struct linux_kill_args *); int linux_rename(struct thread *, struct linux_rename_args *); int linux_mkdir(struct thread *, struct linux_mkdir_args *); int linux_rmdir(struct thread *, struct linux_rmdir_args *); int linux_pipe(struct thread *, struct linux_pipe_args *); int linux_times(struct thread *, struct linux_times_args *); int linux_brk(struct thread *, struct linux_brk_args *); int linux_setgid16(struct thread *, struct linux_setgid16_args *); int linux_getgid16(struct thread *, struct linux_getgid16_args *); int linux_signal(struct thread *, struct linux_signal_args *); int linux_geteuid16(struct thread *, struct linux_geteuid16_args *); int linux_getegid16(struct thread *, struct linux_getegid16_args *); int linux_umount(struct thread *, struct linux_umount_args *); int linux_ioctl(struct thread *, struct linux_ioctl_args *); int linux_fcntl(struct thread *, struct linux_fcntl_args *); int linux_olduname(struct thread *, struct linux_olduname_args *); int linux_ustat(struct thread *, struct linux_ustat_args *); int linux_getppid(struct thread *, struct linux_getppid_args *); int linux_sigaction(struct thread *, struct linux_sigaction_args *); int linux_sgetmask(struct thread *, struct linux_sgetmask_args *); int linux_ssetmask(struct thread *, struct linux_ssetmask_args *); int linux_setreuid16(struct thread *, struct linux_setreuid16_args *); int linux_setregid16(struct thread *, struct linux_setregid16_args *); int linux_sigsuspend(struct thread *, struct linux_sigsuspend_args *); int linux_sigpending(struct thread *, struct linux_sigpending_args *); int linux_sethostname(struct thread *, struct linux_sethostname_args *); int linux_setrlimit(struct thread *, struct linux_setrlimit_args *); int linux_old_getrlimit(struct thread *, struct linux_old_getrlimit_args *); int linux_getgroups16(struct thread *, struct linux_getgroups16_args *); int linux_setgroups16(struct thread *, struct linux_setgroups16_args *); int linux_old_select(struct thread *, struct linux_old_select_args *); int linux_symlink(struct thread *, struct linux_symlink_args *); int linux_lstat(struct thread *, struct linux_lstat_args *); int linux_readlink(struct thread *, struct linux_readlink_args *); int linux_uselib(struct thread *, struct linux_uselib_args *); int linux_reboot(struct thread *, struct linux_reboot_args *); int linux_readdir(struct thread *, struct linux_readdir_args *); int linux_mmap(struct thread *, struct linux_mmap_args *); int linux_truncate(struct thread *, struct linux_truncate_args *); int linux_ftruncate(struct thread *, struct linux_ftruncate_args *); int linux_getpriority(struct thread *, struct linux_getpriority_args *); int linux_statfs(struct thread *, struct linux_statfs_args *); int linux_fstatfs(struct thread *, struct linux_fstatfs_args *); int linux_ioperm(struct thread *, struct linux_ioperm_args *); int linux_socketcall(struct thread *, struct linux_socketcall_args *); int linux_syslog(struct thread *, struct linux_syslog_args *); int linux_setitimer(struct thread *, struct linux_setitimer_args *); int linux_getitimer(struct thread *, struct linux_getitimer_args *); int linux_newstat(struct thread *, struct linux_newstat_args *); int linux_newlstat(struct thread *, struct linux_newlstat_args *); int linux_newfstat(struct thread *, struct linux_newfstat_args *); int linux_uname(struct thread *, struct linux_uname_args *); int linux_iopl(struct thread *, struct linux_iopl_args *); int linux_vhangup(struct thread *, struct linux_vhangup_args *); int linux_vm86old(struct thread *, struct linux_vm86old_args *); int linux_wait4(struct thread *, struct linux_wait4_args *); int linux_swapoff(struct thread *, struct linux_swapoff_args *); int linux_sysinfo(struct thread *, struct linux_sysinfo_args *); int linux_ipc(struct thread *, struct linux_ipc_args *); int linux_sigreturn(struct thread *, struct linux_sigreturn_args *); int linux_clone(struct thread *, struct linux_clone_args *); int linux_setdomainname(struct thread *, struct linux_setdomainname_args *); int linux_newuname(struct thread *, struct linux_newuname_args *); int linux_modify_ldt(struct thread *, struct linux_modify_ldt_args *); int linux_adjtimex(struct thread *, struct linux_adjtimex_args *); int linux_mprotect(struct thread *, struct linux_mprotect_args *); int linux_sigprocmask(struct thread *, struct linux_sigprocmask_args *); int linux_create_module(struct thread *, struct linux_create_module_args *); int linux_init_module(struct thread *, struct linux_init_module_args *); int linux_delete_module(struct thread *, struct linux_delete_module_args *); int linux_get_kernel_syms(struct thread *, struct linux_get_kernel_syms_args *); int linux_quotactl(struct thread *, struct linux_quotactl_args *); int linux_bdflush(struct thread *, struct linux_bdflush_args *); int linux_sysfs(struct thread *, struct linux_sysfs_args *); int linux_personality(struct thread *, struct linux_personality_args *); int linux_setfsuid16(struct thread *, struct linux_setfsuid16_args *); int linux_setfsgid16(struct thread *, struct linux_setfsgid16_args *); int linux_llseek(struct thread *, struct linux_llseek_args *); int linux_getdents(struct thread *, struct linux_getdents_args *); int linux_select(struct thread *, struct linux_select_args *); int linux_msync(struct thread *, struct linux_msync_args *); int linux_getsid(struct thread *, struct linux_getsid_args *); int linux_fdatasync(struct thread *, struct linux_fdatasync_args *); int linux_sysctl(struct thread *, struct linux_sysctl_args *); int linux_sched_setparam(struct thread *, struct linux_sched_setparam_args *); int linux_sched_getparam(struct thread *, struct linux_sched_getparam_args *); int linux_sched_setscheduler(struct thread *, struct linux_sched_setscheduler_args *); int linux_sched_getscheduler(struct thread *, struct linux_sched_getscheduler_args *); int linux_sched_get_priority_max(struct thread *, struct linux_sched_get_priority_max_args *); int linux_sched_get_priority_min(struct thread *, struct linux_sched_get_priority_min_args *); int linux_sched_rr_get_interval(struct thread *, struct linux_sched_rr_get_interval_args *); int linux_nanosleep(struct thread *, struct linux_nanosleep_args *); int linux_mremap(struct thread *, struct linux_mremap_args *); int linux_setresuid16(struct thread *, struct linux_setresuid16_args *); int linux_getresuid16(struct thread *, struct linux_getresuid16_args *); int linux_vm86(struct thread *, struct linux_vm86_args *); int linux_query_module(struct thread *, struct linux_query_module_args *); int linux_nfsservctl(struct thread *, struct linux_nfsservctl_args *); int linux_setresgid16(struct thread *, struct linux_setresgid16_args *); int linux_getresgid16(struct thread *, struct linux_getresgid16_args *); int linux_prctl(struct thread *, struct linux_prctl_args *); int linux_rt_sigreturn(struct thread *, struct linux_rt_sigreturn_args *); int linux_rt_sigaction(struct thread *, struct linux_rt_sigaction_args *); int linux_rt_sigprocmask(struct thread *, struct linux_rt_sigprocmask_args *); int linux_rt_sigpending(struct thread *, struct linux_rt_sigpending_args *); int linux_rt_sigtimedwait(struct thread *, struct linux_rt_sigtimedwait_args *); int linux_rt_sigqueueinfo(struct thread *, struct linux_rt_sigqueueinfo_args *); int linux_rt_sigsuspend(struct thread *, struct linux_rt_sigsuspend_args *); int linux_pread(struct thread *, struct linux_pread_args *); int linux_pwrite(struct thread *, struct linux_pwrite_args *); int linux_chown16(struct thread *, struct linux_chown16_args *); int linux_getcwd(struct thread *, struct linux_getcwd_args *); int linux_capget(struct thread *, struct linux_capget_args *); int linux_capset(struct thread *, struct linux_capset_args *); int linux_sigaltstack(struct thread *, struct linux_sigaltstack_args *); int linux_sendfile(struct thread *, struct linux_sendfile_args *); int linux_vfork(struct thread *, struct linux_vfork_args *); int linux_getrlimit(struct thread *, struct linux_getrlimit_args *); int linux_mmap2(struct thread *, struct linux_mmap2_args *); int linux_truncate64(struct thread *, struct linux_truncate64_args *); int linux_ftruncate64(struct thread *, struct linux_ftruncate64_args *); int linux_stat64(struct thread *, struct linux_stat64_args *); int linux_lstat64(struct thread *, struct linux_lstat64_args *); int linux_fstat64(struct thread *, struct linux_fstat64_args *); int linux_lchown(struct thread *, struct linux_lchown_args *); int linux_getuid(struct thread *, struct linux_getuid_args *); int linux_getgid(struct thread *, struct linux_getgid_args *); int linux_getgroups(struct thread *, struct linux_getgroups_args *); int linux_setgroups(struct thread *, struct linux_setgroups_args *); int linux_chown(struct thread *, struct linux_chown_args *); int linux_setfsuid(struct thread *, struct linux_setfsuid_args *); int linux_setfsgid(struct thread *, struct linux_setfsgid_args *); int linux_pivot_root(struct thread *, struct linux_pivot_root_args *); int linux_mincore(struct thread *, struct linux_mincore_args *); int linux_getdents64(struct thread *, struct linux_getdents64_args *); int linux_fcntl64(struct thread *, struct linux_fcntl64_args *); int linux_gettid(struct thread *, struct linux_gettid_args *); int linux_setxattr(struct thread *, struct linux_setxattr_args *); int linux_lsetxattr(struct thread *, struct linux_lsetxattr_args *); int linux_fsetxattr(struct thread *, struct linux_fsetxattr_args *); int linux_getxattr(struct thread *, struct linux_getxattr_args *); int linux_lgetxattr(struct thread *, struct linux_lgetxattr_args *); int linux_fgetxattr(struct thread *, struct linux_fgetxattr_args *); int linux_listxattr(struct thread *, struct linux_listxattr_args *); int linux_llistxattr(struct thread *, struct linux_llistxattr_args *); int linux_flistxattr(struct thread *, struct linux_flistxattr_args *); int linux_removexattr(struct thread *, struct linux_removexattr_args *); int linux_lremovexattr(struct thread *, struct linux_lremovexattr_args *); int linux_fremovexattr(struct thread *, struct linux_fremovexattr_args *); int linux_tkill(struct thread *, struct linux_tkill_args *); int linux_sys_futex(struct thread *, struct linux_sys_futex_args *); int linux_sched_setaffinity(struct thread *, struct linux_sched_setaffinity_args *); int linux_sched_getaffinity(struct thread *, struct linux_sched_getaffinity_args *); int linux_set_thread_area(struct thread *, struct linux_set_thread_area_args *); int linux_get_thread_area(struct thread *, struct linux_get_thread_area_args *); int linux_fadvise64(struct thread *, struct linux_fadvise64_args *); int linux_exit_group(struct thread *, struct linux_exit_group_args *); int linux_lookup_dcookie(struct thread *, struct linux_lookup_dcookie_args *); int linux_epoll_create(struct thread *, struct linux_epoll_create_args *); int linux_epoll_ctl(struct thread *, struct linux_epoll_ctl_args *); int linux_epoll_wait(struct thread *, struct linux_epoll_wait_args *); int linux_remap_file_pages(struct thread *, struct linux_remap_file_pages_args *); int linux_set_tid_address(struct thread *, struct linux_set_tid_address_args *); int linux_timer_create(struct thread *, struct linux_timer_create_args *); int linux_timer_settime(struct thread *, struct linux_timer_settime_args *); int linux_timer_gettime(struct thread *, struct linux_timer_gettime_args *); int linux_timer_getoverrun(struct thread *, struct linux_timer_getoverrun_args *); int linux_timer_delete(struct thread *, struct linux_timer_delete_args *); int linux_clock_settime(struct thread *, struct linux_clock_settime_args *); int linux_clock_gettime(struct thread *, struct linux_clock_gettime_args *); int linux_clock_getres(struct thread *, struct linux_clock_getres_args *); int linux_clock_nanosleep(struct thread *, struct linux_clock_nanosleep_args *); int linux_statfs64(struct thread *, struct linux_statfs64_args *); int linux_fstatfs64(struct thread *, struct linux_fstatfs64_args *); int linux_tgkill(struct thread *, struct linux_tgkill_args *); int linux_utimes(struct thread *, struct linux_utimes_args *); int linux_fadvise64_64(struct thread *, struct linux_fadvise64_64_args *); int linux_mbind(struct thread *, struct linux_mbind_args *); int linux_get_mempolicy(struct thread *, struct linux_get_mempolicy_args *); int linux_set_mempolicy(struct thread *, struct linux_set_mempolicy_args *); int linux_mq_open(struct thread *, struct linux_mq_open_args *); int linux_mq_unlink(struct thread *, struct linux_mq_unlink_args *); int linux_mq_timedsend(struct thread *, struct linux_mq_timedsend_args *); int linux_mq_timedreceive(struct thread *, struct linux_mq_timedreceive_args *); int linux_mq_notify(struct thread *, struct linux_mq_notify_args *); int linux_mq_getsetattr(struct thread *, struct linux_mq_getsetattr_args *); int linux_kexec_load(struct thread *, struct linux_kexec_load_args *); int linux_waitid(struct thread *, struct linux_waitid_args *); int linux_add_key(struct thread *, struct linux_add_key_args *); int linux_request_key(struct thread *, struct linux_request_key_args *); int linux_keyctl(struct thread *, struct linux_keyctl_args *); int linux_ioprio_set(struct thread *, struct linux_ioprio_set_args *); int linux_ioprio_get(struct thread *, struct linux_ioprio_get_args *); int linux_inotify_init(struct thread *, struct linux_inotify_init_args *); int linux_inotify_add_watch(struct thread *, struct linux_inotify_add_watch_args *); int linux_inotify_rm_watch(struct thread *, struct linux_inotify_rm_watch_args *); int linux_migrate_pages(struct thread *, struct linux_migrate_pages_args *); int linux_openat(struct thread *, struct linux_openat_args *); int linux_mkdirat(struct thread *, struct linux_mkdirat_args *); int linux_mknodat(struct thread *, struct linux_mknodat_args *); int linux_fchownat(struct thread *, struct linux_fchownat_args *); int linux_futimesat(struct thread *, struct linux_futimesat_args *); int linux_fstatat64(struct thread *, struct linux_fstatat64_args *); int linux_unlinkat(struct thread *, struct linux_unlinkat_args *); int linux_renameat(struct thread *, struct linux_renameat_args *); int linux_linkat(struct thread *, struct linux_linkat_args *); int linux_symlinkat(struct thread *, struct linux_symlinkat_args *); int linux_readlinkat(struct thread *, struct linux_readlinkat_args *); int linux_fchmodat(struct thread *, struct linux_fchmodat_args *); int linux_faccessat(struct thread *, struct linux_faccessat_args *); int linux_pselect6(struct thread *, struct linux_pselect6_args *); int linux_ppoll(struct thread *, struct linux_ppoll_args *); int linux_unshare(struct thread *, struct linux_unshare_args *); int linux_set_robust_list(struct thread *, struct linux_set_robust_list_args *); int linux_get_robust_list(struct thread *, struct linux_get_robust_list_args *); int linux_splice(struct thread *, struct linux_splice_args *); int linux_sync_file_range(struct thread *, struct linux_sync_file_range_args *); int linux_tee(struct thread *, struct linux_tee_args *); int linux_vmsplice(struct thread *, struct linux_vmsplice_args *); int linux_move_pages(struct thread *, struct linux_move_pages_args *); int linux_getcpu(struct thread *, struct linux_getcpu_args *); int linux_epoll_pwait(struct thread *, struct linux_epoll_pwait_args *); int linux_utimensat(struct thread *, struct linux_utimensat_args *); int linux_signalfd(struct thread *, struct linux_signalfd_args *); int linux_timerfd_create(struct thread *, struct linux_timerfd_create_args *); int linux_eventfd(struct thread *, struct linux_eventfd_args *); int linux_fallocate(struct thread *, struct linux_fallocate_args *); int linux_timerfd_settime(struct thread *, struct linux_timerfd_settime_args *); int linux_timerfd_gettime(struct thread *, struct linux_timerfd_gettime_args *); int linux_signalfd4(struct thread *, struct linux_signalfd4_args *); int linux_eventfd2(struct thread *, struct linux_eventfd2_args *); int linux_epoll_create1(struct thread *, struct linux_epoll_create1_args *); int linux_dup3(struct thread *, struct linux_dup3_args *); int linux_pipe2(struct thread *, struct linux_pipe2_args *); int linux_inotify_init1(struct thread *, struct linux_inotify_init1_args *); int linux_preadv(struct thread *, struct linux_preadv_args *); int linux_pwritev(struct thread *, struct linux_pwritev_args *); -int linux_rt_tsigqueueinfo(struct thread *, struct linux_rt_tsigqueueinfo_args *); +int linux_rt_tgsigqueueinfo(struct thread *, struct linux_rt_tgsigqueueinfo_args *); int linux_perf_event_open(struct thread *, struct linux_perf_event_open_args *); int linux_recvmmsg(struct thread *, struct linux_recvmmsg_args *); int linux_fanotify_init(struct thread *, struct linux_fanotify_init_args *); int linux_fanotify_mark(struct thread *, struct linux_fanotify_mark_args *); int linux_prlimit64(struct thread *, struct linux_prlimit64_args *); int linux_name_to_handle_at(struct thread *, struct linux_name_to_handle_at_args *); int linux_open_by_handle_at(struct thread *, struct linux_open_by_handle_at_args *); int linux_clock_adjtime(struct thread *, struct linux_clock_adjtime_args *); int linux_syncfs(struct thread *, struct linux_syncfs_args *); int linux_sendmmsg(struct thread *, struct linux_sendmmsg_args *); int linux_setns(struct thread *, struct linux_setns_args *); int linux_process_vm_readv(struct thread *, struct linux_process_vm_readv_args *); int linux_process_vm_writev(struct thread *, struct linux_process_vm_writev_args *); +int linux_kcmp(struct thread *, struct linux_kcmp_args *); +int linux_finit_module(struct thread *, struct linux_finit_module_args *); +int linux_sched_setattr(struct thread *, struct linux_sched_setattr_args *); +int linux_sched_getattr(struct thread *, struct linux_sched_getattr_args *); +int linux_renameat2(struct thread *, struct linux_renameat2_args *); +int linux_seccomp(struct thread *, struct linux_seccomp_args *); +int linux_getrandom(struct thread *, struct linux_getrandom_args *); +int linux_memfd_create(struct thread *, struct linux_memfd_create_args *); +int linux_bpf(struct thread *, struct linux_bpf_args *); +int linux_execveat(struct thread *, struct linux_execveat_args *); +int linux_socket(struct thread *, struct linux_socket_args *); +int linux_socketpair(struct thread *, struct linux_socketpair_args *); +int linux_bind(struct thread *, struct linux_bind_args *); +int linux_connect(struct thread *, struct linux_connect_args *); +int linux_listen(struct thread *, struct linux_listen_args *); +int linux_accept4(struct thread *, struct linux_accept4_args *); +int linux_getsockopt(struct thread *, struct linux_getsockopt_args *); +int linux_setsockopt(struct thread *, struct linux_setsockopt_args *); +int linux_getsockname(struct thread *, struct linux_getsockname_args *); +int linux_getpeername(struct thread *, struct linux_getpeername_args *); +int linux_sendto(struct thread *, struct linux_sendto_args *); +int linux_sendmsg(struct thread *, struct linux_sendmsg_args *); +int linux_recvfrom(struct thread *, struct linux_recvfrom_args *); +int linux_recvmsg(struct thread *, struct linux_recvmsg_args *); +int linux_shutdown(struct thread *, struct linux_shutdown_args *); +int linux_userfaultfd(struct thread *, struct linux_userfaultfd_args *); +int linux_membarrier(struct thread *, struct linux_membarrier_args *); +int linux_mlock2(struct thread *, struct linux_mlock2_args *); +int linux_copy_file_range(struct thread *, struct linux_copy_file_range_args *); +int linux_preadv2(struct thread *, struct linux_preadv2_args *); +int linux_pwritev2(struct thread *, struct linux_pwritev2_args *); +int linux_pkey_mprotect(struct thread *, struct linux_pkey_mprotect_args *); +int linux_pkey_alloc(struct thread *, struct linux_pkey_alloc_args *); +int linux_pkey_free(struct thread *, struct linux_pkey_free_args *); #ifdef COMPAT_43 #define nosys linux_nosys #endif /* COMPAT_43 */ #ifdef COMPAT_FREEBSD4 #define nosys linux_nosys #endif /* COMPAT_FREEBSD4 */ #ifdef COMPAT_FREEBSD6 #define nosys linux_nosys #endif /* COMPAT_FREEBSD6 */ #ifdef COMPAT_FREEBSD7 #define nosys linux_nosys #endif /* COMPAT_FREEBSD7 */ #ifdef COMPAT_FREEBSD10 #define nosys linux_nosys #endif /* COMPAT_FREEBSD10 */ #define LINUX_SYS_AUE_linux_exit AUE_EXIT #define LINUX_SYS_AUE_linux_fork AUE_FORK #define LINUX_SYS_AUE_linux_open AUE_OPEN_RWTC #define LINUX_SYS_AUE_linux_waitpid AUE_WAIT4 #define LINUX_SYS_AUE_linux_creat AUE_CREAT #define LINUX_SYS_AUE_linux_link AUE_LINK #define LINUX_SYS_AUE_linux_unlink AUE_UNLINK #define LINUX_SYS_AUE_linux_execve AUE_EXECVE #define LINUX_SYS_AUE_linux_chdir AUE_CHDIR #define LINUX_SYS_AUE_linux_time AUE_NULL #define LINUX_SYS_AUE_linux_mknod AUE_MKNOD #define LINUX_SYS_AUE_linux_chmod AUE_CHMOD #define LINUX_SYS_AUE_linux_lchown16 AUE_LCHOWN #define LINUX_SYS_AUE_linux_stat AUE_STAT #define LINUX_SYS_AUE_linux_lseek AUE_LSEEK #define LINUX_SYS_AUE_linux_getpid AUE_GETPID #define LINUX_SYS_AUE_linux_mount AUE_MOUNT #define LINUX_SYS_AUE_linux_oldumount AUE_UMOUNT #define LINUX_SYS_AUE_linux_setuid16 AUE_SETUID #define LINUX_SYS_AUE_linux_getuid16 AUE_GETUID #define LINUX_SYS_AUE_linux_stime AUE_SETTIMEOFDAY #define LINUX_SYS_AUE_linux_ptrace AUE_PTRACE #define LINUX_SYS_AUE_linux_alarm AUE_NULL #define LINUX_SYS_AUE_linux_fstat AUE_FSTAT #define LINUX_SYS_AUE_linux_pause AUE_NULL #define LINUX_SYS_AUE_linux_utime AUE_UTIME #define LINUX_SYS_AUE_linux_access AUE_ACCESS #define LINUX_SYS_AUE_linux_nice AUE_NICE #define LINUX_SYS_AUE_linux_kill AUE_KILL #define LINUX_SYS_AUE_linux_rename AUE_RENAME #define LINUX_SYS_AUE_linux_mkdir AUE_MKDIR #define LINUX_SYS_AUE_linux_rmdir AUE_RMDIR #define LINUX_SYS_AUE_linux_pipe AUE_PIPE #define LINUX_SYS_AUE_linux_times AUE_NULL #define LINUX_SYS_AUE_linux_brk AUE_NULL #define LINUX_SYS_AUE_linux_setgid16 AUE_SETGID #define LINUX_SYS_AUE_linux_getgid16 AUE_GETGID #define LINUX_SYS_AUE_linux_signal AUE_NULL #define LINUX_SYS_AUE_linux_geteuid16 AUE_GETEUID #define LINUX_SYS_AUE_linux_getegid16 AUE_GETEGID #define LINUX_SYS_AUE_linux_umount AUE_UMOUNT #define LINUX_SYS_AUE_linux_ioctl AUE_IOCTL #define LINUX_SYS_AUE_linux_fcntl AUE_FCNTL #define LINUX_SYS_AUE_linux_olduname AUE_NULL #define LINUX_SYS_AUE_linux_ustat AUE_NULL #define LINUX_SYS_AUE_linux_getppid AUE_GETPPID #define LINUX_SYS_AUE_linux_sigaction AUE_NULL #define LINUX_SYS_AUE_linux_sgetmask AUE_NULL #define LINUX_SYS_AUE_linux_ssetmask AUE_NULL #define LINUX_SYS_AUE_linux_setreuid16 AUE_SETREUID #define LINUX_SYS_AUE_linux_setregid16 AUE_SETREGID #define LINUX_SYS_AUE_linux_sigsuspend AUE_NULL #define LINUX_SYS_AUE_linux_sigpending AUE_NULL #define LINUX_SYS_AUE_linux_sethostname AUE_SYSCTL #define LINUX_SYS_AUE_linux_setrlimit AUE_SETRLIMIT #define LINUX_SYS_AUE_linux_old_getrlimit AUE_GETRLIMIT #define LINUX_SYS_AUE_linux_getgroups16 AUE_GETGROUPS #define LINUX_SYS_AUE_linux_setgroups16 AUE_SETGROUPS #define LINUX_SYS_AUE_linux_old_select AUE_SELECT #define LINUX_SYS_AUE_linux_symlink AUE_SYMLINK #define LINUX_SYS_AUE_linux_lstat AUE_LSTAT #define LINUX_SYS_AUE_linux_readlink AUE_READLINK #define LINUX_SYS_AUE_linux_uselib AUE_USELIB #define LINUX_SYS_AUE_linux_reboot AUE_REBOOT #define LINUX_SYS_AUE_linux_readdir AUE_GETDIRENTRIES #define LINUX_SYS_AUE_linux_mmap AUE_MMAP #define LINUX_SYS_AUE_linux_truncate AUE_TRUNCATE #define LINUX_SYS_AUE_linux_ftruncate AUE_FTRUNCATE #define LINUX_SYS_AUE_linux_getpriority AUE_GETPRIORITY #define LINUX_SYS_AUE_linux_statfs AUE_STATFS #define LINUX_SYS_AUE_linux_fstatfs AUE_FSTATFS #define LINUX_SYS_AUE_linux_ioperm AUE_NULL #define LINUX_SYS_AUE_linux_socketcall AUE_NULL #define LINUX_SYS_AUE_linux_syslog AUE_NULL #define LINUX_SYS_AUE_linux_setitimer AUE_SETITIMER #define LINUX_SYS_AUE_linux_getitimer AUE_GETITIMER #define LINUX_SYS_AUE_linux_newstat AUE_STAT #define LINUX_SYS_AUE_linux_newlstat AUE_LSTAT #define LINUX_SYS_AUE_linux_newfstat AUE_FSTAT #define LINUX_SYS_AUE_linux_uname AUE_NULL #define LINUX_SYS_AUE_linux_iopl AUE_NULL #define LINUX_SYS_AUE_linux_vhangup AUE_NULL #define LINUX_SYS_AUE_linux_vm86old AUE_NULL #define LINUX_SYS_AUE_linux_wait4 AUE_WAIT4 #define LINUX_SYS_AUE_linux_swapoff AUE_SWAPOFF #define LINUX_SYS_AUE_linux_sysinfo AUE_NULL #define LINUX_SYS_AUE_linux_ipc AUE_NULL #define LINUX_SYS_AUE_linux_sigreturn AUE_SIGRETURN #define LINUX_SYS_AUE_linux_clone AUE_RFORK #define LINUX_SYS_AUE_linux_setdomainname AUE_SYSCTL #define LINUX_SYS_AUE_linux_newuname AUE_NULL #define LINUX_SYS_AUE_linux_modify_ldt AUE_NULL #define LINUX_SYS_AUE_linux_adjtimex AUE_ADJTIME #define LINUX_SYS_AUE_linux_mprotect AUE_MPROTECT #define LINUX_SYS_AUE_linux_sigprocmask AUE_SIGPROCMASK #define LINUX_SYS_AUE_linux_create_module AUE_NULL #define LINUX_SYS_AUE_linux_init_module AUE_NULL #define LINUX_SYS_AUE_linux_delete_module AUE_NULL #define LINUX_SYS_AUE_linux_get_kernel_syms AUE_NULL #define LINUX_SYS_AUE_linux_quotactl AUE_QUOTACTL #define LINUX_SYS_AUE_linux_bdflush AUE_BDFLUSH #define LINUX_SYS_AUE_linux_sysfs AUE_NULL #define LINUX_SYS_AUE_linux_personality AUE_PERSONALITY #define LINUX_SYS_AUE_linux_setfsuid16 AUE_SETFSUID #define LINUX_SYS_AUE_linux_setfsgid16 AUE_SETFSGID #define LINUX_SYS_AUE_linux_llseek AUE_LSEEK #define LINUX_SYS_AUE_linux_getdents AUE_GETDIRENTRIES #define LINUX_SYS_AUE_linux_select AUE_SELECT #define LINUX_SYS_AUE_linux_msync AUE_MSYNC #define LINUX_SYS_AUE_linux_getsid AUE_GETSID #define LINUX_SYS_AUE_linux_fdatasync AUE_NULL #define LINUX_SYS_AUE_linux_sysctl AUE_SYSCTL #define LINUX_SYS_AUE_linux_sched_setparam AUE_SCHED_SETPARAM #define LINUX_SYS_AUE_linux_sched_getparam AUE_SCHED_GETPARAM #define LINUX_SYS_AUE_linux_sched_setscheduler AUE_SCHED_SETSCHEDULER #define LINUX_SYS_AUE_linux_sched_getscheduler AUE_SCHED_GETSCHEDULER #define LINUX_SYS_AUE_linux_sched_get_priority_max AUE_SCHED_GET_PRIORITY_MAX #define LINUX_SYS_AUE_linux_sched_get_priority_min AUE_SCHED_GET_PRIORITY_MIN #define LINUX_SYS_AUE_linux_sched_rr_get_interval AUE_SCHED_RR_GET_INTERVAL #define LINUX_SYS_AUE_linux_nanosleep AUE_NULL #define LINUX_SYS_AUE_linux_mremap AUE_NULL #define LINUX_SYS_AUE_linux_setresuid16 AUE_SETRESUID #define LINUX_SYS_AUE_linux_getresuid16 AUE_GETRESUID #define LINUX_SYS_AUE_linux_vm86 AUE_NULL #define LINUX_SYS_AUE_linux_query_module AUE_NULL #define LINUX_SYS_AUE_linux_nfsservctl AUE_NULL #define LINUX_SYS_AUE_linux_setresgid16 AUE_SETRESGID #define LINUX_SYS_AUE_linux_getresgid16 AUE_GETRESGID #define LINUX_SYS_AUE_linux_prctl AUE_PRCTL #define LINUX_SYS_AUE_linux_rt_sigreturn AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigaction AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigprocmask AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigpending AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigtimedwait AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigqueueinfo AUE_NULL #define LINUX_SYS_AUE_linux_rt_sigsuspend AUE_NULL #define LINUX_SYS_AUE_linux_pread AUE_PREAD #define LINUX_SYS_AUE_linux_pwrite AUE_PWRITE #define LINUX_SYS_AUE_linux_chown16 AUE_CHOWN #define LINUX_SYS_AUE_linux_getcwd AUE_GETCWD #define LINUX_SYS_AUE_linux_capget AUE_CAPGET #define LINUX_SYS_AUE_linux_capset AUE_CAPSET #define LINUX_SYS_AUE_linux_sigaltstack AUE_NULL #define LINUX_SYS_AUE_linux_sendfile AUE_SENDFILE #define LINUX_SYS_AUE_linux_vfork AUE_VFORK #define LINUX_SYS_AUE_linux_getrlimit AUE_GETRLIMIT #define LINUX_SYS_AUE_linux_mmap2 AUE_MMAP #define LINUX_SYS_AUE_linux_truncate64 AUE_TRUNCATE #define LINUX_SYS_AUE_linux_ftruncate64 AUE_FTRUNCATE #define LINUX_SYS_AUE_linux_stat64 AUE_STAT #define LINUX_SYS_AUE_linux_lstat64 AUE_LSTAT #define LINUX_SYS_AUE_linux_fstat64 AUE_FSTAT #define LINUX_SYS_AUE_linux_lchown AUE_LCHOWN #define LINUX_SYS_AUE_linux_getuid AUE_GETUID #define LINUX_SYS_AUE_linux_getgid AUE_GETGID #define LINUX_SYS_AUE_linux_getgroups AUE_GETGROUPS #define LINUX_SYS_AUE_linux_setgroups AUE_SETGROUPS #define LINUX_SYS_AUE_linux_chown AUE_CHOWN #define LINUX_SYS_AUE_linux_setfsuid AUE_SETFSUID #define LINUX_SYS_AUE_linux_setfsgid AUE_SETFSGID #define LINUX_SYS_AUE_linux_pivot_root AUE_PIVOT_ROOT #define LINUX_SYS_AUE_linux_mincore AUE_MINCORE #define LINUX_SYS_AUE_linux_getdents64 AUE_GETDIRENTRIES #define LINUX_SYS_AUE_linux_fcntl64 AUE_FCNTL #define LINUX_SYS_AUE_linux_gettid AUE_NULL #define LINUX_SYS_AUE_linux_setxattr AUE_NULL #define LINUX_SYS_AUE_linux_lsetxattr AUE_NULL #define LINUX_SYS_AUE_linux_fsetxattr AUE_NULL #define LINUX_SYS_AUE_linux_getxattr AUE_NULL #define LINUX_SYS_AUE_linux_lgetxattr AUE_NULL #define LINUX_SYS_AUE_linux_fgetxattr AUE_NULL #define LINUX_SYS_AUE_linux_listxattr AUE_NULL #define LINUX_SYS_AUE_linux_llistxattr AUE_NULL #define LINUX_SYS_AUE_linux_flistxattr AUE_NULL #define LINUX_SYS_AUE_linux_removexattr AUE_NULL #define LINUX_SYS_AUE_linux_lremovexattr AUE_NULL #define LINUX_SYS_AUE_linux_fremovexattr AUE_NULL #define LINUX_SYS_AUE_linux_tkill AUE_NULL #define LINUX_SYS_AUE_linux_sys_futex AUE_NULL #define LINUX_SYS_AUE_linux_sched_setaffinity AUE_NULL #define LINUX_SYS_AUE_linux_sched_getaffinity AUE_NULL #define LINUX_SYS_AUE_linux_set_thread_area AUE_NULL #define LINUX_SYS_AUE_linux_get_thread_area AUE_NULL #define LINUX_SYS_AUE_linux_fadvise64 AUE_NULL #define LINUX_SYS_AUE_linux_exit_group AUE_EXIT #define LINUX_SYS_AUE_linux_lookup_dcookie AUE_NULL #define LINUX_SYS_AUE_linux_epoll_create AUE_NULL #define LINUX_SYS_AUE_linux_epoll_ctl AUE_NULL #define LINUX_SYS_AUE_linux_epoll_wait AUE_NULL #define LINUX_SYS_AUE_linux_remap_file_pages AUE_NULL #define LINUX_SYS_AUE_linux_set_tid_address AUE_NULL #define LINUX_SYS_AUE_linux_timer_create AUE_NULL #define LINUX_SYS_AUE_linux_timer_settime AUE_NULL #define LINUX_SYS_AUE_linux_timer_gettime AUE_NULL #define LINUX_SYS_AUE_linux_timer_getoverrun AUE_NULL #define LINUX_SYS_AUE_linux_timer_delete AUE_NULL #define LINUX_SYS_AUE_linux_clock_settime AUE_CLOCK_SETTIME #define LINUX_SYS_AUE_linux_clock_gettime AUE_NULL #define LINUX_SYS_AUE_linux_clock_getres AUE_NULL #define LINUX_SYS_AUE_linux_clock_nanosleep AUE_NULL #define LINUX_SYS_AUE_linux_statfs64 AUE_STATFS #define LINUX_SYS_AUE_linux_fstatfs64 AUE_FSTATFS #define LINUX_SYS_AUE_linux_tgkill AUE_NULL #define LINUX_SYS_AUE_linux_utimes AUE_UTIMES #define LINUX_SYS_AUE_linux_fadvise64_64 AUE_NULL #define LINUX_SYS_AUE_linux_mbind AUE_NULL #define LINUX_SYS_AUE_linux_get_mempolicy AUE_NULL #define LINUX_SYS_AUE_linux_set_mempolicy AUE_NULL #define LINUX_SYS_AUE_linux_mq_open AUE_NULL #define LINUX_SYS_AUE_linux_mq_unlink AUE_NULL #define LINUX_SYS_AUE_linux_mq_timedsend AUE_NULL #define LINUX_SYS_AUE_linux_mq_timedreceive AUE_NULL #define LINUX_SYS_AUE_linux_mq_notify AUE_NULL #define LINUX_SYS_AUE_linux_mq_getsetattr AUE_NULL #define LINUX_SYS_AUE_linux_kexec_load AUE_NULL #define LINUX_SYS_AUE_linux_waitid AUE_WAIT6 #define LINUX_SYS_AUE_linux_add_key AUE_NULL #define LINUX_SYS_AUE_linux_request_key AUE_NULL #define LINUX_SYS_AUE_linux_keyctl AUE_NULL #define LINUX_SYS_AUE_linux_ioprio_set AUE_NULL #define LINUX_SYS_AUE_linux_ioprio_get AUE_NULL #define LINUX_SYS_AUE_linux_inotify_init AUE_NULL #define LINUX_SYS_AUE_linux_inotify_add_watch AUE_NULL #define LINUX_SYS_AUE_linux_inotify_rm_watch AUE_NULL #define LINUX_SYS_AUE_linux_migrate_pages AUE_NULL #define LINUX_SYS_AUE_linux_openat AUE_OPEN_RWTC #define LINUX_SYS_AUE_linux_mkdirat AUE_MKDIRAT #define LINUX_SYS_AUE_linux_mknodat AUE_MKNODAT #define LINUX_SYS_AUE_linux_fchownat AUE_FCHOWNAT #define LINUX_SYS_AUE_linux_futimesat AUE_FUTIMESAT #define LINUX_SYS_AUE_linux_fstatat64 AUE_FSTATAT #define LINUX_SYS_AUE_linux_unlinkat AUE_UNLINKAT #define LINUX_SYS_AUE_linux_renameat AUE_RENAMEAT #define LINUX_SYS_AUE_linux_linkat AUE_LINKAT #define LINUX_SYS_AUE_linux_symlinkat AUE_SYMLINKAT #define LINUX_SYS_AUE_linux_readlinkat AUE_READLINKAT #define LINUX_SYS_AUE_linux_fchmodat AUE_FCHMODAT #define LINUX_SYS_AUE_linux_faccessat AUE_FACCESSAT #define LINUX_SYS_AUE_linux_pselect6 AUE_SELECT #define LINUX_SYS_AUE_linux_ppoll AUE_POLL #define LINUX_SYS_AUE_linux_unshare AUE_NULL #define LINUX_SYS_AUE_linux_set_robust_list AUE_NULL #define LINUX_SYS_AUE_linux_get_robust_list AUE_NULL #define LINUX_SYS_AUE_linux_splice AUE_NULL #define LINUX_SYS_AUE_linux_sync_file_range AUE_NULL #define LINUX_SYS_AUE_linux_tee AUE_NULL #define LINUX_SYS_AUE_linux_vmsplice AUE_NULL #define LINUX_SYS_AUE_linux_move_pages AUE_NULL #define LINUX_SYS_AUE_linux_getcpu AUE_NULL #define LINUX_SYS_AUE_linux_epoll_pwait AUE_NULL #define LINUX_SYS_AUE_linux_utimensat AUE_FUTIMESAT #define LINUX_SYS_AUE_linux_signalfd AUE_NULL #define LINUX_SYS_AUE_linux_timerfd_create AUE_NULL #define LINUX_SYS_AUE_linux_eventfd AUE_NULL #define LINUX_SYS_AUE_linux_fallocate AUE_NULL #define LINUX_SYS_AUE_linux_timerfd_settime AUE_NULL #define LINUX_SYS_AUE_linux_timerfd_gettime AUE_NULL #define LINUX_SYS_AUE_linux_signalfd4 AUE_NULL #define LINUX_SYS_AUE_linux_eventfd2 AUE_NULL #define LINUX_SYS_AUE_linux_epoll_create1 AUE_NULL #define LINUX_SYS_AUE_linux_dup3 AUE_NULL #define LINUX_SYS_AUE_linux_pipe2 AUE_NULL #define LINUX_SYS_AUE_linux_inotify_init1 AUE_NULL #define LINUX_SYS_AUE_linux_preadv AUE_NULL #define LINUX_SYS_AUE_linux_pwritev AUE_NULL -#define LINUX_SYS_AUE_linux_rt_tsigqueueinfo AUE_NULL +#define LINUX_SYS_AUE_linux_rt_tgsigqueueinfo AUE_NULL #define LINUX_SYS_AUE_linux_perf_event_open AUE_NULL #define LINUX_SYS_AUE_linux_recvmmsg AUE_NULL #define LINUX_SYS_AUE_linux_fanotify_init AUE_NULL #define LINUX_SYS_AUE_linux_fanotify_mark AUE_NULL #define LINUX_SYS_AUE_linux_prlimit64 AUE_NULL #define LINUX_SYS_AUE_linux_name_to_handle_at AUE_NULL #define LINUX_SYS_AUE_linux_open_by_handle_at AUE_NULL #define LINUX_SYS_AUE_linux_clock_adjtime AUE_NULL #define LINUX_SYS_AUE_linux_syncfs AUE_SYNC #define LINUX_SYS_AUE_linux_sendmmsg AUE_NULL #define LINUX_SYS_AUE_linux_setns AUE_NULL #define LINUX_SYS_AUE_linux_process_vm_readv AUE_NULL #define LINUX_SYS_AUE_linux_process_vm_writev AUE_NULL +#define LINUX_SYS_AUE_linux_kcmp AUE_NULL +#define LINUX_SYS_AUE_linux_finit_module AUE_NULL +#define LINUX_SYS_AUE_linux_sched_setattr AUE_NULL +#define LINUX_SYS_AUE_linux_sched_getattr AUE_NULL +#define LINUX_SYS_AUE_linux_renameat2 AUE_NULL +#define LINUX_SYS_AUE_linux_seccomp AUE_NULL +#define LINUX_SYS_AUE_linux_getrandom AUE_NULL +#define LINUX_SYS_AUE_linux_memfd_create AUE_NULL +#define LINUX_SYS_AUE_linux_bpf AUE_NULL +#define LINUX_SYS_AUE_linux_execveat AUE_NULL +#define LINUX_SYS_AUE_linux_socket AUE_SOCKET +#define LINUX_SYS_AUE_linux_socketpair AUE_SOCKETPAIR +#define LINUX_SYS_AUE_linux_bind AUE_BIND +#define LINUX_SYS_AUE_linux_connect AUE_CONNECT +#define LINUX_SYS_AUE_linux_listen AUE_LISTEN +#define LINUX_SYS_AUE_linux_accept4 AUE_ACCEPT +#define LINUX_SYS_AUE_linux_getsockopt AUE_GETSOCKOPT +#define LINUX_SYS_AUE_linux_setsockopt AUE_SETSOCKOPT +#define LINUX_SYS_AUE_linux_getsockname AUE_GETSOCKNAME +#define LINUX_SYS_AUE_linux_getpeername AUE_GETPEERNAME +#define LINUX_SYS_AUE_linux_sendto AUE_SENDTO +#define LINUX_SYS_AUE_linux_sendmsg AUE_SENDMSG +#define LINUX_SYS_AUE_linux_recvfrom AUE_RECVFROM +#define LINUX_SYS_AUE_linux_recvmsg AUE_RECVMSG +#define LINUX_SYS_AUE_linux_shutdown AUE_NULL +#define LINUX_SYS_AUE_linux_userfaultfd AUE_NULL +#define LINUX_SYS_AUE_linux_membarrier AUE_NULL +#define LINUX_SYS_AUE_linux_mlock2 AUE_NULL +#define LINUX_SYS_AUE_linux_copy_file_range AUE_NULL +#define LINUX_SYS_AUE_linux_preadv2 AUE_NULL +#define LINUX_SYS_AUE_linux_pwritev2 AUE_NULL +#define LINUX_SYS_AUE_linux_pkey_mprotect AUE_NULL +#define LINUX_SYS_AUE_linux_pkey_alloc AUE_NULL +#define LINUX_SYS_AUE_linux_pkey_free AUE_NULL #undef PAD_ #undef PADL_ #undef PADR_ #endif /* !_LINUX_SYSPROTO_H_ */ Index: projects/ipsec/sys/i386/linux/linux_syscall.h =================================================================== --- projects/ipsec/sys/i386/linux/linux_syscall.h (revision 313312) +++ projects/ipsec/sys/i386/linux/linux_syscall.h (revision 313313) @@ -1,331 +1,365 @@ /* * System call numbers. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/i386/linux/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/i386/linux/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ #define LINUX_SYS_linux_exit 1 #define LINUX_SYS_linux_fork 2 #define LINUX_SYS_read 3 #define LINUX_SYS_write 4 #define LINUX_SYS_linux_open 5 #define LINUX_SYS_close 6 #define LINUX_SYS_linux_waitpid 7 #define LINUX_SYS_linux_creat 8 #define LINUX_SYS_linux_link 9 #define LINUX_SYS_linux_unlink 10 #define LINUX_SYS_linux_execve 11 #define LINUX_SYS_linux_chdir 12 #define LINUX_SYS_linux_time 13 #define LINUX_SYS_linux_mknod 14 #define LINUX_SYS_linux_chmod 15 #define LINUX_SYS_linux_lchown16 16 #define LINUX_SYS_linux_stat 18 #define LINUX_SYS_linux_lseek 19 #define LINUX_SYS_linux_getpid 20 #define LINUX_SYS_linux_mount 21 #define LINUX_SYS_linux_oldumount 22 #define LINUX_SYS_linux_setuid16 23 #define LINUX_SYS_linux_getuid16 24 #define LINUX_SYS_linux_stime 25 #define LINUX_SYS_linux_ptrace 26 #define LINUX_SYS_linux_alarm 27 #define LINUX_SYS_linux_fstat 28 #define LINUX_SYS_linux_pause 29 #define LINUX_SYS_linux_utime 30 #define LINUX_SYS_linux_access 33 #define LINUX_SYS_linux_nice 34 #define LINUX_SYS_sync 36 #define LINUX_SYS_linux_kill 37 #define LINUX_SYS_linux_rename 38 #define LINUX_SYS_linux_mkdir 39 #define LINUX_SYS_linux_rmdir 40 #define LINUX_SYS_dup 41 #define LINUX_SYS_linux_pipe 42 #define LINUX_SYS_linux_times 43 #define LINUX_SYS_linux_brk 45 #define LINUX_SYS_linux_setgid16 46 #define LINUX_SYS_linux_getgid16 47 #define LINUX_SYS_linux_signal 48 #define LINUX_SYS_linux_geteuid16 49 #define LINUX_SYS_linux_getegid16 50 #define LINUX_SYS_acct 51 #define LINUX_SYS_linux_umount 52 #define LINUX_SYS_linux_ioctl 54 #define LINUX_SYS_linux_fcntl 55 #define LINUX_SYS_setpgid 57 #define LINUX_SYS_linux_olduname 59 #define LINUX_SYS_umask 60 #define LINUX_SYS_chroot 61 #define LINUX_SYS_linux_ustat 62 #define LINUX_SYS_dup2 63 #define LINUX_SYS_linux_getppid 64 #define LINUX_SYS_getpgrp 65 #define LINUX_SYS_setsid 66 #define LINUX_SYS_linux_sigaction 67 #define LINUX_SYS_linux_sgetmask 68 #define LINUX_SYS_linux_ssetmask 69 #define LINUX_SYS_linux_setreuid16 70 #define LINUX_SYS_linux_setregid16 71 #define LINUX_SYS_linux_sigsuspend 72 #define LINUX_SYS_linux_sigpending 73 #define LINUX_SYS_linux_sethostname 74 #define LINUX_SYS_linux_setrlimit 75 #define LINUX_SYS_linux_old_getrlimit 76 #define LINUX_SYS_getrusage 77 #define LINUX_SYS_gettimeofday 78 #define LINUX_SYS_settimeofday 79 #define LINUX_SYS_linux_getgroups16 80 #define LINUX_SYS_linux_setgroups16 81 #define LINUX_SYS_linux_old_select 82 #define LINUX_SYS_linux_symlink 83 #define LINUX_SYS_linux_lstat 84 #define LINUX_SYS_linux_readlink 85 #define LINUX_SYS_linux_uselib 86 #define LINUX_SYS_swapon 87 #define LINUX_SYS_linux_reboot 88 #define LINUX_SYS_linux_readdir 89 #define LINUX_SYS_linux_mmap 90 #define LINUX_SYS_munmap 91 #define LINUX_SYS_linux_truncate 92 #define LINUX_SYS_linux_ftruncate 93 #define LINUX_SYS_fchmod 94 #define LINUX_SYS_fchown 95 #define LINUX_SYS_linux_getpriority 96 #define LINUX_SYS_setpriority 97 #define LINUX_SYS_linux_statfs 99 #define LINUX_SYS_linux_fstatfs 100 #define LINUX_SYS_linux_ioperm 101 #define LINUX_SYS_linux_socketcall 102 #define LINUX_SYS_linux_syslog 103 #define LINUX_SYS_linux_setitimer 104 #define LINUX_SYS_linux_getitimer 105 #define LINUX_SYS_linux_newstat 106 #define LINUX_SYS_linux_newlstat 107 #define LINUX_SYS_linux_newfstat 108 #define LINUX_SYS_linux_uname 109 #define LINUX_SYS_linux_iopl 110 #define LINUX_SYS_linux_vhangup 111 #define LINUX_SYS_linux_vm86old 113 #define LINUX_SYS_linux_wait4 114 #define LINUX_SYS_linux_swapoff 115 #define LINUX_SYS_linux_sysinfo 116 #define LINUX_SYS_linux_ipc 117 #define LINUX_SYS_fsync 118 #define LINUX_SYS_linux_sigreturn 119 #define LINUX_SYS_linux_clone 120 #define LINUX_SYS_linux_setdomainname 121 #define LINUX_SYS_linux_newuname 122 #define LINUX_SYS_linux_modify_ldt 123 #define LINUX_SYS_linux_adjtimex 124 #define LINUX_SYS_linux_mprotect 125 #define LINUX_SYS_linux_sigprocmask 126 #define LINUX_SYS_linux_create_module 127 #define LINUX_SYS_linux_init_module 128 #define LINUX_SYS_linux_delete_module 129 #define LINUX_SYS_linux_get_kernel_syms 130 #define LINUX_SYS_linux_quotactl 131 #define LINUX_SYS_getpgid 132 #define LINUX_SYS_fchdir 133 #define LINUX_SYS_linux_bdflush 134 #define LINUX_SYS_linux_sysfs 135 #define LINUX_SYS_linux_personality 136 #define LINUX_SYS_linux_setfsuid16 138 #define LINUX_SYS_linux_setfsgid16 139 #define LINUX_SYS_linux_llseek 140 #define LINUX_SYS_linux_getdents 141 #define LINUX_SYS_linux_select 142 #define LINUX_SYS_flock 143 #define LINUX_SYS_linux_msync 144 #define LINUX_SYS_readv 145 #define LINUX_SYS_writev 146 #define LINUX_SYS_linux_getsid 147 #define LINUX_SYS_linux_fdatasync 148 #define LINUX_SYS_linux_sysctl 149 #define LINUX_SYS_mlock 150 #define LINUX_SYS_munlock 151 #define LINUX_SYS_mlockall 152 #define LINUX_SYS_munlockall 153 #define LINUX_SYS_linux_sched_setparam 154 #define LINUX_SYS_linux_sched_getparam 155 #define LINUX_SYS_linux_sched_setscheduler 156 #define LINUX_SYS_linux_sched_getscheduler 157 #define LINUX_SYS_sched_yield 158 #define LINUX_SYS_linux_sched_get_priority_max 159 #define LINUX_SYS_linux_sched_get_priority_min 160 #define LINUX_SYS_linux_sched_rr_get_interval 161 #define LINUX_SYS_linux_nanosleep 162 #define LINUX_SYS_linux_mremap 163 #define LINUX_SYS_linux_setresuid16 164 #define LINUX_SYS_linux_getresuid16 165 #define LINUX_SYS_linux_vm86 166 #define LINUX_SYS_linux_query_module 167 #define LINUX_SYS_poll 168 #define LINUX_SYS_linux_nfsservctl 169 #define LINUX_SYS_linux_setresgid16 170 #define LINUX_SYS_linux_getresgid16 171 #define LINUX_SYS_linux_prctl 172 #define LINUX_SYS_linux_rt_sigreturn 173 #define LINUX_SYS_linux_rt_sigaction 174 #define LINUX_SYS_linux_rt_sigprocmask 175 #define LINUX_SYS_linux_rt_sigpending 176 #define LINUX_SYS_linux_rt_sigtimedwait 177 #define LINUX_SYS_linux_rt_sigqueueinfo 178 #define LINUX_SYS_linux_rt_sigsuspend 179 #define LINUX_SYS_linux_pread 180 #define LINUX_SYS_linux_pwrite 181 #define LINUX_SYS_linux_chown16 182 #define LINUX_SYS_linux_getcwd 183 #define LINUX_SYS_linux_capget 184 #define LINUX_SYS_linux_capset 185 #define LINUX_SYS_linux_sigaltstack 186 #define LINUX_SYS_linux_sendfile 187 #define LINUX_SYS_linux_vfork 190 #define LINUX_SYS_linux_getrlimit 191 #define LINUX_SYS_linux_mmap2 192 #define LINUX_SYS_linux_truncate64 193 #define LINUX_SYS_linux_ftruncate64 194 #define LINUX_SYS_linux_stat64 195 #define LINUX_SYS_linux_lstat64 196 #define LINUX_SYS_linux_fstat64 197 #define LINUX_SYS_linux_lchown 198 #define LINUX_SYS_linux_getuid 199 #define LINUX_SYS_linux_getgid 200 #define LINUX_SYS_geteuid 201 #define LINUX_SYS_getegid 202 #define LINUX_SYS_setreuid 203 #define LINUX_SYS_setregid 204 #define LINUX_SYS_linux_getgroups 205 #define LINUX_SYS_linux_setgroups 206 #define LINUX_SYS_setresuid 208 #define LINUX_SYS_getresuid 209 #define LINUX_SYS_setresgid 210 #define LINUX_SYS_getresgid 211 #define LINUX_SYS_linux_chown 212 #define LINUX_SYS_setuid 213 #define LINUX_SYS_setgid 214 #define LINUX_SYS_linux_setfsuid 215 #define LINUX_SYS_linux_setfsgid 216 #define LINUX_SYS_linux_pivot_root 217 #define LINUX_SYS_linux_mincore 218 #define LINUX_SYS_madvise 219 #define LINUX_SYS_linux_getdents64 220 #define LINUX_SYS_linux_fcntl64 221 #define LINUX_SYS_linux_gettid 224 #define LINUX_SYS_linux_setxattr 226 #define LINUX_SYS_linux_lsetxattr 227 #define LINUX_SYS_linux_fsetxattr 228 #define LINUX_SYS_linux_getxattr 229 #define LINUX_SYS_linux_lgetxattr 230 #define LINUX_SYS_linux_fgetxattr 231 #define LINUX_SYS_linux_listxattr 232 #define LINUX_SYS_linux_llistxattr 233 #define LINUX_SYS_linux_flistxattr 234 #define LINUX_SYS_linux_removexattr 235 #define LINUX_SYS_linux_lremovexattr 236 #define LINUX_SYS_linux_fremovexattr 237 #define LINUX_SYS_linux_tkill 238 #define LINUX_SYS_linux_sys_futex 240 #define LINUX_SYS_linux_sched_setaffinity 241 #define LINUX_SYS_linux_sched_getaffinity 242 #define LINUX_SYS_linux_set_thread_area 243 #define LINUX_SYS_linux_get_thread_area 244 #define LINUX_SYS_linux_fadvise64 250 #define LINUX_SYS_linux_exit_group 252 #define LINUX_SYS_linux_lookup_dcookie 253 #define LINUX_SYS_linux_epoll_create 254 #define LINUX_SYS_linux_epoll_ctl 255 #define LINUX_SYS_linux_epoll_wait 256 #define LINUX_SYS_linux_remap_file_pages 257 #define LINUX_SYS_linux_set_tid_address 258 #define LINUX_SYS_linux_timer_create 259 #define LINUX_SYS_linux_timer_settime 260 #define LINUX_SYS_linux_timer_gettime 261 #define LINUX_SYS_linux_timer_getoverrun 262 #define LINUX_SYS_linux_timer_delete 263 #define LINUX_SYS_linux_clock_settime 264 #define LINUX_SYS_linux_clock_gettime 265 #define LINUX_SYS_linux_clock_getres 266 #define LINUX_SYS_linux_clock_nanosleep 267 #define LINUX_SYS_linux_statfs64 268 #define LINUX_SYS_linux_fstatfs64 269 #define LINUX_SYS_linux_tgkill 270 #define LINUX_SYS_linux_utimes 271 #define LINUX_SYS_linux_fadvise64_64 272 #define LINUX_SYS_linux_mbind 274 #define LINUX_SYS_linux_get_mempolicy 275 #define LINUX_SYS_linux_set_mempolicy 276 #define LINUX_SYS_linux_mq_open 277 #define LINUX_SYS_linux_mq_unlink 278 #define LINUX_SYS_linux_mq_timedsend 279 #define LINUX_SYS_linux_mq_timedreceive 280 #define LINUX_SYS_linux_mq_notify 281 #define LINUX_SYS_linux_mq_getsetattr 282 #define LINUX_SYS_linux_kexec_load 283 #define LINUX_SYS_linux_waitid 284 #define LINUX_SYS_linux_add_key 286 #define LINUX_SYS_linux_request_key 287 #define LINUX_SYS_linux_keyctl 288 #define LINUX_SYS_linux_ioprio_set 289 #define LINUX_SYS_linux_ioprio_get 290 #define LINUX_SYS_linux_inotify_init 291 #define LINUX_SYS_linux_inotify_add_watch 292 #define LINUX_SYS_linux_inotify_rm_watch 293 #define LINUX_SYS_linux_migrate_pages 294 #define LINUX_SYS_linux_openat 295 #define LINUX_SYS_linux_mkdirat 296 #define LINUX_SYS_linux_mknodat 297 #define LINUX_SYS_linux_fchownat 298 #define LINUX_SYS_linux_futimesat 299 #define LINUX_SYS_linux_fstatat64 300 #define LINUX_SYS_linux_unlinkat 301 #define LINUX_SYS_linux_renameat 302 #define LINUX_SYS_linux_linkat 303 #define LINUX_SYS_linux_symlinkat 304 #define LINUX_SYS_linux_readlinkat 305 #define LINUX_SYS_linux_fchmodat 306 #define LINUX_SYS_linux_faccessat 307 #define LINUX_SYS_linux_pselect6 308 #define LINUX_SYS_linux_ppoll 309 #define LINUX_SYS_linux_unshare 310 #define LINUX_SYS_linux_set_robust_list 311 #define LINUX_SYS_linux_get_robust_list 312 #define LINUX_SYS_linux_splice 313 #define LINUX_SYS_linux_sync_file_range 314 #define LINUX_SYS_linux_tee 315 #define LINUX_SYS_linux_vmsplice 316 #define LINUX_SYS_linux_move_pages 317 #define LINUX_SYS_linux_getcpu 318 #define LINUX_SYS_linux_epoll_pwait 319 #define LINUX_SYS_linux_utimensat 320 #define LINUX_SYS_linux_signalfd 321 #define LINUX_SYS_linux_timerfd_create 322 #define LINUX_SYS_linux_eventfd 323 #define LINUX_SYS_linux_fallocate 324 #define LINUX_SYS_linux_timerfd_settime 325 #define LINUX_SYS_linux_timerfd_gettime 326 #define LINUX_SYS_linux_signalfd4 327 #define LINUX_SYS_linux_eventfd2 328 #define LINUX_SYS_linux_epoll_create1 329 #define LINUX_SYS_linux_dup3 330 #define LINUX_SYS_linux_pipe2 331 #define LINUX_SYS_linux_inotify_init1 332 #define LINUX_SYS_linux_preadv 333 #define LINUX_SYS_linux_pwritev 334 -#define LINUX_SYS_linux_rt_tsigqueueinfo 335 +#define LINUX_SYS_linux_rt_tgsigqueueinfo 335 #define LINUX_SYS_linux_perf_event_open 336 #define LINUX_SYS_linux_recvmmsg 337 #define LINUX_SYS_linux_fanotify_init 338 #define LINUX_SYS_linux_fanotify_mark 339 #define LINUX_SYS_linux_prlimit64 340 #define LINUX_SYS_linux_name_to_handle_at 341 #define LINUX_SYS_linux_open_by_handle_at 342 #define LINUX_SYS_linux_clock_adjtime 343 #define LINUX_SYS_linux_syncfs 344 #define LINUX_SYS_linux_sendmmsg 345 #define LINUX_SYS_linux_setns 346 #define LINUX_SYS_linux_process_vm_readv 347 #define LINUX_SYS_linux_process_vm_writev 348 -#define LINUX_SYS_MAXSYSCALL 350 +#define LINUX_SYS_linux_kcmp 349 +#define LINUX_SYS_linux_finit_module 350 +#define LINUX_SYS_linux_sched_setattr 351 +#define LINUX_SYS_linux_sched_getattr 352 +#define LINUX_SYS_linux_renameat2 353 +#define LINUX_SYS_linux_seccomp 354 +#define LINUX_SYS_linux_getrandom 355 +#define LINUX_SYS_linux_memfd_create 356 +#define LINUX_SYS_linux_bpf 357 +#define LINUX_SYS_linux_execveat 358 +#define LINUX_SYS_linux_socket 359 +#define LINUX_SYS_linux_socketpair 360 +#define LINUX_SYS_linux_bind 361 +#define LINUX_SYS_linux_connect 362 +#define LINUX_SYS_linux_listen 363 +#define LINUX_SYS_linux_accept4 364 +#define LINUX_SYS_linux_getsockopt 365 +#define LINUX_SYS_linux_setsockopt 366 +#define LINUX_SYS_linux_getsockname 367 +#define LINUX_SYS_linux_getpeername 368 +#define LINUX_SYS_linux_sendto 369 +#define LINUX_SYS_linux_sendmsg 370 +#define LINUX_SYS_linux_recvfrom 371 +#define LINUX_SYS_linux_recvmsg 372 +#define LINUX_SYS_linux_shutdown 373 +#define LINUX_SYS_linux_userfaultfd 374 +#define LINUX_SYS_linux_membarrier 375 +#define LINUX_SYS_linux_mlock2 376 +#define LINUX_SYS_linux_copy_file_range 377 +#define LINUX_SYS_linux_preadv2 378 +#define LINUX_SYS_linux_pwritev2 379 +#define LINUX_SYS_linux_pkey_mprotect 380 +#define LINUX_SYS_linux_pkey_alloc 381 +#define LINUX_SYS_linux_pkey_free 382 +#define LINUX_SYS_MAXSYSCALL 384 Index: projects/ipsec/sys/i386/linux/linux_syscalls.c =================================================================== --- projects/ipsec/sys/i386/linux/linux_syscalls.c (revision 313312) +++ projects/ipsec/sys/i386/linux/linux_syscalls.c (revision 313313) @@ -1,361 +1,395 @@ /* * System call names. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/i386/linux/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/i386/linux/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ const char *linux_syscallnames[] = { #define nosys linux_nosys "#0", /* 0 = setup */ "linux_exit", /* 1 = linux_exit */ "linux_fork", /* 2 = linux_fork */ "read", /* 3 = read */ "write", /* 4 = write */ "linux_open", /* 5 = linux_open */ "close", /* 6 = close */ "linux_waitpid", /* 7 = linux_waitpid */ "linux_creat", /* 8 = linux_creat */ "linux_link", /* 9 = linux_link */ "linux_unlink", /* 10 = linux_unlink */ "linux_execve", /* 11 = linux_execve */ "linux_chdir", /* 12 = linux_chdir */ "linux_time", /* 13 = linux_time */ "linux_mknod", /* 14 = linux_mknod */ "linux_chmod", /* 15 = linux_chmod */ "linux_lchown16", /* 16 = linux_lchown16 */ "#17", /* 17 = break */ "linux_stat", /* 18 = linux_stat */ "linux_lseek", /* 19 = linux_lseek */ "linux_getpid", /* 20 = linux_getpid */ "linux_mount", /* 21 = linux_mount */ "linux_oldumount", /* 22 = linux_oldumount */ "linux_setuid16", /* 23 = linux_setuid16 */ "linux_getuid16", /* 24 = linux_getuid16 */ "linux_stime", /* 25 = linux_stime */ "linux_ptrace", /* 26 = linux_ptrace */ "linux_alarm", /* 27 = linux_alarm */ "linux_fstat", /* 28 = linux_fstat */ "linux_pause", /* 29 = linux_pause */ "linux_utime", /* 30 = linux_utime */ "#31", /* 31 = stty */ "#32", /* 32 = gtty */ "linux_access", /* 33 = linux_access */ "linux_nice", /* 34 = linux_nice */ "#35", /* 35 = ftime */ "sync", /* 36 = sync */ "linux_kill", /* 37 = linux_kill */ "linux_rename", /* 38 = linux_rename */ "linux_mkdir", /* 39 = linux_mkdir */ "linux_rmdir", /* 40 = linux_rmdir */ "dup", /* 41 = dup */ "linux_pipe", /* 42 = linux_pipe */ "linux_times", /* 43 = linux_times */ "#44", /* 44 = prof */ "linux_brk", /* 45 = linux_brk */ "linux_setgid16", /* 46 = linux_setgid16 */ "linux_getgid16", /* 47 = linux_getgid16 */ "linux_signal", /* 48 = linux_signal */ "linux_geteuid16", /* 49 = linux_geteuid16 */ "linux_getegid16", /* 50 = linux_getegid16 */ "acct", /* 51 = acct */ "linux_umount", /* 52 = linux_umount */ "#53", /* 53 = lock */ "linux_ioctl", /* 54 = linux_ioctl */ "linux_fcntl", /* 55 = linux_fcntl */ "#56", /* 56 = mpx */ "setpgid", /* 57 = setpgid */ "#58", /* 58 = ulimit */ "linux_olduname", /* 59 = linux_olduname */ "umask", /* 60 = umask */ "chroot", /* 61 = chroot */ "linux_ustat", /* 62 = linux_ustat */ "dup2", /* 63 = dup2 */ "linux_getppid", /* 64 = linux_getppid */ "getpgrp", /* 65 = getpgrp */ "setsid", /* 66 = setsid */ "linux_sigaction", /* 67 = linux_sigaction */ "linux_sgetmask", /* 68 = linux_sgetmask */ "linux_ssetmask", /* 69 = linux_ssetmask */ "linux_setreuid16", /* 70 = linux_setreuid16 */ "linux_setregid16", /* 71 = linux_setregid16 */ "linux_sigsuspend", /* 72 = linux_sigsuspend */ "linux_sigpending", /* 73 = linux_sigpending */ "linux_sethostname", /* 74 = linux_sethostname */ "linux_setrlimit", /* 75 = linux_setrlimit */ "linux_old_getrlimit", /* 76 = linux_old_getrlimit */ "getrusage", /* 77 = getrusage */ "gettimeofday", /* 78 = gettimeofday */ "settimeofday", /* 79 = settimeofday */ "linux_getgroups16", /* 80 = linux_getgroups16 */ "linux_setgroups16", /* 81 = linux_setgroups16 */ "linux_old_select", /* 82 = linux_old_select */ "linux_symlink", /* 83 = linux_symlink */ "linux_lstat", /* 84 = linux_lstat */ "linux_readlink", /* 85 = linux_readlink */ "linux_uselib", /* 86 = linux_uselib */ "swapon", /* 87 = swapon */ "linux_reboot", /* 88 = linux_reboot */ "linux_readdir", /* 89 = linux_readdir */ "linux_mmap", /* 90 = linux_mmap */ "munmap", /* 91 = munmap */ "linux_truncate", /* 92 = linux_truncate */ "linux_ftruncate", /* 93 = linux_ftruncate */ "fchmod", /* 94 = fchmod */ "fchown", /* 95 = fchown */ "linux_getpriority", /* 96 = linux_getpriority */ "setpriority", /* 97 = setpriority */ "#98", /* 98 = profil */ "linux_statfs", /* 99 = linux_statfs */ "linux_fstatfs", /* 100 = linux_fstatfs */ "linux_ioperm", /* 101 = linux_ioperm */ "linux_socketcall", /* 102 = linux_socketcall */ "linux_syslog", /* 103 = linux_syslog */ "linux_setitimer", /* 104 = linux_setitimer */ "linux_getitimer", /* 105 = linux_getitimer */ "linux_newstat", /* 106 = linux_newstat */ "linux_newlstat", /* 107 = linux_newlstat */ "linux_newfstat", /* 108 = linux_newfstat */ "linux_uname", /* 109 = linux_uname */ "linux_iopl", /* 110 = linux_iopl */ "linux_vhangup", /* 111 = linux_vhangup */ "#112", /* 112 = idle */ "linux_vm86old", /* 113 = linux_vm86old */ "linux_wait4", /* 114 = linux_wait4 */ "linux_swapoff", /* 115 = linux_swapoff */ "linux_sysinfo", /* 116 = linux_sysinfo */ "linux_ipc", /* 117 = linux_ipc */ "fsync", /* 118 = fsync */ "linux_sigreturn", /* 119 = linux_sigreturn */ "linux_clone", /* 120 = linux_clone */ "linux_setdomainname", /* 121 = linux_setdomainname */ "linux_newuname", /* 122 = linux_newuname */ "linux_modify_ldt", /* 123 = linux_modify_ldt */ "linux_adjtimex", /* 124 = linux_adjtimex */ "linux_mprotect", /* 125 = linux_mprotect */ "linux_sigprocmask", /* 126 = linux_sigprocmask */ "linux_create_module", /* 127 = linux_create_module */ "linux_init_module", /* 128 = linux_init_module */ "linux_delete_module", /* 129 = linux_delete_module */ "linux_get_kernel_syms", /* 130 = linux_get_kernel_syms */ "linux_quotactl", /* 131 = linux_quotactl */ "getpgid", /* 132 = getpgid */ "fchdir", /* 133 = fchdir */ "linux_bdflush", /* 134 = linux_bdflush */ "linux_sysfs", /* 135 = linux_sysfs */ "linux_personality", /* 136 = linux_personality */ "#137", /* 137 = afs_syscall */ "linux_setfsuid16", /* 138 = linux_setfsuid16 */ "linux_setfsgid16", /* 139 = linux_setfsgid16 */ "linux_llseek", /* 140 = linux_llseek */ "linux_getdents", /* 141 = linux_getdents */ "linux_select", /* 142 = linux_select */ "flock", /* 143 = flock */ "linux_msync", /* 144 = linux_msync */ "readv", /* 145 = readv */ "writev", /* 146 = writev */ "linux_getsid", /* 147 = linux_getsid */ "linux_fdatasync", /* 148 = linux_fdatasync */ "linux_sysctl", /* 149 = linux_sysctl */ "mlock", /* 150 = mlock */ "munlock", /* 151 = munlock */ "mlockall", /* 152 = mlockall */ "munlockall", /* 153 = munlockall */ "linux_sched_setparam", /* 154 = linux_sched_setparam */ "linux_sched_getparam", /* 155 = linux_sched_getparam */ "linux_sched_setscheduler", /* 156 = linux_sched_setscheduler */ "linux_sched_getscheduler", /* 157 = linux_sched_getscheduler */ "sched_yield", /* 158 = sched_yield */ "linux_sched_get_priority_max", /* 159 = linux_sched_get_priority_max */ "linux_sched_get_priority_min", /* 160 = linux_sched_get_priority_min */ "linux_sched_rr_get_interval", /* 161 = linux_sched_rr_get_interval */ "linux_nanosleep", /* 162 = linux_nanosleep */ "linux_mremap", /* 163 = linux_mremap */ "linux_setresuid16", /* 164 = linux_setresuid16 */ "linux_getresuid16", /* 165 = linux_getresuid16 */ "linux_vm86", /* 166 = linux_vm86 */ "linux_query_module", /* 167 = linux_query_module */ "poll", /* 168 = poll */ "linux_nfsservctl", /* 169 = linux_nfsservctl */ "linux_setresgid16", /* 170 = linux_setresgid16 */ "linux_getresgid16", /* 171 = linux_getresgid16 */ "linux_prctl", /* 172 = linux_prctl */ "linux_rt_sigreturn", /* 173 = linux_rt_sigreturn */ "linux_rt_sigaction", /* 174 = linux_rt_sigaction */ "linux_rt_sigprocmask", /* 175 = linux_rt_sigprocmask */ "linux_rt_sigpending", /* 176 = linux_rt_sigpending */ "linux_rt_sigtimedwait", /* 177 = linux_rt_sigtimedwait */ "linux_rt_sigqueueinfo", /* 178 = linux_rt_sigqueueinfo */ "linux_rt_sigsuspend", /* 179 = linux_rt_sigsuspend */ "linux_pread", /* 180 = linux_pread */ "linux_pwrite", /* 181 = linux_pwrite */ "linux_chown16", /* 182 = linux_chown16 */ "linux_getcwd", /* 183 = linux_getcwd */ "linux_capget", /* 184 = linux_capget */ "linux_capset", /* 185 = linux_capset */ "linux_sigaltstack", /* 186 = linux_sigaltstack */ "linux_sendfile", /* 187 = linux_sendfile */ "#188", /* 188 = getpmsg */ "#189", /* 189 = putpmsg */ "linux_vfork", /* 190 = linux_vfork */ "linux_getrlimit", /* 191 = linux_getrlimit */ "linux_mmap2", /* 192 = linux_mmap2 */ "linux_truncate64", /* 193 = linux_truncate64 */ "linux_ftruncate64", /* 194 = linux_ftruncate64 */ "linux_stat64", /* 195 = linux_stat64 */ "linux_lstat64", /* 196 = linux_lstat64 */ "linux_fstat64", /* 197 = linux_fstat64 */ "linux_lchown", /* 198 = linux_lchown */ "linux_getuid", /* 199 = linux_getuid */ "linux_getgid", /* 200 = linux_getgid */ "geteuid", /* 201 = geteuid */ "getegid", /* 202 = getegid */ "setreuid", /* 203 = setreuid */ "setregid", /* 204 = setregid */ "linux_getgroups", /* 205 = linux_getgroups */ "linux_setgroups", /* 206 = linux_setgroups */ "fchown", /* 207 = fchown */ "setresuid", /* 208 = setresuid */ "getresuid", /* 209 = getresuid */ "setresgid", /* 210 = setresgid */ "getresgid", /* 211 = getresgid */ "linux_chown", /* 212 = linux_chown */ "setuid", /* 213 = setuid */ "setgid", /* 214 = setgid */ "linux_setfsuid", /* 215 = linux_setfsuid */ "linux_setfsgid", /* 216 = linux_setfsgid */ "linux_pivot_root", /* 217 = linux_pivot_root */ "linux_mincore", /* 218 = linux_mincore */ "madvise", /* 219 = madvise */ "linux_getdents64", /* 220 = linux_getdents64 */ "linux_fcntl64", /* 221 = linux_fcntl64 */ "#222", /* 222 = */ "#223", /* 223 = */ "linux_gettid", /* 224 = linux_gettid */ "#225", /* 225 = linux_readahead */ "linux_setxattr", /* 226 = linux_setxattr */ "linux_lsetxattr", /* 227 = linux_lsetxattr */ "linux_fsetxattr", /* 228 = linux_fsetxattr */ "linux_getxattr", /* 229 = linux_getxattr */ "linux_lgetxattr", /* 230 = linux_lgetxattr */ "linux_fgetxattr", /* 231 = linux_fgetxattr */ "linux_listxattr", /* 232 = linux_listxattr */ "linux_llistxattr", /* 233 = linux_llistxattr */ "linux_flistxattr", /* 234 = linux_flistxattr */ "linux_removexattr", /* 235 = linux_removexattr */ "linux_lremovexattr", /* 236 = linux_lremovexattr */ "linux_fremovexattr", /* 237 = linux_fremovexattr */ "linux_tkill", /* 238 = linux_tkill */ "#239", /* 239 = linux_sendfile64 */ "linux_sys_futex", /* 240 = linux_sys_futex */ "linux_sched_setaffinity", /* 241 = linux_sched_setaffinity */ "linux_sched_getaffinity", /* 242 = linux_sched_getaffinity */ "linux_set_thread_area", /* 243 = linux_set_thread_area */ "linux_get_thread_area", /* 244 = linux_get_thread_area */ "#245", /* 245 = linux_io_setup */ "#246", /* 246 = linux_io_destroy */ "#247", /* 247 = linux_io_getevents */ "#248", /* 248 = linux_io_submit */ "#249", /* 249 = linux_io_cancel */ "linux_fadvise64", /* 250 = linux_fadvise64 */ "#251", /* 251 = */ "linux_exit_group", /* 252 = linux_exit_group */ "linux_lookup_dcookie", /* 253 = linux_lookup_dcookie */ "linux_epoll_create", /* 254 = linux_epoll_create */ "linux_epoll_ctl", /* 255 = linux_epoll_ctl */ "linux_epoll_wait", /* 256 = linux_epoll_wait */ "linux_remap_file_pages", /* 257 = linux_remap_file_pages */ "linux_set_tid_address", /* 258 = linux_set_tid_address */ "linux_timer_create", /* 259 = linux_timer_create */ "linux_timer_settime", /* 260 = linux_timer_settime */ "linux_timer_gettime", /* 261 = linux_timer_gettime */ "linux_timer_getoverrun", /* 262 = linux_timer_getoverrun */ "linux_timer_delete", /* 263 = linux_timer_delete */ "linux_clock_settime", /* 264 = linux_clock_settime */ "linux_clock_gettime", /* 265 = linux_clock_gettime */ "linux_clock_getres", /* 266 = linux_clock_getres */ "linux_clock_nanosleep", /* 267 = linux_clock_nanosleep */ "linux_statfs64", /* 268 = linux_statfs64 */ "linux_fstatfs64", /* 269 = linux_fstatfs64 */ "linux_tgkill", /* 270 = linux_tgkill */ "linux_utimes", /* 271 = linux_utimes */ "linux_fadvise64_64", /* 272 = linux_fadvise64_64 */ "#273", /* 273 = vserver */ "linux_mbind", /* 274 = linux_mbind */ "linux_get_mempolicy", /* 275 = linux_get_mempolicy */ "linux_set_mempolicy", /* 276 = linux_set_mempolicy */ "linux_mq_open", /* 277 = linux_mq_open */ "linux_mq_unlink", /* 278 = linux_mq_unlink */ "linux_mq_timedsend", /* 279 = linux_mq_timedsend */ "linux_mq_timedreceive", /* 280 = linux_mq_timedreceive */ "linux_mq_notify", /* 281 = linux_mq_notify */ "linux_mq_getsetattr", /* 282 = linux_mq_getsetattr */ "linux_kexec_load", /* 283 = linux_kexec_load */ "linux_waitid", /* 284 = linux_waitid */ "#285", /* 285 = */ "linux_add_key", /* 286 = linux_add_key */ "linux_request_key", /* 287 = linux_request_key */ "linux_keyctl", /* 288 = linux_keyctl */ "linux_ioprio_set", /* 289 = linux_ioprio_set */ "linux_ioprio_get", /* 290 = linux_ioprio_get */ "linux_inotify_init", /* 291 = linux_inotify_init */ "linux_inotify_add_watch", /* 292 = linux_inotify_add_watch */ "linux_inotify_rm_watch", /* 293 = linux_inotify_rm_watch */ "linux_migrate_pages", /* 294 = linux_migrate_pages */ "linux_openat", /* 295 = linux_openat */ "linux_mkdirat", /* 296 = linux_mkdirat */ "linux_mknodat", /* 297 = linux_mknodat */ "linux_fchownat", /* 298 = linux_fchownat */ "linux_futimesat", /* 299 = linux_futimesat */ "linux_fstatat64", /* 300 = linux_fstatat64 */ "linux_unlinkat", /* 301 = linux_unlinkat */ "linux_renameat", /* 302 = linux_renameat */ "linux_linkat", /* 303 = linux_linkat */ "linux_symlinkat", /* 304 = linux_symlinkat */ "linux_readlinkat", /* 305 = linux_readlinkat */ "linux_fchmodat", /* 306 = linux_fchmodat */ "linux_faccessat", /* 307 = linux_faccessat */ "linux_pselect6", /* 308 = linux_pselect6 */ "linux_ppoll", /* 309 = linux_ppoll */ "linux_unshare", /* 310 = linux_unshare */ "linux_set_robust_list", /* 311 = linux_set_robust_list */ "linux_get_robust_list", /* 312 = linux_get_robust_list */ "linux_splice", /* 313 = linux_splice */ "linux_sync_file_range", /* 314 = linux_sync_file_range */ "linux_tee", /* 315 = linux_tee */ "linux_vmsplice", /* 316 = linux_vmsplice */ "linux_move_pages", /* 317 = linux_move_pages */ "linux_getcpu", /* 318 = linux_getcpu */ "linux_epoll_pwait", /* 319 = linux_epoll_pwait */ "linux_utimensat", /* 320 = linux_utimensat */ "linux_signalfd", /* 321 = linux_signalfd */ "linux_timerfd_create", /* 322 = linux_timerfd_create */ "linux_eventfd", /* 323 = linux_eventfd */ "linux_fallocate", /* 324 = linux_fallocate */ "linux_timerfd_settime", /* 325 = linux_timerfd_settime */ "linux_timerfd_gettime", /* 326 = linux_timerfd_gettime */ "linux_signalfd4", /* 327 = linux_signalfd4 */ "linux_eventfd2", /* 328 = linux_eventfd2 */ "linux_epoll_create1", /* 329 = linux_epoll_create1 */ "linux_dup3", /* 330 = linux_dup3 */ "linux_pipe2", /* 331 = linux_pipe2 */ "linux_inotify_init1", /* 332 = linux_inotify_init1 */ "linux_preadv", /* 333 = linux_preadv */ "linux_pwritev", /* 334 = linux_pwritev */ - "linux_rt_tsigqueueinfo", /* 335 = linux_rt_tsigqueueinfo */ + "linux_rt_tgsigqueueinfo", /* 335 = linux_rt_tgsigqueueinfo */ "linux_perf_event_open", /* 336 = linux_perf_event_open */ "linux_recvmmsg", /* 337 = linux_recvmmsg */ "linux_fanotify_init", /* 338 = linux_fanotify_init */ "linux_fanotify_mark", /* 339 = linux_fanotify_mark */ "linux_prlimit64", /* 340 = linux_prlimit64 */ "linux_name_to_handle_at", /* 341 = linux_name_to_handle_at */ "linux_open_by_handle_at", /* 342 = linux_open_by_handle_at */ "linux_clock_adjtime", /* 343 = linux_clock_adjtime */ "linux_syncfs", /* 344 = linux_syncfs */ "linux_sendmmsg", /* 345 = linux_sendmmsg */ "linux_setns", /* 346 = linux_setns */ "linux_process_vm_readv", /* 347 = linux_process_vm_readv */ "linux_process_vm_writev", /* 348 = linux_process_vm_writev */ - "#349", /* 349 = nosys */ + "linux_kcmp", /* 349 = linux_kcmp */ + "linux_finit_module", /* 350 = linux_finit_module */ + "linux_sched_setattr", /* 351 = linux_sched_setattr */ + "linux_sched_getattr", /* 352 = linux_sched_getattr */ + "linux_renameat2", /* 353 = linux_renameat2 */ + "linux_seccomp", /* 354 = linux_seccomp */ + "linux_getrandom", /* 355 = linux_getrandom */ + "linux_memfd_create", /* 356 = linux_memfd_create */ + "linux_bpf", /* 357 = linux_bpf */ + "linux_execveat", /* 358 = linux_execveat */ + "linux_socket", /* 359 = linux_socket */ + "linux_socketpair", /* 360 = linux_socketpair */ + "linux_bind", /* 361 = linux_bind */ + "linux_connect", /* 362 = linux_connect */ + "linux_listen", /* 363 = linux_listen */ + "linux_accept4", /* 364 = linux_accept4 */ + "linux_getsockopt", /* 365 = linux_getsockopt */ + "linux_setsockopt", /* 366 = linux_setsockopt */ + "linux_getsockname", /* 367 = linux_getsockname */ + "linux_getpeername", /* 368 = linux_getpeername */ + "linux_sendto", /* 369 = linux_sendto */ + "linux_sendmsg", /* 370 = linux_sendmsg */ + "linux_recvfrom", /* 371 = linux_recvfrom */ + "linux_recvmsg", /* 372 = linux_recvmsg */ + "linux_shutdown", /* 373 = linux_shutdown */ + "linux_userfaultfd", /* 374 = linux_userfaultfd */ + "linux_membarrier", /* 375 = linux_membarrier */ + "linux_mlock2", /* 376 = linux_mlock2 */ + "linux_copy_file_range", /* 377 = linux_copy_file_range */ + "linux_preadv2", /* 378 = linux_preadv2 */ + "linux_pwritev2", /* 379 = linux_pwritev2 */ + "linux_pkey_mprotect", /* 380 = linux_pkey_mprotect */ + "linux_pkey_alloc", /* 381 = linux_pkey_alloc */ + "linux_pkey_free", /* 382 = linux_pkey_free */ + "#383", /* 383 = nosys */ }; Index: projects/ipsec/sys/i386/linux/linux_sysent.c =================================================================== --- projects/ipsec/sys/i386/linux/linux_sysent.c (revision 313312) +++ projects/ipsec/sys/i386/linux/linux_sysent.c (revision 313313) @@ -1,371 +1,405 @@ /* * System call switch table. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/i386/linux/syscalls.master 302515 2016-07-10 08:15:50Z dchagin + * created from FreeBSD: head/sys/i386/linux/syscalls.master 313284 2017-02-05 14:17:09Z dchagin */ #include #include #include #include #include #include #define AS(name) (sizeof(struct name) / sizeof(register_t)) /* The casts are bogus but will do for now. */ struct sysent linux_sysent[] = { #define nosys linux_nosys { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 0 = setup */ { AS(linux_exit_args), (sy_call_t *)linux_exit, AUE_EXIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 1 = linux_exit */ { 0, (sy_call_t *)linux_fork, AUE_FORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 2 = linux_fork */ { AS(read_args), (sy_call_t *)sys_read, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 3 = read */ { AS(write_args), (sy_call_t *)sys_write, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 4 = write */ { AS(linux_open_args), (sy_call_t *)linux_open, AUE_OPEN_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 5 = linux_open */ { AS(close_args), (sy_call_t *)sys_close, AUE_CLOSE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 6 = close */ { AS(linux_waitpid_args), (sy_call_t *)linux_waitpid, AUE_WAIT4, NULL, 0, 0, 0, SY_THR_STATIC }, /* 7 = linux_waitpid */ { AS(linux_creat_args), (sy_call_t *)linux_creat, AUE_CREAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 8 = linux_creat */ { AS(linux_link_args), (sy_call_t *)linux_link, AUE_LINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 9 = linux_link */ { AS(linux_unlink_args), (sy_call_t *)linux_unlink, AUE_UNLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 10 = linux_unlink */ { AS(linux_execve_args), (sy_call_t *)linux_execve, AUE_EXECVE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 11 = linux_execve */ { AS(linux_chdir_args), (sy_call_t *)linux_chdir, AUE_CHDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 12 = linux_chdir */ { AS(linux_time_args), (sy_call_t *)linux_time, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 13 = linux_time */ { AS(linux_mknod_args), (sy_call_t *)linux_mknod, AUE_MKNOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 14 = linux_mknod */ { AS(linux_chmod_args), (sy_call_t *)linux_chmod, AUE_CHMOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 15 = linux_chmod */ { AS(linux_lchown16_args), (sy_call_t *)linux_lchown16, AUE_LCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 16 = linux_lchown16 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 17 = break */ { AS(linux_stat_args), (sy_call_t *)linux_stat, AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 18 = linux_stat */ { AS(linux_lseek_args), (sy_call_t *)linux_lseek, AUE_LSEEK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 19 = linux_lseek */ { 0, (sy_call_t *)linux_getpid, AUE_GETPID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 20 = linux_getpid */ { AS(linux_mount_args), (sy_call_t *)linux_mount, AUE_MOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 21 = linux_mount */ { AS(linux_oldumount_args), (sy_call_t *)linux_oldumount, AUE_UMOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 22 = linux_oldumount */ { AS(linux_setuid16_args), (sy_call_t *)linux_setuid16, AUE_SETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 23 = linux_setuid16 */ { 0, (sy_call_t *)linux_getuid16, AUE_GETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 24 = linux_getuid16 */ { 0, (sy_call_t *)linux_stime, AUE_SETTIMEOFDAY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 25 = linux_stime */ { AS(linux_ptrace_args), (sy_call_t *)linux_ptrace, AUE_PTRACE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 26 = linux_ptrace */ { AS(linux_alarm_args), (sy_call_t *)linux_alarm, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 27 = linux_alarm */ { AS(linux_fstat_args), (sy_call_t *)linux_fstat, AUE_FSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 28 = linux_fstat */ { 0, (sy_call_t *)linux_pause, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 29 = linux_pause */ { AS(linux_utime_args), (sy_call_t *)linux_utime, AUE_UTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 30 = linux_utime */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 31 = stty */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 32 = gtty */ { AS(linux_access_args), (sy_call_t *)linux_access, AUE_ACCESS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 33 = linux_access */ { AS(linux_nice_args), (sy_call_t *)linux_nice, AUE_NICE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 34 = linux_nice */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 35 = ftime */ { 0, (sy_call_t *)sys_sync, AUE_SYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 36 = sync */ { AS(linux_kill_args), (sy_call_t *)linux_kill, AUE_KILL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 37 = linux_kill */ { AS(linux_rename_args), (sy_call_t *)linux_rename, AUE_RENAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 38 = linux_rename */ { AS(linux_mkdir_args), (sy_call_t *)linux_mkdir, AUE_MKDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 39 = linux_mkdir */ { AS(linux_rmdir_args), (sy_call_t *)linux_rmdir, AUE_RMDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 40 = linux_rmdir */ { AS(dup_args), (sy_call_t *)sys_dup, AUE_DUP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 41 = dup */ { AS(linux_pipe_args), (sy_call_t *)linux_pipe, AUE_PIPE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 42 = linux_pipe */ { AS(linux_times_args), (sy_call_t *)linux_times, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 43 = linux_times */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 44 = prof */ { AS(linux_brk_args), (sy_call_t *)linux_brk, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 45 = linux_brk */ { AS(linux_setgid16_args), (sy_call_t *)linux_setgid16, AUE_SETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 46 = linux_setgid16 */ { 0, (sy_call_t *)linux_getgid16, AUE_GETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 47 = linux_getgid16 */ { AS(linux_signal_args), (sy_call_t *)linux_signal, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 48 = linux_signal */ { 0, (sy_call_t *)linux_geteuid16, AUE_GETEUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 49 = linux_geteuid16 */ { 0, (sy_call_t *)linux_getegid16, AUE_GETEGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 50 = linux_getegid16 */ { AS(acct_args), (sy_call_t *)sys_acct, AUE_ACCT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 51 = acct */ { AS(linux_umount_args), (sy_call_t *)linux_umount, AUE_UMOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 52 = linux_umount */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 53 = lock */ { AS(linux_ioctl_args), (sy_call_t *)linux_ioctl, AUE_IOCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 54 = linux_ioctl */ { AS(linux_fcntl_args), (sy_call_t *)linux_fcntl, AUE_FCNTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 55 = linux_fcntl */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 56 = mpx */ { AS(setpgid_args), (sy_call_t *)sys_setpgid, AUE_SETPGRP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 57 = setpgid */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 58 = ulimit */ { 0, (sy_call_t *)linux_olduname, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 59 = linux_olduname */ { AS(umask_args), (sy_call_t *)sys_umask, AUE_UMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 60 = umask */ { AS(chroot_args), (sy_call_t *)sys_chroot, AUE_CHROOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 61 = chroot */ { AS(linux_ustat_args), (sy_call_t *)linux_ustat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 62 = linux_ustat */ { AS(dup2_args), (sy_call_t *)sys_dup2, AUE_DUP2, NULL, 0, 0, 0, SY_THR_STATIC }, /* 63 = dup2 */ { 0, (sy_call_t *)linux_getppid, AUE_GETPPID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 64 = linux_getppid */ { 0, (sy_call_t *)sys_getpgrp, AUE_GETPGRP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 65 = getpgrp */ { 0, (sy_call_t *)sys_setsid, AUE_SETSID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 66 = setsid */ { AS(linux_sigaction_args), (sy_call_t *)linux_sigaction, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 67 = linux_sigaction */ { 0, (sy_call_t *)linux_sgetmask, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 68 = linux_sgetmask */ { AS(linux_ssetmask_args), (sy_call_t *)linux_ssetmask, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 69 = linux_ssetmask */ { AS(linux_setreuid16_args), (sy_call_t *)linux_setreuid16, AUE_SETREUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 70 = linux_setreuid16 */ { AS(linux_setregid16_args), (sy_call_t *)linux_setregid16, AUE_SETREGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 71 = linux_setregid16 */ { AS(linux_sigsuspend_args), (sy_call_t *)linux_sigsuspend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 72 = linux_sigsuspend */ { AS(linux_sigpending_args), (sy_call_t *)linux_sigpending, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 73 = linux_sigpending */ { AS(linux_sethostname_args), (sy_call_t *)linux_sethostname, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 74 = linux_sethostname */ { AS(linux_setrlimit_args), (sy_call_t *)linux_setrlimit, AUE_SETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 75 = linux_setrlimit */ { AS(linux_old_getrlimit_args), (sy_call_t *)linux_old_getrlimit, AUE_GETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 76 = linux_old_getrlimit */ { AS(getrusage_args), (sy_call_t *)sys_getrusage, AUE_GETRUSAGE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 77 = getrusage */ { AS(gettimeofday_args), (sy_call_t *)sys_gettimeofday, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 78 = gettimeofday */ { AS(settimeofday_args), (sy_call_t *)sys_settimeofday, AUE_SETTIMEOFDAY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 79 = settimeofday */ { AS(linux_getgroups16_args), (sy_call_t *)linux_getgroups16, AUE_GETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 80 = linux_getgroups16 */ { AS(linux_setgroups16_args), (sy_call_t *)linux_setgroups16, AUE_SETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 81 = linux_setgroups16 */ { AS(linux_old_select_args), (sy_call_t *)linux_old_select, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 82 = linux_old_select */ { AS(linux_symlink_args), (sy_call_t *)linux_symlink, AUE_SYMLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 83 = linux_symlink */ { AS(linux_lstat_args), (sy_call_t *)linux_lstat, AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 84 = linux_lstat */ { AS(linux_readlink_args), (sy_call_t *)linux_readlink, AUE_READLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 85 = linux_readlink */ { AS(linux_uselib_args), (sy_call_t *)linux_uselib, AUE_USELIB, NULL, 0, 0, 0, SY_THR_STATIC }, /* 86 = linux_uselib */ { AS(swapon_args), (sy_call_t *)sys_swapon, AUE_SWAPON, NULL, 0, 0, 0, SY_THR_STATIC }, /* 87 = swapon */ { AS(linux_reboot_args), (sy_call_t *)linux_reboot, AUE_REBOOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 88 = linux_reboot */ { AS(linux_readdir_args), (sy_call_t *)linux_readdir, AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 89 = linux_readdir */ { AS(linux_mmap_args), (sy_call_t *)linux_mmap, AUE_MMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 90 = linux_mmap */ { AS(munmap_args), (sy_call_t *)sys_munmap, AUE_MUNMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 91 = munmap */ { AS(linux_truncate_args), (sy_call_t *)linux_truncate, AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 92 = linux_truncate */ { AS(linux_ftruncate_args), (sy_call_t *)linux_ftruncate, AUE_FTRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 93 = linux_ftruncate */ { AS(fchmod_args), (sy_call_t *)sys_fchmod, AUE_FCHMOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 94 = fchmod */ { AS(fchown_args), (sy_call_t *)sys_fchown, AUE_FCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 95 = fchown */ { AS(linux_getpriority_args), (sy_call_t *)linux_getpriority, AUE_GETPRIORITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 96 = linux_getpriority */ { AS(setpriority_args), (sy_call_t *)sys_setpriority, AUE_SETPRIORITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 97 = setpriority */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 98 = profil */ { AS(linux_statfs_args), (sy_call_t *)linux_statfs, AUE_STATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 99 = linux_statfs */ { AS(linux_fstatfs_args), (sy_call_t *)linux_fstatfs, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 100 = linux_fstatfs */ { AS(linux_ioperm_args), (sy_call_t *)linux_ioperm, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 101 = linux_ioperm */ { AS(linux_socketcall_args), (sy_call_t *)linux_socketcall, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 102 = linux_socketcall */ { AS(linux_syslog_args), (sy_call_t *)linux_syslog, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 103 = linux_syslog */ { AS(linux_setitimer_args), (sy_call_t *)linux_setitimer, AUE_SETITIMER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 104 = linux_setitimer */ { AS(linux_getitimer_args), (sy_call_t *)linux_getitimer, AUE_GETITIMER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 105 = linux_getitimer */ { AS(linux_newstat_args), (sy_call_t *)linux_newstat, AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 106 = linux_newstat */ { AS(linux_newlstat_args), (sy_call_t *)linux_newlstat, AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 107 = linux_newlstat */ { AS(linux_newfstat_args), (sy_call_t *)linux_newfstat, AUE_FSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 108 = linux_newfstat */ { 0, (sy_call_t *)linux_uname, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 109 = linux_uname */ { AS(linux_iopl_args), (sy_call_t *)linux_iopl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 110 = linux_iopl */ { 0, (sy_call_t *)linux_vhangup, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 111 = linux_vhangup */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 112 = idle */ { 0, (sy_call_t *)linux_vm86old, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 113 = linux_vm86old */ { AS(linux_wait4_args), (sy_call_t *)linux_wait4, AUE_WAIT4, NULL, 0, 0, 0, SY_THR_STATIC }, /* 114 = linux_wait4 */ { 0, (sy_call_t *)linux_swapoff, AUE_SWAPOFF, NULL, 0, 0, 0, SY_THR_STATIC }, /* 115 = linux_swapoff */ { AS(linux_sysinfo_args), (sy_call_t *)linux_sysinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 116 = linux_sysinfo */ { AS(linux_ipc_args), (sy_call_t *)linux_ipc, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 117 = linux_ipc */ { AS(fsync_args), (sy_call_t *)sys_fsync, AUE_FSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 118 = fsync */ { AS(linux_sigreturn_args), (sy_call_t *)linux_sigreturn, AUE_SIGRETURN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 119 = linux_sigreturn */ { AS(linux_clone_args), (sy_call_t *)linux_clone, AUE_RFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 120 = linux_clone */ { AS(linux_setdomainname_args), (sy_call_t *)linux_setdomainname, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 121 = linux_setdomainname */ { AS(linux_newuname_args), (sy_call_t *)linux_newuname, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 122 = linux_newuname */ { AS(linux_modify_ldt_args), (sy_call_t *)linux_modify_ldt, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 123 = linux_modify_ldt */ { 0, (sy_call_t *)linux_adjtimex, AUE_ADJTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 124 = linux_adjtimex */ { AS(linux_mprotect_args), (sy_call_t *)linux_mprotect, AUE_MPROTECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 125 = linux_mprotect */ { AS(linux_sigprocmask_args), (sy_call_t *)linux_sigprocmask, AUE_SIGPROCMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 126 = linux_sigprocmask */ { 0, (sy_call_t *)linux_create_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 127 = linux_create_module */ { 0, (sy_call_t *)linux_init_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 128 = linux_init_module */ { 0, (sy_call_t *)linux_delete_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 129 = linux_delete_module */ { 0, (sy_call_t *)linux_get_kernel_syms, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 130 = linux_get_kernel_syms */ { 0, (sy_call_t *)linux_quotactl, AUE_QUOTACTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 131 = linux_quotactl */ { AS(getpgid_args), (sy_call_t *)sys_getpgid, AUE_GETPGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 132 = getpgid */ { AS(fchdir_args), (sy_call_t *)sys_fchdir, AUE_FCHDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 133 = fchdir */ { 0, (sy_call_t *)linux_bdflush, AUE_BDFLUSH, NULL, 0, 0, 0, SY_THR_STATIC }, /* 134 = linux_bdflush */ { AS(linux_sysfs_args), (sy_call_t *)linux_sysfs, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 135 = linux_sysfs */ { AS(linux_personality_args), (sy_call_t *)linux_personality, AUE_PERSONALITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 136 = linux_personality */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 137 = afs_syscall */ { AS(linux_setfsuid16_args), (sy_call_t *)linux_setfsuid16, AUE_SETFSUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 138 = linux_setfsuid16 */ { AS(linux_setfsgid16_args), (sy_call_t *)linux_setfsgid16, AUE_SETFSGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 139 = linux_setfsgid16 */ { AS(linux_llseek_args), (sy_call_t *)linux_llseek, AUE_LSEEK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 140 = linux_llseek */ { AS(linux_getdents_args), (sy_call_t *)linux_getdents, AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 141 = linux_getdents */ { AS(linux_select_args), (sy_call_t *)linux_select, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 142 = linux_select */ { AS(flock_args), (sy_call_t *)sys_flock, AUE_FLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 143 = flock */ { AS(linux_msync_args), (sy_call_t *)linux_msync, AUE_MSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 144 = linux_msync */ { AS(readv_args), (sy_call_t *)sys_readv, AUE_READV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 145 = readv */ { AS(writev_args), (sy_call_t *)sys_writev, AUE_WRITEV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 146 = writev */ { AS(linux_getsid_args), (sy_call_t *)linux_getsid, AUE_GETSID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 147 = linux_getsid */ { AS(linux_fdatasync_args), (sy_call_t *)linux_fdatasync, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 148 = linux_fdatasync */ { AS(linux_sysctl_args), (sy_call_t *)linux_sysctl, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 149 = linux_sysctl */ { AS(mlock_args), (sy_call_t *)sys_mlock, AUE_MLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 150 = mlock */ { AS(munlock_args), (sy_call_t *)sys_munlock, AUE_MUNLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 151 = munlock */ { AS(mlockall_args), (sy_call_t *)sys_mlockall, AUE_MLOCKALL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 152 = mlockall */ { 0, (sy_call_t *)sys_munlockall, AUE_MUNLOCKALL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 153 = munlockall */ { AS(linux_sched_setparam_args), (sy_call_t *)linux_sched_setparam, AUE_SCHED_SETPARAM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 154 = linux_sched_setparam */ { AS(linux_sched_getparam_args), (sy_call_t *)linux_sched_getparam, AUE_SCHED_GETPARAM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 155 = linux_sched_getparam */ { AS(linux_sched_setscheduler_args), (sy_call_t *)linux_sched_setscheduler, AUE_SCHED_SETSCHEDULER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 156 = linux_sched_setscheduler */ { AS(linux_sched_getscheduler_args), (sy_call_t *)linux_sched_getscheduler, AUE_SCHED_GETSCHEDULER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 157 = linux_sched_getscheduler */ { 0, (sy_call_t *)sys_sched_yield, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 158 = sched_yield */ { AS(linux_sched_get_priority_max_args), (sy_call_t *)linux_sched_get_priority_max, AUE_SCHED_GET_PRIORITY_MAX, NULL, 0, 0, 0, SY_THR_STATIC }, /* 159 = linux_sched_get_priority_max */ { AS(linux_sched_get_priority_min_args), (sy_call_t *)linux_sched_get_priority_min, AUE_SCHED_GET_PRIORITY_MIN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 160 = linux_sched_get_priority_min */ { AS(linux_sched_rr_get_interval_args), (sy_call_t *)linux_sched_rr_get_interval, AUE_SCHED_RR_GET_INTERVAL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 161 = linux_sched_rr_get_interval */ { AS(linux_nanosleep_args), (sy_call_t *)linux_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 162 = linux_nanosleep */ { AS(linux_mremap_args), (sy_call_t *)linux_mremap, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 163 = linux_mremap */ { AS(linux_setresuid16_args), (sy_call_t *)linux_setresuid16, AUE_SETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 164 = linux_setresuid16 */ { AS(linux_getresuid16_args), (sy_call_t *)linux_getresuid16, AUE_GETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 165 = linux_getresuid16 */ { 0, (sy_call_t *)linux_vm86, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 166 = linux_vm86 */ { 0, (sy_call_t *)linux_query_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 167 = linux_query_module */ { AS(poll_args), (sy_call_t *)sys_poll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 168 = poll */ { 0, (sy_call_t *)linux_nfsservctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 169 = linux_nfsservctl */ { AS(linux_setresgid16_args), (sy_call_t *)linux_setresgid16, AUE_SETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 170 = linux_setresgid16 */ { AS(linux_getresgid16_args), (sy_call_t *)linux_getresgid16, AUE_GETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 171 = linux_getresgid16 */ { AS(linux_prctl_args), (sy_call_t *)linux_prctl, AUE_PRCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 172 = linux_prctl */ { AS(linux_rt_sigreturn_args), (sy_call_t *)linux_rt_sigreturn, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 173 = linux_rt_sigreturn */ { AS(linux_rt_sigaction_args), (sy_call_t *)linux_rt_sigaction, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 174 = linux_rt_sigaction */ { AS(linux_rt_sigprocmask_args), (sy_call_t *)linux_rt_sigprocmask, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 175 = linux_rt_sigprocmask */ { AS(linux_rt_sigpending_args), (sy_call_t *)linux_rt_sigpending, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 176 = linux_rt_sigpending */ { AS(linux_rt_sigtimedwait_args), (sy_call_t *)linux_rt_sigtimedwait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 177 = linux_rt_sigtimedwait */ { AS(linux_rt_sigqueueinfo_args), (sy_call_t *)linux_rt_sigqueueinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 178 = linux_rt_sigqueueinfo */ { AS(linux_rt_sigsuspend_args), (sy_call_t *)linux_rt_sigsuspend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 179 = linux_rt_sigsuspend */ { AS(linux_pread_args), (sy_call_t *)linux_pread, AUE_PREAD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 180 = linux_pread */ { AS(linux_pwrite_args), (sy_call_t *)linux_pwrite, AUE_PWRITE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 181 = linux_pwrite */ { AS(linux_chown16_args), (sy_call_t *)linux_chown16, AUE_CHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 182 = linux_chown16 */ { AS(linux_getcwd_args), (sy_call_t *)linux_getcwd, AUE_GETCWD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 183 = linux_getcwd */ { AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 184 = linux_capget */ { AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 185 = linux_capset */ { AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 186 = linux_sigaltstack */ { 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 187 = linux_sendfile */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 188 = getpmsg */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 189 = putpmsg */ { 0, (sy_call_t *)linux_vfork, AUE_VFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 190 = linux_vfork */ { AS(linux_getrlimit_args), (sy_call_t *)linux_getrlimit, AUE_GETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 191 = linux_getrlimit */ { AS(linux_mmap2_args), (sy_call_t *)linux_mmap2, AUE_MMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 192 = linux_mmap2 */ { AS(linux_truncate64_args), (sy_call_t *)linux_truncate64, AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 193 = linux_truncate64 */ { AS(linux_ftruncate64_args), (sy_call_t *)linux_ftruncate64, AUE_FTRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 194 = linux_ftruncate64 */ { AS(linux_stat64_args), (sy_call_t *)linux_stat64, AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 195 = linux_stat64 */ { AS(linux_lstat64_args), (sy_call_t *)linux_lstat64, AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 196 = linux_lstat64 */ { AS(linux_fstat64_args), (sy_call_t *)linux_fstat64, AUE_FSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 197 = linux_fstat64 */ { AS(linux_lchown_args), (sy_call_t *)linux_lchown, AUE_LCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 198 = linux_lchown */ { 0, (sy_call_t *)linux_getuid, AUE_GETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 199 = linux_getuid */ { 0, (sy_call_t *)linux_getgid, AUE_GETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 200 = linux_getgid */ { 0, (sy_call_t *)sys_geteuid, AUE_GETEUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 201 = geteuid */ { 0, (sy_call_t *)sys_getegid, AUE_GETEGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 202 = getegid */ { AS(setreuid_args), (sy_call_t *)sys_setreuid, AUE_SETREUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 203 = setreuid */ { AS(setregid_args), (sy_call_t *)sys_setregid, AUE_SETREGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 204 = setregid */ { AS(linux_getgroups_args), (sy_call_t *)linux_getgroups, AUE_GETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 205 = linux_getgroups */ { AS(linux_setgroups_args), (sy_call_t *)linux_setgroups, AUE_SETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 206 = linux_setgroups */ { AS(fchown_args), (sy_call_t *)sys_fchown, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 207 = fchown */ { AS(setresuid_args), (sy_call_t *)sys_setresuid, AUE_SETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 208 = setresuid */ { AS(getresuid_args), (sy_call_t *)sys_getresuid, AUE_GETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 209 = getresuid */ { AS(setresgid_args), (sy_call_t *)sys_setresgid, AUE_SETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 210 = setresgid */ { AS(getresgid_args), (sy_call_t *)sys_getresgid, AUE_GETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 211 = getresgid */ { AS(linux_chown_args), (sy_call_t *)linux_chown, AUE_CHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 212 = linux_chown */ { AS(setuid_args), (sy_call_t *)sys_setuid, AUE_SETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 213 = setuid */ { AS(setgid_args), (sy_call_t *)sys_setgid, AUE_SETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 214 = setgid */ { AS(linux_setfsuid_args), (sy_call_t *)linux_setfsuid, AUE_SETFSUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 215 = linux_setfsuid */ { AS(linux_setfsgid_args), (sy_call_t *)linux_setfsgid, AUE_SETFSGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 216 = linux_setfsgid */ { AS(linux_pivot_root_args), (sy_call_t *)linux_pivot_root, AUE_PIVOT_ROOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 217 = linux_pivot_root */ { AS(linux_mincore_args), (sy_call_t *)linux_mincore, AUE_MINCORE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 218 = linux_mincore */ { AS(madvise_args), (sy_call_t *)sys_madvise, AUE_MADVISE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 219 = madvise */ { AS(linux_getdents64_args), (sy_call_t *)linux_getdents64, AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 220 = linux_getdents64 */ { AS(linux_fcntl64_args), (sy_call_t *)linux_fcntl64, AUE_FCNTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 221 = linux_fcntl64 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 222 = */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 223 = */ { 0, (sy_call_t *)linux_gettid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 224 = linux_gettid */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 225 = linux_readahead */ { 0, (sy_call_t *)linux_setxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 226 = linux_setxattr */ { 0, (sy_call_t *)linux_lsetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 227 = linux_lsetxattr */ { 0, (sy_call_t *)linux_fsetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 228 = linux_fsetxattr */ { 0, (sy_call_t *)linux_getxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 229 = linux_getxattr */ { 0, (sy_call_t *)linux_lgetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 230 = linux_lgetxattr */ { 0, (sy_call_t *)linux_fgetxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 231 = linux_fgetxattr */ { 0, (sy_call_t *)linux_listxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 232 = linux_listxattr */ { 0, (sy_call_t *)linux_llistxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 233 = linux_llistxattr */ { 0, (sy_call_t *)linux_flistxattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 234 = linux_flistxattr */ { 0, (sy_call_t *)linux_removexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 235 = linux_removexattr */ { 0, (sy_call_t *)linux_lremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 236 = linux_lremovexattr */ { 0, (sy_call_t *)linux_fremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 237 = linux_fremovexattr */ { AS(linux_tkill_args), (sy_call_t *)linux_tkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 238 = linux_tkill */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 239 = linux_sendfile64 */ { AS(linux_sys_futex_args), (sy_call_t *)linux_sys_futex, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 240 = linux_sys_futex */ { AS(linux_sched_setaffinity_args), (sy_call_t *)linux_sched_setaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 241 = linux_sched_setaffinity */ { AS(linux_sched_getaffinity_args), (sy_call_t *)linux_sched_getaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 242 = linux_sched_getaffinity */ { AS(linux_set_thread_area_args), (sy_call_t *)linux_set_thread_area, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 243 = linux_set_thread_area */ { AS(linux_get_thread_area_args), (sy_call_t *)linux_get_thread_area, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 244 = linux_get_thread_area */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 245 = linux_io_setup */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 246 = linux_io_destroy */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 247 = linux_io_getevents */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 248 = linux_io_submit */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 249 = linux_io_cancel */ { AS(linux_fadvise64_args), (sy_call_t *)linux_fadvise64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 250 = linux_fadvise64 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 251 = */ { AS(linux_exit_group_args), (sy_call_t *)linux_exit_group, AUE_EXIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 252 = linux_exit_group */ { 0, (sy_call_t *)linux_lookup_dcookie, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 253 = linux_lookup_dcookie */ { AS(linux_epoll_create_args), (sy_call_t *)linux_epoll_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 254 = linux_epoll_create */ { AS(linux_epoll_ctl_args), (sy_call_t *)linux_epoll_ctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 255 = linux_epoll_ctl */ { AS(linux_epoll_wait_args), (sy_call_t *)linux_epoll_wait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 256 = linux_epoll_wait */ { 0, (sy_call_t *)linux_remap_file_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 257 = linux_remap_file_pages */ { AS(linux_set_tid_address_args), (sy_call_t *)linux_set_tid_address, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 258 = linux_set_tid_address */ { AS(linux_timer_create_args), (sy_call_t *)linux_timer_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 259 = linux_timer_create */ { AS(linux_timer_settime_args), (sy_call_t *)linux_timer_settime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 260 = linux_timer_settime */ { AS(linux_timer_gettime_args), (sy_call_t *)linux_timer_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 261 = linux_timer_gettime */ { AS(linux_timer_getoverrun_args), (sy_call_t *)linux_timer_getoverrun, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 262 = linux_timer_getoverrun */ { AS(linux_timer_delete_args), (sy_call_t *)linux_timer_delete, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 263 = linux_timer_delete */ { AS(linux_clock_settime_args), (sy_call_t *)linux_clock_settime, AUE_CLOCK_SETTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 264 = linux_clock_settime */ { AS(linux_clock_gettime_args), (sy_call_t *)linux_clock_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 265 = linux_clock_gettime */ { AS(linux_clock_getres_args), (sy_call_t *)linux_clock_getres, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 266 = linux_clock_getres */ { AS(linux_clock_nanosleep_args), (sy_call_t *)linux_clock_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 267 = linux_clock_nanosleep */ { AS(linux_statfs64_args), (sy_call_t *)linux_statfs64, AUE_STATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 268 = linux_statfs64 */ { AS(linux_fstatfs64_args), (sy_call_t *)linux_fstatfs64, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 269 = linux_fstatfs64 */ { AS(linux_tgkill_args), (sy_call_t *)linux_tgkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 270 = linux_tgkill */ { AS(linux_utimes_args), (sy_call_t *)linux_utimes, AUE_UTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 271 = linux_utimes */ { AS(linux_fadvise64_64_args), (sy_call_t *)linux_fadvise64_64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 272 = linux_fadvise64_64 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 273 = vserver */ { 0, (sy_call_t *)linux_mbind, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 274 = linux_mbind */ { 0, (sy_call_t *)linux_get_mempolicy, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 275 = linux_get_mempolicy */ { 0, (sy_call_t *)linux_set_mempolicy, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 276 = linux_set_mempolicy */ { AS(linux_mq_open_args), (sy_call_t *)linux_mq_open, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 277 = linux_mq_open */ { AS(linux_mq_unlink_args), (sy_call_t *)linux_mq_unlink, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 278 = linux_mq_unlink */ { AS(linux_mq_timedsend_args), (sy_call_t *)linux_mq_timedsend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 279 = linux_mq_timedsend */ { AS(linux_mq_timedreceive_args), (sy_call_t *)linux_mq_timedreceive, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 280 = linux_mq_timedreceive */ { AS(linux_mq_notify_args), (sy_call_t *)linux_mq_notify, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 281 = linux_mq_notify */ { AS(linux_mq_getsetattr_args), (sy_call_t *)linux_mq_getsetattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 282 = linux_mq_getsetattr */ { 0, (sy_call_t *)linux_kexec_load, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 283 = linux_kexec_load */ { AS(linux_waitid_args), (sy_call_t *)linux_waitid, AUE_WAIT6, NULL, 0, 0, 0, SY_THR_STATIC }, /* 284 = linux_waitid */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 285 = */ { 0, (sy_call_t *)linux_add_key, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 286 = linux_add_key */ { 0, (sy_call_t *)linux_request_key, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 287 = linux_request_key */ { 0, (sy_call_t *)linux_keyctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 288 = linux_keyctl */ { 0, (sy_call_t *)linux_ioprio_set, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 289 = linux_ioprio_set */ { 0, (sy_call_t *)linux_ioprio_get, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 290 = linux_ioprio_get */ { 0, (sy_call_t *)linux_inotify_init, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 291 = linux_inotify_init */ { 0, (sy_call_t *)linux_inotify_add_watch, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 292 = linux_inotify_add_watch */ { 0, (sy_call_t *)linux_inotify_rm_watch, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 293 = linux_inotify_rm_watch */ { 0, (sy_call_t *)linux_migrate_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 294 = linux_migrate_pages */ { AS(linux_openat_args), (sy_call_t *)linux_openat, AUE_OPEN_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 295 = linux_openat */ { AS(linux_mkdirat_args), (sy_call_t *)linux_mkdirat, AUE_MKDIRAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 296 = linux_mkdirat */ { AS(linux_mknodat_args), (sy_call_t *)linux_mknodat, AUE_MKNODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 297 = linux_mknodat */ { AS(linux_fchownat_args), (sy_call_t *)linux_fchownat, AUE_FCHOWNAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 298 = linux_fchownat */ { AS(linux_futimesat_args), (sy_call_t *)linux_futimesat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 299 = linux_futimesat */ { AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_FSTATAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 300 = linux_fstatat64 */ { AS(linux_unlinkat_args), (sy_call_t *)linux_unlinkat, AUE_UNLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 301 = linux_unlinkat */ { AS(linux_renameat_args), (sy_call_t *)linux_renameat, AUE_RENAMEAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 302 = linux_renameat */ { AS(linux_linkat_args), (sy_call_t *)linux_linkat, AUE_LINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 303 = linux_linkat */ { AS(linux_symlinkat_args), (sy_call_t *)linux_symlinkat, AUE_SYMLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 304 = linux_symlinkat */ { AS(linux_readlinkat_args), (sy_call_t *)linux_readlinkat, AUE_READLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 305 = linux_readlinkat */ { AS(linux_fchmodat_args), (sy_call_t *)linux_fchmodat, AUE_FCHMODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 306 = linux_fchmodat */ { AS(linux_faccessat_args), (sy_call_t *)linux_faccessat, AUE_FACCESSAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 307 = linux_faccessat */ { AS(linux_pselect6_args), (sy_call_t *)linux_pselect6, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 308 = linux_pselect6 */ { AS(linux_ppoll_args), (sy_call_t *)linux_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 309 = linux_ppoll */ { 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 310 = linux_unshare */ { AS(linux_set_robust_list_args), (sy_call_t *)linux_set_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 311 = linux_set_robust_list */ { AS(linux_get_robust_list_args), (sy_call_t *)linux_get_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 312 = linux_get_robust_list */ { 0, (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 313 = linux_splice */ { 0, (sy_call_t *)linux_sync_file_range, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 314 = linux_sync_file_range */ { 0, (sy_call_t *)linux_tee, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 315 = linux_tee */ { 0, (sy_call_t *)linux_vmsplice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 316 = linux_vmsplice */ { 0, (sy_call_t *)linux_move_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 317 = linux_move_pages */ { 0, (sy_call_t *)linux_getcpu, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 318 = linux_getcpu */ { AS(linux_epoll_pwait_args), (sy_call_t *)linux_epoll_pwait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 319 = linux_epoll_pwait */ { AS(linux_utimensat_args), (sy_call_t *)linux_utimensat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 320 = linux_utimensat */ { 0, (sy_call_t *)linux_signalfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 321 = linux_signalfd */ { 0, (sy_call_t *)linux_timerfd_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 322 = linux_timerfd_create */ { AS(linux_eventfd_args), (sy_call_t *)linux_eventfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 323 = linux_eventfd */ { AS(linux_fallocate_args), (sy_call_t *)linux_fallocate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 324 = linux_fallocate */ { 0, (sy_call_t *)linux_timerfd_settime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 325 = linux_timerfd_settime */ { 0, (sy_call_t *)linux_timerfd_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 326 = linux_timerfd_gettime */ { 0, (sy_call_t *)linux_signalfd4, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 327 = linux_signalfd4 */ { AS(linux_eventfd2_args), (sy_call_t *)linux_eventfd2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 328 = linux_eventfd2 */ { AS(linux_epoll_create1_args), (sy_call_t *)linux_epoll_create1, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 329 = linux_epoll_create1 */ { AS(linux_dup3_args), (sy_call_t *)linux_dup3, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 330 = linux_dup3 */ { AS(linux_pipe2_args), (sy_call_t *)linux_pipe2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 331 = linux_pipe2 */ { 0, (sy_call_t *)linux_inotify_init1, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 332 = linux_inotify_init1 */ - { 0, (sy_call_t *)linux_preadv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 333 = linux_preadv */ - { 0, (sy_call_t *)linux_pwritev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 334 = linux_pwritev */ - { 0, (sy_call_t *)linux_rt_tsigqueueinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 335 = linux_rt_tsigqueueinfo */ + { AS(linux_preadv_args), (sy_call_t *)linux_preadv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 333 = linux_preadv */ + { AS(linux_pwritev_args), (sy_call_t *)linux_pwritev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 334 = linux_pwritev */ + { AS(linux_rt_tgsigqueueinfo_args), (sy_call_t *)linux_rt_tgsigqueueinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 335 = linux_rt_tgsigqueueinfo */ { 0, (sy_call_t *)linux_perf_event_open, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 336 = linux_perf_event_open */ { AS(linux_recvmmsg_args), (sy_call_t *)linux_recvmmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 337 = linux_recvmmsg */ { 0, (sy_call_t *)linux_fanotify_init, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 338 = linux_fanotify_init */ { 0, (sy_call_t *)linux_fanotify_mark, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 339 = linux_fanotify_mark */ { AS(linux_prlimit64_args), (sy_call_t *)linux_prlimit64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 340 = linux_prlimit64 */ { 0, (sy_call_t *)linux_name_to_handle_at, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 341 = linux_name_to_handle_at */ { 0, (sy_call_t *)linux_open_by_handle_at, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 342 = linux_open_by_handle_at */ { 0, (sy_call_t *)linux_clock_adjtime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 343 = linux_clock_adjtime */ { AS(linux_syncfs_args), (sy_call_t *)linux_syncfs, AUE_SYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 344 = linux_syncfs */ { AS(linux_sendmmsg_args), (sy_call_t *)linux_sendmmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 345 = linux_sendmmsg */ { 0, (sy_call_t *)linux_setns, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 346 = linux_setns */ - { 0, (sy_call_t *)linux_process_vm_readv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 347 = linux_process_vm_readv */ - { 0, (sy_call_t *)linux_process_vm_writev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 348 = linux_process_vm_writev */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 349 = nosys */ + { AS(linux_process_vm_readv_args), (sy_call_t *)linux_process_vm_readv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 347 = linux_process_vm_readv */ + { AS(linux_process_vm_writev_args), (sy_call_t *)linux_process_vm_writev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 348 = linux_process_vm_writev */ + { AS(linux_kcmp_args), (sy_call_t *)linux_kcmp, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 349 = linux_kcmp */ + { AS(linux_finit_module_args), (sy_call_t *)linux_finit_module, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 350 = linux_finit_module */ + { AS(linux_sched_setattr_args), (sy_call_t *)linux_sched_setattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 351 = linux_sched_setattr */ + { AS(linux_sched_getattr_args), (sy_call_t *)linux_sched_getattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 352 = linux_sched_getattr */ + { AS(linux_renameat2_args), (sy_call_t *)linux_renameat2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 353 = linux_renameat2 */ + { AS(linux_seccomp_args), (sy_call_t *)linux_seccomp, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 354 = linux_seccomp */ + { AS(linux_getrandom_args), (sy_call_t *)linux_getrandom, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 355 = linux_getrandom */ + { AS(linux_memfd_create_args), (sy_call_t *)linux_memfd_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 356 = linux_memfd_create */ + { AS(linux_bpf_args), (sy_call_t *)linux_bpf, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 357 = linux_bpf */ + { AS(linux_execveat_args), (sy_call_t *)linux_execveat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 358 = linux_execveat */ + { AS(linux_socket_args), (sy_call_t *)linux_socket, AUE_SOCKET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 359 = linux_socket */ + { AS(linux_socketpair_args), (sy_call_t *)linux_socketpair, AUE_SOCKETPAIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 360 = linux_socketpair */ + { AS(linux_bind_args), (sy_call_t *)linux_bind, AUE_BIND, NULL, 0, 0, 0, SY_THR_STATIC }, /* 361 = linux_bind */ + { AS(linux_connect_args), (sy_call_t *)linux_connect, AUE_CONNECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 362 = linux_connect */ + { AS(linux_listen_args), (sy_call_t *)linux_listen, AUE_LISTEN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 363 = linux_listen */ + { AS(linux_accept4_args), (sy_call_t *)linux_accept4, AUE_ACCEPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 364 = linux_accept4 */ + { AS(linux_getsockopt_args), (sy_call_t *)linux_getsockopt, AUE_GETSOCKOPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 365 = linux_getsockopt */ + { AS(linux_setsockopt_args), (sy_call_t *)linux_setsockopt, AUE_SETSOCKOPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 366 = linux_setsockopt */ + { AS(linux_getsockname_args), (sy_call_t *)linux_getsockname, AUE_GETSOCKNAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 367 = linux_getsockname */ + { AS(linux_getpeername_args), (sy_call_t *)linux_getpeername, AUE_GETPEERNAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 368 = linux_getpeername */ + { AS(linux_sendto_args), (sy_call_t *)linux_sendto, AUE_SENDTO, NULL, 0, 0, 0, SY_THR_STATIC }, /* 369 = linux_sendto */ + { AS(linux_sendmsg_args), (sy_call_t *)linux_sendmsg, AUE_SENDMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 370 = linux_sendmsg */ + { AS(linux_recvfrom_args), (sy_call_t *)linux_recvfrom, AUE_RECVFROM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 371 = linux_recvfrom */ + { AS(linux_recvmsg_args), (sy_call_t *)linux_recvmsg, AUE_RECVMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 372 = linux_recvmsg */ + { AS(linux_shutdown_args), (sy_call_t *)linux_shutdown, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 373 = linux_shutdown */ + { AS(linux_userfaultfd_args), (sy_call_t *)linux_userfaultfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 374 = linux_userfaultfd */ + { AS(linux_membarrier_args), (sy_call_t *)linux_membarrier, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 375 = linux_membarrier */ + { AS(linux_mlock2_args), (sy_call_t *)linux_mlock2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 376 = linux_mlock2 */ + { AS(linux_copy_file_range_args), (sy_call_t *)linux_copy_file_range, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 377 = linux_copy_file_range */ + { AS(linux_preadv2_args), (sy_call_t *)linux_preadv2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 378 = linux_preadv2 */ + { AS(linux_pwritev2_args), (sy_call_t *)linux_pwritev2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 379 = linux_pwritev2 */ + { AS(linux_pkey_mprotect_args), (sy_call_t *)linux_pkey_mprotect, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 380 = linux_pkey_mprotect */ + { AS(linux_pkey_alloc_args), (sy_call_t *)linux_pkey_alloc, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 381 = linux_pkey_alloc */ + { AS(linux_pkey_free_args), (sy_call_t *)linux_pkey_free, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 382 = linux_pkey_free */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 383 = nosys */ }; Index: projects/ipsec/sys/i386/linux/linux_systrace_args.c =================================================================== --- projects/ipsec/sys/i386/linux/linux_systrace_args.c (revision 313312) +++ projects/ipsec/sys/i386/linux/linux_systrace_args.c (revision 313313) @@ -1,7437 +1,8681 @@ /* * System call argument to DTrace register array converstion. * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ * This file is part of the DTrace syscall provider. */ static void systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) { int64_t *iarg = (int64_t *) uarg; switch (sysnum) { #define nosys linux_nosys /* linux_exit */ case 1: { struct linux_exit_args *p = params; iarg[0] = p->rval; /* int */ *n_args = 1; break; } /* linux_fork */ case 2: { *n_args = 0; break; } /* read */ case 3: { struct read_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->buf; /* char * */ uarg[2] = p->nbyte; /* u_int */ *n_args = 3; break; } /* write */ case 4: { struct write_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->buf; /* char * */ uarg[2] = p->nbyte; /* u_int */ *n_args = 3; break; } /* linux_open */ case 5: { struct linux_open_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->flags; /* l_int */ iarg[2] = p->mode; /* l_int */ *n_args = 3; break; } /* close */ case 6: { struct close_args *p = params; iarg[0] = p->fd; /* int */ *n_args = 1; break; } /* linux_waitpid */ case 7: { struct linux_waitpid_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->status; /* l_int * */ iarg[2] = p->options; /* l_int */ *n_args = 3; break; } /* linux_creat */ case 8: { struct linux_creat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_int */ *n_args = 2; break; } /* linux_link */ case 9: { struct linux_link_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->to; /* char * */ *n_args = 2; break; } /* linux_unlink */ case 10: { struct linux_unlink_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_execve */ case 11: { struct linux_execve_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->argp; /* char ** */ uarg[2] = (intptr_t) p->envp; /* char ** */ *n_args = 3; break; } /* linux_chdir */ case 12: { struct linux_chdir_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_time */ case 13: { struct linux_time_args *p = params; uarg[0] = (intptr_t) p->tm; /* l_time_t * */ *n_args = 1; break; } /* linux_mknod */ case 14: { struct linux_mknod_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_int */ iarg[2] = p->dev; /* l_dev_t */ *n_args = 3; break; } /* linux_chmod */ case 15: { struct linux_chmod_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_mode_t */ *n_args = 2; break; } /* linux_lchown16 */ case 16: { struct linux_lchown16_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid16_t */ iarg[2] = p->gid; /* l_gid16_t */ *n_args = 3; break; } /* linux_stat */ case 18: { struct linux_stat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->up; /* struct linux_stat * */ *n_args = 2; break; } /* linux_lseek */ case 19: { struct linux_lseek_args *p = params; iarg[0] = p->fdes; /* l_uint */ iarg[1] = p->off; /* l_off_t */ iarg[2] = p->whence; /* l_int */ *n_args = 3; break; } /* linux_getpid */ case 20: { *n_args = 0; break; } /* linux_mount */ case 21: { struct linux_mount_args *p = params; uarg[0] = (intptr_t) p->specialfile; /* char * */ uarg[1] = (intptr_t) p->dir; /* char * */ uarg[2] = (intptr_t) p->filesystemtype; /* char * */ iarg[3] = p->rwflag; /* l_ulong */ uarg[4] = (intptr_t) p->data; /* void * */ *n_args = 5; break; } /* linux_oldumount */ case 22: { struct linux_oldumount_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_setuid16 */ case 23: { struct linux_setuid16_args *p = params; iarg[0] = p->uid; /* l_uid16_t */ *n_args = 1; break; } /* linux_getuid16 */ case 24: { *n_args = 0; break; } /* linux_stime */ case 25: { *n_args = 0; break; } /* linux_ptrace */ case 26: { struct linux_ptrace_args *p = params; iarg[0] = p->req; /* l_long */ iarg[1] = p->pid; /* l_long */ iarg[2] = p->addr; /* l_long */ iarg[3] = p->data; /* l_long */ *n_args = 4; break; } /* linux_alarm */ case 27: { struct linux_alarm_args *p = params; iarg[0] = p->secs; /* l_uint */ *n_args = 1; break; } /* linux_fstat */ case 28: { struct linux_fstat_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->up; /* struct linux_stat * */ *n_args = 2; break; } /* linux_pause */ case 29: { *n_args = 0; break; } /* linux_utime */ case 30: { struct linux_utime_args *p = params; uarg[0] = (intptr_t) p->fname; /* char * */ uarg[1] = (intptr_t) p->times; /* struct l_utimbuf * */ *n_args = 2; break; } /* linux_access */ case 33: { struct linux_access_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->amode; /* l_int */ *n_args = 2; break; } /* linux_nice */ case 34: { struct linux_nice_args *p = params; iarg[0] = p->inc; /* l_int */ *n_args = 1; break; } /* sync */ case 36: { *n_args = 0; break; } /* linux_kill */ case 37: { struct linux_kill_args *p = params; iarg[0] = p->pid; /* l_int */ iarg[1] = p->signum; /* l_int */ *n_args = 2; break; } /* linux_rename */ case 38: { struct linux_rename_args *p = params; uarg[0] = (intptr_t) p->from; /* char * */ uarg[1] = (intptr_t) p->to; /* char * */ *n_args = 2; break; } /* linux_mkdir */ case 39: { struct linux_mkdir_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->mode; /* l_int */ *n_args = 2; break; } /* linux_rmdir */ case 40: { struct linux_rmdir_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* dup */ case 41: { struct dup_args *p = params; uarg[0] = p->fd; /* u_int */ *n_args = 1; break; } /* linux_pipe */ case 42: { struct linux_pipe_args *p = params; uarg[0] = (intptr_t) p->pipefds; /* l_int * */ *n_args = 1; break; } /* linux_times */ case 43: { struct linux_times_args *p = params; uarg[0] = (intptr_t) p->buf; /* struct l_times_argv * */ *n_args = 1; break; } /* linux_brk */ case 45: { struct linux_brk_args *p = params; iarg[0] = p->dsend; /* l_ulong */ *n_args = 1; break; } /* linux_setgid16 */ case 46: { struct linux_setgid16_args *p = params; iarg[0] = p->gid; /* l_gid16_t */ *n_args = 1; break; } /* linux_getgid16 */ case 47: { *n_args = 0; break; } /* linux_signal */ case 48: { struct linux_signal_args *p = params; iarg[0] = p->sig; /* l_int */ uarg[1] = (intptr_t) p->handler; /* void * */ *n_args = 2; break; } /* linux_geteuid16 */ case 49: { *n_args = 0; break; } /* linux_getegid16 */ case 50: { *n_args = 0; break; } /* acct */ case 51: { struct acct_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_umount */ case 52: { struct linux_umount_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->flags; /* l_int */ *n_args = 2; break; } /* linux_ioctl */ case 54: { struct linux_ioctl_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->cmd; /* l_uint */ iarg[2] = p->arg; /* l_ulong */ *n_args = 3; break; } /* linux_fcntl */ case 55: { struct linux_fcntl_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->cmd; /* l_uint */ iarg[2] = p->arg; /* l_ulong */ *n_args = 3; break; } /* setpgid */ case 57: { struct setpgid_args *p = params; iarg[0] = p->pid; /* int */ iarg[1] = p->pgid; /* int */ *n_args = 2; break; } /* linux_olduname */ case 59: { *n_args = 0; break; } /* umask */ case 60: { struct umask_args *p = params; iarg[0] = p->newmask; /* int */ *n_args = 1; break; } /* chroot */ case 61: { struct chroot_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ *n_args = 1; break; } /* linux_ustat */ case 62: { struct linux_ustat_args *p = params; iarg[0] = p->dev; /* l_dev_t */ uarg[1] = (intptr_t) p->ubuf; /* struct l_ustat * */ *n_args = 2; break; } /* dup2 */ case 63: { struct dup2_args *p = params; uarg[0] = p->from; /* u_int */ uarg[1] = p->to; /* u_int */ *n_args = 2; break; } /* linux_getppid */ case 64: { *n_args = 0; break; } /* getpgrp */ case 65: { *n_args = 0; break; } /* setsid */ case 66: { *n_args = 0; break; } /* linux_sigaction */ case 67: { struct linux_sigaction_args *p = params; iarg[0] = p->sig; /* l_int */ uarg[1] = (intptr_t) p->nsa; /* l_osigaction_t * */ uarg[2] = (intptr_t) p->osa; /* l_osigaction_t * */ *n_args = 3; break; } /* linux_sgetmask */ case 68: { *n_args = 0; break; } /* linux_ssetmask */ case 69: { struct linux_ssetmask_args *p = params; iarg[0] = p->mask; /* l_osigset_t */ *n_args = 1; break; } /* linux_setreuid16 */ case 70: { struct linux_setreuid16_args *p = params; iarg[0] = p->ruid; /* l_uid16_t */ iarg[1] = p->euid; /* l_uid16_t */ *n_args = 2; break; } /* linux_setregid16 */ case 71: { struct linux_setregid16_args *p = params; iarg[0] = p->rgid; /* l_gid16_t */ iarg[1] = p->egid; /* l_gid16_t */ *n_args = 2; break; } /* linux_sigsuspend */ case 72: { struct linux_sigsuspend_args *p = params; iarg[0] = p->hist0; /* l_int */ iarg[1] = p->hist1; /* l_int */ iarg[2] = p->mask; /* l_osigset_t */ *n_args = 3; break; } /* linux_sigpending */ case 73: { struct linux_sigpending_args *p = params; uarg[0] = (intptr_t) p->mask; /* l_osigset_t * */ *n_args = 1; break; } /* linux_sethostname */ case 74: { struct linux_sethostname_args *p = params; uarg[0] = (intptr_t) p->hostname; /* char * */ uarg[1] = p->len; /* u_int */ *n_args = 2; break; } /* linux_setrlimit */ case 75: { struct linux_setrlimit_args *p = params; iarg[0] = p->resource; /* l_uint */ uarg[1] = (intptr_t) p->rlim; /* struct l_rlimit * */ *n_args = 2; break; } /* linux_old_getrlimit */ case 76: { struct linux_old_getrlimit_args *p = params; iarg[0] = p->resource; /* l_uint */ uarg[1] = (intptr_t) p->rlim; /* struct l_rlimit * */ *n_args = 2; break; } /* getrusage */ case 77: { struct getrusage_args *p = params; iarg[0] = p->who; /* int */ uarg[1] = (intptr_t) p->rusage; /* struct rusage * */ *n_args = 2; break; } /* gettimeofday */ case 78: { struct gettimeofday_args *p = params; uarg[0] = (intptr_t) p->tp; /* struct timeval * */ uarg[1] = (intptr_t) p->tzp; /* struct timezone * */ *n_args = 2; break; } /* settimeofday */ case 79: { struct settimeofday_args *p = params; uarg[0] = (intptr_t) p->tv; /* struct timeval * */ uarg[1] = (intptr_t) p->tzp; /* struct timezone * */ *n_args = 2; break; } /* linux_getgroups16 */ case 80: { struct linux_getgroups16_args *p = params; iarg[0] = p->gidsetsize; /* l_uint */ uarg[1] = (intptr_t) p->gidset; /* l_gid16_t * */ *n_args = 2; break; } /* linux_setgroups16 */ case 81: { struct linux_setgroups16_args *p = params; iarg[0] = p->gidsetsize; /* l_uint */ uarg[1] = (intptr_t) p->gidset; /* l_gid16_t * */ *n_args = 2; break; } /* linux_old_select */ case 82: { struct linux_old_select_args *p = params; uarg[0] = (intptr_t) p->ptr; /* struct l_old_select_argv * */ *n_args = 1; break; } /* linux_symlink */ case 83: { struct linux_symlink_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->to; /* char * */ *n_args = 2; break; } /* linux_lstat */ case 84: { struct linux_lstat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->up; /* struct l_stat * */ *n_args = 2; break; } /* linux_readlink */ case 85: { struct linux_readlink_args *p = params; uarg[0] = (intptr_t) p->name; /* char * */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->count; /* l_int */ *n_args = 3; break; } /* linux_uselib */ case 86: { struct linux_uselib_args *p = params; uarg[0] = (intptr_t) p->library; /* char * */ *n_args = 1; break; } /* swapon */ case 87: { struct swapon_args *p = params; uarg[0] = (intptr_t) p->name; /* char * */ *n_args = 1; break; } /* linux_reboot */ case 88: { struct linux_reboot_args *p = params; iarg[0] = p->magic1; /* l_int */ iarg[1] = p->magic2; /* l_int */ iarg[2] = p->cmd; /* l_uint */ uarg[3] = (intptr_t) p->arg; /* void * */ *n_args = 4; break; } /* linux_readdir */ case 89: { struct linux_readdir_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->dent; /* struct l_dirent * */ iarg[2] = p->count; /* l_uint */ *n_args = 3; break; } /* linux_mmap */ case 90: { struct linux_mmap_args *p = params; uarg[0] = (intptr_t) p->ptr; /* struct l_mmap_argv * */ *n_args = 1; break; } /* munmap */ case 91: { struct munmap_args *p = params; uarg[0] = (intptr_t) p->addr; /* caddr_t */ iarg[1] = p->len; /* int */ *n_args = 2; break; } /* linux_truncate */ case 92: { struct linux_truncate_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->length; /* l_ulong */ *n_args = 2; break; } /* linux_ftruncate */ case 93: { struct linux_ftruncate_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->length; /* long */ *n_args = 2; break; } /* fchmod */ case 94: { struct fchmod_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->mode; /* int */ *n_args = 2; break; } /* fchown */ case 95: { struct fchown_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->uid; /* int */ iarg[2] = p->gid; /* int */ *n_args = 3; break; } /* linux_getpriority */ case 96: { struct linux_getpriority_args *p = params; iarg[0] = p->which; /* int */ iarg[1] = p->who; /* int */ *n_args = 2; break; } /* setpriority */ case 97: { struct setpriority_args *p = params; iarg[0] = p->which; /* int */ iarg[1] = p->who; /* int */ iarg[2] = p->prio; /* int */ *n_args = 3; break; } /* linux_statfs */ case 99: { struct linux_statfs_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->buf; /* struct l_statfs_buf * */ *n_args = 2; break; } /* linux_fstatfs */ case 100: { struct linux_fstatfs_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* struct l_statfs_buf * */ *n_args = 2; break; } /* linux_ioperm */ case 101: { struct linux_ioperm_args *p = params; iarg[0] = p->start; /* l_ulong */ iarg[1] = p->length; /* l_ulong */ iarg[2] = p->enable; /* l_int */ *n_args = 3; break; } /* linux_socketcall */ case 102: { struct linux_socketcall_args *p = params; iarg[0] = p->what; /* l_int */ iarg[1] = p->args; /* l_ulong */ *n_args = 2; break; } /* linux_syslog */ case 103: { struct linux_syslog_args *p = params; iarg[0] = p->type; /* l_int */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->len; /* l_int */ *n_args = 3; break; } /* linux_setitimer */ case 104: { struct linux_setitimer_args *p = params; iarg[0] = p->which; /* l_int */ uarg[1] = (intptr_t) p->itv; /* struct l_itimerval * */ uarg[2] = (intptr_t) p->oitv; /* struct l_itimerval * */ *n_args = 3; break; } /* linux_getitimer */ case 105: { struct linux_getitimer_args *p = params; iarg[0] = p->which; /* l_int */ uarg[1] = (intptr_t) p->itv; /* struct l_itimerval * */ *n_args = 2; break; } /* linux_newstat */ case 106: { struct linux_newstat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->buf; /* struct l_newstat * */ *n_args = 2; break; } /* linux_newlstat */ case 107: { struct linux_newlstat_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = (intptr_t) p->buf; /* struct l_newstat * */ *n_args = 2; break; } /* linux_newfstat */ case 108: { struct linux_newfstat_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* struct l_newstat * */ *n_args = 2; break; } /* linux_uname */ case 109: { *n_args = 0; break; } /* linux_iopl */ case 110: { struct linux_iopl_args *p = params; iarg[0] = p->level; /* l_int */ *n_args = 1; break; } /* linux_vhangup */ case 111: { *n_args = 0; break; } /* linux_vm86old */ case 113: { *n_args = 0; break; } /* linux_wait4 */ case 114: { struct linux_wait4_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->status; /* l_int * */ iarg[2] = p->options; /* l_int */ uarg[3] = (intptr_t) p->rusage; /* void * */ *n_args = 4; break; } /* linux_swapoff */ case 115: { *n_args = 0; break; } /* linux_sysinfo */ case 116: { struct linux_sysinfo_args *p = params; uarg[0] = (intptr_t) p->info; /* struct l_sysinfo * */ *n_args = 1; break; } /* linux_ipc */ case 117: { struct linux_ipc_args *p = params; iarg[0] = p->what; /* l_uint */ iarg[1] = p->arg1; /* l_int */ iarg[2] = p->arg2; /* l_int */ iarg[3] = p->arg3; /* l_int */ uarg[4] = (intptr_t) p->ptr; /* void * */ iarg[5] = p->arg5; /* l_long */ *n_args = 6; break; } /* fsync */ case 118: { struct fsync_args *p = params; iarg[0] = p->fd; /* int */ *n_args = 1; break; } /* linux_sigreturn */ case 119: { struct linux_sigreturn_args *p = params; uarg[0] = (intptr_t) p->sfp; /* struct l_sigframe * */ *n_args = 1; break; } /* linux_clone */ case 120: { struct linux_clone_args *p = params; iarg[0] = p->flags; /* l_int */ uarg[1] = (intptr_t) p->stack; /* void * */ uarg[2] = (intptr_t) p->parent_tidptr; /* void * */ uarg[3] = (intptr_t) p->tls; /* void * */ uarg[4] = (intptr_t) p->child_tidptr; /* void * */ *n_args = 5; break; } /* linux_setdomainname */ case 121: { struct linux_setdomainname_args *p = params; uarg[0] = (intptr_t) p->name; /* char * */ iarg[1] = p->len; /* int */ *n_args = 2; break; } /* linux_newuname */ case 122: { struct linux_newuname_args *p = params; uarg[0] = (intptr_t) p->buf; /* struct l_new_utsname * */ *n_args = 1; break; } /* linux_modify_ldt */ case 123: { struct linux_modify_ldt_args *p = params; iarg[0] = p->func; /* l_int */ uarg[1] = (intptr_t) p->ptr; /* void * */ iarg[2] = p->bytecount; /* l_ulong */ *n_args = 3; break; } /* linux_adjtimex */ case 124: { *n_args = 0; break; } /* linux_mprotect */ case 125: { struct linux_mprotect_args *p = params; uarg[0] = (intptr_t) p->addr; /* caddr_t */ iarg[1] = p->len; /* int */ iarg[2] = p->prot; /* int */ *n_args = 3; break; } /* linux_sigprocmask */ case 126: { struct linux_sigprocmask_args *p = params; iarg[0] = p->how; /* l_int */ uarg[1] = (intptr_t) p->mask; /* l_osigset_t * */ uarg[2] = (intptr_t) p->omask; /* l_osigset_t * */ *n_args = 3; break; } /* linux_create_module */ case 127: { *n_args = 0; break; } /* linux_init_module */ case 128: { *n_args = 0; break; } /* linux_delete_module */ case 129: { *n_args = 0; break; } /* linux_get_kernel_syms */ case 130: { *n_args = 0; break; } /* linux_quotactl */ case 131: { *n_args = 0; break; } /* getpgid */ case 132: { struct getpgid_args *p = params; iarg[0] = p->pid; /* int */ *n_args = 1; break; } /* fchdir */ case 133: { struct fchdir_args *p = params; iarg[0] = p->fd; /* int */ *n_args = 1; break; } /* linux_bdflush */ case 134: { *n_args = 0; break; } /* linux_sysfs */ case 135: { struct linux_sysfs_args *p = params; iarg[0] = p->option; /* l_int */ iarg[1] = p->arg1; /* l_ulong */ iarg[2] = p->arg2; /* l_ulong */ *n_args = 3; break; } /* linux_personality */ case 136: { struct linux_personality_args *p = params; iarg[0] = p->per; /* l_uint */ *n_args = 1; break; } /* linux_setfsuid16 */ case 138: { struct linux_setfsuid16_args *p = params; iarg[0] = p->uid; /* l_uid16_t */ *n_args = 1; break; } /* linux_setfsgid16 */ case 139: { struct linux_setfsgid16_args *p = params; iarg[0] = p->gid; /* l_gid16_t */ *n_args = 1; break; } /* linux_llseek */ case 140: { struct linux_llseek_args *p = params; iarg[0] = p->fd; /* l_int */ iarg[1] = p->ohigh; /* l_ulong */ iarg[2] = p->olow; /* l_ulong */ uarg[3] = (intptr_t) p->res; /* l_loff_t * */ iarg[4] = p->whence; /* l_uint */ *n_args = 5; break; } /* linux_getdents */ case 141: { struct linux_getdents_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->dent; /* void * */ iarg[2] = p->count; /* l_uint */ *n_args = 3; break; } /* linux_select */ case 142: { struct linux_select_args *p = params; iarg[0] = p->nfds; /* l_int */ uarg[1] = (intptr_t) p->readfds; /* l_fd_set * */ uarg[2] = (intptr_t) p->writefds; /* l_fd_set * */ uarg[3] = (intptr_t) p->exceptfds; /* l_fd_set * */ uarg[4] = (intptr_t) p->timeout; /* struct l_timeval * */ *n_args = 5; break; } /* flock */ case 143: { struct flock_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->how; /* int */ *n_args = 2; break; } /* linux_msync */ case 144: { struct linux_msync_args *p = params; iarg[0] = p->addr; /* l_ulong */ iarg[1] = p->len; /* l_size_t */ iarg[2] = p->fl; /* l_int */ *n_args = 3; break; } /* readv */ case 145: { struct readv_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->iovp; /* struct iovec * */ uarg[2] = p->iovcnt; /* u_int */ *n_args = 3; break; } /* writev */ case 146: { struct writev_args *p = params; iarg[0] = p->fd; /* int */ uarg[1] = (intptr_t) p->iovp; /* struct iovec * */ uarg[2] = p->iovcnt; /* u_int */ *n_args = 3; break; } /* linux_getsid */ case 147: { struct linux_getsid_args *p = params; iarg[0] = p->pid; /* l_pid_t */ *n_args = 1; break; } /* linux_fdatasync */ case 148: { struct linux_fdatasync_args *p = params; iarg[0] = p->fd; /* l_uint */ *n_args = 1; break; } /* linux_sysctl */ case 149: { struct linux_sysctl_args *p = params; uarg[0] = (intptr_t) p->args; /* struct l___sysctl_args * */ *n_args = 1; break; } /* mlock */ case 150: { struct mlock_args *p = params; uarg[0] = (intptr_t) p->addr; /* const void * */ uarg[1] = p->len; /* size_t */ *n_args = 2; break; } /* munlock */ case 151: { struct munlock_args *p = params; uarg[0] = (intptr_t) p->addr; /* const void * */ uarg[1] = p->len; /* size_t */ *n_args = 2; break; } /* mlockall */ case 152: { struct mlockall_args *p = params; iarg[0] = p->how; /* int */ *n_args = 1; break; } /* munlockall */ case 153: { *n_args = 0; break; } /* linux_sched_setparam */ case 154: { struct linux_sched_setparam_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->param; /* struct sched_param * */ *n_args = 2; break; } /* linux_sched_getparam */ case 155: { struct linux_sched_getparam_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->param; /* struct sched_param * */ *n_args = 2; break; } /* linux_sched_setscheduler */ case 156: { struct linux_sched_setscheduler_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->policy; /* l_int */ uarg[2] = (intptr_t) p->param; /* struct sched_param * */ *n_args = 3; break; } /* linux_sched_getscheduler */ case 157: { struct linux_sched_getscheduler_args *p = params; iarg[0] = p->pid; /* l_pid_t */ *n_args = 1; break; } /* sched_yield */ case 158: { *n_args = 0; break; } /* linux_sched_get_priority_max */ case 159: { struct linux_sched_get_priority_max_args *p = params; iarg[0] = p->policy; /* l_int */ *n_args = 1; break; } /* linux_sched_get_priority_min */ case 160: { struct linux_sched_get_priority_min_args *p = params; iarg[0] = p->policy; /* l_int */ *n_args = 1; break; } /* linux_sched_rr_get_interval */ case 161: { struct linux_sched_rr_get_interval_args *p = params; iarg[0] = p->pid; /* l_pid_t */ uarg[1] = (intptr_t) p->interval; /* struct l_timespec * */ *n_args = 2; break; } /* linux_nanosleep */ case 162: { struct linux_nanosleep_args *p = params; uarg[0] = (intptr_t) p->rqtp; /* const struct l_timespec * */ uarg[1] = (intptr_t) p->rmtp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_mremap */ case 163: { struct linux_mremap_args *p = params; iarg[0] = p->addr; /* l_ulong */ iarg[1] = p->old_len; /* l_ulong */ iarg[2] = p->new_len; /* l_ulong */ iarg[3] = p->flags; /* l_ulong */ iarg[4] = p->new_addr; /* l_ulong */ *n_args = 5; break; } /* linux_setresuid16 */ case 164: { struct linux_setresuid16_args *p = params; iarg[0] = p->ruid; /* l_uid16_t */ iarg[1] = p->euid; /* l_uid16_t */ iarg[2] = p->suid; /* l_uid16_t */ *n_args = 3; break; } /* linux_getresuid16 */ case 165: { struct linux_getresuid16_args *p = params; uarg[0] = (intptr_t) p->ruid; /* l_uid16_t * */ uarg[1] = (intptr_t) p->euid; /* l_uid16_t * */ uarg[2] = (intptr_t) p->suid; /* l_uid16_t * */ *n_args = 3; break; } /* linux_vm86 */ case 166: { *n_args = 0; break; } /* linux_query_module */ case 167: { *n_args = 0; break; } /* poll */ case 168: { struct poll_args *p = params; uarg[0] = (intptr_t) p->fds; /* struct pollfd * */ uarg[1] = p->nfds; /* unsigned int */ iarg[2] = p->timeout; /* long */ *n_args = 3; break; } /* linux_nfsservctl */ case 169: { *n_args = 0; break; } /* linux_setresgid16 */ case 170: { struct linux_setresgid16_args *p = params; iarg[0] = p->rgid; /* l_gid16_t */ iarg[1] = p->egid; /* l_gid16_t */ iarg[2] = p->sgid; /* l_gid16_t */ *n_args = 3; break; } /* linux_getresgid16 */ case 171: { struct linux_getresgid16_args *p = params; uarg[0] = (intptr_t) p->rgid; /* l_gid16_t * */ uarg[1] = (intptr_t) p->egid; /* l_gid16_t * */ uarg[2] = (intptr_t) p->sgid; /* l_gid16_t * */ *n_args = 3; break; } /* linux_prctl */ case 172: { struct linux_prctl_args *p = params; iarg[0] = p->option; /* l_int */ iarg[1] = p->arg2; /* l_int */ iarg[2] = p->arg3; /* l_int */ iarg[3] = p->arg4; /* l_int */ iarg[4] = p->arg5; /* l_int */ *n_args = 5; break; } /* linux_rt_sigreturn */ case 173: { struct linux_rt_sigreturn_args *p = params; uarg[0] = (intptr_t) p->ucp; /* struct l_ucontext * */ *n_args = 1; break; } /* linux_rt_sigaction */ case 174: { struct linux_rt_sigaction_args *p = params; iarg[0] = p->sig; /* l_int */ uarg[1] = (intptr_t) p->act; /* l_sigaction_t * */ uarg[2] = (intptr_t) p->oact; /* l_sigaction_t * */ iarg[3] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; } /* linux_rt_sigprocmask */ case 175: { struct linux_rt_sigprocmask_args *p = params; iarg[0] = p->how; /* l_int */ uarg[1] = (intptr_t) p->mask; /* l_sigset_t * */ uarg[2] = (intptr_t) p->omask; /* l_sigset_t * */ iarg[3] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; } /* linux_rt_sigpending */ case 176: { struct linux_rt_sigpending_args *p = params; uarg[0] = (intptr_t) p->set; /* l_sigset_t * */ iarg[1] = p->sigsetsize; /* l_size_t */ *n_args = 2; break; } /* linux_rt_sigtimedwait */ case 177: { struct linux_rt_sigtimedwait_args *p = params; uarg[0] = (intptr_t) p->mask; /* l_sigset_t * */ uarg[1] = (intptr_t) p->ptr; /* l_siginfo_t * */ uarg[2] = (intptr_t) p->timeout; /* struct l_timeval * */ iarg[3] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; } /* linux_rt_sigqueueinfo */ case 178: { struct linux_rt_sigqueueinfo_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->sig; /* l_int */ uarg[2] = (intptr_t) p->info; /* l_siginfo_t * */ *n_args = 3; break; } /* linux_rt_sigsuspend */ case 179: { struct linux_rt_sigsuspend_args *p = params; uarg[0] = (intptr_t) p->newset; /* l_sigset_t * */ iarg[1] = p->sigsetsize; /* l_size_t */ *n_args = 2; break; } /* linux_pread */ case 180: { struct linux_pread_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->nbyte; /* l_size_t */ iarg[3] = p->offset; /* l_loff_t */ *n_args = 4; break; } /* linux_pwrite */ case 181: { struct linux_pwrite_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->buf; /* char * */ iarg[2] = p->nbyte; /* l_size_t */ iarg[3] = p->offset; /* l_loff_t */ *n_args = 4; break; } /* linux_chown16 */ case 182: { struct linux_chown16_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid16_t */ iarg[2] = p->gid; /* l_gid16_t */ *n_args = 3; break; } /* linux_getcwd */ case 183: { struct linux_getcwd_args *p = params; uarg[0] = (intptr_t) p->buf; /* char * */ iarg[1] = p->bufsize; /* l_ulong */ *n_args = 2; break; } /* linux_capget */ case 184: { struct linux_capget_args *p = params; uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */ uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */ *n_args = 2; break; } /* linux_capset */ case 185: { struct linux_capset_args *p = params; uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */ uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */ *n_args = 2; break; } /* linux_sigaltstack */ case 186: { struct linux_sigaltstack_args *p = params; uarg[0] = (intptr_t) p->uss; /* l_stack_t * */ uarg[1] = (intptr_t) p->uoss; /* l_stack_t * */ *n_args = 2; break; } /* linux_sendfile */ case 187: { *n_args = 0; break; } /* linux_vfork */ case 190: { *n_args = 0; break; } /* linux_getrlimit */ case 191: { struct linux_getrlimit_args *p = params; iarg[0] = p->resource; /* l_uint */ uarg[1] = (intptr_t) p->rlim; /* struct l_rlimit * */ *n_args = 2; break; } /* linux_mmap2 */ case 192: { struct linux_mmap2_args *p = params; iarg[0] = p->addr; /* l_ulong */ iarg[1] = p->len; /* l_ulong */ iarg[2] = p->prot; /* l_ulong */ iarg[3] = p->flags; /* l_ulong */ iarg[4] = p->fd; /* l_ulong */ iarg[5] = p->pgoff; /* l_ulong */ *n_args = 6; break; } /* linux_truncate64 */ case 193: { struct linux_truncate64_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->length; /* l_loff_t */ *n_args = 2; break; } /* linux_ftruncate64 */ case 194: { struct linux_ftruncate64_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->length; /* l_loff_t */ *n_args = 2; break; } /* linux_stat64 */ case 195: { struct linux_stat64_args *p = params; uarg[0] = (intptr_t) p->filename; /* const char * */ uarg[1] = (intptr_t) p->statbuf; /* struct l_stat64 * */ *n_args = 2; break; } /* linux_lstat64 */ case 196: { struct linux_lstat64_args *p = params; uarg[0] = (intptr_t) p->filename; /* const char * */ uarg[1] = (intptr_t) p->statbuf; /* struct l_stat64 * */ *n_args = 2; break; } /* linux_fstat64 */ case 197: { struct linux_fstat64_args *p = params; iarg[0] = p->fd; /* l_int */ uarg[1] = (intptr_t) p->statbuf; /* struct l_stat64 * */ *n_args = 2; break; } /* linux_lchown */ case 198: { struct linux_lchown_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid_t */ iarg[2] = p->gid; /* l_gid_t */ *n_args = 3; break; } /* linux_getuid */ case 199: { *n_args = 0; break; } /* linux_getgid */ case 200: { *n_args = 0; break; } /* geteuid */ case 201: { *n_args = 0; break; } /* getegid */ case 202: { *n_args = 0; break; } /* setreuid */ case 203: { struct setreuid_args *p = params; uarg[0] = p->ruid; /* uid_t */ uarg[1] = p->euid; /* uid_t */ *n_args = 2; break; } /* setregid */ case 204: { struct setregid_args *p = params; iarg[0] = p->rgid; /* gid_t */ iarg[1] = p->egid; /* gid_t */ *n_args = 2; break; } /* linux_getgroups */ case 205: { struct linux_getgroups_args *p = params; iarg[0] = p->gidsetsize; /* l_int */ uarg[1] = (intptr_t) p->grouplist; /* l_gid_t * */ *n_args = 2; break; } /* linux_setgroups */ case 206: { struct linux_setgroups_args *p = params; iarg[0] = p->gidsetsize; /* l_int */ uarg[1] = (intptr_t) p->grouplist; /* l_gid_t * */ *n_args = 2; break; } /* fchown */ case 207: { *n_args = 0; break; } /* setresuid */ case 208: { struct setresuid_args *p = params; uarg[0] = p->ruid; /* uid_t */ uarg[1] = p->euid; /* uid_t */ uarg[2] = p->suid; /* uid_t */ *n_args = 3; break; } /* getresuid */ case 209: { struct getresuid_args *p = params; uarg[0] = (intptr_t) p->ruid; /* uid_t * */ uarg[1] = (intptr_t) p->euid; /* uid_t * */ uarg[2] = (intptr_t) p->suid; /* uid_t * */ *n_args = 3; break; } /* setresgid */ case 210: { struct setresgid_args *p = params; iarg[0] = p->rgid; /* gid_t */ iarg[1] = p->egid; /* gid_t */ iarg[2] = p->sgid; /* gid_t */ *n_args = 3; break; } /* getresgid */ case 211: { struct getresgid_args *p = params; uarg[0] = (intptr_t) p->rgid; /* gid_t * */ uarg[1] = (intptr_t) p->egid; /* gid_t * */ uarg[2] = (intptr_t) p->sgid; /* gid_t * */ *n_args = 3; break; } /* linux_chown */ case 212: { struct linux_chown_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ iarg[1] = p->uid; /* l_uid_t */ iarg[2] = p->gid; /* l_gid_t */ *n_args = 3; break; } /* setuid */ case 213: { struct setuid_args *p = params; uarg[0] = p->uid; /* uid_t */ *n_args = 1; break; } /* setgid */ case 214: { struct setgid_args *p = params; iarg[0] = p->gid; /* gid_t */ *n_args = 1; break; } /* linux_setfsuid */ case 215: { struct linux_setfsuid_args *p = params; iarg[0] = p->uid; /* l_uid_t */ *n_args = 1; break; } /* linux_setfsgid */ case 216: { struct linux_setfsgid_args *p = params; iarg[0] = p->gid; /* l_gid_t */ *n_args = 1; break; } /* linux_pivot_root */ case 217: { struct linux_pivot_root_args *p = params; uarg[0] = (intptr_t) p->new_root; /* char * */ uarg[1] = (intptr_t) p->put_old; /* char * */ *n_args = 2; break; } /* linux_mincore */ case 218: { struct linux_mincore_args *p = params; iarg[0] = p->start; /* l_ulong */ iarg[1] = p->len; /* l_size_t */ uarg[2] = (intptr_t) p->vec; /* u_char * */ *n_args = 3; break; } /* madvise */ case 219: { struct madvise_args *p = params; uarg[0] = (intptr_t) p->addr; /* void * */ uarg[1] = p->len; /* size_t */ iarg[2] = p->behav; /* int */ *n_args = 3; break; } /* linux_getdents64 */ case 220: { struct linux_getdents64_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = (intptr_t) p->dirent; /* void * */ iarg[2] = p->count; /* l_uint */ *n_args = 3; break; } /* linux_fcntl64 */ case 221: { struct linux_fcntl64_args *p = params; iarg[0] = p->fd; /* l_uint */ iarg[1] = p->cmd; /* l_uint */ iarg[2] = p->arg; /* l_ulong */ *n_args = 3; break; } /* linux_gettid */ case 224: { *n_args = 0; break; } /* linux_setxattr */ case 226: { *n_args = 0; break; } /* linux_lsetxattr */ case 227: { *n_args = 0; break; } /* linux_fsetxattr */ case 228: { *n_args = 0; break; } /* linux_getxattr */ case 229: { *n_args = 0; break; } /* linux_lgetxattr */ case 230: { *n_args = 0; break; } /* linux_fgetxattr */ case 231: { *n_args = 0; break; } /* linux_listxattr */ case 232: { *n_args = 0; break; } /* linux_llistxattr */ case 233: { *n_args = 0; break; } /* linux_flistxattr */ case 234: { *n_args = 0; break; } /* linux_removexattr */ case 235: { *n_args = 0; break; } /* linux_lremovexattr */ case 236: { *n_args = 0; break; } /* linux_fremovexattr */ case 237: { *n_args = 0; break; } /* linux_tkill */ case 238: { struct linux_tkill_args *p = params; iarg[0] = p->tid; /* int */ iarg[1] = p->sig; /* int */ *n_args = 2; break; } /* linux_sys_futex */ case 240: { struct linux_sys_futex_args *p = params; uarg[0] = (intptr_t) p->uaddr; /* void * */ iarg[1] = p->op; /* int */ uarg[2] = p->val; /* uint32_t */ uarg[3] = (intptr_t) p->timeout; /* struct l_timespec * */ uarg[4] = (intptr_t) p->uaddr2; /* uint32_t * */ uarg[5] = p->val3; /* uint32_t */ *n_args = 6; break; } /* linux_sched_setaffinity */ case 241: { struct linux_sched_setaffinity_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->len; /* l_uint */ uarg[2] = (intptr_t) p->user_mask_ptr; /* l_ulong * */ *n_args = 3; break; } /* linux_sched_getaffinity */ case 242: { struct linux_sched_getaffinity_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->len; /* l_uint */ uarg[2] = (intptr_t) p->user_mask_ptr; /* l_ulong * */ *n_args = 3; break; } /* linux_set_thread_area */ case 243: { struct linux_set_thread_area_args *p = params; uarg[0] = (intptr_t) p->desc; /* struct l_user_desc * */ *n_args = 1; break; } /* linux_get_thread_area */ case 244: { struct linux_get_thread_area_args *p = params; uarg[0] = (intptr_t) p->desc; /* struct l_user_desc * */ *n_args = 1; break; } /* linux_fadvise64 */ case 250: { struct linux_fadvise64_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->offset; /* l_loff_t */ iarg[2] = p->len; /* l_size_t */ iarg[3] = p->advice; /* int */ *n_args = 4; break; } /* linux_exit_group */ case 252: { struct linux_exit_group_args *p = params; iarg[0] = p->error_code; /* int */ *n_args = 1; break; } /* linux_lookup_dcookie */ case 253: { *n_args = 0; break; } /* linux_epoll_create */ case 254: { struct linux_epoll_create_args *p = params; iarg[0] = p->size; /* l_int */ *n_args = 1; break; } /* linux_epoll_ctl */ case 255: { struct linux_epoll_ctl_args *p = params; iarg[0] = p->epfd; /* l_int */ iarg[1] = p->op; /* l_int */ iarg[2] = p->fd; /* l_int */ uarg[3] = (intptr_t) p->event; /* struct epoll_event * */ *n_args = 4; break; } /* linux_epoll_wait */ case 256: { struct linux_epoll_wait_args *p = params; iarg[0] = p->epfd; /* l_int */ uarg[1] = (intptr_t) p->events; /* struct epoll_event * */ iarg[2] = p->maxevents; /* l_int */ iarg[3] = p->timeout; /* l_int */ *n_args = 4; break; } /* linux_remap_file_pages */ case 257: { *n_args = 0; break; } /* linux_set_tid_address */ case 258: { struct linux_set_tid_address_args *p = params; uarg[0] = (intptr_t) p->tidptr; /* int * */ *n_args = 1; break; } /* linux_timer_create */ case 259: { struct linux_timer_create_args *p = params; iarg[0] = p->clock_id; /* clockid_t */ uarg[1] = (intptr_t) p->evp; /* struct sigevent * */ uarg[2] = (intptr_t) p->timerid; /* l_timer_t * */ *n_args = 3; break; } /* linux_timer_settime */ case 260: { struct linux_timer_settime_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ iarg[1] = p->flags; /* l_int */ uarg[2] = (intptr_t) p->new; /* const struct itimerspec * */ uarg[3] = (intptr_t) p->old; /* struct itimerspec * */ *n_args = 4; break; } /* linux_timer_gettime */ case 261: { struct linux_timer_gettime_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ uarg[1] = (intptr_t) p->setting; /* struct itimerspec * */ *n_args = 2; break; } /* linux_timer_getoverrun */ case 262: { struct linux_timer_getoverrun_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ *n_args = 1; break; } /* linux_timer_delete */ case 263: { struct linux_timer_delete_args *p = params; iarg[0] = p->timerid; /* l_timer_t */ *n_args = 1; break; } /* linux_clock_settime */ case 264: { struct linux_clock_settime_args *p = params; iarg[0] = p->which; /* clockid_t */ uarg[1] = (intptr_t) p->tp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_clock_gettime */ case 265: { struct linux_clock_gettime_args *p = params; iarg[0] = p->which; /* clockid_t */ uarg[1] = (intptr_t) p->tp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_clock_getres */ case 266: { struct linux_clock_getres_args *p = params; iarg[0] = p->which; /* clockid_t */ uarg[1] = (intptr_t) p->tp; /* struct l_timespec * */ *n_args = 2; break; } /* linux_clock_nanosleep */ case 267: { struct linux_clock_nanosleep_args *p = params; iarg[0] = p->which; /* clockid_t */ iarg[1] = p->flags; /* int */ uarg[2] = (intptr_t) p->rqtp; /* struct l_timespec * */ uarg[3] = (intptr_t) p->rmtp; /* struct l_timespec * */ *n_args = 4; break; } /* linux_statfs64 */ case 268: { struct linux_statfs64_args *p = params; uarg[0] = (intptr_t) p->path; /* char * */ uarg[1] = p->bufsize; /* size_t */ uarg[2] = (intptr_t) p->buf; /* struct l_statfs64_buf * */ *n_args = 3; break; } /* linux_fstatfs64 */ case 269: { struct linux_fstatfs64_args *p = params; iarg[0] = p->fd; /* l_uint */ uarg[1] = p->bufsize; /* size_t */ uarg[2] = (intptr_t) p->buf; /* struct l_statfs64_buf * */ *n_args = 3; break; } /* linux_tgkill */ case 270: { struct linux_tgkill_args *p = params; iarg[0] = p->tgid; /* int */ iarg[1] = p->pid; /* int */ iarg[2] = p->sig; /* int */ *n_args = 3; break; } /* linux_utimes */ case 271: { struct linux_utimes_args *p = params; uarg[0] = (intptr_t) p->fname; /* char * */ uarg[1] = (intptr_t) p->tptr; /* struct l_timeval * */ *n_args = 2; break; } /* linux_fadvise64_64 */ case 272: { struct linux_fadvise64_64_args *p = params; iarg[0] = p->fd; /* int */ iarg[1] = p->offset; /* l_loff_t */ iarg[2] = p->len; /* l_loff_t */ iarg[3] = p->advice; /* int */ *n_args = 4; break; } /* linux_mbind */ case 274: { *n_args = 0; break; } /* linux_get_mempolicy */ case 275: { *n_args = 0; break; } /* linux_set_mempolicy */ case 276: { *n_args = 0; break; } /* linux_mq_open */ case 277: { struct linux_mq_open_args *p = params; uarg[0] = (intptr_t) p->name; /* const char * */ iarg[1] = p->oflag; /* int */ iarg[2] = p->mode; /* mode_t */ uarg[3] = (intptr_t) p->attr; /* struct mq_attr * */ *n_args = 4; break; } /* linux_mq_unlink */ case 278: { struct linux_mq_unlink_args *p = params; uarg[0] = (intptr_t) p->name; /* const char * */ *n_args = 1; break; } /* linux_mq_timedsend */ case 279: { struct linux_mq_timedsend_args *p = params; iarg[0] = p->mqd; /* l_mqd_t */ uarg[1] = (intptr_t) p->msg_ptr; /* const char * */ uarg[2] = p->msg_len; /* size_t */ uarg[3] = p->msg_prio; /* unsigned int */ uarg[4] = (intptr_t) p->abs_timeout; /* const struct l_timespec * */ *n_args = 5; break; } /* linux_mq_timedreceive */ case 280: { struct linux_mq_timedreceive_args *p = params; iarg[0] = p->mqd; /* l_mqd_t */ uarg[1] = (intptr_t) p->msg_ptr; /* char * */ uarg[2] = p->msg_len; /* size_t */ uarg[3] = p->msg_prio; /* unsigned int */ uarg[4] = (intptr_t) p->abs_timeout; /* const struct l_timespec * */ *n_args = 5; break; } /* linux_mq_notify */ case 281: { struct linux_mq_notify_args *p = params; iarg[0] = p->mqd; /* l_mqd_t */ uarg[1] = (intptr_t) p->abs_timeout; /* const struct l_timespec * */ *n_args = 2; break; } /* linux_mq_getsetattr */ case 282: { struct linux_mq_getsetattr_args *p = params; iarg[0] = p->mqd; /* l_mqd_t */ uarg[1] = (intptr_t) p->attr; /* const struct mq_attr * */ uarg[2] = (intptr_t) p->oattr; /* struct mq_attr * */ *n_args = 3; break; } /* linux_kexec_load */ case 283: { *n_args = 0; break; } /* linux_waitid */ case 284: { struct linux_waitid_args *p = params; iarg[0] = p->idtype; /* int */ iarg[1] = p->id; /* l_pid_t */ uarg[2] = (intptr_t) p->info; /* l_siginfo_t * */ iarg[3] = p->options; /* int */ uarg[4] = (intptr_t) p->rusage; /* void * */ *n_args = 5; break; } /* linux_add_key */ case 286: { *n_args = 0; break; } /* linux_request_key */ case 287: { *n_args = 0; break; } /* linux_keyctl */ case 288: { *n_args = 0; break; } /* linux_ioprio_set */ case 289: { *n_args = 0; break; } /* linux_ioprio_get */ case 290: { *n_args = 0; break; } /* linux_inotify_init */ case 291: { *n_args = 0; break; } /* linux_inotify_add_watch */ case 292: { *n_args = 0; break; } /* linux_inotify_rm_watch */ case 293: { *n_args = 0; break; } /* linux_migrate_pages */ case 294: { *n_args = 0; break; } /* linux_openat */ case 295: { struct linux_openat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->flags; /* l_int */ iarg[3] = p->mode; /* l_int */ *n_args = 4; break; } /* linux_mkdirat */ case 296: { struct linux_mkdirat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* const char * */ iarg[2] = p->mode; /* l_int */ *n_args = 3; break; } /* linux_mknodat */ case 297: { struct linux_mknodat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->mode; /* l_int */ iarg[3] = p->dev; /* l_uint */ *n_args = 4; break; } /* linux_fchownat */ case 298: { struct linux_fchownat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->uid; /* l_uid16_t */ iarg[3] = p->gid; /* l_gid16_t */ iarg[4] = p->flag; /* l_int */ *n_args = 5; break; } /* linux_futimesat */ case 299: { struct linux_futimesat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* char * */ uarg[2] = (intptr_t) p->utimes; /* struct l_timeval * */ *n_args = 3; break; } /* linux_fstatat64 */ case 300: { struct linux_fstatat64_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* char * */ uarg[2] = (intptr_t) p->statbuf; /* struct l_stat64 * */ iarg[3] = p->flag; /* l_int */ *n_args = 4; break; } /* linux_unlinkat */ case 301: { struct linux_unlinkat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* const char * */ iarg[2] = p->flag; /* l_int */ *n_args = 3; break; } /* linux_renameat */ case 302: { struct linux_renameat_args *p = params; iarg[0] = p->olddfd; /* l_int */ uarg[1] = (intptr_t) p->oldname; /* const char * */ iarg[2] = p->newdfd; /* l_int */ uarg[3] = (intptr_t) p->newname; /* const char * */ *n_args = 4; break; } /* linux_linkat */ case 303: { struct linux_linkat_args *p = params; iarg[0] = p->olddfd; /* l_int */ uarg[1] = (intptr_t) p->oldname; /* const char * */ iarg[2] = p->newdfd; /* l_int */ uarg[3] = (intptr_t) p->newname; /* const char * */ iarg[4] = p->flag; /* l_int */ *n_args = 5; break; } /* linux_symlinkat */ case 304: { struct linux_symlinkat_args *p = params; uarg[0] = (intptr_t) p->oldname; /* const char * */ iarg[1] = p->newdfd; /* l_int */ uarg[2] = (intptr_t) p->newname; /* const char * */ *n_args = 3; break; } /* linux_readlinkat */ case 305: { struct linux_readlinkat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->path; /* const char * */ uarg[2] = (intptr_t) p->buf; /* char * */ iarg[3] = p->bufsiz; /* l_int */ *n_args = 4; break; } /* linux_fchmodat */ case 306: { struct linux_fchmodat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->mode; /* l_mode_t */ *n_args = 3; break; } /* linux_faccessat */ case 307: { struct linux_faccessat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->filename; /* const char * */ iarg[2] = p->amode; /* l_int */ *n_args = 3; break; } /* linux_pselect6 */ case 308: { struct linux_pselect6_args *p = params; iarg[0] = p->nfds; /* l_int */ uarg[1] = (intptr_t) p->readfds; /* l_fd_set * */ uarg[2] = (intptr_t) p->writefds; /* l_fd_set * */ uarg[3] = (intptr_t) p->exceptfds; /* l_fd_set * */ uarg[4] = (intptr_t) p->tsp; /* struct l_timespec * */ uarg[5] = (intptr_t) p->sig; /* l_uintptr_t * */ *n_args = 6; break; } /* linux_ppoll */ case 309: { struct linux_ppoll_args *p = params; uarg[0] = (intptr_t) p->fds; /* struct pollfd * */ uarg[1] = p->nfds; /* uint32_t */ uarg[2] = (intptr_t) p->tsp; /* struct l_timespec * */ uarg[3] = (intptr_t) p->sset; /* l_sigset_t * */ iarg[4] = p->ssize; /* l_size_t */ *n_args = 5; break; } /* linux_unshare */ case 310: { *n_args = 0; break; } /* linux_set_robust_list */ case 311: { struct linux_set_robust_list_args *p = params; uarg[0] = (intptr_t) p->head; /* struct linux_robust_list_head * */ iarg[1] = p->len; /* l_size_t */ *n_args = 2; break; } /* linux_get_robust_list */ case 312: { struct linux_get_robust_list_args *p = params; iarg[0] = p->pid; /* l_int */ uarg[1] = (intptr_t) p->head; /* struct linux_robust_list_head ** */ uarg[2] = (intptr_t) p->len; /* l_size_t * */ *n_args = 3; break; } /* linux_splice */ case 313: { *n_args = 0; break; } /* linux_sync_file_range */ case 314: { *n_args = 0; break; } /* linux_tee */ case 315: { *n_args = 0; break; } /* linux_vmsplice */ case 316: { *n_args = 0; break; } /* linux_move_pages */ case 317: { *n_args = 0; break; } /* linux_getcpu */ case 318: { *n_args = 0; break; } /* linux_epoll_pwait */ case 319: { struct linux_epoll_pwait_args *p = params; iarg[0] = p->epfd; /* l_int */ uarg[1] = (intptr_t) p->events; /* struct epoll_event * */ iarg[2] = p->maxevents; /* l_int */ iarg[3] = p->timeout; /* l_int */ uarg[4] = (intptr_t) p->mask; /* l_sigset_t * */ *n_args = 5; break; } /* linux_utimensat */ case 320: { struct linux_utimensat_args *p = params; iarg[0] = p->dfd; /* l_int */ uarg[1] = (intptr_t) p->pathname; /* const char * */ uarg[2] = (intptr_t) p->times; /* const struct l_timespec * */ iarg[3] = p->flags; /* l_int */ *n_args = 4; break; } /* linux_signalfd */ case 321: { *n_args = 0; break; } /* linux_timerfd_create */ case 322: { *n_args = 0; break; } /* linux_eventfd */ case 323: { struct linux_eventfd_args *p = params; iarg[0] = p->initval; /* l_uint */ *n_args = 1; break; } /* linux_fallocate */ case 324: { struct linux_fallocate_args *p = params; iarg[0] = p->fd; /* l_int */ iarg[1] = p->mode; /* l_int */ iarg[2] = p->offset; /* l_loff_t */ iarg[3] = p->len; /* l_loff_t */ *n_args = 4; break; } /* linux_timerfd_settime */ case 325: { *n_args = 0; break; } /* linux_timerfd_gettime */ case 326: { *n_args = 0; break; } /* linux_signalfd4 */ case 327: { *n_args = 0; break; } /* linux_eventfd2 */ case 328: { struct linux_eventfd2_args *p = params; iarg[0] = p->initval; /* l_uint */ iarg[1] = p->flags; /* l_int */ *n_args = 2; break; } /* linux_epoll_create1 */ case 329: { struct linux_epoll_create1_args *p = params; iarg[0] = p->flags; /* l_int */ *n_args = 1; break; } /* linux_dup3 */ case 330: { struct linux_dup3_args *p = params; iarg[0] = p->oldfd; /* l_int */ iarg[1] = p->newfd; /* l_int */ iarg[2] = p->flags; /* l_int */ *n_args = 3; break; } /* linux_pipe2 */ case 331: { struct linux_pipe2_args *p = params; uarg[0] = (intptr_t) p->pipefds; /* l_int * */ iarg[1] = p->flags; /* l_int */ *n_args = 2; break; } /* linux_inotify_init1 */ case 332: { *n_args = 0; break; } /* linux_preadv */ case 333: { - *n_args = 0; + struct linux_preadv_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + *n_args = 5; break; } /* linux_pwritev */ case 334: { - *n_args = 0; + struct linux_pwritev_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + *n_args = 5; break; } - /* linux_rt_tsigqueueinfo */ + /* linux_rt_tgsigqueueinfo */ case 335: { - *n_args = 0; + struct linux_rt_tgsigqueueinfo_args *p = params; + iarg[0] = p->tgid; /* l_pid_t */ + iarg[1] = p->tid; /* l_pid_t */ + iarg[2] = p->sig; /* l_int */ + uarg[3] = (intptr_t) p->uinfo; /* l_siginfo_t * */ + *n_args = 4; break; } /* linux_perf_event_open */ case 336: { *n_args = 0; break; } /* linux_recvmmsg */ case 337: { struct linux_recvmmsg_args *p = params; iarg[0] = p->s; /* l_int */ uarg[1] = (intptr_t) p->msg; /* struct l_mmsghdr * */ iarg[2] = p->vlen; /* l_uint */ iarg[3] = p->flags; /* l_uint */ uarg[4] = (intptr_t) p->timeout; /* struct l_timespec * */ *n_args = 5; break; } /* linux_fanotify_init */ case 338: { *n_args = 0; break; } /* linux_fanotify_mark */ case 339: { *n_args = 0; break; } /* linux_prlimit64 */ case 340: { struct linux_prlimit64_args *p = params; iarg[0] = p->pid; /* l_pid_t */ iarg[1] = p->resource; /* l_uint */ uarg[2] = (intptr_t) p->new; /* struct rlimit * */ uarg[3] = (intptr_t) p->old; /* struct rlimit * */ *n_args = 4; break; } /* linux_name_to_handle_at */ case 341: { *n_args = 0; break; } /* linux_open_by_handle_at */ case 342: { *n_args = 0; break; } /* linux_clock_adjtime */ case 343: { *n_args = 0; break; } /* linux_syncfs */ case 344: { struct linux_syncfs_args *p = params; iarg[0] = p->fd; /* l_int */ *n_args = 1; break; } /* linux_sendmmsg */ case 345: { struct linux_sendmmsg_args *p = params; iarg[0] = p->s; /* l_int */ uarg[1] = (intptr_t) p->msg; /* struct l_mmsghdr * */ iarg[2] = p->vlen; /* l_uint */ iarg[3] = p->flags; /* l_uint */ *n_args = 4; break; } /* linux_setns */ case 346: { *n_args = 0; break; } /* linux_process_vm_readv */ case 347: { - *n_args = 0; + struct linux_process_vm_readv_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->lvec; /* const struct iovec * */ + iarg[2] = p->liovcnt; /* l_ulong */ + uarg[3] = (intptr_t) p->rvec; /* const struct iovec * */ + iarg[4] = p->riovcnt; /* l_ulong */ + iarg[5] = p->flags; /* l_ulong */ + *n_args = 6; break; } /* linux_process_vm_writev */ case 348: { - *n_args = 0; + struct linux_process_vm_writev_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->lvec; /* const struct iovec * */ + iarg[2] = p->liovcnt; /* l_ulong */ + uarg[3] = (intptr_t) p->rvec; /* const struct iovec * */ + iarg[4] = p->riovcnt; /* l_ulong */ + iarg[5] = p->flags; /* l_ulong */ + *n_args = 6; break; } + /* linux_kcmp */ + case 349: { + struct linux_kcmp_args *p = params; + iarg[0] = p->pid1; /* l_pid_t */ + iarg[1] = p->pid2; /* l_pid_t */ + iarg[2] = p->type; /* l_int */ + iarg[3] = p->idx1; /* l_ulong */ + iarg[4] = p->idx; /* l_ulong */ + *n_args = 5; + break; + } + /* linux_finit_module */ + case 350: { + struct linux_finit_module_args *p = params; + iarg[0] = p->fd; /* l_int */ + uarg[1] = (intptr_t) p->uargs; /* const char * */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_sched_setattr */ + case 351: { + struct linux_sched_setattr_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->attr; /* void * */ + iarg[2] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_sched_getattr */ + case 352: { + struct linux_sched_getattr_args *p = params; + iarg[0] = p->pid; /* l_pid_t */ + uarg[1] = (intptr_t) p->attr; /* void * */ + iarg[2] = p->size; /* l_uint */ + iarg[3] = p->flags; /* l_uint */ + *n_args = 4; + break; + } + /* linux_renameat2 */ + case 353: { + struct linux_renameat2_args *p = params; + iarg[0] = p->oldfd; /* l_int */ + uarg[1] = (intptr_t) p->oldname; /* const char * */ + iarg[2] = p->newfd; /* l_int */ + uarg[3] = (intptr_t) p->newname; /* const char * */ + uarg[4] = p->flags; /* unsigned int */ + *n_args = 5; + break; + } + /* linux_seccomp */ + case 354: { + struct linux_seccomp_args *p = params; + iarg[0] = p->op; /* l_uint */ + iarg[1] = p->flags; /* l_uint */ + uarg[2] = (intptr_t) p->uargs; /* const char * */ + *n_args = 3; + break; + } + /* linux_getrandom */ + case 355: { + struct linux_getrandom_args *p = params; + uarg[0] = (intptr_t) p->buf; /* char * */ + iarg[1] = p->count; /* l_size_t */ + iarg[2] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_memfd_create */ + case 356: { + struct linux_memfd_create_args *p = params; + uarg[0] = (intptr_t) p->uname_ptr; /* const char * */ + iarg[1] = p->flags; /* l_uint */ + *n_args = 2; + break; + } + /* linux_bpf */ + case 357: { + struct linux_bpf_args *p = params; + iarg[0] = p->cmd; /* l_int */ + uarg[1] = (intptr_t) p->attr; /* void * */ + iarg[2] = p->size; /* l_uint */ + *n_args = 3; + break; + } + /* linux_execveat */ + case 358: { + struct linux_execveat_args *p = params; + iarg[0] = p->dfd; /* l_int */ + uarg[1] = (intptr_t) p->filename; /* const char * */ + uarg[2] = (intptr_t) p->argv; /* const char ** */ + uarg[3] = (intptr_t) p->envp; /* const char ** */ + iarg[4] = p->flags; /* l_int */ + *n_args = 5; + break; + } + /* linux_socket */ + case 359: { + struct linux_socket_args *p = params; + iarg[0] = p->domain; /* l_int */ + iarg[1] = p->type; /* l_int */ + iarg[2] = p->protocol; /* l_int */ + *n_args = 3; + break; + } + /* linux_socketpair */ + case 360: { + struct linux_socketpair_args *p = params; + iarg[0] = p->domain; /* l_int */ + iarg[1] = p->type; /* l_int */ + iarg[2] = p->protocol; /* l_int */ + iarg[3] = p->rsv; /* l_uintptr_t */ + *n_args = 4; + break; + } + /* linux_bind */ + case 361: { + struct linux_bind_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->name; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_int */ + *n_args = 3; + break; + } + /* linux_connect */ + case 362: { + struct linux_connect_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->name; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_int */ + *n_args = 3; + break; + } + /* linux_listen */ + case 363: { + struct linux_listen_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->backlog; /* l_int */ + *n_args = 2; + break; + } + /* linux_accept4 */ + case 364: { + struct linux_accept4_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->addr; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_uintptr_t */ + iarg[3] = p->flags; /* l_int */ + *n_args = 4; + break; + } + /* linux_getsockopt */ + case 365: { + struct linux_getsockopt_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->level; /* l_int */ + iarg[2] = p->optname; /* l_int */ + iarg[3] = p->optval; /* l_uintptr_t */ + iarg[4] = p->optlen; /* l_uintptr_t */ + *n_args = 5; + break; + } + /* linux_setsockopt */ + case 366: { + struct linux_setsockopt_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->level; /* l_int */ + iarg[2] = p->optname; /* l_int */ + iarg[3] = p->optval; /* l_uintptr_t */ + iarg[4] = p->optlen; /* l_int */ + *n_args = 5; + break; + } + /* linux_getsockname */ + case 367: { + struct linux_getsockname_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->addr; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_uintptr_t */ + *n_args = 3; + break; + } + /* linux_getpeername */ + case 368: { + struct linux_getpeername_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->addr; /* l_uintptr_t */ + iarg[2] = p->namelen; /* l_uintptr_t */ + *n_args = 3; + break; + } + /* linux_sendto */ + case 369: { + struct linux_sendto_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->msg; /* l_uintptr_t */ + iarg[2] = p->len; /* l_int */ + iarg[3] = p->flags; /* l_int */ + iarg[4] = p->to; /* l_uintptr_t */ + iarg[5] = p->tolen; /* l_int */ + *n_args = 6; + break; + } + /* linux_sendmsg */ + case 370: { + struct linux_sendmsg_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->msg; /* l_uintptr_t */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_recvfrom */ + case 371: { + struct linux_recvfrom_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->buf; /* l_uintptr_t */ + iarg[2] = p->len; /* l_size_t */ + iarg[3] = p->flags; /* l_int */ + iarg[4] = p->from; /* l_uintptr_t */ + iarg[5] = p->fromlen; /* l_uintptr_t */ + *n_args = 6; + break; + } + /* linux_recvmsg */ + case 372: { + struct linux_recvmsg_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->msg; /* l_uintptr_t */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_shutdown */ + case 373: { + struct linux_shutdown_args *p = params; + iarg[0] = p->s; /* l_int */ + iarg[1] = p->how; /* l_int */ + *n_args = 2; + break; + } + /* linux_userfaultfd */ + case 374: { + struct linux_userfaultfd_args *p = params; + iarg[0] = p->flags; /* l_int */ + *n_args = 1; + break; + } + /* linux_membarrier */ + case 375: { + struct linux_membarrier_args *p = params; + iarg[0] = p->cmd; /* l_int */ + iarg[1] = p->flags; /* l_int */ + *n_args = 2; + break; + } + /* linux_mlock2 */ + case 376: { + struct linux_mlock2_args *p = params; + iarg[0] = p->start; /* l_ulong */ + iarg[1] = p->len; /* l_size_t */ + iarg[2] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_copy_file_range */ + case 377: { + struct linux_copy_file_range_args *p = params; + iarg[0] = p->fd_in; /* l_int */ + uarg[1] = (intptr_t) p->off_in; /* l_loff_t * */ + iarg[2] = p->fd_out; /* l_int */ + uarg[3] = (intptr_t) p->off_out; /* l_loff_t * */ + iarg[4] = p->len; /* l_size_t */ + iarg[5] = p->flags; /* l_uint */ + *n_args = 6; + break; + } + /* linux_preadv2 */ + case 378: { + struct linux_preadv2_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* const struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + iarg[5] = p->flags; /* l_int */ + *n_args = 6; + break; + } + /* linux_pwritev2 */ + case 379: { + struct linux_pwritev2_args *p = params; + iarg[0] = p->fd; /* l_ulong */ + uarg[1] = (intptr_t) p->vec; /* const struct iovec * */ + iarg[2] = p->vlen; /* l_ulong */ + iarg[3] = p->pos_l; /* l_ulong */ + iarg[4] = p->pos_h; /* l_ulong */ + iarg[5] = p->flags; /* l_int */ + *n_args = 6; + break; + } + /* linux_pkey_mprotect */ + case 380: { + struct linux_pkey_mprotect_args *p = params; + iarg[0] = p->start; /* l_ulong */ + iarg[1] = p->len; /* l_size_t */ + iarg[2] = p->prot; /* l_ulong */ + iarg[3] = p->pkey; /* l_int */ + *n_args = 4; + break; + } + /* linux_pkey_alloc */ + case 381: { + struct linux_pkey_alloc_args *p = params; + iarg[0] = p->flags; /* l_ulong */ + iarg[1] = p->init_val; /* l_ulong */ + *n_args = 2; + break; + } + /* linux_pkey_free */ + case 382: { + struct linux_pkey_free_args *p = params; + iarg[0] = p->pkey; /* l_int */ + *n_args = 1; + break; + } default: *n_args = 0; break; }; } static void systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) { const char *p = NULL; switch (sysnum) { #define nosys linux_nosys /* linux_exit */ case 1: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_fork */ case 2: break; /* read */ case 3: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland char *"; break; case 2: p = "u_int"; break; default: break; }; break; /* write */ case 4: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland char *"; break; case 2: p = "u_int"; break; default: break; }; break; /* linux_open */ case 5: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; default: break; }; break; /* close */ case 6: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_waitpid */ case 7: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland l_int *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_creat */ case 8: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_link */ case 9: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_unlink */ case 10: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_execve */ case 11: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char **"; break; case 2: p = "userland char **"; break; default: break; }; break; /* linux_chdir */ case 12: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_time */ case 13: switch(ndx) { case 0: p = "userland l_time_t *"; break; default: break; }; break; /* linux_mknod */ case 14: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; case 2: p = "l_dev_t"; break; default: break; }; break; /* linux_chmod */ case 15: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_mode_t"; break; default: break; }; break; /* linux_lchown16 */ case 16: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid16_t"; break; case 2: p = "l_gid16_t"; break; default: break; }; break; /* linux_stat */ case 18: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct linux_stat *"; break; default: break; }; break; /* linux_lseek */ case 19: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_off_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_getpid */ case 20: break; /* linux_mount */ case 21: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; case 2: p = "userland char *"; break; case 3: p = "l_ulong"; break; case 4: p = "userland void *"; break; default: break; }; break; /* linux_oldumount */ case 22: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_setuid16 */ case 23: switch(ndx) { case 0: p = "l_uid16_t"; break; default: break; }; break; /* linux_getuid16 */ case 24: break; /* linux_stime */ case 25: break; /* linux_ptrace */ case 26: switch(ndx) { case 0: p = "l_long"; break; case 1: p = "l_long"; break; case 2: p = "l_long"; break; case 3: p = "l_long"; break; default: break; }; break; /* linux_alarm */ case 27: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_fstat */ case 28: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct linux_stat *"; break; default: break; }; break; /* linux_pause */ case 29: break; /* linux_utime */ case 30: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_utimbuf *"; break; default: break; }; break; /* linux_access */ case 33: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_nice */ case 34: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* sync */ case 36: break; /* linux_kill */ case 37: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_rename */ case 38: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_mkdir */ case 39: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_rmdir */ case 40: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* dup */ case 41: switch(ndx) { case 0: p = "u_int"; break; default: break; }; break; /* linux_pipe */ case 42: switch(ndx) { case 0: p = "userland l_int *"; break; default: break; }; break; /* linux_times */ case 43: switch(ndx) { case 0: p = "userland struct l_times_argv *"; break; default: break; }; break; /* linux_brk */ case 45: switch(ndx) { case 0: p = "l_ulong"; break; default: break; }; break; /* linux_setgid16 */ case 46: switch(ndx) { case 0: p = "l_gid16_t"; break; default: break; }; break; /* linux_getgid16 */ case 47: break; /* linux_signal */ case 48: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland void *"; break; default: break; }; break; /* linux_geteuid16 */ case 49: break; /* linux_getegid16 */ case 50: break; /* acct */ case 51: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_umount */ case 52: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_ioctl */ case 54: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_uint"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* linux_fcntl */ case 55: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_uint"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* setpgid */ case 57: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* linux_olduname */ case 59: break; /* umask */ case 60: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* chroot */ case 61: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_ustat */ case 62: switch(ndx) { case 0: p = "l_dev_t"; break; case 1: p = "userland struct l_ustat *"; break; default: break; }; break; /* dup2 */ case 63: switch(ndx) { case 0: p = "u_int"; break; case 1: p = "u_int"; break; default: break; }; break; /* linux_getppid */ case 64: break; /* getpgrp */ case 65: break; /* setsid */ case 66: break; /* linux_sigaction */ case 67: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_osigaction_t *"; break; case 2: p = "userland l_osigaction_t *"; break; default: break; }; break; /* linux_sgetmask */ case 68: break; /* linux_ssetmask */ case 69: switch(ndx) { case 0: p = "l_osigset_t"; break; default: break; }; break; /* linux_setreuid16 */ case 70: switch(ndx) { case 0: p = "l_uid16_t"; break; case 1: p = "l_uid16_t"; break; default: break; }; break; /* linux_setregid16 */ case 71: switch(ndx) { case 0: p = "l_gid16_t"; break; case 1: p = "l_gid16_t"; break; default: break; }; break; /* linux_sigsuspend */ case 72: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_osigset_t"; break; default: break; }; break; /* linux_sigpending */ case 73: switch(ndx) { case 0: p = "userland l_osigset_t *"; break; default: break; }; break; /* linux_sethostname */ case 74: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "u_int"; break; default: break; }; break; /* linux_setrlimit */ case 75: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_rlimit *"; break; default: break; }; break; /* linux_old_getrlimit */ case 76: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_rlimit *"; break; default: break; }; break; /* getrusage */ case 77: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland struct rusage *"; break; default: break; }; break; /* gettimeofday */ case 78: switch(ndx) { case 0: p = "userland struct timeval *"; break; case 1: p = "userland struct timezone *"; break; default: break; }; break; /* settimeofday */ case 79: switch(ndx) { case 0: p = "userland struct timeval *"; break; case 1: p = "userland struct timezone *"; break; default: break; }; break; /* linux_getgroups16 */ case 80: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland l_gid16_t *"; break; default: break; }; break; /* linux_setgroups16 */ case 81: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland l_gid16_t *"; break; default: break; }; break; /* linux_old_select */ case 82: switch(ndx) { case 0: p = "userland struct l_old_select_argv *"; break; default: break; }; break; /* linux_symlink */ case 83: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_lstat */ case 84: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_stat *"; break; default: break; }; break; /* linux_readlink */ case 85: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_uselib */ case 86: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* swapon */ case 87: switch(ndx) { case 0: p = "userland char *"; break; default: break; }; break; /* linux_reboot */ case 88: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_uint"; break; case 3: p = "userland void *"; break; default: break; }; break; /* linux_readdir */ case 89: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_dirent *"; break; case 2: p = "l_uint"; break; default: break; }; break; /* linux_mmap */ case 90: switch(ndx) { case 0: p = "userland struct l_mmap_argv *"; break; default: break; }; break; /* munmap */ case 91: switch(ndx) { case 0: p = "caddr_t"; break; case 1: p = "int"; break; default: break; }; break; /* linux_truncate */ case 92: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_ulong"; break; default: break; }; break; /* linux_ftruncate */ case 93: switch(ndx) { case 0: p = "int"; break; case 1: p = "long"; break; default: break; }; break; /* fchmod */ case 94: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* fchown */ case 95: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_getpriority */ case 96: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* setpriority */ case 97: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_statfs */ case 99: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_statfs_buf *"; break; default: break; }; break; /* linux_fstatfs */ case 100: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_statfs_buf *"; break; default: break; }; break; /* linux_ioperm */ case 101: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_ulong"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_socketcall */ case 102: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_ulong"; break; default: break; }; break; /* linux_syslog */ case 103: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_setitimer */ case 104: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_itimerval *"; break; case 2: p = "userland struct l_itimerval *"; break; default: break; }; break; /* linux_getitimer */ case 105: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_itimerval *"; break; default: break; }; break; /* linux_newstat */ case 106: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_newstat *"; break; default: break; }; break; /* linux_newlstat */ case 107: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_newstat *"; break; default: break; }; break; /* linux_newfstat */ case 108: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_newstat *"; break; default: break; }; break; /* linux_uname */ case 109: break; /* linux_iopl */ case 110: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_vhangup */ case 111: break; /* linux_vm86old */ case 113: break; /* linux_wait4 */ case 114: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland l_int *"; break; case 2: p = "l_int"; break; case 3: p = "userland void *"; break; default: break; }; break; /* linux_swapoff */ case 115: break; /* linux_sysinfo */ case 116: switch(ndx) { case 0: p = "userland struct l_sysinfo *"; break; default: break; }; break; /* linux_ipc */ case 117: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; case 4: p = "userland void *"; break; case 5: p = "l_long"; break; default: break; }; break; /* fsync */ case 118: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_sigreturn */ case 119: switch(ndx) { case 0: p = "userland struct l_sigframe *"; break; default: break; }; break; /* linux_clone */ case 120: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland void *"; break; case 2: p = "userland void *"; break; case 3: p = "userland void *"; break; case 4: p = "userland void *"; break; default: break; }; break; /* linux_setdomainname */ case 121: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "int"; break; default: break; }; break; /* linux_newuname */ case 122: switch(ndx) { case 0: p = "userland struct l_new_utsname *"; break; default: break; }; break; /* linux_modify_ldt */ case 123: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland void *"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* linux_adjtimex */ case 124: break; /* linux_mprotect */ case 125: switch(ndx) { case 0: p = "caddr_t"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_sigprocmask */ case 126: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_osigset_t *"; break; case 2: p = "userland l_osigset_t *"; break; default: break; }; break; /* linux_create_module */ case 127: break; /* linux_init_module */ case 128: break; /* linux_delete_module */ case 129: break; /* linux_get_kernel_syms */ case 130: break; /* linux_quotactl */ case 131: break; /* getpgid */ case 132: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* fchdir */ case 133: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_bdflush */ case 134: break; /* linux_sysfs */ case 135: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* linux_personality */ case 136: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_setfsuid16 */ case 138: switch(ndx) { case 0: p = "l_uid16_t"; break; default: break; }; break; /* linux_setfsgid16 */ case 139: switch(ndx) { case 0: p = "l_gid16_t"; break; default: break; }; break; /* linux_llseek */ case 140: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; case 3: p = "userland l_loff_t *"; break; case 4: p = "l_uint"; break; default: break; }; break; /* linux_getdents */ case 141: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland void *"; break; case 2: p = "l_uint"; break; default: break; }; break; /* linux_select */ case 142: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_fd_set *"; break; case 2: p = "userland l_fd_set *"; break; case 3: p = "userland l_fd_set *"; break; case 4: p = "userland struct l_timeval *"; break; default: break; }; break; /* flock */ case 143: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* linux_msync */ case 144: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_size_t"; break; case 2: p = "l_int"; break; default: break; }; break; /* readv */ case 145: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland struct iovec *"; break; case 2: p = "u_int"; break; default: break; }; break; /* writev */ case 146: switch(ndx) { case 0: p = "int"; break; case 1: p = "userland struct iovec *"; break; case 2: p = "u_int"; break; default: break; }; break; /* linux_getsid */ case 147: switch(ndx) { case 0: p = "l_pid_t"; break; default: break; }; break; /* linux_fdatasync */ case 148: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_sysctl */ case 149: switch(ndx) { case 0: p = "userland struct l___sysctl_args *"; break; default: break; }; break; /* mlock */ case 150: switch(ndx) { case 0: p = "userland const void *"; break; case 1: p = "size_t"; break; default: break; }; break; /* munlock */ case 151: switch(ndx) { case 0: p = "userland const void *"; break; case 1: p = "size_t"; break; default: break; }; break; /* mlockall */ case 152: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* munlockall */ case 153: break; /* linux_sched_setparam */ case 154: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland struct sched_param *"; break; default: break; }; break; /* linux_sched_getparam */ case 155: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland struct sched_param *"; break; default: break; }; break; /* linux_sched_setscheduler */ case 156: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_int"; break; case 2: p = "userland struct sched_param *"; break; default: break; }; break; /* linux_sched_getscheduler */ case 157: switch(ndx) { case 0: p = "l_pid_t"; break; default: break; }; break; /* sched_yield */ case 158: break; /* linux_sched_get_priority_max */ case 159: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_sched_get_priority_min */ case 160: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_sched_rr_get_interval */ case 161: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_nanosleep */ case 162: switch(ndx) { case 0: p = "userland const struct l_timespec *"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_mremap */ case 163: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; case 3: p = "l_ulong"; break; case 4: p = "l_ulong"; break; default: break; }; break; /* linux_setresuid16 */ case 164: switch(ndx) { case 0: p = "l_uid16_t"; break; case 1: p = "l_uid16_t"; break; case 2: p = "l_uid16_t"; break; default: break; }; break; /* linux_getresuid16 */ case 165: switch(ndx) { case 0: p = "userland l_uid16_t *"; break; case 1: p = "userland l_uid16_t *"; break; case 2: p = "userland l_uid16_t *"; break; default: break; }; break; /* linux_vm86 */ case 166: break; /* linux_query_module */ case 167: break; /* poll */ case 168: switch(ndx) { case 0: p = "userland struct pollfd *"; break; case 1: p = "unsigned int"; break; case 2: p = "long"; break; default: break; }; break; /* linux_nfsservctl */ case 169: break; /* linux_setresgid16 */ case 170: switch(ndx) { case 0: p = "l_gid16_t"; break; case 1: p = "l_gid16_t"; break; case 2: p = "l_gid16_t"; break; default: break; }; break; /* linux_getresgid16 */ case 171: switch(ndx) { case 0: p = "userland l_gid16_t *"; break; case 1: p = "userland l_gid16_t *"; break; case 2: p = "userland l_gid16_t *"; break; default: break; }; break; /* linux_prctl */ case 172: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_rt_sigreturn */ case 173: switch(ndx) { case 0: p = "userland struct l_ucontext *"; break; default: break; }; break; /* linux_rt_sigaction */ case 174: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_sigaction_t *"; break; case 2: p = "userland l_sigaction_t *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigprocmask */ case 175: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_sigset_t *"; break; case 2: p = "userland l_sigset_t *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigpending */ case 176: switch(ndx) { case 0: p = "userland l_sigset_t *"; break; case 1: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigtimedwait */ case 177: switch(ndx) { case 0: p = "userland l_sigset_t *"; break; case 1: p = "userland l_siginfo_t *"; break; case 2: p = "userland struct l_timeval *"; break; case 3: p = "l_size_t"; break; default: break; }; break; /* linux_rt_sigqueueinfo */ case 178: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_int"; break; case 2: p = "userland l_siginfo_t *"; break; default: break; }; break; /* linux_rt_sigsuspend */ case 179: switch(ndx) { case 0: p = "userland l_sigset_t *"; break; case 1: p = "l_size_t"; break; default: break; }; break; /* linux_pread */ case 180: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland char *"; break; case 2: p = "l_size_t"; break; case 3: p = "l_loff_t"; break; default: break; }; break; /* linux_pwrite */ case 181: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland char *"; break; case 2: p = "l_size_t"; break; case 3: p = "l_loff_t"; break; default: break; }; break; /* linux_chown16 */ case 182: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid16_t"; break; case 2: p = "l_gid16_t"; break; default: break; }; break; /* linux_getcwd */ case 183: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_ulong"; break; default: break; }; break; /* linux_capget */ case 184: switch(ndx) { case 0: p = "userland struct l_user_cap_header *"; break; case 1: p = "userland struct l_user_cap_data *"; break; default: break; }; break; /* linux_capset */ case 185: switch(ndx) { case 0: p = "userland struct l_user_cap_header *"; break; case 1: p = "userland struct l_user_cap_data *"; break; default: break; }; break; /* linux_sigaltstack */ case 186: switch(ndx) { case 0: p = "userland l_stack_t *"; break; case 1: p = "userland l_stack_t *"; break; default: break; }; break; /* linux_sendfile */ case 187: break; /* linux_vfork */ case 190: break; /* linux_getrlimit */ case 191: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland struct l_rlimit *"; break; default: break; }; break; /* linux_mmap2 */ case 192: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_ulong"; break; case 2: p = "l_ulong"; break; case 3: p = "l_ulong"; break; case 4: p = "l_ulong"; break; case 5: p = "l_ulong"; break; default: break; }; break; /* linux_truncate64 */ case 193: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_loff_t"; break; default: break; }; break; /* linux_ftruncate64 */ case 194: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_loff_t"; break; default: break; }; break; /* linux_stat64 */ case 195: switch(ndx) { case 0: p = "userland const char *"; break; case 1: p = "userland struct l_stat64 *"; break; default: break; }; break; /* linux_lstat64 */ case 196: switch(ndx) { case 0: p = "userland const char *"; break; case 1: p = "userland struct l_stat64 *"; break; default: break; }; break; /* linux_fstat64 */ case 197: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_stat64 *"; break; default: break; }; break; /* linux_lchown */ case 198: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid_t"; break; case 2: p = "l_gid_t"; break; default: break; }; break; /* linux_getuid */ case 199: break; /* linux_getgid */ case 200: break; /* geteuid */ case 201: break; /* getegid */ case 202: break; /* setreuid */ case 203: switch(ndx) { case 0: p = "uid_t"; break; case 1: p = "uid_t"; break; default: break; }; break; /* setregid */ case 204: switch(ndx) { case 0: p = "gid_t"; break; case 1: p = "gid_t"; break; default: break; }; break; /* linux_getgroups */ case 205: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_gid_t *"; break; default: break; }; break; /* linux_setgroups */ case 206: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_gid_t *"; break; default: break; }; break; /* fchown */ case 207: break; /* setresuid */ case 208: switch(ndx) { case 0: p = "uid_t"; break; case 1: p = "uid_t"; break; case 2: p = "uid_t"; break; default: break; }; break; /* getresuid */ case 209: switch(ndx) { case 0: p = "userland uid_t *"; break; case 1: p = "userland uid_t *"; break; case 2: p = "userland uid_t *"; break; default: break; }; break; /* setresgid */ case 210: switch(ndx) { case 0: p = "gid_t"; break; case 1: p = "gid_t"; break; case 2: p = "gid_t"; break; default: break; }; break; /* getresgid */ case 211: switch(ndx) { case 0: p = "userland gid_t *"; break; case 1: p = "userland gid_t *"; break; case 2: p = "userland gid_t *"; break; default: break; }; break; /* linux_chown */ case 212: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "l_uid_t"; break; case 2: p = "l_gid_t"; break; default: break; }; break; /* setuid */ case 213: switch(ndx) { case 0: p = "uid_t"; break; default: break; }; break; /* setgid */ case 214: switch(ndx) { case 0: p = "gid_t"; break; default: break; }; break; /* linux_setfsuid */ case 215: switch(ndx) { case 0: p = "l_uid_t"; break; default: break; }; break; /* linux_setfsgid */ case 216: switch(ndx) { case 0: p = "l_gid_t"; break; default: break; }; break; /* linux_pivot_root */ case 217: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland char *"; break; default: break; }; break; /* linux_mincore */ case 218: switch(ndx) { case 0: p = "l_ulong"; break; case 1: p = "l_size_t"; break; case 2: p = "userland u_char *"; break; default: break; }; break; /* madvise */ case 219: switch(ndx) { case 0: p = "userland void *"; break; case 1: p = "size_t"; break; case 2: p = "int"; break; default: break; }; break; /* linux_getdents64 */ case 220: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "userland void *"; break; case 2: p = "l_uint"; break; default: break; }; break; /* linux_fcntl64 */ case 221: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_uint"; break; case 2: p = "l_ulong"; break; default: break; }; break; /* linux_gettid */ case 224: break; /* linux_setxattr */ case 226: break; /* linux_lsetxattr */ case 227: break; /* linux_fsetxattr */ case 228: break; /* linux_getxattr */ case 229: break; /* linux_lgetxattr */ case 230: break; /* linux_fgetxattr */ case 231: break; /* linux_listxattr */ case 232: break; /* linux_llistxattr */ case 233: break; /* linux_flistxattr */ case 234: break; /* linux_removexattr */ case 235: break; /* linux_lremovexattr */ case 236: break; /* linux_fremovexattr */ case 237: break; /* linux_tkill */ case 238: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; default: break; }; break; /* linux_sys_futex */ case 240: switch(ndx) { case 0: p = "userland void *"; break; case 1: p = "int"; break; case 2: p = "uint32_t"; break; case 3: p = "userland struct l_timespec *"; break; case 4: p = "userland uint32_t *"; break; case 5: p = "uint32_t"; break; default: break; }; break; /* linux_sched_setaffinity */ case 241: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_uint"; break; case 2: p = "userland l_ulong *"; break; default: break; }; break; /* linux_sched_getaffinity */ case 242: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_uint"; break; case 2: p = "userland l_ulong *"; break; default: break; }; break; /* linux_set_thread_area */ case 243: switch(ndx) { case 0: p = "userland struct l_user_desc *"; break; default: break; }; break; /* linux_get_thread_area */ case 244: switch(ndx) { case 0: p = "userland struct l_user_desc *"; break; default: break; }; break; /* linux_fadvise64 */ case 250: switch(ndx) { case 0: p = "int"; break; case 1: p = "l_loff_t"; break; case 2: p = "l_size_t"; break; case 3: p = "int"; break; default: break; }; break; /* linux_exit_group */ case 252: switch(ndx) { case 0: p = "int"; break; default: break; }; break; /* linux_lookup_dcookie */ case 253: break; /* linux_epoll_create */ case 254: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_epoll_ctl */ case 255: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; case 3: p = "userland struct epoll_event *"; break; default: break; }; break; /* linux_epoll_wait */ case 256: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct epoll_event *"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_remap_file_pages */ case 257: break; /* linux_set_tid_address */ case 258: switch(ndx) { case 0: p = "userland int *"; break; default: break; }; break; /* linux_timer_create */ case 259: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct sigevent *"; break; case 2: p = "userland l_timer_t *"; break; default: break; }; break; /* linux_timer_settime */ case 260: switch(ndx) { case 0: p = "l_timer_t"; break; case 1: p = "l_int"; break; case 2: p = "userland const struct itimerspec *"; break; case 3: p = "userland struct itimerspec *"; break; default: break; }; break; /* linux_timer_gettime */ case 261: switch(ndx) { case 0: p = "l_timer_t"; break; case 1: p = "userland struct itimerspec *"; break; default: break; }; break; /* linux_timer_getoverrun */ case 262: switch(ndx) { case 0: p = "l_timer_t"; break; default: break; }; break; /* linux_timer_delete */ case 263: switch(ndx) { case 0: p = "l_timer_t"; break; default: break; }; break; /* linux_clock_settime */ case 264: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_clock_gettime */ case 265: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_clock_getres */ case 266: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_clock_nanosleep */ case 267: switch(ndx) { case 0: p = "clockid_t"; break; case 1: p = "int"; break; case 2: p = "userland struct l_timespec *"; break; case 3: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_statfs64 */ case 268: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "size_t"; break; case 2: p = "userland struct l_statfs64_buf *"; break; default: break; }; break; /* linux_fstatfs64 */ case 269: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "size_t"; break; case 2: p = "userland struct l_statfs64_buf *"; break; default: break; }; break; /* linux_tgkill */ case 270: switch(ndx) { case 0: p = "int"; break; case 1: p = "int"; break; case 2: p = "int"; break; default: break; }; break; /* linux_utimes */ case 271: switch(ndx) { case 0: p = "userland char *"; break; case 1: p = "userland struct l_timeval *"; break; default: break; }; break; /* linux_fadvise64_64 */ case 272: switch(ndx) { case 0: p = "int"; break; case 1: p = "l_loff_t"; break; case 2: p = "l_loff_t"; break; case 3: p = "int"; break; default: break; }; break; /* linux_mbind */ case 274: break; /* linux_get_mempolicy */ case 275: break; /* linux_set_mempolicy */ case 276: break; /* linux_mq_open */ case 277: switch(ndx) { case 0: p = "userland const char *"; break; case 1: p = "int"; break; case 2: p = "mode_t"; break; case 3: p = "userland struct mq_attr *"; break; default: break; }; break; /* linux_mq_unlink */ case 278: switch(ndx) { case 0: p = "userland const char *"; break; default: break; }; break; /* linux_mq_timedsend */ case 279: switch(ndx) { case 0: p = "l_mqd_t"; break; case 1: p = "userland const char *"; break; case 2: p = "size_t"; break; case 3: p = "unsigned int"; break; case 4: p = "userland const struct l_timespec *"; break; default: break; }; break; /* linux_mq_timedreceive */ case 280: switch(ndx) { case 0: p = "l_mqd_t"; break; case 1: p = "userland char *"; break; case 2: p = "size_t"; break; case 3: p = "unsigned int"; break; case 4: p = "userland const struct l_timespec *"; break; default: break; }; break; /* linux_mq_notify */ case 281: switch(ndx) { case 0: p = "l_mqd_t"; break; case 1: p = "userland const struct l_timespec *"; break; default: break; }; break; /* linux_mq_getsetattr */ case 282: switch(ndx) { case 0: p = "l_mqd_t"; break; case 1: p = "userland const struct mq_attr *"; break; case 2: p = "userland struct mq_attr *"; break; default: break; }; break; /* linux_kexec_load */ case 283: break; /* linux_waitid */ case 284: switch(ndx) { case 0: p = "int"; break; case 1: p = "l_pid_t"; break; case 2: p = "userland l_siginfo_t *"; break; case 3: p = "int"; break; case 4: p = "userland void *"; break; default: break; }; break; /* linux_add_key */ case 286: break; /* linux_request_key */ case 287: break; /* linux_keyctl */ case 288: break; /* linux_ioprio_set */ case 289: break; /* linux_ioprio_get */ case 290: break; /* linux_inotify_init */ case 291: break; /* linux_inotify_add_watch */ case 292: break; /* linux_inotify_rm_watch */ case 293: break; /* linux_migrate_pages */ case 294: break; /* linux_openat */ case 295: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_mkdirat */ case 296: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_mknodat */ case 297: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "l_uint"; break; default: break; }; break; /* linux_fchownat */ case 298: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_uid16_t"; break; case 3: p = "l_gid16_t"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_futimesat */ case 299: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "userland struct l_timeval *"; break; default: break; }; break; /* linux_fstatat64 */ case 300: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland char *"; break; case 2: p = "userland struct l_stat64 *"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_unlinkat */ case 301: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_renameat */ case 302: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "userland const char *"; break; default: break; }; break; /* linux_linkat */ case 303: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; case 3: p = "userland const char *"; break; case 4: p = "l_int"; break; default: break; }; break; /* linux_symlinkat */ case 304: switch(ndx) { case 0: p = "userland const char *"; break; case 1: p = "l_int"; break; case 2: p = "userland const char *"; break; default: break; }; break; /* linux_readlinkat */ case 305: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "userland char *"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_fchmodat */ case 306: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_mode_t"; break; default: break; }; break; /* linux_faccessat */ case 307: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_pselect6 */ case 308: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland l_fd_set *"; break; case 2: p = "userland l_fd_set *"; break; case 3: p = "userland l_fd_set *"; break; case 4: p = "userland struct l_timespec *"; break; case 5: p = "userland l_uintptr_t *"; break; default: break; }; break; /* linux_ppoll */ case 309: switch(ndx) { case 0: p = "userland struct pollfd *"; break; case 1: p = "uint32_t"; break; case 2: p = "userland struct l_timespec *"; break; case 3: p = "userland l_sigset_t *"; break; case 4: p = "l_size_t"; break; default: break; }; break; /* linux_unshare */ case 310: break; /* linux_set_robust_list */ case 311: switch(ndx) { case 0: p = "userland struct linux_robust_list_head *"; break; case 1: p = "l_size_t"; break; default: break; }; break; /* linux_get_robust_list */ case 312: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct linux_robust_list_head **"; break; case 2: p = "userland l_size_t *"; break; default: break; }; break; /* linux_splice */ case 313: break; /* linux_sync_file_range */ case 314: break; /* linux_tee */ case 315: break; /* linux_vmsplice */ case 316: break; /* linux_move_pages */ case 317: break; /* linux_getcpu */ case 318: break; /* linux_epoll_pwait */ case 319: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct epoll_event *"; break; case 2: p = "l_int"; break; case 3: p = "l_int"; break; case 4: p = "userland l_sigset_t *"; break; default: break; }; break; /* linux_utimensat */ case 320: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland const char *"; break; case 2: p = "userland const struct l_timespec *"; break; case 3: p = "l_int"; break; default: break; }; break; /* linux_signalfd */ case 321: break; /* linux_timerfd_create */ case 322: break; /* linux_eventfd */ case 323: switch(ndx) { case 0: p = "l_uint"; break; default: break; }; break; /* linux_fallocate */ case 324: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_loff_t"; break; case 3: p = "l_loff_t"; break; default: break; }; break; /* linux_timerfd_settime */ case 325: break; /* linux_timerfd_gettime */ case 326: break; /* linux_signalfd4 */ case 327: break; /* linux_eventfd2 */ case 328: switch(ndx) { case 0: p = "l_uint"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_epoll_create1 */ case 329: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_dup3 */ case 330: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "l_int"; break; case 2: p = "l_int"; break; default: break; }; break; /* linux_pipe2 */ case 331: switch(ndx) { case 0: p = "userland l_int *"; break; case 1: p = "l_int"; break; default: break; }; break; /* linux_inotify_init1 */ case 332: break; /* linux_preadv */ case 333: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; break; /* linux_pwritev */ case 334: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; break; - /* linux_rt_tsigqueueinfo */ + /* linux_rt_tgsigqueueinfo */ case 335: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland l_siginfo_t *"; + break; + default: + break; + }; break; /* linux_perf_event_open */ case 336: break; /* linux_recvmmsg */ case 337: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_mmsghdr *"; break; case 2: p = "l_uint"; break; case 3: p = "l_uint"; break; case 4: p = "userland struct l_timespec *"; break; default: break; }; break; /* linux_fanotify_init */ case 338: break; /* linux_fanotify_mark */ case 339: break; /* linux_prlimit64 */ case 340: switch(ndx) { case 0: p = "l_pid_t"; break; case 1: p = "l_uint"; break; case 2: p = "userland struct rlimit *"; break; case 3: p = "userland struct rlimit *"; break; default: break; }; break; /* linux_name_to_handle_at */ case 341: break; /* linux_open_by_handle_at */ case 342: break; /* linux_clock_adjtime */ case 343: break; /* linux_syncfs */ case 344: switch(ndx) { case 0: p = "l_int"; break; default: break; }; break; /* linux_sendmmsg */ case 345: switch(ndx) { case 0: p = "l_int"; break; case 1: p = "userland struct l_mmsghdr *"; break; case 2: p = "l_uint"; break; case 3: p = "l_uint"; break; default: break; }; break; /* linux_setns */ case 346: break; /* linux_process_vm_readv */ case 347: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "userland const struct iovec *"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_ulong"; + break; + default: + break; + }; break; /* linux_process_vm_writev */ case 348: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "userland const struct iovec *"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_ulong"; + break; + default: + break; + }; break; + /* linux_kcmp */ + case 349: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_finit_module */ + case 350: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sched_setattr */ + case 351: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_sched_getattr */ + case 352: + switch(ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + case 3: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_renameat2 */ + case 353: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland const char *"; + break; + case 4: + p = "unsigned int"; + break; + default: + break; + }; + break; + /* linux_seccomp */ + case 354: + switch(ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_getrandom */ + case 355: + switch(ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_memfd_create */ + case 356: + switch(ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_bpf */ + case 357: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_execveat */ + case 358: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland const char **"; + break; + case 3: + p = "userland const char **"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_socket */ + case 359: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_socketpair */ + case 360: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_bind */ + case 361: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_connect */ + case 362: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_listen */ + case 363: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_accept4 */ + case 364: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_getsockopt */ + case 365: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_uintptr_t"; + break; + case 4: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_setsockopt */ + case 366: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_uintptr_t"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_getsockname */ + case 367: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_getpeername */ + case 368: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_sendto */ + case 369: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_int"; + break; + case 4: + p = "l_uintptr_t"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sendmsg */ + case 370: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_recvfrom */ + case 371: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_int"; + break; + case 4: + p = "l_uintptr_t"; + break; + case 5: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_recvmsg */ + case 372: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_shutdown */ + case 373: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_userfaultfd */ + case 374: + switch(ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_membarrier */ + case 375: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_mlock2 */ + case 376: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_copy_file_range */ + case 377: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland l_loff_t *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland l_loff_t *"; + break; + case 4: + p = "l_size_t"; + break; + case 5: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_preadv2 */ + case 378: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pwritev2 */ + case 379: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pkey_mprotect */ + case 380: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pkey_alloc */ + case 381: + switch(ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_pkey_free */ + case 382: + switch(ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; default: break; }; if (p != NULL) strlcpy(desc, p, descsz); } static void systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) { const char *p = NULL; switch (sysnum) { #define nosys linux_nosys /* linux_exit */ case 1: if (ndx == 0 || ndx == 1) p = "void"; break; /* linux_fork */ case 2: /* read */ case 3: if (ndx == 0 || ndx == 1) p = "int"; break; /* write */ case 4: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_open */ case 5: if (ndx == 0 || ndx == 1) p = "int"; break; /* close */ case 6: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_waitpid */ case 7: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_creat */ case 8: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_link */ case 9: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_unlink */ case 10: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_execve */ case 11: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chdir */ case 12: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_time */ case 13: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mknod */ case 14: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chmod */ case 15: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lchown16 */ case 16: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_stat */ case 18: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lseek */ case 19: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getpid */ case 20: /* linux_mount */ case 21: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_oldumount */ case 22: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setuid16 */ case 23: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getuid16 */ case 24: /* linux_stime */ case 25: /* linux_ptrace */ case 26: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_alarm */ case 27: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstat */ case 28: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pause */ case 29: /* linux_utime */ case 30: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_access */ case 33: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_nice */ case 34: if (ndx == 0 || ndx == 1) p = "int"; break; /* sync */ case 36: /* linux_kill */ case 37: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rename */ case 38: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mkdir */ case 39: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rmdir */ case 40: if (ndx == 0 || ndx == 1) p = "int"; break; /* dup */ case 41: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pipe */ case 42: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_times */ case 43: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_brk */ case 45: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setgid16 */ case 46: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getgid16 */ case 47: /* linux_signal */ case 48: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_geteuid16 */ case 49: /* linux_getegid16 */ case 50: /* acct */ case 51: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_umount */ case 52: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ioctl */ case 54: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fcntl */ case 55: if (ndx == 0 || ndx == 1) p = "int"; break; /* setpgid */ case 57: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_olduname */ case 59: /* umask */ case 60: if (ndx == 0 || ndx == 1) p = "int"; break; /* chroot */ case 61: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ustat */ case 62: if (ndx == 0 || ndx == 1) p = "int"; break; /* dup2 */ case 63: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getppid */ case 64: /* getpgrp */ case 65: /* setsid */ case 66: /* linux_sigaction */ case 67: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sgetmask */ case 68: /* linux_ssetmask */ case 69: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setreuid16 */ case 70: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setregid16 */ case 71: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigsuspend */ case 72: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigpending */ case 73: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sethostname */ case 74: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setrlimit */ case 75: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_old_getrlimit */ case 76: if (ndx == 0 || ndx == 1) p = "int"; break; /* getrusage */ case 77: if (ndx == 0 || ndx == 1) p = "int"; break; /* gettimeofday */ case 78: if (ndx == 0 || ndx == 1) p = "int"; break; /* settimeofday */ case 79: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getgroups16 */ case 80: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setgroups16 */ case 81: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_old_select */ case 82: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_symlink */ case 83: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lstat */ case 84: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_readlink */ case 85: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_uselib */ case 86: if (ndx == 0 || ndx == 1) p = "int"; break; /* swapon */ case 87: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_reboot */ case 88: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_readdir */ case 89: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mmap */ case 90: if (ndx == 0 || ndx == 1) p = "int"; break; /* munmap */ case 91: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_truncate */ case 92: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ftruncate */ case 93: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchmod */ case 94: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchown */ case 95: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getpriority */ case 96: if (ndx == 0 || ndx == 1) p = "int"; break; /* setpriority */ case 97: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_statfs */ case 99: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstatfs */ case 100: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ioperm */ case 101: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_socketcall */ case 102: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_syslog */ case 103: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setitimer */ case 104: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getitimer */ case 105: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newstat */ case 106: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newlstat */ case 107: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newfstat */ case 108: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_uname */ case 109: /* linux_iopl */ case 110: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_vhangup */ case 111: /* linux_vm86old */ case 113: /* linux_wait4 */ case 114: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_swapoff */ case 115: /* linux_sysinfo */ case 116: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ipc */ case 117: if (ndx == 0 || ndx == 1) p = "int"; break; /* fsync */ case 118: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigreturn */ case 119: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clone */ case 120: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setdomainname */ case 121: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_newuname */ case 122: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_modify_ldt */ case 123: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_adjtimex */ case 124: /* linux_mprotect */ case 125: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigprocmask */ case 126: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_create_module */ case 127: /* linux_init_module */ case 128: /* linux_delete_module */ case 129: /* linux_get_kernel_syms */ case 130: /* linux_quotactl */ case 131: /* getpgid */ case 132: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchdir */ case 133: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_bdflush */ case 134: /* linux_sysfs */ case 135: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_personality */ case 136: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsuid16 */ case 138: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsgid16 */ case 139: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_llseek */ case 140: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getdents */ case 141: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_select */ case 142: if (ndx == 0 || ndx == 1) p = "int"; break; /* flock */ case 143: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_msync */ case 144: if (ndx == 0 || ndx == 1) p = "int"; break; /* readv */ case 145: if (ndx == 0 || ndx == 1) p = "int"; break; /* writev */ case 146: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getsid */ case 147: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fdatasync */ case 148: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sysctl */ case 149: if (ndx == 0 || ndx == 1) p = "int"; break; /* mlock */ case 150: if (ndx == 0 || ndx == 1) p = "int"; break; /* munlock */ case 151: if (ndx == 0 || ndx == 1) p = "int"; break; /* mlockall */ case 152: if (ndx == 0 || ndx == 1) p = "int"; break; /* munlockall */ case 153: /* linux_sched_setparam */ case 154: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_getparam */ case 155: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_setscheduler */ case 156: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_getscheduler */ case 157: if (ndx == 0 || ndx == 1) p = "int"; break; /* sched_yield */ case 158: /* linux_sched_get_priority_max */ case 159: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_get_priority_min */ case 160: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_rr_get_interval */ case 161: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_nanosleep */ case 162: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mremap */ case 163: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setresuid16 */ case 164: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getresuid16 */ case 165: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_vm86 */ case 166: /* linux_query_module */ case 167: /* poll */ case 168: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_nfsservctl */ case 169: /* linux_setresgid16 */ case 170: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getresgid16 */ case 171: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_prctl */ case 172: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigreturn */ case 173: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigaction */ case 174: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigprocmask */ case 175: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigpending */ case 176: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigtimedwait */ case 177: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigqueueinfo */ case 178: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_rt_sigsuspend */ case 179: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pread */ case 180: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pwrite */ case 181: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chown16 */ case 182: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getcwd */ case 183: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_capget */ case 184: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_capset */ case 185: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sigaltstack */ case 186: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sendfile */ case 187: /* linux_vfork */ case 190: /* linux_getrlimit */ case 191: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mmap2 */ case 192: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_truncate64 */ case 193: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ftruncate64 */ case 194: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_stat64 */ case 195: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lstat64 */ case 196: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstat64 */ case 197: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lchown */ case 198: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getuid */ case 199: /* linux_getgid */ case 200: /* geteuid */ case 201: /* getegid */ case 202: /* setreuid */ case 203: if (ndx == 0 || ndx == 1) p = "int"; break; /* setregid */ case 204: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getgroups */ case 205: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setgroups */ case 206: if (ndx == 0 || ndx == 1) p = "int"; break; /* fchown */ case 207: /* setresuid */ case 208: if (ndx == 0 || ndx == 1) p = "int"; break; /* getresuid */ case 209: if (ndx == 0 || ndx == 1) p = "int"; break; /* setresgid */ case 210: if (ndx == 0 || ndx == 1) p = "int"; break; /* getresgid */ case 211: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_chown */ case 212: if (ndx == 0 || ndx == 1) p = "int"; break; /* setuid */ case 213: if (ndx == 0 || ndx == 1) p = "int"; break; /* setgid */ case 214: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsuid */ case 215: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setfsgid */ case 216: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pivot_root */ case 217: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mincore */ case 218: if (ndx == 0 || ndx == 1) p = "int"; break; /* madvise */ case 219: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_getdents64 */ case 220: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fcntl64 */ case 221: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_gettid */ case 224: /* linux_setxattr */ case 226: /* linux_lsetxattr */ case 227: /* linux_fsetxattr */ case 228: /* linux_getxattr */ case 229: /* linux_lgetxattr */ case 230: /* linux_fgetxattr */ case 231: /* linux_listxattr */ case 232: /* linux_llistxattr */ case 233: /* linux_flistxattr */ case 234: /* linux_removexattr */ case 235: /* linux_lremovexattr */ case 236: /* linux_fremovexattr */ case 237: /* linux_tkill */ case 238: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sys_futex */ case 240: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_setaffinity */ case 241: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sched_getaffinity */ case 242: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_set_thread_area */ case 243: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_get_thread_area */ case 244: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fadvise64 */ case 250: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_exit_group */ case 252: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_lookup_dcookie */ case 253: /* linux_epoll_create */ case 254: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_ctl */ case 255: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_wait */ case 256: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_remap_file_pages */ case 257: /* linux_set_tid_address */ case 258: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_create */ case 259: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_settime */ case 260: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_gettime */ case 261: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_getoverrun */ case 262: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timer_delete */ case 263: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_settime */ case 264: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_gettime */ case 265: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_getres */ case 266: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_clock_nanosleep */ case 267: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_statfs64 */ case 268: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstatfs64 */ case 269: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_tgkill */ case 270: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_utimes */ case 271: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fadvise64_64 */ case 272: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mbind */ case 274: /* linux_get_mempolicy */ case 275: /* linux_set_mempolicy */ case 276: /* linux_mq_open */ case 277: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mq_unlink */ case 278: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mq_timedsend */ case 279: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mq_timedreceive */ case 280: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mq_notify */ case 281: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mq_getsetattr */ case 282: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_kexec_load */ case 283: /* linux_waitid */ case 284: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_add_key */ case 286: /* linux_request_key */ case 287: /* linux_keyctl */ case 288: /* linux_ioprio_set */ case 289: /* linux_ioprio_get */ case 290: /* linux_inotify_init */ case 291: /* linux_inotify_add_watch */ case 292: /* linux_inotify_rm_watch */ case 293: /* linux_migrate_pages */ case 294: /* linux_openat */ case 295: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mkdirat */ case 296: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_mknodat */ case 297: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fchownat */ case 298: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_futimesat */ case 299: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fstatat64 */ case 300: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_unlinkat */ case 301: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_renameat */ case 302: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_linkat */ case 303: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_symlinkat */ case 304: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_readlinkat */ case 305: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fchmodat */ case 306: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_faccessat */ case 307: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pselect6 */ case 308: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_ppoll */ case 309: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_unshare */ case 310: /* linux_set_robust_list */ case 311: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_get_robust_list */ case 312: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_splice */ case 313: /* linux_sync_file_range */ case 314: /* linux_tee */ case 315: /* linux_vmsplice */ case 316: /* linux_move_pages */ case 317: /* linux_getcpu */ case 318: /* linux_epoll_pwait */ case 319: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_utimensat */ case 320: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_signalfd */ case 321: /* linux_timerfd_create */ case 322: /* linux_eventfd */ case 323: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fallocate */ case 324: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_timerfd_settime */ case 325: /* linux_timerfd_gettime */ case 326: /* linux_signalfd4 */ case 327: /* linux_eventfd2 */ case 328: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_epoll_create1 */ case 329: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_dup3 */ case 330: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_pipe2 */ case 331: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_inotify_init1 */ case 332: /* linux_preadv */ case 333: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_pwritev */ case 334: - /* linux_rt_tsigqueueinfo */ + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_tgsigqueueinfo */ case 335: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_perf_event_open */ case 336: /* linux_recvmmsg */ case 337: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_fanotify_init */ case 338: /* linux_fanotify_mark */ case 339: /* linux_prlimit64 */ case 340: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_name_to_handle_at */ case 341: /* linux_open_by_handle_at */ case 342: /* linux_clock_adjtime */ case 343: /* linux_syncfs */ case 344: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_sendmmsg */ case 345: if (ndx == 0 || ndx == 1) p = "int"; break; /* linux_setns */ case 346: /* linux_process_vm_readv */ case 347: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_process_vm_writev */ case 348: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_kcmp */ + case 349: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_finit_module */ + case 350: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_setattr */ + case 351: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_getattr */ + case 352: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_renameat2 */ + case 353: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_seccomp */ + case 354: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getrandom */ + case 355: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_memfd_create */ + case 356: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_bpf */ + case 357: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_execveat */ + case 358: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_socket */ + case 359: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_socketpair */ + case 360: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_bind */ + case 361: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_connect */ + case 362: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_listen */ + case 363: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_accept4 */ + case 364: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getsockopt */ + case 365: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setsockopt */ + case 366: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getsockname */ + case 367: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getpeername */ + case 368: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sendto */ + case 369: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sendmsg */ + case 370: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_recvfrom */ + case 371: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_recvmsg */ + case 372: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_shutdown */ + case 373: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_userfaultfd */ + case 374: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_membarrier */ + case 375: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mlock2 */ + case 376: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_copy_file_range */ + case 377: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_preadv2 */ + case 378: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pwritev2 */ + case 379: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_mprotect */ + case 380: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_alloc */ + case 381: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_free */ + case 382: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; if (p != NULL) strlcpy(desc, p, descsz); } Index: projects/ipsec/sys/i386/linux/syscalls.master =================================================================== --- projects/ipsec/sys/i386/linux/syscalls.master (revision 313312) +++ projects/ipsec/sys/i386/linux/syscalls.master (revision 313313) @@ -1,592 +1,695 @@ $FreeBSD$ ; @(#)syscalls.master 8.1 (Berkeley) 7/19/93 ; System call name/number master file (or rather, slave, from LINUX). ; Processed to create linux_sysent.c, linux_proto.h and linux_syscall.h. ; Columns: number audit type nargs name alt{name,tag,rtyp}/comments ; number system call number, must be in order ; audit the audit event associated with the system call ; A value of AUE_NULL means no auditing, but it also means that ; there is no audit event for the call at this time. For the ; case where the event exists, but we don't want auditing, the ; event should be #defined to AUE_NULL in audit_kevents.h. -; type one of STD, OBSOL, UNIMPL +; type one of STD, NOPROTO, UNIMPL ; name psuedo-prototype of syscall routine ; If one of the following alts is different, then all appear: ; altname name of system call if different ; alttag name of args struct tag if different from [o]`name'"_args" ; altrtyp return type if not int (bogus - syscalls always return int) -; for UNIMPL/OBSOL, name continues with comments +; for UNIMPL, name continues with comments ; types: ; STD always included -; OBSOL obsolete, not included in system, only specifies name ; UNIMPL not implemented, placeholder only +; NOPROTO same as STD except do not create structure or +; function prototype in sys/sysproto.h. Does add a +; definition to syscall.h besides adding a sysent. #include #include #include #include #include #include ; Isn't pretty, but there seems to be no other way to trap nosys #define nosys linux_nosys ; #ifdef's, etc. may be included, and are copied to the output files. 0 AUE_NULL UNIMPL setup 1 AUE_EXIT STD { void linux_exit(int rval); } 2 AUE_FORK STD { int linux_fork(void); } 3 AUE_NULL NOPROTO { int read(int fd, char *buf, \ u_int nbyte); } 4 AUE_NULL NOPROTO { int write(int fd, char *buf, \ u_int nbyte); } 5 AUE_OPEN_RWTC STD { int linux_open(char *path, l_int flags, \ l_int mode); } 6 AUE_CLOSE NOPROTO { int close(int fd); } 7 AUE_WAIT4 STD { int linux_waitpid(l_pid_t pid, \ l_int *status, l_int options); } 8 AUE_CREAT STD { int linux_creat(char *path, \ l_int mode); } 9 AUE_LINK STD { int linux_link(char *path, char *to); } 10 AUE_UNLINK STD { int linux_unlink(char *path); } 11 AUE_EXECVE STD { int linux_execve(char *path, char **argp, \ char **envp); } 12 AUE_CHDIR STD { int linux_chdir(char *path); } 13 AUE_NULL STD { int linux_time(l_time_t *tm); } 14 AUE_MKNOD STD { int linux_mknod(char *path, l_int mode, \ l_dev_t dev); } 15 AUE_CHMOD STD { int linux_chmod(char *path, \ l_mode_t mode); } 16 AUE_LCHOWN STD { int linux_lchown16(char *path, \ l_uid16_t uid, l_gid16_t gid); } 17 AUE_NULL UNIMPL break 18 AUE_STAT STD { int linux_stat(char *path, \ struct linux_stat *up); } 19 AUE_LSEEK STD { int linux_lseek(l_uint fdes, l_off_t off, \ l_int whence); } 20 AUE_GETPID STD { int linux_getpid(void); } 21 AUE_MOUNT STD { int linux_mount(char *specialfile, \ char *dir, char *filesystemtype, \ l_ulong rwflag, void *data); } 22 AUE_UMOUNT STD { int linux_oldumount(char *path); } 23 AUE_SETUID STD { int linux_setuid16(l_uid16_t uid); } 24 AUE_GETUID STD { int linux_getuid16(void); } 25 AUE_SETTIMEOFDAY STD { int linux_stime(void); } 26 AUE_PTRACE STD { int linux_ptrace(l_long req, l_long pid, \ l_long addr, l_long data); } 27 AUE_NULL STD { int linux_alarm(l_uint secs); } 28 AUE_FSTAT STD { int linux_fstat(l_uint fd, \ struct linux_stat *up); } 29 AUE_NULL STD { int linux_pause(void); } 30 AUE_UTIME STD { int linux_utime(char *fname, \ struct l_utimbuf *times); } 31 AUE_NULL UNIMPL stty 32 AUE_NULL UNIMPL gtty 33 AUE_ACCESS STD { int linux_access(char *path, l_int amode); } 34 AUE_NICE STD { int linux_nice(l_int inc); } 35 AUE_NULL UNIMPL ftime 36 AUE_SYNC NOPROTO { int sync(void); } 37 AUE_KILL STD { int linux_kill(l_int pid, l_int signum); } 38 AUE_RENAME STD { int linux_rename(char *from, char *to); } 39 AUE_MKDIR STD { int linux_mkdir(char *path, l_int mode); } 40 AUE_RMDIR STD { int linux_rmdir(char *path); } 41 AUE_DUP NOPROTO { int dup(u_int fd); } 42 AUE_PIPE STD { int linux_pipe(l_int *pipefds); } 43 AUE_NULL STD { int linux_times(struct l_times_argv *buf); } 44 AUE_NULL UNIMPL prof 45 AUE_NULL STD { int linux_brk(l_ulong dsend); } 46 AUE_SETGID STD { int linux_setgid16(l_gid16_t gid); } 47 AUE_GETGID STD { int linux_getgid16(void); } 48 AUE_NULL STD { int linux_signal(l_int sig, \ void *handler); } 49 AUE_GETEUID STD { int linux_geteuid16(void); } 50 AUE_GETEGID STD { int linux_getegid16(void); } 51 AUE_ACCT NOPROTO { int acct(char *path); } 52 AUE_UMOUNT STD { int linux_umount(char *path, l_int flags); } 53 AUE_NULL UNIMPL lock 54 AUE_IOCTL STD { int linux_ioctl(l_uint fd, l_uint cmd, \ l_ulong arg); } 55 AUE_FCNTL STD { int linux_fcntl(l_uint fd, l_uint cmd, \ l_ulong arg); } 56 AUE_NULL UNIMPL mpx 57 AUE_SETPGRP NOPROTO { int setpgid(int pid, int pgid); } 58 AUE_NULL UNIMPL ulimit 59 AUE_NULL STD { int linux_olduname(void); } 60 AUE_UMASK NOPROTO { int umask(int newmask); } 61 AUE_CHROOT NOPROTO { int chroot(char *path); } 62 AUE_NULL STD { int linux_ustat(l_dev_t dev, \ struct l_ustat *ubuf); } 63 AUE_DUP2 NOPROTO { int dup2(u_int from, u_int to); } 64 AUE_GETPPID STD { int linux_getppid(void); } 65 AUE_GETPGRP NOPROTO { int getpgrp(void); } 66 AUE_SETSID NOPROTO { int setsid(void); } 67 AUE_NULL STD { int linux_sigaction(l_int sig, \ l_osigaction_t *nsa, \ l_osigaction_t *osa); } 68 AUE_NULL STD { int linux_sgetmask(void); } 69 AUE_NULL STD { int linux_ssetmask(l_osigset_t mask); } 70 AUE_SETREUID STD { int linux_setreuid16(l_uid16_t ruid, \ l_uid16_t euid); } 71 AUE_SETREGID STD { int linux_setregid16(l_gid16_t rgid, \ l_gid16_t egid); } 72 AUE_NULL STD { int linux_sigsuspend(l_int hist0, \ l_int hist1, l_osigset_t mask); } 73 AUE_NULL STD { int linux_sigpending(l_osigset_t *mask); } 74 AUE_SYSCTL STD { int linux_sethostname(char *hostname, \ u_int len); } 75 AUE_SETRLIMIT STD { int linux_setrlimit(l_uint resource, \ struct l_rlimit *rlim); } 76 AUE_GETRLIMIT STD { int linux_old_getrlimit(l_uint resource, \ struct l_rlimit *rlim); } 77 AUE_GETRUSAGE NOPROTO { int getrusage(int who, \ struct rusage *rusage); } 78 AUE_NULL NOPROTO { int gettimeofday( \ struct timeval *tp, \ struct timezone *tzp); } 79 AUE_SETTIMEOFDAY NOPROTO { int settimeofday( \ struct timeval *tv, \ struct timezone *tzp); } 80 AUE_GETGROUPS STD { int linux_getgroups16(l_uint gidsetsize, \ l_gid16_t *gidset); } 81 AUE_SETGROUPS STD { int linux_setgroups16(l_uint gidsetsize, \ l_gid16_t *gidset); } 82 AUE_SELECT STD { int linux_old_select( \ struct l_old_select_argv *ptr); } 83 AUE_SYMLINK STD { int linux_symlink(char *path, char *to); } ; 84: oldlstat 84 AUE_LSTAT STD { int linux_lstat(char *path, struct l_stat *up); } 85 AUE_READLINK STD { int linux_readlink(char *name, char *buf, \ l_int count); } 86 AUE_USELIB STD { int linux_uselib(char *library); } 87 AUE_SWAPON NOPROTO { int swapon(char *name); } 88 AUE_REBOOT STD { int linux_reboot(l_int magic1, \ l_int magic2, l_uint cmd, void *arg); } ; 89: old_readdir 89 AUE_GETDIRENTRIES STD { int linux_readdir(l_uint fd, \ struct l_dirent *dent, l_uint count); } ; 90: old_mmap 90 AUE_MMAP STD { int linux_mmap(struct l_mmap_argv *ptr); } 91 AUE_MUNMAP NOPROTO { int munmap(caddr_t addr, int len); } 92 AUE_TRUNCATE STD { int linux_truncate(char *path, \ l_ulong length); } 93 AUE_FTRUNCATE STD { int linux_ftruncate(int fd, long length); } 94 AUE_FCHMOD NOPROTO { int fchmod(int fd, int mode); } 95 AUE_FCHOWN NOPROTO { int fchown(int fd, int uid, int gid); } 96 AUE_GETPRIORITY STD { int linux_getpriority(int which, int who); } 97 AUE_SETPRIORITY NOPROTO { int setpriority(int which, int who, \ int prio); } 98 AUE_PROFILE UNIMPL profil 99 AUE_STATFS STD { int linux_statfs(char *path, \ struct l_statfs_buf *buf); } 100 AUE_FSTATFS STD { int linux_fstatfs(l_uint fd, \ struct l_statfs_buf *buf); } 101 AUE_NULL STD { int linux_ioperm(l_ulong start, \ l_ulong length, l_int enable); } 102 AUE_NULL STD { int linux_socketcall(l_int what, \ l_ulong args); } 103 AUE_NULL STD { int linux_syslog(l_int type, char *buf, \ l_int len); } 104 AUE_SETITIMER STD { int linux_setitimer(l_int which, \ struct l_itimerval *itv, \ struct l_itimerval *oitv); } 105 AUE_GETITIMER STD { int linux_getitimer(l_int which, \ struct l_itimerval *itv); } 106 AUE_STAT STD { int linux_newstat(char *path, \ struct l_newstat *buf); } 107 AUE_LSTAT STD { int linux_newlstat(char *path, \ struct l_newstat *buf); } 108 AUE_FSTAT STD { int linux_newfstat(l_uint fd, \ struct l_newstat *buf); } ; 109: olduname 109 AUE_NULL STD { int linux_uname(void); } 110 AUE_NULL STD { int linux_iopl(l_int level); } 111 AUE_NULL STD { int linux_vhangup(void); } 112 AUE_NULL UNIMPL idle 113 AUE_NULL STD { int linux_vm86old(void); } 114 AUE_WAIT4 STD { int linux_wait4(l_pid_t pid, \ l_int *status, l_int options, \ void *rusage); } 115 AUE_SWAPOFF STD { int linux_swapoff(void); } 116 AUE_NULL STD { int linux_sysinfo(struct l_sysinfo *info); } 117 AUE_NULL STD { int linux_ipc(l_uint what, l_int arg1, \ l_int arg2, l_int arg3, void *ptr, \ l_long arg5); } 118 AUE_FSYNC NOPROTO { int fsync(int fd); } 119 AUE_SIGRETURN STD { int linux_sigreturn( \ struct l_sigframe *sfp); } 120 AUE_RFORK STD { int linux_clone(l_int flags, void *stack, \ void *parent_tidptr, void *tls, void * child_tidptr); } 121 AUE_SYSCTL STD { int linux_setdomainname(char *name, \ int len); } 122 AUE_NULL STD { int linux_newuname( \ struct l_new_utsname *buf); } 123 AUE_NULL STD { int linux_modify_ldt(l_int func, \ void *ptr, l_ulong bytecount); } 124 AUE_ADJTIME STD { int linux_adjtimex(void); } 125 AUE_MPROTECT STD { int linux_mprotect(caddr_t addr, int len, \ int prot); } 126 AUE_SIGPROCMASK STD { int linux_sigprocmask(l_int how, \ l_osigset_t *mask, l_osigset_t *omask); } 127 AUE_NULL STD { int linux_create_module(void); } 128 AUE_NULL STD { int linux_init_module(void); } 129 AUE_NULL STD { int linux_delete_module(void); } 130 AUE_NULL STD { int linux_get_kernel_syms(void); } 131 AUE_QUOTACTL STD { int linux_quotactl(void); } 132 AUE_GETPGID NOPROTO { int getpgid(int pid); } 133 AUE_FCHDIR NOPROTO { int fchdir(int fd); } 134 AUE_BDFLUSH STD { int linux_bdflush(void); } 135 AUE_NULL STD { int linux_sysfs(l_int option, \ l_ulong arg1, l_ulong arg2); } 136 AUE_PERSONALITY STD { int linux_personality(l_uint per); } 137 AUE_NULL UNIMPL afs_syscall 138 AUE_SETFSUID STD { int linux_setfsuid16(l_uid16_t uid); } 139 AUE_SETFSGID STD { int linux_setfsgid16(l_gid16_t gid); } 140 AUE_LSEEK STD { int linux_llseek(l_int fd, l_ulong ohigh, \ l_ulong olow, l_loff_t *res, \ l_uint whence); } 141 AUE_GETDIRENTRIES STD { int linux_getdents(l_uint fd, \ void *dent, l_uint count); } ; 142: newselect 142 AUE_SELECT STD { int linux_select(l_int nfds, \ l_fd_set *readfds, l_fd_set *writefds, \ l_fd_set *exceptfds, \ struct l_timeval *timeout); } 143 AUE_FLOCK NOPROTO { int flock(int fd, int how); } 144 AUE_MSYNC STD { int linux_msync(l_ulong addr, \ l_size_t len, l_int fl); } 145 AUE_READV NOPROTO { int readv(int fd, struct iovec *iovp, \ u_int iovcnt); } 146 AUE_WRITEV NOPROTO { int writev(int fd, struct iovec *iovp, \ u_int iovcnt); } 147 AUE_GETSID STD { int linux_getsid(l_pid_t pid); } 148 AUE_NULL STD { int linux_fdatasync(l_uint fd); } 149 AUE_SYSCTL STD { int linux_sysctl( \ struct l___sysctl_args *args); } 150 AUE_MLOCK NOPROTO { int mlock(const void *addr, size_t len); } 151 AUE_MUNLOCK NOPROTO { int munlock(const void *addr, size_t len); } 152 AUE_MLOCKALL NOPROTO { int mlockall(int how); } 153 AUE_MUNLOCKALL NOPROTO { int munlockall(void); } 154 AUE_SCHED_SETPARAM STD { int linux_sched_setparam(l_pid_t pid, \ struct sched_param *param); } 155 AUE_SCHED_GETPARAM STD { int linux_sched_getparam(l_pid_t pid, \ struct sched_param *param); } 156 AUE_SCHED_SETSCHEDULER STD { int linux_sched_setscheduler( \ l_pid_t pid, l_int policy, \ struct sched_param *param); } 157 AUE_SCHED_GETSCHEDULER STD { int linux_sched_getscheduler( \ l_pid_t pid); } 158 AUE_NULL NOPROTO { int sched_yield(void); } 159 AUE_SCHED_GET_PRIORITY_MAX STD { int linux_sched_get_priority_max( \ l_int policy); } 160 AUE_SCHED_GET_PRIORITY_MIN STD { int linux_sched_get_priority_min( \ l_int policy); } 161 AUE_SCHED_RR_GET_INTERVAL STD { int linux_sched_rr_get_interval( \ l_pid_t pid, struct l_timespec *interval); } 162 AUE_NULL STD { int linux_nanosleep( \ const struct l_timespec *rqtp, \ struct l_timespec *rmtp); } 163 AUE_NULL STD { int linux_mremap(l_ulong addr, \ l_ulong old_len, l_ulong new_len, \ l_ulong flags, l_ulong new_addr); } 164 AUE_SETRESUID STD { int linux_setresuid16(l_uid16_t ruid, \ l_uid16_t euid, l_uid16_t suid); } 165 AUE_GETRESUID STD { int linux_getresuid16(l_uid16_t *ruid, \ l_uid16_t *euid, l_uid16_t *suid); } 166 AUE_NULL STD { int linux_vm86(void); } 167 AUE_NULL STD { int linux_query_module(void); } 168 AUE_POLL NOPROTO { int poll(struct pollfd* fds, \ unsigned int nfds, long timeout); } 169 AUE_NULL STD { int linux_nfsservctl(void); } 170 AUE_SETRESGID STD { int linux_setresgid16(l_gid16_t rgid, \ l_gid16_t egid, l_gid16_t sgid); } 171 AUE_GETRESGID STD { int linux_getresgid16(l_gid16_t *rgid, \ l_gid16_t *egid, l_gid16_t *sgid); } 172 AUE_PRCTL STD { int linux_prctl(l_int option, l_int arg2, l_int arg3, \ l_int arg4, l_int arg5); } 173 AUE_NULL STD { int linux_rt_sigreturn( \ struct l_ucontext *ucp); } 174 AUE_NULL STD { int linux_rt_sigaction(l_int sig, \ l_sigaction_t *act, l_sigaction_t *oact, \ l_size_t sigsetsize); } 175 AUE_NULL STD { int linux_rt_sigprocmask(l_int how, \ l_sigset_t *mask, l_sigset_t *omask, \ l_size_t sigsetsize); } 176 AUE_NULL STD { int linux_rt_sigpending(l_sigset_t *set, \ l_size_t sigsetsize); } 177 AUE_NULL STD { int linux_rt_sigtimedwait(l_sigset_t *mask, \ l_siginfo_t *ptr, \ struct l_timeval *timeout, \ l_size_t sigsetsize); } 178 AUE_NULL STD { int linux_rt_sigqueueinfo(l_pid_t pid, l_int sig, \ l_siginfo_t *info); } 179 AUE_NULL STD { int linux_rt_sigsuspend( \ l_sigset_t *newset, \ l_size_t sigsetsize); } 180 AUE_PREAD STD { int linux_pread(l_uint fd, char *buf, \ l_size_t nbyte, l_loff_t offset); } 181 AUE_PWRITE STD { int linux_pwrite(l_uint fd, char *buf, \ l_size_t nbyte, l_loff_t offset); } 182 AUE_CHOWN STD { int linux_chown16(char *path, \ l_uid16_t uid, l_gid16_t gid); } 183 AUE_GETCWD STD { int linux_getcwd(char *buf, \ l_ulong bufsize); } 184 AUE_CAPGET STD { int linux_capget(struct l_user_cap_header *hdrp, \ struct l_user_cap_data *datap); } 185 AUE_CAPSET STD { int linux_capset(struct l_user_cap_header *hdrp, \ struct l_user_cap_data *datap); } 186 AUE_NULL STD { int linux_sigaltstack(l_stack_t *uss, \ l_stack_t *uoss); } 187 AUE_SENDFILE STD { int linux_sendfile(void); } 188 AUE_GETPMSG UNIMPL getpmsg 189 AUE_PUTPMSG UNIMPL putpmsg 190 AUE_VFORK STD { int linux_vfork(void); } ; 191: ugetrlimit 191 AUE_GETRLIMIT STD { int linux_getrlimit(l_uint resource, \ struct l_rlimit *rlim); } 192 AUE_MMAP STD { int linux_mmap2(l_ulong addr, l_ulong len, \ l_ulong prot, l_ulong flags, l_ulong fd, \ l_ulong pgoff); } 193 AUE_TRUNCATE STD { int linux_truncate64(char *path, \ l_loff_t length); } 194 AUE_FTRUNCATE STD { int linux_ftruncate64(l_uint fd, \ l_loff_t length); } 195 AUE_STAT STD { int linux_stat64(const char *filename, \ struct l_stat64 *statbuf); } 196 AUE_LSTAT STD { int linux_lstat64(const char *filename, \ struct l_stat64 *statbuf); } 197 AUE_FSTAT STD { int linux_fstat64(l_int fd, \ struct l_stat64 *statbuf); } 198 AUE_LCHOWN STD { int linux_lchown(char *path, l_uid_t uid, \ l_gid_t gid); } 199 AUE_GETUID STD { int linux_getuid(void); } 200 AUE_GETGID STD { int linux_getgid(void); } 201 AUE_GETEUID NOPROTO { int geteuid(void); } 202 AUE_GETEGID NOPROTO { int getegid(void); } 203 AUE_SETREUID NOPROTO { int setreuid(uid_t ruid, uid_t euid); } 204 AUE_SETREGID NOPROTO { int setregid(gid_t rgid, gid_t egid); } 205 AUE_GETGROUPS STD { int linux_getgroups(l_int gidsetsize, \ l_gid_t *grouplist); } 206 AUE_SETGROUPS STD { int linux_setgroups(l_int gidsetsize, \ l_gid_t *grouplist); } 207 AUE_FCHOWN NODEF fchown fchown fchown_args int 208 AUE_SETRESUID NOPROTO { int setresuid(uid_t ruid, uid_t euid, \ uid_t suid); } 209 AUE_GETRESUID NOPROTO { int getresuid(uid_t *ruid, uid_t *euid, \ uid_t *suid); } 210 AUE_SETRESGID NOPROTO { int setresgid(gid_t rgid, gid_t egid, \ gid_t sgid); } 211 AUE_GETRESGID NOPROTO { int getresgid(gid_t *rgid, gid_t *egid, \ gid_t *sgid); } 212 AUE_CHOWN STD { int linux_chown(char *path, l_uid_t uid, \ l_gid_t gid); } 213 AUE_SETUID NOPROTO { int setuid(uid_t uid); } 214 AUE_SETGID NOPROTO { int setgid(gid_t gid); } 215 AUE_SETFSUID STD { int linux_setfsuid(l_uid_t uid); } 216 AUE_SETFSGID STD { int linux_setfsgid(l_gid_t gid); } 217 AUE_PIVOT_ROOT STD { int linux_pivot_root(char *new_root, \ char *put_old); } 218 AUE_MINCORE STD { int linux_mincore(l_ulong start, \ l_size_t len, u_char *vec); } 219 AUE_MADVISE NOPROTO { int madvise(void *addr, size_t len, \ int behav); } 220 AUE_GETDIRENTRIES STD { int linux_getdents64(l_uint fd, \ void *dirent, l_uint count); } 221 AUE_FCNTL STD { int linux_fcntl64(l_uint fd, l_uint cmd, \ l_ulong arg); } 222 AUE_NULL UNIMPL 223 AUE_NULL UNIMPL 224 AUE_NULL STD { long linux_gettid(void); } 225 AUE_NULL UNIMPL linux_readahead 226 AUE_NULL STD { int linux_setxattr(void); } 227 AUE_NULL STD { int linux_lsetxattr(void); } 228 AUE_NULL STD { int linux_fsetxattr(void); } 229 AUE_NULL STD { int linux_getxattr(void); } 230 AUE_NULL STD { int linux_lgetxattr(void); } 231 AUE_NULL STD { int linux_fgetxattr(void); } 232 AUE_NULL STD { int linux_listxattr(void); } 233 AUE_NULL STD { int linux_llistxattr(void); } 234 AUE_NULL STD { int linux_flistxattr(void); } 235 AUE_NULL STD { int linux_removexattr(void); } 236 AUE_NULL STD { int linux_lremovexattr(void); } 237 AUE_NULL STD { int linux_fremovexattr(void); } 238 AUE_NULL STD { int linux_tkill(int tid, int sig); } 239 AUE_SENDFILE UNIMPL linux_sendfile64 240 AUE_NULL STD { int linux_sys_futex(void *uaddr, int op, uint32_t val, \ struct l_timespec *timeout, uint32_t *uaddr2, uint32_t val3); } 241 AUE_NULL STD { int linux_sched_setaffinity(l_pid_t pid, l_uint len, \ l_ulong *user_mask_ptr); } 242 AUE_NULL STD { int linux_sched_getaffinity(l_pid_t pid, l_uint len, \ l_ulong *user_mask_ptr); } 243 AUE_NULL STD { int linux_set_thread_area(struct l_user_desc *desc); } 244 AUE_NULL STD { int linux_get_thread_area(struct l_user_desc *desc); } 245 AUE_NULL UNIMPL linux_io_setup 246 AUE_NULL UNIMPL linux_io_destroy 247 AUE_NULL UNIMPL linux_io_getevents 248 AUE_NULL UNIMPL linux_io_submit 249 AUE_NULL UNIMPL linux_io_cancel 250 AUE_NULL STD { int linux_fadvise64(int fd, l_loff_t offset, \ l_size_t len, int advice); } 251 AUE_NULL UNIMPL 252 AUE_EXIT STD { int linux_exit_group(int error_code); } 253 AUE_NULL STD { int linux_lookup_dcookie(void); } 254 AUE_NULL STD { int linux_epoll_create(l_int size); } 255 AUE_NULL STD { int linux_epoll_ctl(l_int epfd, l_int op, l_int fd, \ struct epoll_event *event); } 256 AUE_NULL STD { int linux_epoll_wait(l_int epfd, struct epoll_event *events, \ l_int maxevents, l_int timeout); } 257 AUE_NULL STD { int linux_remap_file_pages(void); } 258 AUE_NULL STD { int linux_set_tid_address(int *tidptr); } 259 AUE_NULL STD { int linux_timer_create(clockid_t clock_id, \ struct sigevent *evp, l_timer_t *timerid); } 260 AUE_NULL STD { int linux_timer_settime(l_timer_t timerid, l_int flags, \ const struct itimerspec *new, struct itimerspec *old); } 261 AUE_NULL STD { int linux_timer_gettime(l_timer_t timerid, struct itimerspec *setting); } 262 AUE_NULL STD { int linux_timer_getoverrun(l_timer_t timerid); } 263 AUE_NULL STD { int linux_timer_delete(l_timer_t timerid); } 264 AUE_CLOCK_SETTIME STD { int linux_clock_settime(clockid_t which, struct l_timespec *tp); } 265 AUE_NULL STD { int linux_clock_gettime(clockid_t which, struct l_timespec *tp); } 266 AUE_NULL STD { int linux_clock_getres(clockid_t which, struct l_timespec *tp); } 267 AUE_NULL STD { int linux_clock_nanosleep(clockid_t which, int flags, \ struct l_timespec *rqtp, struct l_timespec *rmtp); } 268 AUE_STATFS STD { int linux_statfs64(char *path, size_t bufsize, struct l_statfs64_buf *buf); } 269 AUE_FSTATFS STD { int linux_fstatfs64(l_uint fd, size_t bufsize, struct l_statfs64_buf *buf); } 270 AUE_NULL STD { int linux_tgkill(int tgid, int pid, int sig); } 271 AUE_UTIMES STD { int linux_utimes(char *fname, \ struct l_timeval *tptr); } 272 AUE_NULL STD { int linux_fadvise64_64(int fd, \ l_loff_t offset, l_loff_t len, \ int advice); } 273 AUE_NULL UNIMPL vserver 274 AUE_NULL STD { int linux_mbind(void); } 275 AUE_NULL STD { int linux_get_mempolicy(void); } 276 AUE_NULL STD { int linux_set_mempolicy(void); } ; linux 2.6.6: 277 AUE_NULL STD { int linux_mq_open(const char *name, int oflag, mode_t mode, \ struct mq_attr *attr); } 278 AUE_NULL STD { int linux_mq_unlink(const char *name); } 279 AUE_NULL STD { int linux_mq_timedsend(l_mqd_t mqd, const char *msg_ptr, \ size_t msg_len, unsigned int msg_prio, const struct \ l_timespec *abs_timeout); } 280 AUE_NULL STD { int linux_mq_timedreceive(l_mqd_t mqd, char *msg_ptr, \ size_t msg_len, unsigned int msg_prio, const struct \ l_timespec *abs_timeout); } 281 AUE_NULL STD { int linux_mq_notify(l_mqd_t mqd, const struct l_timespec *abs_timeout); } 282 AUE_NULL STD { int linux_mq_getsetattr(l_mqd_t mqd, const struct mq_attr *attr, \ struct mq_attr *oattr); } 283 AUE_NULL STD { int linux_kexec_load(void); } 284 AUE_WAIT6 STD { int linux_waitid(int idtype, l_pid_t id, \ l_siginfo_t *info, int options, \ void *rusage); } 285 AUE_NULL UNIMPL ; linux 2.6.11: 286 AUE_NULL STD { int linux_add_key(void); } 287 AUE_NULL STD { int linux_request_key(void); } 288 AUE_NULL STD { int linux_keyctl(void); } ; linux 2.6.13: 289 AUE_NULL STD { int linux_ioprio_set(void); } 290 AUE_NULL STD { int linux_ioprio_get(void); } 291 AUE_NULL STD { int linux_inotify_init(void); } 292 AUE_NULL STD { int linux_inotify_add_watch(void); } 293 AUE_NULL STD { int linux_inotify_rm_watch(void); } ; linux 2.6.16: 294 AUE_NULL STD { int linux_migrate_pages(void); } 295 AUE_OPEN_RWTC STD { int linux_openat(l_int dfd, const char *filename, \ l_int flags, l_int mode); } 296 AUE_MKDIRAT STD { int linux_mkdirat(l_int dfd, const char *pathname, \ l_int mode); } 297 AUE_MKNODAT STD { int linux_mknodat(l_int dfd, const char *filename, \ l_int mode, l_uint dev); } 298 AUE_FCHOWNAT STD { int linux_fchownat(l_int dfd, const char *filename, \ l_uid16_t uid, l_gid16_t gid, l_int flag); } 299 AUE_FUTIMESAT STD { int linux_futimesat(l_int dfd, char *filename, \ struct l_timeval *utimes); } 300 AUE_FSTATAT STD { int linux_fstatat64(l_int dfd, char *pathname, \ struct l_stat64 *statbuf, l_int flag); } 301 AUE_UNLINKAT STD { int linux_unlinkat(l_int dfd, const char *pathname, \ l_int flag); } 302 AUE_RENAMEAT STD { int linux_renameat(l_int olddfd, const char *oldname, \ l_int newdfd, const char *newname); } 303 AUE_LINKAT STD { int linux_linkat(l_int olddfd, const char *oldname, \ l_int newdfd, const char *newname, l_int flag); } 304 AUE_SYMLINKAT STD { int linux_symlinkat(const char *oldname, l_int newdfd, \ const char *newname); } 305 AUE_READLINKAT STD { int linux_readlinkat(l_int dfd, const char *path, \ char *buf, l_int bufsiz); } 306 AUE_FCHMODAT STD { int linux_fchmodat(l_int dfd, const char *filename, \ l_mode_t mode); } 307 AUE_FACCESSAT STD { int linux_faccessat(l_int dfd, const char *filename, \ l_int amode); } 308 AUE_SELECT STD { int linux_pselect6(l_int nfds, l_fd_set *readfds, \ l_fd_set *writefds, l_fd_set *exceptfds, \ struct l_timespec *tsp, l_uintptr_t *sig); } 309 AUE_POLL STD { int linux_ppoll(struct pollfd *fds, uint32_t nfds, \ struct l_timespec *tsp, l_sigset_t *sset, l_size_t ssize); } 310 AUE_NULL STD { int linux_unshare(void); } ; linux 2.6.17: 311 AUE_NULL STD { int linux_set_robust_list(struct linux_robust_list_head *head, \ l_size_t len); } 312 AUE_NULL STD { int linux_get_robust_list(l_int pid, \ struct linux_robust_list_head **head, l_size_t *len); } 313 AUE_NULL STD { int linux_splice(void); } 314 AUE_NULL STD { int linux_sync_file_range(void); } 315 AUE_NULL STD { int linux_tee(void); } 316 AUE_NULL STD { int linux_vmsplice(void); } ; linux 2.6.18: 317 AUE_NULL STD { int linux_move_pages(void); } ; linux 2.6.19: 318 AUE_NULL STD { int linux_getcpu(void); } 319 AUE_NULL STD { int linux_epoll_pwait(l_int epfd, struct epoll_event *events, \ l_int maxevents, l_int timeout, l_sigset_t *mask); } ; linux 2.6.22: 320 AUE_FUTIMESAT STD { int linux_utimensat(l_int dfd, const char *pathname, \ const struct l_timespec *times, l_int flags); } 321 AUE_NULL STD { int linux_signalfd(void); } 322 AUE_NULL STD { int linux_timerfd_create(void); } 323 AUE_NULL STD { int linux_eventfd(l_uint initval); } ; linux 2.6.23: 324 AUE_NULL STD { int linux_fallocate(l_int fd, l_int mode, \ l_loff_t offset, l_loff_t len); } ; linux 2.6.25: 325 AUE_NULL STD { int linux_timerfd_settime(void); } 326 AUE_NULL STD { int linux_timerfd_gettime(void); } ; linux 2.6.27: 327 AUE_NULL STD { int linux_signalfd4(void); } 328 AUE_NULL STD { int linux_eventfd2(l_uint initval, l_int flags); } 329 AUE_NULL STD { int linux_epoll_create1(l_int flags); } 330 AUE_NULL STD { int linux_dup3(l_int oldfd, \ l_int newfd, l_int flags); } 331 AUE_NULL STD { int linux_pipe2(l_int *pipefds, l_int flags); } 332 AUE_NULL STD { int linux_inotify_init1(void); } ; linux 2.6.30: -333 AUE_NULL STD { int linux_preadv(void); } -334 AUE_NULL STD { int linux_pwritev(void); } +333 AUE_NULL STD { int linux_preadv(l_ulong fd, \ + struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h); } +334 AUE_NULL STD { int linux_pwritev(l_ulong fd, \ + struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h); } ; linux 2.6.31: -335 AUE_NULL STD { int linux_rt_tsigqueueinfo(void); } +335 AUE_NULL STD { int linux_rt_tgsigqueueinfo(l_pid_t tgid, \ + l_pid_t tid, l_int sig, l_siginfo_t *uinfo); } 336 AUE_NULL STD { int linux_perf_event_open(void); } ; linux 2.6.33: 337 AUE_NULL STD { int linux_recvmmsg(l_int s, \ struct l_mmsghdr *msg, l_uint vlen, \ l_uint flags, struct l_timespec *timeout); } 338 AUE_NULL STD { int linux_fanotify_init(void); } 339 AUE_NULL STD { int linux_fanotify_mark(void); } ; linux 2.6.36: 340 AUE_NULL STD { int linux_prlimit64(l_pid_t pid, \ l_uint resource, \ struct rlimit *new, \ struct rlimit *old); } -; later: +; linux 2.6.39: 341 AUE_NULL STD { int linux_name_to_handle_at(void); } 342 AUE_NULL STD { int linux_open_by_handle_at(void); } 343 AUE_NULL STD { int linux_clock_adjtime(void); } 344 AUE_SYNC STD { int linux_syncfs(l_int fd); } +; linux 3.0: 345 AUE_NULL STD { int linux_sendmmsg(l_int s, \ struct l_mmsghdr *msg, l_uint vlen, \ l_uint flags); } 346 AUE_NULL STD { int linux_setns(void); } -347 AUE_NULL STD { int linux_process_vm_readv(void); } -348 AUE_NULL STD { int linux_process_vm_writev(void); } +; linux 3.2 (glibc 2.15): +347 AUE_NULL STD { int linux_process_vm_readv(l_pid_t pid, \ + const struct iovec *lvec, l_ulong liovcnt, \ + const struct iovec *rvec, l_ulong riovcnt, \ + l_ulong flags); } +348 AUE_NULL STD { int linux_process_vm_writev(l_pid_t pid, \ + const struct iovec *lvec, l_ulong liovcnt, \ + const struct iovec *rvec, l_ulong riovcnt, \ + l_ulong flags); } +; linux 3.5 (no glibc wrapper): +349 AUE_NULL STD { int linux_kcmp(l_pid_t pid1, l_pid_t pid2, \ + l_int type, l_ulong idx1, l_ulong idx); } +; linux 3.8 (no glibc wrapper): +350 AUE_NULL STD { int linux_finit_module(l_int fd, \ + const char *uargs, l_int flags); } +; linux 3.14: +351 AUE_NULL STD { int linux_sched_setattr(l_pid_t pid, \ + void *attr, l_uint flags); } +352 AUE_NULL STD { int linux_sched_getattr(l_pid_t pid, \ + void *attr, l_uint size, l_uint flags); } +; linux 3.15: +353 AUE_NULL STD { int linux_renameat2(l_int oldfd, \ + const char *oldname, l_int newfd, \ + const char *newname, unsigned int flags); } +; linux 3.17: +354 AUE_NULL STD { int linux_seccomp(l_uint op, l_uint flags, \ + const char *uargs); } +355 AUE_NULL STD { int linux_getrandom(char *buf, \ + l_size_t count, l_uint flags); } +356 AUE_NULL STD { int linux_memfd_create(const char *uname_ptr, \ + l_uint flags); } +; linux 3.18: +357 AUE_NULL STD { int linux_bpf(l_int cmd, void *attr, \ + l_uint size); } +; linux 3.19: +358 AUE_NULL STD { int linux_execveat(l_int dfd, \ + const char *filename, const char **argv, \ + const char **envp, l_int flags); } +; linux 4.3: sockets now direct system calls: +359 AUE_SOCKET STD { int linux_socket(l_int domain, l_int type, \ + l_int protocol); } +360 AUE_SOCKETPAIR STD { int linux_socketpair(l_int domain, \ + l_int type, l_int protocol, l_uintptr_t rsv); } +361 AUE_BIND STD { int linux_bind(l_int s, l_uintptr_t name, \ + l_int namelen); } +362 AUE_CONNECT STD { int linux_connect(l_int s, l_uintptr_t name, \ + l_int namelen); } +363 AUE_LISTEN STD { int linux_listen(l_int s, l_int backlog); } +364 AUE_ACCEPT STD { int linux_accept4(l_int s, l_uintptr_t addr, \ + l_uintptr_t namelen, l_int flags); } +365 AUE_GETSOCKOPT STD { int linux_getsockopt(l_int s, l_int level, \ + l_int optname, l_uintptr_t optval, \ + l_uintptr_t optlen); } +366 AUE_SETSOCKOPT STD { int linux_setsockopt(l_int s, l_int level, \ + l_int optname, l_uintptr_t optval, \ + l_int optlen); } +367 AUE_GETSOCKNAME STD { int linux_getsockname(l_int s, \ + l_uintptr_t addr, l_uintptr_t namelen); } +368 AUE_GETPEERNAME STD { int linux_getpeername(l_int s, \ + l_uintptr_t addr, l_uintptr_t namelen); } +369 AUE_SENDTO STD { int linux_sendto(l_int s, l_uintptr_t msg, \ + l_int len, l_int flags, l_uintptr_t to, \ + l_int tolen); } +370 AUE_SENDMSG STD { int linux_sendmsg(l_int s, l_uintptr_t msg, \ + l_int flags); } +371 AUE_RECVFROM STD { int linux_recvfrom(l_int s, l_uintptr_t buf, \ + l_size_t len, l_int flags, l_uintptr_t from, \ + l_uintptr_t fromlen); } +372 AUE_RECVMSG STD { int linux_recvmsg(l_int s, l_uintptr_t msg, \ + l_int flags); } +373 AUE_NULL STD { int linux_shutdown(l_int s, l_int how); } +; linux 4.2: +374 AUE_NULL STD { int linux_userfaultfd(l_int flags); } +; linux 4.3: +375 AUE_NULL STD { int linux_membarrier(l_int cmd, l_int flags); } +; linux 4.4: +376 AUE_NULL STD { int linux_mlock2(l_ulong start, l_size_t len, \ + l_int flags); } +; linux 4.5: +377 AUE_NULL STD { int linux_copy_file_range(l_int fd_in, \ + l_loff_t *off_in, l_int fd_out, \ + l_loff_t *off_out, l_size_t len, \ + l_uint flags); } +; linux 4.6: +378 AUE_NULL STD { int linux_preadv2(l_ulong fd, \ + const struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h, l_int flags); } +379 AUE_NULL STD { int linux_pwritev2(l_ulong fd, \ + const struct iovec *vec, l_ulong vlen, \ + l_ulong pos_l, l_ulong pos_h, l_int flags); } +; linux 4.8: +380 AUE_NULL STD { int linux_pkey_mprotect(l_ulong start, \ + l_size_t len, l_ulong prot, l_int pkey); } +381 AUE_NULL STD { int linux_pkey_alloc(l_ulong flags, \ + l_ulong init_val); } +382 AUE_NULL STD { int linux_pkey_free(l_int pkey); } + ; please, keep this line at the end. -349 AUE_NULL UNIMPL nosys +383 AUE_NULL UNIMPL nosys Index: projects/ipsec/sys/kern/kern_cpuset.c =================================================================== --- projects/ipsec/sys/kern/kern_cpuset.c (revision 313312) +++ projects/ipsec/sys/kern/kern_cpuset.c (revision 313313) @@ -1,1307 +1,1322 @@ /*- * Copyright (c) 2008, Jeffrey Roberson * All rights reserved. * * Copyright (c) 2008 Nokia Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DDB #include #endif /* DDB */ /* * cpusets provide a mechanism for creating and manipulating sets of * processors for the purpose of constraining the scheduling of threads to * specific processors. * * Each process belongs to an identified set, by default this is set 1. Each * thread may further restrict the cpus it may run on to a subset of this * named set. This creates an anonymous set which other threads and processes * may not join by number. * * The named set is referred to herein as the 'base' set to avoid ambiguity. * This set is usually a child of a 'root' set while the anonymous set may * simply be referred to as a mask. In the syscall api these are referred to * as the ROOT, CPUSET, and MASK levels where CPUSET is called 'base' here. * * Threads inherit their set from their creator whether it be anonymous or * not. This means that anonymous sets are immutable because they may be * shared. To modify an anonymous set a new set is created with the desired * mask and the same parent as the existing anonymous set. This gives the * illusion of each thread having a private mask. * * Via the syscall apis a user may ask to retrieve or modify the root, base, * or mask that is discovered via a pid, tid, or setid. Modifying a set * modifies all numbered and anonymous child sets to comply with the new mask. * Modifying a pid or tid's mask applies only to that tid but must still * exist within the assigned parent set. * * A thread may not be assigned to a group separate from other threads in * the process. This is to remove ambiguity when the setid is queried with * a pid argument. There is no other technical limitation. * * This somewhat complex arrangement is intended to make it easy for * applications to query available processors and bind their threads to * specific processors while also allowing administrators to dynamically * reprovision by changing sets which apply to groups of processes. * * A simple application should not concern itself with sets at all and * rather apply masks to its own threads via CPU_WHICH_TID and a -1 id * meaning 'curthread'. It may query available cpus for that tid with a * getaffinity call using (CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, ...). */ static uma_zone_t cpuset_zone; static struct mtx cpuset_lock; static struct setlist cpuset_ids; static struct unrhdr *cpuset_unr; static struct cpuset *cpuset_zero, *cpuset_default; /* Return the size of cpuset_t at the kernel level */ SYSCTL_INT(_kern_sched, OID_AUTO, cpusetsize, CTLFLAG_RD | CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, sizeof(cpuset_t), "sizeof(cpuset_t)"); cpuset_t *cpuset_root; cpuset_t cpuset_domain[MAXMEMDOM]; /* * Acquire a reference to a cpuset, all pointers must be tracked with refs. */ struct cpuset * cpuset_ref(struct cpuset *set) { refcount_acquire(&set->cs_ref); return (set); } /* * Walks up the tree from 'set' to find the root. Returns the root * referenced. */ static struct cpuset * cpuset_refroot(struct cpuset *set) { for (; set->cs_parent != NULL; set = set->cs_parent) if (set->cs_flags & CPU_SET_ROOT) break; cpuset_ref(set); return (set); } /* * Find the first non-anonymous set starting from 'set'. Returns this set * referenced. May return the passed in set with an extra ref if it is * not anonymous. */ static struct cpuset * cpuset_refbase(struct cpuset *set) { if (set->cs_id == CPUSET_INVALID) set = set->cs_parent; cpuset_ref(set); return (set); } /* * Release a reference in a context where it is safe to allocate. */ void cpuset_rel(struct cpuset *set) { cpusetid_t id; if (refcount_release(&set->cs_ref) == 0) return; mtx_lock_spin(&cpuset_lock); LIST_REMOVE(set, cs_siblings); id = set->cs_id; if (id != CPUSET_INVALID) LIST_REMOVE(set, cs_link); mtx_unlock_spin(&cpuset_lock); cpuset_rel(set->cs_parent); uma_zfree(cpuset_zone, set); if (id != CPUSET_INVALID) free_unr(cpuset_unr, id); } /* * Deferred release must be used when in a context that is not safe to * allocate/free. This places any unreferenced sets on the list 'head'. */ static void cpuset_rel_defer(struct setlist *head, struct cpuset *set) { if (refcount_release(&set->cs_ref) == 0) return; mtx_lock_spin(&cpuset_lock); LIST_REMOVE(set, cs_siblings); if (set->cs_id != CPUSET_INVALID) LIST_REMOVE(set, cs_link); LIST_INSERT_HEAD(head, set, cs_link); mtx_unlock_spin(&cpuset_lock); } /* * Complete a deferred release. Removes the set from the list provided to * cpuset_rel_defer. */ static void cpuset_rel_complete(struct cpuset *set) { LIST_REMOVE(set, cs_link); cpuset_rel(set->cs_parent); uma_zfree(cpuset_zone, set); } /* * Find a set based on an id. Returns it with a ref. */ static struct cpuset * cpuset_lookup(cpusetid_t setid, struct thread *td) { struct cpuset *set; if (setid == CPUSET_INVALID) return (NULL); mtx_lock_spin(&cpuset_lock); LIST_FOREACH(set, &cpuset_ids, cs_link) if (set->cs_id == setid) break; if (set) cpuset_ref(set); mtx_unlock_spin(&cpuset_lock); KASSERT(td != NULL, ("[%s:%d] td is NULL", __func__, __LINE__)); if (set != NULL && jailed(td->td_ucred)) { struct cpuset *jset, *tset; jset = td->td_ucred->cr_prison->pr_cpuset; for (tset = set; tset != NULL; tset = tset->cs_parent) if (tset == jset) break; if (tset == NULL) { cpuset_rel(set); set = NULL; } } return (set); } /* * Create a set in the space provided in 'set' with the provided parameters. * The set is returned with a single ref. May return EDEADLK if the set * will have no valid cpu based on restrictions from the parent. */ static int _cpuset_create(struct cpuset *set, struct cpuset *parent, const cpuset_t *mask, cpusetid_t id) { if (!CPU_OVERLAP(&parent->cs_mask, mask)) return (EDEADLK); CPU_COPY(mask, &set->cs_mask); LIST_INIT(&set->cs_children); refcount_init(&set->cs_ref, 1); set->cs_flags = 0; mtx_lock_spin(&cpuset_lock); CPU_AND(&set->cs_mask, &parent->cs_mask); set->cs_id = id; set->cs_parent = cpuset_ref(parent); LIST_INSERT_HEAD(&parent->cs_children, set, cs_siblings); if (set->cs_id != CPUSET_INVALID) LIST_INSERT_HEAD(&cpuset_ids, set, cs_link); mtx_unlock_spin(&cpuset_lock); return (0); } /* * Create a new non-anonymous set with the requested parent and mask. May * return failures if the mask is invalid or a new number can not be * allocated. */ static int cpuset_create(struct cpuset **setp, struct cpuset *parent, const cpuset_t *mask) { struct cpuset *set; cpusetid_t id; int error; id = alloc_unr(cpuset_unr); if (id == -1) return (ENFILE); *setp = set = uma_zalloc(cpuset_zone, M_WAITOK); error = _cpuset_create(set, parent, mask, id); if (error == 0) return (0); free_unr(cpuset_unr, id); uma_zfree(cpuset_zone, set); return (error); } /* * Recursively check for errors that would occur from applying mask to * the tree of sets starting at 'set'. Checks for sets that would become * empty as well as RDONLY flags. */ static int cpuset_testupdate(struct cpuset *set, cpuset_t *mask, int check_mask) { struct cpuset *nset; cpuset_t newmask; int error; mtx_assert(&cpuset_lock, MA_OWNED); if (set->cs_flags & CPU_SET_RDONLY) return (EPERM); if (check_mask) { if (!CPU_OVERLAP(&set->cs_mask, mask)) return (EDEADLK); CPU_COPY(&set->cs_mask, &newmask); CPU_AND(&newmask, mask); } else CPU_COPY(mask, &newmask); error = 0; LIST_FOREACH(nset, &set->cs_children, cs_siblings) if ((error = cpuset_testupdate(nset, &newmask, 1)) != 0) break; return (error); } /* * Applies the mask 'mask' without checking for empty sets or permissions. */ static void cpuset_update(struct cpuset *set, cpuset_t *mask) { struct cpuset *nset; mtx_assert(&cpuset_lock, MA_OWNED); CPU_AND(&set->cs_mask, mask); LIST_FOREACH(nset, &set->cs_children, cs_siblings) cpuset_update(nset, &set->cs_mask); return; } /* * Modify the set 'set' to use a copy of the mask provided. Apply this new * mask to restrict all children in the tree. Checks for validity before * applying the changes. */ static int cpuset_modify(struct cpuset *set, cpuset_t *mask) { struct cpuset *root; int error; error = priv_check(curthread, PRIV_SCHED_CPUSET); if (error) return (error); /* * In case we are called from within the jail * we do not allow modifying the dedicated root * cpuset of the jail but may still allow to * change child sets. */ if (jailed(curthread->td_ucred) && set->cs_flags & CPU_SET_ROOT) return (EPERM); /* * Verify that we have access to this set of * cpus. */ root = set->cs_parent; if (root && !CPU_SUBSET(&root->cs_mask, mask)) return (EINVAL); mtx_lock_spin(&cpuset_lock); error = cpuset_testupdate(set, mask, 0); if (error) goto out; CPU_COPY(mask, &set->cs_mask); cpuset_update(set, mask); out: mtx_unlock_spin(&cpuset_lock); return (error); } /* * Resolve the 'which' parameter of several cpuset apis. * * For WHICH_PID and WHICH_TID return a locked proc and valid proc/tid. Also * checks for permission via p_cansched(). * * For WHICH_SET returns a valid set with a new reference. * * -1 may be supplied for any argument to mean the current proc/thread or * the base set of the current thread. May fail with ESRCH/EPERM. */ int cpuset_which(cpuwhich_t which, id_t id, struct proc **pp, struct thread **tdp, struct cpuset **setp) { struct cpuset *set; struct thread *td; struct proc *p; int error; *pp = p = NULL; *tdp = td = NULL; *setp = set = NULL; switch (which) { case CPU_WHICH_PID: if (id == -1) { PROC_LOCK(curproc); p = curproc; break; } if ((p = pfind(id)) == NULL) return (ESRCH); break; case CPU_WHICH_TID: if (id == -1) { PROC_LOCK(curproc); p = curproc; td = curthread; break; } td = tdfind(id, -1); if (td == NULL) return (ESRCH); p = td->td_proc; break; case CPU_WHICH_CPUSET: if (id == -1) { thread_lock(curthread); set = cpuset_refbase(curthread->td_cpuset); thread_unlock(curthread); } else set = cpuset_lookup(id, curthread); if (set) { *setp = set; return (0); } return (ESRCH); case CPU_WHICH_JAIL: { /* Find `set' for prison with given id. */ struct prison *pr; sx_slock(&allprison_lock); pr = prison_find_child(curthread->td_ucred->cr_prison, id); sx_sunlock(&allprison_lock); if (pr == NULL) return (ESRCH); cpuset_ref(pr->pr_cpuset); *setp = pr->pr_cpuset; mtx_unlock(&pr->pr_mtx); return (0); } case CPU_WHICH_IRQ: case CPU_WHICH_DOMAIN: return (0); default: return (EINVAL); } error = p_cansched(curthread, p); if (error) { PROC_UNLOCK(p); return (error); } if (td == NULL) td = FIRST_THREAD_IN_PROC(p); *pp = p; *tdp = td; return (0); } /* * Create an anonymous set with the provided mask in the space provided by * 'fset'. If the passed in set is anonymous we use its parent otherwise * the new set is a child of 'set'. */ static int cpuset_shadow(struct cpuset *set, struct cpuset *fset, const cpuset_t *mask) { struct cpuset *parent; if (set->cs_id == CPUSET_INVALID) parent = set->cs_parent; else parent = set; if (!CPU_SUBSET(&parent->cs_mask, mask)) return (EDEADLK); return (_cpuset_create(fset, parent, mask, CPUSET_INVALID)); } /* * Handle two cases for replacing the base set or mask of an entire process. * * 1) Set is non-null and mask is null. This reparents all anonymous sets * to the provided set and replaces all non-anonymous td_cpusets with the * provided set. * 2) Mask is non-null and set is null. This replaces or creates anonymous * sets for every thread with the existing base as a parent. * * This is overly complicated because we can't allocate while holding a * spinlock and spinlocks must be held while changing and examining thread * state. */ static int cpuset_setproc(pid_t pid, struct cpuset *set, cpuset_t *mask) { struct setlist freelist; struct setlist droplist; struct cpuset *tdset; struct cpuset *nset; struct thread *td; struct proc *p; int threads; int nfree; int error; /* * The algorithm requires two passes due to locking considerations. * * 1) Lookup the process and acquire the locks in the required order. * 2) If enough cpusets have not been allocated release the locks and * allocate them. Loop. */ LIST_INIT(&freelist); LIST_INIT(&droplist); nfree = 0; for (;;) { error = cpuset_which(CPU_WHICH_PID, pid, &p, &td, &nset); if (error) goto out; if (nfree >= p->p_numthreads) break; threads = p->p_numthreads; PROC_UNLOCK(p); for (; nfree < threads; nfree++) { nset = uma_zalloc(cpuset_zone, M_WAITOK); LIST_INSERT_HEAD(&freelist, nset, cs_link); } } PROC_LOCK_ASSERT(p, MA_OWNED); /* * Now that the appropriate locks are held and we have enough cpusets, * make sure the operation will succeed before applying changes. The * proc lock prevents td_cpuset from changing between calls. */ error = 0; FOREACH_THREAD_IN_PROC(p, td) { thread_lock(td); tdset = td->td_cpuset; /* * Verify that a new mask doesn't specify cpus outside of * the set the thread is a member of. */ if (mask) { if (tdset->cs_id == CPUSET_INVALID) tdset = tdset->cs_parent; if (!CPU_SUBSET(&tdset->cs_mask, mask)) error = EDEADLK; /* * Verify that a new set won't leave an existing thread * mask without a cpu to run on. It can, however, restrict * the set. */ } else if (tdset->cs_id == CPUSET_INVALID) { if (!CPU_OVERLAP(&set->cs_mask, &tdset->cs_mask)) error = EDEADLK; } thread_unlock(td); if (error) goto unlock_out; } /* * Replace each thread's cpuset while using deferred release. We * must do this because the thread lock must be held while operating * on the thread and this limits the type of operations allowed. */ FOREACH_THREAD_IN_PROC(p, td) { thread_lock(td); /* * If we presently have an anonymous set or are applying a * mask we must create an anonymous shadow set. That is * either parented to our existing base or the supplied set. * * If we have a base set with no anonymous shadow we simply * replace it outright. */ tdset = td->td_cpuset; if (tdset->cs_id == CPUSET_INVALID || mask) { nset = LIST_FIRST(&freelist); LIST_REMOVE(nset, cs_link); if (mask) error = cpuset_shadow(tdset, nset, mask); else error = _cpuset_create(nset, set, &tdset->cs_mask, CPUSET_INVALID); if (error) { LIST_INSERT_HEAD(&freelist, nset, cs_link); thread_unlock(td); break; } } else nset = cpuset_ref(set); cpuset_rel_defer(&droplist, tdset); td->td_cpuset = nset; sched_affinity(td); thread_unlock(td); } unlock_out: PROC_UNLOCK(p); out: while ((nset = LIST_FIRST(&droplist)) != NULL) cpuset_rel_complete(nset); while ((nset = LIST_FIRST(&freelist)) != NULL) { LIST_REMOVE(nset, cs_link); uma_zfree(cpuset_zone, nset); } return (error); } /* * Return a string representing a valid layout for a cpuset_t object. * It expects an incoming buffer at least sized as CPUSETBUFSIZ. */ char * cpusetobj_strprint(char *buf, const cpuset_t *set) { char *tbuf; size_t i, bytesp, bufsiz; tbuf = buf; bytesp = 0; bufsiz = CPUSETBUFSIZ; for (i = 0; i < (_NCPUWORDS - 1); i++) { bytesp = snprintf(tbuf, bufsiz, "%lx,", set->__bits[i]); bufsiz -= bytesp; tbuf += bytesp; } snprintf(tbuf, bufsiz, "%lx", set->__bits[_NCPUWORDS - 1]); return (buf); } /* * Build a valid cpuset_t object from a string representation. * It expects an incoming buffer at least sized as CPUSETBUFSIZ. */ int cpusetobj_strscan(cpuset_t *set, const char *buf) { u_int nwords; int i, ret; if (strlen(buf) > CPUSETBUFSIZ - 1) return (-1); /* Allow to pass a shorter version of the mask when necessary. */ nwords = 1; for (i = 0; buf[i] != '\0'; i++) if (buf[i] == ',') nwords++; if (nwords > _NCPUWORDS) return (-1); CPU_ZERO(set); for (i = 0; i < (nwords - 1); i++) { ret = sscanf(buf, "%lx,", &set->__bits[i]); if (ret == 0 || ret == -1) return (-1); buf = strstr(buf, ","); if (buf == NULL) return (-1); buf++; } ret = sscanf(buf, "%lx", &set->__bits[nwords - 1]); if (ret == 0 || ret == -1) return (-1); return (0); } /* * Apply an anonymous mask to a single thread. */ int cpuset_setthread(lwpid_t id, cpuset_t *mask) { struct cpuset *nset; struct cpuset *set; struct thread *td; struct proc *p; int error; nset = uma_zalloc(cpuset_zone, M_WAITOK); error = cpuset_which(CPU_WHICH_TID, id, &p, &td, &set); if (error) goto out; set = NULL; thread_lock(td); error = cpuset_shadow(td->td_cpuset, nset, mask); if (error == 0) { set = td->td_cpuset; td->td_cpuset = nset; sched_affinity(td); nset = NULL; } thread_unlock(td); PROC_UNLOCK(p); if (set) cpuset_rel(set); out: if (nset) uma_zfree(cpuset_zone, nset); return (error); } /* * Apply new cpumask to the ithread. */ int cpuset_setithread(lwpid_t id, int cpu) { struct cpuset *nset, *rset; struct cpuset *parent, *old_set; struct thread *td; struct proc *p; cpusetid_t cs_id; cpuset_t mask; int error; nset = uma_zalloc(cpuset_zone, M_WAITOK); rset = uma_zalloc(cpuset_zone, M_WAITOK); cs_id = CPUSET_INVALID; CPU_ZERO(&mask); if (cpu == NOCPU) CPU_COPY(cpuset_root, &mask); else CPU_SET(cpu, &mask); error = cpuset_which(CPU_WHICH_TID, id, &p, &td, &old_set); if (error != 0 || ((cs_id = alloc_unr(cpuset_unr)) == CPUSET_INVALID)) goto out; /* cpuset_which() returns with PROC_LOCK held. */ old_set = td->td_cpuset; if (cpu == NOCPU) { /* * roll back to default set. We're not using cpuset_shadow() * here because we can fail CPU_SUBSET() check. This can happen * if default set does not contain all CPUs. */ error = _cpuset_create(nset, cpuset_default, &mask, CPUSET_INVALID); goto applyset; } if (old_set->cs_id == 1 || (old_set->cs_id == CPUSET_INVALID && old_set->cs_parent->cs_id == 1)) { /* * Current set is either default (1) or * shadowed version of default set. * * Allocate new root set to be able to shadow it * with any mask. */ error = _cpuset_create(rset, cpuset_zero, &cpuset_zero->cs_mask, cs_id); if (error != 0) { PROC_UNLOCK(p); goto out; } rset->cs_flags |= CPU_SET_ROOT; parent = rset; rset = NULL; cs_id = CPUSET_INVALID; } else { /* Assume existing set was already allocated by previous call */ parent = old_set; old_set = NULL; } error = cpuset_shadow(parent, nset, &mask); applyset: if (error == 0) { thread_lock(td); td->td_cpuset = nset; sched_affinity(td); thread_unlock(td); nset = NULL; } else old_set = NULL; PROC_UNLOCK(p); if (old_set != NULL) cpuset_rel(old_set); out: if (nset != NULL) uma_zfree(cpuset_zone, nset); if (rset != NULL) uma_zfree(cpuset_zone, rset); if (cs_id != CPUSET_INVALID) free_unr(cpuset_unr, cs_id); return (error); } /* * Creates system-wide cpusets and the cpuset for thread0 including two * sets: * * 0 - The root set which should represent all valid processors in the * system. It is initially created with a mask of all processors * because we don't know what processors are valid until cpuset_init() * runs. This set is immutable. * 1 - The default set which all processes are a member of until changed. * This allows an administrator to move all threads off of given cpus to * dedicate them to high priority tasks or save power etc. */ struct cpuset * cpuset_thread0(void) { struct cpuset *set; int error, i; cpuset_zone = uma_zcreate("cpuset", sizeof(struct cpuset), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); mtx_init(&cpuset_lock, "cpuset", NULL, MTX_SPIN | MTX_RECURSE); /* * Create the root system set for the whole machine. Doesn't use * cpuset_create() due to NULL parent. */ set = uma_zalloc(cpuset_zone, M_WAITOK | M_ZERO); CPU_FILL(&set->cs_mask); LIST_INIT(&set->cs_children); LIST_INSERT_HEAD(&cpuset_ids, set, cs_link); set->cs_ref = 1; set->cs_flags = CPU_SET_ROOT; cpuset_zero = set; cpuset_root = &set->cs_mask; /* * Now derive a default, modifiable set from that to give out. */ set = uma_zalloc(cpuset_zone, M_WAITOK); error = _cpuset_create(set, cpuset_zero, &cpuset_zero->cs_mask, 1); KASSERT(error == 0, ("Error creating default set: %d\n", error)); cpuset_default = set; /* * Initialize the unit allocator. 0 and 1 are allocated above. */ cpuset_unr = new_unrhdr(2, INT_MAX, NULL); /* * If MD code has not initialized per-domain cpusets, place all * CPUs in domain 0. */ for (i = 0; i < MAXMEMDOM; i++) if (!CPU_EMPTY(&cpuset_domain[i])) goto domains_set; CPU_COPY(&all_cpus, &cpuset_domain[0]); domains_set: return (set); } /* * Create a cpuset, which would be cpuset_create() but * mark the new 'set' as root. * * We are not going to reparent the td to it. Use cpuset_setproc_update_set() * for that. * * In case of no error, returns the set in *setp locked with a reference. */ int cpuset_create_root(struct prison *pr, struct cpuset **setp) { struct cpuset *set; int error; KASSERT(pr != NULL, ("[%s:%d] invalid pr", __func__, __LINE__)); KASSERT(setp != NULL, ("[%s:%d] invalid setp", __func__, __LINE__)); error = cpuset_create(setp, pr->pr_cpuset, &pr->pr_cpuset->cs_mask); if (error) return (error); KASSERT(*setp != NULL, ("[%s:%d] cpuset_create returned invalid data", __func__, __LINE__)); /* Mark the set as root. */ set = *setp; set->cs_flags |= CPU_SET_ROOT; return (0); } int cpuset_setproc_update_set(struct proc *p, struct cpuset *set) { int error; KASSERT(p != NULL, ("[%s:%d] invalid proc", __func__, __LINE__)); KASSERT(set != NULL, ("[%s:%d] invalid set", __func__, __LINE__)); cpuset_ref(set); error = cpuset_setproc(p->p_pid, set, NULL); if (error) return (error); cpuset_rel(set); return (0); } /* * This is called once the final set of system cpus is known. Modifies * the root set and all children and mark the root read-only. */ static void cpuset_init(void *arg) { cpuset_t mask; mask = all_cpus; if (cpuset_modify(cpuset_zero, &mask)) panic("Can't set initial cpuset mask.\n"); cpuset_zero->cs_flags |= CPU_SET_RDONLY; } SYSINIT(cpuset, SI_SUB_SMP, SI_ORDER_ANY, cpuset_init, NULL); #ifndef _SYS_SYSPROTO_H_ struct cpuset_args { cpusetid_t *setid; }; #endif int sys_cpuset(struct thread *td, struct cpuset_args *uap) { struct cpuset *root; struct cpuset *set; int error; thread_lock(td); root = cpuset_refroot(td->td_cpuset); thread_unlock(td); error = cpuset_create(&set, root, &root->cs_mask); cpuset_rel(root); if (error) return (error); error = copyout(&set->cs_id, uap->setid, sizeof(set->cs_id)); if (error == 0) error = cpuset_setproc(-1, set, NULL); cpuset_rel(set); return (error); } #ifndef _SYS_SYSPROTO_H_ struct cpuset_setid_args { cpuwhich_t which; id_t id; cpusetid_t setid; }; #endif int sys_cpuset_setid(struct thread *td, struct cpuset_setid_args *uap) { return (kern_cpuset_setid(td, uap->which, uap->id, uap->setid)); } int kern_cpuset_setid(struct thread *td, cpuwhich_t which, id_t id, cpusetid_t setid) { struct cpuset *set; int error; /* * Presently we only support per-process sets. */ if (which != CPU_WHICH_PID) return (EINVAL); set = cpuset_lookup(setid, td); if (set == NULL) return (ESRCH); error = cpuset_setproc(id, set, NULL); cpuset_rel(set); return (error); } #ifndef _SYS_SYSPROTO_H_ struct cpuset_getid_args { cpulevel_t level; cpuwhich_t which; id_t id; cpusetid_t *setid; }; #endif int sys_cpuset_getid(struct thread *td, struct cpuset_getid_args *uap) { return (kern_cpuset_getid(td, uap->level, uap->which, uap->id, uap->setid)); } int kern_cpuset_getid(struct thread *td, cpulevel_t level, cpuwhich_t which, id_t id, cpusetid_t *setid) { struct cpuset *nset; struct cpuset *set; struct thread *ttd; struct proc *p; cpusetid_t tmpid; int error; if (level == CPU_LEVEL_WHICH && which != CPU_WHICH_CPUSET) return (EINVAL); error = cpuset_which(which, id, &p, &ttd, &set); if (error) return (error); switch (which) { case CPU_WHICH_TID: case CPU_WHICH_PID: thread_lock(ttd); set = cpuset_refbase(ttd->td_cpuset); thread_unlock(ttd); PROC_UNLOCK(p); break; case CPU_WHICH_CPUSET: case CPU_WHICH_JAIL: break; case CPU_WHICH_IRQ: case CPU_WHICH_DOMAIN: return (EINVAL); } switch (level) { case CPU_LEVEL_ROOT: nset = cpuset_refroot(set); cpuset_rel(set); set = nset; break; case CPU_LEVEL_CPUSET: break; case CPU_LEVEL_WHICH: break; } tmpid = set->cs_id; cpuset_rel(set); if (error == 0) error = copyout(&tmpid, setid, sizeof(id)); return (error); } #ifndef _SYS_SYSPROTO_H_ struct cpuset_getaffinity_args { cpulevel_t level; cpuwhich_t which; id_t id; size_t cpusetsize; cpuset_t *mask; }; #endif int sys_cpuset_getaffinity(struct thread *td, struct cpuset_getaffinity_args *uap) { + + return (kern_cpuset_getaffinity(td, uap->level, uap->which, + uap->id, uap->cpusetsize, uap->mask)); +} + +int +kern_cpuset_getaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, + id_t id, size_t cpusetsize, cpuset_t *maskp) +{ struct thread *ttd; struct cpuset *nset; struct cpuset *set; struct proc *p; cpuset_t *mask; int error; size_t size; - if (uap->cpusetsize < sizeof(cpuset_t) || - uap->cpusetsize > CPU_MAXSIZE / NBBY) + if (cpusetsize < sizeof(cpuset_t) || cpusetsize > CPU_MAXSIZE / NBBY) return (ERANGE); - size = uap->cpusetsize; + size = cpusetsize; mask = malloc(size, M_TEMP, M_WAITOK | M_ZERO); - error = cpuset_which(uap->which, uap->id, &p, &ttd, &set); + error = cpuset_which(which, id, &p, &ttd, &set); if (error) goto out; - switch (uap->level) { + switch (level) { case CPU_LEVEL_ROOT: case CPU_LEVEL_CPUSET: - switch (uap->which) { + switch (which) { case CPU_WHICH_TID: case CPU_WHICH_PID: thread_lock(ttd); set = cpuset_ref(ttd->td_cpuset); thread_unlock(ttd); break; case CPU_WHICH_CPUSET: case CPU_WHICH_JAIL: break; case CPU_WHICH_IRQ: case CPU_WHICH_DOMAIN: error = EINVAL; goto out; } - if (uap->level == CPU_LEVEL_ROOT) + if (level == CPU_LEVEL_ROOT) nset = cpuset_refroot(set); else nset = cpuset_refbase(set); CPU_COPY(&nset->cs_mask, mask); cpuset_rel(nset); break; case CPU_LEVEL_WHICH: - switch (uap->which) { + switch (which) { case CPU_WHICH_TID: thread_lock(ttd); CPU_COPY(&ttd->td_cpuset->cs_mask, mask); thread_unlock(ttd); break; case CPU_WHICH_PID: FOREACH_THREAD_IN_PROC(p, ttd) { thread_lock(ttd); CPU_OR(mask, &ttd->td_cpuset->cs_mask); thread_unlock(ttd); } break; case CPU_WHICH_CPUSET: case CPU_WHICH_JAIL: CPU_COPY(&set->cs_mask, mask); break; case CPU_WHICH_IRQ: - error = intr_getaffinity(uap->id, mask); + error = intr_getaffinity(id, mask); break; case CPU_WHICH_DOMAIN: - if (uap->id < 0 || uap->id >= MAXMEMDOM) + if (id < 0 || id >= MAXMEMDOM) error = ESRCH; else - CPU_COPY(&cpuset_domain[uap->id], mask); + CPU_COPY(&cpuset_domain[id], mask); break; } break; default: error = EINVAL; break; } if (set) cpuset_rel(set); if (p) PROC_UNLOCK(p); if (error == 0) - error = copyout(mask, uap->mask, size); + error = copyout(mask, maskp, size); out: free(mask, M_TEMP); return (error); } #ifndef _SYS_SYSPROTO_H_ struct cpuset_setaffinity_args { cpulevel_t level; cpuwhich_t which; id_t id; size_t cpusetsize; const cpuset_t *mask; }; #endif int sys_cpuset_setaffinity(struct thread *td, struct cpuset_setaffinity_args *uap) { + + return (kern_cpuset_setaffinity(td, uap->level, uap->which, + uap->id, uap->cpusetsize, uap->mask)); +} + +int +kern_cpuset_setaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, + id_t id, size_t cpusetsize, const cpuset_t *maskp) +{ struct cpuset *nset; struct cpuset *set; struct thread *ttd; struct proc *p; cpuset_t *mask; int error; - if (uap->cpusetsize < sizeof(cpuset_t) || - uap->cpusetsize > CPU_MAXSIZE / NBBY) + if (cpusetsize < sizeof(cpuset_t) || cpusetsize > CPU_MAXSIZE / NBBY) return (ERANGE); - mask = malloc(uap->cpusetsize, M_TEMP, M_WAITOK | M_ZERO); - error = copyin(uap->mask, mask, uap->cpusetsize); + mask = malloc(cpusetsize, M_TEMP, M_WAITOK | M_ZERO); + error = copyin(maskp, mask, cpusetsize); if (error) goto out; /* * Verify that no high bits are set. */ - if (uap->cpusetsize > sizeof(cpuset_t)) { + if (cpusetsize > sizeof(cpuset_t)) { char *end; char *cp; end = cp = (char *)&mask->__bits; - end += uap->cpusetsize; + end += cpusetsize; cp += sizeof(cpuset_t); while (cp != end) if (*cp++ != 0) { error = EINVAL; goto out; } } - switch (uap->level) { + switch (level) { case CPU_LEVEL_ROOT: case CPU_LEVEL_CPUSET: - error = cpuset_which(uap->which, uap->id, &p, &ttd, &set); + error = cpuset_which(which, id, &p, &ttd, &set); if (error) break; - switch (uap->which) { + switch (which) { case CPU_WHICH_TID: case CPU_WHICH_PID: thread_lock(ttd); set = cpuset_ref(ttd->td_cpuset); thread_unlock(ttd); PROC_UNLOCK(p); break; case CPU_WHICH_CPUSET: case CPU_WHICH_JAIL: break; case CPU_WHICH_IRQ: case CPU_WHICH_DOMAIN: error = EINVAL; goto out; } - if (uap->level == CPU_LEVEL_ROOT) + if (level == CPU_LEVEL_ROOT) nset = cpuset_refroot(set); else nset = cpuset_refbase(set); error = cpuset_modify(nset, mask); cpuset_rel(nset); cpuset_rel(set); break; case CPU_LEVEL_WHICH: - switch (uap->which) { + switch (which) { case CPU_WHICH_TID: - error = cpuset_setthread(uap->id, mask); + error = cpuset_setthread(id, mask); break; case CPU_WHICH_PID: - error = cpuset_setproc(uap->id, NULL, mask); + error = cpuset_setproc(id, NULL, mask); break; case CPU_WHICH_CPUSET: case CPU_WHICH_JAIL: - error = cpuset_which(uap->which, uap->id, &p, - &ttd, &set); + error = cpuset_which(which, id, &p, &ttd, &set); if (error == 0) { error = cpuset_modify(set, mask); cpuset_rel(set); } break; case CPU_WHICH_IRQ: - error = intr_setaffinity(uap->id, mask); + error = intr_setaffinity(id, mask); break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } out: free(mask, M_TEMP); return (error); } #ifdef DDB void ddb_display_cpuset(const cpuset_t *set) { int cpu, once; for (once = 0, cpu = 0; cpu < CPU_SETSIZE; cpu++) { if (CPU_ISSET(cpu, set)) { if (once == 0) { db_printf("%d", cpu); once = 1; } else db_printf(",%d", cpu); } } if (once == 0) db_printf(""); } DB_SHOW_COMMAND(cpusets, db_show_cpusets) { struct cpuset *set; LIST_FOREACH(set, &cpuset_ids, cs_link) { db_printf("set=%p id=%-6u ref=%-6d flags=0x%04x parent id=%d\n", set, set->cs_id, set->cs_ref, set->cs_flags, (set->cs_parent != NULL) ? set->cs_parent->cs_id : 0); db_printf(" mask="); ddb_display_cpuset(&set->cs_mask); db_printf("\n"); if (db_pager_quit) break; } } #endif /* DDB */ Index: projects/ipsec/sys/kern/kern_descrip.c =================================================================== --- projects/ipsec/sys/kern/kern_descrip.c (revision 313312) +++ projects/ipsec/sys/kern/kern_descrip.c (revision 313313) @@ -1,4129 +1,4129 @@ /*- * Copyright (c) 1982, 1986, 1989, 1991, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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 University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)kern_descrip.c 8.6 (Berkeley) 4/19/94 */ #include __FBSDID("$FreeBSD$"); #include "opt_capsicum.h" #include "opt_compat.h" #include "opt_ddb.h" #include "opt_ktrace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KTRACE #include #endif #include #include #include #include #include static MALLOC_DEFINE(M_FILEDESC, "filedesc", "Open file descriptor table"); static MALLOC_DEFINE(M_FILEDESC_TO_LEADER, "filedesc_to_leader", "file desc to leader structures"); static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures"); MALLOC_DEFINE(M_FILECAPS, "filecaps", "descriptor capabilities"); MALLOC_DECLARE(M_FADVISE); static __read_mostly uma_zone_t file_zone; static __read_mostly uma_zone_t filedesc0_zone; static int closefp(struct filedesc *fdp, int fd, struct file *fp, struct thread *td, int holdleaders); static int fd_first_free(struct filedesc *fdp, int low, int size); static int fd_last_used(struct filedesc *fdp, int size); static void fdgrowtable(struct filedesc *fdp, int nfd); static void fdgrowtable_exp(struct filedesc *fdp, int nfd); static void fdunused(struct filedesc *fdp, int fd); static void fdused(struct filedesc *fdp, int fd); static int getmaxfd(struct thread *td); /* * Each process has: * * - An array of open file descriptors (fd_ofiles) * - An array of file flags (fd_ofileflags) * - A bitmap recording which descriptors are in use (fd_map) * * A process starts out with NDFILE descriptors. The value of NDFILE has * been selected based the historical limit of 20 open files, and an * assumption that the majority of processes, especially short-lived * processes like shells, will never need more. * * If this initial allocation is exhausted, a larger descriptor table and * map are allocated dynamically, and the pointers in the process's struct * filedesc are updated to point to those. This is repeated every time * the process runs out of file descriptors (provided it hasn't hit its * resource limit). * * Since threads may hold references to individual descriptor table * entries, the tables are never freed. Instead, they are placed on a * linked list and freed only when the struct filedesc is released. */ #define NDFILE 20 #define NDSLOTSIZE sizeof(NDSLOTTYPE) #define NDENTRIES (NDSLOTSIZE * __CHAR_BIT) #define NDSLOT(x) ((x) / NDENTRIES) #define NDBIT(x) ((NDSLOTTYPE)1 << ((x) % NDENTRIES)) #define NDSLOTS(x) (((x) + NDENTRIES - 1) / NDENTRIES) /* * SLIST entry used to keep track of ofiles which must be reclaimed when * the process exits. */ struct freetable { struct fdescenttbl *ft_table; SLIST_ENTRY(freetable) ft_next; }; /* * Initial allocation: a filedesc structure + the head of SLIST used to * keep track of old ofiles + enough space for NDFILE descriptors. */ struct fdescenttbl0 { int fdt_nfiles; struct filedescent fdt_ofiles[NDFILE]; }; struct filedesc0 { struct filedesc fd_fd; SLIST_HEAD(, freetable) fd_free; struct fdescenttbl0 fd_dfiles; NDSLOTTYPE fd_dmap[NDSLOTS(NDFILE)]; }; /* * Descriptor management. */ volatile int __exclusive_cache_line openfiles; /* actual number of open files */ struct mtx sigio_lock; /* mtx to protect pointers to sigio */ void __read_mostly (*mq_fdclose)(struct thread *td, int fd, struct file *fp); /* * If low >= size, just return low. Otherwise find the first zero bit in the * given bitmap, starting at low and not exceeding size - 1. Return size if * not found. */ static int fd_first_free(struct filedesc *fdp, int low, int size) { NDSLOTTYPE *map = fdp->fd_map; NDSLOTTYPE mask; int off, maxoff; if (low >= size) return (low); off = NDSLOT(low); if (low % NDENTRIES) { mask = ~(~(NDSLOTTYPE)0 >> (NDENTRIES - (low % NDENTRIES))); if ((mask &= ~map[off]) != 0UL) return (off * NDENTRIES + ffsl(mask) - 1); ++off; } for (maxoff = NDSLOTS(size); off < maxoff; ++off) if (map[off] != ~0UL) return (off * NDENTRIES + ffsl(~map[off]) - 1); return (size); } /* * Find the highest non-zero bit in the given bitmap, starting at 0 and * not exceeding size - 1. Return -1 if not found. */ static int fd_last_used(struct filedesc *fdp, int size) { NDSLOTTYPE *map = fdp->fd_map; NDSLOTTYPE mask; int off, minoff; off = NDSLOT(size); if (size % NDENTRIES) { mask = ~(~(NDSLOTTYPE)0 << (size % NDENTRIES)); if ((mask &= map[off]) != 0) return (off * NDENTRIES + flsl(mask) - 1); --off; } for (minoff = NDSLOT(0); off >= minoff; --off) if (map[off] != 0) return (off * NDENTRIES + flsl(map[off]) - 1); return (-1); } static int fdisused(struct filedesc *fdp, int fd) { KASSERT(fd >= 0 && fd < fdp->fd_nfiles, ("file descriptor %d out of range (0, %d)", fd, fdp->fd_nfiles)); return ((fdp->fd_map[NDSLOT(fd)] & NDBIT(fd)) != 0); } /* * Mark a file descriptor as used. */ static void fdused_init(struct filedesc *fdp, int fd) { KASSERT(!fdisused(fdp, fd), ("fd=%d is already used", fd)); fdp->fd_map[NDSLOT(fd)] |= NDBIT(fd); } static void fdused(struct filedesc *fdp, int fd) { FILEDESC_XLOCK_ASSERT(fdp); fdused_init(fdp, fd); if (fd > fdp->fd_lastfile) fdp->fd_lastfile = fd; if (fd == fdp->fd_freefile) fdp->fd_freefile = fd_first_free(fdp, fd, fdp->fd_nfiles); } /* * Mark a file descriptor as unused. */ static void fdunused(struct filedesc *fdp, int fd) { FILEDESC_XLOCK_ASSERT(fdp); KASSERT(fdisused(fdp, fd), ("fd=%d is already unused", fd)); KASSERT(fdp->fd_ofiles[fd].fde_file == NULL, ("fd=%d is still in use", fd)); fdp->fd_map[NDSLOT(fd)] &= ~NDBIT(fd); if (fd < fdp->fd_freefile) fdp->fd_freefile = fd; if (fd == fdp->fd_lastfile) fdp->fd_lastfile = fd_last_used(fdp, fd); } /* * Free a file descriptor. * * Avoid some work if fdp is about to be destroyed. */ static inline void fdefree_last(struct filedescent *fde) { filecaps_free(&fde->fde_caps); } static inline void fdfree(struct filedesc *fdp, int fd) { struct filedescent *fde; fde = &fdp->fd_ofiles[fd]; #ifdef CAPABILITIES seq_write_begin(&fde->fde_seq); #endif fdefree_last(fde); fde->fde_file = NULL; fdunused(fdp, fd); #ifdef CAPABILITIES seq_write_end(&fde->fde_seq); #endif } void pwd_ensure_dirs(void) { struct filedesc *fdp; fdp = curproc->p_fd; FILEDESC_XLOCK(fdp); if (fdp->fd_cdir == NULL) { fdp->fd_cdir = rootvnode; vrefact(rootvnode); } if (fdp->fd_rdir == NULL) { fdp->fd_rdir = rootvnode; vrefact(rootvnode); } FILEDESC_XUNLOCK(fdp); } /* * System calls on descriptors. */ #ifndef _SYS_SYSPROTO_H_ struct getdtablesize_args { int dummy; }; #endif /* ARGSUSED */ int sys_getdtablesize(struct thread *td, struct getdtablesize_args *uap) { #ifdef RACCT uint64_t lim; #endif td->td_retval[0] = min((int)lim_cur(td, RLIMIT_NOFILE), maxfilesperproc); #ifdef RACCT PROC_LOCK(td->td_proc); lim = racct_get_limit(td->td_proc, RACCT_NOFILE); PROC_UNLOCK(td->td_proc); if (lim < td->td_retval[0]) td->td_retval[0] = lim; #endif return (0); } /* * Duplicate a file descriptor to a particular value. * * Note: keep in mind that a potential race condition exists when closing * descriptors from a shared descriptor table (via rfork). */ #ifndef _SYS_SYSPROTO_H_ struct dup2_args { u_int from; u_int to; }; #endif /* ARGSUSED */ int sys_dup2(struct thread *td, struct dup2_args *uap) { return (kern_dup(td, FDDUP_FIXED, 0, (int)uap->from, (int)uap->to)); } /* * Duplicate a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct dup_args { u_int fd; }; #endif /* ARGSUSED */ int sys_dup(struct thread *td, struct dup_args *uap) { return (kern_dup(td, FDDUP_NORMAL, 0, (int)uap->fd, 0)); } /* * The file control system call. */ #ifndef _SYS_SYSPROTO_H_ struct fcntl_args { int fd; int cmd; long arg; }; #endif /* ARGSUSED */ int sys_fcntl(struct thread *td, struct fcntl_args *uap) { return (kern_fcntl_freebsd(td, uap->fd, uap->cmd, uap->arg)); } int kern_fcntl_freebsd(struct thread *td, int fd, int cmd, long arg) { struct flock fl; struct __oflock ofl; intptr_t arg1; int error, newcmd; error = 0; newcmd = cmd; switch (cmd) { case F_OGETLK: case F_OSETLK: case F_OSETLKW: /* * Convert old flock structure to new. */ error = copyin((void *)(intptr_t)arg, &ofl, sizeof(ofl)); fl.l_start = ofl.l_start; fl.l_len = ofl.l_len; fl.l_pid = ofl.l_pid; fl.l_type = ofl.l_type; fl.l_whence = ofl.l_whence; fl.l_sysid = 0; switch (cmd) { case F_OGETLK: newcmd = F_GETLK; break; case F_OSETLK: newcmd = F_SETLK; break; case F_OSETLKW: newcmd = F_SETLKW; break; } arg1 = (intptr_t)&fl; break; case F_GETLK: case F_SETLK: case F_SETLKW: case F_SETLK_REMOTE: error = copyin((void *)(intptr_t)arg, &fl, sizeof(fl)); arg1 = (intptr_t)&fl; break; default: arg1 = arg; break; } if (error) return (error); error = kern_fcntl(td, fd, newcmd, arg1); if (error) return (error); if (cmd == F_OGETLK) { ofl.l_start = fl.l_start; ofl.l_len = fl.l_len; ofl.l_pid = fl.l_pid; ofl.l_type = fl.l_type; ofl.l_whence = fl.l_whence; error = copyout(&ofl, (void *)(intptr_t)arg, sizeof(ofl)); } else if (cmd == F_GETLK) { error = copyout(&fl, (void *)(intptr_t)arg, sizeof(fl)); } return (error); } int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) { struct filedesc *fdp; struct flock *flp; struct file *fp, *fp2; struct filedescent *fde; struct proc *p; struct vnode *vp; cap_rights_t rights; int error, flg, tmp; uint64_t bsize; off_t foffset; error = 0; flg = F_POSIX; p = td->td_proc; fdp = p->p_fd; AUDIT_ARG_FD(cmd); AUDIT_ARG_CMD(cmd); switch (cmd) { case F_DUPFD: tmp = arg; error = kern_dup(td, FDDUP_FCNTL, 0, fd, tmp); break; case F_DUPFD_CLOEXEC: tmp = arg; error = kern_dup(td, FDDUP_FCNTL, FDDUP_FLAG_CLOEXEC, fd, tmp); break; case F_DUP2FD: tmp = arg; error = kern_dup(td, FDDUP_FIXED, 0, fd, tmp); break; case F_DUP2FD_CLOEXEC: tmp = arg; error = kern_dup(td, FDDUP_FIXED, FDDUP_FLAG_CLOEXEC, fd, tmp); break; case F_GETFD: error = EBADF; FILEDESC_SLOCK(fdp); fde = fdeget_locked(fdp, fd); if (fde != NULL) { td->td_retval[0] = (fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0; error = 0; } FILEDESC_SUNLOCK(fdp); break; case F_SETFD: error = EBADF; FILEDESC_XLOCK(fdp); fde = fdeget_locked(fdp, fd); if (fde != NULL) { fde->fde_flags = (fde->fde_flags & ~UF_EXCLOSE) | (arg & FD_CLOEXEC ? UF_EXCLOSE : 0); error = 0; } FILEDESC_XUNLOCK(fdp); break; case F_GETFL: error = fget_fcntl(td, fd, cap_rights_init(&rights, CAP_FCNTL), F_GETFL, &fp); if (error != 0) break; td->td_retval[0] = OFLAGS(fp->f_flag); fdrop(fp, td); break; case F_SETFL: error = fget_fcntl(td, fd, cap_rights_init(&rights, CAP_FCNTL), F_SETFL, &fp); if (error != 0) break; do { tmp = flg = fp->f_flag; tmp &= ~FCNTLFLAGS; tmp |= FFLAGS(arg & ~O_ACCMODE) & FCNTLFLAGS; } while(atomic_cmpset_int(&fp->f_flag, flg, tmp) == 0); tmp = fp->f_flag & FNONBLOCK; error = fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td); if (error != 0) { fdrop(fp, td); break; } tmp = fp->f_flag & FASYNC; error = fo_ioctl(fp, FIOASYNC, &tmp, td->td_ucred, td); if (error == 0) { fdrop(fp, td); break; } atomic_clear_int(&fp->f_flag, FNONBLOCK); tmp = 0; (void)fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td); fdrop(fp, td); break; case F_GETOWN: error = fget_fcntl(td, fd, cap_rights_init(&rights, CAP_FCNTL), F_GETOWN, &fp); if (error != 0) break; error = fo_ioctl(fp, FIOGETOWN, &tmp, td->td_ucred, td); if (error == 0) td->td_retval[0] = tmp; fdrop(fp, td); break; case F_SETOWN: error = fget_fcntl(td, fd, cap_rights_init(&rights, CAP_FCNTL), F_SETOWN, &fp); if (error != 0) break; tmp = arg; error = fo_ioctl(fp, FIOSETOWN, &tmp, td->td_ucred, td); fdrop(fp, td); break; case F_SETLK_REMOTE: error = priv_check(td, PRIV_NFS_LOCKD); if (error) return (error); flg = F_REMOTE; goto do_setlk; case F_SETLKW: flg |= F_WAIT; /* FALLTHROUGH F_SETLK */ case F_SETLK: do_setlk: cap_rights_init(&rights, CAP_FLOCK); error = fget_unlocked(fdp, fd, &rights, &fp, NULL); if (error != 0) break; if (fp->f_type != DTYPE_VNODE) { error = EBADF; fdrop(fp, td); break; } flp = (struct flock *)arg; if (flp->l_whence == SEEK_CUR) { foffset = foffset_get(fp); if (foffset < 0 || (flp->l_start > 0 && foffset > OFF_MAX - flp->l_start)) { error = EOVERFLOW; fdrop(fp, td); break; } flp->l_start += foffset; } vp = fp->f_vnode; switch (flp->l_type) { case F_RDLCK: if ((fp->f_flag & FREAD) == 0) { error = EBADF; break; } PROC_LOCK(p->p_leader); p->p_leader->p_flag |= P_ADVLOCK; PROC_UNLOCK(p->p_leader); error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_SETLK, flp, flg); break; case F_WRLCK: if ((fp->f_flag & FWRITE) == 0) { error = EBADF; break; } PROC_LOCK(p->p_leader); p->p_leader->p_flag |= P_ADVLOCK; PROC_UNLOCK(p->p_leader); error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_SETLK, flp, flg); break; case F_UNLCK: error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_UNLCK, flp, flg); break; case F_UNLCKSYS: /* * Temporary api for testing remote lock * infrastructure. */ if (flg != F_REMOTE) { error = EINVAL; break; } error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_UNLCKSYS, flp, flg); break; default: error = EINVAL; break; } if (error != 0 || flp->l_type == F_UNLCK || flp->l_type == F_UNLCKSYS) { fdrop(fp, td); break; } /* * Check for a race with close. * * The vnode is now advisory locked (or unlocked, but this case * is not really important) as the caller requested. * We had to drop the filedesc lock, so we need to recheck if * the descriptor is still valid, because if it was closed * in the meantime we need to remove advisory lock from the * vnode - close on any descriptor leading to an advisory * locked vnode, removes that lock. * We will return 0 on purpose in that case, as the result of * successful advisory lock might have been externally visible * already. This is fine - effectively we pretend to the caller * that the closing thread was a bit slower and that the * advisory lock succeeded before the close. */ error = fget_unlocked(fdp, fd, &rights, &fp2, NULL); if (error != 0) { fdrop(fp, td); break; } if (fp != fp2) { flp->l_whence = SEEK_SET; flp->l_start = 0; flp->l_len = 0; flp->l_type = F_UNLCK; (void) VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_UNLCK, flp, F_POSIX); } fdrop(fp, td); fdrop(fp2, td); break; case F_GETLK: error = fget_unlocked(fdp, fd, cap_rights_init(&rights, CAP_FLOCK), &fp, NULL); if (error != 0) break; if (fp->f_type != DTYPE_VNODE) { error = EBADF; fdrop(fp, td); break; } flp = (struct flock *)arg; if (flp->l_type != F_RDLCK && flp->l_type != F_WRLCK && flp->l_type != F_UNLCK) { error = EINVAL; fdrop(fp, td); break; } if (flp->l_whence == SEEK_CUR) { foffset = foffset_get(fp); if ((flp->l_start > 0 && foffset > OFF_MAX - flp->l_start) || (flp->l_start < 0 && foffset < OFF_MIN - flp->l_start)) { error = EOVERFLOW; fdrop(fp, td); break; } flp->l_start += foffset; } vp = fp->f_vnode; error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_GETLK, flp, F_POSIX); fdrop(fp, td); break; case F_RDAHEAD: arg = arg ? 128 * 1024: 0; /* FALLTHROUGH */ case F_READAHEAD: error = fget_unlocked(fdp, fd, cap_rights_init(&rights), &fp, NULL); if (error != 0) break; if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); error = EBADF; break; } vp = fp->f_vnode; /* * Exclusive lock synchronizes against f_seqcount reads and * writes in sequential_heuristic(). */ error = vn_lock(vp, LK_EXCLUSIVE); if (error != 0) { fdrop(fp, td); break; } if (arg >= 0) { bsize = fp->f_vnode->v_mount->mnt_stat.f_iosize; fp->f_seqcount = (arg + bsize - 1) / bsize; atomic_set_int(&fp->f_flag, FRDAHEAD); } else { atomic_clear_int(&fp->f_flag, FRDAHEAD); } VOP_UNLOCK(vp, 0); fdrop(fp, td); break; default: error = EINVAL; break; } return (error); } static int getmaxfd(struct thread *td) { return (min((int)lim_cur(td, RLIMIT_NOFILE), maxfilesperproc)); } /* * Common code for dup, dup2, fcntl(F_DUPFD) and fcntl(F_DUP2FD). */ int kern_dup(struct thread *td, u_int mode, int flags, int old, int new) { struct filedesc *fdp; struct filedescent *oldfde, *newfde; struct proc *p; struct file *delfp; int error, maxfd; p = td->td_proc; fdp = p->p_fd; MPASS((flags & ~(FDDUP_FLAG_CLOEXEC)) == 0); MPASS(mode < FDDUP_LASTMODE); AUDIT_ARG_FD(old); /* XXXRW: if (flags & FDDUP_FIXED) AUDIT_ARG_FD2(new); */ /* * Verify we have a valid descriptor to dup from and possibly to * dup to. Unlike dup() and dup2(), fcntl()'s F_DUPFD should * return EINVAL when the new descriptor is out of bounds. */ if (old < 0) return (EBADF); if (new < 0) return (mode == FDDUP_FCNTL ? EINVAL : EBADF); maxfd = getmaxfd(td); if (new >= maxfd) return (mode == FDDUP_FCNTL ? EINVAL : EBADF); error = EBADF; FILEDESC_XLOCK(fdp); if (fget_locked(fdp, old) == NULL) goto unlock; if ((mode == FDDUP_FIXED || mode == FDDUP_MUSTREPLACE) && old == new) { td->td_retval[0] = new; if (flags & FDDUP_FLAG_CLOEXEC) fdp->fd_ofiles[new].fde_flags |= UF_EXCLOSE; error = 0; goto unlock; } /* * If the caller specified a file descriptor, make sure the file * table is large enough to hold it, and grab it. Otherwise, just * allocate a new descriptor the usual way. */ switch (mode) { case FDDUP_NORMAL: case FDDUP_FCNTL: if ((error = fdalloc(td, new, &new)) != 0) goto unlock; break; case FDDUP_MUSTREPLACE: /* Target file descriptor must exist. */ if (fget_locked(fdp, new) == NULL) goto unlock; break; case FDDUP_FIXED: if (new >= fdp->fd_nfiles) { /* * The resource limits are here instead of e.g. * fdalloc(), because the file descriptor table may be * shared between processes, so we can't really use * racct_add()/racct_sub(). Instead of counting the * number of actually allocated descriptors, just put * the limit on the size of the file descriptor table. */ #ifdef RACCT if (racct_enable) { PROC_LOCK(p); error = racct_set(p, RACCT_NOFILE, new + 1); PROC_UNLOCK(p); if (error != 0) { error = EMFILE; goto unlock; } } #endif fdgrowtable_exp(fdp, new + 1); } if (!fdisused(fdp, new)) fdused(fdp, new); break; default: KASSERT(0, ("%s unsupported mode %d", __func__, mode)); } KASSERT(old != new, ("new fd is same as old")); oldfde = &fdp->fd_ofiles[old]; fhold(oldfde->fde_file); newfde = &fdp->fd_ofiles[new]; delfp = newfde->fde_file; /* * Duplicate the source descriptor. */ #ifdef CAPABILITIES seq_write_begin(&newfde->fde_seq); #endif filecaps_free(&newfde->fde_caps); memcpy(newfde, oldfde, fde_change_size); filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps, true); if ((flags & FDDUP_FLAG_CLOEXEC) != 0) newfde->fde_flags = oldfde->fde_flags | UF_EXCLOSE; else newfde->fde_flags = oldfde->fde_flags & ~UF_EXCLOSE; #ifdef CAPABILITIES seq_write_end(&newfde->fde_seq); #endif td->td_retval[0] = new; error = 0; if (delfp != NULL) { (void) closefp(fdp, new, delfp, td, 1); FILEDESC_UNLOCK_ASSERT(fdp); } else { unlock: FILEDESC_XUNLOCK(fdp); } return (error); } /* * If sigio is on the list associated with a process or process group, * disable signalling from the device, remove sigio from the list and * free sigio. */ void funsetown(struct sigio **sigiop) { struct sigio *sigio; if (*sigiop == NULL) return; SIGIO_LOCK(); sigio = *sigiop; if (sigio == NULL) { SIGIO_UNLOCK(); return; } *(sigio->sio_myref) = NULL; if ((sigio)->sio_pgid < 0) { struct pgrp *pg = (sigio)->sio_pgrp; PGRP_LOCK(pg); SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio, sigio, sio_pgsigio); PGRP_UNLOCK(pg); } else { struct proc *p = (sigio)->sio_proc; PROC_LOCK(p); SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio, sigio, sio_pgsigio); PROC_UNLOCK(p); } SIGIO_UNLOCK(); crfree(sigio->sio_ucred); free(sigio, M_SIGIO); } /* * Free a list of sigio structures. * We only need to lock the SIGIO_LOCK because we have made ourselves * inaccessible to callers of fsetown and therefore do not need to lock * the proc or pgrp struct for the list manipulation. */ void funsetownlst(struct sigiolst *sigiolst) { struct proc *p; struct pgrp *pg; struct sigio *sigio; sigio = SLIST_FIRST(sigiolst); if (sigio == NULL) return; p = NULL; pg = NULL; /* * Every entry of the list should belong * to a single proc or pgrp. */ if (sigio->sio_pgid < 0) { pg = sigio->sio_pgrp; PGRP_LOCK_ASSERT(pg, MA_NOTOWNED); } else /* if (sigio->sio_pgid > 0) */ { p = sigio->sio_proc; PROC_LOCK_ASSERT(p, MA_NOTOWNED); } SIGIO_LOCK(); while ((sigio = SLIST_FIRST(sigiolst)) != NULL) { *(sigio->sio_myref) = NULL; if (pg != NULL) { KASSERT(sigio->sio_pgid < 0, ("Proc sigio in pgrp sigio list")); KASSERT(sigio->sio_pgrp == pg, ("Bogus pgrp in sigio list")); PGRP_LOCK(pg); SLIST_REMOVE(&pg->pg_sigiolst, sigio, sigio, sio_pgsigio); PGRP_UNLOCK(pg); } else /* if (p != NULL) */ { KASSERT(sigio->sio_pgid > 0, ("Pgrp sigio in proc sigio list")); KASSERT(sigio->sio_proc == p, ("Bogus proc in sigio list")); PROC_LOCK(p); SLIST_REMOVE(&p->p_sigiolst, sigio, sigio, sio_pgsigio); PROC_UNLOCK(p); } SIGIO_UNLOCK(); crfree(sigio->sio_ucred); free(sigio, M_SIGIO); SIGIO_LOCK(); } SIGIO_UNLOCK(); } /* * This is common code for FIOSETOWN ioctl called by fcntl(fd, F_SETOWN, arg). * * After permission checking, add a sigio structure to the sigio list for * the process or process group. */ int fsetown(pid_t pgid, struct sigio **sigiop) { struct proc *proc; struct pgrp *pgrp; struct sigio *sigio; int ret; if (pgid == 0) { funsetown(sigiop); return (0); } ret = 0; /* Allocate and fill in the new sigio out of locks. */ sigio = malloc(sizeof(struct sigio), M_SIGIO, M_WAITOK); sigio->sio_pgid = pgid; sigio->sio_ucred = crhold(curthread->td_ucred); sigio->sio_myref = sigiop; sx_slock(&proctree_lock); if (pgid > 0) { proc = pfind(pgid); if (proc == NULL) { ret = ESRCH; goto fail; } /* * Policy - Don't allow a process to FSETOWN a process * in another session. * * Remove this test to allow maximum flexibility or * restrict FSETOWN to the current process or process * group for maximum safety. */ PROC_UNLOCK(proc); if (proc->p_session != curthread->td_proc->p_session) { ret = EPERM; goto fail; } pgrp = NULL; } else /* if (pgid < 0) */ { pgrp = pgfind(-pgid); if (pgrp == NULL) { ret = ESRCH; goto fail; } PGRP_UNLOCK(pgrp); /* * Policy - Don't allow a process to FSETOWN a process * in another session. * * Remove this test to allow maximum flexibility or * restrict FSETOWN to the current process or process * group for maximum safety. */ if (pgrp->pg_session != curthread->td_proc->p_session) { ret = EPERM; goto fail; } proc = NULL; } funsetown(sigiop); if (pgid > 0) { PROC_LOCK(proc); /* * Since funsetownlst() is called without the proctree * locked, we need to check for P_WEXIT. * XXX: is ESRCH correct? */ if ((proc->p_flag & P_WEXIT) != 0) { PROC_UNLOCK(proc); ret = ESRCH; goto fail; } SLIST_INSERT_HEAD(&proc->p_sigiolst, sigio, sio_pgsigio); sigio->sio_proc = proc; PROC_UNLOCK(proc); } else { PGRP_LOCK(pgrp); SLIST_INSERT_HEAD(&pgrp->pg_sigiolst, sigio, sio_pgsigio); sigio->sio_pgrp = pgrp; PGRP_UNLOCK(pgrp); } sx_sunlock(&proctree_lock); SIGIO_LOCK(); *sigiop = sigio; SIGIO_UNLOCK(); return (0); fail: sx_sunlock(&proctree_lock); crfree(sigio->sio_ucred); free(sigio, M_SIGIO); return (ret); } /* * This is common code for FIOGETOWN ioctl called by fcntl(fd, F_GETOWN, arg). */ pid_t fgetown(sigiop) struct sigio **sigiop; { pid_t pgid; SIGIO_LOCK(); pgid = (*sigiop != NULL) ? (*sigiop)->sio_pgid : 0; SIGIO_UNLOCK(); return (pgid); } /* * Function drops the filedesc lock on return. */ static int closefp(struct filedesc *fdp, int fd, struct file *fp, struct thread *td, int holdleaders) { int error; FILEDESC_XLOCK_ASSERT(fdp); if (holdleaders) { if (td->td_proc->p_fdtol != NULL) { /* * Ask fdfree() to sleep to ensure that all relevant * process leaders can be traversed in closef(). */ fdp->fd_holdleaderscount++; } else { holdleaders = 0; } } /* * We now hold the fp reference that used to be owned by the * descriptor array. We have to unlock the FILEDESC *AFTER* * knote_fdclose to prevent a race of the fd getting opened, a knote * added, and deleteing a knote for the new fd. */ knote_fdclose(td, fd); /* * We need to notify mqueue if the object is of type mqueue. */ if (fp->f_type == DTYPE_MQUEUE) mq_fdclose(td, fd, fp); FILEDESC_XUNLOCK(fdp); error = closef(fp, td); if (holdleaders) { FILEDESC_XLOCK(fdp); fdp->fd_holdleaderscount--; if (fdp->fd_holdleaderscount == 0 && fdp->fd_holdleaderswakeup != 0) { fdp->fd_holdleaderswakeup = 0; wakeup(&fdp->fd_holdleaderscount); } FILEDESC_XUNLOCK(fdp); } return (error); } /* * Close a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct close_args { int fd; }; #endif /* ARGSUSED */ int sys_close(struct thread *td, struct close_args *uap) { return (kern_close(td, uap->fd)); } int kern_close(struct thread *td, int fd) { struct filedesc *fdp; struct file *fp; fdp = td->td_proc->p_fd; AUDIT_SYSCLOSE(td, fd); FILEDESC_XLOCK(fdp); if ((fp = fget_locked(fdp, fd)) == NULL) { FILEDESC_XUNLOCK(fdp); return (EBADF); } fdfree(fdp, fd); /* closefp() drops the FILEDESC lock for us. */ return (closefp(fdp, fd, fp, td, 1)); } /* * Close open file descriptors. */ #ifndef _SYS_SYSPROTO_H_ struct closefrom_args { int lowfd; }; #endif /* ARGSUSED */ int sys_closefrom(struct thread *td, struct closefrom_args *uap) { struct filedesc *fdp; int fd; fdp = td->td_proc->p_fd; AUDIT_ARG_FD(uap->lowfd); /* * Treat negative starting file descriptor values identical to * closefrom(0) which closes all files. */ if (uap->lowfd < 0) uap->lowfd = 0; FILEDESC_SLOCK(fdp); for (fd = uap->lowfd; fd <= fdp->fd_lastfile; fd++) { if (fdp->fd_ofiles[fd].fde_file != NULL) { FILEDESC_SUNLOCK(fdp); (void)kern_close(td, fd); FILEDESC_SLOCK(fdp); } } FILEDESC_SUNLOCK(fdp); return (0); } #if defined(COMPAT_43) /* * Return status information about a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct ofstat_args { int fd; struct ostat *sb; }; #endif /* ARGSUSED */ int ofstat(struct thread *td, struct ofstat_args *uap) { struct ostat oub; struct stat ub; int error; error = kern_fstat(td, uap->fd, &ub); if (error == 0) { cvtstat(&ub, &oub); error = copyout(&oub, uap->sb, sizeof(oub)); } return (error); } #endif /* COMPAT_43 */ /* * Return status information about a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct fstat_args { int fd; struct stat *sb; }; #endif /* ARGSUSED */ int sys_fstat(struct thread *td, struct fstat_args *uap) { struct stat ub; int error; error = kern_fstat(td, uap->fd, &ub); if (error == 0) error = copyout(&ub, uap->sb, sizeof(ub)); return (error); } int kern_fstat(struct thread *td, int fd, struct stat *sbp) { struct file *fp; cap_rights_t rights; int error; AUDIT_ARG_FD(fd); error = fget(td, fd, cap_rights_init(&rights, CAP_FSTAT), &fp); if (error != 0) return (error); AUDIT_ARG_FILE(td->td_proc, fp); error = fo_stat(fp, sbp, td->td_ucred, td); fdrop(fp, td); #ifdef KTRACE if (error == 0 && KTRPOINT(td, KTR_STRUCT)) ktrstat(sbp); #endif return (error); } /* * Return status information about a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct nfstat_args { int fd; struct nstat *sb; }; #endif /* ARGSUSED */ int sys_nfstat(struct thread *td, struct nfstat_args *uap) { struct nstat nub; struct stat ub; int error; error = kern_fstat(td, uap->fd, &ub); if (error == 0) { cvtnstat(&ub, &nub); error = copyout(&nub, uap->sb, sizeof(nub)); } return (error); } /* * Return pathconf information about a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct fpathconf_args { int fd; int name; }; #endif /* ARGSUSED */ int sys_fpathconf(struct thread *td, struct fpathconf_args *uap) { struct file *fp; struct vnode *vp; cap_rights_t rights; int error; error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FPATHCONF), &fp); if (error != 0) return (error); if (uap->name == _PC_ASYNC_IO) { td->td_retval[0] = _POSIX_ASYNCHRONOUS_IO; goto out; } vp = fp->f_vnode; if (vp != NULL) { vn_lock(vp, LK_SHARED | LK_RETRY); error = VOP_PATHCONF(vp, uap->name, td->td_retval); VOP_UNLOCK(vp, 0); } else if (fp->f_type == DTYPE_PIPE || fp->f_type == DTYPE_SOCKET) { if (uap->name != _PC_PIPE_BUF) { error = EINVAL; } else { td->td_retval[0] = PIPE_BUF; error = 0; } } else { error = EOPNOTSUPP; } out: fdrop(fp, td); return (error); } /* * Initialize filecaps structure. */ void filecaps_init(struct filecaps *fcaps) { bzero(fcaps, sizeof(*fcaps)); fcaps->fc_nioctls = -1; } /* * Copy filecaps structure allocating memory for ioctls array if needed. * * The last parameter indicates whether the fdtable is locked. If it is not and * ioctls are encountered, copying fails and the caller must lock the table. * * Note that if the table was not locked, the caller has to check the relevant * sequence counter to determine whether the operation was successful. */ int filecaps_copy(const struct filecaps *src, struct filecaps *dst, bool locked) { size_t size; *dst = *src; if (src->fc_ioctls == NULL) return (0); if (!locked) return (1); KASSERT(src->fc_nioctls > 0, ("fc_ioctls != NULL, but fc_nioctls=%hd", src->fc_nioctls)); size = sizeof(src->fc_ioctls[0]) * src->fc_nioctls; dst->fc_ioctls = malloc(size, M_FILECAPS, M_WAITOK); bcopy(src->fc_ioctls, dst->fc_ioctls, size); return (0); } /* * Move filecaps structure to the new place and clear the old place. */ void filecaps_move(struct filecaps *src, struct filecaps *dst) { *dst = *src; bzero(src, sizeof(*src)); } /* * Fill the given filecaps structure with full rights. */ static void filecaps_fill(struct filecaps *fcaps) { CAP_ALL(&fcaps->fc_rights); fcaps->fc_ioctls = NULL; fcaps->fc_nioctls = -1; fcaps->fc_fcntls = CAP_FCNTL_ALL; } /* * Free memory allocated within filecaps structure. */ void filecaps_free(struct filecaps *fcaps) { free(fcaps->fc_ioctls, M_FILECAPS); bzero(fcaps, sizeof(*fcaps)); } /* * Validate the given filecaps structure. */ static void filecaps_validate(const struct filecaps *fcaps, const char *func) { KASSERT(cap_rights_is_valid(&fcaps->fc_rights), ("%s: invalid rights", func)); KASSERT((fcaps->fc_fcntls & ~CAP_FCNTL_ALL) == 0, ("%s: invalid fcntls", func)); KASSERT(fcaps->fc_fcntls == 0 || cap_rights_is_set(&fcaps->fc_rights, CAP_FCNTL), ("%s: fcntls without CAP_FCNTL", func)); KASSERT(fcaps->fc_ioctls != NULL ? fcaps->fc_nioctls > 0 : (fcaps->fc_nioctls == -1 || fcaps->fc_nioctls == 0), ("%s: invalid ioctls", func)); KASSERT(fcaps->fc_nioctls == 0 || cap_rights_is_set(&fcaps->fc_rights, CAP_IOCTL), ("%s: ioctls without CAP_IOCTL", func)); } static void fdgrowtable_exp(struct filedesc *fdp, int nfd) { int nfd1; FILEDESC_XLOCK_ASSERT(fdp); nfd1 = fdp->fd_nfiles * 2; if (nfd1 < nfd) nfd1 = nfd; fdgrowtable(fdp, nfd1); } /* * Grow the file table to accommodate (at least) nfd descriptors. */ static void fdgrowtable(struct filedesc *fdp, int nfd) { struct filedesc0 *fdp0; struct freetable *ft; struct fdescenttbl *ntable; struct fdescenttbl *otable; int nnfiles, onfiles; NDSLOTTYPE *nmap, *omap; /* * If lastfile is -1 this struct filedesc was just allocated and we are * growing it to accommodate for the one we are going to copy from. There * is no need to have a lock on this one as it's not visible to anyone. */ if (fdp->fd_lastfile != -1) FILEDESC_XLOCK_ASSERT(fdp); KASSERT(fdp->fd_nfiles > 0, ("zero-length file table")); /* save old values */ onfiles = fdp->fd_nfiles; otable = fdp->fd_files; omap = fdp->fd_map; /* compute the size of the new table */ nnfiles = NDSLOTS(nfd) * NDENTRIES; /* round up */ if (nnfiles <= onfiles) /* the table is already large enough */ return; /* * Allocate a new table. We need enough space for the number of * entries, file entries themselves and the struct freetable we will use * when we decommission the table and place it on the freelist. * We place the struct freetable in the middle so we don't have * to worry about padding. */ ntable = malloc(offsetof(struct fdescenttbl, fdt_ofiles) + nnfiles * sizeof(ntable->fdt_ofiles[0]) + sizeof(struct freetable), M_FILEDESC, M_ZERO | M_WAITOK); /* copy the old data */ ntable->fdt_nfiles = nnfiles; memcpy(ntable->fdt_ofiles, otable->fdt_ofiles, onfiles * sizeof(ntable->fdt_ofiles[0])); /* * Allocate a new map only if the old is not large enough. It will * grow at a slower rate than the table as it can map more * entries than the table can hold. */ if (NDSLOTS(nnfiles) > NDSLOTS(onfiles)) { nmap = malloc(NDSLOTS(nnfiles) * NDSLOTSIZE, M_FILEDESC, M_ZERO | M_WAITOK); /* copy over the old data and update the pointer */ memcpy(nmap, omap, NDSLOTS(onfiles) * sizeof(*omap)); fdp->fd_map = nmap; } /* * Make sure that ntable is correctly initialized before we replace * fd_files poiner. Otherwise fget_unlocked() may see inconsistent * data. */ atomic_store_rel_ptr((volatile void *)&fdp->fd_files, (uintptr_t)ntable); /* * Do not free the old file table, as some threads may still * reference entries within it. Instead, place it on a freelist * which will be processed when the struct filedesc is released. * * Note that if onfiles == NDFILE, we're dealing with the original * static allocation contained within (struct filedesc0 *)fdp, * which must not be freed. */ if (onfiles > NDFILE) { ft = (struct freetable *)&otable->fdt_ofiles[onfiles]; fdp0 = (struct filedesc0 *)fdp; ft->ft_table = otable; SLIST_INSERT_HEAD(&fdp0->fd_free, ft, ft_next); } /* * The map does not have the same possibility of threads still * holding references to it. So always free it as long as it * does not reference the original static allocation. */ if (NDSLOTS(onfiles) > NDSLOTS(NDFILE)) free(omap, M_FILEDESC); } /* * Allocate a file descriptor for the process. */ int fdalloc(struct thread *td, int minfd, int *result) { struct proc *p = td->td_proc; struct filedesc *fdp = p->p_fd; int fd, maxfd, allocfd; #ifdef RACCT int error; #endif FILEDESC_XLOCK_ASSERT(fdp); if (fdp->fd_freefile > minfd) minfd = fdp->fd_freefile; maxfd = getmaxfd(td); /* * Search the bitmap for a free descriptor starting at minfd. * If none is found, grow the file table. */ fd = fd_first_free(fdp, minfd, fdp->fd_nfiles); if (fd >= maxfd) return (EMFILE); if (fd >= fdp->fd_nfiles) { allocfd = min(fd * 2, maxfd); #ifdef RACCT if (racct_enable) { PROC_LOCK(p); error = racct_set(p, RACCT_NOFILE, allocfd); PROC_UNLOCK(p); if (error != 0) return (EMFILE); } #endif /* * fd is already equal to first free descriptor >= minfd, so * we only need to grow the table and we are done. */ fdgrowtable_exp(fdp, allocfd); } /* * Perform some sanity checks, then mark the file descriptor as * used and return it to the caller. */ KASSERT(fd >= 0 && fd < min(maxfd, fdp->fd_nfiles), ("invalid descriptor %d", fd)); KASSERT(!fdisused(fdp, fd), ("fd_first_free() returned non-free descriptor")); KASSERT(fdp->fd_ofiles[fd].fde_file == NULL, ("file descriptor isn't free")); fdused(fdp, fd); *result = fd; return (0); } /* * Allocate n file descriptors for the process. */ int fdallocn(struct thread *td, int minfd, int *fds, int n) { struct proc *p = td->td_proc; struct filedesc *fdp = p->p_fd; int i; FILEDESC_XLOCK_ASSERT(fdp); for (i = 0; i < n; i++) if (fdalloc(td, 0, &fds[i]) != 0) break; if (i < n) { for (i--; i >= 0; i--) fdunused(fdp, fds[i]); return (EMFILE); } return (0); } /* * Create a new open file structure and allocate a file descriptor for the * process that refers to it. We add one reference to the file for the * descriptor table and one reference for resultfp. This is to prevent us * being preempted and the entry in the descriptor table closed after we * release the FILEDESC lock. */ int falloc_caps(struct thread *td, struct file **resultfp, int *resultfd, int flags, struct filecaps *fcaps) { struct file *fp; int error, fd; error = falloc_noinstall(td, &fp); if (error) return (error); /* no reference held on error */ error = finstall(td, fp, &fd, flags, fcaps); if (error) { fdrop(fp, td); /* one reference (fp only) */ return (error); } if (resultfp != NULL) *resultfp = fp; /* copy out result */ else fdrop(fp, td); /* release local reference */ if (resultfd != NULL) *resultfd = fd; return (0); } /* * Create a new open file structure without allocating a file descriptor. */ int falloc_noinstall(struct thread *td, struct file **resultfp) { struct file *fp; int maxuserfiles = maxfiles - (maxfiles / 20); int openfiles_new; static struct timeval lastfail; static int curfail; KASSERT(resultfp != NULL, ("%s: resultfp == NULL", __func__)); openfiles_new = atomic_fetchadd_int(&openfiles, 1) + 1; if ((openfiles_new >= maxuserfiles && priv_check(td, PRIV_MAXFILES) != 0) || openfiles_new >= maxfiles) { atomic_subtract_int(&openfiles, 1); if (ppsratecheck(&lastfail, &curfail, 1)) { printf("kern.maxfiles limit exceeded by uid %i, (%s) " "please see tuning(7).\n", td->td_ucred->cr_ruid, td->td_proc->p_comm); } return (ENFILE); } fp = uma_zalloc(file_zone, M_WAITOK | M_ZERO); refcount_init(&fp->f_count, 1); fp->f_cred = crhold(td->td_ucred); fp->f_ops = &badfileops; *resultfp = fp; return (0); } /* * Install a file in a file descriptor table. */ void _finstall(struct filedesc *fdp, struct file *fp, int fd, int flags, struct filecaps *fcaps) { struct filedescent *fde; MPASS(fp != NULL); if (fcaps != NULL) filecaps_validate(fcaps, __func__); FILEDESC_XLOCK_ASSERT(fdp); fde = &fdp->fd_ofiles[fd]; #ifdef CAPABILITIES seq_write_begin(&fde->fde_seq); #endif fde->fde_file = fp; fde->fde_flags = (flags & O_CLOEXEC) != 0 ? UF_EXCLOSE : 0; if (fcaps != NULL) filecaps_move(fcaps, &fde->fde_caps); else filecaps_fill(&fde->fde_caps); #ifdef CAPABILITIES seq_write_end(&fde->fde_seq); #endif } int finstall(struct thread *td, struct file *fp, int *fd, int flags, struct filecaps *fcaps) { struct filedesc *fdp = td->td_proc->p_fd; int error; MPASS(fd != NULL); FILEDESC_XLOCK(fdp); if ((error = fdalloc(td, 0, fd))) { FILEDESC_XUNLOCK(fdp); return (error); } fhold(fp); _finstall(fdp, fp, *fd, flags, fcaps); FILEDESC_XUNLOCK(fdp); return (0); } /* * Build a new filedesc structure from another. * Copy the current, root, and jail root vnode references. * * If fdp is not NULL, return with it shared locked. */ struct filedesc * fdinit(struct filedesc *fdp, bool prepfiles) { struct filedesc0 *newfdp0; struct filedesc *newfdp; newfdp0 = uma_zalloc(filedesc0_zone, M_WAITOK | M_ZERO); newfdp = &newfdp0->fd_fd; /* Create the file descriptor table. */ FILEDESC_LOCK_INIT(newfdp); refcount_init(&newfdp->fd_refcnt, 1); refcount_init(&newfdp->fd_holdcnt, 1); newfdp->fd_cmask = CMASK; newfdp->fd_map = newfdp0->fd_dmap; newfdp->fd_lastfile = -1; newfdp->fd_files = (struct fdescenttbl *)&newfdp0->fd_dfiles; newfdp->fd_files->fdt_nfiles = NDFILE; if (fdp == NULL) return (newfdp); if (prepfiles && fdp->fd_lastfile >= newfdp->fd_nfiles) fdgrowtable(newfdp, fdp->fd_lastfile + 1); FILEDESC_SLOCK(fdp); newfdp->fd_cdir = fdp->fd_cdir; if (newfdp->fd_cdir) vrefact(newfdp->fd_cdir); newfdp->fd_rdir = fdp->fd_rdir; if (newfdp->fd_rdir) vrefact(newfdp->fd_rdir); newfdp->fd_jdir = fdp->fd_jdir; if (newfdp->fd_jdir) vrefact(newfdp->fd_jdir); if (!prepfiles) { FILEDESC_SUNLOCK(fdp); } else { while (fdp->fd_lastfile >= newfdp->fd_nfiles) { FILEDESC_SUNLOCK(fdp); fdgrowtable(newfdp, fdp->fd_lastfile + 1); FILEDESC_SLOCK(fdp); } } return (newfdp); } static struct filedesc * fdhold(struct proc *p) { struct filedesc *fdp; PROC_LOCK_ASSERT(p, MA_OWNED); fdp = p->p_fd; if (fdp != NULL) refcount_acquire(&fdp->fd_holdcnt); return (fdp); } static void fddrop(struct filedesc *fdp) { if (fdp->fd_holdcnt > 1) { if (refcount_release(&fdp->fd_holdcnt) == 0) return; } FILEDESC_LOCK_DESTROY(fdp); uma_zfree(filedesc0_zone, fdp); } /* * Share a filedesc structure. */ struct filedesc * fdshare(struct filedesc *fdp) { refcount_acquire(&fdp->fd_refcnt); return (fdp); } /* * Unshare a filedesc structure, if necessary by making a copy */ void fdunshare(struct thread *td) { struct filedesc *tmp; struct proc *p = td->td_proc; if (p->p_fd->fd_refcnt == 1) return; tmp = fdcopy(p->p_fd); fdescfree(td); p->p_fd = tmp; } void fdinstall_remapped(struct thread *td, struct filedesc *fdp) { fdescfree(td); td->td_proc->p_fd = fdp; } /* * Copy a filedesc structure. A NULL pointer in returns a NULL reference, * this is to ease callers, not catch errors. */ struct filedesc * fdcopy(struct filedesc *fdp) { struct filedesc *newfdp; struct filedescent *nfde, *ofde; int i; MPASS(fdp != NULL); newfdp = fdinit(fdp, true); /* copy all passable descriptors (i.e. not kqueue) */ newfdp->fd_freefile = -1; for (i = 0; i <= fdp->fd_lastfile; ++i) { ofde = &fdp->fd_ofiles[i]; if (ofde->fde_file == NULL || (ofde->fde_file->f_ops->fo_flags & DFLAG_PASSABLE) == 0) { if (newfdp->fd_freefile == -1) newfdp->fd_freefile = i; continue; } nfde = &newfdp->fd_ofiles[i]; *nfde = *ofde; filecaps_copy(&ofde->fde_caps, &nfde->fde_caps, true); fhold(nfde->fde_file); fdused_init(newfdp, i); newfdp->fd_lastfile = i; } if (newfdp->fd_freefile == -1) newfdp->fd_freefile = i; newfdp->fd_cmask = fdp->fd_cmask; FILEDESC_SUNLOCK(fdp); return (newfdp); } /* * Copies a filedesc structure, while remapping all file descriptors * stored inside using a translation table. * * File descriptors are copied over to the new file descriptor table, * regardless of whether the close-on-exec flag is set. */ int fdcopy_remapped(struct filedesc *fdp, const int *fds, size_t nfds, struct filedesc **ret) { struct filedesc *newfdp; struct filedescent *nfde, *ofde; int error, i; MPASS(fdp != NULL); newfdp = fdinit(fdp, true); if (nfds > fdp->fd_lastfile + 1) { /* New table cannot be larger than the old one. */ error = E2BIG; goto bad; } /* Copy all passable descriptors (i.e. not kqueue). */ newfdp->fd_freefile = nfds; for (i = 0; i < nfds; ++i) { if (fds[i] < 0 || fds[i] > fdp->fd_lastfile) { /* File descriptor out of bounds. */ error = EBADF; goto bad; } ofde = &fdp->fd_ofiles[fds[i]]; if (ofde->fde_file == NULL) { /* Unused file descriptor. */ error = EBADF; goto bad; } if ((ofde->fde_file->f_ops->fo_flags & DFLAG_PASSABLE) == 0) { /* File descriptor cannot be passed. */ error = EINVAL; goto bad; } nfde = &newfdp->fd_ofiles[i]; *nfde = *ofde; filecaps_copy(&ofde->fde_caps, &nfde->fde_caps, true); fhold(nfde->fde_file); fdused_init(newfdp, i); newfdp->fd_lastfile = i; } newfdp->fd_cmask = fdp->fd_cmask; FILEDESC_SUNLOCK(fdp); *ret = newfdp; return (0); bad: FILEDESC_SUNLOCK(fdp); fdescfree_remapped(newfdp); return (error); } /* * Clear POSIX style locks. This is only used when fdp looses a reference (i.e. * one of processes using it exits) and the table used to be shared. */ static void fdclearlocks(struct thread *td) { struct filedesc *fdp; struct filedesc_to_leader *fdtol; struct flock lf; struct file *fp; struct proc *p; struct vnode *vp; int i; p = td->td_proc; fdp = p->p_fd; fdtol = p->p_fdtol; MPASS(fdtol != NULL); FILEDESC_XLOCK(fdp); KASSERT(fdtol->fdl_refcount > 0, ("filedesc_to_refcount botch: fdl_refcount=%d", fdtol->fdl_refcount)); if (fdtol->fdl_refcount == 1 && (p->p_leader->p_flag & P_ADVLOCK) != 0) { for (i = 0; i <= fdp->fd_lastfile; i++) { fp = fdp->fd_ofiles[i].fde_file; if (fp == NULL || fp->f_type != DTYPE_VNODE) continue; fhold(fp); FILEDESC_XUNLOCK(fdp); lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; lf.l_type = F_UNLCK; vp = fp->f_vnode; (void) VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_UNLCK, &lf, F_POSIX); FILEDESC_XLOCK(fdp); fdrop(fp, td); } } retry: if (fdtol->fdl_refcount == 1) { if (fdp->fd_holdleaderscount > 0 && (p->p_leader->p_flag & P_ADVLOCK) != 0) { /* * close() or kern_dup() has cleared a reference * in a shared file descriptor table. */ fdp->fd_holdleaderswakeup = 1; sx_sleep(&fdp->fd_holdleaderscount, FILEDESC_LOCK(fdp), PLOCK, "fdlhold", 0); goto retry; } if (fdtol->fdl_holdcount > 0) { /* * Ensure that fdtol->fdl_leader remains * valid in closef(). */ fdtol->fdl_wakeup = 1; sx_sleep(fdtol, FILEDESC_LOCK(fdp), PLOCK, "fdlhold", 0); goto retry; } } fdtol->fdl_refcount--; if (fdtol->fdl_refcount == 0 && fdtol->fdl_holdcount == 0) { fdtol->fdl_next->fdl_prev = fdtol->fdl_prev; fdtol->fdl_prev->fdl_next = fdtol->fdl_next; } else fdtol = NULL; p->p_fdtol = NULL; FILEDESC_XUNLOCK(fdp); if (fdtol != NULL) free(fdtol, M_FILEDESC_TO_LEADER); } /* * Release a filedesc structure. */ static void fdescfree_fds(struct thread *td, struct filedesc *fdp, bool needclose) { struct filedesc0 *fdp0; struct freetable *ft, *tft; struct filedescent *fde; struct file *fp; int i; for (i = 0; i <= fdp->fd_lastfile; i++) { fde = &fdp->fd_ofiles[i]; fp = fde->fde_file; if (fp != NULL) { fdefree_last(fde); if (needclose) (void) closef(fp, td); else fdrop(fp, td); } } if (NDSLOTS(fdp->fd_nfiles) > NDSLOTS(NDFILE)) free(fdp->fd_map, M_FILEDESC); if (fdp->fd_nfiles > NDFILE) free(fdp->fd_files, M_FILEDESC); fdp0 = (struct filedesc0 *)fdp; SLIST_FOREACH_SAFE(ft, &fdp0->fd_free, ft_next, tft) free(ft->ft_table, M_FILEDESC); fddrop(fdp); } void fdescfree(struct thread *td) { struct proc *p; struct filedesc *fdp; struct vnode *cdir, *jdir, *rdir; p = td->td_proc; fdp = p->p_fd; MPASS(fdp != NULL); #ifdef RACCT if (racct_enable) { PROC_LOCK(p); racct_set(p, RACCT_NOFILE, 0); PROC_UNLOCK(p); } #endif if (p->p_fdtol != NULL) fdclearlocks(td); PROC_LOCK(p); p->p_fd = NULL; PROC_UNLOCK(p); if (refcount_release(&fdp->fd_refcnt) == 0) return; FILEDESC_XLOCK(fdp); cdir = fdp->fd_cdir; fdp->fd_cdir = NULL; rdir = fdp->fd_rdir; fdp->fd_rdir = NULL; jdir = fdp->fd_jdir; fdp->fd_jdir = NULL; FILEDESC_XUNLOCK(fdp); if (cdir != NULL) vrele(cdir); if (rdir != NULL) vrele(rdir); if (jdir != NULL) vrele(jdir); fdescfree_fds(td, fdp, 1); } void fdescfree_remapped(struct filedesc *fdp) { if (fdp->fd_cdir != NULL) vrele(fdp->fd_cdir); if (fdp->fd_rdir != NULL) vrele(fdp->fd_rdir); if (fdp->fd_jdir != NULL) vrele(fdp->fd_jdir); fdescfree_fds(curthread, fdp, 0); } /* * For setugid programs, we don't want to people to use that setugidness * to generate error messages which write to a file which otherwise would * otherwise be off-limits to the process. We check for filesystems where * the vnode can change out from under us after execve (like [lin]procfs). * * Since fdsetugidsafety calls this only for fd 0, 1 and 2, this check is * sufficient. We also don't check for setugidness since we know we are. */ static bool is_unsafe(struct file *fp) { struct vnode *vp; if (fp->f_type != DTYPE_VNODE) return (false); vp = fp->f_vnode; return ((vp->v_vflag & VV_PROCDEP) != 0); } /* * Make this setguid thing safe, if at all possible. */ void fdsetugidsafety(struct thread *td) { struct filedesc *fdp; struct file *fp; int i; fdp = td->td_proc->p_fd; KASSERT(fdp->fd_refcnt == 1, ("the fdtable should not be shared")); MPASS(fdp->fd_nfiles >= 3); for (i = 0; i <= 2; i++) { fp = fdp->fd_ofiles[i].fde_file; if (fp != NULL && is_unsafe(fp)) { FILEDESC_XLOCK(fdp); knote_fdclose(td, i); /* * NULL-out descriptor prior to close to avoid * a race while close blocks. */ fdfree(fdp, i); FILEDESC_XUNLOCK(fdp); (void) closef(fp, td); } } } /* * If a specific file object occupies a specific file descriptor, close the * file descriptor entry and drop a reference on the file object. This is a * convenience function to handle a subsequent error in a function that calls * falloc() that handles the race that another thread might have closed the * file descriptor out from under the thread creating the file object. */ void fdclose(struct thread *td, struct file *fp, int idx) { struct filedesc *fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); if (fdp->fd_ofiles[idx].fde_file == fp) { fdfree(fdp, idx); FILEDESC_XUNLOCK(fdp); fdrop(fp, td); } else FILEDESC_XUNLOCK(fdp); } /* * Close any files on exec? */ void fdcloseexec(struct thread *td) { struct filedesc *fdp; struct filedescent *fde; struct file *fp; int i; fdp = td->td_proc->p_fd; KASSERT(fdp->fd_refcnt == 1, ("the fdtable should not be shared")); for (i = 0; i <= fdp->fd_lastfile; i++) { fde = &fdp->fd_ofiles[i]; fp = fde->fde_file; if (fp != NULL && (fp->f_type == DTYPE_MQUEUE || (fde->fde_flags & UF_EXCLOSE))) { FILEDESC_XLOCK(fdp); fdfree(fdp, i); (void) closefp(fdp, i, fp, td, 0); FILEDESC_UNLOCK_ASSERT(fdp); } } } /* * It is unsafe for set[ug]id processes to be started with file * descriptors 0..2 closed, as these descriptors are given implicit * significance in the Standard C library. fdcheckstd() will create a * descriptor referencing /dev/null for each of stdin, stdout, and * stderr that is not already open. */ int fdcheckstd(struct thread *td) { struct filedesc *fdp; register_t save; int i, error, devnull; fdp = td->td_proc->p_fd; KASSERT(fdp->fd_refcnt == 1, ("the fdtable should not be shared")); MPASS(fdp->fd_nfiles >= 3); devnull = -1; for (i = 0; i <= 2; i++) { if (fdp->fd_ofiles[i].fde_file != NULL) continue; save = td->td_retval[0]; if (devnull != -1) { error = kern_dup(td, FDDUP_FIXED, 0, devnull, i); } else { error = kern_openat(td, AT_FDCWD, "/dev/null", UIO_SYSSPACE, O_RDWR, 0); if (error == 0) { devnull = td->td_retval[0]; KASSERT(devnull == i, ("we didn't get our fd")); } } td->td_retval[0] = save; if (error != 0) return (error); } return (0); } /* * Internal form of close. Decrement reference count on file structure. * Note: td may be NULL when closing a file that was being passed in a * message. * * XXXRW: Giant is not required for the caller, but often will be held; this * makes it moderately likely the Giant will be recursed in the VFS case. */ int closef(struct file *fp, struct thread *td) { struct vnode *vp; struct flock lf; struct filedesc_to_leader *fdtol; struct filedesc *fdp; /* * POSIX record locking dictates that any close releases ALL * locks owned by this process. This is handled by setting * a flag in the unlock to free ONLY locks obeying POSIX * semantics, and not to free BSD-style file locks. * If the descriptor was in a message, POSIX-style locks * aren't passed with the descriptor, and the thread pointer * will be NULL. Callers should be careful only to pass a * NULL thread pointer when there really is no owning * context that might have locks, or the locks will be * leaked. */ if (fp->f_type == DTYPE_VNODE && td != NULL) { vp = fp->f_vnode; if ((td->td_proc->p_leader->p_flag & P_ADVLOCK) != 0) { lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; lf.l_type = F_UNLCK; (void) VOP_ADVLOCK(vp, (caddr_t)td->td_proc->p_leader, F_UNLCK, &lf, F_POSIX); } fdtol = td->td_proc->p_fdtol; if (fdtol != NULL) { /* * Handle special case where file descriptor table is * shared between multiple process leaders. */ fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); for (fdtol = fdtol->fdl_next; fdtol != td->td_proc->p_fdtol; fdtol = fdtol->fdl_next) { if ((fdtol->fdl_leader->p_flag & P_ADVLOCK) == 0) continue; fdtol->fdl_holdcount++; FILEDESC_XUNLOCK(fdp); lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; lf.l_type = F_UNLCK; vp = fp->f_vnode; (void) VOP_ADVLOCK(vp, (caddr_t)fdtol->fdl_leader, F_UNLCK, &lf, F_POSIX); FILEDESC_XLOCK(fdp); fdtol->fdl_holdcount--; if (fdtol->fdl_holdcount == 0 && fdtol->fdl_wakeup != 0) { fdtol->fdl_wakeup = 0; wakeup(fdtol); } } FILEDESC_XUNLOCK(fdp); } } return (fdrop(fp, td)); } /* * Initialize the file pointer with the specified properties. * * The ops are set with release semantics to be certain that the flags, type, * and data are visible when ops is. This is to prevent ops methods from being * called with bad data. */ void finit(struct file *fp, u_int flag, short type, void *data, struct fileops *ops) { fp->f_data = data; fp->f_flag = flag; fp->f_type = type; atomic_store_rel_ptr((volatile uintptr_t *)&fp->f_ops, (uintptr_t)ops); } int fget_cap_locked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, struct file **fpp, struct filecaps *havecapsp) { struct filedescent *fde; int error; FILEDESC_LOCK_ASSERT(fdp); fde = fdeget_locked(fdp, fd); if (fde == NULL) { error = EBADF; goto out; } #ifdef CAPABILITIES error = cap_check(cap_rights_fde(fde), needrightsp); if (error != 0) goto out; #endif if (havecapsp != NULL) filecaps_copy(&fde->fde_caps, havecapsp, true); *fpp = fde->fde_file; error = 0; out: return (error); } int fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp, struct file **fpp, struct filecaps *havecapsp) { struct filedesc *fdp = td->td_proc->p_fd; int error; #ifndef CAPABILITIES error = fget_unlocked(fdp, fd, needrightsp, fpp, NULL); if (error == 0 && havecapsp != NULL) filecaps_fill(havecapsp); #else struct file *fp; seq_t seq; for (;;) { error = fget_unlocked(fdp, fd, needrightsp, &fp, &seq); if (error != 0) return (error); if (havecapsp != NULL) { if (!filecaps_copy(&fdp->fd_ofiles[fd].fde_caps, havecapsp, false)) { fdrop(fp, td); goto get_locked; } } if (!fd_modified(fdp, fd, seq)) break; fdrop(fp, td); } *fpp = fp; return (0); get_locked: FILEDESC_SLOCK(fdp); error = fget_cap_locked(fdp, fd, needrightsp, fpp, havecapsp); if (error == 0) fhold(*fpp); FILEDESC_SUNLOCK(fdp); #endif return (error); } int fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, struct file **fpp, seq_t *seqp) { #ifdef CAPABILITIES struct filedescent *fde; #endif struct fdescenttbl *fdt; struct file *fp; u_int count; #ifdef CAPABILITIES seq_t seq; cap_rights_t haverights; int error; #endif fdt = fdp->fd_files; if ((u_int)fd >= fdt->fdt_nfiles) return (EBADF); /* * Fetch the descriptor locklessly. We avoid fdrop() races by * never raising a refcount above 0. To accomplish this we have * to use a cmpset loop rather than an atomic_add. The descriptor * must be re-verified once we acquire a reference to be certain * that the identity is still correct and we did not lose a race * due to preemption. */ for (;;) { #ifdef CAPABILITIES seq = seq_read(fd_seq(fdt, fd)); fde = &fdt->fdt_ofiles[fd]; haverights = *cap_rights_fde(fde); fp = fde->fde_file; if (!seq_consistent(fd_seq(fdt, fd), seq)) continue; #else fp = fdt->fdt_ofiles[fd].fde_file; #endif if (fp == NULL) return (EBADF); #ifdef CAPABILITIES error = cap_check(&haverights, needrightsp); if (error != 0) return (error); #endif - retry: count = fp->f_count; + retry: if (count == 0) { /* * Force a reload. Other thread could reallocate the * table before this fd was closed, so it possible that * there is a stale fp pointer in cached version. */ fdt = *(struct fdescenttbl * volatile *)&(fdp->fd_files); continue; } /* * Use an acquire barrier to force re-reading of fdt so it is * refreshed for verification. */ - if (atomic_cmpset_acq_int(&fp->f_count, count, count + 1) == 0) + if (atomic_fcmpset_acq_int(&fp->f_count, &count, count + 1) == 0) goto retry; fdt = fdp->fd_files; #ifdef CAPABILITIES if (seq_consistent_nomb(fd_seq(fdt, fd), seq)) #else if (fp == fdt->fdt_ofiles[fd].fde_file) #endif break; fdrop(fp, curthread); } *fpp = fp; if (seqp != NULL) { #ifdef CAPABILITIES *seqp = seq; #endif } return (0); } /* * Extract the file pointer associated with the specified descriptor for the * current user process. * * If the descriptor doesn't exist or doesn't match 'flags', EBADF is * returned. * * File's rights will be checked against the capability rights mask. * * If an error occurred the non-zero error is returned and *fpp is set to * NULL. Otherwise *fpp is held and set and zero is returned. Caller is * responsible for fdrop(). */ static __inline int _fget(struct thread *td, int fd, struct file **fpp, int flags, cap_rights_t *needrightsp, seq_t *seqp) { struct filedesc *fdp; struct file *fp; int error; *fpp = NULL; fdp = td->td_proc->p_fd; error = fget_unlocked(fdp, fd, needrightsp, &fp, seqp); if (error != 0) return (error); if (fp->f_ops == &badfileops) { fdrop(fp, td); return (EBADF); } /* * FREAD and FWRITE failure return EBADF as per POSIX. */ error = 0; switch (flags) { case FREAD: case FWRITE: if ((fp->f_flag & flags) == 0) error = EBADF; break; case FEXEC: if ((fp->f_flag & (FREAD | FEXEC)) == 0 || ((fp->f_flag & FWRITE) != 0)) error = EBADF; break; case 0: break; default: KASSERT(0, ("wrong flags")); } if (error != 0) { fdrop(fp, td); return (error); } *fpp = fp; return (0); } int fget(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp) { return (_fget(td, fd, fpp, 0, rightsp, NULL)); } int fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, u_char *maxprotp, struct file **fpp) { int error; #ifndef CAPABILITIES error = _fget(td, fd, fpp, 0, rightsp, NULL); if (maxprotp != NULL) *maxprotp = VM_PROT_ALL; #else struct filedesc *fdp = td->td_proc->p_fd; seq_t seq; MPASS(cap_rights_is_set(rightsp, CAP_MMAP)); for (;;) { error = _fget(td, fd, fpp, 0, rightsp, &seq); if (error != 0) return (error); /* * If requested, convert capability rights to access flags. */ if (maxprotp != NULL) *maxprotp = cap_rights_to_vmprot(cap_rights(fdp, fd)); if (!fd_modified(fdp, fd, seq)) break; fdrop(*fpp, td); } #endif return (error); } int fget_read(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp) { return (_fget(td, fd, fpp, FREAD, rightsp, NULL)); } int fget_write(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp) { return (_fget(td, fd, fpp, FWRITE, rightsp, NULL)); } int fget_fcntl(struct thread *td, int fd, cap_rights_t *rightsp, int needfcntl, struct file **fpp) { struct filedesc *fdp = td->td_proc->p_fd; #ifndef CAPABILITIES return (fget_unlocked(fdp, fd, rightsp, fpp, NULL)); #else int error; seq_t seq; MPASS(cap_rights_is_set(rightsp, CAP_FCNTL)); for (;;) { error = fget_unlocked(fdp, fd, rightsp, fpp, &seq); if (error != 0) return (error); error = cap_fcntl_check(fdp, fd, needfcntl); if (!fd_modified(fdp, fd, seq)) break; fdrop(*fpp, td); } if (error != 0) { fdrop(*fpp, td); *fpp = NULL; } return (error); #endif } /* * Like fget() but loads the underlying vnode, or returns an error if the * descriptor does not represent a vnode. Note that pipes use vnodes but * never have VM objects. The returned vnode will be vref()'d. * * XXX: what about the unused flags ? */ static __inline int _fgetvp(struct thread *td, int fd, int flags, cap_rights_t *needrightsp, struct vnode **vpp) { struct file *fp; int error; *vpp = NULL; error = _fget(td, fd, &fp, flags, needrightsp, NULL); if (error != 0) return (error); if (fp->f_vnode == NULL) { error = EINVAL; } else { *vpp = fp->f_vnode; vrefact(*vpp); } fdrop(fp, td); return (error); } int fgetvp(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) { return (_fgetvp(td, fd, 0, rightsp, vpp)); } int fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp, struct filecaps *havecaps, struct vnode **vpp) { struct filedesc *fdp; struct filecaps caps; struct file *fp; int error; fdp = td->td_proc->p_fd; error = fget_cap_locked(fdp, fd, needrightsp, &fp, &caps); if (error != 0) return (error); if (fp->f_ops == &badfileops) { error = EBADF; goto out; } if (fp->f_vnode == NULL) { error = EINVAL; goto out; } *havecaps = caps; *vpp = fp->f_vnode; vrefact(*vpp); return (0); out: filecaps_free(&caps); return (error); } int fgetvp_read(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) { return (_fgetvp(td, fd, FREAD, rightsp, vpp)); } int fgetvp_exec(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) { return (_fgetvp(td, fd, FEXEC, rightsp, vpp)); } #ifdef notyet int fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) { return (_fgetvp(td, fd, FWRITE, rightsp, vpp)); } #endif /* * Handle the last reference to a file being closed. */ int _fdrop(struct file *fp, struct thread *td) { int error; if (fp->f_count != 0) panic("fdrop: count %d", fp->f_count); error = fo_close(fp, td); atomic_subtract_int(&openfiles, 1); crfree(fp->f_cred); free(fp->f_advice, M_FADVISE); uma_zfree(file_zone, fp); return (error); } /* * Apply an advisory lock on a file descriptor. * * Just attempt to get a record lock of the requested type on the entire file * (l_whence = SEEK_SET, l_start = 0, l_len = 0). */ #ifndef _SYS_SYSPROTO_H_ struct flock_args { int fd; int how; }; #endif /* ARGSUSED */ int sys_flock(struct thread *td, struct flock_args *uap) { struct file *fp; struct vnode *vp; struct flock lf; cap_rights_t rights; int error; error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FLOCK), &fp); if (error != 0) return (error); if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); return (EOPNOTSUPP); } vp = fp->f_vnode; lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; if (uap->how & LOCK_UN) { lf.l_type = F_UNLCK; atomic_clear_int(&fp->f_flag, FHASLOCK); error = VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); goto done2; } if (uap->how & LOCK_EX) lf.l_type = F_WRLCK; else if (uap->how & LOCK_SH) lf.l_type = F_RDLCK; else { error = EBADF; goto done2; } atomic_set_int(&fp->f_flag, FHASLOCK); error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, (uap->how & LOCK_NB) ? F_FLOCK : F_FLOCK | F_WAIT); done2: fdrop(fp, td); return (error); } /* * Duplicate the specified descriptor to a free descriptor. */ int dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode, int openerror, int *indxp) { struct filedescent *newfde, *oldfde; struct file *fp; int error, indx; KASSERT(openerror == ENODEV || openerror == ENXIO, ("unexpected error %d in %s", openerror, __func__)); /* * If the to-be-dup'd fd number is greater than the allowed number * of file descriptors, or the fd to be dup'd has already been * closed, then reject. */ FILEDESC_XLOCK(fdp); if ((fp = fget_locked(fdp, dfd)) == NULL) { FILEDESC_XUNLOCK(fdp); return (EBADF); } error = fdalloc(td, 0, &indx); if (error != 0) { FILEDESC_XUNLOCK(fdp); return (error); } /* * There are two cases of interest here. * * For ENODEV simply dup (dfd) to file descriptor (indx) and return. * * For ENXIO steal away the file structure from (dfd) and store it in * (indx). (dfd) is effectively closed by this operation. */ switch (openerror) { case ENODEV: /* * Check that the mode the file is being opened for is a * subset of the mode of the existing descriptor. */ if (((mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) { fdunused(fdp, indx); FILEDESC_XUNLOCK(fdp); return (EACCES); } fhold(fp); newfde = &fdp->fd_ofiles[indx]; oldfde = &fdp->fd_ofiles[dfd]; #ifdef CAPABILITIES seq_write_begin(&newfde->fde_seq); #endif memcpy(newfde, oldfde, fde_change_size); filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps, true); #ifdef CAPABILITIES seq_write_end(&newfde->fde_seq); #endif break; case ENXIO: /* * Steal away the file pointer from dfd and stuff it into indx. */ newfde = &fdp->fd_ofiles[indx]; oldfde = &fdp->fd_ofiles[dfd]; #ifdef CAPABILITIES seq_write_begin(&newfde->fde_seq); #endif memcpy(newfde, oldfde, fde_change_size); oldfde->fde_file = NULL; fdunused(fdp, dfd); #ifdef CAPABILITIES seq_write_end(&newfde->fde_seq); #endif break; } FILEDESC_XUNLOCK(fdp); *indxp = indx; return (0); } /* * This sysctl determines if we will allow a process to chroot(2) if it * has a directory open: * 0: disallowed for all processes. * 1: allowed for processes that were not already chroot(2)'ed. * 2: allowed for all processes. */ static int chroot_allow_open_directories = 1; SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW, &chroot_allow_open_directories, 0, "Allow a process to chroot(2) if it has a directory open"); /* * Helper function for raised chroot(2) security function: Refuse if * any filedescriptors are open directories. */ static int chroot_refuse_vdir_fds(struct filedesc *fdp) { struct vnode *vp; struct file *fp; int fd; FILEDESC_LOCK_ASSERT(fdp); for (fd = 0; fd <= fdp->fd_lastfile; fd++) { fp = fget_locked(fdp, fd); if (fp == NULL) continue; if (fp->f_type == DTYPE_VNODE) { vp = fp->f_vnode; if (vp->v_type == VDIR) return (EPERM); } } return (0); } /* * Common routine for kern_chroot() and jail_attach(). The caller is * responsible for invoking priv_check() and mac_vnode_check_chroot() to * authorize this operation. */ int pwd_chroot(struct thread *td, struct vnode *vp) { struct filedesc *fdp; struct vnode *oldvp; int error; fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); if (chroot_allow_open_directories == 0 || (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { error = chroot_refuse_vdir_fds(fdp); if (error != 0) { FILEDESC_XUNLOCK(fdp); return (error); } } oldvp = fdp->fd_rdir; vrefact(vp); fdp->fd_rdir = vp; if (fdp->fd_jdir == NULL) { vrefact(vp); fdp->fd_jdir = vp; } FILEDESC_XUNLOCK(fdp); vrele(oldvp); return (0); } void pwd_chdir(struct thread *td, struct vnode *vp) { struct filedesc *fdp; struct vnode *oldvp; fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); VNASSERT(vp->v_usecount > 0, vp, ("chdir to a vnode with zero usecount")); oldvp = fdp->fd_cdir; fdp->fd_cdir = vp; FILEDESC_XUNLOCK(fdp); vrele(oldvp); } /* * Scan all active processes and prisons to see if any of them have a current * or root directory of `olddp'. If so, replace them with the new mount point. */ void mountcheckdirs(struct vnode *olddp, struct vnode *newdp) { struct filedesc *fdp; struct prison *pr; struct proc *p; int nrele; if (vrefcnt(olddp) == 1) return; nrele = 0; sx_slock(&allproc_lock); FOREACH_PROC_IN_SYSTEM(p) { PROC_LOCK(p); fdp = fdhold(p); PROC_UNLOCK(p); if (fdp == NULL) continue; FILEDESC_XLOCK(fdp); if (fdp->fd_cdir == olddp) { vrefact(newdp); fdp->fd_cdir = newdp; nrele++; } if (fdp->fd_rdir == olddp) { vrefact(newdp); fdp->fd_rdir = newdp; nrele++; } if (fdp->fd_jdir == olddp) { vrefact(newdp); fdp->fd_jdir = newdp; nrele++; } FILEDESC_XUNLOCK(fdp); fddrop(fdp); } sx_sunlock(&allproc_lock); if (rootvnode == olddp) { vrefact(newdp); rootvnode = newdp; nrele++; } mtx_lock(&prison0.pr_mtx); if (prison0.pr_root == olddp) { vrefact(newdp); prison0.pr_root = newdp; nrele++; } mtx_unlock(&prison0.pr_mtx); sx_slock(&allprison_lock); TAILQ_FOREACH(pr, &allprison, pr_list) { mtx_lock(&pr->pr_mtx); if (pr->pr_root == olddp) { vrefact(newdp); pr->pr_root = newdp; nrele++; } mtx_unlock(&pr->pr_mtx); } sx_sunlock(&allprison_lock); while (nrele--) vrele(olddp); } struct filedesc_to_leader * filedesc_to_leader_alloc(struct filedesc_to_leader *old, struct filedesc *fdp, struct proc *leader) { struct filedesc_to_leader *fdtol; fdtol = malloc(sizeof(struct filedesc_to_leader), M_FILEDESC_TO_LEADER, M_WAITOK); fdtol->fdl_refcount = 1; fdtol->fdl_holdcount = 0; fdtol->fdl_wakeup = 0; fdtol->fdl_leader = leader; if (old != NULL) { FILEDESC_XLOCK(fdp); fdtol->fdl_next = old->fdl_next; fdtol->fdl_prev = old; old->fdl_next = fdtol; fdtol->fdl_next->fdl_prev = fdtol; FILEDESC_XUNLOCK(fdp); } else { fdtol->fdl_next = fdtol; fdtol->fdl_prev = fdtol; } return (fdtol); } static int sysctl_kern_proc_nfds(SYSCTL_HANDLER_ARGS) { struct filedesc *fdp; int i, count, slots; if (*(int *)arg1 != 0) return (EINVAL); fdp = curproc->p_fd; count = 0; FILEDESC_SLOCK(fdp); slots = NDSLOTS(fdp->fd_lastfile + 1); for (i = 0; i < slots; i++) count += bitcountl(fdp->fd_map[i]); FILEDESC_SUNLOCK(fdp); return (SYSCTL_OUT(req, &count, sizeof(count))); } static SYSCTL_NODE(_kern_proc, KERN_PROC_NFDS, nfds, CTLFLAG_RD|CTLFLAG_CAPRD|CTLFLAG_MPSAFE, sysctl_kern_proc_nfds, "Number of open file descriptors"); /* * Get file structures globally. */ static int sysctl_kern_file(SYSCTL_HANDLER_ARGS) { struct xfile xf; struct filedesc *fdp; struct file *fp; struct proc *p; int error, n; error = sysctl_wire_old_buffer(req, 0); if (error != 0) return (error); if (req->oldptr == NULL) { n = 0; sx_slock(&allproc_lock); FOREACH_PROC_IN_SYSTEM(p) { PROC_LOCK(p); if (p->p_state == PRS_NEW) { PROC_UNLOCK(p); continue; } fdp = fdhold(p); PROC_UNLOCK(p); if (fdp == NULL) continue; /* overestimates sparse tables. */ if (fdp->fd_lastfile > 0) n += fdp->fd_lastfile; fddrop(fdp); } sx_sunlock(&allproc_lock); return (SYSCTL_OUT(req, 0, n * sizeof(xf))); } error = 0; bzero(&xf, sizeof(xf)); xf.xf_size = sizeof(xf); sx_slock(&allproc_lock); FOREACH_PROC_IN_SYSTEM(p) { PROC_LOCK(p); if (p->p_state == PRS_NEW) { PROC_UNLOCK(p); continue; } if (p_cansee(req->td, p) != 0) { PROC_UNLOCK(p); continue; } xf.xf_pid = p->p_pid; xf.xf_uid = p->p_ucred->cr_uid; fdp = fdhold(p); PROC_UNLOCK(p); if (fdp == NULL) continue; FILEDESC_SLOCK(fdp); for (n = 0; fdp->fd_refcnt > 0 && n <= fdp->fd_lastfile; ++n) { if ((fp = fdp->fd_ofiles[n].fde_file) == NULL) continue; xf.xf_fd = n; xf.xf_file = fp; xf.xf_data = fp->f_data; xf.xf_vnode = fp->f_vnode; xf.xf_type = fp->f_type; xf.xf_count = fp->f_count; xf.xf_msgcount = 0; xf.xf_offset = foffset_get(fp); xf.xf_flag = fp->f_flag; error = SYSCTL_OUT(req, &xf, sizeof(xf)); if (error) break; } FILEDESC_SUNLOCK(fdp); fddrop(fdp); if (error) break; } sx_sunlock(&allproc_lock); return (error); } SYSCTL_PROC(_kern, KERN_FILE, file, CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_MPSAFE, 0, 0, sysctl_kern_file, "S,xfile", "Entire file table"); #ifdef KINFO_FILE_SIZE CTASSERT(sizeof(struct kinfo_file) == KINFO_FILE_SIZE); #endif static int xlate_fflags(int fflags) { static const struct { int fflag; int kf_fflag; } fflags_table[] = { { FAPPEND, KF_FLAG_APPEND }, { FASYNC, KF_FLAG_ASYNC }, { FFSYNC, KF_FLAG_FSYNC }, { FHASLOCK, KF_FLAG_HASLOCK }, { FNONBLOCK, KF_FLAG_NONBLOCK }, { FREAD, KF_FLAG_READ }, { FWRITE, KF_FLAG_WRITE }, { O_CREAT, KF_FLAG_CREAT }, { O_DIRECT, KF_FLAG_DIRECT }, { O_EXCL, KF_FLAG_EXCL }, { O_EXEC, KF_FLAG_EXEC }, { O_EXLOCK, KF_FLAG_EXLOCK }, { O_NOFOLLOW, KF_FLAG_NOFOLLOW }, { O_SHLOCK, KF_FLAG_SHLOCK }, { O_TRUNC, KF_FLAG_TRUNC } }; unsigned int i; int kflags; kflags = 0; for (i = 0; i < nitems(fflags_table); i++) if (fflags & fflags_table[i].fflag) kflags |= fflags_table[i].kf_fflag; return (kflags); } /* Trim unused data from kf_path by truncating the structure size. */ static void pack_kinfo(struct kinfo_file *kif) { kif->kf_structsize = offsetof(struct kinfo_file, kf_path) + strlen(kif->kf_path) + 1; kif->kf_structsize = roundup(kif->kf_structsize, sizeof(uint64_t)); } static void export_file_to_kinfo(struct file *fp, int fd, cap_rights_t *rightsp, struct kinfo_file *kif, struct filedesc *fdp, int flags) { int error; bzero(kif, sizeof(*kif)); /* Set a default type to allow for empty fill_kinfo() methods. */ kif->kf_type = KF_TYPE_UNKNOWN; kif->kf_flags = xlate_fflags(fp->f_flag); if (rightsp != NULL) kif->kf_cap_rights = *rightsp; else cap_rights_init(&kif->kf_cap_rights); kif->kf_fd = fd; kif->kf_ref_count = fp->f_count; kif->kf_offset = foffset_get(fp); /* * This may drop the filedesc lock, so the 'fp' cannot be * accessed after this call. */ error = fo_fill_kinfo(fp, kif, fdp); if (error == 0) kif->kf_status |= KF_ATTR_VALID; if ((flags & KERN_FILEDESC_PACK_KINFO) != 0) pack_kinfo(kif); else kif->kf_structsize = roundup2(sizeof(*kif), sizeof(uint64_t)); } static void export_vnode_to_kinfo(struct vnode *vp, int fd, int fflags, struct kinfo_file *kif, int flags) { int error; bzero(kif, sizeof(*kif)); kif->kf_type = KF_TYPE_VNODE; error = vn_fill_kinfo_vnode(vp, kif); if (error == 0) kif->kf_status |= KF_ATTR_VALID; kif->kf_flags = xlate_fflags(fflags); cap_rights_init(&kif->kf_cap_rights); kif->kf_fd = fd; kif->kf_ref_count = -1; kif->kf_offset = -1; if ((flags & KERN_FILEDESC_PACK_KINFO) != 0) pack_kinfo(kif); else kif->kf_structsize = roundup2(sizeof(*kif), sizeof(uint64_t)); vrele(vp); } struct export_fd_buf { struct filedesc *fdp; struct sbuf *sb; ssize_t remainder; struct kinfo_file kif; int flags; }; static int export_kinfo_to_sb(struct export_fd_buf *efbuf) { struct kinfo_file *kif; kif = &efbuf->kif; if (efbuf->remainder != -1) { if (efbuf->remainder < kif->kf_structsize) { /* Terminate export. */ efbuf->remainder = 0; return (0); } efbuf->remainder -= kif->kf_structsize; } return (sbuf_bcat(efbuf->sb, kif, kif->kf_structsize) == 0 ? 0 : ENOMEM); } static int export_file_to_sb(struct file *fp, int fd, cap_rights_t *rightsp, struct export_fd_buf *efbuf) { int error; if (efbuf->remainder == 0) return (0); export_file_to_kinfo(fp, fd, rightsp, &efbuf->kif, efbuf->fdp, efbuf->flags); FILEDESC_SUNLOCK(efbuf->fdp); error = export_kinfo_to_sb(efbuf); FILEDESC_SLOCK(efbuf->fdp); return (error); } static int export_vnode_to_sb(struct vnode *vp, int fd, int fflags, struct export_fd_buf *efbuf) { int error; if (efbuf->remainder == 0) return (0); if (efbuf->fdp != NULL) FILEDESC_SUNLOCK(efbuf->fdp); export_vnode_to_kinfo(vp, fd, fflags, &efbuf->kif, efbuf->flags); error = export_kinfo_to_sb(efbuf); if (efbuf->fdp != NULL) FILEDESC_SLOCK(efbuf->fdp); return (error); } /* * Store a process file descriptor information to sbuf. * * Takes a locked proc as argument, and returns with the proc unlocked. */ int kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, int flags) { struct file *fp; struct filedesc *fdp; struct export_fd_buf *efbuf; struct vnode *cttyvp, *textvp, *tracevp; int error, i; cap_rights_t rights; PROC_LOCK_ASSERT(p, MA_OWNED); /* ktrace vnode */ tracevp = p->p_tracevp; if (tracevp != NULL) vrefact(tracevp); /* text vnode */ textvp = p->p_textvp; if (textvp != NULL) vrefact(textvp); /* Controlling tty. */ cttyvp = NULL; if (p->p_pgrp != NULL && p->p_pgrp->pg_session != NULL) { cttyvp = p->p_pgrp->pg_session->s_ttyvp; if (cttyvp != NULL) vrefact(cttyvp); } fdp = fdhold(p); PROC_UNLOCK(p); efbuf = malloc(sizeof(*efbuf), M_TEMP, M_WAITOK); efbuf->fdp = NULL; efbuf->sb = sb; efbuf->remainder = maxlen; efbuf->flags = flags; if (tracevp != NULL) export_vnode_to_sb(tracevp, KF_FD_TYPE_TRACE, FREAD | FWRITE, efbuf); if (textvp != NULL) export_vnode_to_sb(textvp, KF_FD_TYPE_TEXT, FREAD, efbuf); if (cttyvp != NULL) export_vnode_to_sb(cttyvp, KF_FD_TYPE_CTTY, FREAD | FWRITE, efbuf); error = 0; if (fdp == NULL) goto fail; efbuf->fdp = fdp; FILEDESC_SLOCK(fdp); /* working directory */ if (fdp->fd_cdir != NULL) { vrefact(fdp->fd_cdir); export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD, FREAD, efbuf); } /* root directory */ if (fdp->fd_rdir != NULL) { vrefact(fdp->fd_rdir); export_vnode_to_sb(fdp->fd_rdir, KF_FD_TYPE_ROOT, FREAD, efbuf); } /* jail directory */ if (fdp->fd_jdir != NULL) { vrefact(fdp->fd_jdir); export_vnode_to_sb(fdp->fd_jdir, KF_FD_TYPE_JAIL, FREAD, efbuf); } for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) { if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) continue; #ifdef CAPABILITIES rights = *cap_rights(fdp, i); #else /* !CAPABILITIES */ cap_rights_init(&rights); #endif /* * Create sysctl entry. It is OK to drop the filedesc * lock inside of export_file_to_sb() as we will * re-validate and re-evaluate its properties when the * loop continues. */ error = export_file_to_sb(fp, i, &rights, efbuf); if (error != 0 || efbuf->remainder == 0) break; } FILEDESC_SUNLOCK(fdp); fddrop(fdp); fail: free(efbuf, M_TEMP); return (error); } #define FILEDESC_SBUF_SIZE (sizeof(struct kinfo_file) * 5) /* * Get per-process file descriptors for use by procstat(1), et al. */ static int sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) { struct sbuf sb; struct proc *p; ssize_t maxlen; int error, error2, *name; name = (int *)arg1; sbuf_new_for_sysctl(&sb, NULL, FILEDESC_SBUF_SIZE, req); sbuf_clear_flags(&sb, SBUF_INCLUDENUL); error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); if (error != 0) { sbuf_delete(&sb); return (error); } maxlen = req->oldptr != NULL ? req->oldlen : -1; error = kern_proc_filedesc_out(p, &sb, maxlen, KERN_FILEDESC_PACK_KINFO); error2 = sbuf_finish(&sb); sbuf_delete(&sb); return (error != 0 ? error : error2); } #ifdef KINFO_OFILE_SIZE CTASSERT(sizeof(struct kinfo_ofile) == KINFO_OFILE_SIZE); #endif #ifdef COMPAT_FREEBSD7 static void kinfo_to_okinfo(struct kinfo_file *kif, struct kinfo_ofile *okif) { okif->kf_structsize = sizeof(*okif); okif->kf_type = kif->kf_type; okif->kf_fd = kif->kf_fd; okif->kf_ref_count = kif->kf_ref_count; okif->kf_flags = kif->kf_flags & (KF_FLAG_READ | KF_FLAG_WRITE | KF_FLAG_APPEND | KF_FLAG_ASYNC | KF_FLAG_FSYNC | KF_FLAG_NONBLOCK | KF_FLAG_DIRECT | KF_FLAG_HASLOCK); okif->kf_offset = kif->kf_offset; okif->kf_vnode_type = kif->kf_vnode_type; okif->kf_sock_domain = kif->kf_sock_domain; okif->kf_sock_type = kif->kf_sock_type; okif->kf_sock_protocol = kif->kf_sock_protocol; strlcpy(okif->kf_path, kif->kf_path, sizeof(okif->kf_path)); okif->kf_sa_local = kif->kf_sa_local; okif->kf_sa_peer = kif->kf_sa_peer; } static int export_vnode_for_osysctl(struct vnode *vp, int type, struct kinfo_file *kif, struct kinfo_ofile *okif, struct filedesc *fdp, struct sysctl_req *req) { int error; vrefact(vp); FILEDESC_SUNLOCK(fdp); export_vnode_to_kinfo(vp, type, 0, kif, KERN_FILEDESC_PACK_KINFO); kinfo_to_okinfo(kif, okif); error = SYSCTL_OUT(req, okif, sizeof(*okif)); FILEDESC_SLOCK(fdp); return (error); } /* * Get per-process file descriptors for use by procstat(1), et al. */ static int sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) { struct kinfo_ofile *okif; struct kinfo_file *kif; struct filedesc *fdp; int error, i, *name; struct file *fp; struct proc *p; name = (int *)arg1; error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); if (error != 0) return (error); fdp = fdhold(p); PROC_UNLOCK(p); if (fdp == NULL) return (ENOENT); kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK); okif = malloc(sizeof(*okif), M_TEMP, M_WAITOK); FILEDESC_SLOCK(fdp); if (fdp->fd_cdir != NULL) export_vnode_for_osysctl(fdp->fd_cdir, KF_FD_TYPE_CWD, kif, okif, fdp, req); if (fdp->fd_rdir != NULL) export_vnode_for_osysctl(fdp->fd_rdir, KF_FD_TYPE_ROOT, kif, okif, fdp, req); if (fdp->fd_jdir != NULL) export_vnode_for_osysctl(fdp->fd_jdir, KF_FD_TYPE_JAIL, kif, okif, fdp, req); for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) { if ((fp = fdp->fd_ofiles[i].fde_file) == NULL) continue; export_file_to_kinfo(fp, i, NULL, kif, fdp, KERN_FILEDESC_PACK_KINFO); FILEDESC_SUNLOCK(fdp); kinfo_to_okinfo(kif, okif); error = SYSCTL_OUT(req, okif, sizeof(*okif)); FILEDESC_SLOCK(fdp); if (error) break; } FILEDESC_SUNLOCK(fdp); fddrop(fdp); free(kif, M_TEMP); free(okif, M_TEMP); return (0); } static SYSCTL_NODE(_kern_proc, KERN_PROC_OFILEDESC, ofiledesc, CTLFLAG_RD|CTLFLAG_MPSAFE, sysctl_kern_proc_ofiledesc, "Process ofiledesc entries"); #endif /* COMPAT_FREEBSD7 */ int vntype_to_kinfo(int vtype) { struct { int vtype; int kf_vtype; } vtypes_table[] = { { VBAD, KF_VTYPE_VBAD }, { VBLK, KF_VTYPE_VBLK }, { VCHR, KF_VTYPE_VCHR }, { VDIR, KF_VTYPE_VDIR }, { VFIFO, KF_VTYPE_VFIFO }, { VLNK, KF_VTYPE_VLNK }, { VNON, KF_VTYPE_VNON }, { VREG, KF_VTYPE_VREG }, { VSOCK, KF_VTYPE_VSOCK } }; unsigned int i; /* * Perform vtype translation. */ for (i = 0; i < nitems(vtypes_table); i++) if (vtypes_table[i].vtype == vtype) return (vtypes_table[i].kf_vtype); return (KF_VTYPE_UNKNOWN); } static SYSCTL_NODE(_kern_proc, KERN_PROC_FILEDESC, filedesc, CTLFLAG_RD|CTLFLAG_MPSAFE, sysctl_kern_proc_filedesc, "Process filedesc entries"); /* * Store a process current working directory information to sbuf. * * Takes a locked proc as argument, and returns with the proc unlocked. */ int kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) { struct filedesc *fdp; struct export_fd_buf *efbuf; int error; PROC_LOCK_ASSERT(p, MA_OWNED); fdp = fdhold(p); PROC_UNLOCK(p); if (fdp == NULL) return (EINVAL); efbuf = malloc(sizeof(*efbuf), M_TEMP, M_WAITOK); efbuf->fdp = fdp; efbuf->sb = sb; efbuf->remainder = maxlen; FILEDESC_SLOCK(fdp); if (fdp->fd_cdir == NULL) error = EINVAL; else { vrefact(fdp->fd_cdir); error = export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD, FREAD, efbuf); } FILEDESC_SUNLOCK(fdp); fddrop(fdp); free(efbuf, M_TEMP); return (error); } /* * Get per-process current working directory. */ static int sysctl_kern_proc_cwd(SYSCTL_HANDLER_ARGS) { struct sbuf sb; struct proc *p; ssize_t maxlen; int error, error2, *name; name = (int *)arg1; sbuf_new_for_sysctl(&sb, NULL, sizeof(struct kinfo_file), req); sbuf_clear_flags(&sb, SBUF_INCLUDENUL); error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); if (error != 0) { sbuf_delete(&sb); return (error); } maxlen = req->oldptr != NULL ? req->oldlen : -1; error = kern_proc_cwd_out(p, &sb, maxlen); error2 = sbuf_finish(&sb); sbuf_delete(&sb); return (error != 0 ? error : error2); } static SYSCTL_NODE(_kern_proc, KERN_PROC_CWD, cwd, CTLFLAG_RD|CTLFLAG_MPSAFE, sysctl_kern_proc_cwd, "Process current working directory"); #ifdef DDB /* * For the purposes of debugging, generate a human-readable string for the * file type. */ static const char * file_type_to_name(short type) { switch (type) { case 0: return ("zero"); case DTYPE_VNODE: return ("vnod"); case DTYPE_SOCKET: return ("sock"); case DTYPE_PIPE: return ("pipe"); case DTYPE_FIFO: return ("fifo"); case DTYPE_KQUEUE: return ("kque"); case DTYPE_CRYPTO: return ("crpt"); case DTYPE_MQUEUE: return ("mque"); case DTYPE_SHM: return ("shm"); case DTYPE_SEM: return ("ksem"); default: return ("unkn"); } } /* * For the purposes of debugging, identify a process (if any, perhaps one of * many) that references the passed file in its file descriptor array. Return * NULL if none. */ static struct proc * file_to_first_proc(struct file *fp) { struct filedesc *fdp; struct proc *p; int n; FOREACH_PROC_IN_SYSTEM(p) { if (p->p_state == PRS_NEW) continue; fdp = p->p_fd; if (fdp == NULL) continue; for (n = 0; n <= fdp->fd_lastfile; n++) { if (fp == fdp->fd_ofiles[n].fde_file) return (p); } } return (NULL); } static void db_print_file(struct file *fp, int header) { struct proc *p; if (header) db_printf("%8s %4s %8s %8s %4s %5s %6s %8s %5s %12s\n", "File", "Type", "Data", "Flag", "GCFl", "Count", "MCount", "Vnode", "FPID", "FCmd"); p = file_to_first_proc(fp); db_printf("%8p %4s %8p %08x %04x %5d %6d %8p %5d %12s\n", fp, file_type_to_name(fp->f_type), fp->f_data, fp->f_flag, 0, fp->f_count, 0, fp->f_vnode, p != NULL ? p->p_pid : -1, p != NULL ? p->p_comm : "-"); } DB_SHOW_COMMAND(file, db_show_file) { struct file *fp; if (!have_addr) { db_printf("usage: show file \n"); return; } fp = (struct file *)addr; db_print_file(fp, 1); } DB_SHOW_COMMAND(files, db_show_files) { struct filedesc *fdp; struct file *fp; struct proc *p; int header; int n; header = 1; FOREACH_PROC_IN_SYSTEM(p) { if (p->p_state == PRS_NEW) continue; if ((fdp = p->p_fd) == NULL) continue; for (n = 0; n <= fdp->fd_lastfile; ++n) { if ((fp = fdp->fd_ofiles[n].fde_file) == NULL) continue; db_print_file(fp, header); header = 0; } } } #endif SYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, CTLFLAG_RW, &maxfilesperproc, 0, "Maximum files allowed open per process"); SYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, "Maximum number of files"); SYSCTL_INT(_kern, OID_AUTO, openfiles, CTLFLAG_RD, __DEVOLATILE(int *, &openfiles), 0, "System-wide number of open files"); /* ARGSUSED*/ static void filelistinit(void *dummy) { file_zone = uma_zcreate("Files", sizeof(struct file), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); filedesc0_zone = uma_zcreate("filedesc0", sizeof(struct filedesc0), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); mtx_init(&sigio_lock, "sigio lock", NULL, MTX_DEF); } SYSINIT(select, SI_SUB_LOCK, SI_ORDER_FIRST, filelistinit, NULL); /*-------------------------------------------------------------------*/ static int badfo_readwrite(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags, struct thread *td) { return (EBADF); } static int badfo_truncate(struct file *fp, off_t length, struct ucred *active_cred, struct thread *td) { return (EINVAL); } static int badfo_ioctl(struct file *fp, u_long com, void *data, struct ucred *active_cred, struct thread *td) { return (EBADF); } static int badfo_poll(struct file *fp, int events, struct ucred *active_cred, struct thread *td) { return (0); } static int badfo_kqfilter(struct file *fp, struct knote *kn) { return (EBADF); } static int badfo_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, struct thread *td) { return (EBADF); } static int badfo_close(struct file *fp, struct thread *td) { return (0); } static int badfo_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, struct thread *td) { return (EBADF); } static int badfo_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, struct thread *td) { return (EBADF); } static int badfo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio, struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags, struct thread *td) { return (EBADF); } static int badfo_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) { return (0); } struct fileops badfileops = { .fo_read = badfo_readwrite, .fo_write = badfo_readwrite, .fo_truncate = badfo_truncate, .fo_ioctl = badfo_ioctl, .fo_poll = badfo_poll, .fo_kqfilter = badfo_kqfilter, .fo_stat = badfo_stat, .fo_close = badfo_close, .fo_chmod = badfo_chmod, .fo_chown = badfo_chown, .fo_sendfile = badfo_sendfile, .fo_fill_kinfo = badfo_fill_kinfo, }; int invfo_rdwr(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags, struct thread *td) { return (EOPNOTSUPP); } int invfo_truncate(struct file *fp, off_t length, struct ucred *active_cred, struct thread *td) { return (EINVAL); } int invfo_ioctl(struct file *fp, u_long com, void *data, struct ucred *active_cred, struct thread *td) { return (ENOTTY); } int invfo_poll(struct file *fp, int events, struct ucred *active_cred, struct thread *td) { return (poll_no_poll(events)); } int invfo_kqfilter(struct file *fp, struct knote *kn) { return (EINVAL); } int invfo_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, struct thread *td) { return (EINVAL); } int invfo_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, struct thread *td) { return (EINVAL); } int invfo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio, struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags, struct thread *td) { return (EINVAL); } /*-------------------------------------------------------------------*/ /* * File Descriptor pseudo-device driver (/dev/fd/). * * Opening minor device N dup()s the file (if any) connected to file * descriptor N belonging to the calling process. Note that this driver * consists of only the ``open()'' routine, because all subsequent * references to this file will be direct to the other driver. * * XXX: we could give this one a cloning event handler if necessary. */ /* ARGSUSED */ static int fdopen(struct cdev *dev, int mode, int type, struct thread *td) { /* * XXX Kludge: set curthread->td_dupfd to contain the value of the * the file descriptor being sought for duplication. The error * return ensures that the vnode for this device will be released * by vn_open. Open will detect this special error and take the * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN * will simply report the error. */ td->td_dupfd = dev2unit(dev); return (ENODEV); } static struct cdevsw fildesc_cdevsw = { .d_version = D_VERSION, .d_open = fdopen, .d_name = "FD", }; static void fildesc_drvinit(void *unused) { struct cdev *dev; dev = make_dev_credf(MAKEDEV_ETERNAL, &fildesc_cdevsw, 0, NULL, UID_ROOT, GID_WHEEL, 0666, "fd/0"); make_dev_alias(dev, "stdin"); dev = make_dev_credf(MAKEDEV_ETERNAL, &fildesc_cdevsw, 1, NULL, UID_ROOT, GID_WHEEL, 0666, "fd/1"); make_dev_alias(dev, "stdout"); dev = make_dev_credf(MAKEDEV_ETERNAL, &fildesc_cdevsw, 2, NULL, UID_ROOT, GID_WHEEL, 0666, "fd/2"); make_dev_alias(dev, "stderr"); } SYSINIT(fildescdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, fildesc_drvinit, NULL); Index: projects/ipsec/sys/kern/kern_mutex.c =================================================================== --- projects/ipsec/sys/kern/kern_mutex.c (revision 313312) +++ projects/ipsec/sys/kern/kern_mutex.c (revision 313313) @@ -1,1139 +1,1142 @@ /*- * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Berkeley Software Design Inc's name may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``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 BERKELEY SOFTWARE DESIGN INC BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from BSDI $Id: mutex_witness.c,v 1.1.2.20 2000/04/27 03:10:27 cp Exp $ * and BSDI $Id: synch_machdep.c,v 2.3.2.39 2000/04/27 03:10:25 cp Exp $ */ /* * Machine independent bits of mutex implementation. */ #include __FBSDID("$FreeBSD$"); #include "opt_adaptive_mutexes.h" #include "opt_ddb.h" #include "opt_hwpmc_hooks.h" #include "opt_sched.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(SMP) && !defined(NO_ADAPTIVE_MUTEXES) #define ADAPTIVE_MUTEXES #endif #ifdef HWPMC_HOOKS #include PMC_SOFT_DEFINE( , , lock, failed); #endif /* * Return the mutex address when the lock cookie address is provided. * This functionality assumes that struct mtx* have a member named mtx_lock. */ #define mtxlock2mtx(c) (__containerof(c, struct mtx, mtx_lock)) /* * Internal utility macros. */ #define mtx_unowned(m) ((m)->mtx_lock == MTX_UNOWNED) #define mtx_destroyed(m) ((m)->mtx_lock == MTX_DESTROYED) static void assert_mtx(const struct lock_object *lock, int what); #ifdef DDB static void db_show_mtx(const struct lock_object *lock); #endif static void lock_mtx(struct lock_object *lock, uintptr_t how); static void lock_spin(struct lock_object *lock, uintptr_t how); #ifdef KDTRACE_HOOKS static int owner_mtx(const struct lock_object *lock, struct thread **owner); #endif static uintptr_t unlock_mtx(struct lock_object *lock); static uintptr_t unlock_spin(struct lock_object *lock); /* * Lock classes for sleep and spin mutexes. */ struct lock_class lock_class_mtx_sleep = { .lc_name = "sleep mutex", .lc_flags = LC_SLEEPLOCK | LC_RECURSABLE, .lc_assert = assert_mtx, #ifdef DDB .lc_ddb_show = db_show_mtx, #endif .lc_lock = lock_mtx, .lc_unlock = unlock_mtx, #ifdef KDTRACE_HOOKS .lc_owner = owner_mtx, #endif }; struct lock_class lock_class_mtx_spin = { .lc_name = "spin mutex", .lc_flags = LC_SPINLOCK | LC_RECURSABLE, .lc_assert = assert_mtx, #ifdef DDB .lc_ddb_show = db_show_mtx, #endif .lc_lock = lock_spin, .lc_unlock = unlock_spin, #ifdef KDTRACE_HOOKS .lc_owner = owner_mtx, #endif }; #ifdef ADAPTIVE_MUTEXES static SYSCTL_NODE(_debug, OID_AUTO, mtx, CTLFLAG_RD, NULL, "mtx debugging"); static struct lock_delay_config __read_mostly mtx_delay = { .initial = 1000, .step = 500, .min = 100, .max = 5000, }; SYSCTL_INT(_debug_mtx, OID_AUTO, delay_initial, CTLFLAG_RW, &mtx_delay.initial, 0, ""); SYSCTL_INT(_debug_mtx, OID_AUTO, delay_step, CTLFLAG_RW, &mtx_delay.step, 0, ""); SYSCTL_INT(_debug_mtx, OID_AUTO, delay_min, CTLFLAG_RW, &mtx_delay.min, 0, ""); SYSCTL_INT(_debug_mtx, OID_AUTO, delay_max, CTLFLAG_RW, &mtx_delay.max, 0, ""); static void mtx_delay_sysinit(void *dummy) { mtx_delay.initial = mp_ncpus * 25; mtx_delay.step = (mp_ncpus * 25) / 2; mtx_delay.min = mp_ncpus * 5; mtx_delay.max = mp_ncpus * 25 * 10; } LOCK_DELAY_SYSINIT(mtx_delay_sysinit); #endif static SYSCTL_NODE(_debug, OID_AUTO, mtx_spin, CTLFLAG_RD, NULL, "mtx spin debugging"); static struct lock_delay_config __read_mostly mtx_spin_delay = { .initial = 1000, .step = 500, .min = 100, .max = 5000, }; SYSCTL_INT(_debug_mtx_spin, OID_AUTO, delay_initial, CTLFLAG_RW, &mtx_spin_delay.initial, 0, ""); SYSCTL_INT(_debug_mtx_spin, OID_AUTO, delay_step, CTLFLAG_RW, &mtx_spin_delay.step, 0, ""); SYSCTL_INT(_debug_mtx_spin, OID_AUTO, delay_min, CTLFLAG_RW, &mtx_spin_delay.min, 0, ""); SYSCTL_INT(_debug_mtx_spin, OID_AUTO, delay_max, CTLFLAG_RW, &mtx_spin_delay.max, 0, ""); static void mtx_spin_delay_sysinit(void *dummy) { mtx_spin_delay.initial = mp_ncpus * 25; mtx_spin_delay.step = (mp_ncpus * 25) / 2; mtx_spin_delay.min = mp_ncpus * 5; mtx_spin_delay.max = mp_ncpus * 25 * 10; } LOCK_DELAY_SYSINIT(mtx_spin_delay_sysinit); /* * System-wide mutexes */ struct mtx blocked_lock; struct mtx Giant; void assert_mtx(const struct lock_object *lock, int what) { mtx_assert((const struct mtx *)lock, what); } void lock_mtx(struct lock_object *lock, uintptr_t how) { mtx_lock((struct mtx *)lock); } void lock_spin(struct lock_object *lock, uintptr_t how) { panic("spin locks can only use msleep_spin"); } uintptr_t unlock_mtx(struct lock_object *lock) { struct mtx *m; m = (struct mtx *)lock; mtx_assert(m, MA_OWNED | MA_NOTRECURSED); mtx_unlock(m); return (0); } uintptr_t unlock_spin(struct lock_object *lock) { panic("spin locks can only use msleep_spin"); } #ifdef KDTRACE_HOOKS int owner_mtx(const struct lock_object *lock, struct thread **owner) { const struct mtx *m; uintptr_t x; m = (const struct mtx *)lock; x = m->mtx_lock; *owner = (struct thread *)(x & ~MTX_FLAGMASK); return (x != MTX_UNOWNED); } #endif /* * Function versions of the inlined __mtx_* macros. These are used by * modules and can also be called from assembly language if needed. */ void __mtx_lock_flags(volatile uintptr_t *c, int opts, const char *file, int line) { struct mtx *m; + uintptr_t tid, v; if (SCHEDULER_STOPPED()) return; m = mtxlock2mtx(c); KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("mtx_lock() by idle thread %p on sleep mutex %s @ %s:%d", curthread, m->lock_object.lo_name, file, line)); KASSERT(m->mtx_lock != MTX_DESTROYED, ("mtx_lock() of destroyed mutex @ %s:%d", file, line)); KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_sleep, ("mtx_lock() of spin mutex %s @ %s:%d", m->lock_object.lo_name, file, line)); WITNESS_CHECKORDER(&m->lock_object, (opts & ~MTX_RECURSE) | LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL); - __mtx_lock(m, curthread, opts, file, line); + tid = (uintptr_t)curthread; + v = MTX_UNOWNED; + if (!_mtx_obtain_lock_fetch(m, &v, tid)) + _mtx_lock_sleep(m, v, tid, opts, file, line); + else + LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(adaptive__acquire, + m, 0, 0, file, line); LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file, line); WITNESS_LOCK(&m->lock_object, (opts & ~MTX_RECURSE) | LOP_EXCLUSIVE, file, line); TD_LOCKS_INC(curthread); } void __mtx_unlock_flags(volatile uintptr_t *c, int opts, const char *file, int line) { struct mtx *m; if (SCHEDULER_STOPPED()) return; m = mtxlock2mtx(c); KASSERT(m->mtx_lock != MTX_DESTROYED, ("mtx_unlock() of destroyed mutex @ %s:%d", file, line)); KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_sleep, ("mtx_unlock() of spin mutex %s @ %s:%d", m->lock_object.lo_name, file, line)); WITNESS_UNLOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line); LOCK_LOG_LOCK("UNLOCK", &m->lock_object, opts, m->mtx_recurse, file, line); mtx_assert(m, MA_OWNED); - __mtx_unlock(m, curthread, opts, file, line); + __mtx_unlock_sleep(c, opts, file, line); TD_LOCKS_DEC(curthread); } void __mtx_lock_spin_flags(volatile uintptr_t *c, int opts, const char *file, int line) { struct mtx *m; if (SCHEDULER_STOPPED()) return; m = mtxlock2mtx(c); KASSERT(m->mtx_lock != MTX_DESTROYED, ("mtx_lock_spin() of destroyed mutex @ %s:%d", file, line)); KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin, ("mtx_lock_spin() of sleep mutex %s @ %s:%d", m->lock_object.lo_name, file, line)); if (mtx_owned(m)) KASSERT((m->lock_object.lo_flags & LO_RECURSABLE) != 0 || (opts & MTX_RECURSE) != 0, ("mtx_lock_spin: recursed on non-recursive mutex %s @ %s:%d\n", m->lock_object.lo_name, file, line)); opts &= ~MTX_RECURSE; WITNESS_CHECKORDER(&m->lock_object, opts | LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL); __mtx_lock_spin(m, curthread, opts, file, line); LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file, line); WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line); } int __mtx_trylock_spin_flags(volatile uintptr_t *c, int opts, const char *file, int line) { struct mtx *m; if (SCHEDULER_STOPPED()) return (1); m = mtxlock2mtx(c); KASSERT(m->mtx_lock != MTX_DESTROYED, ("mtx_trylock_spin() of destroyed mutex @ %s:%d", file, line)); KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin, ("mtx_trylock_spin() of sleep mutex %s @ %s:%d", m->lock_object.lo_name, file, line)); KASSERT((opts & MTX_RECURSE) == 0, ("mtx_trylock_spin: unsupp. opt MTX_RECURSE on mutex %s @ %s:%d\n", m->lock_object.lo_name, file, line)); if (__mtx_trylock_spin(m, curthread, opts, file, line)) { LOCK_LOG_TRY("LOCK", &m->lock_object, opts, 1, file, line); WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line); return (1); } LOCK_LOG_TRY("LOCK", &m->lock_object, opts, 0, file, line); return (0); } void __mtx_unlock_spin_flags(volatile uintptr_t *c, int opts, const char *file, int line) { struct mtx *m; if (SCHEDULER_STOPPED()) return; m = mtxlock2mtx(c); KASSERT(m->mtx_lock != MTX_DESTROYED, ("mtx_unlock_spin() of destroyed mutex @ %s:%d", file, line)); KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin, ("mtx_unlock_spin() of sleep mutex %s @ %s:%d", m->lock_object.lo_name, file, line)); WITNESS_UNLOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line); LOCK_LOG_LOCK("UNLOCK", &m->lock_object, opts, m->mtx_recurse, file, line); mtx_assert(m, MA_OWNED); __mtx_unlock_spin(m); } /* * The important part of mtx_trylock{,_flags}() * Tries to acquire lock `m.' If this function is called on a mutex that * is already owned, it will recursively acquire the lock. */ int _mtx_trylock_flags_(volatile uintptr_t *c, int opts, const char *file, int line) { struct mtx *m; #ifdef LOCK_PROFILING uint64_t waittime = 0; int contested = 0; #endif int rval; if (SCHEDULER_STOPPED()) return (1); m = mtxlock2mtx(c); KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("mtx_trylock() by idle thread %p on sleep mutex %s @ %s:%d", curthread, m->lock_object.lo_name, file, line)); KASSERT(m->mtx_lock != MTX_DESTROYED, ("mtx_trylock() of destroyed mutex @ %s:%d", file, line)); KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_sleep, ("mtx_trylock() of spin mutex %s @ %s:%d", m->lock_object.lo_name, file, line)); if (mtx_owned(m) && ((m->lock_object.lo_flags & LO_RECURSABLE) != 0 || (opts & MTX_RECURSE) != 0)) { m->mtx_recurse++; atomic_set_ptr(&m->mtx_lock, MTX_RECURSED); rval = 1; } else rval = _mtx_obtain_lock(m, (uintptr_t)curthread); opts &= ~MTX_RECURSE; LOCK_LOG_TRY("LOCK", &m->lock_object, opts, rval, file, line); if (rval) { WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE | LOP_TRYLOCK, file, line); TD_LOCKS_INC(curthread); if (m->mtx_recurse == 0) LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(adaptive__acquire, m, contested, waittime, file, line); } return (rval); } /* * __mtx_lock_sleep: the tougher part of acquiring an MTX_DEF lock. * * We call this if the lock is either contested (i.e. we need to go to * sleep waiting for it), or if we need to recurse on it. */ void -__mtx_lock_sleep(volatile uintptr_t *c, uintptr_t tid, int opts, +__mtx_lock_sleep(volatile uintptr_t *c, uintptr_t v, uintptr_t tid, int opts, const char *file, int line) { struct mtx *m; struct turnstile *ts; - uintptr_t v; #ifdef ADAPTIVE_MUTEXES volatile struct thread *owner; #endif #ifdef KTR int cont_logged = 0; #endif #ifdef LOCK_PROFILING int contested = 0; uint64_t waittime = 0; #endif #if defined(ADAPTIVE_MUTEXES) || defined(KDTRACE_HOOKS) struct lock_delay_arg lda; #endif #ifdef KDTRACE_HOOKS u_int sleep_cnt = 0; int64_t sleep_time = 0; int64_t all_time = 0; #endif if (SCHEDULER_STOPPED()) return; #if defined(ADAPTIVE_MUTEXES) lock_delay_arg_init(&lda, &mtx_delay); #elif defined(KDTRACE_HOOKS) lock_delay_arg_init(&lda, NULL); #endif m = mtxlock2mtx(c); - v = MTX_READ_VALUE(m); if (__predict_false(lv_mtx_owner(v) == (struct thread *)tid)) { KASSERT((m->lock_object.lo_flags & LO_RECURSABLE) != 0 || (opts & MTX_RECURSE) != 0, ("_mtx_lock_sleep: recursed on non-recursive mutex %s @ %s:%d\n", m->lock_object.lo_name, file, line)); opts &= ~MTX_RECURSE; m->mtx_recurse++; atomic_set_ptr(&m->mtx_lock, MTX_RECURSED); if (LOCK_LOG_TEST(&m->lock_object, opts)) CTR1(KTR_LOCK, "_mtx_lock_sleep: %p recursing", m); return; } opts &= ~MTX_RECURSE; #ifdef HWPMC_HOOKS PMC_SOFT_CALL( , , lock, failed); #endif lock_profile_obtain_lock_failed(&m->lock_object, &contested, &waittime); if (LOCK_LOG_TEST(&m->lock_object, opts)) CTR4(KTR_LOCK, "_mtx_lock_sleep: %s contested (lock=%p) at %s:%d", m->lock_object.lo_name, (void *)m->mtx_lock, file, line); #ifdef KDTRACE_HOOKS all_time -= lockstat_nsecs(&m->lock_object); #endif for (;;) { if (v == MTX_UNOWNED) { - if (_mtx_obtain_lock(m, tid)) + if (_mtx_obtain_lock_fetch(m, &v, tid)) break; - v = MTX_READ_VALUE(m); continue; } #ifdef KDTRACE_HOOKS lda.spin_cnt++; #endif #ifdef ADAPTIVE_MUTEXES /* * If the owner is running on another CPU, spin until the * owner stops running or the state of the lock changes. */ owner = lv_mtx_owner(v); if (TD_IS_RUNNING(owner)) { if (LOCK_LOG_TEST(&m->lock_object, 0)) CTR3(KTR_LOCK, "%s: spinning on %p held by %p", __func__, m, owner); KTR_STATE1(KTR_SCHED, "thread", sched_tdname((struct thread *)tid), "spinning", "lockname:\"%s\"", m->lock_object.lo_name); do { lock_delay(&lda); v = MTX_READ_VALUE(m); owner = lv_mtx_owner(v); } while (v != MTX_UNOWNED && TD_IS_RUNNING(owner)); KTR_STATE0(KTR_SCHED, "thread", sched_tdname((struct thread *)tid), "running"); continue; } #endif ts = turnstile_trywait(&m->lock_object); v = MTX_READ_VALUE(m); /* * Check if the lock has been released while spinning for * the turnstile chain lock. */ if (v == MTX_UNOWNED) { turnstile_cancel(ts); continue; } #ifdef ADAPTIVE_MUTEXES /* * The current lock owner might have started executing * on another CPU (or the lock could have changed * owners) while we were waiting on the turnstile * chain lock. If so, drop the turnstile lock and try * again. */ owner = lv_mtx_owner(v); if (TD_IS_RUNNING(owner)) { turnstile_cancel(ts); continue; } #endif /* * If the mutex isn't already contested and a failure occurs * setting the contested bit, the mutex was either released * or the state of the MTX_RECURSED bit changed. */ if ((v & MTX_CONTESTED) == 0 && !atomic_cmpset_ptr(&m->mtx_lock, v, v | MTX_CONTESTED)) { turnstile_cancel(ts); v = MTX_READ_VALUE(m); continue; } /* * We definitely must sleep for this lock. */ mtx_assert(m, MA_NOTOWNED); #ifdef KTR if (!cont_logged) { CTR6(KTR_CONTENTION, "contention: %p at %s:%d wants %s, taken by %s:%d", (void *)tid, file, line, m->lock_object.lo_name, WITNESS_FILE(&m->lock_object), WITNESS_LINE(&m->lock_object)); cont_logged = 1; } #endif /* * Block on the turnstile. */ #ifdef KDTRACE_HOOKS sleep_time -= lockstat_nsecs(&m->lock_object); #endif turnstile_wait(ts, mtx_owner(m), TS_EXCLUSIVE_QUEUE); #ifdef KDTRACE_HOOKS sleep_time += lockstat_nsecs(&m->lock_object); sleep_cnt++; #endif v = MTX_READ_VALUE(m); } #ifdef KDTRACE_HOOKS all_time += lockstat_nsecs(&m->lock_object); #endif #ifdef KTR if (cont_logged) { CTR4(KTR_CONTENTION, "contention end: %s acquired by %p at %s:%d", m->lock_object.lo_name, (void *)tid, file, line); } #endif LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(adaptive__acquire, m, contested, waittime, file, line); #ifdef KDTRACE_HOOKS if (sleep_time) LOCKSTAT_RECORD1(adaptive__block, m, sleep_time); /* * Only record the loops spinning and not sleeping. */ if (lda.spin_cnt > sleep_cnt) LOCKSTAT_RECORD1(adaptive__spin, m, all_time - sleep_time); #endif } static void _mtx_lock_spin_failed(struct mtx *m) { struct thread *td; td = mtx_owner(m); /* If the mutex is unlocked, try again. */ if (td == NULL) return; printf( "spin lock %p (%s) held by %p (tid %d) too long\n", m, m->lock_object.lo_name, td, td->td_tid); #ifdef WITNESS witness_display_spinlock(&m->lock_object, td, printf); #endif panic("spin lock held too long"); } #ifdef SMP /* * _mtx_lock_spin_cookie: the tougher part of acquiring an MTX_SPIN lock. * * This is only called if we need to actually spin for the lock. Recursion * is handled inline. */ void -_mtx_lock_spin_cookie(volatile uintptr_t *c, uintptr_t tid, int opts, - const char *file, int line) +_mtx_lock_spin_cookie(volatile uintptr_t *c, uintptr_t v, uintptr_t tid, + int opts, const char *file, int line) { struct mtx *m; struct lock_delay_arg lda; - uintptr_t v; #ifdef LOCK_PROFILING int contested = 0; uint64_t waittime = 0; #endif #ifdef KDTRACE_HOOKS int64_t spin_time = 0; #endif if (SCHEDULER_STOPPED()) return; lock_delay_arg_init(&lda, &mtx_spin_delay); m = mtxlock2mtx(c); if (LOCK_LOG_TEST(&m->lock_object, opts)) CTR1(KTR_LOCK, "_mtx_lock_spin: %p spinning", m); KTR_STATE1(KTR_SCHED, "thread", sched_tdname((struct thread *)tid), "spinning", "lockname:\"%s\"", m->lock_object.lo_name); #ifdef HWPMC_HOOKS PMC_SOFT_CALL( , , lock, failed); #endif lock_profile_obtain_lock_failed(&m->lock_object, &contested, &waittime); #ifdef KDTRACE_HOOKS spin_time -= lockstat_nsecs(&m->lock_object); #endif - v = MTX_READ_VALUE(m); for (;;) { if (v == MTX_UNOWNED) { - if (_mtx_obtain_lock(m, tid)) + if (_mtx_obtain_lock_fetch(m, &v, tid)) break; - v = MTX_READ_VALUE(m); continue; } /* Give interrupts a chance while we spin. */ spinlock_exit(); do { if (lda.spin_cnt < 10000000) { lock_delay(&lda); } else { lda.spin_cnt++; if (lda.spin_cnt < 60000000 || kdb_active || panicstr != NULL) DELAY(1); else _mtx_lock_spin_failed(m); cpu_spinwait(); } v = MTX_READ_VALUE(m); } while (v != MTX_UNOWNED); spinlock_enter(); } #ifdef KDTRACE_HOOKS spin_time += lockstat_nsecs(&m->lock_object); #endif if (LOCK_LOG_TEST(&m->lock_object, opts)) CTR1(KTR_LOCK, "_mtx_lock_spin: %p spin done", m); KTR_STATE0(KTR_SCHED, "thread", sched_tdname((struct thread *)tid), "running"); #ifdef KDTRACE_HOOKS LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, m, contested, waittime, file, line); if (spin_time != 0) LOCKSTAT_RECORD1(spin__spin, m, spin_time); #endif } #endif /* SMP */ void thread_lock_flags_(struct thread *td, int opts, const char *file, int line) { struct mtx *m; uintptr_t tid, v; struct lock_delay_arg lda; #ifdef LOCK_PROFILING int contested = 0; uint64_t waittime = 0; #endif #ifdef KDTRACE_HOOKS int64_t spin_time = 0; #endif tid = (uintptr_t)curthread; if (SCHEDULER_STOPPED()) { /* * Ensure that spinlock sections are balanced even when the * scheduler is stopped, since we may otherwise inadvertently * re-enable interrupts while dumping core. */ spinlock_enter(); return; } lock_delay_arg_init(&lda, &mtx_spin_delay); #ifdef KDTRACE_HOOKS spin_time -= lockstat_nsecs(&td->td_lock->lock_object); #endif for (;;) { retry: + v = MTX_UNOWNED; spinlock_enter(); m = td->td_lock; KASSERT(m->mtx_lock != MTX_DESTROYED, ("thread_lock() of destroyed mutex @ %s:%d", file, line)); KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin, ("thread_lock() of sleep mutex %s @ %s:%d", m->lock_object.lo_name, file, line)); if (mtx_owned(m)) KASSERT((m->lock_object.lo_flags & LO_RECURSABLE) != 0, ("thread_lock: recursed on non-recursive mutex %s @ %s:%d\n", m->lock_object.lo_name, file, line)); WITNESS_CHECKORDER(&m->lock_object, opts | LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL); - v = MTX_READ_VALUE(m); for (;;) { - if (v == MTX_UNOWNED) { - if (_mtx_obtain_lock(m, tid)) - break; - v = MTX_READ_VALUE(m); + if (_mtx_obtain_lock_fetch(m, &v, tid)) + break; + if (v == MTX_UNOWNED) continue; - } if (v == tid) { m->mtx_recurse++; break; } #ifdef HWPMC_HOOKS PMC_SOFT_CALL( , , lock, failed); #endif lock_profile_obtain_lock_failed(&m->lock_object, &contested, &waittime); /* Give interrupts a chance while we spin. */ spinlock_exit(); do { if (lda.spin_cnt < 10000000) { lock_delay(&lda); } else { lda.spin_cnt++; if (lda.spin_cnt < 60000000 || kdb_active || panicstr != NULL) DELAY(1); else _mtx_lock_spin_failed(m); cpu_spinwait(); } if (m != td->td_lock) goto retry; v = MTX_READ_VALUE(m); } while (v != MTX_UNOWNED); spinlock_enter(); } if (m == td->td_lock) break; __mtx_unlock_spin(m); /* does spinlock_exit() */ } #ifdef KDTRACE_HOOKS spin_time += lockstat_nsecs(&m->lock_object); #endif if (m->mtx_recurse == 0) LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, m, contested, waittime, file, line); LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file, line); WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line); #ifdef KDTRACE_HOOKS if (spin_time != 0) LOCKSTAT_RECORD1(thread__spin, m, spin_time); #endif } struct mtx * thread_lock_block(struct thread *td) { struct mtx *lock; THREAD_LOCK_ASSERT(td, MA_OWNED); lock = td->td_lock; td->td_lock = &blocked_lock; mtx_unlock_spin(lock); return (lock); } void thread_lock_unblock(struct thread *td, struct mtx *new) { mtx_assert(new, MA_OWNED); MPASS(td->td_lock == &blocked_lock); atomic_store_rel_ptr((volatile void *)&td->td_lock, (uintptr_t)new); } void thread_lock_set(struct thread *td, struct mtx *new) { struct mtx *lock; mtx_assert(new, MA_OWNED); THREAD_LOCK_ASSERT(td, MA_OWNED); lock = td->td_lock; td->td_lock = new; mtx_unlock_spin(lock); } /* * __mtx_unlock_sleep: the tougher part of releasing an MTX_DEF lock. * * We are only called here if the lock is recursed or contested (i.e. we * need to wake up a blocked thread). */ void __mtx_unlock_sleep(volatile uintptr_t *c, int opts, const char *file, int line) { struct mtx *m; struct turnstile *ts; if (SCHEDULER_STOPPED()) return; m = mtxlock2mtx(c); - if (mtx_recursed(m)) { + if (!mtx_recursed(m)) { + LOCKSTAT_PROFILE_RELEASE_LOCK(adaptive__release, m); + if (_mtx_release_lock(m, (uintptr_t)curthread)) + return; + } else { if (--(m->mtx_recurse) == 0) atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED); if (LOCK_LOG_TEST(&m->lock_object, opts)) CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p unrecurse", m); return; } /* * We have to lock the chain before the turnstile so this turnstile * can be removed from the hash list if it is empty. */ turnstile_chain_lock(&m->lock_object); ts = turnstile_lookup(&m->lock_object); if (LOCK_LOG_TEST(&m->lock_object, opts)) CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p contested", m); MPASS(ts != NULL); turnstile_broadcast(ts, TS_EXCLUSIVE_QUEUE); _mtx_release_lock_quick(m); /* * This turnstile is now no longer associated with the mutex. We can * unlock the chain lock so a new turnstile may take it's place. */ turnstile_unpend(ts, TS_EXCLUSIVE_LOCK); turnstile_chain_unlock(&m->lock_object); } /* * All the unlocking of MTX_SPIN locks is done inline. * See the __mtx_unlock_spin() macro for the details. */ /* * The backing function for the INVARIANTS-enabled mtx_assert() */ #ifdef INVARIANT_SUPPORT void __mtx_assert(const volatile uintptr_t *c, int what, const char *file, int line) { const struct mtx *m; if (panicstr != NULL || dumping || SCHEDULER_STOPPED()) return; m = mtxlock2mtx(c); switch (what) { case MA_OWNED: case MA_OWNED | MA_RECURSED: case MA_OWNED | MA_NOTRECURSED: if (!mtx_owned(m)) panic("mutex %s not owned at %s:%d", m->lock_object.lo_name, file, line); if (mtx_recursed(m)) { if ((what & MA_NOTRECURSED) != 0) panic("mutex %s recursed at %s:%d", m->lock_object.lo_name, file, line); } else if ((what & MA_RECURSED) != 0) { panic("mutex %s unrecursed at %s:%d", m->lock_object.lo_name, file, line); } break; case MA_NOTOWNED: if (mtx_owned(m)) panic("mutex %s owned at %s:%d", m->lock_object.lo_name, file, line); break; default: panic("unknown mtx_assert at %s:%d", file, line); } } #endif /* * General init routine used by the MTX_SYSINIT() macro. */ void mtx_sysinit(void *arg) { struct mtx_args *margs = arg; mtx_init((struct mtx *)margs->ma_mtx, margs->ma_desc, NULL, margs->ma_opts); } /* * Mutex initialization routine; initialize lock `m' of type contained in * `opts' with options contained in `opts' and name `name.' The optional * lock type `type' is used as a general lock category name for use with * witness. */ void _mtx_init(volatile uintptr_t *c, const char *name, const char *type, int opts) { struct mtx *m; struct lock_class *class; int flags; m = mtxlock2mtx(c); MPASS((opts & ~(MTX_SPIN | MTX_QUIET | MTX_RECURSE | MTX_NOWITNESS | MTX_DUPOK | MTX_NOPROFILE | MTX_NEW)) == 0); ASSERT_ATOMIC_LOAD_PTR(m->mtx_lock, ("%s: mtx_lock not aligned for %s: %p", __func__, name, &m->mtx_lock)); /* Determine lock class and lock flags. */ if (opts & MTX_SPIN) class = &lock_class_mtx_spin; else class = &lock_class_mtx_sleep; flags = 0; if (opts & MTX_QUIET) flags |= LO_QUIET; if (opts & MTX_RECURSE) flags |= LO_RECURSABLE; if ((opts & MTX_NOWITNESS) == 0) flags |= LO_WITNESS; if (opts & MTX_DUPOK) flags |= LO_DUPOK; if (opts & MTX_NOPROFILE) flags |= LO_NOPROFILE; if (opts & MTX_NEW) flags |= LO_NEW; /* Initialize mutex. */ lock_init(&m->lock_object, class, name, type, flags); m->mtx_lock = MTX_UNOWNED; m->mtx_recurse = 0; } /* * Remove lock `m' from all_mtx queue. We don't allow MTX_QUIET to be * passed in as a flag here because if the corresponding mtx_init() was * called with MTX_QUIET set, then it will already be set in the mutex's * flags. */ void _mtx_destroy(volatile uintptr_t *c) { struct mtx *m; m = mtxlock2mtx(c); if (!mtx_owned(m)) MPASS(mtx_unowned(m)); else { MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0); /* Perform the non-mtx related part of mtx_unlock_spin(). */ if (LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin) spinlock_exit(); else TD_LOCKS_DEC(curthread); lock_profile_release_lock(&m->lock_object); /* Tell witness this isn't locked to make it happy. */ WITNESS_UNLOCK(&m->lock_object, LOP_EXCLUSIVE, __FILE__, __LINE__); } m->mtx_lock = MTX_DESTROYED; lock_destroy(&m->lock_object); } /* * Intialize the mutex code and system mutexes. This is called from the MD * startup code prior to mi_startup(). The per-CPU data space needs to be * setup before this is called. */ void mutex_init(void) { /* Setup turnstiles so that sleep mutexes work. */ init_turnstiles(); /* * Initialize mutexes. */ mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE); mtx_init(&blocked_lock, "blocked lock", NULL, MTX_SPIN); blocked_lock.mtx_lock = 0xdeadc0de; /* Always blocked. */ mtx_init(&proc0.p_mtx, "process lock", NULL, MTX_DEF | MTX_DUPOK); mtx_init(&proc0.p_slock, "process slock", NULL, MTX_SPIN); mtx_init(&proc0.p_statmtx, "pstatl", NULL, MTX_SPIN); mtx_init(&proc0.p_itimmtx, "pitiml", NULL, MTX_SPIN); mtx_init(&proc0.p_profmtx, "pprofl", NULL, MTX_SPIN); mtx_init(&devmtx, "cdev", NULL, MTX_DEF); mtx_lock(&Giant); } #ifdef DDB void db_show_mtx(const struct lock_object *lock) { struct thread *td; const struct mtx *m; m = (const struct mtx *)lock; db_printf(" flags: {"); if (LOCK_CLASS(lock) == &lock_class_mtx_spin) db_printf("SPIN"); else db_printf("DEF"); if (m->lock_object.lo_flags & LO_RECURSABLE) db_printf(", RECURSE"); if (m->lock_object.lo_flags & LO_DUPOK) db_printf(", DUPOK"); db_printf("}\n"); db_printf(" state: {"); if (mtx_unowned(m)) db_printf("UNOWNED"); else if (mtx_destroyed(m)) db_printf("DESTROYED"); else { db_printf("OWNED"); if (m->mtx_lock & MTX_CONTESTED) db_printf(", CONTESTED"); if (m->mtx_lock & MTX_RECURSED) db_printf(", RECURSED"); } db_printf("}\n"); if (!mtx_unowned(m) && !mtx_destroyed(m)) { td = mtx_owner(m); db_printf(" owner: %p (tid %d, pid %d, \"%s\")\n", td, td->td_tid, td->td_proc->p_pid, td->td_name); if (mtx_recursed(m)) db_printf(" recursed: %d\n", m->mtx_recurse); } } #endif Index: projects/ipsec/sys/kern/kern_rmlock.c =================================================================== --- projects/ipsec/sys/kern/kern_rmlock.c (revision 313312) +++ projects/ipsec/sys/kern/kern_rmlock.c (revision 313313) @@ -1,860 +1,860 @@ /*- * Copyright (c) 2007 Stephan Uphoff * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ /* * Machine independent bits of reader/writer lock implementation. */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DDB #include #endif /* * A cookie to mark destroyed rmlocks. This is stored in the head of * rm_activeReaders. */ #define RM_DESTROYED ((void *)0xdead) #define rm_destroyed(rm) \ (LIST_FIRST(&(rm)->rm_activeReaders) == RM_DESTROYED) #define RMPF_ONQUEUE 1 #define RMPF_SIGNAL 2 #ifndef INVARIANTS #define _rm_assert(c, what, file, line) #endif static void assert_rm(const struct lock_object *lock, int what); #ifdef DDB static void db_show_rm(const struct lock_object *lock); #endif static void lock_rm(struct lock_object *lock, uintptr_t how); #ifdef KDTRACE_HOOKS static int owner_rm(const struct lock_object *lock, struct thread **owner); #endif static uintptr_t unlock_rm(struct lock_object *lock); struct lock_class lock_class_rm = { .lc_name = "rm", .lc_flags = LC_SLEEPLOCK | LC_RECURSABLE, .lc_assert = assert_rm, #ifdef DDB .lc_ddb_show = db_show_rm, #endif .lc_lock = lock_rm, .lc_unlock = unlock_rm, #ifdef KDTRACE_HOOKS .lc_owner = owner_rm, #endif }; struct lock_class lock_class_rm_sleepable = { .lc_name = "sleepable rm", .lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE, .lc_assert = assert_rm, #ifdef DDB .lc_ddb_show = db_show_rm, #endif .lc_lock = lock_rm, .lc_unlock = unlock_rm, #ifdef KDTRACE_HOOKS .lc_owner = owner_rm, #endif }; static void assert_rm(const struct lock_object *lock, int what) { rm_assert((const struct rmlock *)lock, what); } static void lock_rm(struct lock_object *lock, uintptr_t how) { struct rmlock *rm; struct rm_priotracker *tracker; rm = (struct rmlock *)lock; if (how == 0) rm_wlock(rm); else { tracker = (struct rm_priotracker *)how; rm_rlock(rm, tracker); } } static uintptr_t unlock_rm(struct lock_object *lock) { struct thread *td; struct pcpu *pc; struct rmlock *rm; struct rm_queue *queue; struct rm_priotracker *tracker; uintptr_t how; rm = (struct rmlock *)lock; tracker = NULL; how = 0; rm_assert(rm, RA_LOCKED | RA_NOTRECURSED); if (rm_wowned(rm)) rm_wunlock(rm); else { /* * Find the right rm_priotracker structure for curthread. * The guarantee about its uniqueness is given by the fact * we already asserted the lock wasn't recursively acquired. */ critical_enter(); td = curthread; - pc = get_pcpu(); + pc = pcpu_find(curcpu); for (queue = pc->pc_rm_queue.rmq_next; queue != &pc->pc_rm_queue; queue = queue->rmq_next) { tracker = (struct rm_priotracker *)queue; if ((tracker->rmp_rmlock == rm) && (tracker->rmp_thread == td)) { how = (uintptr_t)tracker; break; } } KASSERT(tracker != NULL, ("rm_priotracker is non-NULL when lock held in read mode")); critical_exit(); rm_runlock(rm, tracker); } return (how); } #ifdef KDTRACE_HOOKS static int owner_rm(const struct lock_object *lock, struct thread **owner) { const struct rmlock *rm; struct lock_class *lc; rm = (const struct rmlock *)lock; lc = LOCK_CLASS(&rm->rm_wlock_object); return (lc->lc_owner(&rm->rm_wlock_object, owner)); } #endif static struct mtx rm_spinlock; MTX_SYSINIT(rm_spinlock, &rm_spinlock, "rm_spinlock", MTX_SPIN); /* * Add or remove tracker from per-cpu list. * * The per-cpu list can be traversed at any time in forward direction from an * interrupt on the *local* cpu. */ static void inline rm_tracker_add(struct pcpu *pc, struct rm_priotracker *tracker) { struct rm_queue *next; /* Initialize all tracker pointers */ tracker->rmp_cpuQueue.rmq_prev = &pc->pc_rm_queue; next = pc->pc_rm_queue.rmq_next; tracker->rmp_cpuQueue.rmq_next = next; /* rmq_prev is not used during froward traversal. */ next->rmq_prev = &tracker->rmp_cpuQueue; /* Update pointer to first element. */ pc->pc_rm_queue.rmq_next = &tracker->rmp_cpuQueue; } /* * Return a count of the number of trackers the thread 'td' already * has on this CPU for the lock 'rm'. */ static int rm_trackers_present(const struct pcpu *pc, const struct rmlock *rm, const struct thread *td) { struct rm_queue *queue; struct rm_priotracker *tracker; int count; count = 0; for (queue = pc->pc_rm_queue.rmq_next; queue != &pc->pc_rm_queue; queue = queue->rmq_next) { tracker = (struct rm_priotracker *)queue; if ((tracker->rmp_rmlock == rm) && (tracker->rmp_thread == td)) count++; } return (count); } static void inline rm_tracker_remove(struct pcpu *pc, struct rm_priotracker *tracker) { struct rm_queue *next, *prev; next = tracker->rmp_cpuQueue.rmq_next; prev = tracker->rmp_cpuQueue.rmq_prev; /* Not used during forward traversal. */ next->rmq_prev = prev; /* Remove from list. */ prev->rmq_next = next; } static void rm_cleanIPI(void *arg) { struct pcpu *pc; struct rmlock *rm = arg; struct rm_priotracker *tracker; struct rm_queue *queue; - pc = get_pcpu(); + pc = pcpu_find(curcpu); for (queue = pc->pc_rm_queue.rmq_next; queue != &pc->pc_rm_queue; queue = queue->rmq_next) { tracker = (struct rm_priotracker *)queue; if (tracker->rmp_rmlock == rm && tracker->rmp_flags == 0) { tracker->rmp_flags = RMPF_ONQUEUE; mtx_lock_spin(&rm_spinlock); LIST_INSERT_HEAD(&rm->rm_activeReaders, tracker, rmp_qentry); mtx_unlock_spin(&rm_spinlock); } } } void rm_init_flags(struct rmlock *rm, const char *name, int opts) { struct lock_class *lc; int liflags, xflags; liflags = 0; if (!(opts & RM_NOWITNESS)) liflags |= LO_WITNESS; if (opts & RM_RECURSE) liflags |= LO_RECURSABLE; if (opts & RM_NEW) liflags |= LO_NEW; rm->rm_writecpus = all_cpus; LIST_INIT(&rm->rm_activeReaders); if (opts & RM_SLEEPABLE) { liflags |= LO_SLEEPABLE; lc = &lock_class_rm_sleepable; xflags = (opts & RM_NEW ? SX_NEW : 0); sx_init_flags(&rm->rm_lock_sx, "rmlock_sx", xflags | SX_NOWITNESS); } else { lc = &lock_class_rm; xflags = (opts & RM_NEW ? MTX_NEW : 0); mtx_init(&rm->rm_lock_mtx, name, "rmlock_mtx", xflags | MTX_NOWITNESS); } lock_init(&rm->lock_object, lc, name, NULL, liflags); } void rm_init(struct rmlock *rm, const char *name) { rm_init_flags(rm, name, 0); } void rm_destroy(struct rmlock *rm) { rm_assert(rm, RA_UNLOCKED); LIST_FIRST(&rm->rm_activeReaders) = RM_DESTROYED; if (rm->lock_object.lo_flags & LO_SLEEPABLE) sx_destroy(&rm->rm_lock_sx); else mtx_destroy(&rm->rm_lock_mtx); lock_destroy(&rm->lock_object); } int rm_wowned(const struct rmlock *rm) { if (rm->lock_object.lo_flags & LO_SLEEPABLE) return (sx_xlocked(&rm->rm_lock_sx)); else return (mtx_owned(&rm->rm_lock_mtx)); } void rm_sysinit(void *arg) { struct rm_args *args = arg; rm_init(args->ra_rm, args->ra_desc); } void rm_sysinit_flags(void *arg) { struct rm_args_flags *args = arg; rm_init_flags(args->ra_rm, args->ra_desc, args->ra_opts); } static int _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker, int trylock) { struct pcpu *pc; critical_enter(); - pc = get_pcpu(); + pc = pcpu_find(curcpu); /* Check if we just need to do a proper critical_exit. */ if (!CPU_ISSET(pc->pc_cpuid, &rm->rm_writecpus)) { critical_exit(); return (1); } /* Remove our tracker from the per-cpu list. */ rm_tracker_remove(pc, tracker); /* Check to see if the IPI granted us the lock after all. */ if (tracker->rmp_flags) { /* Just add back tracker - we hold the lock. */ rm_tracker_add(pc, tracker); critical_exit(); return (1); } /* * We allow readers to acquire a lock even if a writer is blocked if * the lock is recursive and the reader already holds the lock. */ if ((rm->lock_object.lo_flags & LO_RECURSABLE) != 0) { /* * Just grant the lock if this thread already has a tracker * for this lock on the per-cpu queue. */ if (rm_trackers_present(pc, rm, curthread) != 0) { mtx_lock_spin(&rm_spinlock); LIST_INSERT_HEAD(&rm->rm_activeReaders, tracker, rmp_qentry); tracker->rmp_flags = RMPF_ONQUEUE; mtx_unlock_spin(&rm_spinlock); rm_tracker_add(pc, tracker); critical_exit(); return (1); } } sched_unpin(); critical_exit(); if (trylock) { if (rm->lock_object.lo_flags & LO_SLEEPABLE) { if (!sx_try_xlock(&rm->rm_lock_sx)) return (0); } else { if (!mtx_trylock(&rm->rm_lock_mtx)) return (0); } } else { if (rm->lock_object.lo_flags & LO_SLEEPABLE) { THREAD_SLEEPING_OK(); sx_xlock(&rm->rm_lock_sx); THREAD_NO_SLEEPING(); } else mtx_lock(&rm->rm_lock_mtx); } critical_enter(); - pc = get_pcpu(); + pc = pcpu_find(curcpu); CPU_CLR(pc->pc_cpuid, &rm->rm_writecpus); rm_tracker_add(pc, tracker); sched_pin(); critical_exit(); if (rm->lock_object.lo_flags & LO_SLEEPABLE) sx_xunlock(&rm->rm_lock_sx); else mtx_unlock(&rm->rm_lock_mtx); return (1); } int _rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker, int trylock) { struct thread *td = curthread; struct pcpu *pc; if (SCHEDULER_STOPPED()) return (1); tracker->rmp_flags = 0; tracker->rmp_thread = td; tracker->rmp_rmlock = rm; if (rm->lock_object.lo_flags & LO_SLEEPABLE) THREAD_NO_SLEEPING(); td->td_critnest++; /* critical_enter(); */ __compiler_membar(); pc = cpuid_to_pcpu[td->td_oncpu]; /* pcpu_find(td->td_oncpu); */ rm_tracker_add(pc, tracker); sched_pin(); __compiler_membar(); td->td_critnest--; /* * Fast path to combine two common conditions into a single * conditional jump. */ if (0 == (td->td_owepreempt | CPU_ISSET(pc->pc_cpuid, &rm->rm_writecpus))) return (1); /* We do not have a read token and need to acquire one. */ return _rm_rlock_hard(rm, tracker, trylock); } static void _rm_unlock_hard(struct thread *td,struct rm_priotracker *tracker) { if (td->td_owepreempt) { td->td_critnest++; critical_exit(); } if (!tracker->rmp_flags) return; mtx_lock_spin(&rm_spinlock); LIST_REMOVE(tracker, rmp_qentry); if (tracker->rmp_flags & RMPF_SIGNAL) { struct rmlock *rm; struct turnstile *ts; rm = tracker->rmp_rmlock; turnstile_chain_lock(&rm->lock_object); mtx_unlock_spin(&rm_spinlock); ts = turnstile_lookup(&rm->lock_object); turnstile_signal(ts, TS_EXCLUSIVE_QUEUE); turnstile_unpend(ts, TS_EXCLUSIVE_LOCK); turnstile_chain_unlock(&rm->lock_object); } else mtx_unlock_spin(&rm_spinlock); } void _rm_runlock(struct rmlock *rm, struct rm_priotracker *tracker) { struct pcpu *pc; struct thread *td = tracker->rmp_thread; if (SCHEDULER_STOPPED()) return; td->td_critnest++; /* critical_enter(); */ pc = cpuid_to_pcpu[td->td_oncpu]; /* pcpu_find(td->td_oncpu); */ rm_tracker_remove(pc, tracker); td->td_critnest--; sched_unpin(); if (rm->lock_object.lo_flags & LO_SLEEPABLE) THREAD_SLEEPING_OK(); if (0 == (td->td_owepreempt | tracker->rmp_flags)) return; _rm_unlock_hard(td, tracker); } void _rm_wlock(struct rmlock *rm) { struct rm_priotracker *prio; struct turnstile *ts; cpuset_t readcpus; if (SCHEDULER_STOPPED()) return; if (rm->lock_object.lo_flags & LO_SLEEPABLE) sx_xlock(&rm->rm_lock_sx); else mtx_lock(&rm->rm_lock_mtx); if (CPU_CMP(&rm->rm_writecpus, &all_cpus)) { /* Get all read tokens back */ readcpus = all_cpus; CPU_NAND(&readcpus, &rm->rm_writecpus); rm->rm_writecpus = all_cpus; /* * Assumes rm->rm_writecpus update is visible on other CPUs * before rm_cleanIPI is called. */ #ifdef SMP smp_rendezvous_cpus(readcpus, smp_no_rendevous_barrier, rm_cleanIPI, smp_no_rendevous_barrier, rm); #else rm_cleanIPI(rm); #endif mtx_lock_spin(&rm_spinlock); while ((prio = LIST_FIRST(&rm->rm_activeReaders)) != NULL) { ts = turnstile_trywait(&rm->lock_object); prio->rmp_flags = RMPF_ONQUEUE | RMPF_SIGNAL; mtx_unlock_spin(&rm_spinlock); turnstile_wait(ts, prio->rmp_thread, TS_EXCLUSIVE_QUEUE); mtx_lock_spin(&rm_spinlock); } mtx_unlock_spin(&rm_spinlock); } } void _rm_wunlock(struct rmlock *rm) { if (rm->lock_object.lo_flags & LO_SLEEPABLE) sx_xunlock(&rm->rm_lock_sx); else mtx_unlock(&rm->rm_lock_mtx); } #if LOCK_DEBUG > 0 void _rm_wlock_debug(struct rmlock *rm, const char *file, int line) { if (SCHEDULER_STOPPED()) return; KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("rm_wlock() by idle thread %p on rmlock %s @ %s:%d", curthread, rm->lock_object.lo_name, file, line)); KASSERT(!rm_destroyed(rm), ("rm_wlock() of destroyed rmlock @ %s:%d", file, line)); _rm_assert(rm, RA_UNLOCKED, file, line); WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL); _rm_wlock(rm); LOCK_LOG_LOCK("RMWLOCK", &rm->lock_object, 0, 0, file, line); WITNESS_LOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line); TD_LOCKS_INC(curthread); } void _rm_wunlock_debug(struct rmlock *rm, const char *file, int line) { if (SCHEDULER_STOPPED()) return; KASSERT(!rm_destroyed(rm), ("rm_wunlock() of destroyed rmlock @ %s:%d", file, line)); _rm_assert(rm, RA_WLOCKED, file, line); WITNESS_UNLOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line); LOCK_LOG_LOCK("RMWUNLOCK", &rm->lock_object, 0, 0, file, line); _rm_wunlock(rm); TD_LOCKS_DEC(curthread); } int _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, int trylock, const char *file, int line) { if (SCHEDULER_STOPPED()) return (1); #ifdef INVARIANTS if (!(rm->lock_object.lo_flags & LO_RECURSABLE) && !trylock) { critical_enter(); - KASSERT(rm_trackers_present(get_pcpu(), rm, + KASSERT(rm_trackers_present(pcpu_find(curcpu), rm, curthread) == 0, ("rm_rlock: recursed on non-recursive rmlock %s @ %s:%d\n", rm->lock_object.lo_name, file, line)); critical_exit(); } #endif KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("rm_rlock() by idle thread %p on rmlock %s @ %s:%d", curthread, rm->lock_object.lo_name, file, line)); KASSERT(!rm_destroyed(rm), ("rm_rlock() of destroyed rmlock @ %s:%d", file, line)); if (!trylock) { KASSERT(!rm_wowned(rm), ("rm_rlock: wlock already held for %s @ %s:%d", rm->lock_object.lo_name, file, line)); WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER, file, line, NULL); } if (_rm_rlock(rm, tracker, trylock)) { if (trylock) LOCK_LOG_TRY("RMRLOCK", &rm->lock_object, 0, 1, file, line); else LOCK_LOG_LOCK("RMRLOCK", &rm->lock_object, 0, 0, file, line); WITNESS_LOCK(&rm->lock_object, 0, file, line); TD_LOCKS_INC(curthread); return (1); } else if (trylock) LOCK_LOG_TRY("RMRLOCK", &rm->lock_object, 0, 0, file, line); return (0); } void _rm_runlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, const char *file, int line) { if (SCHEDULER_STOPPED()) return; KASSERT(!rm_destroyed(rm), ("rm_runlock() of destroyed rmlock @ %s:%d", file, line)); _rm_assert(rm, RA_RLOCKED, file, line); WITNESS_UNLOCK(&rm->lock_object, 0, file, line); LOCK_LOG_LOCK("RMRUNLOCK", &rm->lock_object, 0, 0, file, line); _rm_runlock(rm, tracker); TD_LOCKS_DEC(curthread); } #else /* * Just strip out file and line arguments if no lock debugging is enabled in * the kernel - we are called from a kernel module. */ void _rm_wlock_debug(struct rmlock *rm, const char *file, int line) { _rm_wlock(rm); } void _rm_wunlock_debug(struct rmlock *rm, const char *file, int line) { _rm_wunlock(rm); } int _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, int trylock, const char *file, int line) { return _rm_rlock(rm, tracker, trylock); } void _rm_runlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, const char *file, int line) { _rm_runlock(rm, tracker); } #endif #ifdef INVARIANT_SUPPORT #ifndef INVARIANTS #undef _rm_assert #endif /* * Note that this does not need to use witness_assert() for read lock * assertions since an exact count of read locks held by this thread * is computable. */ void _rm_assert(const struct rmlock *rm, int what, const char *file, int line) { int count; if (panicstr != NULL) return; switch (what) { case RA_LOCKED: case RA_LOCKED | RA_RECURSED: case RA_LOCKED | RA_NOTRECURSED: case RA_RLOCKED: case RA_RLOCKED | RA_RECURSED: case RA_RLOCKED | RA_NOTRECURSED: /* * Handle the write-locked case. Unlike other * primitives, writers can never recurse. */ if (rm_wowned(rm)) { if (what & RA_RLOCKED) panic("Lock %s exclusively locked @ %s:%d\n", rm->lock_object.lo_name, file, line); if (what & RA_RECURSED) panic("Lock %s not recursed @ %s:%d\n", rm->lock_object.lo_name, file, line); break; } critical_enter(); - count = rm_trackers_present(get_pcpu(), rm, curthread); + count = rm_trackers_present(pcpu_find(curcpu), rm, curthread); critical_exit(); if (count == 0) panic("Lock %s not %slocked @ %s:%d\n", rm->lock_object.lo_name, (what & RA_RLOCKED) ? "read " : "", file, line); if (count > 1) { if (what & RA_NOTRECURSED) panic("Lock %s recursed @ %s:%d\n", rm->lock_object.lo_name, file, line); } else if (what & RA_RECURSED) panic("Lock %s not recursed @ %s:%d\n", rm->lock_object.lo_name, file, line); break; case RA_WLOCKED: if (!rm_wowned(rm)) panic("Lock %s not exclusively locked @ %s:%d\n", rm->lock_object.lo_name, file, line); break; case RA_UNLOCKED: if (rm_wowned(rm)) panic("Lock %s exclusively locked @ %s:%d\n", rm->lock_object.lo_name, file, line); critical_enter(); - count = rm_trackers_present(get_pcpu(), rm, curthread); + count = rm_trackers_present(pcpu_find(curcpu), rm, curthread); critical_exit(); if (count != 0) panic("Lock %s read locked @ %s:%d\n", rm->lock_object.lo_name, file, line); break; default: panic("Unknown rm lock assertion: %d @ %s:%d", what, file, line); } } #endif /* INVARIANT_SUPPORT */ #ifdef DDB static void print_tracker(struct rm_priotracker *tr) { struct thread *td; td = tr->rmp_thread; db_printf(" thread %p (tid %d, pid %d, \"%s\") {", td, td->td_tid, td->td_proc->p_pid, td->td_name); if (tr->rmp_flags & RMPF_ONQUEUE) { db_printf("ONQUEUE"); if (tr->rmp_flags & RMPF_SIGNAL) db_printf(",SIGNAL"); } else db_printf("0"); db_printf("}\n"); } static void db_show_rm(const struct lock_object *lock) { struct rm_priotracker *tr; struct rm_queue *queue; const struct rmlock *rm; struct lock_class *lc; struct pcpu *pc; rm = (const struct rmlock *)lock; db_printf(" writecpus: "); ddb_display_cpuset(__DEQUALIFY(const cpuset_t *, &rm->rm_writecpus)); db_printf("\n"); db_printf(" per-CPU readers:\n"); STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) for (queue = pc->pc_rm_queue.rmq_next; queue != &pc->pc_rm_queue; queue = queue->rmq_next) { tr = (struct rm_priotracker *)queue; if (tr->rmp_rmlock == rm) print_tracker(tr); } db_printf(" active readers:\n"); LIST_FOREACH(tr, &rm->rm_activeReaders, rmp_qentry) print_tracker(tr); lc = LOCK_CLASS(&rm->rm_wlock_object); db_printf("Backing write-lock (%s):\n", lc->lc_name); lc->lc_ddb_show(&rm->rm_wlock_object); } #endif Index: projects/ipsec/sys/kern/kern_rwlock.c =================================================================== --- projects/ipsec/sys/kern/kern_rwlock.c (revision 313312) +++ projects/ipsec/sys/kern/kern_rwlock.c (revision 313313) @@ -1,1335 +1,1341 @@ /*- * Copyright (c) 2006 John Baldwin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ /* * Machine independent bits of reader/writer lock implementation. */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_hwpmc_hooks.h" #include "opt_no_adaptive_rwlocks.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(SMP) && !defined(NO_ADAPTIVE_RWLOCKS) #define ADAPTIVE_RWLOCKS #endif #ifdef HWPMC_HOOKS #include PMC_SOFT_DECLARE( , , lock, failed); #endif /* * Return the rwlock address when the lock cookie address is provided. * This functionality assumes that struct rwlock* have a member named rw_lock. */ #define rwlock2rw(c) (__containerof(c, struct rwlock, rw_lock)) #ifdef DDB #include static void db_show_rwlock(const struct lock_object *lock); #endif static void assert_rw(const struct lock_object *lock, int what); static void lock_rw(struct lock_object *lock, uintptr_t how); #ifdef KDTRACE_HOOKS static int owner_rw(const struct lock_object *lock, struct thread **owner); #endif static uintptr_t unlock_rw(struct lock_object *lock); struct lock_class lock_class_rw = { .lc_name = "rw", .lc_flags = LC_SLEEPLOCK | LC_RECURSABLE | LC_UPGRADABLE, .lc_assert = assert_rw, #ifdef DDB .lc_ddb_show = db_show_rwlock, #endif .lc_lock = lock_rw, .lc_unlock = unlock_rw, #ifdef KDTRACE_HOOKS .lc_owner = owner_rw, #endif }; #ifdef ADAPTIVE_RWLOCKS static int rowner_retries = 10; static int rowner_loops = 10000; static SYSCTL_NODE(_debug, OID_AUTO, rwlock, CTLFLAG_RD, NULL, "rwlock debugging"); SYSCTL_INT(_debug_rwlock, OID_AUTO, retry, CTLFLAG_RW, &rowner_retries, 0, ""); SYSCTL_INT(_debug_rwlock, OID_AUTO, loops, CTLFLAG_RW, &rowner_loops, 0, ""); static struct lock_delay_config __read_mostly rw_delay = { .initial = 1000, .step = 500, .min = 100, .max = 5000, }; SYSCTL_INT(_debug_rwlock, OID_AUTO, delay_initial, CTLFLAG_RW, &rw_delay.initial, 0, ""); SYSCTL_INT(_debug_rwlock, OID_AUTO, delay_step, CTLFLAG_RW, &rw_delay.step, 0, ""); SYSCTL_INT(_debug_rwlock, OID_AUTO, delay_min, CTLFLAG_RW, &rw_delay.min, 0, ""); SYSCTL_INT(_debug_rwlock, OID_AUTO, delay_max, CTLFLAG_RW, &rw_delay.max, 0, ""); static void rw_delay_sysinit(void *dummy) { rw_delay.initial = mp_ncpus * 25; rw_delay.step = (mp_ncpus * 25) / 2; rw_delay.min = mp_ncpus * 5; rw_delay.max = mp_ncpus * 25 * 10; } LOCK_DELAY_SYSINIT(rw_delay_sysinit); #endif /* * Return a pointer to the owning thread if the lock is write-locked or * NULL if the lock is unlocked or read-locked. */ #define lv_rw_wowner(v) \ ((v) & RW_LOCK_READ ? NULL : \ (struct thread *)RW_OWNER((v))) #define rw_wowner(rw) lv_rw_wowner(RW_READ_VALUE(rw)) /* * Returns if a write owner is recursed. Write ownership is not assured * here and should be previously checked. */ #define rw_recursed(rw) ((rw)->rw_recurse != 0) /* * Return true if curthread helds the lock. */ #define rw_wlocked(rw) (rw_wowner((rw)) == curthread) /* * Return a pointer to the owning thread for this lock who should receive * any priority lent by threads that block on this lock. Currently this * is identical to rw_wowner(). */ #define rw_owner(rw) rw_wowner(rw) #ifndef INVARIANTS #define __rw_assert(c, what, file, line) #endif void assert_rw(const struct lock_object *lock, int what) { rw_assert((const struct rwlock *)lock, what); } void lock_rw(struct lock_object *lock, uintptr_t how) { struct rwlock *rw; rw = (struct rwlock *)lock; if (how) rw_rlock(rw); else rw_wlock(rw); } uintptr_t unlock_rw(struct lock_object *lock) { struct rwlock *rw; rw = (struct rwlock *)lock; rw_assert(rw, RA_LOCKED | LA_NOTRECURSED); if (rw->rw_lock & RW_LOCK_READ) { rw_runlock(rw); return (1); } else { rw_wunlock(rw); return (0); } } #ifdef KDTRACE_HOOKS int owner_rw(const struct lock_object *lock, struct thread **owner) { const struct rwlock *rw = (const struct rwlock *)lock; uintptr_t x = rw->rw_lock; *owner = rw_wowner(rw); return ((x & RW_LOCK_READ) != 0 ? (RW_READERS(x) != 0) : (*owner != NULL)); } #endif void _rw_init_flags(volatile uintptr_t *c, const char *name, int opts) { struct rwlock *rw; int flags; rw = rwlock2rw(c); MPASS((opts & ~(RW_DUPOK | RW_NOPROFILE | RW_NOWITNESS | RW_QUIET | RW_RECURSE | RW_NEW)) == 0); ASSERT_ATOMIC_LOAD_PTR(rw->rw_lock, ("%s: rw_lock not aligned for %s: %p", __func__, name, &rw->rw_lock)); flags = LO_UPGRADABLE; if (opts & RW_DUPOK) flags |= LO_DUPOK; if (opts & RW_NOPROFILE) flags |= LO_NOPROFILE; if (!(opts & RW_NOWITNESS)) flags |= LO_WITNESS; if (opts & RW_RECURSE) flags |= LO_RECURSABLE; if (opts & RW_QUIET) flags |= LO_QUIET; if (opts & RW_NEW) flags |= LO_NEW; lock_init(&rw->lock_object, &lock_class_rw, name, NULL, flags); rw->rw_lock = RW_UNLOCKED; rw->rw_recurse = 0; } void _rw_destroy(volatile uintptr_t *c) { struct rwlock *rw; rw = rwlock2rw(c); KASSERT(rw->rw_lock == RW_UNLOCKED, ("rw lock %p not unlocked", rw)); KASSERT(rw->rw_recurse == 0, ("rw lock %p still recursed", rw)); rw->rw_lock = RW_DESTROYED; lock_destroy(&rw->lock_object); } void rw_sysinit(void *arg) { struct rw_args *args = arg; rw_init((struct rwlock *)args->ra_rw, args->ra_desc); } void rw_sysinit_flags(void *arg) { struct rw_args_flags *args = arg; rw_init_flags((struct rwlock *)args->ra_rw, args->ra_desc, args->ra_flags); } int _rw_wowned(const volatile uintptr_t *c) { return (rw_wowner(rwlock2rw(c)) == curthread); } void _rw_wlock_cookie(volatile uintptr_t *c, const char *file, int line) { struct rwlock *rw; + uintptr_t tid, v; if (SCHEDULER_STOPPED()) return; rw = rwlock2rw(c); KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("rw_wlock() by idle thread %p on rwlock %s @ %s:%d", curthread, rw->lock_object.lo_name, file, line)); KASSERT(rw->rw_lock != RW_DESTROYED, ("rw_wlock() of destroyed rwlock @ %s:%d", file, line)); WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL); - __rw_wlock(rw, curthread, file, line); + tid = (uintptr_t)curthread; + v = RW_UNLOCKED; + if (!_rw_write_lock_fetch(rw, &v, tid)) + _rw_wlock_hard(rw, v, tid, file, line); + else + LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(rw__acquire, rw, + 0, 0, file, line, LOCKSTAT_WRITER); + LOCK_LOG_LOCK("WLOCK", &rw->lock_object, 0, rw->rw_recurse, file, line); WITNESS_LOCK(&rw->lock_object, LOP_EXCLUSIVE, file, line); TD_LOCKS_INC(curthread); } int __rw_try_wlock(volatile uintptr_t *c, const char *file, int line) { struct rwlock *rw; int rval; if (SCHEDULER_STOPPED()) return (1); rw = rwlock2rw(c); KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("rw_try_wlock() by idle thread %p on rwlock %s @ %s:%d", curthread, rw->lock_object.lo_name, file, line)); KASSERT(rw->rw_lock != RW_DESTROYED, ("rw_try_wlock() of destroyed rwlock @ %s:%d", file, line)); if (rw_wlocked(rw) && (rw->lock_object.lo_flags & LO_RECURSABLE) != 0) { rw->rw_recurse++; rval = 1; } else rval = atomic_cmpset_acq_ptr(&rw->rw_lock, RW_UNLOCKED, (uintptr_t)curthread); LOCK_LOG_TRY("WLOCK", &rw->lock_object, 0, rval, file, line); if (rval) { WITNESS_LOCK(&rw->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK, file, line); if (!rw_recursed(rw)) LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(rw__acquire, rw, 0, 0, file, line, LOCKSTAT_WRITER); TD_LOCKS_INC(curthread); } return (rval); } void _rw_wunlock_cookie(volatile uintptr_t *c, const char *file, int line) { struct rwlock *rw; if (SCHEDULER_STOPPED()) return; rw = rwlock2rw(c); KASSERT(rw->rw_lock != RW_DESTROYED, ("rw_wunlock() of destroyed rwlock @ %s:%d", file, line)); __rw_assert(c, RA_WLOCKED, file, line); WITNESS_UNLOCK(&rw->lock_object, LOP_EXCLUSIVE, file, line); LOCK_LOG_LOCK("WUNLOCK", &rw->lock_object, 0, rw->rw_recurse, file, line); - __rw_wunlock(rw, curthread, file, line); + if (rw->rw_recurse) + rw->rw_recurse--; + else + _rw_wunlock_hard(rw, (uintptr_t)curthread, file, line); + TD_LOCKS_DEC(curthread); } /* * Determines whether a new reader can acquire a lock. Succeeds if the * reader already owns a read lock and the lock is locked for read to * prevent deadlock from reader recursion. Also succeeds if the lock * is unlocked and has no writer waiters or spinners. Failing otherwise * prioritizes writers before readers. */ #define RW_CAN_READ(_rw) \ ((curthread->td_rw_rlocks && (_rw) & RW_LOCK_READ) || ((_rw) & \ (RW_LOCK_READ | RW_LOCK_WRITE_WAITERS | RW_LOCK_WRITE_SPINNER)) == \ RW_LOCK_READ) void __rw_rlock(volatile uintptr_t *c, const char *file, int line) { struct rwlock *rw; struct turnstile *ts; #ifdef ADAPTIVE_RWLOCKS volatile struct thread *owner; int spintries = 0; int i; #endif #ifdef LOCK_PROFILING uint64_t waittime = 0; int contested = 0; #endif uintptr_t v; #if defined(ADAPTIVE_RWLOCKS) || defined(KDTRACE_HOOKS) struct lock_delay_arg lda; #endif #ifdef KDTRACE_HOOKS uintptr_t state; u_int sleep_cnt = 0; int64_t sleep_time = 0; int64_t all_time = 0; #endif if (SCHEDULER_STOPPED()) return; #if defined(ADAPTIVE_RWLOCKS) lock_delay_arg_init(&lda, &rw_delay); #elif defined(KDTRACE_HOOKS) lock_delay_arg_init(&lda, NULL); #endif rw = rwlock2rw(c); KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("rw_rlock() by idle thread %p on rwlock %s @ %s:%d", curthread, rw->lock_object.lo_name, file, line)); KASSERT(rw->rw_lock != RW_DESTROYED, ("rw_rlock() of destroyed rwlock @ %s:%d", file, line)); KASSERT(rw_wowner(rw) != curthread, ("rw_rlock: wlock already held for %s @ %s:%d", rw->lock_object.lo_name, file, line)); WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER, file, line, NULL); #ifdef KDTRACE_HOOKS all_time -= lockstat_nsecs(&rw->lock_object); #endif v = RW_READ_VALUE(rw); #ifdef KDTRACE_HOOKS state = v; #endif for (;;) { /* * Handle the easy case. If no other thread has a write * lock, then try to bump up the count of read locks. Note * that we have to preserve the current state of the * RW_LOCK_WRITE_WAITERS flag. If we fail to acquire a * read lock, then rw_lock must have changed, so restart * the loop. Note that this handles the case of a * completely unlocked rwlock since such a lock is encoded * as a read lock with no waiters. */ if (RW_CAN_READ(v)) { /* * The RW_LOCK_READ_WAITERS flag should only be set * if the lock has been unlocked and write waiters * were present. */ - if (atomic_cmpset_acq_ptr(&rw->rw_lock, v, + if (atomic_fcmpset_acq_ptr(&rw->rw_lock, &v, v + RW_ONE_READER)) { if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR4(KTR_LOCK, "%s: %p succeed %p -> %p", __func__, rw, (void *)v, (void *)(v + RW_ONE_READER)); break; } - v = RW_READ_VALUE(rw); continue; } #ifdef KDTRACE_HOOKS lda.spin_cnt++; #endif #ifdef HWPMC_HOOKS PMC_SOFT_CALL( , , lock, failed); #endif lock_profile_obtain_lock_failed(&rw->lock_object, &contested, &waittime); #ifdef ADAPTIVE_RWLOCKS /* * If the owner is running on another CPU, spin until * the owner stops running or the state of the lock * changes. */ if ((v & RW_LOCK_READ) == 0) { owner = (struct thread *)RW_OWNER(v); if (TD_IS_RUNNING(owner)) { if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR3(KTR_LOCK, "%s: spinning on %p held by %p", __func__, rw, owner); KTR_STATE1(KTR_SCHED, "thread", sched_tdname(curthread), "spinning", "lockname:\"%s\"", rw->lock_object.lo_name); do { lock_delay(&lda); v = RW_READ_VALUE(rw); owner = lv_rw_wowner(v); } while (owner != NULL && TD_IS_RUNNING(owner)); KTR_STATE0(KTR_SCHED, "thread", sched_tdname(curthread), "running"); continue; } } else if (spintries < rowner_retries) { spintries++; KTR_STATE1(KTR_SCHED, "thread", sched_tdname(curthread), "spinning", "lockname:\"%s\"", rw->lock_object.lo_name); for (i = 0; i < rowner_loops; i++) { v = RW_READ_VALUE(rw); if ((v & RW_LOCK_READ) == 0 || RW_CAN_READ(v)) break; cpu_spinwait(); } v = RW_READ_VALUE(rw); #ifdef KDTRACE_HOOKS lda.spin_cnt += rowner_loops - i; #endif KTR_STATE0(KTR_SCHED, "thread", sched_tdname(curthread), "running"); if (i != rowner_loops) continue; } #endif /* * Okay, now it's the hard case. Some other thread already * has a write lock or there are write waiters present, * acquire the turnstile lock so we can begin the process * of blocking. */ ts = turnstile_trywait(&rw->lock_object); /* * The lock might have been released while we spun, so * recheck its state and restart the loop if needed. */ v = RW_READ_VALUE(rw); if (RW_CAN_READ(v)) { turnstile_cancel(ts); continue; } #ifdef ADAPTIVE_RWLOCKS /* * The current lock owner might have started executing * on another CPU (or the lock could have changed * owners) while we were waiting on the turnstile * chain lock. If so, drop the turnstile lock and try * again. */ if ((v & RW_LOCK_READ) == 0) { owner = (struct thread *)RW_OWNER(v); if (TD_IS_RUNNING(owner)) { turnstile_cancel(ts); continue; } } #endif /* * The lock is held in write mode or it already has waiters. */ MPASS(!RW_CAN_READ(v)); /* * If the RW_LOCK_READ_WAITERS flag is already set, then * we can go ahead and block. If it is not set then try * to set it. If we fail to set it drop the turnstile * lock and restart the loop. */ if (!(v & RW_LOCK_READ_WAITERS)) { if (!atomic_cmpset_ptr(&rw->rw_lock, v, v | RW_LOCK_READ_WAITERS)) { turnstile_cancel(ts); v = RW_READ_VALUE(rw); continue; } if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p set read waiters flag", __func__, rw); } /* * We were unable to acquire the lock and the read waiters * flag is set, so we must block on the turnstile. */ if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p blocking on turnstile", __func__, rw); #ifdef KDTRACE_HOOKS sleep_time -= lockstat_nsecs(&rw->lock_object); #endif turnstile_wait(ts, rw_owner(rw), TS_SHARED_QUEUE); #ifdef KDTRACE_HOOKS sleep_time += lockstat_nsecs(&rw->lock_object); sleep_cnt++; #endif if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p resuming from turnstile", __func__, rw); v = RW_READ_VALUE(rw); } #ifdef KDTRACE_HOOKS all_time += lockstat_nsecs(&rw->lock_object); if (sleep_time) LOCKSTAT_RECORD4(rw__block, rw, sleep_time, LOCKSTAT_READER, (state & RW_LOCK_READ) == 0, (state & RW_LOCK_READ) == 0 ? 0 : RW_READERS(state)); /* Record only the loops spinning and not sleeping. */ if (lda.spin_cnt > sleep_cnt) LOCKSTAT_RECORD4(rw__spin, rw, all_time - sleep_time, LOCKSTAT_READER, (state & RW_LOCK_READ) == 0, (state & RW_LOCK_READ) == 0 ? 0 : RW_READERS(state)); #endif /* * TODO: acquire "owner of record" here. Here be turnstile dragons * however. turnstiles don't like owners changing between calls to * turnstile_wait() currently. */ LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(rw__acquire, rw, contested, waittime, file, line, LOCKSTAT_READER); LOCK_LOG_LOCK("RLOCK", &rw->lock_object, 0, 0, file, line); WITNESS_LOCK(&rw->lock_object, 0, file, line); TD_LOCKS_INC(curthread); curthread->td_rw_rlocks++; } int __rw_try_rlock(volatile uintptr_t *c, const char *file, int line) { struct rwlock *rw; uintptr_t x; if (SCHEDULER_STOPPED()) return (1); rw = rwlock2rw(c); KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("rw_try_rlock() by idle thread %p on rwlock %s @ %s:%d", curthread, rw->lock_object.lo_name, file, line)); for (;;) { x = rw->rw_lock; KASSERT(rw->rw_lock != RW_DESTROYED, ("rw_try_rlock() of destroyed rwlock @ %s:%d", file, line)); if (!(x & RW_LOCK_READ)) break; if (atomic_cmpset_acq_ptr(&rw->rw_lock, x, x + RW_ONE_READER)) { LOCK_LOG_TRY("RLOCK", &rw->lock_object, 0, 1, file, line); WITNESS_LOCK(&rw->lock_object, LOP_TRYLOCK, file, line); LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(rw__acquire, rw, 0, 0, file, line, LOCKSTAT_READER); TD_LOCKS_INC(curthread); curthread->td_rw_rlocks++; return (1); } } LOCK_LOG_TRY("RLOCK", &rw->lock_object, 0, 0, file, line); return (0); } void _rw_runlock_cookie(volatile uintptr_t *c, const char *file, int line) { struct rwlock *rw; struct turnstile *ts; uintptr_t x, v, queue; if (SCHEDULER_STOPPED()) return; rw = rwlock2rw(c); KASSERT(rw->rw_lock != RW_DESTROYED, ("rw_runlock() of destroyed rwlock @ %s:%d", file, line)); __rw_assert(c, RA_RLOCKED, file, line); WITNESS_UNLOCK(&rw->lock_object, 0, file, line); LOCK_LOG_LOCK("RUNLOCK", &rw->lock_object, 0, 0, file, line); /* TODO: drop "owner of record" here. */ x = RW_READ_VALUE(rw); for (;;) { /* * See if there is more than one read lock held. If so, * just drop one and return. */ if (RW_READERS(x) > 1) { - if (atomic_cmpset_rel_ptr(&rw->rw_lock, x, + if (atomic_fcmpset_rel_ptr(&rw->rw_lock, &x, x - RW_ONE_READER)) { if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR4(KTR_LOCK, "%s: %p succeeded %p -> %p", __func__, rw, (void *)x, (void *)(x - RW_ONE_READER)); break; } - x = RW_READ_VALUE(rw); continue; } /* * If there aren't any waiters for a write lock, then try * to drop it quickly. */ if (!(x & RW_LOCK_WAITERS)) { MPASS((x & ~RW_LOCK_WRITE_SPINNER) == RW_READERS_LOCK(1)); - if (atomic_cmpset_rel_ptr(&rw->rw_lock, x, + if (atomic_fcmpset_rel_ptr(&rw->rw_lock, &x, RW_UNLOCKED)) { if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p last succeeded", __func__, rw); break; } - x = RW_READ_VALUE(rw); continue; } /* * Ok, we know we have waiters and we think we are the * last reader, so grab the turnstile lock. */ turnstile_chain_lock(&rw->lock_object); v = rw->rw_lock & (RW_LOCK_WAITERS | RW_LOCK_WRITE_SPINNER); MPASS(v & RW_LOCK_WAITERS); /* * Try to drop our lock leaving the lock in a unlocked * state. * * If you wanted to do explicit lock handoff you'd have to * do it here. You'd also want to use turnstile_signal() * and you'd have to handle the race where a higher * priority thread blocks on the write lock before the * thread you wakeup actually runs and have the new thread * "steal" the lock. For now it's a lot simpler to just * wakeup all of the waiters. * * As above, if we fail, then another thread might have * acquired a read lock, so drop the turnstile lock and * restart. */ x = RW_UNLOCKED; if (v & RW_LOCK_WRITE_WAITERS) { queue = TS_EXCLUSIVE_QUEUE; x |= (v & RW_LOCK_READ_WAITERS); } else queue = TS_SHARED_QUEUE; if (!atomic_cmpset_rel_ptr(&rw->rw_lock, RW_READERS_LOCK(1) | v, x)) { turnstile_chain_unlock(&rw->lock_object); x = RW_READ_VALUE(rw); continue; } if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p last succeeded with waiters", __func__, rw); /* * Ok. The lock is released and all that's left is to * wake up the waiters. Note that the lock might not be * free anymore, but in that case the writers will just * block again if they run before the new lock holder(s) * release the lock. */ ts = turnstile_lookup(&rw->lock_object); MPASS(ts != NULL); turnstile_broadcast(ts, queue); turnstile_unpend(ts, TS_SHARED_LOCK); turnstile_chain_unlock(&rw->lock_object); break; } LOCKSTAT_PROFILE_RELEASE_RWLOCK(rw__release, rw, LOCKSTAT_READER); TD_LOCKS_DEC(curthread); curthread->td_rw_rlocks--; } /* * This function is called when we are unable to obtain a write lock on the * first try. This means that at least one other thread holds either a * read or write lock. */ void -__rw_wlock_hard(volatile uintptr_t *c, uintptr_t tid, const char *file, - int line) +__rw_wlock_hard(volatile uintptr_t *c, uintptr_t v, uintptr_t tid, + const char *file, int line) { struct rwlock *rw; struct turnstile *ts; #ifdef ADAPTIVE_RWLOCKS volatile struct thread *owner; int spintries = 0; int i; #endif - uintptr_t v, x; + uintptr_t x; #ifdef LOCK_PROFILING uint64_t waittime = 0; int contested = 0; #endif #if defined(ADAPTIVE_RWLOCKS) || defined(KDTRACE_HOOKS) struct lock_delay_arg lda; #endif #ifdef KDTRACE_HOOKS uintptr_t state; u_int sleep_cnt = 0; int64_t sleep_time = 0; int64_t all_time = 0; #endif if (SCHEDULER_STOPPED()) return; #if defined(ADAPTIVE_RWLOCKS) lock_delay_arg_init(&lda, &rw_delay); #elif defined(KDTRACE_HOOKS) lock_delay_arg_init(&lda, NULL); #endif rw = rwlock2rw(c); - v = RW_READ_VALUE(rw); if (__predict_false(lv_rw_wowner(v) == (struct thread *)tid)) { KASSERT(rw->lock_object.lo_flags & LO_RECURSABLE, ("%s: recursing but non-recursive rw %s @ %s:%d\n", __func__, rw->lock_object.lo_name, file, line)); rw->rw_recurse++; if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p recursing", __func__, rw); return; } if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__, rw->lock_object.lo_name, (void *)rw->rw_lock, file, line); #ifdef KDTRACE_HOOKS all_time -= lockstat_nsecs(&rw->lock_object); state = v; #endif for (;;) { if (v == RW_UNLOCKED) { - if (_rw_write_lock(rw, tid)) + if (_rw_write_lock_fetch(rw, &v, tid)) break; - v = RW_READ_VALUE(rw); continue; } #ifdef KDTRACE_HOOKS lda.spin_cnt++; #endif #ifdef HWPMC_HOOKS PMC_SOFT_CALL( , , lock, failed); #endif lock_profile_obtain_lock_failed(&rw->lock_object, &contested, &waittime); #ifdef ADAPTIVE_RWLOCKS /* * If the lock is write locked and the owner is * running on another CPU, spin until the owner stops * running or the state of the lock changes. */ owner = lv_rw_wowner(v); if (!(v & RW_LOCK_READ) && TD_IS_RUNNING(owner)) { if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR3(KTR_LOCK, "%s: spinning on %p held by %p", __func__, rw, owner); KTR_STATE1(KTR_SCHED, "thread", sched_tdname(curthread), "spinning", "lockname:\"%s\"", rw->lock_object.lo_name); do { lock_delay(&lda); v = RW_READ_VALUE(rw); owner = lv_rw_wowner(v); } while (owner != NULL && TD_IS_RUNNING(owner)); KTR_STATE0(KTR_SCHED, "thread", sched_tdname(curthread), "running"); continue; } if ((v & RW_LOCK_READ) && RW_READERS(v) && spintries < rowner_retries) { if (!(v & RW_LOCK_WRITE_SPINNER)) { if (!atomic_cmpset_ptr(&rw->rw_lock, v, v | RW_LOCK_WRITE_SPINNER)) { v = RW_READ_VALUE(rw); continue; } } spintries++; KTR_STATE1(KTR_SCHED, "thread", sched_tdname(curthread), "spinning", "lockname:\"%s\"", rw->lock_object.lo_name); for (i = 0; i < rowner_loops; i++) { if ((rw->rw_lock & RW_LOCK_WRITE_SPINNER) == 0) break; cpu_spinwait(); } KTR_STATE0(KTR_SCHED, "thread", sched_tdname(curthread), "running"); v = RW_READ_VALUE(rw); #ifdef KDTRACE_HOOKS lda.spin_cnt += rowner_loops - i; #endif if (i != rowner_loops) continue; } #endif ts = turnstile_trywait(&rw->lock_object); v = RW_READ_VALUE(rw); #ifdef ADAPTIVE_RWLOCKS /* * The current lock owner might have started executing * on another CPU (or the lock could have changed * owners) while we were waiting on the turnstile * chain lock. If so, drop the turnstile lock and try * again. */ if (!(v & RW_LOCK_READ)) { owner = (struct thread *)RW_OWNER(v); if (TD_IS_RUNNING(owner)) { turnstile_cancel(ts); continue; } } #endif /* * Check for the waiters flags about this rwlock. * If the lock was released, without maintain any pending * waiters queue, simply try to acquire it. * If a pending waiters queue is present, claim the lock * ownership and maintain the pending queue. */ x = v & (RW_LOCK_WAITERS | RW_LOCK_WRITE_SPINNER); if ((v & ~x) == RW_UNLOCKED) { x &= ~RW_LOCK_WRITE_SPINNER; if (atomic_cmpset_acq_ptr(&rw->rw_lock, v, tid | x)) { if (x) turnstile_claim(ts); else turnstile_cancel(ts); break; } turnstile_cancel(ts); v = RW_READ_VALUE(rw); continue; } /* * If the RW_LOCK_WRITE_WAITERS flag isn't set, then try to * set it. If we fail to set it, then loop back and try * again. */ if (!(v & RW_LOCK_WRITE_WAITERS)) { if (!atomic_cmpset_ptr(&rw->rw_lock, v, v | RW_LOCK_WRITE_WAITERS)) { turnstile_cancel(ts); v = RW_READ_VALUE(rw); continue; } if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p set write waiters flag", __func__, rw); } /* * We were unable to acquire the lock and the write waiters * flag is set, so we must block on the turnstile. */ if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p blocking on turnstile", __func__, rw); #ifdef KDTRACE_HOOKS sleep_time -= lockstat_nsecs(&rw->lock_object); #endif turnstile_wait(ts, rw_owner(rw), TS_EXCLUSIVE_QUEUE); #ifdef KDTRACE_HOOKS sleep_time += lockstat_nsecs(&rw->lock_object); sleep_cnt++; #endif if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p resuming from turnstile", __func__, rw); #ifdef ADAPTIVE_RWLOCKS spintries = 0; #endif v = RW_READ_VALUE(rw); } #ifdef KDTRACE_HOOKS all_time += lockstat_nsecs(&rw->lock_object); if (sleep_time) LOCKSTAT_RECORD4(rw__block, rw, sleep_time, LOCKSTAT_WRITER, (state & RW_LOCK_READ) == 0, (state & RW_LOCK_READ) == 0 ? 0 : RW_READERS(state)); /* Record only the loops spinning and not sleeping. */ if (lda.spin_cnt > sleep_cnt) LOCKSTAT_RECORD4(rw__spin, rw, all_time - sleep_time, LOCKSTAT_WRITER, (state & RW_LOCK_READ) == 0, (state & RW_LOCK_READ) == 0 ? 0 : RW_READERS(state)); #endif LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(rw__acquire, rw, contested, waittime, file, line, LOCKSTAT_WRITER); } /* * This function is called if the first try at releasing a write lock failed. * This means that one of the 2 waiter bits must be set indicating that at * least one thread is waiting on this lock. */ void __rw_wunlock_hard(volatile uintptr_t *c, uintptr_t tid, const char *file, int line) { struct rwlock *rw; struct turnstile *ts; uintptr_t v; int queue; if (SCHEDULER_STOPPED()) return; rw = rwlock2rw(c); + MPASS(!rw_recursed(rw)); - if (rw_wlocked(rw) && rw_recursed(rw)) { - rw->rw_recurse--; - if (LOCK_LOG_TEST(&rw->lock_object, 0)) - CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, rw); + LOCKSTAT_PROFILE_RELEASE_RWLOCK(rw__release, rw, + LOCKSTAT_WRITER); + if (_rw_write_unlock(rw, tid)) return; - } KASSERT(rw->rw_lock & (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS), ("%s: neither of the waiter flags are set", __func__)); if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p contested", __func__, rw); turnstile_chain_lock(&rw->lock_object); ts = turnstile_lookup(&rw->lock_object); MPASS(ts != NULL); /* * Use the same algo as sx locks for now. Prefer waking up shared * waiters if we have any over writers. This is probably not ideal. * * 'v' is the value we are going to write back to rw_lock. If we * have waiters on both queues, we need to preserve the state of * the waiter flag for the queue we don't wake up. For now this is * hardcoded for the algorithm mentioned above. * * In the case of both readers and writers waiting we wakeup the * readers but leave the RW_LOCK_WRITE_WAITERS flag set. If a * new writer comes in before a reader it will claim the lock up * above. There is probably a potential priority inversion in * there that could be worked around either by waking both queues * of waiters or doing some complicated lock handoff gymnastics. */ v = RW_UNLOCKED; if (rw->rw_lock & RW_LOCK_WRITE_WAITERS) { queue = TS_EXCLUSIVE_QUEUE; v |= (rw->rw_lock & RW_LOCK_READ_WAITERS); } else queue = TS_SHARED_QUEUE; /* Wake up all waiters for the specific queue. */ if (LOCK_LOG_TEST(&rw->lock_object, 0)) CTR3(KTR_LOCK, "%s: %p waking up %s waiters", __func__, rw, queue == TS_SHARED_QUEUE ? "read" : "write"); turnstile_broadcast(ts, queue); atomic_store_rel_ptr(&rw->rw_lock, v); turnstile_unpend(ts, TS_EXCLUSIVE_LOCK); turnstile_chain_unlock(&rw->lock_object); } /* * Attempt to do a non-blocking upgrade from a read lock to a write * lock. This will only succeed if this thread holds a single read * lock. Returns true if the upgrade succeeded and false otherwise. */ int __rw_try_upgrade(volatile uintptr_t *c, const char *file, int line) { struct rwlock *rw; uintptr_t v, x, tid; struct turnstile *ts; int success; if (SCHEDULER_STOPPED()) return (1); rw = rwlock2rw(c); KASSERT(rw->rw_lock != RW_DESTROYED, ("rw_try_upgrade() of destroyed rwlock @ %s:%d", file, line)); __rw_assert(c, RA_RLOCKED, file, line); /* * Attempt to switch from one reader to a writer. If there * are any write waiters, then we will have to lock the * turnstile first to prevent races with another writer * calling turnstile_wait() before we have claimed this * turnstile. So, do the simple case of no waiters first. */ tid = (uintptr_t)curthread; success = 0; for (;;) { v = rw->rw_lock; if (RW_READERS(v) > 1) break; if (!(v & RW_LOCK_WAITERS)) { success = atomic_cmpset_ptr(&rw->rw_lock, v, tid); if (!success) continue; break; } /* * Ok, we think we have waiters, so lock the turnstile. */ ts = turnstile_trywait(&rw->lock_object); v = rw->rw_lock; if (RW_READERS(v) > 1) { turnstile_cancel(ts); break; } /* * Try to switch from one reader to a writer again. This time * we honor the current state of the waiters flags. * If we obtain the lock with the flags set, then claim * ownership of the turnstile. */ x = rw->rw_lock & RW_LOCK_WAITERS; success = atomic_cmpset_ptr(&rw->rw_lock, v, tid | x); if (success) { if (x) turnstile_claim(ts); else turnstile_cancel(ts); break; } turnstile_cancel(ts); } LOCK_LOG_TRY("WUPGRADE", &rw->lock_object, 0, success, file, line); if (success) { curthread->td_rw_rlocks--; WITNESS_UPGRADE(&rw->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK, file, line); LOCKSTAT_RECORD0(rw__upgrade, rw); } return (success); } /* * Downgrade a write lock into a single read lock. */ void __rw_downgrade(volatile uintptr_t *c, const char *file, int line) { struct rwlock *rw; struct turnstile *ts; uintptr_t tid, v; int rwait, wwait; if (SCHEDULER_STOPPED()) return; rw = rwlock2rw(c); KASSERT(rw->rw_lock != RW_DESTROYED, ("rw_downgrade() of destroyed rwlock @ %s:%d", file, line)); __rw_assert(c, RA_WLOCKED | RA_NOTRECURSED, file, line); #ifndef INVARIANTS if (rw_recursed(rw)) panic("downgrade of a recursed lock"); #endif WITNESS_DOWNGRADE(&rw->lock_object, 0, file, line); /* * Convert from a writer to a single reader. First we handle * the easy case with no waiters. If there are any waiters, we * lock the turnstile and "disown" the lock. */ tid = (uintptr_t)curthread; if (atomic_cmpset_rel_ptr(&rw->rw_lock, tid, RW_READERS_LOCK(1))) goto out; /* * Ok, we think we have waiters, so lock the turnstile so we can * read the waiter flags without any races. */ turnstile_chain_lock(&rw->lock_object); v = rw->rw_lock & RW_LOCK_WAITERS; rwait = v & RW_LOCK_READ_WAITERS; wwait = v & RW_LOCK_WRITE_WAITERS; MPASS(rwait | wwait); /* * Downgrade from a write lock while preserving waiters flag * and give up ownership of the turnstile. */ ts = turnstile_lookup(&rw->lock_object); MPASS(ts != NULL); if (!wwait) v &= ~RW_LOCK_READ_WAITERS; atomic_store_rel_ptr(&rw->rw_lock, RW_READERS_LOCK(1) | v); /* * Wake other readers if there are no writers pending. Otherwise they * won't be able to acquire the lock anyway. */ if (rwait && !wwait) { turnstile_broadcast(ts, TS_SHARED_QUEUE); turnstile_unpend(ts, TS_EXCLUSIVE_LOCK); } else turnstile_disown(ts); turnstile_chain_unlock(&rw->lock_object); out: curthread->td_rw_rlocks++; LOCK_LOG_LOCK("WDOWNGRADE", &rw->lock_object, 0, 0, file, line); LOCKSTAT_RECORD0(rw__downgrade, rw); } #ifdef INVARIANT_SUPPORT #ifndef INVARIANTS #undef __rw_assert #endif /* * In the non-WITNESS case, rw_assert() can only detect that at least * *some* thread owns an rlock, but it cannot guarantee that *this* * thread owns an rlock. */ void __rw_assert(const volatile uintptr_t *c, int what, const char *file, int line) { const struct rwlock *rw; if (panicstr != NULL) return; rw = rwlock2rw(c); switch (what) { case RA_LOCKED: case RA_LOCKED | RA_RECURSED: case RA_LOCKED | RA_NOTRECURSED: case RA_RLOCKED: case RA_RLOCKED | RA_RECURSED: case RA_RLOCKED | RA_NOTRECURSED: #ifdef WITNESS witness_assert(&rw->lock_object, what, file, line); #else /* * If some other thread has a write lock or we have one * and are asserting a read lock, fail. Also, if no one * has a lock at all, fail. */ if (rw->rw_lock == RW_UNLOCKED || (!(rw->rw_lock & RW_LOCK_READ) && (what & RA_RLOCKED || rw_wowner(rw) != curthread))) panic("Lock %s not %slocked @ %s:%d\n", rw->lock_object.lo_name, (what & RA_RLOCKED) ? "read " : "", file, line); if (!(rw->rw_lock & RW_LOCK_READ) && !(what & RA_RLOCKED)) { if (rw_recursed(rw)) { if (what & RA_NOTRECURSED) panic("Lock %s recursed @ %s:%d\n", rw->lock_object.lo_name, file, line); } else if (what & RA_RECURSED) panic("Lock %s not recursed @ %s:%d\n", rw->lock_object.lo_name, file, line); } #endif break; case RA_WLOCKED: case RA_WLOCKED | RA_RECURSED: case RA_WLOCKED | RA_NOTRECURSED: if (rw_wowner(rw) != curthread) panic("Lock %s not exclusively locked @ %s:%d\n", rw->lock_object.lo_name, file, line); if (rw_recursed(rw)) { if (what & RA_NOTRECURSED) panic("Lock %s recursed @ %s:%d\n", rw->lock_object.lo_name, file, line); } else if (what & RA_RECURSED) panic("Lock %s not recursed @ %s:%d\n", rw->lock_object.lo_name, file, line); break; case RA_UNLOCKED: #ifdef WITNESS witness_assert(&rw->lock_object, what, file, line); #else /* * If we hold a write lock fail. We can't reliably check * to see if we hold a read lock or not. */ if (rw_wowner(rw) == curthread) panic("Lock %s exclusively locked @ %s:%d\n", rw->lock_object.lo_name, file, line); #endif break; default: panic("Unknown rw lock assertion: %d @ %s:%d", what, file, line); } } #endif /* INVARIANT_SUPPORT */ #ifdef DDB void db_show_rwlock(const struct lock_object *lock) { const struct rwlock *rw; struct thread *td; rw = (const struct rwlock *)lock; db_printf(" state: "); if (rw->rw_lock == RW_UNLOCKED) db_printf("UNLOCKED\n"); else if (rw->rw_lock == RW_DESTROYED) { db_printf("DESTROYED\n"); return; } else if (rw->rw_lock & RW_LOCK_READ) db_printf("RLOCK: %ju locks\n", (uintmax_t)(RW_READERS(rw->rw_lock))); else { td = rw_wowner(rw); db_printf("WLOCK: %p (tid %d, pid %d, \"%s\")\n", td, td->td_tid, td->td_proc->p_pid, td->td_name); if (rw_recursed(rw)) db_printf(" recursed: %u\n", rw->rw_recurse); } db_printf(" waiters: "); switch (rw->rw_lock & (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS)) { case RW_LOCK_READ_WAITERS: db_printf("readers\n"); break; case RW_LOCK_WRITE_WAITERS: db_printf("writers\n"); break; case RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS: db_printf("readers and writers\n"); break; default: db_printf("none\n"); break; } } #endif Index: projects/ipsec/sys/kern/kern_sx.c =================================================================== --- projects/ipsec/sys/kern/kern_sx.c (revision 313312) +++ projects/ipsec/sys/kern/kern_sx.c (revision 313313) @@ -1,1316 +1,1288 @@ /*- * Copyright (c) 2007 Attilio Rao * Copyright (c) 2001 Jason Evans * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice(s), this list of conditions and the following disclaimer as * the first lines of this file unmodified other than the possible * addition of one or more copyright notices. * 2. Redistributions in binary form must reproduce the above copyright * notice(s), this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. */ /* * Shared/exclusive locks. This implementation attempts to ensure * deterministic lock granting behavior, so that slocks and xlocks are * interleaved. * * Priority propagation will not generally raise the priority of lock holders, * so should not be relied upon in combination with sx locks. */ #include "opt_ddb.h" #include "opt_hwpmc_hooks.h" #include "opt_no_adaptive_sx.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(SMP) && !defined(NO_ADAPTIVE_SX) #include #endif #ifdef DDB #include #endif #if defined(SMP) && !defined(NO_ADAPTIVE_SX) #define ADAPTIVE_SX #endif CTASSERT((SX_NOADAPTIVE & LO_CLASSFLAGS) == SX_NOADAPTIVE); #ifdef HWPMC_HOOKS #include PMC_SOFT_DECLARE( , , lock, failed); #endif /* Handy macros for sleep queues. */ #define SQ_EXCLUSIVE_QUEUE 0 #define SQ_SHARED_QUEUE 1 /* * Variations on DROP_GIANT()/PICKUP_GIANT() for use in this file. We * drop Giant anytime we have to sleep or if we adaptively spin. */ #define GIANT_DECLARE \ int _giantcnt = 0; \ WITNESS_SAVE_DECL(Giant) \ #define GIANT_SAVE() do { \ if (mtx_owned(&Giant)) { \ WITNESS_SAVE(&Giant.lock_object, Giant); \ while (mtx_owned(&Giant)) { \ _giantcnt++; \ mtx_unlock(&Giant); \ } \ } \ } while (0) #define GIANT_RESTORE() do { \ if (_giantcnt > 0) { \ mtx_assert(&Giant, MA_NOTOWNED); \ while (_giantcnt--) \ mtx_lock(&Giant); \ WITNESS_RESTORE(&Giant.lock_object, Giant); \ } \ } while (0) /* * Returns true if an exclusive lock is recursed. It assumes * curthread currently has an exclusive lock. */ #define sx_recursed(sx) ((sx)->sx_recurse != 0) static void assert_sx(const struct lock_object *lock, int what); #ifdef DDB static void db_show_sx(const struct lock_object *lock); #endif static void lock_sx(struct lock_object *lock, uintptr_t how); #ifdef KDTRACE_HOOKS static int owner_sx(const struct lock_object *lock, struct thread **owner); #endif static uintptr_t unlock_sx(struct lock_object *lock); struct lock_class lock_class_sx = { .lc_name = "sx", .lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE, .lc_assert = assert_sx, #ifdef DDB .lc_ddb_show = db_show_sx, #endif .lc_lock = lock_sx, .lc_unlock = unlock_sx, #ifdef KDTRACE_HOOKS .lc_owner = owner_sx, #endif }; #ifndef INVARIANTS #define _sx_assert(sx, what, file, line) #endif #ifdef ADAPTIVE_SX static u_int asx_retries = 10; static u_int asx_loops = 10000; static SYSCTL_NODE(_debug, OID_AUTO, sx, CTLFLAG_RD, NULL, "sxlock debugging"); SYSCTL_UINT(_debug_sx, OID_AUTO, retries, CTLFLAG_RW, &asx_retries, 0, ""); SYSCTL_UINT(_debug_sx, OID_AUTO, loops, CTLFLAG_RW, &asx_loops, 0, ""); static struct lock_delay_config __read_mostly sx_delay = { .initial = 1000, .step = 500, .min = 100, .max = 5000, }; SYSCTL_INT(_debug_sx, OID_AUTO, delay_initial, CTLFLAG_RW, &sx_delay.initial, 0, ""); SYSCTL_INT(_debug_sx, OID_AUTO, delay_step, CTLFLAG_RW, &sx_delay.step, 0, ""); SYSCTL_INT(_debug_sx, OID_AUTO, delay_min, CTLFLAG_RW, &sx_delay.min, 0, ""); SYSCTL_INT(_debug_sx, OID_AUTO, delay_max, CTLFLAG_RW, &sx_delay.max, 0, ""); static void sx_delay_sysinit(void *dummy) { sx_delay.initial = mp_ncpus * 25; sx_delay.step = (mp_ncpus * 25) / 2; sx_delay.min = mp_ncpus * 5; sx_delay.max = mp_ncpus * 25 * 10; } LOCK_DELAY_SYSINIT(sx_delay_sysinit); #endif void assert_sx(const struct lock_object *lock, int what) { sx_assert((const struct sx *)lock, what); } void lock_sx(struct lock_object *lock, uintptr_t how) { struct sx *sx; sx = (struct sx *)lock; if (how) sx_slock(sx); else sx_xlock(sx); } uintptr_t unlock_sx(struct lock_object *lock) { struct sx *sx; sx = (struct sx *)lock; sx_assert(sx, SA_LOCKED | SA_NOTRECURSED); if (sx_xlocked(sx)) { sx_xunlock(sx); return (0); } else { sx_sunlock(sx); return (1); } } #ifdef KDTRACE_HOOKS int owner_sx(const struct lock_object *lock, struct thread **owner) { const struct sx *sx; uintptr_t x; sx = (const struct sx *)lock; x = sx->sx_lock; *owner = NULL; return ((x & SX_LOCK_SHARED) != 0 ? (SX_SHARERS(x) != 0) : ((*owner = (struct thread *)SX_OWNER(x)) != NULL)); } #endif void sx_sysinit(void *arg) { struct sx_args *sargs = arg; sx_init_flags(sargs->sa_sx, sargs->sa_desc, sargs->sa_flags); } void sx_init_flags(struct sx *sx, const char *description, int opts) { int flags; MPASS((opts & ~(SX_QUIET | SX_RECURSE | SX_NOWITNESS | SX_DUPOK | SX_NOPROFILE | SX_NOADAPTIVE | SX_NEW)) == 0); ASSERT_ATOMIC_LOAD_PTR(sx->sx_lock, ("%s: sx_lock not aligned for %s: %p", __func__, description, &sx->sx_lock)); flags = LO_SLEEPABLE | LO_UPGRADABLE; if (opts & SX_DUPOK) flags |= LO_DUPOK; if (opts & SX_NOPROFILE) flags |= LO_NOPROFILE; if (!(opts & SX_NOWITNESS)) flags |= LO_WITNESS; if (opts & SX_RECURSE) flags |= LO_RECURSABLE; if (opts & SX_QUIET) flags |= LO_QUIET; if (opts & SX_NEW) flags |= LO_NEW; flags |= opts & SX_NOADAPTIVE; lock_init(&sx->lock_object, &lock_class_sx, description, NULL, flags); sx->sx_lock = SX_LOCK_UNLOCKED; sx->sx_recurse = 0; } void sx_destroy(struct sx *sx) { KASSERT(sx->sx_lock == SX_LOCK_UNLOCKED, ("sx lock still held")); KASSERT(sx->sx_recurse == 0, ("sx lock still recursed")); sx->sx_lock = SX_LOCK_DESTROYED; lock_destroy(&sx->lock_object); } int -_sx_slock(struct sx *sx, int opts, const char *file, int line) -{ - int error = 0; - - if (SCHEDULER_STOPPED()) - return (0); - KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), - ("sx_slock() by idle thread %p on sx %s @ %s:%d", - curthread, sx->lock_object.lo_name, file, line)); - KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, - ("sx_slock() of destroyed sx @ %s:%d", file, line)); - WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER, file, line, NULL); - error = __sx_slock(sx, opts, file, line); - if (!error) { - LOCK_LOG_LOCK("SLOCK", &sx->lock_object, 0, 0, file, line); - WITNESS_LOCK(&sx->lock_object, 0, file, line); - TD_LOCKS_INC(curthread); - } - - return (error); -} - -int sx_try_slock_(struct sx *sx, const char *file, int line) { uintptr_t x; if (SCHEDULER_STOPPED()) return (1); KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("sx_try_slock() by idle thread %p on sx %s @ %s:%d", curthread, sx->lock_object.lo_name, file, line)); for (;;) { x = sx->sx_lock; KASSERT(x != SX_LOCK_DESTROYED, ("sx_try_slock() of destroyed sx @ %s:%d", file, line)); if (!(x & SX_LOCK_SHARED)) break; if (atomic_cmpset_acq_ptr(&sx->sx_lock, x, x + SX_ONE_SHARER)) { LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 1, file, line); WITNESS_LOCK(&sx->lock_object, LOP_TRYLOCK, file, line); LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(sx__acquire, sx, 0, 0, file, line, LOCKSTAT_READER); TD_LOCKS_INC(curthread); return (1); } } LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 0, file, line); return (0); } int _sx_xlock(struct sx *sx, int opts, const char *file, int line) { + uintptr_t tid, x; int error = 0; if (SCHEDULER_STOPPED()) return (0); KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("sx_xlock() by idle thread %p on sx %s @ %s:%d", curthread, sx->lock_object.lo_name, file, line)); KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, ("sx_xlock() of destroyed sx @ %s:%d", file, line)); WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL); - error = __sx_xlock(sx, curthread, opts, file, line); + tid = (uintptr_t)curthread; + x = SX_LOCK_UNLOCKED; + if (!atomic_fcmpset_acq_ptr(&sx->sx_lock, &x, tid)) + error = _sx_xlock_hard(sx, x, tid, opts, file, line); + else + LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(sx__acquire, sx, + 0, 0, file, line, LOCKSTAT_WRITER); if (!error) { LOCK_LOG_LOCK("XLOCK", &sx->lock_object, 0, sx->sx_recurse, file, line); WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line); TD_LOCKS_INC(curthread); } return (error); } int sx_try_xlock_(struct sx *sx, const char *file, int line) { int rval; if (SCHEDULER_STOPPED()) return (1); KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), ("sx_try_xlock() by idle thread %p on sx %s @ %s:%d", curthread, sx->lock_object.lo_name, file, line)); KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, ("sx_try_xlock() of destroyed sx @ %s:%d", file, line)); if (sx_xlocked(sx) && (sx->lock_object.lo_flags & LO_RECURSABLE) != 0) { sx->sx_recurse++; atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED); rval = 1; } else rval = atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, (uintptr_t)curthread); LOCK_LOG_TRY("XLOCK", &sx->lock_object, 0, rval, file, line); if (rval) { WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK, file, line); if (!sx_recursed(sx)) LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(sx__acquire, sx, 0, 0, file, line, LOCKSTAT_WRITER); TD_LOCKS_INC(curthread); } return (rval); } void -_sx_sunlock(struct sx *sx, const char *file, int line) -{ - - if (SCHEDULER_STOPPED()) - return; - KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, - ("sx_sunlock() of destroyed sx @ %s:%d", file, line)); - _sx_assert(sx, SA_SLOCKED, file, line); - WITNESS_UNLOCK(&sx->lock_object, 0, file, line); - LOCK_LOG_LOCK("SUNLOCK", &sx->lock_object, 0, 0, file, line); - __sx_sunlock(sx, file, line); - TD_LOCKS_DEC(curthread); -} - -void _sx_xunlock(struct sx *sx, const char *file, int line) { if (SCHEDULER_STOPPED()) return; KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, ("sx_xunlock() of destroyed sx @ %s:%d", file, line)); _sx_assert(sx, SA_XLOCKED, file, line); WITNESS_UNLOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line); LOCK_LOG_LOCK("XUNLOCK", &sx->lock_object, 0, sx->sx_recurse, file, line); - __sx_xunlock(sx, curthread, file, line); + _sx_xunlock_hard(sx, (uintptr_t)curthread, file, line); TD_LOCKS_DEC(curthread); } /* * Try to do a non-blocking upgrade from a shared lock to an exclusive lock. * This will only succeed if this thread holds a single shared lock. * Return 1 if if the upgrade succeed, 0 otherwise. */ int sx_try_upgrade_(struct sx *sx, const char *file, int line) { uintptr_t x; int success; if (SCHEDULER_STOPPED()) return (1); KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, ("sx_try_upgrade() of destroyed sx @ %s:%d", file, line)); _sx_assert(sx, SA_SLOCKED, file, line); /* * Try to switch from one shared lock to an exclusive lock. We need * to maintain the SX_LOCK_EXCLUSIVE_WAITERS flag if set so that * we will wake up the exclusive waiters when we drop the lock. */ x = sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS; success = atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | x, (uintptr_t)curthread | x); LOCK_LOG_TRY("XUPGRADE", &sx->lock_object, 0, success, file, line); if (success) { WITNESS_UPGRADE(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK, file, line); LOCKSTAT_RECORD0(sx__upgrade, sx); } return (success); } /* * Downgrade an unrecursed exclusive lock into a single shared lock. */ void sx_downgrade_(struct sx *sx, const char *file, int line) { uintptr_t x; int wakeup_swapper; if (SCHEDULER_STOPPED()) return; KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, ("sx_downgrade() of destroyed sx @ %s:%d", file, line)); _sx_assert(sx, SA_XLOCKED | SA_NOTRECURSED, file, line); #ifndef INVARIANTS if (sx_recursed(sx)) panic("downgrade of a recursed lock"); #endif WITNESS_DOWNGRADE(&sx->lock_object, 0, file, line); /* * Try to switch from an exclusive lock with no shared waiters * to one sharer with no shared waiters. If there are * exclusive waiters, we don't need to lock the sleep queue so * long as we preserve the flag. We do one quick try and if * that fails we grab the sleepq lock to keep the flags from * changing and do it the slow way. * * We have to lock the sleep queue if there are shared waiters * so we can wake them up. */ x = sx->sx_lock; if (!(x & SX_LOCK_SHARED_WAITERS) && atomic_cmpset_rel_ptr(&sx->sx_lock, x, SX_SHARERS_LOCK(1) | (x & SX_LOCK_EXCLUSIVE_WAITERS))) { LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line); return; } /* * Lock the sleep queue so we can read the waiters bits * without any races and wakeup any shared waiters. */ sleepq_lock(&sx->lock_object); /* * Preserve SX_LOCK_EXCLUSIVE_WAITERS while downgraded to a single * shared lock. If there are any shared waiters, wake them up. */ wakeup_swapper = 0; x = sx->sx_lock; atomic_store_rel_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | (x & SX_LOCK_EXCLUSIVE_WAITERS)); if (x & SX_LOCK_SHARED_WAITERS) wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, 0, SQ_SHARED_QUEUE); sleepq_release(&sx->lock_object); LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line); LOCKSTAT_RECORD0(sx__downgrade, sx); if (wakeup_swapper) kick_proc0(); } /* * This function represents the so-called 'hard case' for sx_xlock * operation. All 'easy case' failures are redirected to this. Note * that ideally this would be a static function, but it needs to be * accessible from at least sx.h. */ int -_sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file, - int line) +_sx_xlock_hard(struct sx *sx, uintptr_t x, uintptr_t tid, int opts, + const char *file, int line) { GIANT_DECLARE; #ifdef ADAPTIVE_SX volatile struct thread *owner; u_int i, spintries = 0; #endif - uintptr_t x; #ifdef LOCK_PROFILING uint64_t waittime = 0; int contested = 0; #endif int error = 0; #if defined(ADAPTIVE_SX) || defined(KDTRACE_HOOKS) struct lock_delay_arg lda; #endif #ifdef KDTRACE_HOOKS uintptr_t state; u_int sleep_cnt = 0; int64_t sleep_time = 0; int64_t all_time = 0; #endif if (SCHEDULER_STOPPED()) return (0); #if defined(ADAPTIVE_SX) lock_delay_arg_init(&lda, &sx_delay); #elif defined(KDTRACE_HOOKS) lock_delay_arg_init(&lda, NULL); #endif - x = SX_READ_VALUE(sx); - /* If we already hold an exclusive lock, then recurse. */ if (__predict_false(lv_sx_owner(x) == (struct thread *)tid)) { KASSERT((sx->lock_object.lo_flags & LO_RECURSABLE) != 0, ("_sx_xlock_hard: recursed on non-recursive sx %s @ %s:%d\n", sx->lock_object.lo_name, file, line)); sx->sx_recurse++; atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED); if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p recursing", __func__, sx); return (0); } if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__, sx->lock_object.lo_name, (void *)sx->sx_lock, file, line); #ifdef KDTRACE_HOOKS all_time -= lockstat_nsecs(&sx->lock_object); state = x; #endif for (;;) { if (x == SX_LOCK_UNLOCKED) { - if (atomic_cmpset_acq_ptr(&sx->sx_lock, x, tid)) + if (atomic_fcmpset_acq_ptr(&sx->sx_lock, &x, tid)) break; - x = SX_READ_VALUE(sx); continue; } #ifdef KDTRACE_HOOKS lda.spin_cnt++; #endif #ifdef HWPMC_HOOKS PMC_SOFT_CALL( , , lock, failed); #endif lock_profile_obtain_lock_failed(&sx->lock_object, &contested, &waittime); #ifdef ADAPTIVE_SX /* * If the lock is write locked and the owner is * running on another CPU, spin until the owner stops * running or the state of the lock changes. */ if ((sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) { if ((x & SX_LOCK_SHARED) == 0) { owner = lv_sx_owner(x); if (TD_IS_RUNNING(owner)) { if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR3(KTR_LOCK, "%s: spinning on %p held by %p", __func__, sx, owner); KTR_STATE1(KTR_SCHED, "thread", sched_tdname(curthread), "spinning", "lockname:\"%s\"", sx->lock_object.lo_name); GIANT_SAVE(); do { lock_delay(&lda); x = SX_READ_VALUE(sx); owner = lv_sx_owner(x); } while (owner != NULL && TD_IS_RUNNING(owner)); KTR_STATE0(KTR_SCHED, "thread", sched_tdname(curthread), "running"); continue; } } else if (SX_SHARERS(x) && spintries < asx_retries) { KTR_STATE1(KTR_SCHED, "thread", sched_tdname(curthread), "spinning", "lockname:\"%s\"", sx->lock_object.lo_name); GIANT_SAVE(); spintries++; for (i = 0; i < asx_loops; i++) { if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR4(KTR_LOCK, "%s: shared spinning on %p with %u and %u", __func__, sx, spintries, i); x = sx->sx_lock; if ((x & SX_LOCK_SHARED) == 0 || SX_SHARERS(x) == 0) break; cpu_spinwait(); #ifdef KDTRACE_HOOKS lda.spin_cnt++; #endif } KTR_STATE0(KTR_SCHED, "thread", sched_tdname(curthread), "running"); x = SX_READ_VALUE(sx); if (i != asx_loops) continue; } } #endif sleepq_lock(&sx->lock_object); x = SX_READ_VALUE(sx); /* * If the lock was released while spinning on the * sleep queue chain lock, try again. */ if (x == SX_LOCK_UNLOCKED) { sleepq_release(&sx->lock_object); continue; } #ifdef ADAPTIVE_SX /* * The current lock owner might have started executing * on another CPU (or the lock could have changed * owners) while we were waiting on the sleep queue * chain lock. If so, drop the sleep queue lock and try * again. */ if (!(x & SX_LOCK_SHARED) && (sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) { owner = (struct thread *)SX_OWNER(x); if (TD_IS_RUNNING(owner)) { sleepq_release(&sx->lock_object); continue; } } #endif /* * If an exclusive lock was released with both shared * and exclusive waiters and a shared waiter hasn't * woken up and acquired the lock yet, sx_lock will be * set to SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS. * If we see that value, try to acquire it once. Note * that we have to preserve SX_LOCK_EXCLUSIVE_WAITERS * as there are other exclusive waiters still. If we * fail, restart the loop. */ if (x == (SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS)) { if (atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS, tid | SX_LOCK_EXCLUSIVE_WAITERS)) { sleepq_release(&sx->lock_object); CTR2(KTR_LOCK, "%s: %p claimed by new writer", __func__, sx); break; } sleepq_release(&sx->lock_object); x = SX_READ_VALUE(sx); continue; } /* * Try to set the SX_LOCK_EXCLUSIVE_WAITERS. If we fail, * than loop back and retry. */ if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) { if (!atomic_cmpset_ptr(&sx->sx_lock, x, x | SX_LOCK_EXCLUSIVE_WAITERS)) { sleepq_release(&sx->lock_object); x = SX_READ_VALUE(sx); continue; } if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p set excl waiters flag", __func__, sx); } /* * Since we have been unable to acquire the exclusive * lock and the exclusive waiters flag is set, we have * to sleep. */ if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p blocking on sleep queue", __func__, sx); #ifdef KDTRACE_HOOKS sleep_time -= lockstat_nsecs(&sx->lock_object); #endif GIANT_SAVE(); sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name, SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ? SLEEPQ_INTERRUPTIBLE : 0), SQ_EXCLUSIVE_QUEUE); if (!(opts & SX_INTERRUPTIBLE)) sleepq_wait(&sx->lock_object, 0); else error = sleepq_wait_sig(&sx->lock_object, 0); #ifdef KDTRACE_HOOKS sleep_time += lockstat_nsecs(&sx->lock_object); sleep_cnt++; #endif if (error) { if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: interruptible sleep by %p suspended by signal", __func__, sx); break; } if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p resuming from sleep queue", __func__, sx); x = SX_READ_VALUE(sx); } #ifdef KDTRACE_HOOKS all_time += lockstat_nsecs(&sx->lock_object); if (sleep_time) LOCKSTAT_RECORD4(sx__block, sx, sleep_time, LOCKSTAT_WRITER, (state & SX_LOCK_SHARED) == 0, (state & SX_LOCK_SHARED) == 0 ? 0 : SX_SHARERS(state)); if (lda.spin_cnt > sleep_cnt) LOCKSTAT_RECORD4(sx__spin, sx, all_time - sleep_time, LOCKSTAT_WRITER, (state & SX_LOCK_SHARED) == 0, (state & SX_LOCK_SHARED) == 0 ? 0 : SX_SHARERS(state)); #endif if (!error) LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(sx__acquire, sx, contested, waittime, file, line, LOCKSTAT_WRITER); GIANT_RESTORE(); return (error); } /* * This function represents the so-called 'hard case' for sx_xunlock * operation. All 'easy case' failures are redirected to this. Note * that ideally this would be a static function, but it needs to be * accessible from at least sx.h. */ void _sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line) { uintptr_t x; int queue, wakeup_swapper; if (SCHEDULER_STOPPED()) return; MPASS(!(sx->sx_lock & SX_LOCK_SHARED)); - /* If the lock is recursed, then unrecurse one level. */ - if (sx_xlocked(sx) && sx_recursed(sx)) { + if (!sx_recursed(sx)) { + LOCKSTAT_PROFILE_RELEASE_RWLOCK(sx__release, sx, + LOCKSTAT_WRITER); + if (atomic_cmpset_rel_ptr(&sx->sx_lock, tid, SX_LOCK_UNLOCKED)) + return; + } else { + /* The lock is recursed, unrecurse one level. */ if ((--sx->sx_recurse) == 0) atomic_clear_ptr(&sx->sx_lock, SX_LOCK_RECURSED); if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, sx); return; } MPASS(sx->sx_lock & (SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS)); if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p contested", __func__, sx); sleepq_lock(&sx->lock_object); x = SX_LOCK_UNLOCKED; /* * The wake up algorithm here is quite simple and probably not * ideal. It gives precedence to shared waiters if they are * present. For this condition, we have to preserve the * state of the exclusive waiters flag. * If interruptible sleeps left the shared queue empty avoid a * starvation for the threads sleeping on the exclusive queue by giving * them precedence and cleaning up the shared waiters bit anyway. */ if ((sx->sx_lock & SX_LOCK_SHARED_WAITERS) != 0 && sleepq_sleepcnt(&sx->lock_object, SQ_SHARED_QUEUE) != 0) { queue = SQ_SHARED_QUEUE; x |= (sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS); } else queue = SQ_EXCLUSIVE_QUEUE; /* Wake up all the waiters for the specific queue. */ if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR3(KTR_LOCK, "%s: %p waking up all threads on %s queue", __func__, sx, queue == SQ_SHARED_QUEUE ? "shared" : "exclusive"); atomic_store_rel_ptr(&sx->sx_lock, x); wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, 0, queue); sleepq_release(&sx->lock_object); if (wakeup_swapper) kick_proc0(); } -/* - * This function represents the so-called 'hard case' for sx_slock - * operation. All 'easy case' failures are redirected to this. Note - * that ideally this would be a static function, but it needs to be - * accessible from at least sx.h. - */ int -_sx_slock_hard(struct sx *sx, int opts, const char *file, int line) +_sx_slock(struct sx *sx, int opts, const char *file, int line) { GIANT_DECLARE; #ifdef ADAPTIVE_SX volatile struct thread *owner; #endif #ifdef LOCK_PROFILING uint64_t waittime = 0; int contested = 0; #endif uintptr_t x; int error = 0; #if defined(ADAPTIVE_SX) || defined(KDTRACE_HOOKS) struct lock_delay_arg lda; #endif #ifdef KDTRACE_HOOKS uintptr_t state; u_int sleep_cnt = 0; int64_t sleep_time = 0; int64_t all_time = 0; #endif if (SCHEDULER_STOPPED()) return (0); #if defined(ADAPTIVE_SX) lock_delay_arg_init(&lda, &sx_delay); #elif defined(KDTRACE_HOOKS) lock_delay_arg_init(&lda, NULL); #endif + KASSERT(kdb_active != 0 || !TD_IS_IDLETHREAD(curthread), + ("sx_slock() by idle thread %p on sx %s @ %s:%d", + curthread, sx->lock_object.lo_name, file, line)); + KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, + ("sx_slock() of destroyed sx @ %s:%d", file, line)); + WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER, file, line, NULL); #ifdef KDTRACE_HOOKS all_time -= lockstat_nsecs(&sx->lock_object); #endif x = SX_READ_VALUE(sx); #ifdef KDTRACE_HOOKS state = x; #endif /* * As with rwlocks, we don't make any attempt to try to block * shared locks once there is an exclusive waiter. */ for (;;) { /* * If no other thread has an exclusive lock then try to bump up * the count of sharers. Since we have to preserve the state * of SX_LOCK_EXCLUSIVE_WAITERS, if we fail to acquire the * shared lock loop back and retry. */ if (x & SX_LOCK_SHARED) { MPASS(!(x & SX_LOCK_SHARED_WAITERS)); - if (atomic_cmpset_acq_ptr(&sx->sx_lock, x, + if (atomic_fcmpset_acq_ptr(&sx->sx_lock, &x, x + SX_ONE_SHARER)) { if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR4(KTR_LOCK, "%s: %p succeed %p -> %p", __func__, sx, (void *)x, (void *)(x + SX_ONE_SHARER)); break; } - x = SX_READ_VALUE(sx); continue; } #ifdef KDTRACE_HOOKS lda.spin_cnt++; #endif #ifdef HWPMC_HOOKS PMC_SOFT_CALL( , , lock, failed); #endif lock_profile_obtain_lock_failed(&sx->lock_object, &contested, &waittime); #ifdef ADAPTIVE_SX /* * If the owner is running on another CPU, spin until * the owner stops running or the state of the lock * changes. */ if ((sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) { owner = lv_sx_owner(x); if (TD_IS_RUNNING(owner)) { if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR3(KTR_LOCK, "%s: spinning on %p held by %p", __func__, sx, owner); KTR_STATE1(KTR_SCHED, "thread", sched_tdname(curthread), "spinning", "lockname:\"%s\"", sx->lock_object.lo_name); GIANT_SAVE(); do { lock_delay(&lda); x = SX_READ_VALUE(sx); owner = lv_sx_owner(x); } while (owner != NULL && TD_IS_RUNNING(owner)); KTR_STATE0(KTR_SCHED, "thread", sched_tdname(curthread), "running"); continue; } } #endif /* * Some other thread already has an exclusive lock, so * start the process of blocking. */ sleepq_lock(&sx->lock_object); x = SX_READ_VALUE(sx); /* * The lock could have been released while we spun. * In this case loop back and retry. */ if (x & SX_LOCK_SHARED) { sleepq_release(&sx->lock_object); continue; } #ifdef ADAPTIVE_SX /* * If the owner is running on another CPU, spin until * the owner stops running or the state of the lock * changes. */ if (!(x & SX_LOCK_SHARED) && (sx->lock_object.lo_flags & SX_NOADAPTIVE) == 0) { owner = (struct thread *)SX_OWNER(x); if (TD_IS_RUNNING(owner)) { sleepq_release(&sx->lock_object); x = SX_READ_VALUE(sx); continue; } } #endif /* * Try to set the SX_LOCK_SHARED_WAITERS flag. If we * fail to set it drop the sleep queue lock and loop * back. */ if (!(x & SX_LOCK_SHARED_WAITERS)) { if (!atomic_cmpset_ptr(&sx->sx_lock, x, x | SX_LOCK_SHARED_WAITERS)) { sleepq_release(&sx->lock_object); x = SX_READ_VALUE(sx); continue; } if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p set shared waiters flag", __func__, sx); } /* * Since we have been unable to acquire the shared lock, * we have to sleep. */ if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p blocking on sleep queue", __func__, sx); #ifdef KDTRACE_HOOKS sleep_time -= lockstat_nsecs(&sx->lock_object); #endif GIANT_SAVE(); sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name, SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ? SLEEPQ_INTERRUPTIBLE : 0), SQ_SHARED_QUEUE); if (!(opts & SX_INTERRUPTIBLE)) sleepq_wait(&sx->lock_object, 0); else error = sleepq_wait_sig(&sx->lock_object, 0); #ifdef KDTRACE_HOOKS sleep_time += lockstat_nsecs(&sx->lock_object); sleep_cnt++; #endif if (error) { if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: interruptible sleep by %p suspended by signal", __func__, sx); break; } if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p resuming from sleep queue", __func__, sx); x = SX_READ_VALUE(sx); } #ifdef KDTRACE_HOOKS all_time += lockstat_nsecs(&sx->lock_object); if (sleep_time) LOCKSTAT_RECORD4(sx__block, sx, sleep_time, LOCKSTAT_READER, (state & SX_LOCK_SHARED) == 0, (state & SX_LOCK_SHARED) == 0 ? 0 : SX_SHARERS(state)); if (lda.spin_cnt > sleep_cnt) LOCKSTAT_RECORD4(sx__spin, sx, all_time - sleep_time, LOCKSTAT_READER, (state & SX_LOCK_SHARED) == 0, (state & SX_LOCK_SHARED) == 0 ? 0 : SX_SHARERS(state)); #endif - if (error == 0) + if (error == 0) { LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(sx__acquire, sx, contested, waittime, file, line, LOCKSTAT_READER); + LOCK_LOG_LOCK("SLOCK", &sx->lock_object, 0, 0, file, line); + WITNESS_LOCK(&sx->lock_object, 0, file, line); + TD_LOCKS_INC(curthread); + } GIANT_RESTORE(); return (error); } -/* - * This function represents the so-called 'hard case' for sx_sunlock - * operation. All 'easy case' failures are redirected to this. Note - * that ideally this would be a static function, but it needs to be - * accessible from at least sx.h. - */ void -_sx_sunlock_hard(struct sx *sx, const char *file, int line) +_sx_sunlock(struct sx *sx, const char *file, int line) { uintptr_t x; int wakeup_swapper; if (SCHEDULER_STOPPED()) return; + KASSERT(sx->sx_lock != SX_LOCK_DESTROYED, + ("sx_sunlock() of destroyed sx @ %s:%d", file, line)); + _sx_assert(sx, SA_SLOCKED, file, line); + WITNESS_UNLOCK(&sx->lock_object, 0, file, line); + LOCK_LOG_LOCK("SUNLOCK", &sx->lock_object, 0, 0, file, line); + LOCKSTAT_PROFILE_RELEASE_RWLOCK(sx__release, sx, LOCKSTAT_READER); x = SX_READ_VALUE(sx); for (;;) { /* * We should never have sharers while at least one thread * holds a shared lock. */ KASSERT(!(x & SX_LOCK_SHARED_WAITERS), ("%s: waiting sharers", __func__)); /* * See if there is more than one shared lock held. If * so, just drop one and return. */ if (SX_SHARERS(x) > 1) { - if (atomic_cmpset_rel_ptr(&sx->sx_lock, x, + if (atomic_fcmpset_rel_ptr(&sx->sx_lock, &x, x - SX_ONE_SHARER)) { if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR4(KTR_LOCK, "%s: %p succeeded %p -> %p", __func__, sx, (void *)x, (void *)(x - SX_ONE_SHARER)); break; } - - x = SX_READ_VALUE(sx); continue; } /* * If there aren't any waiters for an exclusive lock, * then try to drop it quickly. */ if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) { MPASS(x == SX_SHARERS_LOCK(1)); - if (atomic_cmpset_rel_ptr(&sx->sx_lock, - SX_SHARERS_LOCK(1), SX_LOCK_UNLOCKED)) { + x = SX_SHARERS_LOCK(1); + if (atomic_fcmpset_rel_ptr(&sx->sx_lock, + &x, SX_LOCK_UNLOCKED)) { if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p last succeeded", __func__, sx); break; } - x = SX_READ_VALUE(sx); continue; } /* * At this point, there should just be one sharer with * exclusive waiters. */ MPASS(x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS)); sleepq_lock(&sx->lock_object); /* * Wake up semantic here is quite simple: * Just wake up all the exclusive waiters. * Note that the state of the lock could have changed, * so if it fails loop back and retry. */ if (!atomic_cmpset_rel_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS, SX_LOCK_UNLOCKED)) { sleepq_release(&sx->lock_object); x = SX_READ_VALUE(sx); continue; } if (LOCK_LOG_TEST(&sx->lock_object, 0)) CTR2(KTR_LOCK, "%s: %p waking up all thread on" "exclusive queue", __func__, sx); wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, 0, SQ_EXCLUSIVE_QUEUE); sleepq_release(&sx->lock_object); if (wakeup_swapper) kick_proc0(); break; } + TD_LOCKS_DEC(curthread); } #ifdef INVARIANT_SUPPORT #ifndef INVARIANTS #undef _sx_assert #endif /* * In the non-WITNESS case, sx_assert() can only detect that at least * *some* thread owns an slock, but it cannot guarantee that *this* * thread owns an slock. */ void _sx_assert(const struct sx *sx, int what, const char *file, int line) { #ifndef WITNESS int slocked = 0; #endif if (panicstr != NULL) return; switch (what) { case SA_SLOCKED: case SA_SLOCKED | SA_NOTRECURSED: case SA_SLOCKED | SA_RECURSED: #ifndef WITNESS slocked = 1; /* FALLTHROUGH */ #endif case SA_LOCKED: case SA_LOCKED | SA_NOTRECURSED: case SA_LOCKED | SA_RECURSED: #ifdef WITNESS witness_assert(&sx->lock_object, what, file, line); #else /* * If some other thread has an exclusive lock or we * have one and are asserting a shared lock, fail. * Also, if no one has a lock at all, fail. */ if (sx->sx_lock == SX_LOCK_UNLOCKED || (!(sx->sx_lock & SX_LOCK_SHARED) && (slocked || sx_xholder(sx) != curthread))) panic("Lock %s not %slocked @ %s:%d\n", sx->lock_object.lo_name, slocked ? "share " : "", file, line); if (!(sx->sx_lock & SX_LOCK_SHARED)) { if (sx_recursed(sx)) { if (what & SA_NOTRECURSED) panic("Lock %s recursed @ %s:%d\n", sx->lock_object.lo_name, file, line); } else if (what & SA_RECURSED) panic("Lock %s not recursed @ %s:%d\n", sx->lock_object.lo_name, file, line); } #endif break; case SA_XLOCKED: case SA_XLOCKED | SA_NOTRECURSED: case SA_XLOCKED | SA_RECURSED: if (sx_xholder(sx) != curthread) panic("Lock %s not exclusively locked @ %s:%d\n", sx->lock_object.lo_name, file, line); if (sx_recursed(sx)) { if (what & SA_NOTRECURSED) panic("Lock %s recursed @ %s:%d\n", sx->lock_object.lo_name, file, line); } else if (what & SA_RECURSED) panic("Lock %s not recursed @ %s:%d\n", sx->lock_object.lo_name, file, line); break; case SA_UNLOCKED: #ifdef WITNESS witness_assert(&sx->lock_object, what, file, line); #else /* * If we hold an exclusve lock fail. We can't * reliably check to see if we hold a shared lock or * not. */ if (sx_xholder(sx) == curthread) panic("Lock %s exclusively locked @ %s:%d\n", sx->lock_object.lo_name, file, line); #endif break; default: panic("Unknown sx lock assertion: %d @ %s:%d", what, file, line); } } #endif /* INVARIANT_SUPPORT */ #ifdef DDB static void db_show_sx(const struct lock_object *lock) { struct thread *td; const struct sx *sx; sx = (const struct sx *)lock; db_printf(" state: "); if (sx->sx_lock == SX_LOCK_UNLOCKED) db_printf("UNLOCKED\n"); else if (sx->sx_lock == SX_LOCK_DESTROYED) { db_printf("DESTROYED\n"); return; } else if (sx->sx_lock & SX_LOCK_SHARED) db_printf("SLOCK: %ju\n", (uintmax_t)SX_SHARERS(sx->sx_lock)); else { td = sx_xholder(sx); db_printf("XLOCK: %p (tid %d, pid %d, \"%s\")\n", td, td->td_tid, td->td_proc->p_pid, td->td_name); if (sx_recursed(sx)) db_printf(" recursed: %d\n", sx->sx_recurse); } db_printf(" waiters: "); switch(sx->sx_lock & (SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS)) { case SX_LOCK_SHARED_WAITERS: db_printf("shared\n"); break; case SX_LOCK_EXCLUSIVE_WAITERS: db_printf("exclusive\n"); break; case SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS: db_printf("exclusive and shared\n"); break; default: db_printf("none\n"); } } /* * Check to see if a thread that is blocked on a sleep queue is actually * blocked on an sx lock. If so, output some details and return true. * If the lock has an exclusive owner, return that in *ownerp. */ int sx_chain(struct thread *td, struct thread **ownerp) { struct sx *sx; /* * Check to see if this thread is blocked on an sx lock. * First, we check the lock class. If that is ok, then we * compare the lock name against the wait message. */ sx = td->td_wchan; if (LOCK_CLASS(&sx->lock_object) != &lock_class_sx || sx->lock_object.lo_name != td->td_wmesg) return (0); /* We think we have an sx lock, so output some details. */ db_printf("blocked on sx \"%s\" ", td->td_wmesg); *ownerp = sx_xholder(sx); if (sx->sx_lock & SX_LOCK_SHARED) db_printf("SLOCK (count %ju)\n", (uintmax_t)SX_SHARERS(sx->sx_lock)); else db_printf("XLOCK\n"); return (1); } #endif Index: projects/ipsec/sys/kern/subr_witness.c =================================================================== --- projects/ipsec/sys/kern/subr_witness.c (revision 313312) +++ projects/ipsec/sys/kern/subr_witness.c (revision 313313) @@ -1,3025 +1,3024 @@ /*- * Copyright (c) 2008 Isilon Systems, Inc. * Copyright (c) 2008 Ilya Maykov * Copyright (c) 1998 Berkeley Software Design, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Berkeley Software Design Inc's name may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``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 BERKELEY SOFTWARE DESIGN INC BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from BSDI $Id: mutex_witness.c,v 1.1.2.20 2000/04/27 03:10:27 cp Exp $ * and BSDI $Id: synch_machdep.c,v 2.3.2.39 2000/04/27 03:10:25 cp Exp $ */ /* * Implementation of the `witness' lock verifier. Originally implemented for * mutexes in BSD/OS. Extended to handle generic lock objects and lock * classes in FreeBSD. */ /* * Main Entry: witness * Pronunciation: 'wit-n&s * Function: noun * Etymology: Middle English witnesse, from Old English witnes knowledge, * testimony, witness, from 2wit * Date: before 12th century * 1 : attestation of a fact or event : TESTIMONY * 2 : one that gives evidence; specifically : one who testifies in * a cause or before a judicial tribunal * 3 : one asked to be present at a transaction so as to be able to * testify to its having taken place * 4 : one who has personal knowledge of something * 5 a : something serving as evidence or proof : SIGN * b : public affirmation by word or example of usually * religious faith or conviction * 6 capitalized : a member of the Jehovah's Witnesses */ /* * Special rules concerning Giant and lock orders: * * 1) Giant must be acquired before any other mutexes. Stated another way, * no other mutex may be held when Giant is acquired. * * 2) Giant must be released when blocking on a sleepable lock. * * This rule is less obvious, but is a result of Giant providing the same * semantics as spl(). Basically, when a thread sleeps, it must release * Giant. When a thread blocks on a sleepable lock, it sleeps. Hence rule * 2). * * 3) Giant may be acquired before or after sleepable locks. * * This rule is also not quite as obvious. Giant may be acquired after * a sleepable lock because it is a non-sleepable lock and non-sleepable * locks may always be acquired while holding a sleepable lock. The second * case, Giant before a sleepable lock, follows from rule 2) above. Suppose * you have two threads T1 and T2 and a sleepable lock X. Suppose that T1 * acquires X and blocks on Giant. Then suppose that T2 acquires Giant and * blocks on X. When T2 blocks on X, T2 will release Giant allowing T1 to * execute. Thus, acquiring Giant both before and after a sleepable lock * will not result in a lock order reversal. */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_hwpmc_hooks.h" #include "opt_stack.h" #include "opt_witness.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DDB #include #endif #include #if !defined(DDB) && !defined(STACK) #error "DDB or STACK options are required for WITNESS" #endif /* Note that these traces do not work with KTR_ALQ. */ #if 0 #define KTR_WITNESS KTR_SUBSYS #else #define KTR_WITNESS 0 #endif #define LI_RECURSEMASK 0x0000ffff /* Recursion depth of lock instance. */ #define LI_EXCLUSIVE 0x00010000 /* Exclusive lock instance. */ #define LI_NORELEASE 0x00020000 /* Lock not allowed to be released. */ /* Define this to check for blessed mutexes */ #undef BLESSING #ifndef WITNESS_COUNT #define WITNESS_COUNT 1536 #endif #define WITNESS_HASH_SIZE 251 /* Prime, gives load factor < 2 */ #define WITNESS_PENDLIST (1024 + MAXCPU) /* Allocate 256 KB of stack data space */ #define WITNESS_LO_DATA_COUNT 2048 /* Prime, gives load factor of ~2 at full load */ #define WITNESS_LO_HASH_SIZE 1021 /* * XXX: This is somewhat bogus, as we assume here that at most 2048 threads * will hold LOCK_NCHILDREN locks. We handle failure ok, and we should * probably be safe for the most part, but it's still a SWAG. */ #define LOCK_NCHILDREN 5 #define LOCK_CHILDCOUNT 2048 #define MAX_W_NAME 64 #define FULLGRAPH_SBUF_SIZE 512 /* * These flags go in the witness relationship matrix and describe the * relationship between any two struct witness objects. */ #define WITNESS_UNRELATED 0x00 /* No lock order relation. */ #define WITNESS_PARENT 0x01 /* Parent, aka direct ancestor. */ #define WITNESS_ANCESTOR 0x02 /* Direct or indirect ancestor. */ #define WITNESS_CHILD 0x04 /* Child, aka direct descendant. */ #define WITNESS_DESCENDANT 0x08 /* Direct or indirect descendant. */ #define WITNESS_ANCESTOR_MASK (WITNESS_PARENT | WITNESS_ANCESTOR) #define WITNESS_DESCENDANT_MASK (WITNESS_CHILD | WITNESS_DESCENDANT) #define WITNESS_RELATED_MASK \ (WITNESS_ANCESTOR_MASK | WITNESS_DESCENDANT_MASK) #define WITNESS_REVERSAL 0x10 /* A lock order reversal has been * observed. */ #define WITNESS_RESERVED1 0x20 /* Unused flag, reserved. */ #define WITNESS_RESERVED2 0x40 /* Unused flag, reserved. */ #define WITNESS_LOCK_ORDER_KNOWN 0x80 /* This lock order is known. */ /* Descendant to ancestor flags */ #define WITNESS_DTOA(x) (((x) & WITNESS_RELATED_MASK) >> 2) /* Ancestor to descendant flags */ #define WITNESS_ATOD(x) (((x) & WITNESS_RELATED_MASK) << 2) #define WITNESS_INDEX_ASSERT(i) \ MPASS((i) > 0 && (i) <= w_max_used_index && (i) < witness_count) static MALLOC_DEFINE(M_WITNESS, "Witness", "Witness"); /* * Lock instances. A lock instance is the data associated with a lock while * it is held by witness. For example, a lock instance will hold the * recursion count of a lock. Lock instances are held in lists. Spin locks * are held in a per-cpu list while sleep locks are held in per-thread list. */ struct lock_instance { struct lock_object *li_lock; const char *li_file; int li_line; u_int li_flags; }; /* * A simple list type used to build the list of locks held by a thread * or CPU. We can't simply embed the list in struct lock_object since a * lock may be held by more than one thread if it is a shared lock. Locks * are added to the head of the list, so we fill up each list entry from * "the back" logically. To ease some of the arithmetic, we actually fill * in each list entry the normal way (children[0] then children[1], etc.) but * when we traverse the list we read children[count-1] as the first entry * down to children[0] as the final entry. */ struct lock_list_entry { struct lock_list_entry *ll_next; struct lock_instance ll_children[LOCK_NCHILDREN]; u_int ll_count; }; /* * The main witness structure. One of these per named lock type in the system * (for example, "vnode interlock"). */ struct witness { char w_name[MAX_W_NAME]; uint32_t w_index; /* Index in the relationship matrix */ struct lock_class *w_class; STAILQ_ENTRY(witness) w_list; /* List of all witnesses. */ STAILQ_ENTRY(witness) w_typelist; /* Witnesses of a type. */ struct witness *w_hash_next; /* Linked list in hash buckets. */ const char *w_file; /* File where last acquired */ uint32_t w_line; /* Line where last acquired */ uint32_t w_refcount; uint16_t w_num_ancestors; /* direct/indirect * ancestor count */ uint16_t w_num_descendants; /* direct/indirect * descendant count */ int16_t w_ddb_level; unsigned w_displayed:1; unsigned w_reversed:1; }; STAILQ_HEAD(witness_list, witness); /* * The witness hash table. Keys are witness names (const char *), elements are * witness objects (struct witness *). */ struct witness_hash { struct witness *wh_array[WITNESS_HASH_SIZE]; uint32_t wh_size; uint32_t wh_count; }; /* * Key type for the lock order data hash table. */ struct witness_lock_order_key { uint16_t from; uint16_t to; }; struct witness_lock_order_data { struct stack wlod_stack; struct witness_lock_order_key wlod_key; struct witness_lock_order_data *wlod_next; }; /* * The witness lock order data hash table. Keys are witness index tuples * (struct witness_lock_order_key), elements are lock order data objects * (struct witness_lock_order_data). */ struct witness_lock_order_hash { struct witness_lock_order_data *wloh_array[WITNESS_LO_HASH_SIZE]; u_int wloh_size; u_int wloh_count; }; #ifdef BLESSING struct witness_blessed { const char *b_lock1; const char *b_lock2; }; #endif struct witness_pendhelp { const char *wh_type; struct lock_object *wh_lock; }; struct witness_order_list_entry { const char *w_name; struct lock_class *w_class; }; /* * Returns 0 if one of the locks is a spin lock and the other is not. * Returns 1 otherwise. */ static __inline int witness_lock_type_equal(struct witness *w1, struct witness *w2) { return ((w1->w_class->lc_flags & (LC_SLEEPLOCK | LC_SPINLOCK)) == (w2->w_class->lc_flags & (LC_SLEEPLOCK | LC_SPINLOCK))); } static __inline int witness_lock_order_key_equal(const struct witness_lock_order_key *a, const struct witness_lock_order_key *b) { return (a->from == b->from && a->to == b->to); } static int _isitmyx(struct witness *w1, struct witness *w2, int rmask, const char *fname); static void adopt(struct witness *parent, struct witness *child); #ifdef BLESSING static int blessed(struct witness *, struct witness *); #endif static void depart(struct witness *w); static struct witness *enroll(const char *description, struct lock_class *lock_class); static struct lock_instance *find_instance(struct lock_list_entry *list, const struct lock_object *lock); static int isitmychild(struct witness *parent, struct witness *child); static int isitmydescendant(struct witness *parent, struct witness *child); static void itismychild(struct witness *parent, struct witness *child); static int sysctl_debug_witness_badstacks(SYSCTL_HANDLER_ARGS); static int sysctl_debug_witness_watch(SYSCTL_HANDLER_ARGS); static int sysctl_debug_witness_fullgraph(SYSCTL_HANDLER_ARGS); static int sysctl_debug_witness_channel(SYSCTL_HANDLER_ARGS); static void witness_add_fullgraph(struct sbuf *sb, struct witness *parent); #ifdef DDB static void witness_ddb_compute_levels(void); static void witness_ddb_display(int(*)(const char *fmt, ...)); static void witness_ddb_display_descendants(int(*)(const char *fmt, ...), struct witness *, int indent); static void witness_ddb_display_list(int(*prnt)(const char *fmt, ...), struct witness_list *list); static void witness_ddb_level_descendants(struct witness *parent, int l); static void witness_ddb_list(struct thread *td); #endif static void witness_debugger(int cond, const char *msg); static void witness_free(struct witness *m); static struct witness *witness_get(void); static uint32_t witness_hash_djb2(const uint8_t *key, uint32_t size); static struct witness *witness_hash_get(const char *key); static void witness_hash_put(struct witness *w); static void witness_init_hash_tables(void); static void witness_increment_graph_generation(void); static void witness_lock_list_free(struct lock_list_entry *lle); static struct lock_list_entry *witness_lock_list_get(void); static int witness_lock_order_add(struct witness *parent, struct witness *child); static int witness_lock_order_check(struct witness *parent, struct witness *child); static struct witness_lock_order_data *witness_lock_order_get( struct witness *parent, struct witness *child); static void witness_list_lock(struct lock_instance *instance, int (*prnt)(const char *fmt, ...)); static int witness_output(const char *fmt, ...) __printflike(1, 2); static int witness_voutput(const char *fmt, va_list ap) __printflike(1, 0); static void witness_setflag(struct lock_object *lock, int flag, int set); static SYSCTL_NODE(_debug, OID_AUTO, witness, CTLFLAG_RW, NULL, "Witness Locking"); /* * If set to 0, lock order checking is disabled. If set to -1, * witness is completely disabled. Otherwise witness performs full * lock order checking for all locks. At runtime, lock order checking * may be toggled. However, witness cannot be reenabled once it is * completely disabled. */ static int witness_watch = 1; SYSCTL_PROC(_debug_witness, OID_AUTO, watch, CTLFLAG_RWTUN | CTLTYPE_INT, NULL, 0, sysctl_debug_witness_watch, "I", "witness is watching lock operations"); #ifdef KDB /* * When KDB is enabled and witness_kdb is 1, it will cause the system * to drop into kdebug() when: * - a lock hierarchy violation occurs * - locks are held when going to sleep. */ #ifdef WITNESS_KDB int witness_kdb = 1; #else int witness_kdb = 0; #endif SYSCTL_INT(_debug_witness, OID_AUTO, kdb, CTLFLAG_RWTUN, &witness_kdb, 0, ""); #endif /* KDB */ #if defined(DDB) || defined(KDB) /* * When DDB or KDB is enabled and witness_trace is 1, it will cause the system * to print a stack trace: * - a lock hierarchy violation occurs * - locks are held when going to sleep. */ int witness_trace = 1; SYSCTL_INT(_debug_witness, OID_AUTO, trace, CTLFLAG_RWTUN, &witness_trace, 0, ""); #endif /* DDB || KDB */ #ifdef WITNESS_SKIPSPIN int witness_skipspin = 1; #else int witness_skipspin = 0; #endif SYSCTL_INT(_debug_witness, OID_AUTO, skipspin, CTLFLAG_RDTUN, &witness_skipspin, 0, ""); int badstack_sbuf_size; int witness_count = WITNESS_COUNT; SYSCTL_INT(_debug_witness, OID_AUTO, witness_count, CTLFLAG_RDTUN, &witness_count, 0, ""); /* * Output channel for witness messages. By default we print to the console. */ enum witness_channel { WITNESS_CONSOLE, WITNESS_LOG, WITNESS_NONE, }; static enum witness_channel witness_channel = WITNESS_CONSOLE; SYSCTL_PROC(_debug_witness, OID_AUTO, output_channel, CTLTYPE_STRING | CTLFLAG_RWTUN, NULL, 0, sysctl_debug_witness_channel, "A", "Output channel for warnings"); /* * Call this to print out the relations between locks. */ SYSCTL_PROC(_debug_witness, OID_AUTO, fullgraph, CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, sysctl_debug_witness_fullgraph, "A", "Show locks relation graphs"); /* * Call this to print out the witness faulty stacks. */ SYSCTL_PROC(_debug_witness, OID_AUTO, badstacks, CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, sysctl_debug_witness_badstacks, "A", "Show bad witness stacks"); static struct mtx w_mtx; /* w_list */ static struct witness_list w_free = STAILQ_HEAD_INITIALIZER(w_free); static struct witness_list w_all = STAILQ_HEAD_INITIALIZER(w_all); /* w_typelist */ static struct witness_list w_spin = STAILQ_HEAD_INITIALIZER(w_spin); static struct witness_list w_sleep = STAILQ_HEAD_INITIALIZER(w_sleep); /* lock list */ static struct lock_list_entry *w_lock_list_free = NULL; static struct witness_pendhelp pending_locks[WITNESS_PENDLIST]; static u_int pending_cnt; static int w_free_cnt, w_spin_cnt, w_sleep_cnt; SYSCTL_INT(_debug_witness, OID_AUTO, free_cnt, CTLFLAG_RD, &w_free_cnt, 0, ""); SYSCTL_INT(_debug_witness, OID_AUTO, spin_cnt, CTLFLAG_RD, &w_spin_cnt, 0, ""); SYSCTL_INT(_debug_witness, OID_AUTO, sleep_cnt, CTLFLAG_RD, &w_sleep_cnt, 0, ""); static struct witness *w_data; static uint8_t **w_rmatrix; static struct lock_list_entry w_locklistdata[LOCK_CHILDCOUNT]; static struct witness_hash w_hash; /* The witness hash table. */ /* The lock order data hash */ static struct witness_lock_order_data w_lodata[WITNESS_LO_DATA_COUNT]; static struct witness_lock_order_data *w_lofree = NULL; static struct witness_lock_order_hash w_lohash; static int w_max_used_index = 0; static unsigned int w_generation = 0; static const char w_notrunning[] = "Witness not running\n"; static const char w_stillcold[] = "Witness is still cold\n"; static struct witness_order_list_entry order_lists[] = { /* * sx locks */ { "proctree", &lock_class_sx }, { "allproc", &lock_class_sx }, { "allprison", &lock_class_sx }, { NULL, NULL }, /* * Various mutexes */ { "Giant", &lock_class_mtx_sleep }, { "pipe mutex", &lock_class_mtx_sleep }, { "sigio lock", &lock_class_mtx_sleep }, { "process group", &lock_class_mtx_sleep }, { "process lock", &lock_class_mtx_sleep }, { "session", &lock_class_mtx_sleep }, { "uidinfo hash", &lock_class_rw }, #ifdef HWPMC_HOOKS { "pmc-sleep", &lock_class_mtx_sleep }, #endif { "time lock", &lock_class_mtx_sleep }, { NULL, NULL }, /* * umtx */ { "umtx lock", &lock_class_mtx_sleep }, { NULL, NULL }, /* * Sockets */ { "accept", &lock_class_mtx_sleep }, { "so_snd", &lock_class_mtx_sleep }, { "so_rcv", &lock_class_mtx_sleep }, { "sellck", &lock_class_mtx_sleep }, { NULL, NULL }, /* * Routing */ { "so_rcv", &lock_class_mtx_sleep }, { "radix node head", &lock_class_rw }, { "rtentry", &lock_class_mtx_sleep }, { "ifaddr", &lock_class_mtx_sleep }, { NULL, NULL }, /* * IPv4 multicast: * protocol locks before interface locks, after UDP locks. */ { "udpinp", &lock_class_rw }, { "in_multi_mtx", &lock_class_mtx_sleep }, { "igmp_mtx", &lock_class_mtx_sleep }, { "if_addr_lock", &lock_class_rw }, { NULL, NULL }, /* * IPv6 multicast: * protocol locks before interface locks, after UDP locks. */ { "udpinp", &lock_class_rw }, { "in6_multi_mtx", &lock_class_mtx_sleep }, { "mld_mtx", &lock_class_mtx_sleep }, { "if_addr_lock", &lock_class_rw }, { NULL, NULL }, /* * UNIX Domain Sockets */ { "unp_link_rwlock", &lock_class_rw }, { "unp_list_lock", &lock_class_mtx_sleep }, { "unp", &lock_class_mtx_sleep }, { "so_snd", &lock_class_mtx_sleep }, { NULL, NULL }, /* * UDP/IP */ { "udp", &lock_class_rw }, { "udpinp", &lock_class_rw }, { "so_snd", &lock_class_mtx_sleep }, { NULL, NULL }, /* * TCP/IP */ { "tcp", &lock_class_rw }, { "tcpinp", &lock_class_rw }, { "so_snd", &lock_class_mtx_sleep }, { NULL, NULL }, /* * BPF */ { "bpf global lock", &lock_class_mtx_sleep }, { "bpf interface lock", &lock_class_rw }, { "bpf cdev lock", &lock_class_mtx_sleep }, { NULL, NULL }, /* * NFS server */ { "nfsd_mtx", &lock_class_mtx_sleep }, { "so_snd", &lock_class_mtx_sleep }, { NULL, NULL }, /* * IEEE 802.11 */ { "802.11 com lock", &lock_class_mtx_sleep}, { NULL, NULL }, /* * Network drivers */ { "network driver", &lock_class_mtx_sleep}, { NULL, NULL }, /* * Netgraph */ { "ng_node", &lock_class_mtx_sleep }, { "ng_worklist", &lock_class_mtx_sleep }, { NULL, NULL }, /* * CDEV */ { "vm map (system)", &lock_class_mtx_sleep }, { "vm pagequeue", &lock_class_mtx_sleep }, { "vnode interlock", &lock_class_mtx_sleep }, { "cdev", &lock_class_mtx_sleep }, { NULL, NULL }, /* * VM */ { "vm map (user)", &lock_class_sx }, { "vm object", &lock_class_rw }, { "vm page", &lock_class_mtx_sleep }, { "vm pagequeue", &lock_class_mtx_sleep }, { "pmap pv global", &lock_class_rw }, { "pmap", &lock_class_mtx_sleep }, { "pmap pv list", &lock_class_rw }, { "vm page free queue", &lock_class_mtx_sleep }, { NULL, NULL }, /* * kqueue/VFS interaction */ { "kqueue", &lock_class_mtx_sleep }, { "struct mount mtx", &lock_class_mtx_sleep }, { "vnode interlock", &lock_class_mtx_sleep }, { NULL, NULL }, /* * VFS namecache */ { "ncvn", &lock_class_mtx_sleep }, { "ncbuc", &lock_class_rw }, { "vnode interlock", &lock_class_mtx_sleep }, { "ncneg", &lock_class_mtx_sleep }, { NULL, NULL }, /* * ZFS locking */ { "dn->dn_mtx", &lock_class_sx }, { "dr->dt.di.dr_mtx", &lock_class_sx }, { "db->db_mtx", &lock_class_sx }, { NULL, NULL }, /* * spin locks */ #ifdef SMP { "ap boot", &lock_class_mtx_spin }, #endif { "rm.mutex_mtx", &lock_class_mtx_spin }, { "sio", &lock_class_mtx_spin }, #ifdef __i386__ { "cy", &lock_class_mtx_spin }, #endif #ifdef __sparc64__ { "pcib_mtx", &lock_class_mtx_spin }, { "rtc_mtx", &lock_class_mtx_spin }, #endif { "scc_hwmtx", &lock_class_mtx_spin }, { "uart_hwmtx", &lock_class_mtx_spin }, { "fast_taskqueue", &lock_class_mtx_spin }, { "intr table", &lock_class_mtx_spin }, #ifdef HWPMC_HOOKS { "pmc-per-proc", &lock_class_mtx_spin }, #endif { "process slock", &lock_class_mtx_spin }, { "syscons video lock", &lock_class_mtx_spin }, { "sleepq chain", &lock_class_mtx_spin }, { "rm_spinlock", &lock_class_mtx_spin }, { "turnstile chain", &lock_class_mtx_spin }, { "turnstile lock", &lock_class_mtx_spin }, { "sched lock", &lock_class_mtx_spin }, { "td_contested", &lock_class_mtx_spin }, { "callout", &lock_class_mtx_spin }, { "entropy harvest mutex", &lock_class_mtx_spin }, #ifdef SMP { "smp rendezvous", &lock_class_mtx_spin }, #endif #ifdef __powerpc__ { "tlb0", &lock_class_mtx_spin }, #endif /* * leaf locks */ { "intrcnt", &lock_class_mtx_spin }, { "icu", &lock_class_mtx_spin }, #if defined(SMP) && defined(__sparc64__) { "ipi", &lock_class_mtx_spin }, #endif #ifdef __i386__ { "allpmaps", &lock_class_mtx_spin }, { "descriptor tables", &lock_class_mtx_spin }, #endif { "clk", &lock_class_mtx_spin }, { "cpuset", &lock_class_mtx_spin }, { "mprof lock", &lock_class_mtx_spin }, { "zombie lock", &lock_class_mtx_spin }, { "ALD Queue", &lock_class_mtx_spin }, #if defined(__i386__) || defined(__amd64__) { "pcicfg", &lock_class_mtx_spin }, { "NDIS thread lock", &lock_class_mtx_spin }, #endif { "tw_osl_io_lock", &lock_class_mtx_spin }, { "tw_osl_q_lock", &lock_class_mtx_spin }, { "tw_cl_io_lock", &lock_class_mtx_spin }, { "tw_cl_intr_lock", &lock_class_mtx_spin }, { "tw_cl_gen_lock", &lock_class_mtx_spin }, #ifdef HWPMC_HOOKS { "pmc-leaf", &lock_class_mtx_spin }, #endif { "blocked lock", &lock_class_mtx_spin }, { NULL, NULL }, { NULL, NULL } }; #ifdef BLESSING /* * Pairs of locks which have been blessed * Don't complain about order problems with blessed locks */ static struct witness_blessed blessed_list[] = { }; #endif /* * This global is set to 0 once it becomes safe to use the witness code. */ static int witness_cold = 1; /* * This global is set to 1 once the static lock orders have been enrolled * so that a warning can be issued for any spin locks enrolled later. */ static int witness_spin_warn = 0; /* Trim useless garbage from filenames. */ static const char * fixup_filename(const char *file) { if (file == NULL) return (NULL); while (strncmp(file, "../", 3) == 0) file += 3; return (file); } /* * The WITNESS-enabled diagnostic code. Note that the witness code does * assume that the early boot is single-threaded at least until after this * routine is completed. */ static void witness_initialize(void *dummy __unused) { struct lock_object *lock; struct witness_order_list_entry *order; struct witness *w, *w1; int i; w_data = malloc(sizeof (struct witness) * witness_count, M_WITNESS, M_WAITOK | M_ZERO); w_rmatrix = malloc(sizeof(*w_rmatrix) * (witness_count + 1), M_WITNESS, M_WAITOK | M_ZERO); for (i = 0; i < witness_count + 1; i++) { w_rmatrix[i] = malloc(sizeof(*w_rmatrix[i]) * (witness_count + 1), M_WITNESS, M_WAITOK | M_ZERO); } badstack_sbuf_size = witness_count * 256; /* * We have to release Giant before initializing its witness * structure so that WITNESS doesn't get confused. */ mtx_unlock(&Giant); mtx_assert(&Giant, MA_NOTOWNED); CTR1(KTR_WITNESS, "%s: initializing witness", __func__); mtx_init(&w_mtx, "witness lock", NULL, MTX_SPIN | MTX_QUIET | MTX_NOWITNESS | MTX_NOPROFILE); for (i = witness_count - 1; i >= 0; i--) { w = &w_data[i]; memset(w, 0, sizeof(*w)); w_data[i].w_index = i; /* Witness index never changes. */ witness_free(w); } KASSERT(STAILQ_FIRST(&w_free)->w_index == 0, ("%s: Invalid list of free witness objects", __func__)); /* Witness with index 0 is not used to aid in debugging. */ STAILQ_REMOVE_HEAD(&w_free, w_list); w_free_cnt--; for (i = 0; i < witness_count; i++) { memset(w_rmatrix[i], 0, sizeof(*w_rmatrix[i]) * (witness_count + 1)); } for (i = 0; i < LOCK_CHILDCOUNT; i++) witness_lock_list_free(&w_locklistdata[i]); witness_init_hash_tables(); /* First add in all the specified order lists. */ for (order = order_lists; order->w_name != NULL; order++) { w = enroll(order->w_name, order->w_class); if (w == NULL) continue; w->w_file = "order list"; for (order++; order->w_name != NULL; order++) { w1 = enroll(order->w_name, order->w_class); if (w1 == NULL) continue; w1->w_file = "order list"; itismychild(w, w1); w = w1; } } witness_spin_warn = 1; /* Iterate through all locks and add them to witness. */ for (i = 0; pending_locks[i].wh_lock != NULL; i++) { lock = pending_locks[i].wh_lock; KASSERT(lock->lo_flags & LO_WITNESS, ("%s: lock %s is on pending list but not LO_WITNESS", __func__, lock->lo_name)); lock->lo_witness = enroll(pending_locks[i].wh_type, LOCK_CLASS(lock)); } /* Mark the witness code as being ready for use. */ witness_cold = 0; mtx_lock(&Giant); } SYSINIT(witness_init, SI_SUB_WITNESS, SI_ORDER_FIRST, witness_initialize, NULL); void witness_init(struct lock_object *lock, const char *type) { struct lock_class *class; /* Various sanity checks. */ class = LOCK_CLASS(lock); if ((lock->lo_flags & LO_RECURSABLE) != 0 && (class->lc_flags & LC_RECURSABLE) == 0) kassert_panic("%s: lock (%s) %s can not be recursable", __func__, class->lc_name, lock->lo_name); if ((lock->lo_flags & LO_SLEEPABLE) != 0 && (class->lc_flags & LC_SLEEPABLE) == 0) kassert_panic("%s: lock (%s) %s can not be sleepable", __func__, class->lc_name, lock->lo_name); if ((lock->lo_flags & LO_UPGRADABLE) != 0 && (class->lc_flags & LC_UPGRADABLE) == 0) kassert_panic("%s: lock (%s) %s can not be upgradable", __func__, class->lc_name, lock->lo_name); /* * If we shouldn't watch this lock, then just clear lo_witness. * Otherwise, if witness_cold is set, then it is too early to * enroll this lock, so defer it to witness_initialize() by adding * it to the pending_locks list. If it is not too early, then enroll * the lock now. */ if (witness_watch < 1 || panicstr != NULL || (lock->lo_flags & LO_WITNESS) == 0) lock->lo_witness = NULL; else if (witness_cold) { pending_locks[pending_cnt].wh_lock = lock; pending_locks[pending_cnt++].wh_type = type; if (pending_cnt > WITNESS_PENDLIST) panic("%s: pending locks list is too small, " "increase WITNESS_PENDLIST\n", __func__); } else lock->lo_witness = enroll(type, class); } void witness_destroy(struct lock_object *lock) { struct lock_class *class; struct witness *w; class = LOCK_CLASS(lock); if (witness_cold) panic("lock (%s) %s destroyed while witness_cold", class->lc_name, lock->lo_name); /* XXX: need to verify that no one holds the lock */ if ((lock->lo_flags & LO_WITNESS) == 0 || lock->lo_witness == NULL) return; w = lock->lo_witness; mtx_lock_spin(&w_mtx); MPASS(w->w_refcount > 0); w->w_refcount--; if (w->w_refcount == 0) depart(w); mtx_unlock_spin(&w_mtx); } #ifdef DDB static void witness_ddb_compute_levels(void) { struct witness *w; /* * First clear all levels. */ STAILQ_FOREACH(w, &w_all, w_list) w->w_ddb_level = -1; /* * Look for locks with no parents and level all their descendants. */ STAILQ_FOREACH(w, &w_all, w_list) { /* If the witness has ancestors (is not a root), skip it. */ if (w->w_num_ancestors > 0) continue; witness_ddb_level_descendants(w, 0); } } static void witness_ddb_level_descendants(struct witness *w, int l) { int i; if (w->w_ddb_level >= l) return; w->w_ddb_level = l; l++; for (i = 1; i <= w_max_used_index; i++) { if (w_rmatrix[w->w_index][i] & WITNESS_PARENT) witness_ddb_level_descendants(&w_data[i], l); } } static void witness_ddb_display_descendants(int(*prnt)(const char *fmt, ...), struct witness *w, int indent) { int i; for (i = 0; i < indent; i++) prnt(" "); prnt("%s (type: %s, depth: %d, active refs: %d)", w->w_name, w->w_class->lc_name, w->w_ddb_level, w->w_refcount); if (w->w_displayed) { prnt(" -- (already displayed)\n"); return; } w->w_displayed = 1; if (w->w_file != NULL && w->w_line != 0) prnt(" -- last acquired @ %s:%d\n", fixup_filename(w->w_file), w->w_line); else prnt(" -- never acquired\n"); indent++; WITNESS_INDEX_ASSERT(w->w_index); for (i = 1; i <= w_max_used_index; i++) { if (db_pager_quit) return; if (w_rmatrix[w->w_index][i] & WITNESS_PARENT) witness_ddb_display_descendants(prnt, &w_data[i], indent); } } static void witness_ddb_display_list(int(*prnt)(const char *fmt, ...), struct witness_list *list) { struct witness *w; STAILQ_FOREACH(w, list, w_typelist) { if (w->w_file == NULL || w->w_ddb_level > 0) continue; /* This lock has no anscestors - display its descendants. */ witness_ddb_display_descendants(prnt, w, 0); if (db_pager_quit) return; } } static void witness_ddb_display(int(*prnt)(const char *fmt, ...)) { struct witness *w; KASSERT(witness_cold == 0, ("%s: witness_cold", __func__)); witness_ddb_compute_levels(); /* Clear all the displayed flags. */ STAILQ_FOREACH(w, &w_all, w_list) w->w_displayed = 0; /* * First, handle sleep locks which have been acquired at least * once. */ prnt("Sleep locks:\n"); witness_ddb_display_list(prnt, &w_sleep); if (db_pager_quit) return; /* * Now do spin locks which have been acquired at least once. */ prnt("\nSpin locks:\n"); witness_ddb_display_list(prnt, &w_spin); if (db_pager_quit) return; /* * Finally, any locks which have not been acquired yet. */ prnt("\nLocks which were never acquired:\n"); STAILQ_FOREACH(w, &w_all, w_list) { if (w->w_file != NULL || w->w_refcount == 0) continue; prnt("%s (type: %s, depth: %d)\n", w->w_name, w->w_class->lc_name, w->w_ddb_level); if (db_pager_quit) return; } } #endif /* DDB */ int witness_defineorder(struct lock_object *lock1, struct lock_object *lock2) { if (witness_watch == -1 || panicstr != NULL) return (0); /* Require locks that witness knows about. */ if (lock1 == NULL || lock1->lo_witness == NULL || lock2 == NULL || lock2->lo_witness == NULL) return (EINVAL); mtx_assert(&w_mtx, MA_NOTOWNED); mtx_lock_spin(&w_mtx); /* * If we already have either an explicit or implied lock order that * is the other way around, then return an error. */ if (witness_watch && isitmydescendant(lock2->lo_witness, lock1->lo_witness)) { mtx_unlock_spin(&w_mtx); return (EDOOFUS); } /* Try to add the new order. */ CTR3(KTR_WITNESS, "%s: adding %s as a child of %s", __func__, lock2->lo_witness->w_name, lock1->lo_witness->w_name); itismychild(lock1->lo_witness, lock2->lo_witness); mtx_unlock_spin(&w_mtx); return (0); } void witness_checkorder(struct lock_object *lock, int flags, const char *file, int line, struct lock_object *interlock) { struct lock_list_entry *lock_list, *lle; struct lock_instance *lock1, *lock2, *plock; struct lock_class *class, *iclass; struct witness *w, *w1; struct thread *td; int i, j; if (witness_cold || witness_watch < 1 || lock->lo_witness == NULL || panicstr != NULL) return; w = lock->lo_witness; class = LOCK_CLASS(lock); td = curthread; if (class->lc_flags & LC_SLEEPLOCK) { /* * Since spin locks include a critical section, this check * implicitly enforces a lock order of all sleep locks before * all spin locks. */ if (td->td_critnest != 0 && !kdb_active) kassert_panic("acquiring blockable sleep lock with " "spinlock or critical section held (%s) %s @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); /* * If this is the first lock acquired then just return as * no order checking is needed. */ lock_list = td->td_sleeplocks; if (lock_list == NULL || lock_list->ll_count == 0) return; } else { /* * If this is the first lock, just return as no order * checking is needed. Avoid problems with thread * migration pinning the thread while checking if * spinlocks are held. If at least one spinlock is held * the thread is in a safe path and it is allowed to * unpin it. */ sched_pin(); lock_list = PCPU_GET(spinlocks); if (lock_list == NULL || lock_list->ll_count == 0) { sched_unpin(); return; } sched_unpin(); } /* * Check to see if we are recursing on a lock we already own. If * so, make sure that we don't mismatch exclusive and shared lock * acquires. */ lock1 = find_instance(lock_list, lock); if (lock1 != NULL) { if ((lock1->li_flags & LI_EXCLUSIVE) != 0 && (flags & LOP_EXCLUSIVE) == 0) { witness_output("shared lock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); witness_output("while exclusively locked from %s:%d\n", fixup_filename(lock1->li_file), lock1->li_line); kassert_panic("excl->share"); } if ((lock1->li_flags & LI_EXCLUSIVE) == 0 && (flags & LOP_EXCLUSIVE) != 0) { witness_output("exclusive lock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); witness_output("while share locked from %s:%d\n", fixup_filename(lock1->li_file), lock1->li_line); kassert_panic("share->excl"); } return; } /* Warn if the interlock is not locked exactly once. */ if (interlock != NULL) { iclass = LOCK_CLASS(interlock); lock1 = find_instance(lock_list, interlock); if (lock1 == NULL) kassert_panic("interlock (%s) %s not locked @ %s:%d", iclass->lc_name, interlock->lo_name, fixup_filename(file), line); else if ((lock1->li_flags & LI_RECURSEMASK) != 0) kassert_panic("interlock (%s) %s recursed @ %s:%d", iclass->lc_name, interlock->lo_name, fixup_filename(file), line); } /* * Find the previously acquired lock, but ignore interlocks. */ plock = &lock_list->ll_children[lock_list->ll_count - 1]; if (interlock != NULL && plock->li_lock == interlock) { if (lock_list->ll_count > 1) plock = &lock_list->ll_children[lock_list->ll_count - 2]; else { lle = lock_list->ll_next; /* * The interlock is the only lock we hold, so * simply return. */ if (lle == NULL) return; plock = &lle->ll_children[lle->ll_count - 1]; } } /* * Try to perform most checks without a lock. If this succeeds we * can skip acquiring the lock and return success. Otherwise we redo * the check with the lock held to handle races with concurrent updates. */ w1 = plock->li_lock->lo_witness; if (witness_lock_order_check(w1, w)) return; mtx_lock_spin(&w_mtx); if (witness_lock_order_check(w1, w)) { mtx_unlock_spin(&w_mtx); return; } witness_lock_order_add(w1, w); /* * Check for duplicate locks of the same type. Note that we only * have to check for this on the last lock we just acquired. Any * other cases will be caught as lock order violations. */ if (w1 == w) { i = w->w_index; if (!(lock->lo_flags & LO_DUPOK) && !(flags & LOP_DUPOK) && !(w_rmatrix[i][i] & WITNESS_REVERSAL)) { w_rmatrix[i][i] |= WITNESS_REVERSAL; w->w_reversed = 1; mtx_unlock_spin(&w_mtx); witness_output( "acquiring duplicate lock of same type: \"%s\"\n", w->w_name); witness_output(" 1st %s @ %s:%d\n", plock->li_lock->lo_name, fixup_filename(plock->li_file), plock->li_line); witness_output(" 2nd %s @ %s:%d\n", lock->lo_name, fixup_filename(file), line); witness_debugger(1, __func__); } else mtx_unlock_spin(&w_mtx); return; } mtx_assert(&w_mtx, MA_OWNED); /* * If we know that the lock we are acquiring comes after * the lock we most recently acquired in the lock order tree, * then there is no need for any further checks. */ if (isitmychild(w1, w)) goto out; for (j = 0, lle = lock_list; lle != NULL; lle = lle->ll_next) { for (i = lle->ll_count - 1; i >= 0; i--, j++) { MPASS(j < LOCK_CHILDCOUNT * LOCK_NCHILDREN); lock1 = &lle->ll_children[i]; /* * Ignore the interlock. */ if (interlock == lock1->li_lock) continue; /* * If this lock doesn't undergo witness checking, * then skip it. */ w1 = lock1->li_lock->lo_witness; if (w1 == NULL) { KASSERT((lock1->li_lock->lo_flags & LO_WITNESS) == 0, ("lock missing witness structure")); continue; } /* * If we are locking Giant and this is a sleepable * lock, then skip it. */ if ((lock1->li_lock->lo_flags & LO_SLEEPABLE) != 0 && lock == &Giant.lock_object) continue; /* * If we are locking a sleepable lock and this lock * is Giant, then skip it. */ if ((lock->lo_flags & LO_SLEEPABLE) != 0 && lock1->li_lock == &Giant.lock_object) continue; /* * If we are locking a sleepable lock and this lock * isn't sleepable, we want to treat it as a lock * order violation to enfore a general lock order of * sleepable locks before non-sleepable locks. */ if (((lock->lo_flags & LO_SLEEPABLE) != 0 && (lock1->li_lock->lo_flags & LO_SLEEPABLE) == 0)) goto reversal; /* * If we are locking Giant and this is a non-sleepable * lock, then treat it as a reversal. */ if ((lock1->li_lock->lo_flags & LO_SLEEPABLE) == 0 && lock == &Giant.lock_object) goto reversal; /* * Check the lock order hierarchy for a reveresal. */ if (!isitmydescendant(w, w1)) continue; reversal: /* * We have a lock order violation, check to see if it * is allowed or has already been yelled about. */ #ifdef BLESSING /* * If the lock order is blessed, just bail. We don't * look for other lock order violations though, which * may be a bug. */ if (blessed(w, w1)) goto out; #endif /* Bail if this violation is known */ if (w_rmatrix[w1->w_index][w->w_index] & WITNESS_REVERSAL) goto out; /* Record this as a violation */ w_rmatrix[w1->w_index][w->w_index] |= WITNESS_REVERSAL; w_rmatrix[w->w_index][w1->w_index] |= WITNESS_REVERSAL; w->w_reversed = w1->w_reversed = 1; witness_increment_graph_generation(); mtx_unlock_spin(&w_mtx); #ifdef WITNESS_NO_VNODE /* * There are known LORs between VNODE locks. They are * not an indication of a bug. VNODE locks are flagged * as such (LO_IS_VNODE) and we don't yell if the LOR * is between 2 VNODE locks. */ if ((lock->lo_flags & LO_IS_VNODE) != 0 && (lock1->li_lock->lo_flags & LO_IS_VNODE) != 0) return; #endif /* * Ok, yell about it. */ if (((lock->lo_flags & LO_SLEEPABLE) != 0 && (lock1->li_lock->lo_flags & LO_SLEEPABLE) == 0)) witness_output( "lock order reversal: (sleepable after non-sleepable)\n"); else if ((lock1->li_lock->lo_flags & LO_SLEEPABLE) == 0 && lock == &Giant.lock_object) witness_output( "lock order reversal: (Giant after non-sleepable)\n"); else witness_output("lock order reversal:\n"); /* * Try to locate an earlier lock with * witness w in our list. */ do { lock2 = &lle->ll_children[i]; MPASS(lock2->li_lock != NULL); if (lock2->li_lock->lo_witness == w) break; if (i == 0 && lle->ll_next != NULL) { lle = lle->ll_next; i = lle->ll_count - 1; MPASS(i >= 0 && i < LOCK_NCHILDREN); } else i--; } while (i >= 0); if (i < 0) { witness_output(" 1st %p %s (%s) @ %s:%d\n", lock1->li_lock, lock1->li_lock->lo_name, w1->w_name, fixup_filename(lock1->li_file), lock1->li_line); witness_output(" 2nd %p %s (%s) @ %s:%d\n", lock, lock->lo_name, w->w_name, fixup_filename(file), line); } else { witness_output(" 1st %p %s (%s) @ %s:%d\n", lock2->li_lock, lock2->li_lock->lo_name, lock2->li_lock->lo_witness->w_name, fixup_filename(lock2->li_file), lock2->li_line); witness_output(" 2nd %p %s (%s) @ %s:%d\n", lock1->li_lock, lock1->li_lock->lo_name, w1->w_name, fixup_filename(lock1->li_file), lock1->li_line); witness_output(" 3rd %p %s (%s) @ %s:%d\n", lock, lock->lo_name, w->w_name, fixup_filename(file), line); } witness_debugger(1, __func__); return; } } /* * If requested, build a new lock order. However, don't build a new * relationship between a sleepable lock and Giant if it is in the * wrong direction. The correct lock order is that sleepable locks * always come before Giant. */ if (flags & LOP_NEWORDER && !(plock->li_lock == &Giant.lock_object && (lock->lo_flags & LO_SLEEPABLE) != 0)) { CTR3(KTR_WITNESS, "%s: adding %s as a child of %s", __func__, w->w_name, plock->li_lock->lo_witness->w_name); itismychild(plock->li_lock->lo_witness, w); } out: mtx_unlock_spin(&w_mtx); } void witness_lock(struct lock_object *lock, int flags, const char *file, int line) { struct lock_list_entry **lock_list, *lle; struct lock_instance *instance; struct witness *w; struct thread *td; if (witness_cold || witness_watch == -1 || lock->lo_witness == NULL || panicstr != NULL) return; w = lock->lo_witness; td = curthread; /* Determine lock list for this lock. */ if (LOCK_CLASS(lock)->lc_flags & LC_SLEEPLOCK) lock_list = &td->td_sleeplocks; else lock_list = PCPU_PTR(spinlocks); /* Check to see if we are recursing on a lock we already own. */ instance = find_instance(*lock_list, lock); if (instance != NULL) { instance->li_flags++; CTR4(KTR_WITNESS, "%s: pid %d recursed on %s r=%d", __func__, td->td_proc->p_pid, lock->lo_name, instance->li_flags & LI_RECURSEMASK); instance->li_file = file; instance->li_line = line; return; } /* Update per-witness last file and line acquire. */ w->w_file = file; w->w_line = line; /* Find the next open lock instance in the list and fill it. */ lle = *lock_list; if (lle == NULL || lle->ll_count == LOCK_NCHILDREN) { lle = witness_lock_list_get(); if (lle == NULL) return; lle->ll_next = *lock_list; CTR3(KTR_WITNESS, "%s: pid %d added lle %p", __func__, td->td_proc->p_pid, lle); *lock_list = lle; } instance = &lle->ll_children[lle->ll_count++]; instance->li_lock = lock; instance->li_line = line; instance->li_file = file; if ((flags & LOP_EXCLUSIVE) != 0) instance->li_flags = LI_EXCLUSIVE; else instance->li_flags = 0; CTR4(KTR_WITNESS, "%s: pid %d added %s as lle[%d]", __func__, td->td_proc->p_pid, lock->lo_name, lle->ll_count - 1); } void witness_upgrade(struct lock_object *lock, int flags, const char *file, int line) { struct lock_instance *instance; struct lock_class *class; KASSERT(witness_cold == 0, ("%s: witness_cold", __func__)); if (lock->lo_witness == NULL || witness_watch == -1 || panicstr != NULL) return; class = LOCK_CLASS(lock); if (witness_watch) { if ((lock->lo_flags & LO_UPGRADABLE) == 0) kassert_panic( "upgrade of non-upgradable lock (%s) %s @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); if ((class->lc_flags & LC_SLEEPLOCK) == 0) kassert_panic( "upgrade of non-sleep lock (%s) %s @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); } instance = find_instance(curthread->td_sleeplocks, lock); if (instance == NULL) { kassert_panic("upgrade of unlocked lock (%s) %s @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); return; } if (witness_watch) { if ((instance->li_flags & LI_EXCLUSIVE) != 0) kassert_panic( "upgrade of exclusive lock (%s) %s @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); if ((instance->li_flags & LI_RECURSEMASK) != 0) kassert_panic( "upgrade of recursed lock (%s) %s r=%d @ %s:%d", class->lc_name, lock->lo_name, instance->li_flags & LI_RECURSEMASK, fixup_filename(file), line); } instance->li_flags |= LI_EXCLUSIVE; } void witness_downgrade(struct lock_object *lock, int flags, const char *file, int line) { struct lock_instance *instance; struct lock_class *class; KASSERT(witness_cold == 0, ("%s: witness_cold", __func__)); if (lock->lo_witness == NULL || witness_watch == -1 || panicstr != NULL) return; class = LOCK_CLASS(lock); if (witness_watch) { if ((lock->lo_flags & LO_UPGRADABLE) == 0) kassert_panic( "downgrade of non-upgradable lock (%s) %s @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); if ((class->lc_flags & LC_SLEEPLOCK) == 0) kassert_panic( "downgrade of non-sleep lock (%s) %s @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); } instance = find_instance(curthread->td_sleeplocks, lock); if (instance == NULL) { kassert_panic("downgrade of unlocked lock (%s) %s @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); return; } if (witness_watch) { if ((instance->li_flags & LI_EXCLUSIVE) == 0) kassert_panic( "downgrade of shared lock (%s) %s @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); if ((instance->li_flags & LI_RECURSEMASK) != 0) kassert_panic( "downgrade of recursed lock (%s) %s r=%d @ %s:%d", class->lc_name, lock->lo_name, instance->li_flags & LI_RECURSEMASK, fixup_filename(file), line); } instance->li_flags &= ~LI_EXCLUSIVE; } void witness_unlock(struct lock_object *lock, int flags, const char *file, int line) { struct lock_list_entry **lock_list, *lle; struct lock_instance *instance; struct lock_class *class; struct thread *td; register_t s; int i, j; if (witness_cold || lock->lo_witness == NULL || panicstr != NULL) return; td = curthread; class = LOCK_CLASS(lock); /* Find lock instance associated with this lock. */ if (class->lc_flags & LC_SLEEPLOCK) lock_list = &td->td_sleeplocks; else lock_list = PCPU_PTR(spinlocks); lle = *lock_list; for (; *lock_list != NULL; lock_list = &(*lock_list)->ll_next) for (i = 0; i < (*lock_list)->ll_count; i++) { instance = &(*lock_list)->ll_children[i]; if (instance->li_lock == lock) goto found; } /* * When disabling WITNESS through witness_watch we could end up in * having registered locks in the td_sleeplocks queue. * We have to make sure we flush these queues, so just search for * eventual register locks and remove them. */ if (witness_watch > 0) { kassert_panic("lock (%s) %s not locked @ %s:%d", class->lc_name, lock->lo_name, fixup_filename(file), line); return; } else { return; } found: /* First, check for shared/exclusive mismatches. */ if ((instance->li_flags & LI_EXCLUSIVE) != 0 && witness_watch > 0 && (flags & LOP_EXCLUSIVE) == 0) { witness_output("shared unlock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); witness_output("while exclusively locked from %s:%d\n", fixup_filename(instance->li_file), instance->li_line); kassert_panic("excl->ushare"); } if ((instance->li_flags & LI_EXCLUSIVE) == 0 && witness_watch > 0 && (flags & LOP_EXCLUSIVE) != 0) { witness_output("exclusive unlock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); witness_output("while share locked from %s:%d\n", fixup_filename(instance->li_file), instance->li_line); kassert_panic("share->uexcl"); } /* If we are recursed, unrecurse. */ if ((instance->li_flags & LI_RECURSEMASK) > 0) { CTR4(KTR_WITNESS, "%s: pid %d unrecursed on %s r=%d", __func__, td->td_proc->p_pid, instance->li_lock->lo_name, instance->li_flags); instance->li_flags--; return; } /* The lock is now being dropped, check for NORELEASE flag */ if ((instance->li_flags & LI_NORELEASE) != 0 && witness_watch > 0) { witness_output("forbidden unlock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); kassert_panic("lock marked norelease"); } /* Otherwise, remove this item from the list. */ s = intr_disable(); CTR4(KTR_WITNESS, "%s: pid %d removed %s from lle[%d]", __func__, td->td_proc->p_pid, instance->li_lock->lo_name, (*lock_list)->ll_count - 1); for (j = i; j < (*lock_list)->ll_count - 1; j++) (*lock_list)->ll_children[j] = (*lock_list)->ll_children[j + 1]; (*lock_list)->ll_count--; intr_restore(s); /* * In order to reduce contention on w_mtx, we want to keep always an * head object into lists so that frequent allocation from the * free witness pool (and subsequent locking) is avoided. * In order to maintain the current code simple, when the head * object is totally unloaded it means also that we do not have * further objects in the list, so the list ownership needs to be * hand over to another object if the current head needs to be freed. */ if ((*lock_list)->ll_count == 0) { if (*lock_list == lle) { if (lle->ll_next == NULL) return; } else lle = *lock_list; *lock_list = lle->ll_next; CTR3(KTR_WITNESS, "%s: pid %d removed lle %p", __func__, td->td_proc->p_pid, lle); witness_lock_list_free(lle); } } void witness_thread_exit(struct thread *td) { struct lock_list_entry *lle; int i, n; lle = td->td_sleeplocks; if (lle == NULL || panicstr != NULL) return; if (lle->ll_count != 0) { for (n = 0; lle != NULL; lle = lle->ll_next) for (i = lle->ll_count - 1; i >= 0; i--) { if (n == 0) witness_output( "Thread %p exiting with the following locks held:\n", td); n++; witness_list_lock(&lle->ll_children[i], witness_output); } kassert_panic( "Thread %p cannot exit while holding sleeplocks\n", td); } witness_lock_list_free(lle); } /* * Warn if any locks other than 'lock' are held. Flags can be passed in to * exempt Giant and sleepable locks from the checks as well. If any * non-exempt locks are held, then a supplied message is printed to the * output channel along with a list of the offending locks. If indicated in the * flags then a failure results in a panic as well. */ int witness_warn(int flags, struct lock_object *lock, const char *fmt, ...) { struct lock_list_entry *lock_list, *lle; struct lock_instance *lock1; struct thread *td; va_list ap; int i, n; if (witness_cold || witness_watch < 1 || panicstr != NULL) return (0); n = 0; td = curthread; for (lle = td->td_sleeplocks; lle != NULL; lle = lle->ll_next) for (i = lle->ll_count - 1; i >= 0; i--) { lock1 = &lle->ll_children[i]; if (lock1->li_lock == lock) continue; if (flags & WARN_GIANTOK && lock1->li_lock == &Giant.lock_object) continue; if (flags & WARN_SLEEPOK && (lock1->li_lock->lo_flags & LO_SLEEPABLE) != 0) continue; if (n == 0) { va_start(ap, fmt); - witness_voutput(fmt, ap); + vprintf(fmt, ap); va_end(ap); - witness_output( - " with the following %slocks held:\n", + printf(" with the following %slocks held:\n", (flags & WARN_SLEEPOK) != 0 ? "non-sleepable " : ""); } n++; - witness_list_lock(lock1, witness_output); + witness_list_lock(lock1, printf); } /* * Pin the thread in order to avoid problems with thread migration. * Once that all verifies are passed about spinlocks ownership, * the thread is in a safe path and it can be unpinned. */ sched_pin(); lock_list = PCPU_GET(spinlocks); if (lock_list != NULL && lock_list->ll_count != 0) { sched_unpin(); /* * We should only have one spinlock and as long as * the flags cannot match for this locks class, * check if the first spinlock is the one curthread * should hold. */ lock1 = &lock_list->ll_children[lock_list->ll_count - 1]; if (lock_list->ll_count == 1 && lock_list->ll_next == NULL && lock1->li_lock == lock && n == 0) return (0); va_start(ap, fmt); - witness_voutput(fmt, ap); + vprintf(fmt, ap); va_end(ap); - witness_output(" with the following %slocks held:\n", + printf(" with the following %slocks held:\n", (flags & WARN_SLEEPOK) != 0 ? "non-sleepable " : ""); - n += witness_list_locks(&lock_list, witness_output); + n += witness_list_locks(&lock_list, printf); } else sched_unpin(); if (flags & WARN_PANIC && n) kassert_panic("%s", __func__); else witness_debugger(n, __func__); return (n); } const char * witness_file(struct lock_object *lock) { struct witness *w; if (witness_cold || witness_watch < 1 || lock->lo_witness == NULL) return ("?"); w = lock->lo_witness; return (w->w_file); } int witness_line(struct lock_object *lock) { struct witness *w; if (witness_cold || witness_watch < 1 || lock->lo_witness == NULL) return (0); w = lock->lo_witness; return (w->w_line); } static struct witness * enroll(const char *description, struct lock_class *lock_class) { struct witness *w; struct witness_list *typelist; MPASS(description != NULL); if (witness_watch == -1 || panicstr != NULL) return (NULL); if ((lock_class->lc_flags & LC_SPINLOCK)) { if (witness_skipspin) return (NULL); else typelist = &w_spin; } else if ((lock_class->lc_flags & LC_SLEEPLOCK)) { typelist = &w_sleep; } else { kassert_panic("lock class %s is not sleep or spin", lock_class->lc_name); return (NULL); } mtx_lock_spin(&w_mtx); w = witness_hash_get(description); if (w) goto found; if ((w = witness_get()) == NULL) return (NULL); MPASS(strlen(description) < MAX_W_NAME); strcpy(w->w_name, description); w->w_class = lock_class; w->w_refcount = 1; STAILQ_INSERT_HEAD(&w_all, w, w_list); if (lock_class->lc_flags & LC_SPINLOCK) { STAILQ_INSERT_HEAD(&w_spin, w, w_typelist); w_spin_cnt++; } else if (lock_class->lc_flags & LC_SLEEPLOCK) { STAILQ_INSERT_HEAD(&w_sleep, w, w_typelist); w_sleep_cnt++; } /* Insert new witness into the hash */ witness_hash_put(w); witness_increment_graph_generation(); mtx_unlock_spin(&w_mtx); return (w); found: w->w_refcount++; mtx_unlock_spin(&w_mtx); if (lock_class != w->w_class) kassert_panic( "lock (%s) %s does not match earlier (%s) lock", description, lock_class->lc_name, w->w_class->lc_name); return (w); } static void depart(struct witness *w) { struct witness_list *list; MPASS(w->w_refcount == 0); if (w->w_class->lc_flags & LC_SLEEPLOCK) { list = &w_sleep; w_sleep_cnt--; } else { list = &w_spin; w_spin_cnt--; } /* * Set file to NULL as it may point into a loadable module. */ w->w_file = NULL; w->w_line = 0; witness_increment_graph_generation(); } static void adopt(struct witness *parent, struct witness *child) { int pi, ci, i, j; if (witness_cold == 0) mtx_assert(&w_mtx, MA_OWNED); /* If the relationship is already known, there's no work to be done. */ if (isitmychild(parent, child)) return; /* When the structure of the graph changes, bump up the generation. */ witness_increment_graph_generation(); /* * The hard part ... create the direct relationship, then propagate all * indirect relationships. */ pi = parent->w_index; ci = child->w_index; WITNESS_INDEX_ASSERT(pi); WITNESS_INDEX_ASSERT(ci); MPASS(pi != ci); w_rmatrix[pi][ci] |= WITNESS_PARENT; w_rmatrix[ci][pi] |= WITNESS_CHILD; /* * If parent was not already an ancestor of child, * then we increment the descendant and ancestor counters. */ if ((w_rmatrix[pi][ci] & WITNESS_ANCESTOR) == 0) { parent->w_num_descendants++; child->w_num_ancestors++; } /* * Find each ancestor of 'pi'. Note that 'pi' itself is counted as * an ancestor of 'pi' during this loop. */ for (i = 1; i <= w_max_used_index; i++) { if ((w_rmatrix[i][pi] & WITNESS_ANCESTOR_MASK) == 0 && (i != pi)) continue; /* Find each descendant of 'i' and mark it as a descendant. */ for (j = 1; j <= w_max_used_index; j++) { /* * Skip children that are already marked as * descendants of 'i'. */ if (w_rmatrix[i][j] & WITNESS_ANCESTOR_MASK) continue; /* * We are only interested in descendants of 'ci'. Note * that 'ci' itself is counted as a descendant of 'ci'. */ if ((w_rmatrix[ci][j] & WITNESS_ANCESTOR_MASK) == 0 && (j != ci)) continue; w_rmatrix[i][j] |= WITNESS_ANCESTOR; w_rmatrix[j][i] |= WITNESS_DESCENDANT; w_data[i].w_num_descendants++; w_data[j].w_num_ancestors++; /* * Make sure we aren't marking a node as both an * ancestor and descendant. We should have caught * this as a lock order reversal earlier. */ if ((w_rmatrix[i][j] & WITNESS_ANCESTOR_MASK) && (w_rmatrix[i][j] & WITNESS_DESCENDANT_MASK)) { printf("witness rmatrix paradox! [%d][%d]=%d " "both ancestor and descendant\n", i, j, w_rmatrix[i][j]); kdb_backtrace(); printf("Witness disabled.\n"); witness_watch = -1; } if ((w_rmatrix[j][i] & WITNESS_ANCESTOR_MASK) && (w_rmatrix[j][i] & WITNESS_DESCENDANT_MASK)) { printf("witness rmatrix paradox! [%d][%d]=%d " "both ancestor and descendant\n", j, i, w_rmatrix[j][i]); kdb_backtrace(); printf("Witness disabled.\n"); witness_watch = -1; } } } } static void itismychild(struct witness *parent, struct witness *child) { int unlocked; MPASS(child != NULL && parent != NULL); if (witness_cold == 0) mtx_assert(&w_mtx, MA_OWNED); if (!witness_lock_type_equal(parent, child)) { if (witness_cold == 0) { unlocked = 1; mtx_unlock_spin(&w_mtx); } else { unlocked = 0; } kassert_panic( "%s: parent \"%s\" (%s) and child \"%s\" (%s) are not " "the same lock type", __func__, parent->w_name, parent->w_class->lc_name, child->w_name, child->w_class->lc_name); if (unlocked) mtx_lock_spin(&w_mtx); } adopt(parent, child); } /* * Generic code for the isitmy*() functions. The rmask parameter is the * expected relationship of w1 to w2. */ static int _isitmyx(struct witness *w1, struct witness *w2, int rmask, const char *fname) { unsigned char r1, r2; int i1, i2; i1 = w1->w_index; i2 = w2->w_index; WITNESS_INDEX_ASSERT(i1); WITNESS_INDEX_ASSERT(i2); r1 = w_rmatrix[i1][i2] & WITNESS_RELATED_MASK; r2 = w_rmatrix[i2][i1] & WITNESS_RELATED_MASK; /* The flags on one better be the inverse of the flags on the other */ if (!((WITNESS_ATOD(r1) == r2 && WITNESS_DTOA(r2) == r1) || (WITNESS_DTOA(r1) == r2 && WITNESS_ATOD(r2) == r1))) { /* Don't squawk if we're potentially racing with an update. */ if (!mtx_owned(&w_mtx)) return (0); printf("%s: rmatrix mismatch between %s (index %d) and %s " "(index %d): w_rmatrix[%d][%d] == %hhx but " "w_rmatrix[%d][%d] == %hhx\n", fname, w1->w_name, i1, w2->w_name, i2, i1, i2, r1, i2, i1, r2); kdb_backtrace(); printf("Witness disabled.\n"); witness_watch = -1; } return (r1 & rmask); } /* * Checks if @child is a direct child of @parent. */ static int isitmychild(struct witness *parent, struct witness *child) { return (_isitmyx(parent, child, WITNESS_PARENT, __func__)); } /* * Checks if @descendant is a direct or inderect descendant of @ancestor. */ static int isitmydescendant(struct witness *ancestor, struct witness *descendant) { return (_isitmyx(ancestor, descendant, WITNESS_ANCESTOR_MASK, __func__)); } #ifdef BLESSING static int blessed(struct witness *w1, struct witness *w2) { int i; struct witness_blessed *b; for (i = 0; i < nitems(blessed_list); i++) { b = &blessed_list[i]; if (strcmp(w1->w_name, b->b_lock1) == 0) { if (strcmp(w2->w_name, b->b_lock2) == 0) return (1); continue; } if (strcmp(w1->w_name, b->b_lock2) == 0) if (strcmp(w2->w_name, b->b_lock1) == 0) return (1); } return (0); } #endif static struct witness * witness_get(void) { struct witness *w; int index; if (witness_cold == 0) mtx_assert(&w_mtx, MA_OWNED); if (witness_watch == -1) { mtx_unlock_spin(&w_mtx); return (NULL); } if (STAILQ_EMPTY(&w_free)) { witness_watch = -1; mtx_unlock_spin(&w_mtx); printf("WITNESS: unable to allocate a new witness object\n"); return (NULL); } w = STAILQ_FIRST(&w_free); STAILQ_REMOVE_HEAD(&w_free, w_list); w_free_cnt--; index = w->w_index; MPASS(index > 0 && index == w_max_used_index+1 && index < witness_count); bzero(w, sizeof(*w)); w->w_index = index; if (index > w_max_used_index) w_max_used_index = index; return (w); } static void witness_free(struct witness *w) { STAILQ_INSERT_HEAD(&w_free, w, w_list); w_free_cnt++; } static struct lock_list_entry * witness_lock_list_get(void) { struct lock_list_entry *lle; if (witness_watch == -1) return (NULL); mtx_lock_spin(&w_mtx); lle = w_lock_list_free; if (lle == NULL) { witness_watch = -1; mtx_unlock_spin(&w_mtx); printf("%s: witness exhausted\n", __func__); return (NULL); } w_lock_list_free = lle->ll_next; mtx_unlock_spin(&w_mtx); bzero(lle, sizeof(*lle)); return (lle); } static void witness_lock_list_free(struct lock_list_entry *lle) { mtx_lock_spin(&w_mtx); lle->ll_next = w_lock_list_free; w_lock_list_free = lle; mtx_unlock_spin(&w_mtx); } static struct lock_instance * find_instance(struct lock_list_entry *list, const struct lock_object *lock) { struct lock_list_entry *lle; struct lock_instance *instance; int i; for (lle = list; lle != NULL; lle = lle->ll_next) for (i = lle->ll_count - 1; i >= 0; i--) { instance = &lle->ll_children[i]; if (instance->li_lock == lock) return (instance); } return (NULL); } static void witness_list_lock(struct lock_instance *instance, int (*prnt)(const char *fmt, ...)) { struct lock_object *lock; lock = instance->li_lock; prnt("%s %s %s", (instance->li_flags & LI_EXCLUSIVE) != 0 ? "exclusive" : "shared", LOCK_CLASS(lock)->lc_name, lock->lo_name); if (lock->lo_witness->w_name != lock->lo_name) prnt(" (%s)", lock->lo_witness->w_name); prnt(" r = %d (%p) locked @ %s:%d\n", instance->li_flags & LI_RECURSEMASK, lock, fixup_filename(instance->li_file), instance->li_line); } static int witness_output(const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = witness_voutput(fmt, ap); va_end(ap); return (ret); } static int witness_voutput(const char *fmt, va_list ap) { int ret; ret = 0; switch (witness_channel) { case WITNESS_CONSOLE: ret = vprintf(fmt, ap); break; case WITNESS_LOG: vlog(LOG_NOTICE, fmt, ap); break; case WITNESS_NONE: break; } return (ret); } #ifdef DDB static int witness_thread_has_locks(struct thread *td) { if (td->td_sleeplocks == NULL) return (0); return (td->td_sleeplocks->ll_count != 0); } static int witness_proc_has_locks(struct proc *p) { struct thread *td; FOREACH_THREAD_IN_PROC(p, td) { if (witness_thread_has_locks(td)) return (1); } return (0); } #endif int witness_list_locks(struct lock_list_entry **lock_list, int (*prnt)(const char *fmt, ...)) { struct lock_list_entry *lle; int i, nheld; nheld = 0; for (lle = *lock_list; lle != NULL; lle = lle->ll_next) for (i = lle->ll_count - 1; i >= 0; i--) { witness_list_lock(&lle->ll_children[i], prnt); nheld++; } return (nheld); } /* * This is a bit risky at best. We call this function when we have timed * out acquiring a spin lock, and we assume that the other CPU is stuck * with this lock held. So, we go groveling around in the other CPU's * per-cpu data to try to find the lock instance for this spin lock to * see when it was last acquired. */ void witness_display_spinlock(struct lock_object *lock, struct thread *owner, int (*prnt)(const char *fmt, ...)) { struct lock_instance *instance; struct pcpu *pc; if (owner->td_critnest == 0 || owner->td_oncpu == NOCPU) return; pc = pcpu_find(owner->td_oncpu); instance = find_instance(pc->pc_spinlocks, lock); if (instance != NULL) witness_list_lock(instance, prnt); } void witness_save(struct lock_object *lock, const char **filep, int *linep) { struct lock_list_entry *lock_list; struct lock_instance *instance; struct lock_class *class; /* * This function is used independently in locking code to deal with * Giant, SCHEDULER_STOPPED() check can be removed here after Giant * is gone. */ if (SCHEDULER_STOPPED()) return; KASSERT(witness_cold == 0, ("%s: witness_cold", __func__)); if (lock->lo_witness == NULL || witness_watch == -1 || panicstr != NULL) return; class = LOCK_CLASS(lock); if (class->lc_flags & LC_SLEEPLOCK) lock_list = curthread->td_sleeplocks; else { if (witness_skipspin) return; lock_list = PCPU_GET(spinlocks); } instance = find_instance(lock_list, lock); if (instance == NULL) { kassert_panic("%s: lock (%s) %s not locked", __func__, class->lc_name, lock->lo_name); return; } *filep = instance->li_file; *linep = instance->li_line; } void witness_restore(struct lock_object *lock, const char *file, int line) { struct lock_list_entry *lock_list; struct lock_instance *instance; struct lock_class *class; /* * This function is used independently in locking code to deal with * Giant, SCHEDULER_STOPPED() check can be removed here after Giant * is gone. */ if (SCHEDULER_STOPPED()) return; KASSERT(witness_cold == 0, ("%s: witness_cold", __func__)); if (lock->lo_witness == NULL || witness_watch == -1 || panicstr != NULL) return; class = LOCK_CLASS(lock); if (class->lc_flags & LC_SLEEPLOCK) lock_list = curthread->td_sleeplocks; else { if (witness_skipspin) return; lock_list = PCPU_GET(spinlocks); } instance = find_instance(lock_list, lock); if (instance == NULL) kassert_panic("%s: lock (%s) %s not locked", __func__, class->lc_name, lock->lo_name); lock->lo_witness->w_file = file; lock->lo_witness->w_line = line; if (instance == NULL) return; instance->li_file = file; instance->li_line = line; } void witness_assert(const struct lock_object *lock, int flags, const char *file, int line) { #ifdef INVARIANT_SUPPORT struct lock_instance *instance; struct lock_class *class; if (lock->lo_witness == NULL || witness_watch < 1 || panicstr != NULL) return; class = LOCK_CLASS(lock); if ((class->lc_flags & LC_SLEEPLOCK) != 0) instance = find_instance(curthread->td_sleeplocks, lock); else if ((class->lc_flags & LC_SPINLOCK) != 0) instance = find_instance(PCPU_GET(spinlocks), lock); else { kassert_panic("Lock (%s) %s is not sleep or spin!", class->lc_name, lock->lo_name); return; } switch (flags) { case LA_UNLOCKED: if (instance != NULL) kassert_panic("Lock (%s) %s locked @ %s:%d.", class->lc_name, lock->lo_name, fixup_filename(file), line); break; case LA_LOCKED: case LA_LOCKED | LA_RECURSED: case LA_LOCKED | LA_NOTRECURSED: case LA_SLOCKED: case LA_SLOCKED | LA_RECURSED: case LA_SLOCKED | LA_NOTRECURSED: case LA_XLOCKED: case LA_XLOCKED | LA_RECURSED: case LA_XLOCKED | LA_NOTRECURSED: if (instance == NULL) { kassert_panic("Lock (%s) %s not locked @ %s:%d.", class->lc_name, lock->lo_name, fixup_filename(file), line); break; } if ((flags & LA_XLOCKED) != 0 && (instance->li_flags & LI_EXCLUSIVE) == 0) kassert_panic( "Lock (%s) %s not exclusively locked @ %s:%d.", class->lc_name, lock->lo_name, fixup_filename(file), line); if ((flags & LA_SLOCKED) != 0 && (instance->li_flags & LI_EXCLUSIVE) != 0) kassert_panic( "Lock (%s) %s exclusively locked @ %s:%d.", class->lc_name, lock->lo_name, fixup_filename(file), line); if ((flags & LA_RECURSED) != 0 && (instance->li_flags & LI_RECURSEMASK) == 0) kassert_panic("Lock (%s) %s not recursed @ %s:%d.", class->lc_name, lock->lo_name, fixup_filename(file), line); if ((flags & LA_NOTRECURSED) != 0 && (instance->li_flags & LI_RECURSEMASK) != 0) kassert_panic("Lock (%s) %s recursed @ %s:%d.", class->lc_name, lock->lo_name, fixup_filename(file), line); break; default: kassert_panic("Invalid lock assertion at %s:%d.", fixup_filename(file), line); } #endif /* INVARIANT_SUPPORT */ } static void witness_setflag(struct lock_object *lock, int flag, int set) { struct lock_list_entry *lock_list; struct lock_instance *instance; struct lock_class *class; if (lock->lo_witness == NULL || witness_watch == -1 || panicstr != NULL) return; class = LOCK_CLASS(lock); if (class->lc_flags & LC_SLEEPLOCK) lock_list = curthread->td_sleeplocks; else { if (witness_skipspin) return; lock_list = PCPU_GET(spinlocks); } instance = find_instance(lock_list, lock); if (instance == NULL) { kassert_panic("%s: lock (%s) %s not locked", __func__, class->lc_name, lock->lo_name); return; } if (set) instance->li_flags |= flag; else instance->li_flags &= ~flag; } void witness_norelease(struct lock_object *lock) { witness_setflag(lock, LI_NORELEASE, 1); } void witness_releaseok(struct lock_object *lock) { witness_setflag(lock, LI_NORELEASE, 0); } #ifdef DDB static void witness_ddb_list(struct thread *td) { KASSERT(witness_cold == 0, ("%s: witness_cold", __func__)); KASSERT(kdb_active, ("%s: not in the debugger", __func__)); if (witness_watch < 1) return; witness_list_locks(&td->td_sleeplocks, db_printf); /* * We only handle spinlocks if td == curthread. This is somewhat broken * if td is currently executing on some other CPU and holds spin locks * as we won't display those locks. If we had a MI way of getting * the per-cpu data for a given cpu then we could use * td->td_oncpu to get the list of spinlocks for this thread * and "fix" this. * * That still wouldn't really fix this unless we locked the scheduler * lock or stopped the other CPU to make sure it wasn't changing the * list out from under us. It is probably best to just not try to * handle threads on other CPU's for now. */ if (td == curthread && PCPU_GET(spinlocks) != NULL) witness_list_locks(PCPU_PTR(spinlocks), db_printf); } DB_SHOW_COMMAND(locks, db_witness_list) { struct thread *td; if (have_addr) td = db_lookup_thread(addr, true); else td = kdb_thread; witness_ddb_list(td); } DB_SHOW_ALL_COMMAND(locks, db_witness_list_all) { struct thread *td; struct proc *p; /* * It would be nice to list only threads and processes that actually * held sleep locks, but that information is currently not exported * by WITNESS. */ FOREACH_PROC_IN_SYSTEM(p) { if (!witness_proc_has_locks(p)) continue; FOREACH_THREAD_IN_PROC(p, td) { if (!witness_thread_has_locks(td)) continue; db_printf("Process %d (%s) thread %p (%d)\n", p->p_pid, p->p_comm, td, td->td_tid); witness_ddb_list(td); if (db_pager_quit) return; } } } DB_SHOW_ALIAS(alllocks, db_witness_list_all) DB_SHOW_COMMAND(witness, db_witness_display) { witness_ddb_display(db_printf); } #endif static int sysctl_debug_witness_badstacks(SYSCTL_HANDLER_ARGS) { struct witness_lock_order_data *data1, *data2, *tmp_data1, *tmp_data2; struct witness *tmp_w1, *tmp_w2, *w1, *w2; struct sbuf *sb; u_int w_rmatrix1, w_rmatrix2; int error, generation, i, j; tmp_data1 = NULL; tmp_data2 = NULL; tmp_w1 = NULL; tmp_w2 = NULL; if (witness_watch < 1) { error = SYSCTL_OUT(req, w_notrunning, sizeof(w_notrunning)); return (error); } if (witness_cold) { error = SYSCTL_OUT(req, w_stillcold, sizeof(w_stillcold)); return (error); } error = 0; sb = sbuf_new(NULL, NULL, badstack_sbuf_size, SBUF_AUTOEXTEND); if (sb == NULL) return (ENOMEM); /* Allocate and init temporary storage space. */ tmp_w1 = malloc(sizeof(struct witness), M_TEMP, M_WAITOK | M_ZERO); tmp_w2 = malloc(sizeof(struct witness), M_TEMP, M_WAITOK | M_ZERO); tmp_data1 = malloc(sizeof(struct witness_lock_order_data), M_TEMP, M_WAITOK | M_ZERO); tmp_data2 = malloc(sizeof(struct witness_lock_order_data), M_TEMP, M_WAITOK | M_ZERO); stack_zero(&tmp_data1->wlod_stack); stack_zero(&tmp_data2->wlod_stack); restart: mtx_lock_spin(&w_mtx); generation = w_generation; mtx_unlock_spin(&w_mtx); sbuf_printf(sb, "Number of known direct relationships is %d\n", w_lohash.wloh_count); for (i = 1; i < w_max_used_index; i++) { mtx_lock_spin(&w_mtx); if (generation != w_generation) { mtx_unlock_spin(&w_mtx); /* The graph has changed, try again. */ req->oldidx = 0; sbuf_clear(sb); goto restart; } w1 = &w_data[i]; if (w1->w_reversed == 0) { mtx_unlock_spin(&w_mtx); continue; } /* Copy w1 locally so we can release the spin lock. */ *tmp_w1 = *w1; mtx_unlock_spin(&w_mtx); if (tmp_w1->w_reversed == 0) continue; for (j = 1; j < w_max_used_index; j++) { if ((w_rmatrix[i][j] & WITNESS_REVERSAL) == 0 || i > j) continue; mtx_lock_spin(&w_mtx); if (generation != w_generation) { mtx_unlock_spin(&w_mtx); /* The graph has changed, try again. */ req->oldidx = 0; sbuf_clear(sb); goto restart; } w2 = &w_data[j]; data1 = witness_lock_order_get(w1, w2); data2 = witness_lock_order_get(w2, w1); /* * Copy information locally so we can release the * spin lock. */ *tmp_w2 = *w2; w_rmatrix1 = (unsigned int)w_rmatrix[i][j]; w_rmatrix2 = (unsigned int)w_rmatrix[j][i]; if (data1) { stack_zero(&tmp_data1->wlod_stack); stack_copy(&data1->wlod_stack, &tmp_data1->wlod_stack); } if (data2 && data2 != data1) { stack_zero(&tmp_data2->wlod_stack); stack_copy(&data2->wlod_stack, &tmp_data2->wlod_stack); } mtx_unlock_spin(&w_mtx); sbuf_printf(sb, "\nLock order reversal between \"%s\"(%s) and \"%s\"(%s)!\n", tmp_w1->w_name, tmp_w1->w_class->lc_name, tmp_w2->w_name, tmp_w2->w_class->lc_name); if (data1) { sbuf_printf(sb, "Lock order \"%s\"(%s) -> \"%s\"(%s) first seen at:\n", tmp_w1->w_name, tmp_w1->w_class->lc_name, tmp_w2->w_name, tmp_w2->w_class->lc_name); stack_sbuf_print(sb, &tmp_data1->wlod_stack); sbuf_printf(sb, "\n"); } if (data2 && data2 != data1) { sbuf_printf(sb, "Lock order \"%s\"(%s) -> \"%s\"(%s) first seen at:\n", tmp_w2->w_name, tmp_w2->w_class->lc_name, tmp_w1->w_name, tmp_w1->w_class->lc_name); stack_sbuf_print(sb, &tmp_data2->wlod_stack); sbuf_printf(sb, "\n"); } } } mtx_lock_spin(&w_mtx); if (generation != w_generation) { mtx_unlock_spin(&w_mtx); /* * The graph changed while we were printing stack data, * try again. */ req->oldidx = 0; sbuf_clear(sb); goto restart; } mtx_unlock_spin(&w_mtx); /* Free temporary storage space. */ free(tmp_data1, M_TEMP); free(tmp_data2, M_TEMP); free(tmp_w1, M_TEMP); free(tmp_w2, M_TEMP); sbuf_finish(sb); error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); sbuf_delete(sb); return (error); } static int sysctl_debug_witness_channel(SYSCTL_HANDLER_ARGS) { static const struct { enum witness_channel channel; const char *name; } channels[] = { { WITNESS_CONSOLE, "console" }, { WITNESS_LOG, "log" }, { WITNESS_NONE, "none" }, }; char buf[16]; u_int i; int error; buf[0] = '\0'; for (i = 0; i < nitems(channels); i++) if (witness_channel == channels[i].channel) { snprintf(buf, sizeof(buf), "%s", channels[i].name); break; } error = sysctl_handle_string(oidp, buf, sizeof(buf), req); if (error != 0 || req->newptr == NULL) return (error); error = EINVAL; for (i = 0; i < nitems(channels); i++) if (strcmp(channels[i].name, buf) == 0) { witness_channel = channels[i].channel; error = 0; break; } return (error); } static int sysctl_debug_witness_fullgraph(SYSCTL_HANDLER_ARGS) { struct witness *w; struct sbuf *sb; int error; if (witness_watch < 1) { error = SYSCTL_OUT(req, w_notrunning, sizeof(w_notrunning)); return (error); } if (witness_cold) { error = SYSCTL_OUT(req, w_stillcold, sizeof(w_stillcold)); return (error); } error = 0; error = sysctl_wire_old_buffer(req, 0); if (error != 0) return (error); sb = sbuf_new_for_sysctl(NULL, NULL, FULLGRAPH_SBUF_SIZE, req); if (sb == NULL) return (ENOMEM); sbuf_printf(sb, "\n"); mtx_lock_spin(&w_mtx); STAILQ_FOREACH(w, &w_all, w_list) w->w_displayed = 0; STAILQ_FOREACH(w, &w_all, w_list) witness_add_fullgraph(sb, w); mtx_unlock_spin(&w_mtx); /* * Close the sbuf and return to userland. */ error = sbuf_finish(sb); sbuf_delete(sb); return (error); } static int sysctl_debug_witness_watch(SYSCTL_HANDLER_ARGS) { int error, value; value = witness_watch; error = sysctl_handle_int(oidp, &value, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (value > 1 || value < -1 || (witness_watch == -1 && value != witness_watch)) return (EINVAL); witness_watch = value; return (0); } static void witness_add_fullgraph(struct sbuf *sb, struct witness *w) { int i; if (w->w_displayed != 0 || (w->w_file == NULL && w->w_line == 0)) return; w->w_displayed = 1; WITNESS_INDEX_ASSERT(w->w_index); for (i = 1; i <= w_max_used_index; i++) { if (w_rmatrix[w->w_index][i] & WITNESS_PARENT) { sbuf_printf(sb, "\"%s\",\"%s\"\n", w->w_name, w_data[i].w_name); witness_add_fullgraph(sb, &w_data[i]); } } } /* * A simple hash function. Takes a key pointer and a key size. If size == 0, * interprets the key as a string and reads until the null * terminator. Otherwise, reads the first size bytes. Returns an unsigned 32-bit * hash value computed from the key. */ static uint32_t witness_hash_djb2(const uint8_t *key, uint32_t size) { unsigned int hash = 5381; int i; /* hash = hash * 33 + key[i] */ if (size) for (i = 0; i < size; i++) hash = ((hash << 5) + hash) + (unsigned int)key[i]; else for (i = 0; key[i] != 0; i++) hash = ((hash << 5) + hash) + (unsigned int)key[i]; return (hash); } /* * Initializes the two witness hash tables. Called exactly once from * witness_initialize(). */ static void witness_init_hash_tables(void) { int i; MPASS(witness_cold); /* Initialize the hash tables. */ for (i = 0; i < WITNESS_HASH_SIZE; i++) w_hash.wh_array[i] = NULL; w_hash.wh_size = WITNESS_HASH_SIZE; w_hash.wh_count = 0; /* Initialize the lock order data hash. */ w_lofree = NULL; for (i = 0; i < WITNESS_LO_DATA_COUNT; i++) { memset(&w_lodata[i], 0, sizeof(w_lodata[i])); w_lodata[i].wlod_next = w_lofree; w_lofree = &w_lodata[i]; } w_lohash.wloh_size = WITNESS_LO_HASH_SIZE; w_lohash.wloh_count = 0; for (i = 0; i < WITNESS_LO_HASH_SIZE; i++) w_lohash.wloh_array[i] = NULL; } static struct witness * witness_hash_get(const char *key) { struct witness *w; uint32_t hash; MPASS(key != NULL); if (witness_cold == 0) mtx_assert(&w_mtx, MA_OWNED); hash = witness_hash_djb2(key, 0) % w_hash.wh_size; w = w_hash.wh_array[hash]; while (w != NULL) { if (strcmp(w->w_name, key) == 0) goto out; w = w->w_hash_next; } out: return (w); } static void witness_hash_put(struct witness *w) { uint32_t hash; MPASS(w != NULL); MPASS(w->w_name != NULL); if (witness_cold == 0) mtx_assert(&w_mtx, MA_OWNED); KASSERT(witness_hash_get(w->w_name) == NULL, ("%s: trying to add a hash entry that already exists!", __func__)); KASSERT(w->w_hash_next == NULL, ("%s: w->w_hash_next != NULL", __func__)); hash = witness_hash_djb2(w->w_name, 0) % w_hash.wh_size; w->w_hash_next = w_hash.wh_array[hash]; w_hash.wh_array[hash] = w; w_hash.wh_count++; } static struct witness_lock_order_data * witness_lock_order_get(struct witness *parent, struct witness *child) { struct witness_lock_order_data *data = NULL; struct witness_lock_order_key key; unsigned int hash; MPASS(parent != NULL && child != NULL); key.from = parent->w_index; key.to = child->w_index; WITNESS_INDEX_ASSERT(key.from); WITNESS_INDEX_ASSERT(key.to); if ((w_rmatrix[parent->w_index][child->w_index] & WITNESS_LOCK_ORDER_KNOWN) == 0) goto out; hash = witness_hash_djb2((const char*)&key, sizeof(key)) % w_lohash.wloh_size; data = w_lohash.wloh_array[hash]; while (data != NULL) { if (witness_lock_order_key_equal(&data->wlod_key, &key)) break; data = data->wlod_next; } out: return (data); } /* * Verify that parent and child have a known relationship, are not the same, * and child is actually a child of parent. This is done without w_mtx * to avoid contention in the common case. */ static int witness_lock_order_check(struct witness *parent, struct witness *child) { if (parent != child && w_rmatrix[parent->w_index][child->w_index] & WITNESS_LOCK_ORDER_KNOWN && isitmychild(parent, child)) return (1); return (0); } static int witness_lock_order_add(struct witness *parent, struct witness *child) { struct witness_lock_order_data *data = NULL; struct witness_lock_order_key key; unsigned int hash; MPASS(parent != NULL && child != NULL); key.from = parent->w_index; key.to = child->w_index; WITNESS_INDEX_ASSERT(key.from); WITNESS_INDEX_ASSERT(key.to); if (w_rmatrix[parent->w_index][child->w_index] & WITNESS_LOCK_ORDER_KNOWN) return (1); hash = witness_hash_djb2((const char*)&key, sizeof(key)) % w_lohash.wloh_size; w_rmatrix[parent->w_index][child->w_index] |= WITNESS_LOCK_ORDER_KNOWN; data = w_lofree; if (data == NULL) return (0); w_lofree = data->wlod_next; data->wlod_next = w_lohash.wloh_array[hash]; data->wlod_key = key; w_lohash.wloh_array[hash] = data; w_lohash.wloh_count++; stack_zero(&data->wlod_stack); stack_save(&data->wlod_stack); return (1); } /* Call this whenever the structure of the witness graph changes. */ static void witness_increment_graph_generation(void) { if (witness_cold == 0) mtx_assert(&w_mtx, MA_OWNED); w_generation++; } static int witness_output_drain(void *arg __unused, const char *data, int len) { witness_output("%.*s", len, data); return (len); } static void witness_debugger(int cond, const char *msg) { char buf[32]; struct sbuf sb; struct stack st; if (!cond) return; if (witness_trace) { sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); sbuf_set_drain(&sb, witness_output_drain, NULL); stack_zero(&st); stack_save(&st); witness_output("stack backtrace:\n"); stack_sbuf_print_ddb(&sb, &st); sbuf_finish(&sb); } #ifdef KDB if (witness_kdb) kdb_enter(KDB_WHY_WITNESS, msg); #endif } Index: projects/ipsec/sys/kern/vfs_subr.c =================================================================== --- projects/ipsec/sys/kern/vfs_subr.c (revision 313312) +++ projects/ipsec/sys/kern/vfs_subr.c (revision 313313) @@ -1,5456 +1,5456 @@ /*- * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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 University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 */ /* * External virtual filesystem routines */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_ddb.h" #include "opt_watchdog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DDB #include #endif static void delmntque(struct vnode *vp); static int flushbuflist(struct bufv *bufv, int flags, struct bufobj *bo, int slpflag, int slptimeo); static void syncer_shutdown(void *arg, int howto); static int vtryrecycle(struct vnode *vp); static void v_init_counters(struct vnode *); static void v_incr_usecount(struct vnode *); static void v_incr_usecount_locked(struct vnode *); static void v_incr_devcount(struct vnode *); static void v_decr_devcount(struct vnode *); static void vgonel(struct vnode *); static void vfs_knllock(void *arg); static void vfs_knlunlock(void *arg); static void vfs_knl_assert_locked(void *arg); static void vfs_knl_assert_unlocked(void *arg); static void vnlru_return_batches(struct vfsops *mnt_op); static void destroy_vpollinfo(struct vpollinfo *vi); /* * Number of vnodes in existence. Increased whenever getnewvnode() * allocates a new vnode, decreased in vdropl() for VI_DOOMED vnode. */ static unsigned long numvnodes; SYSCTL_ULONG(_vfs, OID_AUTO, numvnodes, CTLFLAG_RD, &numvnodes, 0, "Number of vnodes in existence"); static counter_u64_t vnodes_created; SYSCTL_COUNTER_U64(_vfs, OID_AUTO, vnodes_created, CTLFLAG_RD, &vnodes_created, "Number of vnodes created by getnewvnode"); static u_long mnt_free_list_batch = 128; SYSCTL_ULONG(_vfs, OID_AUTO, mnt_free_list_batch, CTLFLAG_RW, &mnt_free_list_batch, 0, "Limit of vnodes held on mnt's free list"); /* * Conversion tables for conversion from vnode types to inode formats * and back. */ enum vtype iftovt_tab[16] = { VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, }; int vttoif_tab[10] = { 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, S_IFMT, S_IFMT }; /* * List of vnodes that are ready for recycling. */ static TAILQ_HEAD(freelst, vnode) vnode_free_list; /* * "Free" vnode target. Free vnodes are rarely completely free, but are * just ones that are cheap to recycle. Usually they are for files which * have been stat'd but not read; these usually have inode and namecache * data attached to them. This target is the preferred minimum size of a * sub-cache consisting mostly of such files. The system balances the size * of this sub-cache with its complement to try to prevent either from * thrashing while the other is relatively inactive. The targets express * a preference for the best balance. * * "Above" this target there are 2 further targets (watermarks) related * to recyling of free vnodes. In the best-operating case, the cache is * exactly full, the free list has size between vlowat and vhiwat above the * free target, and recycling from it and normal use maintains this state. * Sometimes the free list is below vlowat or even empty, but this state * is even better for immediate use provided the cache is not full. * Otherwise, vnlru_proc() runs to reclaim enough vnodes (usually non-free * ones) to reach one of these states. The watermarks are currently hard- * coded as 4% and 9% of the available space higher. These and the default * of 25% for wantfreevnodes are too large if the memory size is large. * E.g., 9% of 75% of MAXVNODES is more than 566000 vnodes to reclaim * whenever vnlru_proc() becomes active. */ static u_long wantfreevnodes; SYSCTL_ULONG(_vfs, OID_AUTO, wantfreevnodes, CTLFLAG_RW, &wantfreevnodes, 0, "Target for minimum number of \"free\" vnodes"); static u_long freevnodes; SYSCTL_ULONG(_vfs, OID_AUTO, freevnodes, CTLFLAG_RD, &freevnodes, 0, "Number of \"free\" vnodes"); static counter_u64_t recycles_count; SYSCTL_COUNTER_U64(_vfs, OID_AUTO, recycles, CTLFLAG_RD, &recycles_count, "Number of vnodes recycled to meet vnode cache targets"); /* * Various variables used for debugging the new implementation of * reassignbuf(). * XXX these are probably of (very) limited utility now. */ static int reassignbufcalls; SYSCTL_INT(_vfs, OID_AUTO, reassignbufcalls, CTLFLAG_RW, &reassignbufcalls, 0, "Number of calls to reassignbuf"); static counter_u64_t free_owe_inact; SYSCTL_COUNTER_U64(_vfs, OID_AUTO, free_owe_inact, CTLFLAG_RD, &free_owe_inact, "Number of times free vnodes kept on active list due to VFS " "owing inactivation"); /* To keep more than one thread at a time from running vfs_getnewfsid */ static struct mtx mntid_mtx; /* * Lock for any access to the following: * vnode_free_list * numvnodes * freevnodes */ static struct mtx vnode_free_list_mtx; /* Publicly exported FS */ struct nfs_public nfs_pub; static uma_zone_t buf_trie_zone; /* Zone for allocation of new vnodes - used exclusively by getnewvnode() */ static uma_zone_t vnode_zone; static uma_zone_t vnodepoll_zone; /* * The workitem queue. * * It is useful to delay writes of file data and filesystem metadata * for tens of seconds so that quickly created and deleted files need * not waste disk bandwidth being created and removed. To realize this, * we append vnodes to a "workitem" queue. When running with a soft * updates implementation, most pending metadata dependencies should * not wait for more than a few seconds. Thus, mounted on block devices * are delayed only about a half the time that file data is delayed. * Similarly, directory updates are more critical, so are only delayed * about a third the time that file data is delayed. Thus, there are * SYNCER_MAXDELAY queues that are processed round-robin at a rate of * one each second (driven off the filesystem syncer process). The * syncer_delayno variable indicates the next queue that is to be processed. * Items that need to be processed soon are placed in this queue: * * syncer_workitem_pending[syncer_delayno] * * A delay of fifteen seconds is done by placing the request fifteen * entries later in the queue: * * syncer_workitem_pending[(syncer_delayno + 15) & syncer_mask] * */ static int syncer_delayno; static long syncer_mask; LIST_HEAD(synclist, bufobj); static struct synclist *syncer_workitem_pending; /* * The sync_mtx protects: * bo->bo_synclist * sync_vnode_count * syncer_delayno * syncer_state * syncer_workitem_pending * syncer_worklist_len * rushjob */ static struct mtx sync_mtx; static struct cv sync_wakeup; #define SYNCER_MAXDELAY 32 static int syncer_maxdelay = SYNCER_MAXDELAY; /* maximum delay time */ static int syncdelay = 30; /* max time to delay syncing data */ static int filedelay = 30; /* time to delay syncing files */ SYSCTL_INT(_kern, OID_AUTO, filedelay, CTLFLAG_RW, &filedelay, 0, "Time to delay syncing files (in seconds)"); static int dirdelay = 29; /* time to delay syncing directories */ SYSCTL_INT(_kern, OID_AUTO, dirdelay, CTLFLAG_RW, &dirdelay, 0, "Time to delay syncing directories (in seconds)"); static int metadelay = 28; /* time to delay syncing metadata */ SYSCTL_INT(_kern, OID_AUTO, metadelay, CTLFLAG_RW, &metadelay, 0, "Time to delay syncing metadata (in seconds)"); static int rushjob; /* number of slots to run ASAP */ static int stat_rush_requests; /* number of times I/O speeded up */ SYSCTL_INT(_debug, OID_AUTO, rush_requests, CTLFLAG_RW, &stat_rush_requests, 0, "Number of times I/O speeded up (rush requests)"); /* * When shutting down the syncer, run it at four times normal speed. */ #define SYNCER_SHUTDOWN_SPEEDUP 4 static int sync_vnode_count; static int syncer_worklist_len; static enum { SYNCER_RUNNING, SYNCER_SHUTTING_DOWN, SYNCER_FINAL_DELAY } syncer_state; /* Target for maximum number of vnodes. */ int desiredvnodes; static int gapvnodes; /* gap between wanted and desired */ static int vhiwat; /* enough extras after expansion */ static int vlowat; /* minimal extras before expansion */ static int vstir; /* nonzero to stir non-free vnodes */ static volatile int vsmalltrigger = 8; /* pref to keep if > this many pages */ static int sysctl_update_desiredvnodes(SYSCTL_HANDLER_ARGS) { int error, old_desiredvnodes; old_desiredvnodes = desiredvnodes; if ((error = sysctl_handle_int(oidp, arg1, arg2, req)) != 0) return (error); if (old_desiredvnodes != desiredvnodes) { wantfreevnodes = desiredvnodes / 4; /* XXX locking seems to be incomplete. */ vfs_hash_changesize(desiredvnodes); cache_changesize(desiredvnodes); } return (0); } SYSCTL_PROC(_kern, KERN_MAXVNODES, maxvnodes, CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW, &desiredvnodes, 0, sysctl_update_desiredvnodes, "I", "Target for maximum number of vnodes"); SYSCTL_ULONG(_kern, OID_AUTO, minvnodes, CTLFLAG_RW, &wantfreevnodes, 0, "Old name for vfs.wantfreevnodes (legacy)"); static int vnlru_nowhere; SYSCTL_INT(_debug, OID_AUTO, vnlru_nowhere, CTLFLAG_RW, &vnlru_nowhere, 0, "Number of times the vnlru process ran without success"); /* Shift count for (uintptr_t)vp to initialize vp->v_hash. */ static int vnsz2log; /* * Support for the bufobj clean & dirty pctrie. */ static void * buf_trie_alloc(struct pctrie *ptree) { return uma_zalloc(buf_trie_zone, M_NOWAIT); } static void buf_trie_free(struct pctrie *ptree, void *node) { uma_zfree(buf_trie_zone, node); } PCTRIE_DEFINE(BUF, buf, b_lblkno, buf_trie_alloc, buf_trie_free); /* * Initialize the vnode management data structures. * * Reevaluate the following cap on the number of vnodes after the physical * memory size exceeds 512GB. In the limit, as the physical memory size * grows, the ratio of the memory size in KB to to vnodes approaches 64:1. */ #ifndef MAXVNODES_MAX #define MAXVNODES_MAX (512 * 1024 * 1024 / 64) /* 8M */ #endif /* * Initialize a vnode as it first enters the zone. */ static int vnode_init(void *mem, int size, int flags) { struct vnode *vp; struct bufobj *bo; vp = mem; bzero(vp, size); /* * Setup locks. */ vp->v_vnlock = &vp->v_lock; mtx_init(&vp->v_interlock, "vnode interlock", NULL, MTX_DEF); /* * By default, don't allow shared locks unless filesystems opt-in. */ lockinit(vp->v_vnlock, PVFS, "vnode", VLKTIMEOUT, LK_NOSHARE | LK_IS_VNODE); /* * Initialize bufobj. */ bo = &vp->v_bufobj; rw_init(BO_LOCKPTR(bo), "bufobj interlock"); bo->bo_private = vp; TAILQ_INIT(&bo->bo_clean.bv_hd); TAILQ_INIT(&bo->bo_dirty.bv_hd); /* * Initialize namecache. */ LIST_INIT(&vp->v_cache_src); TAILQ_INIT(&vp->v_cache_dst); /* * Initialize rangelocks. */ rangelock_init(&vp->v_rl); return (0); } /* * Free a vnode when it is cleared from the zone. */ static void vnode_fini(void *mem, int size) { struct vnode *vp; struct bufobj *bo; vp = mem; rangelock_destroy(&vp->v_rl); lockdestroy(vp->v_vnlock); mtx_destroy(&vp->v_interlock); bo = &vp->v_bufobj; rw_destroy(BO_LOCKPTR(bo)); } /* * Provide the size of NFS nclnode and NFS fh for calculation of the * vnode memory consumption. The size is specified directly to * eliminate dependency on NFS-private header. * * Other filesystems may use bigger or smaller (like UFS and ZFS) * private inode data, but the NFS-based estimation is ample enough. * Still, we care about differences in the size between 64- and 32-bit * platforms. * * Namecache structure size is heuristically * sizeof(struct namecache_ts) + CACHE_PATH_CUTOFF + 1. */ #ifdef _LP64 #define NFS_NCLNODE_SZ (528 + 64) #define NC_SZ 148 #else #define NFS_NCLNODE_SZ (360 + 32) #define NC_SZ 92 #endif static void vntblinit(void *dummy __unused) { u_int i; int physvnodes, virtvnodes; /* * Desiredvnodes is a function of the physical memory size and the * kernel's heap size. Generally speaking, it scales with the * physical memory size. The ratio of desiredvnodes to the physical * memory size is 1:16 until desiredvnodes exceeds 98,304. * Thereafter, the * marginal ratio of desiredvnodes to the physical memory size is * 1:64. However, desiredvnodes is limited by the kernel's heap * size. The memory required by desiredvnodes vnodes and vm objects * must not exceed 1/10th of the kernel's heap size. */ physvnodes = maxproc + pgtok(vm_cnt.v_page_count) / 64 + 3 * min(98304 * 16, pgtok(vm_cnt.v_page_count)) / 64; virtvnodes = vm_kmem_size / (10 * (sizeof(struct vm_object) + sizeof(struct vnode) + NC_SZ * ncsizefactor + NFS_NCLNODE_SZ)); desiredvnodes = min(physvnodes, virtvnodes); if (desiredvnodes > MAXVNODES_MAX) { if (bootverbose) printf("Reducing kern.maxvnodes %d -> %d\n", desiredvnodes, MAXVNODES_MAX); desiredvnodes = MAXVNODES_MAX; } wantfreevnodes = desiredvnodes / 4; mtx_init(&mntid_mtx, "mntid", NULL, MTX_DEF); TAILQ_INIT(&vnode_free_list); mtx_init(&vnode_free_list_mtx, "vnode_free_list", NULL, MTX_DEF); vnode_zone = uma_zcreate("VNODE", sizeof (struct vnode), NULL, NULL, vnode_init, vnode_fini, UMA_ALIGN_PTR, 0); vnodepoll_zone = uma_zcreate("VNODEPOLL", sizeof (struct vpollinfo), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); /* * Preallocate enough nodes to support one-per buf so that * we can not fail an insert. reassignbuf() callers can not * tolerate the insertion failure. */ buf_trie_zone = uma_zcreate("BUF TRIE", pctrie_node_size(), NULL, NULL, pctrie_zone_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE | UMA_ZONE_VM); uma_prealloc(buf_trie_zone, nbuf); vnodes_created = counter_u64_alloc(M_WAITOK); recycles_count = counter_u64_alloc(M_WAITOK); free_owe_inact = counter_u64_alloc(M_WAITOK); /* * Initialize the filesystem syncer. */ syncer_workitem_pending = hashinit(syncer_maxdelay, M_VNODE, &syncer_mask); syncer_maxdelay = syncer_mask + 1; mtx_init(&sync_mtx, "Syncer mtx", NULL, MTX_DEF); cv_init(&sync_wakeup, "syncer"); for (i = 1; i <= sizeof(struct vnode); i <<= 1) vnsz2log++; vnsz2log--; } SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vntblinit, NULL); /* * Mark a mount point as busy. Used to synchronize access and to delay * unmounting. Eventually, mountlist_mtx is not released on failure. * * vfs_busy() is a custom lock, it can block the caller. * vfs_busy() only sleeps if the unmount is active on the mount point. * For a mountpoint mp, vfs_busy-enforced lock is before lock of any * vnode belonging to mp. * * Lookup uses vfs_busy() to traverse mount points. * root fs var fs * / vnode lock A / vnode lock (/var) D * /var vnode lock B /log vnode lock(/var/log) E * vfs_busy lock C vfs_busy lock F * * Within each file system, the lock order is C->A->B and F->D->E. * * When traversing across mounts, the system follows that lock order: * * C->A->B * | * +->F->D->E * * The lookup() process for namei("/var") illustrates the process: * VOP_LOOKUP() obtains B while A is held * vfs_busy() obtains a shared lock on F while A and B are held * vput() releases lock on B * vput() releases lock on A * VFS_ROOT() obtains lock on D while shared lock on F is held * vfs_unbusy() releases shared lock on F * vn_lock() obtains lock on deadfs vnode vp_crossmp instead of A. * Attempt to lock A (instead of vp_crossmp) while D is held would * violate the global order, causing deadlocks. * * dounmount() locks B while F is drained. */ int vfs_busy(struct mount *mp, int flags) { MPASS((flags & ~MBF_MASK) == 0); CTR3(KTR_VFS, "%s: mp %p with flags %d", __func__, mp, flags); MNT_ILOCK(mp); MNT_REF(mp); /* * If mount point is currently being unmounted, sleep until the * mount point fate is decided. If thread doing the unmounting fails, * it will clear MNTK_UNMOUNT flag before waking us up, indicating * that this mount point has survived the unmount attempt and vfs_busy * should retry. Otherwise the unmounter thread will set MNTK_REFEXPIRE * flag in addition to MNTK_UNMOUNT, indicating that mount point is * about to be really destroyed. vfs_busy needs to release its * reference on the mount point in this case and return with ENOENT, * telling the caller that mount mount it tried to busy is no longer * valid. */ while (mp->mnt_kern_flag & MNTK_UNMOUNT) { if (flags & MBF_NOWAIT || mp->mnt_kern_flag & MNTK_REFEXPIRE) { MNT_REL(mp); MNT_IUNLOCK(mp); CTR1(KTR_VFS, "%s: failed busying before sleeping", __func__); return (ENOENT); } if (flags & MBF_MNTLSTLOCK) mtx_unlock(&mountlist_mtx); mp->mnt_kern_flag |= MNTK_MWAIT; msleep(mp, MNT_MTX(mp), PVFS | PDROP, "vfs_busy", 0); if (flags & MBF_MNTLSTLOCK) mtx_lock(&mountlist_mtx); MNT_ILOCK(mp); } if (flags & MBF_MNTLSTLOCK) mtx_unlock(&mountlist_mtx); mp->mnt_lockref++; MNT_IUNLOCK(mp); return (0); } /* * Free a busy filesystem. */ void vfs_unbusy(struct mount *mp) { CTR2(KTR_VFS, "%s: mp %p", __func__, mp); MNT_ILOCK(mp); MNT_REL(mp); KASSERT(mp->mnt_lockref > 0, ("negative mnt_lockref")); mp->mnt_lockref--; if (mp->mnt_lockref == 0 && (mp->mnt_kern_flag & MNTK_DRAINING) != 0) { MPASS(mp->mnt_kern_flag & MNTK_UNMOUNT); CTR1(KTR_VFS, "%s: waking up waiters", __func__); mp->mnt_kern_flag &= ~MNTK_DRAINING; wakeup(&mp->mnt_lockref); } MNT_IUNLOCK(mp); } /* * Lookup a mount point by filesystem identifier. */ struct mount * vfs_getvfs(fsid_t *fsid) { struct mount *mp; CTR2(KTR_VFS, "%s: fsid %p", __func__, fsid); mtx_lock(&mountlist_mtx); TAILQ_FOREACH(mp, &mountlist, mnt_list) { if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { vfs_ref(mp); mtx_unlock(&mountlist_mtx); return (mp); } } mtx_unlock(&mountlist_mtx); CTR2(KTR_VFS, "%s: lookup failed for %p id", __func__, fsid); return ((struct mount *) 0); } /* * Lookup a mount point by filesystem identifier, busying it before * returning. * * To avoid congestion on mountlist_mtx, implement simple direct-mapped * cache for popular filesystem identifiers. The cache is lockess, using * the fact that struct mount's are never freed. In worst case we may * get pointer to unmounted or even different filesystem, so we have to * check what we got, and go slow way if so. */ struct mount * vfs_busyfs(fsid_t *fsid) { #define FSID_CACHE_SIZE 256 typedef struct mount * volatile vmp_t; static vmp_t cache[FSID_CACHE_SIZE]; struct mount *mp; int error; uint32_t hash; CTR2(KTR_VFS, "%s: fsid %p", __func__, fsid); hash = fsid->val[0] ^ fsid->val[1]; hash = (hash >> 16 ^ hash) & (FSID_CACHE_SIZE - 1); mp = cache[hash]; if (mp == NULL || mp->mnt_stat.f_fsid.val[0] != fsid->val[0] || mp->mnt_stat.f_fsid.val[1] != fsid->val[1]) goto slow; if (vfs_busy(mp, 0) != 0) { cache[hash] = NULL; goto slow; } if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) return (mp); else vfs_unbusy(mp); slow: mtx_lock(&mountlist_mtx); TAILQ_FOREACH(mp, &mountlist, mnt_list) { if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { error = vfs_busy(mp, MBF_MNTLSTLOCK); if (error) { cache[hash] = NULL; mtx_unlock(&mountlist_mtx); return (NULL); } cache[hash] = mp; return (mp); } } CTR2(KTR_VFS, "%s: lookup failed for %p id", __func__, fsid); mtx_unlock(&mountlist_mtx); return ((struct mount *) 0); } /* * Check if a user can access privileged mount options. */ int vfs_suser(struct mount *mp, struct thread *td) { int error; /* * If the thread is jailed, but this is not a jail-friendly file * system, deny immediately. */ if (!(mp->mnt_vfc->vfc_flags & VFCF_JAIL) && jailed(td->td_ucred)) return (EPERM); /* * If the file system was mounted outside the jail of the calling * thread, deny immediately. */ if (prison_check(td->td_ucred, mp->mnt_cred) != 0) return (EPERM); /* * If file system supports delegated administration, we don't check * for the PRIV_VFS_MOUNT_OWNER privilege - it will be better verified * by the file system itself. * If this is not the user that did original mount, we check for * the PRIV_VFS_MOUNT_OWNER privilege. */ if (!(mp->mnt_vfc->vfc_flags & VFCF_DELEGADMIN) && mp->mnt_cred->cr_uid != td->td_ucred->cr_uid) { if ((error = priv_check(td, PRIV_VFS_MOUNT_OWNER)) != 0) return (error); } return (0); } /* * Get a new unique fsid. Try to make its val[0] unique, since this value * will be used to create fake device numbers for stat(). Also try (but * not so hard) make its val[0] unique mod 2^16, since some emulators only * support 16-bit device numbers. We end up with unique val[0]'s for the * first 2^16 calls and unique val[0]'s mod 2^16 for the first 2^8 calls. * * Keep in mind that several mounts may be running in parallel. Starting * the search one past where the previous search terminated is both a * micro-optimization and a defense against returning the same fsid to * different mounts. */ void vfs_getnewfsid(struct mount *mp) { static uint16_t mntid_base; struct mount *nmp; fsid_t tfsid; int mtype; CTR2(KTR_VFS, "%s: mp %p", __func__, mp); mtx_lock(&mntid_mtx); mtype = mp->mnt_vfc->vfc_typenum; tfsid.val[1] = mtype; mtype = (mtype & 0xFF) << 24; for (;;) { tfsid.val[0] = makedev(255, mtype | ((mntid_base & 0xFF00) << 8) | (mntid_base & 0xFF)); mntid_base++; if ((nmp = vfs_getvfs(&tfsid)) == NULL) break; vfs_rel(nmp); } mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; mp->mnt_stat.f_fsid.val[1] = tfsid.val[1]; mtx_unlock(&mntid_mtx); } /* * Knob to control the precision of file timestamps: * * 0 = seconds only; nanoseconds zeroed. * 1 = seconds and nanoseconds, accurate within 1/HZ. * 2 = seconds and nanoseconds, truncated to microseconds. * >=3 = seconds and nanoseconds, maximum precision. */ enum { TSP_SEC, TSP_HZ, TSP_USEC, TSP_NSEC }; static int timestamp_precision = TSP_USEC; SYSCTL_INT(_vfs, OID_AUTO, timestamp_precision, CTLFLAG_RW, ×tamp_precision, 0, "File timestamp precision (0: seconds, " "1: sec + ns accurate to 1/HZ, 2: sec + ns truncated to ms, " "3+: sec + ns (max. precision))"); /* * Get a current timestamp. */ void vfs_timestamp(struct timespec *tsp) { struct timeval tv; switch (timestamp_precision) { case TSP_SEC: tsp->tv_sec = time_second; tsp->tv_nsec = 0; break; case TSP_HZ: getnanotime(tsp); break; case TSP_USEC: microtime(&tv); TIMEVAL_TO_TIMESPEC(&tv, tsp); break; case TSP_NSEC: default: nanotime(tsp); break; } } /* * Set vnode attributes to VNOVAL */ void vattr_null(struct vattr *vap) { vap->va_type = VNON; vap->va_size = VNOVAL; vap->va_bytes = VNOVAL; vap->va_mode = VNOVAL; vap->va_nlink = VNOVAL; vap->va_uid = VNOVAL; vap->va_gid = VNOVAL; vap->va_fsid = VNOVAL; vap->va_fileid = VNOVAL; vap->va_blocksize = VNOVAL; vap->va_rdev = VNOVAL; vap->va_atime.tv_sec = VNOVAL; vap->va_atime.tv_nsec = VNOVAL; vap->va_mtime.tv_sec = VNOVAL; vap->va_mtime.tv_nsec = VNOVAL; vap->va_ctime.tv_sec = VNOVAL; vap->va_ctime.tv_nsec = VNOVAL; vap->va_birthtime.tv_sec = VNOVAL; vap->va_birthtime.tv_nsec = VNOVAL; vap->va_flags = VNOVAL; vap->va_gen = VNOVAL; vap->va_vaflags = 0; } /* * This routine is called when we have too many vnodes. It attempts * to free vnodes and will potentially free vnodes that still * have VM backing store (VM backing store is typically the cause * of a vnode blowout so we want to do this). Therefore, this operation * is not considered cheap. * * A number of conditions may prevent a vnode from being reclaimed. * the buffer cache may have references on the vnode, a directory * vnode may still have references due to the namei cache representing * underlying files, or the vnode may be in active use. It is not * desirable to reuse such vnodes. These conditions may cause the * number of vnodes to reach some minimum value regardless of what * you set kern.maxvnodes to. Do not set kern.maxvnodes too low. */ static int vlrureclaim(struct mount *mp, int reclaim_nc_src, int trigger) { struct vnode *vp; int count, done, target; done = 0; vn_start_write(NULL, &mp, V_WAIT); MNT_ILOCK(mp); count = mp->mnt_nvnodelistsize; target = count * (int64_t)gapvnodes / imax(desiredvnodes, 1); target = target / 10 + 1; while (count != 0 && done < target) { vp = TAILQ_FIRST(&mp->mnt_nvnodelist); while (vp != NULL && vp->v_type == VMARKER) vp = TAILQ_NEXT(vp, v_nmntvnodes); if (vp == NULL) break; /* * XXX LRU is completely broken for non-free vnodes. First * by calling here in mountpoint order, then by moving * unselected vnodes to the end here, and most grossly by * removing the vlruvp() function that was supposed to * maintain the order. (This function was born broken * since syncer problems prevented it doing anything.) The * order is closer to LRC (C = Created). * * LRU reclaiming of vnodes seems to have last worked in * FreeBSD-3 where LRU wasn't mentioned under any spelling. * Then there was no hold count, and inactive vnodes were * simply put on the free list in LRU order. The separate * lists also break LRU. We prefer to reclaim from the * free list for technical reasons. This tends to thrash * the free list to keep very unrecently used held vnodes. * The problem is mitigated by keeping the free list large. */ TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes); TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist, vp, v_nmntvnodes); --count; if (!VI_TRYLOCK(vp)) goto next_iter; /* * If it's been deconstructed already, it's still * referenced, or it exceeds the trigger, skip it. * Also skip free vnodes. We are trying to make space * to expand the free list, not reduce it. */ if (vp->v_usecount || (!reclaim_nc_src && !LIST_EMPTY(&vp->v_cache_src)) || ((vp->v_iflag & VI_FREE) != 0) || (vp->v_iflag & VI_DOOMED) != 0 || (vp->v_object != NULL && vp->v_object->resident_page_count > trigger)) { VI_UNLOCK(vp); goto next_iter; } MNT_IUNLOCK(mp); vholdl(vp); if (VOP_LOCK(vp, LK_INTERLOCK|LK_EXCLUSIVE|LK_NOWAIT)) { vdrop(vp); goto next_iter_mntunlocked; } VI_LOCK(vp); /* * v_usecount may have been bumped after VOP_LOCK() dropped * the vnode interlock and before it was locked again. * * It is not necessary to recheck VI_DOOMED because it can * only be set by another thread that holds both the vnode * lock and vnode interlock. If another thread has the * vnode lock before we get to VOP_LOCK() and obtains the * vnode interlock after VOP_LOCK() drops the vnode * interlock, the other thread will be unable to drop the * vnode lock before our VOP_LOCK() call fails. */ if (vp->v_usecount || (!reclaim_nc_src && !LIST_EMPTY(&vp->v_cache_src)) || (vp->v_iflag & VI_FREE) != 0 || (vp->v_object != NULL && vp->v_object->resident_page_count > trigger)) { VOP_UNLOCK(vp, LK_INTERLOCK); vdrop(vp); goto next_iter_mntunlocked; } KASSERT((vp->v_iflag & VI_DOOMED) == 0, ("VI_DOOMED unexpectedly detected in vlrureclaim()")); counter_u64_add(recycles_count, 1); vgonel(vp); VOP_UNLOCK(vp, 0); vdropl(vp); done++; next_iter_mntunlocked: if (!should_yield()) goto relock_mnt; goto yield; next_iter: if (!should_yield()) continue; MNT_IUNLOCK(mp); yield: kern_yield(PRI_USER); relock_mnt: MNT_ILOCK(mp); } MNT_IUNLOCK(mp); vn_finished_write(mp); return done; } static int max_vnlru_free = 10000; /* limit on vnode free requests per call */ SYSCTL_INT(_debug, OID_AUTO, max_vnlru_free, CTLFLAG_RW, &max_vnlru_free, 0, "limit on vnode free requests per call to the vnlru_free routine"); /* * Attempt to reduce the free list by the requested amount. */ static void vnlru_free_locked(int count, struct vfsops *mnt_op) { struct vnode *vp; struct mount *mp; bool tried_batches; tried_batches = false; mtx_assert(&vnode_free_list_mtx, MA_OWNED); if (count > max_vnlru_free) count = max_vnlru_free; for (; count > 0; count--) { vp = TAILQ_FIRST(&vnode_free_list); /* * The list can be modified while the free_list_mtx * has been dropped and vp could be NULL here. */ if (vp == NULL) { if (tried_batches) break; mtx_unlock(&vnode_free_list_mtx); vnlru_return_batches(mnt_op); tried_batches = true; mtx_lock(&vnode_free_list_mtx); continue; } VNASSERT(vp->v_op != NULL, vp, ("vnlru_free: vnode already reclaimed.")); KASSERT((vp->v_iflag & VI_FREE) != 0, ("Removing vnode not on freelist")); KASSERT((vp->v_iflag & VI_ACTIVE) == 0, ("Mangling active vnode")); TAILQ_REMOVE(&vnode_free_list, vp, v_actfreelist); /* * Don't recycle if our vnode is from different type * of mount point. Note that mp is type-safe, the * check does not reach unmapped address even if * vnode is reclaimed. * Don't recycle if we can't get the interlock without * blocking. */ if ((mnt_op != NULL && (mp = vp->v_mount) != NULL && mp->mnt_op != mnt_op) || !VI_TRYLOCK(vp)) { TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_actfreelist); continue; } VNASSERT((vp->v_iflag & VI_FREE) != 0 && vp->v_holdcnt == 0, vp, ("vp inconsistent on freelist")); /* * The clear of VI_FREE prevents activation of the * vnode. There is no sense in putting the vnode on * the mount point active list, only to remove it * later during recycling. Inline the relevant part * of vholdl(), to avoid triggering assertions or * activating. */ freevnodes--; vp->v_iflag &= ~VI_FREE; refcount_acquire(&vp->v_holdcnt); mtx_unlock(&vnode_free_list_mtx); VI_UNLOCK(vp); vtryrecycle(vp); /* * If the recycled succeeded this vdrop will actually free * the vnode. If not it will simply place it back on * the free list. */ vdrop(vp); mtx_lock(&vnode_free_list_mtx); } } void vnlru_free(int count, struct vfsops *mnt_op) { mtx_lock(&vnode_free_list_mtx); vnlru_free_locked(count, mnt_op); mtx_unlock(&vnode_free_list_mtx); } /* XXX some names and initialization are bad for limits and watermarks. */ static int vspace(void) { int space; gapvnodes = imax(desiredvnodes - wantfreevnodes, 100); vhiwat = gapvnodes / 11; /* 9% -- just under the 10% in vlrureclaim() */ vlowat = vhiwat / 2; if (numvnodes > desiredvnodes) return (0); space = desiredvnodes - numvnodes; if (freevnodes > wantfreevnodes) space += freevnodes - wantfreevnodes; return (space); } static void vnlru_return_batch_locked(struct mount *mp) { struct vnode *vp; mtx_assert(&mp->mnt_listmtx, MA_OWNED); if (mp->mnt_tmpfreevnodelistsize == 0) return; TAILQ_FOREACH(vp, &mp->mnt_tmpfreevnodelist, v_actfreelist) { VNASSERT((vp->v_mflag & VMP_TMPMNTFREELIST) != 0, vp, ("vnode without VMP_TMPMNTFREELIST on mnt_tmpfreevnodelist")); vp->v_mflag &= ~VMP_TMPMNTFREELIST; } mtx_lock(&vnode_free_list_mtx); TAILQ_CONCAT(&vnode_free_list, &mp->mnt_tmpfreevnodelist, v_actfreelist); freevnodes += mp->mnt_tmpfreevnodelistsize; mtx_unlock(&vnode_free_list_mtx); mp->mnt_tmpfreevnodelistsize = 0; } static void vnlru_return_batch(struct mount *mp) { mtx_lock(&mp->mnt_listmtx); vnlru_return_batch_locked(mp); mtx_unlock(&mp->mnt_listmtx); } static void vnlru_return_batches(struct vfsops *mnt_op) { struct mount *mp, *nmp; bool need_unbusy; mtx_lock(&mountlist_mtx); for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { need_unbusy = false; if (mnt_op != NULL && mp->mnt_op != mnt_op) goto next; if (mp->mnt_tmpfreevnodelistsize == 0) goto next; if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK) == 0) { vnlru_return_batch(mp); need_unbusy = true; mtx_lock(&mountlist_mtx); } next: nmp = TAILQ_NEXT(mp, mnt_list); if (need_unbusy) vfs_unbusy(mp); } mtx_unlock(&mountlist_mtx); } /* * Attempt to recycle vnodes in a context that is always safe to block. * Calling vlrurecycle() from the bowels of filesystem code has some * interesting deadlock problems. */ static struct proc *vnlruproc; static int vnlruproc_sig; static void vnlru_proc(void) { struct mount *mp, *nmp; unsigned long ofreevnodes, onumvnodes; int done, force, reclaim_nc_src, trigger, usevnodes; EVENTHANDLER_REGISTER(shutdown_pre_sync, kproc_shutdown, vnlruproc, SHUTDOWN_PRI_FIRST); force = 0; for (;;) { kproc_suspend_check(vnlruproc); mtx_lock(&vnode_free_list_mtx); /* * If numvnodes is too large (due to desiredvnodes being * adjusted using its sysctl, or emergency growth), first * try to reduce it by discarding from the free list. */ if (numvnodes > desiredvnodes) vnlru_free_locked(numvnodes - desiredvnodes, NULL); /* * Sleep if the vnode cache is in a good state. This is * when it is not over-full and has space for about a 4% * or 9% expansion (by growing its size or inexcessively * reducing its free list). Otherwise, try to reclaim * space for a 10% expansion. */ if (vstir && force == 0) { force = 1; vstir = 0; } if (vspace() >= vlowat && force == 0) { vnlruproc_sig = 0; wakeup(&vnlruproc_sig); msleep(vnlruproc, &vnode_free_list_mtx, PVFS|PDROP, "vlruwt", hz); continue; } mtx_unlock(&vnode_free_list_mtx); done = 0; ofreevnodes = freevnodes; onumvnodes = numvnodes; /* * Calculate parameters for recycling. These are the same * throughout the loop to give some semblance of fairness. * The trigger point is to avoid recycling vnodes with lots * of resident pages. We aren't trying to free memory; we * are trying to recycle or at least free vnodes. */ if (numvnodes <= desiredvnodes) usevnodes = numvnodes - freevnodes; else usevnodes = numvnodes; if (usevnodes <= 0) usevnodes = 1; /* * The trigger value is is chosen to give a conservatively * large value to ensure that it alone doesn't prevent * making progress. The value can easily be so large that * it is effectively infinite in some congested and * misconfigured cases, and this is necessary. Normally * it is about 8 to 100 (pages), which is quite large. */ trigger = vm_cnt.v_page_count * 2 / usevnodes; if (force < 2) trigger = vsmalltrigger; reclaim_nc_src = force >= 3; mtx_lock(&mountlist_mtx); for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK)) { nmp = TAILQ_NEXT(mp, mnt_list); continue; } done += vlrureclaim(mp, reclaim_nc_src, trigger); mtx_lock(&mountlist_mtx); nmp = TAILQ_NEXT(mp, mnt_list); vfs_unbusy(mp); } mtx_unlock(&mountlist_mtx); if (onumvnodes > desiredvnodes && numvnodes <= desiredvnodes) uma_reclaim(); if (done == 0) { if (force == 0 || force == 1) { force = 2; continue; } if (force == 2) { force = 3; continue; } force = 0; vnlru_nowhere++; tsleep(vnlruproc, PPAUSE, "vlrup", hz * 3); } else kern_yield(PRI_USER); /* * After becoming active to expand above low water, keep * active until above high water. */ force = vspace() < vhiwat; } } static struct kproc_desc vnlru_kp = { "vnlru", vnlru_proc, &vnlruproc }; SYSINIT(vnlru, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &vnlru_kp); /* * Routines having to do with the management of the vnode table. */ /* * Try to recycle a freed vnode. We abort if anyone picks up a reference * before we actually vgone(). This function must be called with the vnode * held to prevent the vnode from being returned to the free list midway * through vgone(). */ static int vtryrecycle(struct vnode *vp) { struct mount *vnmp; CTR2(KTR_VFS, "%s: vp %p", __func__, vp); VNASSERT(vp->v_holdcnt, vp, ("vtryrecycle: Recycling vp %p without a reference.", vp)); /* * This vnode may found and locked via some other list, if so we * can't recycle it yet. */ if (VOP_LOCK(vp, LK_EXCLUSIVE | LK_NOWAIT) != 0) { CTR2(KTR_VFS, "%s: impossible to recycle, vp %p lock is already held", __func__, vp); return (EWOULDBLOCK); } /* * Don't recycle if its filesystem is being suspended. */ if (vn_start_write(vp, &vnmp, V_NOWAIT) != 0) { VOP_UNLOCK(vp, 0); CTR2(KTR_VFS, "%s: impossible to recycle, cannot start the write for %p", __func__, vp); return (EBUSY); } /* * If we got this far, we need to acquire the interlock and see if * anyone picked up this vnode from another list. If not, we will * mark it with DOOMED via vgonel() so that anyone who does find it * will skip over it. */ VI_LOCK(vp); if (vp->v_usecount) { VOP_UNLOCK(vp, LK_INTERLOCK); vn_finished_write(vnmp); CTR2(KTR_VFS, "%s: impossible to recycle, %p is already referenced", __func__, vp); return (EBUSY); } if ((vp->v_iflag & VI_DOOMED) == 0) { counter_u64_add(recycles_count, 1); vgonel(vp); } VOP_UNLOCK(vp, LK_INTERLOCK); vn_finished_write(vnmp); return (0); } static void vcheckspace(void) { if (vspace() < vlowat && vnlruproc_sig == 0) { vnlruproc_sig = 1; wakeup(vnlruproc); } } /* * Wait if necessary for space for a new vnode. */ static int getnewvnode_wait(int suspended) { mtx_assert(&vnode_free_list_mtx, MA_OWNED); if (numvnodes >= desiredvnodes) { if (suspended) { /* * The file system is being suspended. We cannot * risk a deadlock here, so allow allocation of * another vnode even if this would give too many. */ return (0); } if (vnlruproc_sig == 0) { vnlruproc_sig = 1; /* avoid unnecessary wakeups */ wakeup(vnlruproc); } msleep(&vnlruproc_sig, &vnode_free_list_mtx, PVFS, "vlruwk", hz); } /* Post-adjust like the pre-adjust in getnewvnode(). */ if (numvnodes + 1 > desiredvnodes && freevnodes > 1) vnlru_free_locked(1, NULL); return (numvnodes >= desiredvnodes ? ENFILE : 0); } /* * This hack is fragile, and probably not needed any more now that the * watermark handling works. */ void getnewvnode_reserve(u_int count) { struct thread *td; /* Pre-adjust like the pre-adjust in getnewvnode(), with any count. */ /* XXX no longer so quick, but this part is not racy. */ mtx_lock(&vnode_free_list_mtx); if (numvnodes + count > desiredvnodes && freevnodes > wantfreevnodes) vnlru_free_locked(ulmin(numvnodes + count - desiredvnodes, freevnodes - wantfreevnodes), NULL); mtx_unlock(&vnode_free_list_mtx); td = curthread; /* First try to be quick and racy. */ if (atomic_fetchadd_long(&numvnodes, count) + count <= desiredvnodes) { td->td_vp_reserv += count; vcheckspace(); /* XXX no longer so quick, but more racy */ return; } else atomic_subtract_long(&numvnodes, count); mtx_lock(&vnode_free_list_mtx); while (count > 0) { if (getnewvnode_wait(0) == 0) { count--; td->td_vp_reserv++; atomic_add_long(&numvnodes, 1); } } vcheckspace(); mtx_unlock(&vnode_free_list_mtx); } /* * This hack is fragile, especially if desiredvnodes or wantvnodes are * misconfgured or changed significantly. Reducing desiredvnodes below * the reserved amount should cause bizarre behaviour like reducing it * below the number of active vnodes -- the system will try to reduce * numvnodes to match, but should fail, so the subtraction below should * not overflow. */ void getnewvnode_drop_reserve(void) { struct thread *td; td = curthread; atomic_subtract_long(&numvnodes, td->td_vp_reserv); td->td_vp_reserv = 0; } /* * Return the next vnode from the free list. */ int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, struct vnode **vpp) { struct vnode *vp; struct thread *td; struct lock_object *lo; static int cyclecount; int error; CTR3(KTR_VFS, "%s: mp %p with tag %s", __func__, mp, tag); vp = NULL; td = curthread; if (td->td_vp_reserv > 0) { td->td_vp_reserv -= 1; goto alloc; } mtx_lock(&vnode_free_list_mtx); if (numvnodes < desiredvnodes) cyclecount = 0; else if (cyclecount++ >= freevnodes) { cyclecount = 0; vstir = 1; } /* * Grow the vnode cache if it will not be above its target max * after growing. Otherwise, if the free list is nonempty, try * to reclaim 1 item from it before growing the cache (possibly * above its target max if the reclamation failed or is delayed). * Otherwise, wait for some space. In all cases, schedule * vnlru_proc() if we are getting short of space. The watermarks * should be chosen so that we never wait or even reclaim from * the free list to below its target minimum. */ if (numvnodes + 1 <= desiredvnodes) ; else if (freevnodes > 0) vnlru_free_locked(1, NULL); else { error = getnewvnode_wait(mp != NULL && (mp->mnt_kern_flag & MNTK_SUSPEND)); #if 0 /* XXX Not all VFS_VGET/ffs_vget callers check returns. */ if (error != 0) { mtx_unlock(&vnode_free_list_mtx); return (error); } #endif } vcheckspace(); atomic_add_long(&numvnodes, 1); mtx_unlock(&vnode_free_list_mtx); alloc: counter_u64_add(vnodes_created, 1); vp = (struct vnode *) uma_zalloc(vnode_zone, M_WAITOK); /* * Locks are given the generic name "vnode" when created. * Follow the historic practice of using the filesystem * name when they allocated, e.g., "zfs", "ufs", "nfs, etc. * * Locks live in a witness group keyed on their name. Thus, * when a lock is renamed, it must also move from the witness * group of its old name to the witness group of its new name. * * The change only needs to be made when the vnode moves * from one filesystem type to another. We ensure that each * filesystem use a single static name pointer for its tag so * that we can compare pointers rather than doing a strcmp(). */ lo = &vp->v_vnlock->lock_object; if (lo->lo_name != tag) { lo->lo_name = tag; WITNESS_DESTROY(lo); WITNESS_INIT(lo, tag); } /* * By default, don't allow shared locks unless filesystems opt-in. */ vp->v_vnlock->lock_object.lo_flags |= LK_NOSHARE; /* * Finalize various vnode identity bits. */ KASSERT(vp->v_object == NULL, ("stale v_object %p", vp)); KASSERT(vp->v_lockf == NULL, ("stale v_lockf %p", vp)); KASSERT(vp->v_pollinfo == NULL, ("stale v_pollinfo %p", vp)); vp->v_type = VNON; vp->v_tag = tag; vp->v_op = vops; v_init_counters(vp); vp->v_bufobj.bo_ops = &buf_ops_bio; #ifdef DIAGNOSTIC if (mp == NULL && vops != &dead_vnodeops) printf("NULL mp in getnewvnode(9), tag %s\n", tag); #endif #ifdef MAC mac_vnode_init(vp); if (mp != NULL && (mp->mnt_flag & MNT_MULTILABEL) == 0) mac_vnode_associate_singlelabel(mp, vp); #endif if (mp != NULL) { vp->v_bufobj.bo_bsize = mp->mnt_stat.f_iosize; if ((mp->mnt_kern_flag & MNTK_NOKNOTE) != 0) vp->v_vflag |= VV_NOKNOTE; } /* * For the filesystems which do not use vfs_hash_insert(), * still initialize v_hash to have vfs_hash_index() useful. * E.g., nullfs uses vfs_hash_index() on the lower vnode for * its own hashing. */ vp->v_hash = (uintptr_t)vp >> vnsz2log; *vpp = vp; return (0); } /* * Delete from old mount point vnode list, if on one. */ static void delmntque(struct vnode *vp) { struct mount *mp; int active; mp = vp->v_mount; if (mp == NULL) return; MNT_ILOCK(mp); VI_LOCK(vp); KASSERT(mp->mnt_activevnodelistsize <= mp->mnt_nvnodelistsize, ("Active vnode list size %d > Vnode list size %d", mp->mnt_activevnodelistsize, mp->mnt_nvnodelistsize)); active = vp->v_iflag & VI_ACTIVE; vp->v_iflag &= ~VI_ACTIVE; if (active) { mtx_lock(&mp->mnt_listmtx); TAILQ_REMOVE(&mp->mnt_activevnodelist, vp, v_actfreelist); mp->mnt_activevnodelistsize--; mtx_unlock(&mp->mnt_listmtx); } vp->v_mount = NULL; VI_UNLOCK(vp); VNASSERT(mp->mnt_nvnodelistsize > 0, vp, ("bad mount point vnode list size")); TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes); mp->mnt_nvnodelistsize--; MNT_REL(mp); MNT_IUNLOCK(mp); } static void insmntque_stddtr(struct vnode *vp, void *dtr_arg) { vp->v_data = NULL; vp->v_op = &dead_vnodeops; vgone(vp); vput(vp); } /* * Insert into list of vnodes for the new mount point, if available. */ int insmntque1(struct vnode *vp, struct mount *mp, void (*dtr)(struct vnode *, void *), void *dtr_arg) { KASSERT(vp->v_mount == NULL, ("insmntque: vnode already on per mount vnode list")); VNASSERT(mp != NULL, vp, ("Don't call insmntque(foo, NULL)")); ASSERT_VOP_ELOCKED(vp, "insmntque: non-locked vp"); /* * We acquire the vnode interlock early to ensure that the * vnode cannot be recycled by another process releasing a * holdcnt on it before we get it on both the vnode list * and the active vnode list. The mount mutex protects only * manipulation of the vnode list and the vnode freelist * mutex protects only manipulation of the active vnode list. * Hence the need to hold the vnode interlock throughout. */ MNT_ILOCK(mp); VI_LOCK(vp); if (((mp->mnt_kern_flag & MNTK_NOINSMNTQ) != 0 && ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 || mp->mnt_nvnodelistsize == 0)) && (vp->v_vflag & VV_FORCEINSMQ) == 0) { VI_UNLOCK(vp); MNT_IUNLOCK(mp); if (dtr != NULL) dtr(vp, dtr_arg); return (EBUSY); } vp->v_mount = mp; MNT_REF(mp); TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist, vp, v_nmntvnodes); VNASSERT(mp->mnt_nvnodelistsize >= 0, vp, ("neg mount point vnode list size")); mp->mnt_nvnodelistsize++; KASSERT((vp->v_iflag & VI_ACTIVE) == 0, ("Activating already active vnode")); vp->v_iflag |= VI_ACTIVE; mtx_lock(&mp->mnt_listmtx); TAILQ_INSERT_HEAD(&mp->mnt_activevnodelist, vp, v_actfreelist); mp->mnt_activevnodelistsize++; mtx_unlock(&mp->mnt_listmtx); VI_UNLOCK(vp); MNT_IUNLOCK(mp); return (0); } int insmntque(struct vnode *vp, struct mount *mp) { return (insmntque1(vp, mp, insmntque_stddtr, NULL)); } /* * Flush out and invalidate all buffers associated with a bufobj * Called with the underlying object locked. */ int bufobj_invalbuf(struct bufobj *bo, int flags, int slpflag, int slptimeo) { int error; BO_LOCK(bo); if (flags & V_SAVE) { error = bufobj_wwait(bo, slpflag, slptimeo); if (error) { BO_UNLOCK(bo); return (error); } if (bo->bo_dirty.bv_cnt > 0) { BO_UNLOCK(bo); if ((error = BO_SYNC(bo, MNT_WAIT)) != 0) return (error); /* * XXX We could save a lock/unlock if this was only * enabled under INVARIANTS */ BO_LOCK(bo); if (bo->bo_numoutput > 0 || bo->bo_dirty.bv_cnt > 0) panic("vinvalbuf: dirty bufs"); } } /* * If you alter this loop please notice that interlock is dropped and * reacquired in flushbuflist. Special care is needed to ensure that * no race conditions occur from this. */ do { error = flushbuflist(&bo->bo_clean, flags, bo, slpflag, slptimeo); if (error == 0 && !(flags & V_CLEANONLY)) error = flushbuflist(&bo->bo_dirty, flags, bo, slpflag, slptimeo); if (error != 0 && error != EAGAIN) { BO_UNLOCK(bo); return (error); } } while (error != 0); /* * Wait for I/O to complete. XXX needs cleaning up. The vnode can * have write I/O in-progress but if there is a VM object then the * VM object can also have read-I/O in-progress. */ do { bufobj_wwait(bo, 0, 0); BO_UNLOCK(bo); if (bo->bo_object != NULL) { VM_OBJECT_WLOCK(bo->bo_object); vm_object_pip_wait(bo->bo_object, "bovlbx"); VM_OBJECT_WUNLOCK(bo->bo_object); } BO_LOCK(bo); } while (bo->bo_numoutput > 0); BO_UNLOCK(bo); /* * Destroy the copy in the VM cache, too. */ if (bo->bo_object != NULL && (flags & (V_ALT | V_NORMAL | V_CLEANONLY)) == 0) { VM_OBJECT_WLOCK(bo->bo_object); vm_object_page_remove(bo->bo_object, 0, 0, (flags & V_SAVE) ? OBJPR_CLEANONLY : 0); VM_OBJECT_WUNLOCK(bo->bo_object); } #ifdef INVARIANTS BO_LOCK(bo); if ((flags & (V_ALT | V_NORMAL | V_CLEANONLY)) == 0 && (bo->bo_dirty.bv_cnt > 0 || bo->bo_clean.bv_cnt > 0)) panic("vinvalbuf: flush failed"); BO_UNLOCK(bo); #endif return (0); } /* * Flush out and invalidate all buffers associated with a vnode. * Called with the underlying object locked. */ int vinvalbuf(struct vnode *vp, int flags, int slpflag, int slptimeo) { CTR3(KTR_VFS, "%s: vp %p with flags %d", __func__, vp, flags); ASSERT_VOP_LOCKED(vp, "vinvalbuf"); if (vp->v_object != NULL && vp->v_object->handle != vp) return (0); return (bufobj_invalbuf(&vp->v_bufobj, flags, slpflag, slptimeo)); } /* * Flush out buffers on the specified list. * */ static int flushbuflist(struct bufv *bufv, int flags, struct bufobj *bo, int slpflag, int slptimeo) { struct buf *bp, *nbp; int retval, error; daddr_t lblkno; b_xflags_t xflags; ASSERT_BO_WLOCKED(bo); retval = 0; TAILQ_FOREACH_SAFE(bp, &bufv->bv_hd, b_bobufs, nbp) { if (((flags & V_NORMAL) && (bp->b_xflags & BX_ALTDATA)) || ((flags & V_ALT) && (bp->b_xflags & BX_ALTDATA) == 0)) { continue; } lblkno = 0; xflags = 0; if (nbp != NULL) { lblkno = nbp->b_lblkno; xflags = nbp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN); } retval = EAGAIN; error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, BO_LOCKPTR(bo), "flushbuf", slpflag, slptimeo); if (error) { BO_LOCK(bo); return (error != ENOLCK ? error : EAGAIN); } KASSERT(bp->b_bufobj == bo, ("bp %p wrong b_bufobj %p should be %p", bp, bp->b_bufobj, bo)); /* * XXX Since there are no node locks for NFS, I * believe there is a slight chance that a delayed * write will occur while sleeping just above, so * check for it. */ if (((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI) && (flags & V_SAVE)) { bremfree(bp); bp->b_flags |= B_ASYNC; bwrite(bp); BO_LOCK(bo); return (EAGAIN); /* XXX: why not loop ? */ } bremfree(bp); bp->b_flags |= (B_INVAL | B_RELBUF); bp->b_flags &= ~B_ASYNC; brelse(bp); BO_LOCK(bo); nbp = gbincore(bo, lblkno); if (nbp == NULL || (nbp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) != xflags) break; /* nbp invalid */ } return (retval); } int bnoreuselist(struct bufv *bufv, struct bufobj *bo, daddr_t startn, daddr_t endn) { struct buf *bp; int error; daddr_t lblkno; ASSERT_BO_LOCKED(bo); for (lblkno = startn;;) { again: bp = BUF_PCTRIE_LOOKUP_GE(&bufv->bv_root, lblkno); if (bp == NULL || bp->b_lblkno >= endn || bp->b_lblkno < startn) break; error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, BO_LOCKPTR(bo), "brlsfl", 0, 0); if (error != 0) { BO_RLOCK(bo); if (error == ENOLCK) goto again; return (error); } KASSERT(bp->b_bufobj == bo, ("bp %p wrong b_bufobj %p should be %p", bp, bp->b_bufobj, bo)); lblkno = bp->b_lblkno + 1; if ((bp->b_flags & B_MANAGED) == 0) bremfree(bp); bp->b_flags |= B_RELBUF; /* * In the VMIO case, use the B_NOREUSE flag to hint that the * pages backing each buffer in the range are unlikely to be * reused. Dirty buffers will have the hint applied once * they've been written. */ if (bp->b_vp->v_object != NULL) bp->b_flags |= B_NOREUSE; brelse(bp); BO_RLOCK(bo); } return (0); } /* * Truncate a file's buffer and pages to a specified length. This * is in lieu of the old vinvalbuf mechanism, which performed unneeded * sync activity. */ int vtruncbuf(struct vnode *vp, struct ucred *cred, off_t length, int blksize) { struct buf *bp, *nbp; int anyfreed; int trunclbn; struct bufobj *bo; CTR5(KTR_VFS, "%s: vp %p with cred %p and block %d:%ju", __func__, vp, cred, blksize, (uintmax_t)length); /* * Round up to the *next* lbn. */ trunclbn = howmany(length, blksize); ASSERT_VOP_LOCKED(vp, "vtruncbuf"); restart: bo = &vp->v_bufobj; BO_LOCK(bo); anyfreed = 1; for (;anyfreed;) { anyfreed = 0; TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, nbp) { if (bp->b_lblkno < trunclbn) continue; if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, BO_LOCKPTR(bo)) == ENOLCK) goto restart; bremfree(bp); bp->b_flags |= (B_INVAL | B_RELBUF); bp->b_flags &= ~B_ASYNC; brelse(bp); anyfreed = 1; BO_LOCK(bo); if (nbp != NULL && (((nbp->b_xflags & BX_VNCLEAN) == 0) || (nbp->b_vp != vp) || (nbp->b_flags & B_DELWRI))) { BO_UNLOCK(bo); goto restart; } } TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { if (bp->b_lblkno < trunclbn) continue; if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, BO_LOCKPTR(bo)) == ENOLCK) goto restart; bremfree(bp); bp->b_flags |= (B_INVAL | B_RELBUF); bp->b_flags &= ~B_ASYNC; brelse(bp); anyfreed = 1; BO_LOCK(bo); if (nbp != NULL && (((nbp->b_xflags & BX_VNDIRTY) == 0) || (nbp->b_vp != vp) || (nbp->b_flags & B_DELWRI) == 0)) { BO_UNLOCK(bo); goto restart; } } } if (length > 0) { restartsync: TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { if (bp->b_lblkno > 0) continue; /* * Since we hold the vnode lock this should only * fail if we're racing with the buf daemon. */ if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, BO_LOCKPTR(bo)) == ENOLCK) { goto restart; } VNASSERT((bp->b_flags & B_DELWRI), vp, ("buf(%p) on dirty queue without DELWRI", bp)); bremfree(bp); bawrite(bp); BO_LOCK(bo); goto restartsync; } } bufobj_wwait(bo, 0, 0); BO_UNLOCK(bo); vnode_pager_setsize(vp, length); return (0); } static void buf_vlist_remove(struct buf *bp) { struct bufv *bv; KASSERT(bp->b_bufobj != NULL, ("No b_bufobj %p", bp)); ASSERT_BO_WLOCKED(bp->b_bufobj); KASSERT((bp->b_xflags & (BX_VNDIRTY|BX_VNCLEAN)) != (BX_VNDIRTY|BX_VNCLEAN), ("buf_vlist_remove: Buf %p is on two lists", bp)); if (bp->b_xflags & BX_VNDIRTY) bv = &bp->b_bufobj->bo_dirty; else bv = &bp->b_bufobj->bo_clean; BUF_PCTRIE_REMOVE(&bv->bv_root, bp->b_lblkno); TAILQ_REMOVE(&bv->bv_hd, bp, b_bobufs); bv->bv_cnt--; bp->b_xflags &= ~(BX_VNDIRTY | BX_VNCLEAN); } /* * Add the buffer to the sorted clean or dirty block list. * * NOTE: xflags is passed as a constant, optimizing this inline function! */ static void buf_vlist_add(struct buf *bp, struct bufobj *bo, b_xflags_t xflags) { struct bufv *bv; struct buf *n; int error; ASSERT_BO_WLOCKED(bo); KASSERT((xflags & BX_VNDIRTY) == 0 || (bo->bo_flag & BO_DEAD) == 0, ("dead bo %p", bo)); KASSERT((bp->b_xflags & (BX_VNDIRTY|BX_VNCLEAN)) == 0, ("buf_vlist_add: Buf %p has existing xflags %d", bp, bp->b_xflags)); bp->b_xflags |= xflags; if (xflags & BX_VNDIRTY) bv = &bo->bo_dirty; else bv = &bo->bo_clean; /* * Keep the list ordered. Optimize empty list insertion. Assume * we tend to grow at the tail so lookup_le should usually be cheaper * than _ge. */ if (bv->bv_cnt == 0 || bp->b_lblkno > TAILQ_LAST(&bv->bv_hd, buflists)->b_lblkno) TAILQ_INSERT_TAIL(&bv->bv_hd, bp, b_bobufs); else if ((n = BUF_PCTRIE_LOOKUP_LE(&bv->bv_root, bp->b_lblkno)) == NULL) TAILQ_INSERT_HEAD(&bv->bv_hd, bp, b_bobufs); else TAILQ_INSERT_AFTER(&bv->bv_hd, n, bp, b_bobufs); error = BUF_PCTRIE_INSERT(&bv->bv_root, bp); if (error) panic("buf_vlist_add: Preallocated nodes insufficient."); bv->bv_cnt++; } /* * Look up a buffer using the buffer tries. */ struct buf * gbincore(struct bufobj *bo, daddr_t lblkno) { struct buf *bp; ASSERT_BO_LOCKED(bo); bp = BUF_PCTRIE_LOOKUP(&bo->bo_clean.bv_root, lblkno); if (bp != NULL) return (bp); return BUF_PCTRIE_LOOKUP(&bo->bo_dirty.bv_root, lblkno); } /* * Associate a buffer with a vnode. */ void bgetvp(struct vnode *vp, struct buf *bp) { struct bufobj *bo; bo = &vp->v_bufobj; ASSERT_BO_WLOCKED(bo); VNASSERT(bp->b_vp == NULL, bp->b_vp, ("bgetvp: not free")); CTR3(KTR_BUF, "bgetvp(%p) vp %p flags %X", bp, vp, bp->b_flags); VNASSERT((bp->b_xflags & (BX_VNDIRTY|BX_VNCLEAN)) == 0, vp, ("bgetvp: bp already attached! %p", bp)); vhold(vp); bp->b_vp = vp; bp->b_bufobj = bo; /* * Insert onto list for new vnode. */ buf_vlist_add(bp, bo, BX_VNCLEAN); } /* * Disassociate a buffer from a vnode. */ void brelvp(struct buf *bp) { struct bufobj *bo; struct vnode *vp; CTR3(KTR_BUF, "brelvp(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags); KASSERT(bp->b_vp != NULL, ("brelvp: NULL")); /* * Delete from old vnode list, if on one. */ vp = bp->b_vp; /* XXX */ bo = bp->b_bufobj; BO_LOCK(bo); if (bp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) buf_vlist_remove(bp); else panic("brelvp: Buffer %p not on queue.", bp); if ((bo->bo_flag & BO_ONWORKLST) && bo->bo_dirty.bv_cnt == 0) { bo->bo_flag &= ~BO_ONWORKLST; mtx_lock(&sync_mtx); LIST_REMOVE(bo, bo_synclist); syncer_worklist_len--; mtx_unlock(&sync_mtx); } bp->b_vp = NULL; bp->b_bufobj = NULL; BO_UNLOCK(bo); vdrop(vp); } /* * Add an item to the syncer work queue. */ static void vn_syncer_add_to_worklist(struct bufobj *bo, int delay) { int slot; ASSERT_BO_WLOCKED(bo); mtx_lock(&sync_mtx); if (bo->bo_flag & BO_ONWORKLST) LIST_REMOVE(bo, bo_synclist); else { bo->bo_flag |= BO_ONWORKLST; syncer_worklist_len++; } if (delay > syncer_maxdelay - 2) delay = syncer_maxdelay - 2; slot = (syncer_delayno + delay) & syncer_mask; LIST_INSERT_HEAD(&syncer_workitem_pending[slot], bo, bo_synclist); mtx_unlock(&sync_mtx); } static int sysctl_vfs_worklist_len(SYSCTL_HANDLER_ARGS) { int error, len; mtx_lock(&sync_mtx); len = syncer_worklist_len - sync_vnode_count; mtx_unlock(&sync_mtx); error = SYSCTL_OUT(req, &len, sizeof(len)); return (error); } SYSCTL_PROC(_vfs, OID_AUTO, worklist_len, CTLTYPE_INT | CTLFLAG_RD, NULL, 0, sysctl_vfs_worklist_len, "I", "Syncer thread worklist length"); static struct proc *updateproc; static void sched_sync(void); static struct kproc_desc up_kp = { "syncer", sched_sync, &updateproc }; SYSINIT(syncer, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &up_kp); static int sync_vnode(struct synclist *slp, struct bufobj **bo, struct thread *td) { struct vnode *vp; struct mount *mp; *bo = LIST_FIRST(slp); if (*bo == NULL) return (0); vp = bo2vnode(*bo); if (VOP_ISLOCKED(vp) != 0 || VI_TRYLOCK(vp) == 0) return (1); /* * We use vhold in case the vnode does not * successfully sync. vhold prevents the vnode from * going away when we unlock the sync_mtx so that * we can acquire the vnode interlock. */ vholdl(vp); mtx_unlock(&sync_mtx); VI_UNLOCK(vp); if (vn_start_write(vp, &mp, V_NOWAIT) != 0) { vdrop(vp); mtx_lock(&sync_mtx); return (*bo == LIST_FIRST(slp)); } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); (void) VOP_FSYNC(vp, MNT_LAZY, td); VOP_UNLOCK(vp, 0); vn_finished_write(mp); BO_LOCK(*bo); if (((*bo)->bo_flag & BO_ONWORKLST) != 0) { /* * Put us back on the worklist. The worklist * routine will remove us from our current * position and then add us back in at a later * position. */ vn_syncer_add_to_worklist(*bo, syncdelay); } BO_UNLOCK(*bo); vdrop(vp); mtx_lock(&sync_mtx); return (0); } static int first_printf = 1; /* * System filesystem synchronizer daemon. */ static void sched_sync(void) { struct synclist *next, *slp; struct bufobj *bo; long starttime; struct thread *td = curthread; int last_work_seen; int net_worklist_len; int syncer_final_iter; int error; last_work_seen = 0; syncer_final_iter = 0; syncer_state = SYNCER_RUNNING; starttime = time_uptime; td->td_pflags |= TDP_NORUNNINGBUF; EVENTHANDLER_REGISTER(shutdown_pre_sync, syncer_shutdown, td->td_proc, SHUTDOWN_PRI_LAST); mtx_lock(&sync_mtx); for (;;) { if (syncer_state == SYNCER_FINAL_DELAY && syncer_final_iter == 0) { mtx_unlock(&sync_mtx); kproc_suspend_check(td->td_proc); mtx_lock(&sync_mtx); } net_worklist_len = syncer_worklist_len - sync_vnode_count; if (syncer_state != SYNCER_RUNNING && starttime != time_uptime) { if (first_printf) { printf("\nSyncing disks, vnodes remaining... "); first_printf = 0; } printf("%d ", net_worklist_len); } starttime = time_uptime; /* * Push files whose dirty time has expired. Be careful * of interrupt race on slp queue. * * Skip over empty worklist slots when shutting down. */ do { slp = &syncer_workitem_pending[syncer_delayno]; syncer_delayno += 1; if (syncer_delayno == syncer_maxdelay) syncer_delayno = 0; next = &syncer_workitem_pending[syncer_delayno]; /* * If the worklist has wrapped since the * it was emptied of all but syncer vnodes, * switch to the FINAL_DELAY state and run * for one more second. */ if (syncer_state == SYNCER_SHUTTING_DOWN && net_worklist_len == 0 && last_work_seen == syncer_delayno) { syncer_state = SYNCER_FINAL_DELAY; syncer_final_iter = SYNCER_SHUTDOWN_SPEEDUP; } } while (syncer_state != SYNCER_RUNNING && LIST_EMPTY(slp) && syncer_worklist_len > 0); /* * Keep track of the last time there was anything * on the worklist other than syncer vnodes. * Return to the SHUTTING_DOWN state if any * new work appears. */ if (net_worklist_len > 0 || syncer_state == SYNCER_RUNNING) last_work_seen = syncer_delayno; if (net_worklist_len > 0 && syncer_state == SYNCER_FINAL_DELAY) syncer_state = SYNCER_SHUTTING_DOWN; while (!LIST_EMPTY(slp)) { error = sync_vnode(slp, &bo, td); if (error == 1) { LIST_REMOVE(bo, bo_synclist); LIST_INSERT_HEAD(next, bo, bo_synclist); continue; } if (first_printf == 0) { /* * Drop the sync mutex, because some watchdog * drivers need to sleep while patting */ mtx_unlock(&sync_mtx); wdog_kern_pat(WD_LASTVAL); mtx_lock(&sync_mtx); } } if (syncer_state == SYNCER_FINAL_DELAY && syncer_final_iter > 0) syncer_final_iter--; /* * The variable rushjob allows the kernel to speed up the * processing of the filesystem syncer process. A rushjob * value of N tells the filesystem syncer to process the next * N seconds worth of work on its queue ASAP. Currently rushjob * is used by the soft update code to speed up the filesystem * syncer process when the incore state is getting so far * ahead of the disk that the kernel memory pool is being * threatened with exhaustion. */ if (rushjob > 0) { rushjob -= 1; continue; } /* * Just sleep for a short period of time between * iterations when shutting down to allow some I/O * to happen. * * If it has taken us less than a second to process the * current work, then wait. Otherwise start right over * again. We can still lose time if any single round * takes more than two seconds, but it does not really * matter as we are just trying to generally pace the * filesystem activity. */ if (syncer_state != SYNCER_RUNNING || time_uptime == starttime) { thread_lock(td); sched_prio(td, PPAUSE); thread_unlock(td); } if (syncer_state != SYNCER_RUNNING) cv_timedwait(&sync_wakeup, &sync_mtx, hz / SYNCER_SHUTDOWN_SPEEDUP); else if (time_uptime == starttime) cv_timedwait(&sync_wakeup, &sync_mtx, hz); } } /* * Request the syncer daemon to speed up its work. * We never push it to speed up more than half of its * normal turn time, otherwise it could take over the cpu. */ int speedup_syncer(void) { int ret = 0; mtx_lock(&sync_mtx); if (rushjob < syncdelay / 2) { rushjob += 1; stat_rush_requests += 1; ret = 1; } mtx_unlock(&sync_mtx); cv_broadcast(&sync_wakeup); return (ret); } /* * Tell the syncer to speed up its work and run though its work * list several times, then tell it to shut down. */ static void syncer_shutdown(void *arg, int howto) { if (howto & RB_NOSYNC) return; mtx_lock(&sync_mtx); syncer_state = SYNCER_SHUTTING_DOWN; rushjob = 0; mtx_unlock(&sync_mtx); cv_broadcast(&sync_wakeup); kproc_shutdown(arg, howto); } void syncer_suspend(void) { syncer_shutdown(updateproc, 0); } void syncer_resume(void) { mtx_lock(&sync_mtx); first_printf = 1; syncer_state = SYNCER_RUNNING; mtx_unlock(&sync_mtx); cv_broadcast(&sync_wakeup); kproc_resume(updateproc); } /* * Reassign a buffer from one vnode to another. * Used to assign file specific control information * (indirect blocks) to the vnode to which they belong. */ void reassignbuf(struct buf *bp) { struct vnode *vp; struct bufobj *bo; int delay; #ifdef INVARIANTS struct bufv *bv; #endif vp = bp->b_vp; bo = bp->b_bufobj; ++reassignbufcalls; CTR3(KTR_BUF, "reassignbuf(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags); /* * B_PAGING flagged buffers cannot be reassigned because their vp * is not fully linked in. */ if (bp->b_flags & B_PAGING) panic("cannot reassign paging buffer"); /* * Delete from old vnode list, if on one. */ BO_LOCK(bo); if (bp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) buf_vlist_remove(bp); else panic("reassignbuf: Buffer %p not on queue.", bp); /* * If dirty, put on list of dirty buffers; otherwise insert onto list * of clean buffers. */ if (bp->b_flags & B_DELWRI) { if ((bo->bo_flag & BO_ONWORKLST) == 0) { switch (vp->v_type) { case VDIR: delay = dirdelay; break; case VCHR: delay = metadelay; break; default: delay = filedelay; } vn_syncer_add_to_worklist(bo, delay); } buf_vlist_add(bp, bo, BX_VNDIRTY); } else { buf_vlist_add(bp, bo, BX_VNCLEAN); if ((bo->bo_flag & BO_ONWORKLST) && bo->bo_dirty.bv_cnt == 0) { mtx_lock(&sync_mtx); LIST_REMOVE(bo, bo_synclist); syncer_worklist_len--; mtx_unlock(&sync_mtx); bo->bo_flag &= ~BO_ONWORKLST; } } #ifdef INVARIANTS bv = &bo->bo_clean; bp = TAILQ_FIRST(&bv->bv_hd); KASSERT(bp == NULL || bp->b_bufobj == bo, ("bp %p wrong b_bufobj %p should be %p", bp, bp->b_bufobj, bo)); bp = TAILQ_LAST(&bv->bv_hd, buflists); KASSERT(bp == NULL || bp->b_bufobj == bo, ("bp %p wrong b_bufobj %p should be %p", bp, bp->b_bufobj, bo)); bv = &bo->bo_dirty; bp = TAILQ_FIRST(&bv->bv_hd); KASSERT(bp == NULL || bp->b_bufobj == bo, ("bp %p wrong b_bufobj %p should be %p", bp, bp->b_bufobj, bo)); bp = TAILQ_LAST(&bv->bv_hd, buflists); KASSERT(bp == NULL || bp->b_bufobj == bo, ("bp %p wrong b_bufobj %p should be %p", bp, bp->b_bufobj, bo)); #endif BO_UNLOCK(bo); } /* * A temporary hack until refcount_* APIs are sorted out. */ static __inline int vfs_refcount_acquire_if_not_zero(volatile u_int *count) { u_int old; + old = *count; for (;;) { - old = *count; if (old == 0) return (0); - if (atomic_cmpset_int(count, old, old + 1)) + if (atomic_fcmpset_int(count, &old, old + 1)) return (1); } } static __inline int vfs_refcount_release_if_not_last(volatile u_int *count) { u_int old; + old = *count; for (;;) { - old = *count; if (old == 1) return (0); - if (atomic_cmpset_int(count, old, old - 1)) + if (atomic_fcmpset_int(count, &old, old - 1)) return (1); } } static void v_init_counters(struct vnode *vp) { VNASSERT(vp->v_type == VNON && vp->v_data == NULL && vp->v_iflag == 0, vp, ("%s called for an initialized vnode", __FUNCTION__)); ASSERT_VI_UNLOCKED(vp, __FUNCTION__); refcount_init(&vp->v_holdcnt, 1); refcount_init(&vp->v_usecount, 1); } static void v_incr_usecount_locked(struct vnode *vp) { ASSERT_VI_LOCKED(vp, __func__); if ((vp->v_iflag & VI_OWEINACT) != 0) { VNASSERT(vp->v_usecount == 0, vp, ("vnode with usecount and VI_OWEINACT set")); vp->v_iflag &= ~VI_OWEINACT; } refcount_acquire(&vp->v_usecount); v_incr_devcount(vp); } /* * Increment the use count on the vnode, taking care to reference * the driver's usecount if this is a chardev. */ static void v_incr_usecount(struct vnode *vp) { ASSERT_VI_UNLOCKED(vp, __func__); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); if (vp->v_type != VCHR && vfs_refcount_acquire_if_not_zero(&vp->v_usecount)) { VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, ("vnode with usecount and VI_OWEINACT set")); } else { VI_LOCK(vp); v_incr_usecount_locked(vp); VI_UNLOCK(vp); } } /* * Increment si_usecount of the associated device, if any. */ static void v_incr_devcount(struct vnode *vp) { ASSERT_VI_LOCKED(vp, __FUNCTION__); if (vp->v_type == VCHR && vp->v_rdev != NULL) { dev_lock(); vp->v_rdev->si_usecount++; dev_unlock(); } } /* * Decrement si_usecount of the associated device, if any. */ static void v_decr_devcount(struct vnode *vp) { ASSERT_VI_LOCKED(vp, __FUNCTION__); if (vp->v_type == VCHR && vp->v_rdev != NULL) { dev_lock(); vp->v_rdev->si_usecount--; dev_unlock(); } } /* * Grab a particular vnode from the free list, increment its * reference count and lock it. VI_DOOMED is set if the vnode * is being destroyed. Only callers who specify LK_RETRY will * see doomed vnodes. If inactive processing was delayed in * vput try to do it here. * * Notes on lockless counter manipulation: * _vhold, vputx and other routines make various decisions based * on either holdcnt or usecount being 0. As long as either counter * is not transitioning 0->1 nor 1->0, the manipulation can be done * with atomic operations. Otherwise the interlock is taken covering * both the atomic and additional actions. */ int vget(struct vnode *vp, int flags, struct thread *td) { int error, oweinact; VNASSERT((flags & LK_TYPE_MASK) != 0, vp, ("vget: invalid lock operation")); if ((flags & LK_INTERLOCK) != 0) ASSERT_VI_LOCKED(vp, __func__); else ASSERT_VI_UNLOCKED(vp, __func__); if ((flags & LK_VNHELD) != 0) VNASSERT((vp->v_holdcnt > 0), vp, ("vget: LK_VNHELD passed but vnode not held")); CTR3(KTR_VFS, "%s: vp %p with flags %d", __func__, vp, flags); if ((flags & LK_VNHELD) == 0) _vhold(vp, (flags & LK_INTERLOCK) != 0); if ((error = vn_lock(vp, flags)) != 0) { vdrop(vp); CTR2(KTR_VFS, "%s: impossible to lock vnode %p", __func__, vp); return (error); } if (vp->v_iflag & VI_DOOMED && (flags & LK_RETRY) == 0) panic("vget: vn_lock failed to return ENOENT\n"); /* * We don't guarantee that any particular close will * trigger inactive processing so just make a best effort * here at preventing a reference to a removed file. If * we don't succeed no harm is done. * * Upgrade our holdcnt to a usecount. */ if (vp->v_type == VCHR || !vfs_refcount_acquire_if_not_zero(&vp->v_usecount)) { VI_LOCK(vp); if ((vp->v_iflag & VI_OWEINACT) == 0) { oweinact = 0; } else { oweinact = 1; vp->v_iflag &= ~VI_OWEINACT; } refcount_acquire(&vp->v_usecount); v_incr_devcount(vp); if (oweinact && VOP_ISLOCKED(vp) == LK_EXCLUSIVE && (flags & LK_NOWAIT) == 0) vinactive(vp, td); VI_UNLOCK(vp); } return (0); } /* * Increase the reference (use) and hold count of a vnode. * This will also remove the vnode from the free list if it is presently free. */ void vref(struct vnode *vp) { CTR2(KTR_VFS, "%s: vp %p", __func__, vp); _vhold(vp, false); v_incr_usecount(vp); } void vrefl(struct vnode *vp) { ASSERT_VI_LOCKED(vp, __func__); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); _vhold(vp, true); v_incr_usecount_locked(vp); } void vrefact(struct vnode *vp) { CTR2(KTR_VFS, "%s: vp %p", __func__, vp); if (__predict_false(vp->v_type == VCHR)) { VNASSERT(vp->v_holdcnt > 0 && vp->v_usecount > 0, vp, ("%s: wrong ref counts", __func__)); vref(vp); return; } #ifdef INVARIANTS int old = atomic_fetchadd_int(&vp->v_holdcnt, 1); VNASSERT(old > 0, vp, ("%s: wrong hold count", __func__)); old = atomic_fetchadd_int(&vp->v_usecount, 1); VNASSERT(old > 0, vp, ("%s: wrong use count", __func__)); #else refcount_acquire(&vp->v_holdcnt); refcount_acquire(&vp->v_usecount); #endif } /* * Return reference count of a vnode. * * The results of this call are only guaranteed when some mechanism is used to * stop other processes from gaining references to the vnode. This may be the * case if the caller holds the only reference. This is also useful when stale * data is acceptable as race conditions may be accounted for by some other * means. */ int vrefcnt(struct vnode *vp) { return (vp->v_usecount); } #define VPUTX_VRELE 1 #define VPUTX_VPUT 2 #define VPUTX_VUNREF 3 /* * Decrement the use and hold counts for a vnode. * * See an explanation near vget() as to why atomic operation is safe. */ static void vputx(struct vnode *vp, int func) { int error; KASSERT(vp != NULL, ("vputx: null vp")); if (func == VPUTX_VUNREF) ASSERT_VOP_LOCKED(vp, "vunref"); else if (func == VPUTX_VPUT) ASSERT_VOP_LOCKED(vp, "vput"); else KASSERT(func == VPUTX_VRELE, ("vputx: wrong func")); ASSERT_VI_UNLOCKED(vp, __func__); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); if (vp->v_type != VCHR && vfs_refcount_release_if_not_last(&vp->v_usecount)) { if (func == VPUTX_VPUT) VOP_UNLOCK(vp, 0); vdrop(vp); return; } VI_LOCK(vp); /* * We want to hold the vnode until the inactive finishes to * prevent vgone() races. We drop the use count here and the * hold count below when we're done. */ if (!refcount_release(&vp->v_usecount) || (vp->v_iflag & VI_DOINGINACT)) { if (func == VPUTX_VPUT) VOP_UNLOCK(vp, 0); v_decr_devcount(vp); vdropl(vp); return; } v_decr_devcount(vp); error = 0; if (vp->v_usecount != 0) { vn_printf(vp, "vputx: usecount not zero for vnode "); panic("vputx: usecount not zero"); } CTR2(KTR_VFS, "%s: return vnode %p to the freelist", __func__, vp); /* * We must call VOP_INACTIVE with the node locked. Mark * as VI_DOINGINACT to avoid recursion. */ vp->v_iflag |= VI_OWEINACT; switch (func) { case VPUTX_VRELE: error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK); VI_LOCK(vp); break; case VPUTX_VPUT: if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { error = VOP_LOCK(vp, LK_UPGRADE | LK_INTERLOCK | LK_NOWAIT); VI_LOCK(vp); } break; case VPUTX_VUNREF: if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { error = VOP_LOCK(vp, LK_TRYUPGRADE | LK_INTERLOCK); VI_LOCK(vp); } break; } VNASSERT(vp->v_usecount == 0 || (vp->v_iflag & VI_OWEINACT) == 0, vp, ("vnode with usecount and VI_OWEINACT set")); if (error == 0) { if (vp->v_iflag & VI_OWEINACT) vinactive(vp, curthread); if (func != VPUTX_VUNREF) VOP_UNLOCK(vp, 0); } vdropl(vp); } /* * Vnode put/release. * If count drops to zero, call inactive routine and return to freelist. */ void vrele(struct vnode *vp) { vputx(vp, VPUTX_VRELE); } /* * Release an already locked vnode. This give the same effects as * unlock+vrele(), but takes less time and avoids releasing and * re-aquiring the lock (as vrele() acquires the lock internally.) */ void vput(struct vnode *vp) { vputx(vp, VPUTX_VPUT); } /* * Release an exclusively locked vnode. Do not unlock the vnode lock. */ void vunref(struct vnode *vp) { vputx(vp, VPUTX_VUNREF); } /* * Increase the hold count and activate if this is the first reference. */ void _vhold(struct vnode *vp, bool locked) { struct mount *mp; if (locked) ASSERT_VI_LOCKED(vp, __func__); else ASSERT_VI_UNLOCKED(vp, __func__); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); if (!locked && vfs_refcount_acquire_if_not_zero(&vp->v_holdcnt)) { VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, ("_vhold: vnode with holdcnt is free")); return; } if (!locked) VI_LOCK(vp); if ((vp->v_iflag & VI_FREE) == 0) { refcount_acquire(&vp->v_holdcnt); if (!locked) VI_UNLOCK(vp); return; } VNASSERT(vp->v_holdcnt == 0, vp, ("%s: wrong hold count", __func__)); VNASSERT(vp->v_op != NULL, vp, ("%s: vnode already reclaimed.", __func__)); /* * Remove a vnode from the free list, mark it as in use, * and put it on the active list. */ mp = vp->v_mount; mtx_lock(&mp->mnt_listmtx); if ((vp->v_mflag & VMP_TMPMNTFREELIST) != 0) { TAILQ_REMOVE(&mp->mnt_tmpfreevnodelist, vp, v_actfreelist); mp->mnt_tmpfreevnodelistsize--; vp->v_mflag &= ~VMP_TMPMNTFREELIST; } else { mtx_lock(&vnode_free_list_mtx); TAILQ_REMOVE(&vnode_free_list, vp, v_actfreelist); freevnodes--; mtx_unlock(&vnode_free_list_mtx); } KASSERT((vp->v_iflag & VI_ACTIVE) == 0, ("Activating already active vnode")); vp->v_iflag &= ~VI_FREE; vp->v_iflag |= VI_ACTIVE; TAILQ_INSERT_HEAD(&mp->mnt_activevnodelist, vp, v_actfreelist); mp->mnt_activevnodelistsize++; mtx_unlock(&mp->mnt_listmtx); refcount_acquire(&vp->v_holdcnt); if (!locked) VI_UNLOCK(vp); } /* * Drop the hold count of the vnode. If this is the last reference to * the vnode we place it on the free list unless it has been vgone'd * (marked VI_DOOMED) in which case we will free it. * * Because the vnode vm object keeps a hold reference on the vnode if * there is at least one resident non-cached page, the vnode cannot * leave the active list without the page cleanup done. */ void _vdrop(struct vnode *vp, bool locked) { struct bufobj *bo; struct mount *mp; int active; if (locked) ASSERT_VI_LOCKED(vp, __func__); else ASSERT_VI_UNLOCKED(vp, __func__); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); if ((int)vp->v_holdcnt <= 0) panic("vdrop: holdcnt %d", vp->v_holdcnt); if (vfs_refcount_release_if_not_last(&vp->v_holdcnt)) { if (locked) VI_UNLOCK(vp); return; } if (!locked) VI_LOCK(vp); if (refcount_release(&vp->v_holdcnt) == 0) { VI_UNLOCK(vp); return; } if ((vp->v_iflag & VI_DOOMED) == 0) { /* * Mark a vnode as free: remove it from its active list * and put it up for recycling on the freelist. */ VNASSERT(vp->v_op != NULL, vp, ("vdropl: vnode already reclaimed.")); VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, ("vnode already free")); VNASSERT(vp->v_holdcnt == 0, vp, ("vdropl: freeing when we shouldn't")); active = vp->v_iflag & VI_ACTIVE; if ((vp->v_iflag & VI_OWEINACT) == 0) { vp->v_iflag &= ~VI_ACTIVE; mp = vp->v_mount; mtx_lock(&mp->mnt_listmtx); if (active) { TAILQ_REMOVE(&mp->mnt_activevnodelist, vp, v_actfreelist); mp->mnt_activevnodelistsize--; } TAILQ_INSERT_TAIL(&mp->mnt_tmpfreevnodelist, vp, v_actfreelist); mp->mnt_tmpfreevnodelistsize++; vp->v_iflag |= VI_FREE; vp->v_mflag |= VMP_TMPMNTFREELIST; VI_UNLOCK(vp); if (mp->mnt_tmpfreevnodelistsize >= mnt_free_list_batch) vnlru_return_batch_locked(mp); mtx_unlock(&mp->mnt_listmtx); } else { VI_UNLOCK(vp); counter_u64_add(free_owe_inact, 1); } return; } /* * The vnode has been marked for destruction, so free it. * * The vnode will be returned to the zone where it will * normally remain until it is needed for another vnode. We * need to cleanup (or verify that the cleanup has already * been done) any residual data left from its current use * so as not to contaminate the freshly allocated vnode. */ CTR2(KTR_VFS, "%s: destroying the vnode %p", __func__, vp); atomic_subtract_long(&numvnodes, 1); bo = &vp->v_bufobj; VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, ("cleaned vnode still on the free list.")); VNASSERT(vp->v_data == NULL, vp, ("cleaned vnode isn't")); VNASSERT(vp->v_holdcnt == 0, vp, ("Non-zero hold count")); VNASSERT(vp->v_usecount == 0, vp, ("Non-zero use count")); VNASSERT(vp->v_writecount == 0, vp, ("Non-zero write count")); VNASSERT(bo->bo_numoutput == 0, vp, ("Clean vnode has pending I/O's")); VNASSERT(bo->bo_clean.bv_cnt == 0, vp, ("cleanbufcnt not 0")); VNASSERT(pctrie_is_empty(&bo->bo_clean.bv_root), vp, ("clean blk trie not empty")); VNASSERT(bo->bo_dirty.bv_cnt == 0, vp, ("dirtybufcnt not 0")); VNASSERT(pctrie_is_empty(&bo->bo_dirty.bv_root), vp, ("dirty blk trie not empty")); VNASSERT(TAILQ_EMPTY(&vp->v_cache_dst), vp, ("vp has namecache dst")); VNASSERT(LIST_EMPTY(&vp->v_cache_src), vp, ("vp has namecache src")); VNASSERT(vp->v_cache_dd == NULL, vp, ("vp has namecache for ..")); VNASSERT(TAILQ_EMPTY(&vp->v_rl.rl_waiters), vp, ("Dangling rangelock waiters")); VI_UNLOCK(vp); #ifdef MAC mac_vnode_destroy(vp); #endif if (vp->v_pollinfo != NULL) { destroy_vpollinfo(vp->v_pollinfo); vp->v_pollinfo = NULL; } #ifdef INVARIANTS /* XXX Elsewhere we detect an already freed vnode via NULL v_op. */ vp->v_op = NULL; #endif bzero(&vp->v_un, sizeof(vp->v_un)); vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0; vp->v_iflag = 0; vp->v_vflag = 0; bo->bo_flag = 0; uma_zfree(vnode_zone, vp); } /* * Call VOP_INACTIVE on the vnode and manage the DOINGINACT and OWEINACT * flags. DOINGINACT prevents us from recursing in calls to vinactive. * OWEINACT tracks whether a vnode missed a call to inactive due to a * failed lock upgrade. */ void vinactive(struct vnode *vp, struct thread *td) { struct vm_object *obj; ASSERT_VOP_ELOCKED(vp, "vinactive"); ASSERT_VI_LOCKED(vp, "vinactive"); VNASSERT((vp->v_iflag & VI_DOINGINACT) == 0, vp, ("vinactive: recursed on VI_DOINGINACT")); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); vp->v_iflag |= VI_DOINGINACT; vp->v_iflag &= ~VI_OWEINACT; VI_UNLOCK(vp); /* * Before moving off the active list, we must be sure that any * modified pages are converted into the vnode's dirty * buffers, since these will no longer be checked once the * vnode is on the inactive list. * * The write-out of the dirty pages is asynchronous. At the * point that VOP_INACTIVE() is called, there could still be * pending I/O and dirty pages in the object. */ obj = vp->v_object; if (obj != NULL && (obj->flags & OBJ_MIGHTBEDIRTY) != 0) { VM_OBJECT_WLOCK(obj); vm_object_page_clean(obj, 0, 0, 0); VM_OBJECT_WUNLOCK(obj); } VOP_INACTIVE(vp, td); VI_LOCK(vp); VNASSERT(vp->v_iflag & VI_DOINGINACT, vp, ("vinactive: lost VI_DOINGINACT")); vp->v_iflag &= ~VI_DOINGINACT; } /* * Remove any vnodes in the vnode table belonging to mount point mp. * * If FORCECLOSE is not specified, there should not be any active ones, * return error if any are found (nb: this is a user error, not a * system error). If FORCECLOSE is specified, detach any active vnodes * that are found. * * If WRITECLOSE is set, only flush out regular file vnodes open for * writing. * * SKIPSYSTEM causes any vnodes marked VV_SYSTEM to be skipped. * * `rootrefs' specifies the base reference count for the root vnode * of this filesystem. The root vnode is considered busy if its * v_usecount exceeds this value. On a successful return, vflush(, td) * will call vrele() on the root vnode exactly rootrefs times. * If the SKIPSYSTEM or WRITECLOSE flags are specified, rootrefs must * be zero. */ #ifdef DIAGNOSTIC static int busyprt = 0; /* print out busy vnodes */ SYSCTL_INT(_debug, OID_AUTO, busyprt, CTLFLAG_RW, &busyprt, 0, "Print out busy vnodes"); #endif int vflush(struct mount *mp, int rootrefs, int flags, struct thread *td) { struct vnode *vp, *mvp, *rootvp = NULL; struct vattr vattr; int busy = 0, error; CTR4(KTR_VFS, "%s: mp %p with rootrefs %d and flags %d", __func__, mp, rootrefs, flags); if (rootrefs > 0) { KASSERT((flags & (SKIPSYSTEM | WRITECLOSE)) == 0, ("vflush: bad args")); /* * Get the filesystem root vnode. We can vput() it * immediately, since with rootrefs > 0, it won't go away. */ if ((error = VFS_ROOT(mp, LK_EXCLUSIVE, &rootvp)) != 0) { CTR2(KTR_VFS, "%s: vfs_root lookup failed with %d", __func__, error); return (error); } vput(rootvp); } loop: MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { vholdl(vp); error = vn_lock(vp, LK_INTERLOCK | LK_EXCLUSIVE); if (error) { vdrop(vp); MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); goto loop; } /* * Skip over a vnodes marked VV_SYSTEM. */ if ((flags & SKIPSYSTEM) && (vp->v_vflag & VV_SYSTEM)) { VOP_UNLOCK(vp, 0); vdrop(vp); continue; } /* * If WRITECLOSE is set, flush out unlinked but still open * files (even if open only for reading) and regular file * vnodes open for writing. */ if (flags & WRITECLOSE) { if (vp->v_object != NULL) { VM_OBJECT_WLOCK(vp->v_object); vm_object_page_clean(vp->v_object, 0, 0, 0); VM_OBJECT_WUNLOCK(vp->v_object); } error = VOP_FSYNC(vp, MNT_WAIT, td); if (error != 0) { VOP_UNLOCK(vp, 0); vdrop(vp); MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); return (error); } error = VOP_GETATTR(vp, &vattr, td->td_ucred); VI_LOCK(vp); if ((vp->v_type == VNON || (error == 0 && vattr.va_nlink > 0)) && (vp->v_writecount == 0 || vp->v_type != VREG)) { VOP_UNLOCK(vp, 0); vdropl(vp); continue; } } else VI_LOCK(vp); /* * With v_usecount == 0, all we need to do is clear out the * vnode data structures and we are done. * * If FORCECLOSE is set, forcibly close the vnode. */ if (vp->v_usecount == 0 || (flags & FORCECLOSE)) { vgonel(vp); } else { busy++; #ifdef DIAGNOSTIC if (busyprt) vn_printf(vp, "vflush: busy vnode "); #endif } VOP_UNLOCK(vp, 0); vdropl(vp); } if (rootrefs > 0 && (flags & FORCECLOSE) == 0) { /* * If just the root vnode is busy, and if its refcount * is equal to `rootrefs', then go ahead and kill it. */ VI_LOCK(rootvp); KASSERT(busy > 0, ("vflush: not busy")); VNASSERT(rootvp->v_usecount >= rootrefs, rootvp, ("vflush: usecount %d < rootrefs %d", rootvp->v_usecount, rootrefs)); if (busy == 1 && rootvp->v_usecount == rootrefs) { VOP_LOCK(rootvp, LK_EXCLUSIVE|LK_INTERLOCK); vgone(rootvp); VOP_UNLOCK(rootvp, 0); busy = 0; } else VI_UNLOCK(rootvp); } if (busy) { CTR2(KTR_VFS, "%s: failing as %d vnodes are busy", __func__, busy); return (EBUSY); } for (; rootrefs > 0; rootrefs--) vrele(rootvp); return (0); } /* * Recycle an unused vnode to the front of the free list. */ int vrecycle(struct vnode *vp) { int recycled; VI_LOCK(vp); recycled = vrecyclel(vp); VI_UNLOCK(vp); return (recycled); } /* * vrecycle, with the vp interlock held. */ int vrecyclel(struct vnode *vp) { int recycled; ASSERT_VOP_ELOCKED(vp, __func__); ASSERT_VI_LOCKED(vp, __func__); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); recycled = 0; if (vp->v_usecount == 0) { recycled = 1; vgonel(vp); } return (recycled); } /* * Eliminate all activity associated with a vnode * in preparation for reuse. */ void vgone(struct vnode *vp) { VI_LOCK(vp); vgonel(vp); VI_UNLOCK(vp); } static void notify_lowervp_vfs_dummy(struct mount *mp __unused, struct vnode *lowervp __unused) { } /* * Notify upper mounts about reclaimed or unlinked vnode. */ void vfs_notify_upper(struct vnode *vp, int event) { static struct vfsops vgonel_vfsops = { .vfs_reclaim_lowervp = notify_lowervp_vfs_dummy, .vfs_unlink_lowervp = notify_lowervp_vfs_dummy, }; struct mount *mp, *ump, *mmp; mp = vp->v_mount; if (mp == NULL) return; MNT_ILOCK(mp); if (TAILQ_EMPTY(&mp->mnt_uppers)) goto unlock; MNT_IUNLOCK(mp); mmp = malloc(sizeof(struct mount), M_TEMP, M_WAITOK | M_ZERO); mmp->mnt_op = &vgonel_vfsops; mmp->mnt_kern_flag |= MNTK_MARKER; MNT_ILOCK(mp); mp->mnt_kern_flag |= MNTK_VGONE_UPPER; for (ump = TAILQ_FIRST(&mp->mnt_uppers); ump != NULL;) { if ((ump->mnt_kern_flag & MNTK_MARKER) != 0) { ump = TAILQ_NEXT(ump, mnt_upper_link); continue; } TAILQ_INSERT_AFTER(&mp->mnt_uppers, ump, mmp, mnt_upper_link); MNT_IUNLOCK(mp); switch (event) { case VFS_NOTIFY_UPPER_RECLAIM: VFS_RECLAIM_LOWERVP(ump, vp); break; case VFS_NOTIFY_UPPER_UNLINK: VFS_UNLINK_LOWERVP(ump, vp); break; default: KASSERT(0, ("invalid event %d", event)); break; } MNT_ILOCK(mp); ump = TAILQ_NEXT(mmp, mnt_upper_link); TAILQ_REMOVE(&mp->mnt_uppers, mmp, mnt_upper_link); } free(mmp, M_TEMP); mp->mnt_kern_flag &= ~MNTK_VGONE_UPPER; if ((mp->mnt_kern_flag & MNTK_VGONE_WAITER) != 0) { mp->mnt_kern_flag &= ~MNTK_VGONE_WAITER; wakeup(&mp->mnt_uppers); } unlock: MNT_IUNLOCK(mp); } /* * vgone, with the vp interlock held. */ static void vgonel(struct vnode *vp) { struct thread *td; int oweinact; int active; struct mount *mp; ASSERT_VOP_ELOCKED(vp, "vgonel"); ASSERT_VI_LOCKED(vp, "vgonel"); VNASSERT(vp->v_holdcnt, vp, ("vgonel: vp %p has no reference.", vp)); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); td = curthread; /* * Don't vgonel if we're already doomed. */ if (vp->v_iflag & VI_DOOMED) return; vp->v_iflag |= VI_DOOMED; /* * Check to see if the vnode is in use. If so, we have to call * VOP_CLOSE() and VOP_INACTIVE(). */ active = vp->v_usecount; oweinact = (vp->v_iflag & VI_OWEINACT); VI_UNLOCK(vp); vfs_notify_upper(vp, VFS_NOTIFY_UPPER_RECLAIM); /* * If purging an active vnode, it must be closed and * deactivated before being reclaimed. */ if (active) VOP_CLOSE(vp, FNONBLOCK, NOCRED, td); if (oweinact || active) { VI_LOCK(vp); if ((vp->v_iflag & VI_DOINGINACT) == 0) vinactive(vp, td); VI_UNLOCK(vp); } if (vp->v_type == VSOCK) vfs_unp_reclaim(vp); /* * Clean out any buffers associated with the vnode. * If the flush fails, just toss the buffers. */ mp = NULL; if (!TAILQ_EMPTY(&vp->v_bufobj.bo_dirty.bv_hd)) (void) vn_start_secondary_write(vp, &mp, V_WAIT); if (vinvalbuf(vp, V_SAVE, 0, 0) != 0) { while (vinvalbuf(vp, 0, 0, 0) != 0) ; } BO_LOCK(&vp->v_bufobj); KASSERT(TAILQ_EMPTY(&vp->v_bufobj.bo_dirty.bv_hd) && vp->v_bufobj.bo_dirty.bv_cnt == 0 && TAILQ_EMPTY(&vp->v_bufobj.bo_clean.bv_hd) && vp->v_bufobj.bo_clean.bv_cnt == 0, ("vp %p bufobj not invalidated", vp)); /* * For VMIO bufobj, BO_DEAD is set in vm_object_terminate() * after the object's page queue is flushed. */ if (vp->v_bufobj.bo_object == NULL) vp->v_bufobj.bo_flag |= BO_DEAD; BO_UNLOCK(&vp->v_bufobj); /* * Reclaim the vnode. */ if (VOP_RECLAIM(vp, td)) panic("vgone: cannot reclaim"); if (mp != NULL) vn_finished_secondary_write(mp); VNASSERT(vp->v_object == NULL, vp, ("vop_reclaim left v_object vp=%p, tag=%s", vp, vp->v_tag)); /* * Clear the advisory locks and wake up waiting threads. */ (void)VOP_ADVLOCKPURGE(vp); vp->v_lockf = NULL; /* * Delete from old mount point vnode list. */ delmntque(vp); cache_purge(vp); /* * Done with purge, reset to the standard lock and invalidate * the vnode. */ VI_LOCK(vp); vp->v_vnlock = &vp->v_lock; vp->v_op = &dead_vnodeops; vp->v_tag = "none"; vp->v_type = VBAD; } /* * Calculate the total number of references to a special device. */ int vcount(struct vnode *vp) { int count; dev_lock(); count = vp->v_rdev->si_usecount; dev_unlock(); return (count); } /* * Same as above, but using the struct cdev *as argument */ int count_dev(struct cdev *dev) { int count; dev_lock(); count = dev->si_usecount; dev_unlock(); return(count); } /* * Print out a description of a vnode. */ static char *typename[] = {"VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD", "VMARKER"}; void vn_printf(struct vnode *vp, const char *fmt, ...) { va_list ap; char buf[256], buf2[16]; u_long flags; va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("%p: ", (void *)vp); printf("tag %s, type %s\n", vp->v_tag, typename[vp->v_type]); printf(" usecount %d, writecount %d, refcount %d mountedhere %p\n", vp->v_usecount, vp->v_writecount, vp->v_holdcnt, vp->v_mountedhere); buf[0] = '\0'; buf[1] = '\0'; if (vp->v_vflag & VV_ROOT) strlcat(buf, "|VV_ROOT", sizeof(buf)); if (vp->v_vflag & VV_ISTTY) strlcat(buf, "|VV_ISTTY", sizeof(buf)); if (vp->v_vflag & VV_NOSYNC) strlcat(buf, "|VV_NOSYNC", sizeof(buf)); if (vp->v_vflag & VV_ETERNALDEV) strlcat(buf, "|VV_ETERNALDEV", sizeof(buf)); if (vp->v_vflag & VV_CACHEDLABEL) strlcat(buf, "|VV_CACHEDLABEL", sizeof(buf)); if (vp->v_vflag & VV_TEXT) strlcat(buf, "|VV_TEXT", sizeof(buf)); if (vp->v_vflag & VV_COPYONWRITE) strlcat(buf, "|VV_COPYONWRITE", sizeof(buf)); if (vp->v_vflag & VV_SYSTEM) strlcat(buf, "|VV_SYSTEM", sizeof(buf)); if (vp->v_vflag & VV_PROCDEP) strlcat(buf, "|VV_PROCDEP", sizeof(buf)); if (vp->v_vflag & VV_NOKNOTE) strlcat(buf, "|VV_NOKNOTE", sizeof(buf)); if (vp->v_vflag & VV_DELETED) strlcat(buf, "|VV_DELETED", sizeof(buf)); if (vp->v_vflag & VV_MD) strlcat(buf, "|VV_MD", sizeof(buf)); if (vp->v_vflag & VV_FORCEINSMQ) strlcat(buf, "|VV_FORCEINSMQ", sizeof(buf)); flags = vp->v_vflag & ~(VV_ROOT | VV_ISTTY | VV_NOSYNC | VV_ETERNALDEV | VV_CACHEDLABEL | VV_TEXT | VV_COPYONWRITE | VV_SYSTEM | VV_PROCDEP | VV_NOKNOTE | VV_DELETED | VV_MD | VV_FORCEINSMQ); if (flags != 0) { snprintf(buf2, sizeof(buf2), "|VV(0x%lx)", flags); strlcat(buf, buf2, sizeof(buf)); } if (vp->v_iflag & VI_MOUNT) strlcat(buf, "|VI_MOUNT", sizeof(buf)); if (vp->v_iflag & VI_DOOMED) strlcat(buf, "|VI_DOOMED", sizeof(buf)); if (vp->v_iflag & VI_FREE) strlcat(buf, "|VI_FREE", sizeof(buf)); if (vp->v_iflag & VI_ACTIVE) strlcat(buf, "|VI_ACTIVE", sizeof(buf)); if (vp->v_iflag & VI_DOINGINACT) strlcat(buf, "|VI_DOINGINACT", sizeof(buf)); if (vp->v_iflag & VI_OWEINACT) strlcat(buf, "|VI_OWEINACT", sizeof(buf)); flags = vp->v_iflag & ~(VI_MOUNT | VI_DOOMED | VI_FREE | VI_ACTIVE | VI_DOINGINACT | VI_OWEINACT); if (flags != 0) { snprintf(buf2, sizeof(buf2), "|VI(0x%lx)", flags); strlcat(buf, buf2, sizeof(buf)); } printf(" flags (%s)\n", buf + 1); if (mtx_owned(VI_MTX(vp))) printf(" VI_LOCKed"); if (vp->v_object != NULL) printf(" v_object %p ref %d pages %d " "cleanbuf %d dirtybuf %d\n", vp->v_object, vp->v_object->ref_count, vp->v_object->resident_page_count, vp->v_bufobj.bo_clean.bv_cnt, vp->v_bufobj.bo_dirty.bv_cnt); printf(" "); lockmgr_printinfo(vp->v_vnlock); if (vp->v_data != NULL) VOP_PRINT(vp); } #ifdef DDB /* * List all of the locked vnodes in the system. * Called when debugging the kernel. */ DB_SHOW_COMMAND(lockedvnods, lockedvnodes) { struct mount *mp; struct vnode *vp; /* * Note: because this is DDB, we can't obey the locking semantics * for these structures, which means we could catch an inconsistent * state and dereference a nasty pointer. Not much to be done * about that. */ db_printf("Locked vnodes\n"); TAILQ_FOREACH(mp, &mountlist, mnt_list) { TAILQ_FOREACH(vp, &mp->mnt_nvnodelist, v_nmntvnodes) { if (vp->v_type != VMARKER && VOP_ISLOCKED(vp)) vn_printf(vp, "vnode "); } } } /* * Show details about the given vnode. */ DB_SHOW_COMMAND(vnode, db_show_vnode) { struct vnode *vp; if (!have_addr) return; vp = (struct vnode *)addr; vn_printf(vp, "vnode "); } /* * Show details about the given mount point. */ DB_SHOW_COMMAND(mount, db_show_mount) { struct mount *mp; struct vfsopt *opt; struct statfs *sp; struct vnode *vp; char buf[512]; uint64_t mflags; u_int flags; if (!have_addr) { /* No address given, print short info about all mount points. */ TAILQ_FOREACH(mp, &mountlist, mnt_list) { db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename); if (db_pager_quit) break; } db_printf("\nMore info: show mount \n"); return; } mp = (struct mount *)addr; db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename); buf[0] = '\0'; mflags = mp->mnt_flag; #define MNT_FLAG(flag) do { \ if (mflags & (flag)) { \ if (buf[0] != '\0') \ strlcat(buf, ", ", sizeof(buf)); \ strlcat(buf, (#flag) + 4, sizeof(buf)); \ mflags &= ~(flag); \ } \ } while (0) MNT_FLAG(MNT_RDONLY); MNT_FLAG(MNT_SYNCHRONOUS); MNT_FLAG(MNT_NOEXEC); MNT_FLAG(MNT_NOSUID); MNT_FLAG(MNT_NFS4ACLS); MNT_FLAG(MNT_UNION); MNT_FLAG(MNT_ASYNC); MNT_FLAG(MNT_SUIDDIR); MNT_FLAG(MNT_SOFTDEP); MNT_FLAG(MNT_NOSYMFOLLOW); MNT_FLAG(MNT_GJOURNAL); MNT_FLAG(MNT_MULTILABEL); MNT_FLAG(MNT_ACLS); MNT_FLAG(MNT_NOATIME); MNT_FLAG(MNT_NOCLUSTERR); MNT_FLAG(MNT_NOCLUSTERW); MNT_FLAG(MNT_SUJ); MNT_FLAG(MNT_EXRDONLY); MNT_FLAG(MNT_EXPORTED); MNT_FLAG(MNT_DEFEXPORTED); MNT_FLAG(MNT_EXPORTANON); MNT_FLAG(MNT_EXKERB); MNT_FLAG(MNT_EXPUBLIC); MNT_FLAG(MNT_LOCAL); MNT_FLAG(MNT_QUOTA); MNT_FLAG(MNT_ROOTFS); MNT_FLAG(MNT_USER); MNT_FLAG(MNT_IGNORE); MNT_FLAG(MNT_UPDATE); MNT_FLAG(MNT_DELEXPORT); MNT_FLAG(MNT_RELOAD); MNT_FLAG(MNT_FORCE); MNT_FLAG(MNT_SNAPSHOT); MNT_FLAG(MNT_BYFSID); #undef MNT_FLAG if (mflags != 0) { if (buf[0] != '\0') strlcat(buf, ", ", sizeof(buf)); snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "0x%016jx", mflags); } db_printf(" mnt_flag = %s\n", buf); buf[0] = '\0'; flags = mp->mnt_kern_flag; #define MNT_KERN_FLAG(flag) do { \ if (flags & (flag)) { \ if (buf[0] != '\0') \ strlcat(buf, ", ", sizeof(buf)); \ strlcat(buf, (#flag) + 5, sizeof(buf)); \ flags &= ~(flag); \ } \ } while (0) MNT_KERN_FLAG(MNTK_UNMOUNTF); MNT_KERN_FLAG(MNTK_ASYNC); MNT_KERN_FLAG(MNTK_SOFTDEP); MNT_KERN_FLAG(MNTK_NOINSMNTQ); MNT_KERN_FLAG(MNTK_DRAINING); MNT_KERN_FLAG(MNTK_REFEXPIRE); MNT_KERN_FLAG(MNTK_EXTENDED_SHARED); MNT_KERN_FLAG(MNTK_SHARED_WRITES); MNT_KERN_FLAG(MNTK_NO_IOPF); MNT_KERN_FLAG(MNTK_VGONE_UPPER); MNT_KERN_FLAG(MNTK_VGONE_WAITER); MNT_KERN_FLAG(MNTK_LOOKUP_EXCL_DOTDOT); MNT_KERN_FLAG(MNTK_MARKER); MNT_KERN_FLAG(MNTK_USES_BCACHE); MNT_KERN_FLAG(MNTK_NOASYNC); MNT_KERN_FLAG(MNTK_UNMOUNT); MNT_KERN_FLAG(MNTK_MWAIT); MNT_KERN_FLAG(MNTK_SUSPEND); MNT_KERN_FLAG(MNTK_SUSPEND2); MNT_KERN_FLAG(MNTK_SUSPENDED); MNT_KERN_FLAG(MNTK_LOOKUP_SHARED); MNT_KERN_FLAG(MNTK_NOKNOTE); #undef MNT_KERN_FLAG if (flags != 0) { if (buf[0] != '\0') strlcat(buf, ", ", sizeof(buf)); snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "0x%08x", flags); } db_printf(" mnt_kern_flag = %s\n", buf); db_printf(" mnt_opt = "); opt = TAILQ_FIRST(mp->mnt_opt); if (opt != NULL) { db_printf("%s", opt->name); opt = TAILQ_NEXT(opt, link); while (opt != NULL) { db_printf(", %s", opt->name); opt = TAILQ_NEXT(opt, link); } } db_printf("\n"); sp = &mp->mnt_stat; db_printf(" mnt_stat = { version=%u type=%u flags=0x%016jx " "bsize=%ju iosize=%ju blocks=%ju bfree=%ju bavail=%jd files=%ju " "ffree=%jd syncwrites=%ju asyncwrites=%ju syncreads=%ju " "asyncreads=%ju namemax=%u owner=%u fsid=[%d, %d] }\n", (u_int)sp->f_version, (u_int)sp->f_type, (uintmax_t)sp->f_flags, (uintmax_t)sp->f_bsize, (uintmax_t)sp->f_iosize, (uintmax_t)sp->f_blocks, (uintmax_t)sp->f_bfree, (intmax_t)sp->f_bavail, (uintmax_t)sp->f_files, (intmax_t)sp->f_ffree, (uintmax_t)sp->f_syncwrites, (uintmax_t)sp->f_asyncwrites, (uintmax_t)sp->f_syncreads, (uintmax_t)sp->f_asyncreads, (u_int)sp->f_namemax, (u_int)sp->f_owner, (int)sp->f_fsid.val[0], (int)sp->f_fsid.val[1]); db_printf(" mnt_cred = { uid=%u ruid=%u", (u_int)mp->mnt_cred->cr_uid, (u_int)mp->mnt_cred->cr_ruid); if (jailed(mp->mnt_cred)) db_printf(", jail=%d", mp->mnt_cred->cr_prison->pr_id); db_printf(" }\n"); db_printf(" mnt_ref = %d\n", mp->mnt_ref); db_printf(" mnt_gen = %d\n", mp->mnt_gen); db_printf(" mnt_nvnodelistsize = %d\n", mp->mnt_nvnodelistsize); db_printf(" mnt_activevnodelistsize = %d\n", mp->mnt_activevnodelistsize); db_printf(" mnt_writeopcount = %d\n", mp->mnt_writeopcount); db_printf(" mnt_maxsymlinklen = %d\n", mp->mnt_maxsymlinklen); db_printf(" mnt_iosize_max = %d\n", mp->mnt_iosize_max); db_printf(" mnt_hashseed = %u\n", mp->mnt_hashseed); db_printf(" mnt_lockref = %d\n", mp->mnt_lockref); db_printf(" mnt_secondary_writes = %d\n", mp->mnt_secondary_writes); db_printf(" mnt_secondary_accwrites = %d\n", mp->mnt_secondary_accwrites); db_printf(" mnt_gjprovider = %s\n", mp->mnt_gjprovider != NULL ? mp->mnt_gjprovider : "NULL"); db_printf("\n\nList of active vnodes\n"); TAILQ_FOREACH(vp, &mp->mnt_activevnodelist, v_actfreelist) { if (vp->v_type != VMARKER) { vn_printf(vp, "vnode "); if (db_pager_quit) break; } } db_printf("\n\nList of inactive vnodes\n"); TAILQ_FOREACH(vp, &mp->mnt_nvnodelist, v_nmntvnodes) { if (vp->v_type != VMARKER && (vp->v_iflag & VI_ACTIVE) == 0) { vn_printf(vp, "vnode "); if (db_pager_quit) break; } } } #endif /* DDB */ /* * Fill in a struct xvfsconf based on a struct vfsconf. */ static int vfsconf2x(struct sysctl_req *req, struct vfsconf *vfsp) { struct xvfsconf xvfsp; bzero(&xvfsp, sizeof(xvfsp)); strcpy(xvfsp.vfc_name, vfsp->vfc_name); xvfsp.vfc_typenum = vfsp->vfc_typenum; xvfsp.vfc_refcount = vfsp->vfc_refcount; xvfsp.vfc_flags = vfsp->vfc_flags; /* * These are unused in userland, we keep them * to not break binary compatibility. */ xvfsp.vfc_vfsops = NULL; xvfsp.vfc_next = NULL; return (SYSCTL_OUT(req, &xvfsp, sizeof(xvfsp))); } #ifdef COMPAT_FREEBSD32 struct xvfsconf32 { uint32_t vfc_vfsops; char vfc_name[MFSNAMELEN]; int32_t vfc_typenum; int32_t vfc_refcount; int32_t vfc_flags; uint32_t vfc_next; }; static int vfsconf2x32(struct sysctl_req *req, struct vfsconf *vfsp) { struct xvfsconf32 xvfsp; strcpy(xvfsp.vfc_name, vfsp->vfc_name); xvfsp.vfc_typenum = vfsp->vfc_typenum; xvfsp.vfc_refcount = vfsp->vfc_refcount; xvfsp.vfc_flags = vfsp->vfc_flags; xvfsp.vfc_vfsops = 0; xvfsp.vfc_next = 0; return (SYSCTL_OUT(req, &xvfsp, sizeof(xvfsp))); } #endif /* * Top level filesystem related information gathering. */ static int sysctl_vfs_conflist(SYSCTL_HANDLER_ARGS) { struct vfsconf *vfsp; int error; error = 0; vfsconf_slock(); TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { #ifdef COMPAT_FREEBSD32 if (req->flags & SCTL_MASK32) error = vfsconf2x32(req, vfsp); else #endif error = vfsconf2x(req, vfsp); if (error) break; } vfsconf_sunlock(); return (error); } SYSCTL_PROC(_vfs, OID_AUTO, conflist, CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_vfs_conflist, "S,xvfsconf", "List of all configured filesystems"); #ifndef BURN_BRIDGES static int sysctl_ovfs_conf(SYSCTL_HANDLER_ARGS); static int vfs_sysctl(SYSCTL_HANDLER_ARGS) { int *name = (int *)arg1 - 1; /* XXX */ u_int namelen = arg2 + 1; /* XXX */ struct vfsconf *vfsp; log(LOG_WARNING, "userland calling deprecated sysctl, " "please rebuild world\n"); #if 1 || defined(COMPAT_PRELITE2) /* Resolve ambiguity between VFS_VFSCONF and VFS_GENERIC. */ if (namelen == 1) return (sysctl_ovfs_conf(oidp, arg1, arg2, req)); #endif switch (name[1]) { case VFS_MAXTYPENUM: if (namelen != 2) return (ENOTDIR); return (SYSCTL_OUT(req, &maxvfsconf, sizeof(int))); case VFS_CONF: if (namelen != 3) return (ENOTDIR); /* overloaded */ vfsconf_slock(); TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { if (vfsp->vfc_typenum == name[2]) break; } vfsconf_sunlock(); if (vfsp == NULL) return (EOPNOTSUPP); #ifdef COMPAT_FREEBSD32 if (req->flags & SCTL_MASK32) return (vfsconf2x32(req, vfsp)); else #endif return (vfsconf2x(req, vfsp)); } return (EOPNOTSUPP); } static SYSCTL_NODE(_vfs, VFS_GENERIC, generic, CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE, vfs_sysctl, "Generic filesystem"); #if 1 || defined(COMPAT_PRELITE2) static int sysctl_ovfs_conf(SYSCTL_HANDLER_ARGS) { int error; struct vfsconf *vfsp; struct ovfsconf ovfs; vfsconf_slock(); TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { bzero(&ovfs, sizeof(ovfs)); ovfs.vfc_vfsops = vfsp->vfc_vfsops; /* XXX used as flag */ strcpy(ovfs.vfc_name, vfsp->vfc_name); ovfs.vfc_index = vfsp->vfc_typenum; ovfs.vfc_refcount = vfsp->vfc_refcount; ovfs.vfc_flags = vfsp->vfc_flags; error = SYSCTL_OUT(req, &ovfs, sizeof ovfs); if (error != 0) { vfsconf_sunlock(); return (error); } } vfsconf_sunlock(); return (0); } #endif /* 1 || COMPAT_PRELITE2 */ #endif /* !BURN_BRIDGES */ #define KINFO_VNODESLOP 10 #ifdef notyet /* * Dump vnode list (via sysctl). */ /* ARGSUSED */ static int sysctl_vnode(SYSCTL_HANDLER_ARGS) { struct xvnode *xvn; struct mount *mp; struct vnode *vp; int error, len, n; /* * Stale numvnodes access is not fatal here. */ req->lock = 0; len = (numvnodes + KINFO_VNODESLOP) * sizeof *xvn; if (!req->oldptr) /* Make an estimate */ return (SYSCTL_OUT(req, 0, len)); error = sysctl_wire_old_buffer(req, 0); if (error != 0) return (error); xvn = malloc(len, M_TEMP, M_ZERO | M_WAITOK); n = 0; mtx_lock(&mountlist_mtx); TAILQ_FOREACH(mp, &mountlist, mnt_list) { if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK)) continue; MNT_ILOCK(mp); TAILQ_FOREACH(vp, &mp->mnt_nvnodelist, v_nmntvnodes) { if (n == len) break; vref(vp); xvn[n].xv_size = sizeof *xvn; xvn[n].xv_vnode = vp; xvn[n].xv_id = 0; /* XXX compat */ #define XV_COPY(field) xvn[n].xv_##field = vp->v_##field XV_COPY(usecount); XV_COPY(writecount); XV_COPY(holdcnt); XV_COPY(mount); XV_COPY(numoutput); XV_COPY(type); #undef XV_COPY xvn[n].xv_flag = vp->v_vflag; switch (vp->v_type) { case VREG: case VDIR: case VLNK: break; case VBLK: case VCHR: if (vp->v_rdev == NULL) { vrele(vp); continue; } xvn[n].xv_dev = dev2udev(vp->v_rdev); break; case VSOCK: xvn[n].xv_socket = vp->v_socket; break; case VFIFO: xvn[n].xv_fifo = vp->v_fifoinfo; break; case VNON: case VBAD: default: /* shouldn't happen? */ vrele(vp); continue; } vrele(vp); ++n; } MNT_IUNLOCK(mp); mtx_lock(&mountlist_mtx); vfs_unbusy(mp); if (n == len) break; } mtx_unlock(&mountlist_mtx); error = SYSCTL_OUT(req, xvn, n * sizeof *xvn); free(xvn, M_TEMP); return (error); } SYSCTL_PROC(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0, sysctl_vnode, "S,xvnode", ""); #endif static void unmount_or_warn(struct mount *mp) { int error; error = dounmount(mp, MNT_FORCE, curthread); if (error != 0) { printf("unmount of %s failed (", mp->mnt_stat.f_mntonname); if (error == EBUSY) printf("BUSY)\n"); else printf("%d)\n", error); } } /* * Unmount all filesystems. The list is traversed in reverse order * of mounting to avoid dependencies. */ void vfs_unmountall(void) { struct mount *mp, *tmp; CTR1(KTR_VFS, "%s: unmounting all filesystems", __func__); /* * Since this only runs when rebooting, it is not interlocked. */ TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mntlist, mnt_list, tmp) { vfs_ref(mp); /* * Forcibly unmounting "/dev" before "/" would prevent clean * unmount of the latter. */ if (mp == rootdevmp) continue; unmount_or_warn(mp); } if (rootdevmp != NULL) unmount_or_warn(rootdevmp); } /* * perform msync on all vnodes under a mount point * the mount point must be locked. */ void vfs_msync(struct mount *mp, int flags) { struct vnode *vp, *mvp; struct vm_object *obj; CTR2(KTR_VFS, "%s: mp %p", __func__, mp); vnlru_return_batch(mp); MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { obj = vp->v_object; if (obj != NULL && (obj->flags & OBJ_MIGHTBEDIRTY) != 0 && (flags == MNT_WAIT || VOP_ISLOCKED(vp) == 0)) { if (!vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK, curthread)) { if (vp->v_vflag & VV_NOSYNC) { /* unlinked */ vput(vp); continue; } obj = vp->v_object; if (obj != NULL) { VM_OBJECT_WLOCK(obj); vm_object_page_clean(obj, 0, 0, flags == MNT_WAIT ? OBJPC_SYNC : OBJPC_NOSYNC); VM_OBJECT_WUNLOCK(obj); } vput(vp); } } else VI_UNLOCK(vp); } } static void destroy_vpollinfo_free(struct vpollinfo *vi) { knlist_destroy(&vi->vpi_selinfo.si_note); mtx_destroy(&vi->vpi_lock); uma_zfree(vnodepoll_zone, vi); } static void destroy_vpollinfo(struct vpollinfo *vi) { knlist_clear(&vi->vpi_selinfo.si_note, 1); seldrain(&vi->vpi_selinfo); destroy_vpollinfo_free(vi); } /* * Initialize per-vnode helper structure to hold poll-related state. */ void v_addpollinfo(struct vnode *vp) { struct vpollinfo *vi; if (vp->v_pollinfo != NULL) return; vi = uma_zalloc(vnodepoll_zone, M_WAITOK | M_ZERO); mtx_init(&vi->vpi_lock, "vnode pollinfo", NULL, MTX_DEF); knlist_init(&vi->vpi_selinfo.si_note, vp, vfs_knllock, vfs_knlunlock, vfs_knl_assert_locked, vfs_knl_assert_unlocked); VI_LOCK(vp); if (vp->v_pollinfo != NULL) { VI_UNLOCK(vp); destroy_vpollinfo_free(vi); return; } vp->v_pollinfo = vi; VI_UNLOCK(vp); } /* * Record a process's interest in events which might happen to * a vnode. Because poll uses the historic select-style interface * internally, this routine serves as both the ``check for any * pending events'' and the ``record my interest in future events'' * functions. (These are done together, while the lock is held, * to avoid race conditions.) */ int vn_pollrecord(struct vnode *vp, struct thread *td, int events) { v_addpollinfo(vp); mtx_lock(&vp->v_pollinfo->vpi_lock); if (vp->v_pollinfo->vpi_revents & events) { /* * This leaves events we are not interested * in available for the other process which * which presumably had requested them * (otherwise they would never have been * recorded). */ events &= vp->v_pollinfo->vpi_revents; vp->v_pollinfo->vpi_revents &= ~events; mtx_unlock(&vp->v_pollinfo->vpi_lock); return (events); } vp->v_pollinfo->vpi_events |= events; selrecord(td, &vp->v_pollinfo->vpi_selinfo); mtx_unlock(&vp->v_pollinfo->vpi_lock); return (0); } /* * Routine to create and manage a filesystem syncer vnode. */ #define sync_close ((int (*)(struct vop_close_args *))nullop) static int sync_fsync(struct vop_fsync_args *); static int sync_inactive(struct vop_inactive_args *); static int sync_reclaim(struct vop_reclaim_args *); static struct vop_vector sync_vnodeops = { .vop_bypass = VOP_EOPNOTSUPP, .vop_close = sync_close, /* close */ .vop_fsync = sync_fsync, /* fsync */ .vop_inactive = sync_inactive, /* inactive */ .vop_reclaim = sync_reclaim, /* reclaim */ .vop_lock1 = vop_stdlock, /* lock */ .vop_unlock = vop_stdunlock, /* unlock */ .vop_islocked = vop_stdislocked, /* islocked */ }; /* * Create a new filesystem syncer vnode for the specified mount point. */ void vfs_allocate_syncvnode(struct mount *mp) { struct vnode *vp; struct bufobj *bo; static long start, incr, next; int error; /* Allocate a new vnode */ error = getnewvnode("syncer", mp, &sync_vnodeops, &vp); if (error != 0) panic("vfs_allocate_syncvnode: getnewvnode() failed"); vp->v_type = VNON; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vp->v_vflag |= VV_FORCEINSMQ; error = insmntque(vp, mp); if (error != 0) panic("vfs_allocate_syncvnode: insmntque() failed"); vp->v_vflag &= ~VV_FORCEINSMQ; VOP_UNLOCK(vp, 0); /* * Place the vnode onto the syncer worklist. We attempt to * scatter them about on the list so that they will go off * at evenly distributed times even if all the filesystems * are mounted at once. */ next += incr; if (next == 0 || next > syncer_maxdelay) { start /= 2; incr /= 2; if (start == 0) { start = syncer_maxdelay / 2; incr = syncer_maxdelay; } next = start; } bo = &vp->v_bufobj; BO_LOCK(bo); vn_syncer_add_to_worklist(bo, syncdelay > 0 ? next % syncdelay : 0); /* XXX - vn_syncer_add_to_worklist() also grabs and drops sync_mtx. */ mtx_lock(&sync_mtx); sync_vnode_count++; if (mp->mnt_syncer == NULL) { mp->mnt_syncer = vp; vp = NULL; } mtx_unlock(&sync_mtx); BO_UNLOCK(bo); if (vp != NULL) { vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vgone(vp); vput(vp); } } void vfs_deallocate_syncvnode(struct mount *mp) { struct vnode *vp; mtx_lock(&sync_mtx); vp = mp->mnt_syncer; if (vp != NULL) mp->mnt_syncer = NULL; mtx_unlock(&sync_mtx); if (vp != NULL) vrele(vp); } /* * Do a lazy sync of the filesystem. */ static int sync_fsync(struct vop_fsync_args *ap) { struct vnode *syncvp = ap->a_vp; struct mount *mp = syncvp->v_mount; int error, save; struct bufobj *bo; /* * We only need to do something if this is a lazy evaluation. */ if (ap->a_waitfor != MNT_LAZY) return (0); /* * Move ourselves to the back of the sync list. */ bo = &syncvp->v_bufobj; BO_LOCK(bo); vn_syncer_add_to_worklist(bo, syncdelay); BO_UNLOCK(bo); /* * Walk the list of vnodes pushing all that are dirty and * not already on the sync list. */ if (vfs_busy(mp, MBF_NOWAIT) != 0) return (0); if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) { vfs_unbusy(mp); return (0); } save = curthread_pflags_set(TDP_SYNCIO); vfs_msync(mp, MNT_NOWAIT); error = VFS_SYNC(mp, MNT_LAZY); curthread_pflags_restore(save); vn_finished_write(mp); vfs_unbusy(mp); return (error); } /* * The syncer vnode is no referenced. */ static int sync_inactive(struct vop_inactive_args *ap) { vgone(ap->a_vp); return (0); } /* * The syncer vnode is no longer needed and is being decommissioned. * * Modifications to the worklist must be protected by sync_mtx. */ static int sync_reclaim(struct vop_reclaim_args *ap) { struct vnode *vp = ap->a_vp; struct bufobj *bo; bo = &vp->v_bufobj; BO_LOCK(bo); mtx_lock(&sync_mtx); if (vp->v_mount->mnt_syncer == vp) vp->v_mount->mnt_syncer = NULL; if (bo->bo_flag & BO_ONWORKLST) { LIST_REMOVE(bo, bo_synclist); syncer_worklist_len--; sync_vnode_count--; bo->bo_flag &= ~BO_ONWORKLST; } mtx_unlock(&sync_mtx); BO_UNLOCK(bo); return (0); } /* * Check if vnode represents a disk device */ int vn_isdisk(struct vnode *vp, int *errp) { int error; if (vp->v_type != VCHR) { error = ENOTBLK; goto out; } error = 0; dev_lock(); if (vp->v_rdev == NULL) error = ENXIO; else if (vp->v_rdev->si_devsw == NULL) error = ENXIO; else if (!(vp->v_rdev->si_devsw->d_flags & D_DISK)) error = ENOTBLK; dev_unlock(); out: if (errp != NULL) *errp = error; return (error == 0); } /* * Common filesystem object access control check routine. Accepts a * vnode's type, "mode", uid and gid, requested access mode, credentials, * and optional call-by-reference privused argument allowing vaccess() * to indicate to the caller whether privilege was used to satisfy the * request (obsoleted). Returns 0 on success, or an errno on failure. */ int vaccess(enum vtype type, mode_t file_mode, uid_t file_uid, gid_t file_gid, accmode_t accmode, struct ucred *cred, int *privused) { accmode_t dac_granted; accmode_t priv_granted; KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0, ("invalid bit in accmode")); KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE), ("VAPPEND without VWRITE")); /* * Look for a normal, non-privileged way to access the file/directory * as requested. If it exists, go with that. */ if (privused != NULL) *privused = 0; dac_granted = 0; /* Check the owner. */ if (cred->cr_uid == file_uid) { dac_granted |= VADMIN; if (file_mode & S_IXUSR) dac_granted |= VEXEC; if (file_mode & S_IRUSR) dac_granted |= VREAD; if (file_mode & S_IWUSR) dac_granted |= (VWRITE | VAPPEND); if ((accmode & dac_granted) == accmode) return (0); goto privcheck; } /* Otherwise, check the groups (first match) */ if (groupmember(file_gid, cred)) { if (file_mode & S_IXGRP) dac_granted |= VEXEC; if (file_mode & S_IRGRP) dac_granted |= VREAD; if (file_mode & S_IWGRP) dac_granted |= (VWRITE | VAPPEND); if ((accmode & dac_granted) == accmode) return (0); goto privcheck; } /* Otherwise, check everyone else. */ if (file_mode & S_IXOTH) dac_granted |= VEXEC; if (file_mode & S_IROTH) dac_granted |= VREAD; if (file_mode & S_IWOTH) dac_granted |= (VWRITE | VAPPEND); if ((accmode & dac_granted) == accmode) return (0); privcheck: /* * Build a privilege mask to determine if the set of privileges * satisfies the requirements when combined with the granted mask * from above. For each privilege, if the privilege is required, * bitwise or the request type onto the priv_granted mask. */ priv_granted = 0; if (type == VDIR) { /* * For directories, use PRIV_VFS_LOOKUP to satisfy VEXEC * requests, instead of PRIV_VFS_EXEC. */ if ((accmode & VEXEC) && ((dac_granted & VEXEC) == 0) && !priv_check_cred(cred, PRIV_VFS_LOOKUP, 0)) priv_granted |= VEXEC; } else { /* * Ensure that at least one execute bit is on. Otherwise, * a privileged user will always succeed, and we don't want * this to happen unless the file really is executable. */ if ((accmode & VEXEC) && ((dac_granted & VEXEC) == 0) && (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 && !priv_check_cred(cred, PRIV_VFS_EXEC, 0)) priv_granted |= VEXEC; } if ((accmode & VREAD) && ((dac_granted & VREAD) == 0) && !priv_check_cred(cred, PRIV_VFS_READ, 0)) priv_granted |= VREAD; if ((accmode & VWRITE) && ((dac_granted & VWRITE) == 0) && !priv_check_cred(cred, PRIV_VFS_WRITE, 0)) priv_granted |= (VWRITE | VAPPEND); if ((accmode & VADMIN) && ((dac_granted & VADMIN) == 0) && !priv_check_cred(cred, PRIV_VFS_ADMIN, 0)) priv_granted |= VADMIN; if ((accmode & (priv_granted | dac_granted)) == accmode) { /* XXX audit: privilege used */ if (privused != NULL) *privused = 1; return (0); } return ((accmode & VADMIN) ? EPERM : EACCES); } /* * Credential check based on process requesting service, and per-attribute * permissions. */ int extattr_check_cred(struct vnode *vp, int attrnamespace, struct ucred *cred, struct thread *td, accmode_t accmode) { /* * Kernel-invoked always succeeds. */ if (cred == NOCRED) return (0); /* * Do not allow privileged processes in jail to directly manipulate * system attributes. */ switch (attrnamespace) { case EXTATTR_NAMESPACE_SYSTEM: /* Potentially should be: return (EPERM); */ return (priv_check_cred(cred, PRIV_VFS_EXTATTR_SYSTEM, 0)); case EXTATTR_NAMESPACE_USER: return (VOP_ACCESS(vp, accmode, cred, td)); default: return (EPERM); } } #ifdef DEBUG_VFS_LOCKS /* * This only exists to suppress warnings from unlocked specfs accesses. It is * no longer ok to have an unlocked VFS. */ #define IGNORE_LOCK(vp) (panicstr != NULL || (vp) == NULL || \ (vp)->v_type == VCHR || (vp)->v_type == VBAD) int vfs_badlock_ddb = 1; /* Drop into debugger on violation. */ SYSCTL_INT(_debug, OID_AUTO, vfs_badlock_ddb, CTLFLAG_RW, &vfs_badlock_ddb, 0, "Drop into debugger on lock violation"); int vfs_badlock_mutex = 1; /* Check for interlock across VOPs. */ SYSCTL_INT(_debug, OID_AUTO, vfs_badlock_mutex, CTLFLAG_RW, &vfs_badlock_mutex, 0, "Check for interlock across VOPs"); int vfs_badlock_print = 1; /* Print lock violations. */ SYSCTL_INT(_debug, OID_AUTO, vfs_badlock_print, CTLFLAG_RW, &vfs_badlock_print, 0, "Print lock violations"); int vfs_badlock_vnode = 1; /* Print vnode details on lock violations. */ SYSCTL_INT(_debug, OID_AUTO, vfs_badlock_vnode, CTLFLAG_RW, &vfs_badlock_vnode, 0, "Print vnode details on lock violations"); #ifdef KDB int vfs_badlock_backtrace = 1; /* Print backtrace at lock violations. */ SYSCTL_INT(_debug, OID_AUTO, vfs_badlock_backtrace, CTLFLAG_RW, &vfs_badlock_backtrace, 0, "Print backtrace at lock violations"); #endif static void vfs_badlock(const char *msg, const char *str, struct vnode *vp) { #ifdef KDB if (vfs_badlock_backtrace) kdb_backtrace(); #endif if (vfs_badlock_vnode) vn_printf(vp, "vnode "); if (vfs_badlock_print) printf("%s: %p %s\n", str, (void *)vp, msg); if (vfs_badlock_ddb) kdb_enter(KDB_WHY_VFSLOCK, "lock violation"); } void assert_vi_locked(struct vnode *vp, const char *str) { if (vfs_badlock_mutex && !mtx_owned(VI_MTX(vp))) vfs_badlock("interlock is not locked but should be", str, vp); } void assert_vi_unlocked(struct vnode *vp, const char *str) { if (vfs_badlock_mutex && mtx_owned(VI_MTX(vp))) vfs_badlock("interlock is locked but should not be", str, vp); } void assert_vop_locked(struct vnode *vp, const char *str) { int locked; if (!IGNORE_LOCK(vp)) { locked = VOP_ISLOCKED(vp); if (locked == 0 || locked == LK_EXCLOTHER) vfs_badlock("is not locked but should be", str, vp); } } void assert_vop_unlocked(struct vnode *vp, const char *str) { if (!IGNORE_LOCK(vp) && VOP_ISLOCKED(vp) == LK_EXCLUSIVE) vfs_badlock("is locked but should not be", str, vp); } void assert_vop_elocked(struct vnode *vp, const char *str) { if (!IGNORE_LOCK(vp) && VOP_ISLOCKED(vp) != LK_EXCLUSIVE) vfs_badlock("is not exclusive locked but should be", str, vp); } #endif /* DEBUG_VFS_LOCKS */ void vop_rename_fail(struct vop_rename_args *ap) { if (ap->a_tvp != NULL) vput(ap->a_tvp); if (ap->a_tdvp == ap->a_tvp) vrele(ap->a_tdvp); else vput(ap->a_tdvp); vrele(ap->a_fdvp); vrele(ap->a_fvp); } void vop_rename_pre(void *ap) { struct vop_rename_args *a = ap; #ifdef DEBUG_VFS_LOCKS if (a->a_tvp) ASSERT_VI_UNLOCKED(a->a_tvp, "VOP_RENAME"); ASSERT_VI_UNLOCKED(a->a_tdvp, "VOP_RENAME"); ASSERT_VI_UNLOCKED(a->a_fvp, "VOP_RENAME"); ASSERT_VI_UNLOCKED(a->a_fdvp, "VOP_RENAME"); /* Check the source (from). */ if (a->a_tdvp->v_vnlock != a->a_fdvp->v_vnlock && (a->a_tvp == NULL || a->a_tvp->v_vnlock != a->a_fdvp->v_vnlock)) ASSERT_VOP_UNLOCKED(a->a_fdvp, "vop_rename: fdvp locked"); if (a->a_tvp == NULL || a->a_tvp->v_vnlock != a->a_fvp->v_vnlock) ASSERT_VOP_UNLOCKED(a->a_fvp, "vop_rename: fvp locked"); /* Check the target. */ if (a->a_tvp) ASSERT_VOP_LOCKED(a->a_tvp, "vop_rename: tvp not locked"); ASSERT_VOP_LOCKED(a->a_tdvp, "vop_rename: tdvp not locked"); #endif if (a->a_tdvp != a->a_fdvp) vhold(a->a_fdvp); if (a->a_tvp != a->a_fvp) vhold(a->a_fvp); vhold(a->a_tdvp); if (a->a_tvp) vhold(a->a_tvp); } #ifdef DEBUG_VFS_LOCKS void vop_strategy_pre(void *ap) { struct vop_strategy_args *a; struct buf *bp; a = ap; bp = a->a_bp; /* * Cluster ops lock their component buffers but not the IO container. */ if ((bp->b_flags & B_CLUSTER) != 0) return; if (panicstr == NULL && !BUF_ISLOCKED(bp)) { if (vfs_badlock_print) printf( "VOP_STRATEGY: bp is not locked but should be\n"); if (vfs_badlock_ddb) kdb_enter(KDB_WHY_VFSLOCK, "lock violation"); } } void vop_lock_pre(void *ap) { struct vop_lock1_args *a = ap; if ((a->a_flags & LK_INTERLOCK) == 0) ASSERT_VI_UNLOCKED(a->a_vp, "VOP_LOCK"); else ASSERT_VI_LOCKED(a->a_vp, "VOP_LOCK"); } void vop_lock_post(void *ap, int rc) { struct vop_lock1_args *a = ap; ASSERT_VI_UNLOCKED(a->a_vp, "VOP_LOCK"); if (rc == 0 && (a->a_flags & LK_EXCLOTHER) == 0) ASSERT_VOP_LOCKED(a->a_vp, "VOP_LOCK"); } void vop_unlock_pre(void *ap) { struct vop_unlock_args *a = ap; if (a->a_flags & LK_INTERLOCK) ASSERT_VI_LOCKED(a->a_vp, "VOP_UNLOCK"); ASSERT_VOP_LOCKED(a->a_vp, "VOP_UNLOCK"); } void vop_unlock_post(void *ap, int rc) { struct vop_unlock_args *a = ap; if (a->a_flags & LK_INTERLOCK) ASSERT_VI_UNLOCKED(a->a_vp, "VOP_UNLOCK"); } #endif void vop_create_post(void *ap, int rc) { struct vop_create_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); } void vop_deleteextattr_post(void *ap, int rc) { struct vop_deleteextattr_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); } void vop_link_post(void *ap, int rc) { struct vop_link_args *a = ap; if (!rc) { VFS_KNOTE_LOCKED(a->a_vp, NOTE_LINK); VFS_KNOTE_LOCKED(a->a_tdvp, NOTE_WRITE); } } void vop_mkdir_post(void *ap, int rc) { struct vop_mkdir_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE | NOTE_LINK); } void vop_mknod_post(void *ap, int rc) { struct vop_mknod_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); } void vop_reclaim_post(void *ap, int rc) { struct vop_reclaim_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_vp, NOTE_REVOKE); } void vop_remove_post(void *ap, int rc) { struct vop_remove_args *a = ap; if (!rc) { VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); VFS_KNOTE_LOCKED(a->a_vp, NOTE_DELETE); } } void vop_rename_post(void *ap, int rc) { struct vop_rename_args *a = ap; long hint; if (!rc) { hint = NOTE_WRITE; if (a->a_fdvp == a->a_tdvp) { if (a->a_tvp != NULL && a->a_tvp->v_type == VDIR) hint |= NOTE_LINK; VFS_KNOTE_UNLOCKED(a->a_fdvp, hint); VFS_KNOTE_UNLOCKED(a->a_tdvp, hint); } else { hint |= NOTE_EXTEND; if (a->a_fvp->v_type == VDIR) hint |= NOTE_LINK; VFS_KNOTE_UNLOCKED(a->a_fdvp, hint); if (a->a_fvp->v_type == VDIR && a->a_tvp != NULL && a->a_tvp->v_type == VDIR) hint &= ~NOTE_LINK; VFS_KNOTE_UNLOCKED(a->a_tdvp, hint); } VFS_KNOTE_UNLOCKED(a->a_fvp, NOTE_RENAME); if (a->a_tvp) VFS_KNOTE_UNLOCKED(a->a_tvp, NOTE_DELETE); } if (a->a_tdvp != a->a_fdvp) vdrop(a->a_fdvp); if (a->a_tvp != a->a_fvp) vdrop(a->a_fvp); vdrop(a->a_tdvp); if (a->a_tvp) vdrop(a->a_tvp); } void vop_rmdir_post(void *ap, int rc) { struct vop_rmdir_args *a = ap; if (!rc) { VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE | NOTE_LINK); VFS_KNOTE_LOCKED(a->a_vp, NOTE_DELETE); } } void vop_setattr_post(void *ap, int rc) { struct vop_setattr_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); } void vop_setextattr_post(void *ap, int rc) { struct vop_setextattr_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); } void vop_symlink_post(void *ap, int rc) { struct vop_symlink_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); } void vop_open_post(void *ap, int rc) { struct vop_open_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_vp, NOTE_OPEN); } void vop_close_post(void *ap, int rc) { struct vop_close_args *a = ap; if (!rc && (a->a_cred != NOCRED || /* filter out revokes */ (a->a_vp->v_iflag & VI_DOOMED) == 0)) { VFS_KNOTE_LOCKED(a->a_vp, (a->a_fflag & FWRITE) != 0 ? NOTE_CLOSE_WRITE : NOTE_CLOSE); } } void vop_read_post(void *ap, int rc) { struct vop_read_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_vp, NOTE_READ); } void vop_readdir_post(void *ap, int rc) { struct vop_readdir_args *a = ap; if (!rc) VFS_KNOTE_LOCKED(a->a_vp, NOTE_READ); } static struct knlist fs_knlist; static void vfs_event_init(void *arg) { knlist_init_mtx(&fs_knlist, NULL); } /* XXX - correct order? */ SYSINIT(vfs_knlist, SI_SUB_VFS, SI_ORDER_ANY, vfs_event_init, NULL); void vfs_event_signal(fsid_t *fsid, uint32_t event, intptr_t data __unused) { KNOTE_UNLOCKED(&fs_knlist, event); } static int filt_fsattach(struct knote *kn); static void filt_fsdetach(struct knote *kn); static int filt_fsevent(struct knote *kn, long hint); struct filterops fs_filtops = { .f_isfd = 0, .f_attach = filt_fsattach, .f_detach = filt_fsdetach, .f_event = filt_fsevent }; static int filt_fsattach(struct knote *kn) { kn->kn_flags |= EV_CLEAR; knlist_add(&fs_knlist, kn, 0); return (0); } static void filt_fsdetach(struct knote *kn) { knlist_remove(&fs_knlist, kn, 0); } static int filt_fsevent(struct knote *kn, long hint) { kn->kn_fflags |= hint; return (kn->kn_fflags != 0); } static int sysctl_vfs_ctl(SYSCTL_HANDLER_ARGS) { struct vfsidctl vc; int error; struct mount *mp; error = SYSCTL_IN(req, &vc, sizeof(vc)); if (error) return (error); if (vc.vc_vers != VFS_CTL_VERS1) return (EINVAL); mp = vfs_getvfs(&vc.vc_fsid); if (mp == NULL) return (ENOENT); /* ensure that a specific sysctl goes to the right filesystem. */ if (strcmp(vc.vc_fstypename, "*") != 0 && strcmp(vc.vc_fstypename, mp->mnt_vfc->vfc_name) != 0) { vfs_rel(mp); return (EINVAL); } VCTLTOREQ(&vc, req); error = VFS_SYSCTL(mp, vc.vc_op, req); vfs_rel(mp); return (error); } SYSCTL_PROC(_vfs, OID_AUTO, ctl, CTLTYPE_OPAQUE | CTLFLAG_WR, NULL, 0, sysctl_vfs_ctl, "", "Sysctl by fsid"); /* * Function to initialize a va_filerev field sensibly. * XXX: Wouldn't a random number make a lot more sense ?? */ u_quad_t init_va_filerev(void) { struct bintime bt; getbinuptime(&bt); return (((u_quad_t)bt.sec << 32LL) | (bt.frac >> 32LL)); } static int filt_vfsread(struct knote *kn, long hint); static int filt_vfswrite(struct knote *kn, long hint); static int filt_vfsvnode(struct knote *kn, long hint); static void filt_vfsdetach(struct knote *kn); static struct filterops vfsread_filtops = { .f_isfd = 1, .f_detach = filt_vfsdetach, .f_event = filt_vfsread }; static struct filterops vfswrite_filtops = { .f_isfd = 1, .f_detach = filt_vfsdetach, .f_event = filt_vfswrite }; static struct filterops vfsvnode_filtops = { .f_isfd = 1, .f_detach = filt_vfsdetach, .f_event = filt_vfsvnode }; static void vfs_knllock(void *arg) { struct vnode *vp = arg; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); } static void vfs_knlunlock(void *arg) { struct vnode *vp = arg; VOP_UNLOCK(vp, 0); } static void vfs_knl_assert_locked(void *arg) { #ifdef DEBUG_VFS_LOCKS struct vnode *vp = arg; ASSERT_VOP_LOCKED(vp, "vfs_knl_assert_locked"); #endif } static void vfs_knl_assert_unlocked(void *arg) { #ifdef DEBUG_VFS_LOCKS struct vnode *vp = arg; ASSERT_VOP_UNLOCKED(vp, "vfs_knl_assert_unlocked"); #endif } int vfs_kqfilter(struct vop_kqfilter_args *ap) { struct vnode *vp = ap->a_vp; struct knote *kn = ap->a_kn; struct knlist *knl; switch (kn->kn_filter) { case EVFILT_READ: kn->kn_fop = &vfsread_filtops; break; case EVFILT_WRITE: kn->kn_fop = &vfswrite_filtops; break; case EVFILT_VNODE: kn->kn_fop = &vfsvnode_filtops; break; default: return (EINVAL); } kn->kn_hook = (caddr_t)vp; v_addpollinfo(vp); if (vp->v_pollinfo == NULL) return (ENOMEM); knl = &vp->v_pollinfo->vpi_selinfo.si_note; vhold(vp); knlist_add(knl, kn, 0); return (0); } /* * Detach knote from vnode */ static void filt_vfsdetach(struct knote *kn) { struct vnode *vp = (struct vnode *)kn->kn_hook; KASSERT(vp->v_pollinfo != NULL, ("Missing v_pollinfo")); knlist_remove(&vp->v_pollinfo->vpi_selinfo.si_note, kn, 0); vdrop(vp); } /*ARGSUSED*/ static int filt_vfsread(struct knote *kn, long hint) { struct vnode *vp = (struct vnode *)kn->kn_hook; struct vattr va; int res; /* * filesystem is gone, so set the EOF flag and schedule * the knote for deletion. */ if (hint == NOTE_REVOKE || (hint == 0 && vp->v_type == VBAD)) { VI_LOCK(vp); kn->kn_flags |= (EV_EOF | EV_ONESHOT); VI_UNLOCK(vp); return (1); } if (VOP_GETATTR(vp, &va, curthread->td_ucred)) return (0); VI_LOCK(vp); kn->kn_data = va.va_size - kn->kn_fp->f_offset; res = (kn->kn_sfflags & NOTE_FILE_POLL) != 0 || kn->kn_data != 0; VI_UNLOCK(vp); return (res); } /*ARGSUSED*/ static int filt_vfswrite(struct knote *kn, long hint) { struct vnode *vp = (struct vnode *)kn->kn_hook; VI_LOCK(vp); /* * filesystem is gone, so set the EOF flag and schedule * the knote for deletion. */ if (hint == NOTE_REVOKE || (hint == 0 && vp->v_type == VBAD)) kn->kn_flags |= (EV_EOF | EV_ONESHOT); kn->kn_data = 0; VI_UNLOCK(vp); return (1); } static int filt_vfsvnode(struct knote *kn, long hint) { struct vnode *vp = (struct vnode *)kn->kn_hook; int res; VI_LOCK(vp); if (kn->kn_sfflags & hint) kn->kn_fflags |= hint; if (hint == NOTE_REVOKE || (hint == 0 && vp->v_type == VBAD)) { kn->kn_flags |= EV_EOF; VI_UNLOCK(vp); return (1); } res = (kn->kn_fflags != 0); VI_UNLOCK(vp); return (res); } int vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off) { int error; if (dp->d_reclen > ap->a_uio->uio_resid) return (ENAMETOOLONG); error = uiomove(dp, dp->d_reclen, ap->a_uio); if (error) { if (ap->a_ncookies != NULL) { if (ap->a_cookies != NULL) free(ap->a_cookies, M_TEMP); ap->a_cookies = NULL; *ap->a_ncookies = 0; } return (error); } if (ap->a_ncookies == NULL) return (0); KASSERT(ap->a_cookies, ("NULL ap->a_cookies value with non-NULL ap->a_ncookies!")); *ap->a_cookies = realloc(*ap->a_cookies, (*ap->a_ncookies + 1) * sizeof(u_long), M_TEMP, M_WAITOK | M_ZERO); (*ap->a_cookies)[*ap->a_ncookies] = off; *ap->a_ncookies += 1; return (0); } /* * Mark for update the access time of the file if the filesystem * supports VOP_MARKATIME. This functionality is used by execve and * mmap, so we want to avoid the I/O implied by directly setting * va_atime for the sake of efficiency. */ void vfs_mark_atime(struct vnode *vp, struct ucred *cred) { struct mount *mp; mp = vp->v_mount; ASSERT_VOP_LOCKED(vp, "vfs_mark_atime"); if (mp != NULL && (mp->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0) (void)VOP_MARKATIME(vp); } /* * The purpose of this routine is to remove granularity from accmode_t, * reducing it into standard unix access bits - VEXEC, VREAD, VWRITE, * VADMIN and VAPPEND. * * If it returns 0, the caller is supposed to continue with the usual * access checks using 'accmode' as modified by this routine. If it * returns nonzero value, the caller is supposed to return that value * as errno. * * Note that after this routine runs, accmode may be zero. */ int vfs_unixify_accmode(accmode_t *accmode) { /* * There is no way to specify explicit "deny" rule using * file mode or POSIX.1e ACLs. */ if (*accmode & VEXPLICIT_DENY) { *accmode = 0; return (0); } /* * None of these can be translated into usual access bits. * Also, the common case for NFSv4 ACLs is to not contain * either of these bits. Caller should check for VWRITE * on the containing directory instead. */ if (*accmode & (VDELETE_CHILD | VDELETE)) return (EPERM); if (*accmode & VADMIN_PERMS) { *accmode &= ~VADMIN_PERMS; *accmode |= VADMIN; } /* * There is no way to deny VREAD_ATTRIBUTES, VREAD_ACL * or VSYNCHRONIZE using file mode or POSIX.1e ACL. */ *accmode &= ~(VSTAT_PERMS | VSYNCHRONIZE); return (0); } /* * These are helper functions for filesystems to traverse all * their vnodes. See MNT_VNODE_FOREACH_ALL() in sys/mount.h. * * This interface replaces MNT_VNODE_FOREACH. */ MALLOC_DEFINE(M_VNODE_MARKER, "vnodemarker", "vnode marker"); struct vnode * __mnt_vnode_next_all(struct vnode **mvp, struct mount *mp) { struct vnode *vp; if (should_yield()) kern_yield(PRI_USER); MNT_ILOCK(mp); KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch")); vp = TAILQ_NEXT(*mvp, v_nmntvnodes); while (vp != NULL && (vp->v_type == VMARKER || (vp->v_iflag & VI_DOOMED) != 0)) vp = TAILQ_NEXT(vp, v_nmntvnodes); /* Check if we are done */ if (vp == NULL) { __mnt_vnode_markerfree_all(mvp, mp); /* MNT_IUNLOCK(mp); -- done in above function */ mtx_assert(MNT_MTX(mp), MA_NOTOWNED); return (NULL); } TAILQ_REMOVE(&mp->mnt_nvnodelist, *mvp, v_nmntvnodes); TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, *mvp, v_nmntvnodes); VI_LOCK(vp); MNT_IUNLOCK(mp); return (vp); } struct vnode * __mnt_vnode_first_all(struct vnode **mvp, struct mount *mp) { struct vnode *vp; *mvp = malloc(sizeof(struct vnode), M_VNODE_MARKER, M_WAITOK | M_ZERO); MNT_ILOCK(mp); MNT_REF(mp); (*mvp)->v_type = VMARKER; vp = TAILQ_FIRST(&mp->mnt_nvnodelist); while (vp != NULL && (vp->v_type == VMARKER || (vp->v_iflag & VI_DOOMED) != 0)) vp = TAILQ_NEXT(vp, v_nmntvnodes); /* Check if we are done */ if (vp == NULL) { MNT_REL(mp); MNT_IUNLOCK(mp); free(*mvp, M_VNODE_MARKER); *mvp = NULL; return (NULL); } (*mvp)->v_mount = mp; TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, *mvp, v_nmntvnodes); VI_LOCK(vp); MNT_IUNLOCK(mp); return (vp); } void __mnt_vnode_markerfree_all(struct vnode **mvp, struct mount *mp) { if (*mvp == NULL) { MNT_IUNLOCK(mp); return; } mtx_assert(MNT_MTX(mp), MA_OWNED); KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch")); TAILQ_REMOVE(&mp->mnt_nvnodelist, *mvp, v_nmntvnodes); MNT_REL(mp); MNT_IUNLOCK(mp); free(*mvp, M_VNODE_MARKER); *mvp = NULL; } /* * These are helper functions for filesystems to traverse their * active vnodes. See MNT_VNODE_FOREACH_ACTIVE() in sys/mount.h */ static void mnt_vnode_markerfree_active(struct vnode **mvp, struct mount *mp) { KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch")); MNT_ILOCK(mp); MNT_REL(mp); MNT_IUNLOCK(mp); free(*mvp, M_VNODE_MARKER); *mvp = NULL; } static struct vnode * mnt_vnode_next_active(struct vnode **mvp, struct mount *mp) { struct vnode *vp, *nvp; mtx_assert(&mp->mnt_listmtx, MA_OWNED); KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch")); restart: vp = TAILQ_NEXT(*mvp, v_actfreelist); TAILQ_REMOVE(&mp->mnt_activevnodelist, *mvp, v_actfreelist); while (vp != NULL) { if (vp->v_type == VMARKER) { vp = TAILQ_NEXT(vp, v_actfreelist); continue; } if (!VI_TRYLOCK(vp)) { if (mp_ncpus == 1 || should_yield()) { TAILQ_INSERT_BEFORE(vp, *mvp, v_actfreelist); mtx_unlock(&mp->mnt_listmtx); pause("vnacti", 1); mtx_lock(&mp->mnt_listmtx); goto restart; } continue; } KASSERT(vp->v_type != VMARKER, ("locked marker %p", vp)); KASSERT(vp->v_mount == mp || vp->v_mount == NULL, ("alien vnode on the active list %p %p", vp, mp)); if (vp->v_mount == mp && (vp->v_iflag & VI_DOOMED) == 0) break; nvp = TAILQ_NEXT(vp, v_actfreelist); VI_UNLOCK(vp); vp = nvp; } /* Check if we are done */ if (vp == NULL) { mtx_unlock(&mp->mnt_listmtx); mnt_vnode_markerfree_active(mvp, mp); return (NULL); } TAILQ_INSERT_AFTER(&mp->mnt_activevnodelist, vp, *mvp, v_actfreelist); mtx_unlock(&mp->mnt_listmtx); ASSERT_VI_LOCKED(vp, "active iter"); KASSERT((vp->v_iflag & VI_ACTIVE) != 0, ("Non-active vp %p", vp)); return (vp); } struct vnode * __mnt_vnode_next_active(struct vnode **mvp, struct mount *mp) { if (should_yield()) kern_yield(PRI_USER); mtx_lock(&mp->mnt_listmtx); return (mnt_vnode_next_active(mvp, mp)); } struct vnode * __mnt_vnode_first_active(struct vnode **mvp, struct mount *mp) { struct vnode *vp; *mvp = malloc(sizeof(struct vnode), M_VNODE_MARKER, M_WAITOK | M_ZERO); MNT_ILOCK(mp); MNT_REF(mp); MNT_IUNLOCK(mp); (*mvp)->v_type = VMARKER; (*mvp)->v_mount = mp; mtx_lock(&mp->mnt_listmtx); vp = TAILQ_FIRST(&mp->mnt_activevnodelist); if (vp == NULL) { mtx_unlock(&mp->mnt_listmtx); mnt_vnode_markerfree_active(mvp, mp); return (NULL); } TAILQ_INSERT_BEFORE(vp, *mvp, v_actfreelist); return (mnt_vnode_next_active(mvp, mp)); } void __mnt_vnode_markerfree_active(struct vnode **mvp, struct mount *mp) { if (*mvp == NULL) return; mtx_lock(&mp->mnt_listmtx); TAILQ_REMOVE(&mp->mnt_activevnodelist, *mvp, v_actfreelist); mtx_unlock(&mp->mnt_listmtx); mnt_vnode_markerfree_active(mvp, mp); } Index: projects/ipsec/sys/mips/include/_types.h =================================================================== --- projects/ipsec/sys/mips/include/_types.h (revision 313312) +++ projects/ipsec/sys/mips/include/_types.h (revision 313313) @@ -1,167 +1,165 @@ /*- * Copyright (c) 2002 Mike Barcroft * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From: @(#)ansi.h 8.2 (Berkeley) 1/4/94 * From: @(#)types.h 8.3 (Berkeley) 1/5/94 * from: src/sys/i386/include/_types.h,v 1.12 2005/07/02 23:13:31 thompsa * $FreeBSD$ */ #ifndef _MACHINE__TYPES_H_ #define _MACHINE__TYPES_H_ #ifndef _SYS_CDEFS_H_ #error this file needs sys/cdefs.h as a prerequisite #endif /* * Basic types upon which most other types are built. */ typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; typedef unsigned short __uint16_t; typedef int __int32_t; typedef unsigned int __uint32_t; #ifdef __mips_n64 typedef long __int64_t; typedef unsigned long __uint64_t; #else #ifndef lint __extension__ #endif /* LONGLONG */ typedef long long __int64_t; #ifndef lint __extension__ #endif /* LONGLONG */ typedef unsigned long long __uint64_t; #endif /* * Standard type definitions. */ typedef __int32_t __clock_t; /* clock()... */ typedef double __double_t; typedef float __float_t; #ifdef __mips_n64 typedef __int64_t __critical_t; typedef __int64_t __intfptr_t; typedef __int64_t __intptr_t; #else typedef __int32_t __critical_t; typedef __int32_t __intfptr_t; typedef __int32_t __intptr_t; #endif typedef __int64_t __intmax_t; typedef __int32_t __int_fast8_t; typedef __int32_t __int_fast16_t; typedef __int32_t __int_fast32_t; typedef __int64_t __int_fast64_t; typedef __int8_t __int_least8_t; typedef __int16_t __int_least16_t; typedef __int32_t __int_least32_t; typedef __int64_t __int_least64_t; #if defined(__mips_n64) || defined(__mips_n32) typedef __int64_t __register_t; typedef __int64_t f_register_t; #else typedef __int32_t __register_t; typedef __int32_t f_register_t; #endif #ifdef __mips_n64 typedef __int64_t __ptrdiff_t; typedef __int64_t __segsz_t; typedef __uint64_t __size_t; typedef __int64_t __ssize_t; typedef __uint64_t __uintfptr_t; typedef __uint64_t __uintptr_t; #else typedef __int32_t __ptrdiff_t; /* ptr1 - ptr2 */ typedef __int32_t __segsz_t; /* segment size (in pages) */ typedef __uint32_t __size_t; /* sizeof() */ typedef __int32_t __ssize_t; /* byte count or error */ typedef __uint32_t __uintfptr_t; typedef __uint32_t __uintptr_t; #endif typedef __int64_t __time_t; /* time()... */ typedef __uint64_t __uintmax_t; typedef __uint32_t __uint_fast8_t; typedef __uint32_t __uint_fast16_t; typedef __uint32_t __uint_fast32_t; typedef __uint64_t __uint_fast64_t; typedef __uint8_t __uint_least8_t; typedef __uint16_t __uint_least16_t; typedef __uint32_t __uint_least32_t; typedef __uint64_t __uint_least64_t; #if defined(__mips_n64) || defined(__mips_n32) typedef __uint64_t __u_register_t; #else typedef __uint32_t __u_register_t; #endif #ifdef __mips_n64 typedef __uint64_t __vm_offset_t; typedef __uint64_t __vm_size_t; #else typedef __uint32_t __vm_offset_t; typedef __uint32_t __vm_size_t; #endif #if defined(__mips_n64) || defined(__mips_n32) /* PHYSADDR_64_BIT */ typedef __uint64_t __vm_paddr_t; #else typedef __uint32_t __vm_paddr_t; #endif -typedef __int64_t __vm_ooffset_t; -typedef __uint64_t __vm_pindex_t; typedef int ___wchar_t; #define __WCHAR_MIN __INT_MIN /* min value for a wchar_t */ #define __WCHAR_MAX __INT_MAX /* max value for a wchar_t */ /* * Unusual type definitions. */ #ifdef __GNUCLIKE_BUILTIN_VARARGS typedef __builtin_va_list __va_list; /* internally known to gcc */ #else typedef char * __va_list; #endif /* __GNUCLIKE_BUILTIN_VARARGS */ #if defined(__GNUC_VA_LIST_COMPATIBILITY) && !defined(__GNUC_VA_LIST) \ && !defined(__NO_GNUC_VA_LIST) #define __GNUC_VA_LIST typedef __va_list __gnuc_va_list; /* compatibility w/GNU headers*/ #endif #endif /* !_MACHINE__TYPES_H_ */ Index: projects/ipsec/sys/mips/include/pcpu.h =================================================================== --- projects/ipsec/sys/mips/include/pcpu.h (revision 313312) +++ projects/ipsec/sys/mips/include/pcpu.h (revision 313313) @@ -1,85 +1,84 @@ /*- * Copyright (c) 1999 Luoqi Chen * Copyright (c) Peter Wemm * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: src/sys/alpha/include/pcpu.h,v 1.15 2004/11/05 19:16:44 jhb * $FreeBSD$ */ #ifndef _MACHINE_PCPU_H_ #define _MACHINE_PCPU_H_ #include #include #define PCPU_MD_COMMON_FIELDS \ pd_entry_t *pc_segbase; /* curthread segbase */ \ struct pmap *pc_curpmap; /* pmap of curthread */ \ u_int32_t pc_next_asid; /* next ASID to alloc */ \ u_int32_t pc_asid_generation; /* current ASID generation */ \ u_int pc_pending_ipis; /* IPIs pending to this CPU */ #ifdef __mips_n64 #define PCPU_MD_MIPS64_FIELDS \ PCPU_MD_COMMON_FIELDS \ char __pad[61] #else #define PCPU_MD_MIPS32_FIELDS \ PCPU_MD_COMMON_FIELDS \ char __pad[193] #endif #ifdef __mips_n64 #define PCPU_MD_FIELDS PCPU_MD_MIPS64_FIELDS #else #define PCPU_MD_FIELDS PCPU_MD_MIPS32_FIELDS #endif #ifdef _KERNEL extern char pcpu_space[MAXCPU][PAGE_SIZE * 2]; #define PCPU_ADDR(cpu) (struct pcpu *)(pcpu_space[(cpu)]) extern struct pcpu *pcpup; #define PCPUP pcpup -#define get_pcpu() (pcpup) #define PCPU_ADD(member, value) (PCPUP->pc_ ## member += (value)) #define PCPU_GET(member) (PCPUP->pc_ ## member) #define PCPU_INC(member) PCPU_ADD(member, 1) #define PCPU_PTR(member) (&PCPUP->pc_ ## member) #define PCPU_SET(member,value) (PCPUP->pc_ ## member = (value)) #define PCPU_LAZY_INC(member) (++PCPUP->pc_ ## member) #ifdef SMP /* * Instantiate the wired TLB entry at PCPU_TLB_ENTRY to map 'pcpu' at 'pcpup'. */ void mips_pcpu_tlb_init(struct pcpu *pcpu); #endif #endif /* _KERNEL */ #endif /* !_MACHINE_PCPU_H_ */ Index: projects/ipsec/sys/net/iflib.c =================================================================== --- projects/ipsec/sys/net/iflib.c (revision 313312) +++ projects/ipsec/sys/net/iflib.c (revision 313313) @@ -1,5246 +1,5244 @@ /*- * Copyright (c) 2014-2017, Matthew Macy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Neither the name of Matthew Macy 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include "opt_acpi.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ifdi_if.h" #if defined(__i386__) || defined(__amd64__) #include #include #include #include #include #include #endif /* * enable accounting of every mbuf as it comes in to and goes out of iflib's software descriptor references */ #define MEMORY_LOGGING 0 /* * Enable mbuf vectors for compressing long mbuf chains */ /* * NB: * - Prefetching in tx cleaning should perhaps be a tunable. The distance ahead * we prefetch needs to be determined by the time spent in m_free vis a vis * the cost of a prefetch. This will of course vary based on the workload: * - NFLX's m_free path is dominated by vm-based M_EXT manipulation which * is quite expensive, thus suggesting very little prefetch. * - small packet forwarding which is just returning a single mbuf to * UMA will typically be very fast vis a vis the cost of a memory * access. */ /* * File organization: * - private structures * - iflib private utility functions * - ifnet functions * - vlan registry and other exported functions * - iflib public core functions * * */ static MALLOC_DEFINE(M_IFLIB, "iflib", "ifnet library"); struct iflib_txq; typedef struct iflib_txq *iflib_txq_t; struct iflib_rxq; typedef struct iflib_rxq *iflib_rxq_t; struct iflib_fl; typedef struct iflib_fl *iflib_fl_t; struct iflib_ctx; typedef struct iflib_filter_info { driver_filter_t *ifi_filter; void *ifi_filter_arg; struct grouptask *ifi_task; struct iflib_ctx *ifi_ctx; } *iflib_filter_info_t; struct iflib_ctx { KOBJ_FIELDS; /* * Pointer to hardware driver's softc */ void *ifc_softc; device_t ifc_dev; if_t ifc_ifp; cpuset_t ifc_cpus; if_shared_ctx_t ifc_sctx; struct if_softc_ctx ifc_softc_ctx; struct mtx ifc_mtx; uint16_t ifc_nhwtxqs; uint16_t ifc_nhwrxqs; iflib_txq_t ifc_txqs; iflib_rxq_t ifc_rxqs; uint32_t ifc_if_flags; uint32_t ifc_flags; uint32_t ifc_max_fl_buf_size; int ifc_in_detach; int ifc_link_state; int ifc_link_irq; int ifc_pause_frames; int ifc_watchdog_events; struct cdev *ifc_led_dev; struct resource *ifc_msix_mem; struct if_irq ifc_legacy_irq; struct grouptask ifc_admin_task; struct grouptask ifc_vflr_task; struct iflib_filter_info ifc_filter_info; struct ifmedia ifc_media; struct sysctl_oid *ifc_sysctl_node; uint16_t ifc_sysctl_ntxqs; uint16_t ifc_sysctl_nrxqs; uint16_t ifc_sysctl_qs_eq_override; uint16_t ifc_sysctl_ntxds[8]; uint16_t ifc_sysctl_nrxds[8]; struct if_txrx ifc_txrx; #define isc_txd_encap ifc_txrx.ift_txd_encap #define isc_txd_flush ifc_txrx.ift_txd_flush #define isc_txd_credits_update ifc_txrx.ift_txd_credits_update #define isc_rxd_available ifc_txrx.ift_rxd_available #define isc_rxd_pkt_get ifc_txrx.ift_rxd_pkt_get #define isc_rxd_refill ifc_txrx.ift_rxd_refill #define isc_rxd_flush ifc_txrx.ift_rxd_flush #define isc_rxd_refill ifc_txrx.ift_rxd_refill #define isc_rxd_refill ifc_txrx.ift_rxd_refill #define isc_legacy_intr ifc_txrx.ift_legacy_intr eventhandler_tag ifc_vlan_attach_event; eventhandler_tag ifc_vlan_detach_event; uint8_t ifc_mac[ETHER_ADDR_LEN]; char ifc_mtx_name[16]; }; void * iflib_get_softc(if_ctx_t ctx) { return (ctx->ifc_softc); } device_t iflib_get_dev(if_ctx_t ctx) { return (ctx->ifc_dev); } if_t iflib_get_ifp(if_ctx_t ctx) { return (ctx->ifc_ifp); } struct ifmedia * iflib_get_media(if_ctx_t ctx) { return (&ctx->ifc_media); } void iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN]) { bcopy(mac, ctx->ifc_mac, ETHER_ADDR_LEN); } if_softc_ctx_t iflib_get_softc_ctx(if_ctx_t ctx) { return (&ctx->ifc_softc_ctx); } if_shared_ctx_t iflib_get_sctx(if_ctx_t ctx) { return (ctx->ifc_sctx); } #define CACHE_PTR_INCREMENT (CACHE_LINE_SIZE/sizeof(void*)) #define LINK_ACTIVE(ctx) ((ctx)->ifc_link_state == LINK_STATE_UP) #define CTX_IS_VF(ctx) ((ctx)->ifc_sctx->isc_flags & IFLIB_IS_VF) #define RX_SW_DESC_MAP_CREATED (1 << 0) #define TX_SW_DESC_MAP_CREATED (1 << 1) #define RX_SW_DESC_INUSE (1 << 3) #define TX_SW_DESC_MAPPED (1 << 4) typedef struct iflib_sw_rx_desc_array { bus_dmamap_t *ifsd_map; /* bus_dma maps for packet */ struct mbuf **ifsd_m; /* pkthdr mbufs */ caddr_t *ifsd_cl; /* direct cluster pointer for rx */ uint8_t *ifsd_flags; } iflib_rxsd_array_t; typedef struct iflib_sw_tx_desc_array { bus_dmamap_t *ifsd_map; /* bus_dma maps for packet */ struct mbuf **ifsd_m; /* pkthdr mbufs */ uint8_t *ifsd_flags; } iflib_txsd_array_t; /* magic number that should be high enough for any hardware */ #define IFLIB_MAX_TX_SEGS 128 #define IFLIB_MAX_RX_SEGS 32 #define IFLIB_RX_COPY_THRESH 63 #define IFLIB_MAX_RX_REFRESH 32 #define IFLIB_QUEUE_IDLE 0 #define IFLIB_QUEUE_HUNG 1 #define IFLIB_QUEUE_WORKING 2 /* this should really scale with ring size - 32 is a fairly arbitrary value for this */ #define TX_BATCH_SIZE 16 #define IFLIB_RESTART_BUDGET 8 #define IFC_LEGACY 0x01 #define IFC_QFLUSH 0x02 #define IFC_MULTISEG 0x04 #define IFC_DMAR 0x08 #define IFC_SC_ALLOCATED 0x10 #define IFC_INIT_DONE 0x20 #define CSUM_OFFLOAD (CSUM_IP_TSO|CSUM_IP6_TSO|CSUM_IP| \ CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP| \ CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP) struct iflib_txq { uint16_t ift_in_use; uint16_t ift_cidx; uint16_t ift_cidx_processed; uint16_t ift_pidx; uint8_t ift_gen; uint8_t ift_db_pending; uint8_t ift_db_pending_queued; uint8_t ift_npending; uint8_t ift_br_offset; /* implicit pad */ uint64_t ift_processed; uint64_t ift_cleaned; #if MEMORY_LOGGING uint64_t ift_enqueued; uint64_t ift_dequeued; #endif uint64_t ift_no_tx_dma_setup; uint64_t ift_no_desc_avail; uint64_t ift_mbuf_defrag_failed; uint64_t ift_mbuf_defrag; uint64_t ift_map_failed; uint64_t ift_txd_encap_efbig; uint64_t ift_pullups; struct mtx ift_mtx; struct mtx ift_db_mtx; /* constant values */ if_ctx_t ift_ctx; struct ifmp_ring **ift_br; struct grouptask ift_task; uint16_t ift_size; uint16_t ift_id; struct callout ift_timer; struct callout ift_db_check; iflib_txsd_array_t ift_sds; uint8_t ift_nbr; uint8_t ift_qstatus; uint8_t ift_active; uint8_t ift_closed; int ift_watchdog_time; struct iflib_filter_info ift_filter_info; bus_dma_tag_t ift_desc_tag; bus_dma_tag_t ift_tso_desc_tag; iflib_dma_info_t ift_ifdi; #define MTX_NAME_LEN 16 char ift_mtx_name[MTX_NAME_LEN]; char ift_db_mtx_name[MTX_NAME_LEN]; bus_dma_segment_t ift_segs[IFLIB_MAX_TX_SEGS] __aligned(CACHE_LINE_SIZE); #ifdef IFLIB_DIAGNOSTICS uint64_t ift_cpu_exec_count[256]; #endif } __aligned(CACHE_LINE_SIZE); struct iflib_fl { uint16_t ifl_cidx; uint16_t ifl_pidx; uint16_t ifl_credits; uint8_t ifl_gen; #if MEMORY_LOGGING uint64_t ifl_m_enqueued; uint64_t ifl_m_dequeued; uint64_t ifl_cl_enqueued; uint64_t ifl_cl_dequeued; #endif /* implicit pad */ /* constant */ uint16_t ifl_size; uint16_t ifl_buf_size; uint16_t ifl_cltype; uma_zone_t ifl_zone; iflib_rxsd_array_t ifl_sds; iflib_rxq_t ifl_rxq; uint8_t ifl_id; bus_dma_tag_t ifl_desc_tag; iflib_dma_info_t ifl_ifdi; uint64_t ifl_bus_addrs[IFLIB_MAX_RX_REFRESH] __aligned(CACHE_LINE_SIZE); caddr_t ifl_vm_addrs[IFLIB_MAX_RX_REFRESH]; } __aligned(CACHE_LINE_SIZE); static inline int get_inuse(int size, int cidx, int pidx, int gen) { int used; if (pidx > cidx) used = pidx - cidx; else if (pidx < cidx) used = size - cidx + pidx; else if (gen == 0 && pidx == cidx) used = 0; else if (gen == 1 && pidx == cidx) used = size; else panic("bad state"); return (used); } #define TXQ_AVAIL(txq) (txq->ift_size - get_inuse(txq->ift_size, txq->ift_cidx, txq->ift_pidx, txq->ift_gen)) #define IDXDIFF(head, tail, wrap) \ ((head) >= (tail) ? (head) - (tail) : (wrap) - (tail) + (head)) struct iflib_rxq { /* If there is a separate completion queue - * these are the cq cidx and pidx. Otherwise * these are unused. */ uint16_t ifr_size; uint16_t ifr_cq_cidx; uint16_t ifr_cq_pidx; uint8_t ifr_cq_gen; uint8_t ifr_fl_offset; if_ctx_t ifr_ctx; iflib_fl_t ifr_fl; uint64_t ifr_rx_irq; uint16_t ifr_id; uint8_t ifr_lro_enabled; uint8_t ifr_nfl; struct lro_ctrl ifr_lc; struct grouptask ifr_task; struct iflib_filter_info ifr_filter_info; iflib_dma_info_t ifr_ifdi; /* dynamically allocate if any drivers need a value substantially larger than this */ struct if_rxd_frag ifr_frags[IFLIB_MAX_RX_SEGS] __aligned(CACHE_LINE_SIZE); #ifdef IFLIB_DIAGNOSTICS uint64_t ifr_cpu_exec_count[256]; #endif } __aligned(CACHE_LINE_SIZE); /* * Only allow a single packet to take up most 1/nth of the tx ring */ #define MAX_SINGLE_PACKET_FRACTION 12 #define IF_BAD_DMA (bus_addr_t)-1 static int enable_msix = 1; #define CTX_ACTIVE(ctx) ((if_getdrvflags((ctx)->ifc_ifp) & IFF_DRV_RUNNING)) #define CTX_LOCK_INIT(_sc, _name) mtx_init(&(_sc)->ifc_mtx, _name, "iflib ctx lock", MTX_DEF) #define CTX_LOCK(ctx) mtx_lock(&(ctx)->ifc_mtx) #define CTX_UNLOCK(ctx) mtx_unlock(&(ctx)->ifc_mtx) #define CTX_LOCK_DESTROY(ctx) mtx_destroy(&(ctx)->ifc_mtx) #define TXDB_LOCK_INIT(txq) mtx_init(&(txq)->ift_db_mtx, (txq)->ift_db_mtx_name, NULL, MTX_DEF) #define TXDB_TRYLOCK(txq) mtx_trylock(&(txq)->ift_db_mtx) #define TXDB_LOCK(txq) mtx_lock(&(txq)->ift_db_mtx) #define TXDB_UNLOCK(txq) mtx_unlock(&(txq)->ift_db_mtx) #define TXDB_LOCK_DESTROY(txq) mtx_destroy(&(txq)->ift_db_mtx) #define CALLOUT_LOCK(txq) mtx_lock(&txq->ift_mtx) #define CALLOUT_UNLOCK(txq) mtx_unlock(&txq->ift_mtx) /* Our boot-time initialization hook */ static int iflib_module_event_handler(module_t, int, void *); static moduledata_t iflib_moduledata = { "iflib", iflib_module_event_handler, NULL }; DECLARE_MODULE(iflib, iflib_moduledata, SI_SUB_INIT_IF, SI_ORDER_ANY); MODULE_VERSION(iflib, 1); MODULE_DEPEND(iflib, pci, 1, 1, 1); MODULE_DEPEND(iflib, ether, 1, 1, 1); TASKQGROUP_DEFINE(if_io_tqg, mp_ncpus, 1); TASKQGROUP_DEFINE(if_config_tqg, 1, 1); #ifndef IFLIB_DEBUG_COUNTERS #ifdef INVARIANTS #define IFLIB_DEBUG_COUNTERS 1 #else #define IFLIB_DEBUG_COUNTERS 0 #endif /* !INVARIANTS */ #endif static SYSCTL_NODE(_net, OID_AUTO, iflib, CTLFLAG_RD, 0, "iflib driver parameters"); /* * XXX need to ensure that this can't accidentally cause the head to be moved backwards */ static int iflib_min_tx_latency = 0; SYSCTL_INT(_net_iflib, OID_AUTO, min_tx_latency, CTLFLAG_RW, &iflib_min_tx_latency, 0, "minimize transmit latency at the possible expense of throughput"); #if IFLIB_DEBUG_COUNTERS static int iflib_tx_seen; static int iflib_tx_sent; static int iflib_tx_encap; static int iflib_rx_allocs; static int iflib_fl_refills; static int iflib_fl_refills_large; static int iflib_tx_frees; SYSCTL_INT(_net_iflib, OID_AUTO, tx_seen, CTLFLAG_RD, &iflib_tx_seen, 0, "# tx mbufs seen"); SYSCTL_INT(_net_iflib, OID_AUTO, tx_sent, CTLFLAG_RD, &iflib_tx_sent, 0, "# tx mbufs sent"); SYSCTL_INT(_net_iflib, OID_AUTO, tx_encap, CTLFLAG_RD, &iflib_tx_encap, 0, "# tx mbufs encapped"); SYSCTL_INT(_net_iflib, OID_AUTO, tx_frees, CTLFLAG_RD, &iflib_tx_frees, 0, "# tx frees"); SYSCTL_INT(_net_iflib, OID_AUTO, rx_allocs, CTLFLAG_RD, &iflib_rx_allocs, 0, "# rx allocations"); SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills, CTLFLAG_RD, &iflib_fl_refills, 0, "# refills"); SYSCTL_INT(_net_iflib, OID_AUTO, fl_refills_large, CTLFLAG_RD, &iflib_fl_refills_large, 0, "# large refills"); static int iflib_txq_drain_flushing; static int iflib_txq_drain_oactive; static int iflib_txq_drain_notready; static int iflib_txq_drain_encapfail; SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_flushing, CTLFLAG_RD, &iflib_txq_drain_flushing, 0, "# drain flushes"); SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_oactive, CTLFLAG_RD, &iflib_txq_drain_oactive, 0, "# drain oactives"); SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_notready, CTLFLAG_RD, &iflib_txq_drain_notready, 0, "# drain notready"); SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_encapfail, CTLFLAG_RD, &iflib_txq_drain_encapfail, 0, "# drain encap fails"); static int iflib_encap_load_mbuf_fail; static int iflib_encap_txq_avail_fail; static int iflib_encap_txd_encap_fail; SYSCTL_INT(_net_iflib, OID_AUTO, encap_load_mbuf_fail, CTLFLAG_RD, &iflib_encap_load_mbuf_fail, 0, "# busdma load failures"); SYSCTL_INT(_net_iflib, OID_AUTO, encap_txq_avail_fail, CTLFLAG_RD, &iflib_encap_txq_avail_fail, 0, "# txq avail failures"); SYSCTL_INT(_net_iflib, OID_AUTO, encap_txd_encap_fail, CTLFLAG_RD, &iflib_encap_txd_encap_fail, 0, "# driver encap failures"); static int iflib_task_fn_rxs; static int iflib_rx_intr_enables; static int iflib_fast_intrs; static int iflib_intr_link; static int iflib_intr_msix; static int iflib_rx_unavail; static int iflib_rx_ctx_inactive; static int iflib_rx_zero_len; static int iflib_rx_if_input; static int iflib_rx_mbuf_null; static int iflib_rxd_flush; static int iflib_verbose_debug; SYSCTL_INT(_net_iflib, OID_AUTO, intr_link, CTLFLAG_RD, &iflib_intr_link, 0, "# intr link calls"); SYSCTL_INT(_net_iflib, OID_AUTO, intr_msix, CTLFLAG_RD, &iflib_intr_msix, 0, "# intr msix calls"); SYSCTL_INT(_net_iflib, OID_AUTO, task_fn_rx, CTLFLAG_RD, &iflib_task_fn_rxs, 0, "# task_fn_rx calls"); SYSCTL_INT(_net_iflib, OID_AUTO, rx_intr_enables, CTLFLAG_RD, &iflib_rx_intr_enables, 0, "# rx intr enables"); SYSCTL_INT(_net_iflib, OID_AUTO, fast_intrs, CTLFLAG_RD, &iflib_fast_intrs, 0, "# fast_intr calls"); SYSCTL_INT(_net_iflib, OID_AUTO, rx_unavail, CTLFLAG_RD, &iflib_rx_unavail, 0, "# times rxeof called with no available data"); SYSCTL_INT(_net_iflib, OID_AUTO, rx_ctx_inactive, CTLFLAG_RD, &iflib_rx_ctx_inactive, 0, "# times rxeof called with inactive context"); SYSCTL_INT(_net_iflib, OID_AUTO, rx_zero_len, CTLFLAG_RD, &iflib_rx_zero_len, 0, "# times rxeof saw zero len mbuf"); SYSCTL_INT(_net_iflib, OID_AUTO, rx_if_input, CTLFLAG_RD, &iflib_rx_if_input, 0, "# times rxeof called if_input"); SYSCTL_INT(_net_iflib, OID_AUTO, rx_mbuf_null, CTLFLAG_RD, &iflib_rx_mbuf_null, 0, "# times rxeof got null mbuf"); SYSCTL_INT(_net_iflib, OID_AUTO, rxd_flush, CTLFLAG_RD, &iflib_rxd_flush, 0, "# times rxd_flush called"); SYSCTL_INT(_net_iflib, OID_AUTO, verbose_debug, CTLFLAG_RW, &iflib_verbose_debug, 0, "enable verbose debugging"); #define DBG_COUNTER_INC(name) atomic_add_int(&(iflib_ ## name), 1) static void iflib_debug_reset(void) { iflib_tx_seen = iflib_tx_sent = iflib_tx_encap = iflib_rx_allocs = iflib_fl_refills = iflib_fl_refills_large = iflib_tx_frees = iflib_txq_drain_flushing = iflib_txq_drain_oactive = iflib_txq_drain_notready = iflib_txq_drain_encapfail = iflib_encap_load_mbuf_fail = iflib_encap_txq_avail_fail = iflib_encap_txd_encap_fail = iflib_task_fn_rxs = iflib_rx_intr_enables = iflib_fast_intrs = iflib_intr_link = iflib_intr_msix = iflib_rx_unavail = iflib_rx_ctx_inactive = iflib_rx_zero_len = iflib_rx_if_input = iflib_rx_mbuf_null = iflib_rxd_flush = 0; } #else #define DBG_COUNTER_INC(name) static void iflib_debug_reset(void) {} #endif #define IFLIB_DEBUG 0 static void iflib_tx_structures_free(if_ctx_t ctx); static void iflib_rx_structures_free(if_ctx_t ctx); static int iflib_queues_alloc(if_ctx_t ctx); static int iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq); static int iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, int cidx, int budget); static int iflib_qset_structures_setup(if_ctx_t ctx); static int iflib_msix_init(if_ctx_t ctx); static int iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filterarg, int *rid, char *str); static void iflib_txq_check_drain(iflib_txq_t txq, int budget); static uint32_t iflib_txq_can_drain(struct ifmp_ring *); static int iflib_register(if_ctx_t); static void iflib_init_locked(if_ctx_t ctx); static void iflib_add_device_sysctl_pre(if_ctx_t ctx); static void iflib_add_device_sysctl_post(if_ctx_t ctx); static void iflib_ifmp_purge(iflib_txq_t txq); static void _iflib_pre_assert(if_softc_ctx_t scctx); #ifdef DEV_NETMAP #include #include #include MODULE_DEPEND(iflib, netmap, 1, 1, 1); /* * device-specific sysctl variables: * * iflib_crcstrip: 0: keep CRC in rx frames (default), 1: strip it. * During regular operations the CRC is stripped, but on some * hardware reception of frames not multiple of 64 is slower, * so using crcstrip=0 helps in benchmarks. * * iflib_rx_miss, iflib_rx_miss_bufs: * count packets that might be missed due to lost interrupts. */ SYSCTL_DECL(_dev_netmap); /* * The xl driver by default strips CRCs and we do not override it. */ int iflib_crcstrip = 1; SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_crcstrip, CTLFLAG_RW, &iflib_crcstrip, 1, "strip CRC on rx frames"); int iflib_rx_miss, iflib_rx_miss_bufs; SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss, CTLFLAG_RW, &iflib_rx_miss, 0, "potentially missed rx intr"); SYSCTL_INT(_dev_netmap, OID_AUTO, iflib_rx_miss_bufs, CTLFLAG_RW, &iflib_rx_miss_bufs, 0, "potentially missed rx intr bufs"); /* * Register/unregister. We are already under netmap lock. * Only called on the first register or the last unregister. */ static int iflib_netmap_register(struct netmap_adapter *na, int onoff) { struct ifnet *ifp = na->ifp; if_ctx_t ctx = ifp->if_softc; CTX_LOCK(ctx); IFDI_INTR_DISABLE(ctx); /* Tell the stack that the interface is no longer active */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); if (!CTX_IS_VF(ctx)) IFDI_CRCSTRIP_SET(ctx, onoff, iflib_crcstrip); /* enable or disable flags and callbacks in na and ifp */ if (onoff) { nm_set_native_flags(na); } else { nm_clear_native_flags(na); } IFDI_INIT(ctx); IFDI_CRCSTRIP_SET(ctx, onoff, iflib_crcstrip); // XXX why twice ? CTX_UNLOCK(ctx); return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1); } /* * Reconcile kernel and user view of the transmit ring. * * All information is in the kring. * Userspace wants to send packets up to the one before kring->rhead, * kernel knows kring->nr_hwcur is the first unsent packet. * * Here we push packets out (as many as possible), and possibly * reclaim buffers from previously completed transmission. * * The caller (netmap) guarantees that there is only one instance * running at any time. Any interference with other driver * methods should be handled by the individual drivers. */ static int iflib_netmap_txsync(struct netmap_kring *kring, int flags) { struct netmap_adapter *na = kring->na; struct ifnet *ifp = na->ifp; struct netmap_ring *ring = kring->ring; u_int nm_i; /* index into the netmap ring */ u_int nic_i; /* index into the NIC ring */ u_int n; u_int const lim = kring->nkr_num_slots - 1; u_int const head = kring->rhead; struct if_pkt_info pi; /* * interrupts on every tx packet are expensive so request * them every half ring, or where NS_REPORT is set */ u_int report_frequency = kring->nkr_num_slots >> 1; /* device-specific */ if_ctx_t ctx = ifp->if_softc; iflib_txq_t txq = &ctx->ifc_txqs[kring->ring_id]; pi.ipi_segs = txq->ift_segs; pi.ipi_qsidx = kring->ring_id; pi.ipi_ndescs = 0; bus_dmamap_sync(txq->ift_desc_tag, txq->ift_ifdi->idi_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); /* * First part: process new packets to send. * nm_i is the current index in the netmap ring, * nic_i is the corresponding index in the NIC ring. * * If we have packets to send (nm_i != head) * iterate over the netmap ring, fetch length and update * the corresponding slot in the NIC ring. Some drivers also * need to update the buffer's physical address in the NIC slot * even NS_BUF_CHANGED is not set (PNMB computes the addresses). * * The netmap_reload_map() calls is especially expensive, * even when (as in this case) the tag is 0, so do only * when the buffer has actually changed. * * If possible do not set the report/intr bit on all slots, * but only a few times per ring or when NS_REPORT is set. * * Finally, on 10G and faster drivers, it might be useful * to prefetch the next slot and txr entry. */ nm_i = kring->nr_hwcur; if (nm_i != head) { /* we have new packets to send */ nic_i = netmap_idx_k2n(kring, nm_i); __builtin_prefetch(&ring->slot[nm_i]); __builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i]); __builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i]); for (n = 0; nm_i != head; n++) { struct netmap_slot *slot = &ring->slot[nm_i]; u_int len = slot->len; uint64_t paddr; void *addr = PNMB(na, slot, &paddr); int flags = (slot->flags & NS_REPORT || nic_i == 0 || nic_i == report_frequency) ? IPI_TX_INTR : 0; /* device-specific */ pi.ipi_pidx = nic_i; pi.ipi_flags = flags; /* Fill the slot in the NIC ring. */ ctx->isc_txd_encap(ctx->ifc_softc, &pi); /* prefetch for next round */ __builtin_prefetch(&ring->slot[nm_i + 1]); __builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i + 1]); __builtin_prefetch(&txq->ift_sds.ifsd_map[nic_i + 1]); NM_CHECK_ADDR_LEN(na, addr, len); if (slot->flags & NS_BUF_CHANGED) { /* buffer has changed, reload map */ netmap_reload_map(na, txq->ift_desc_tag, txq->ift_sds.ifsd_map[nic_i], addr); } slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); /* make sure changes to the buffer are synced */ bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_sds.ifsd_map[nic_i], BUS_DMASYNC_PREWRITE); nm_i = nm_next(nm_i, lim); nic_i = nm_next(nic_i, lim); } kring->nr_hwcur = head; /* synchronize the NIC ring */ bus_dmamap_sync(txq->ift_desc_tag, txq->ift_ifdi->idi_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* (re)start the tx unit up to slot nic_i (excluded) */ ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, nic_i); } /* * Second part: reclaim buffers for completed transmissions. */ if (iflib_tx_credits_update(ctx, txq)) { /* some tx completed, increment avail */ nic_i = txq->ift_cidx_processed; kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim); } return (0); } /* * Reconcile kernel and user view of the receive ring. * Same as for the txsync, this routine must be efficient. * The caller guarantees a single invocations, but races against * the rest of the driver should be handled here. * * On call, kring->rhead is the first packet that userspace wants * to keep, and kring->rcur is the wakeup point. * The kernel has previously reported packets up to kring->rtail. * * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective * of whether or not we received an interrupt. */ static int iflib_netmap_rxsync(struct netmap_kring *kring, int flags) { struct netmap_adapter *na = kring->na; struct ifnet *ifp = na->ifp; struct netmap_ring *ring = kring->ring; u_int nm_i; /* index into the netmap ring */ u_int nic_i; /* index into the NIC ring */ u_int i, n; u_int const lim = kring->nkr_num_slots - 1; u_int const head = kring->rhead; int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; struct if_rxd_info ri; /* device-specific */ if_ctx_t ctx = ifp->if_softc; iflib_rxq_t rxq = &ctx->ifc_rxqs[kring->ring_id]; iflib_fl_t fl = rxq->ifr_fl; if (head > lim) return netmap_ring_reinit(kring); bzero(&ri, sizeof(ri)); ri.iri_qsidx = kring->ring_id; ri.iri_ifp = ctx->ifc_ifp; /* XXX check sync modes */ for (i = 0, fl = rxq->ifr_fl; i < rxq->ifr_nfl; i++, fl++) bus_dmamap_sync(rxq->ifr_fl[i].ifl_desc_tag, fl->ifl_ifdi->idi_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); /* * First part: import newly received packets. * * nm_i is the index of the next free slot in the netmap ring, * nic_i is the index of the next received packet in the NIC ring, * and they may differ in case if_init() has been called while * in netmap mode. For the receive ring we have * * nic_i = rxr->next_check; * nm_i = kring->nr_hwtail (previous) * and * nm_i == (nic_i + kring->nkr_hwofs) % ring_size * * rxr->next_check is set to 0 on a ring reinit */ if (netmap_no_pendintr || force_update) { int crclen = iflib_crcstrip ? 0 : 4; int error, avail; uint16_t slot_flags = kring->nkr_slot_flags; for (fl = rxq->ifr_fl, i = 0; i < rxq->ifr_nfl; i++, fl++) { nic_i = fl->ifl_cidx; nm_i = netmap_idx_n2k(kring, nic_i); avail = ctx->isc_rxd_available(ctx->ifc_softc, kring->ring_id, nic_i, INT_MAX); for (n = 0; avail > 0; n++, avail--) { error = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri); if (error) ring->slot[nm_i].len = 0; else ring->slot[nm_i].len = ri.iri_len - crclen; ring->slot[nm_i].flags = slot_flags; bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_sds.ifsd_map[nic_i], BUS_DMASYNC_POSTREAD); nm_i = nm_next(nm_i, lim); nic_i = nm_next(nic_i, lim); } if (n) { /* update the state variables */ if (netmap_no_pendintr && !force_update) { /* diagnostics */ iflib_rx_miss ++; iflib_rx_miss_bufs += n; } fl->ifl_cidx = nic_i; kring->nr_hwtail = nm_i; } kring->nr_kflags &= ~NKR_PENDINTR; } } /* * Second part: skip past packets that userspace has released. * (kring->nr_hwcur to head excluded), * and make the buffers available for reception. * As usual nm_i is the index in the netmap ring, * nic_i is the index in the NIC ring, and * nm_i == (nic_i + kring->nkr_hwofs) % ring_size */ /* XXX not sure how this will work with multiple free lists */ nm_i = kring->nr_hwcur; if (nm_i != head) { nic_i = netmap_idx_k2n(kring, nm_i); for (n = 0; nm_i != head; n++) { struct netmap_slot *slot = &ring->slot[nm_i]; uint64_t paddr; caddr_t vaddr; void *addr = PNMB(na, slot, &paddr); if (addr == NETMAP_BUF_BASE(na)) /* bad buf */ goto ring_reset; vaddr = addr; if (slot->flags & NS_BUF_CHANGED) { /* buffer has changed, reload map */ netmap_reload_map(na, fl->ifl_ifdi->idi_tag, fl->ifl_sds.ifsd_map[nic_i], addr); slot->flags &= ~NS_BUF_CHANGED; } /* * XXX we should be batching this operation - TODO */ ctx->isc_rxd_refill(ctx->ifc_softc, rxq->ifr_id, fl->ifl_id, nic_i, &paddr, &vaddr, 1, fl->ifl_buf_size); bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_sds.ifsd_map[nic_i], BUS_DMASYNC_PREREAD); nm_i = nm_next(nm_i, lim); nic_i = nm_next(nic_i, lim); } kring->nr_hwcur = head; bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* * IMPORTANT: we must leave one free slot in the ring, * so move nic_i back by one unit */ nic_i = nm_prev(nic_i, lim); ctx->isc_rxd_flush(ctx->ifc_softc, rxq->ifr_id, fl->ifl_id, nic_i); } return 0; ring_reset: return netmap_ring_reinit(kring); } static int iflib_netmap_attach(if_ctx_t ctx) { struct netmap_adapter na; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; bzero(&na, sizeof(na)); na.ifp = ctx->ifc_ifp; na.na_flags = NAF_BDG_MAYSLEEP; MPASS(ctx->ifc_softc_ctx.isc_ntxqsets); MPASS(ctx->ifc_softc_ctx.isc_nrxqsets); na.num_tx_desc = scctx->isc_ntxd[0]; na.num_rx_desc = scctx->isc_nrxd[0]; na.nm_txsync = iflib_netmap_txsync; na.nm_rxsync = iflib_netmap_rxsync; na.nm_register = iflib_netmap_register; na.num_tx_rings = ctx->ifc_softc_ctx.isc_ntxqsets; na.num_rx_rings = ctx->ifc_softc_ctx.isc_nrxqsets; return (netmap_attach(&na)); } static void iflib_netmap_txq_init(if_ctx_t ctx, iflib_txq_t txq) { struct netmap_adapter *na = NA(ctx->ifc_ifp); struct netmap_slot *slot; slot = netmap_reset(na, NR_TX, txq->ift_id, 0); if (slot == 0) return; for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxd[0]; i++) { /* * In netmap mode, set the map for the packet buffer. * NOTE: Some drivers (not this one) also need to set * the physical buffer address in the NIC ring. * netmap_idx_n2k() maps a nic index, i, into the corresponding * netmap slot index, si */ int si = netmap_idx_n2k(&na->tx_rings[txq->ift_id], i); netmap_load_map(na, txq->ift_desc_tag, txq->ift_sds.ifsd_map[i], NMB(na, slot + si)); } } static void iflib_netmap_rxq_init(if_ctx_t ctx, iflib_rxq_t rxq) { struct netmap_adapter *na = NA(ctx->ifc_ifp); struct netmap_slot *slot; bus_dmamap_t *map; int nrxd; slot = netmap_reset(na, NR_RX, rxq->ifr_id, 0); if (slot == 0) return; map = rxq->ifr_fl[0].ifl_sds.ifsd_map; nrxd = ctx->ifc_softc_ctx.isc_nrxd[0]; for (int i = 0; i < nrxd; i++, map++) { int sj = netmap_idx_n2k(&na->rx_rings[rxq->ifr_id], i); uint64_t paddr; void *addr; caddr_t vaddr; vaddr = addr = PNMB(na, slot + sj, &paddr); netmap_load_map(na, rxq->ifr_fl[0].ifl_ifdi->idi_tag, *map, addr); /* Update descriptor and the cached value */ ctx->isc_rxd_refill(ctx->ifc_softc, rxq->ifr_id, 0 /* fl_id */, i, &paddr, &vaddr, 1, rxq->ifr_fl[0].ifl_buf_size); } /* preserve queue */ if (ctx->ifc_ifp->if_capenable & IFCAP_NETMAP) { struct netmap_kring *kring = &na->rx_rings[rxq->ifr_id]; int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); ctx->isc_rxd_flush(ctx->ifc_softc, rxq->ifr_id, 0 /* fl_id */, t); } else ctx->isc_rxd_flush(ctx->ifc_softc, rxq->ifr_id, 0 /* fl_id */, nrxd-1); } #define iflib_netmap_detach(ifp) netmap_detach(ifp) #else #define iflib_netmap_txq_init(ctx, txq) #define iflib_netmap_rxq_init(ctx, rxq) #define iflib_netmap_detach(ifp) #define iflib_netmap_attach(ctx) (0) #define netmap_rx_irq(ifp, qid, budget) (0) #endif #if defined(__i386__) || defined(__amd64__) static __inline void prefetch(void *x) { __asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x)); } #else #define prefetch(x) #endif static void _iflib_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) { if (err) return; *(bus_addr_t *) arg = segs[0].ds_addr; } int iflib_dma_alloc(if_ctx_t ctx, int size, iflib_dma_info_t dma, int mapflags) { int err; if_shared_ctx_t sctx = ctx->ifc_sctx; device_t dev = ctx->ifc_dev; KASSERT(sctx->isc_q_align != 0, ("alignment value not initialized")); err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ sctx->isc_q_align, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ size, /* maxsize */ 1, /* nsegments */ size, /* maxsegsize */ BUS_DMA_ALLOCNOW, /* flags */ NULL, /* lockfunc */ NULL, /* lockarg */ &dma->idi_tag); if (err) { device_printf(dev, "%s: bus_dma_tag_create failed: %d\n", __func__, err); goto fail_0; } err = bus_dmamem_alloc(dma->idi_tag, (void**) &dma->idi_vaddr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_ZERO, &dma->idi_map); if (err) { device_printf(dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__, (uintmax_t)size, err); goto fail_1; } dma->idi_paddr = IF_BAD_DMA; err = bus_dmamap_load(dma->idi_tag, dma->idi_map, dma->idi_vaddr, size, _iflib_dmamap_cb, &dma->idi_paddr, mapflags | BUS_DMA_NOWAIT); if (err || dma->idi_paddr == IF_BAD_DMA) { device_printf(dev, "%s: bus_dmamap_load failed: %d\n", __func__, err); goto fail_2; } dma->idi_size = size; return (0); fail_2: bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map); fail_1: bus_dma_tag_destroy(dma->idi_tag); fail_0: dma->idi_tag = NULL; return (err); } int iflib_dma_alloc_multi(if_ctx_t ctx, int *sizes, iflib_dma_info_t *dmalist, int mapflags, int count) { int i, err; iflib_dma_info_t *dmaiter; dmaiter = dmalist; for (i = 0; i < count; i++, dmaiter++) { if ((err = iflib_dma_alloc(ctx, sizes[i], *dmaiter, mapflags)) != 0) break; } if (err) iflib_dma_free_multi(dmalist, i); return (err); } void iflib_dma_free(iflib_dma_info_t dma) { if (dma->idi_tag == NULL) return; if (dma->idi_paddr != IF_BAD_DMA) { bus_dmamap_sync(dma->idi_tag, dma->idi_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(dma->idi_tag, dma->idi_map); dma->idi_paddr = IF_BAD_DMA; } if (dma->idi_vaddr != NULL) { bus_dmamem_free(dma->idi_tag, dma->idi_vaddr, dma->idi_map); dma->idi_vaddr = NULL; } bus_dma_tag_destroy(dma->idi_tag); dma->idi_tag = NULL; } void iflib_dma_free_multi(iflib_dma_info_t *dmalist, int count) { int i; iflib_dma_info_t *dmaiter = dmalist; for (i = 0; i < count; i++, dmaiter++) iflib_dma_free(*dmaiter); } #ifdef EARLY_AP_STARTUP static const int iflib_started = 1; #else /* * We used to abuse the smp_started flag to decide if the queues have been * fully initialized (by late taskqgroup_adjust() calls in a SYSINIT()). * That gave bad races, since the SYSINIT() runs strictly after smp_started * is set. Run a SYSINIT() strictly after that to just set a usable * completion flag. */ static int iflib_started; static void iflib_record_started(void *arg) { iflib_started = 1; } SYSINIT(iflib_record_started, SI_SUB_SMP + 1, SI_ORDER_FIRST, iflib_record_started, NULL); #endif static int iflib_fast_intr(void *arg) { iflib_filter_info_t info = arg; struct grouptask *gtask = info->ifi_task; if (!iflib_started) return (FILTER_HANDLED); DBG_COUNTER_INC(fast_intrs); if (info->ifi_filter != NULL && info->ifi_filter(info->ifi_filter_arg) == FILTER_HANDLED) return (FILTER_HANDLED); GROUPTASK_ENQUEUE(gtask); return (FILTER_HANDLED); } static int _iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid, driver_filter_t filter, driver_intr_t handler, void *arg, char *name) { int rc; struct resource *res; void *tag; device_t dev = ctx->ifc_dev; MPASS(rid < 512); irq->ii_rid = rid; res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq->ii_rid, RF_SHAREABLE | RF_ACTIVE); if (res == NULL) { device_printf(dev, "failed to allocate IRQ for rid %d, name %s.\n", rid, name); return (ENOMEM); } irq->ii_res = res; KASSERT(filter == NULL || handler == NULL, ("filter and handler can't both be non-NULL")); rc = bus_setup_intr(dev, res, INTR_MPSAFE | INTR_TYPE_NET, filter, handler, arg, &tag); if (rc != 0) { device_printf(dev, "failed to setup interrupt for rid %d, name %s: %d\n", rid, name ? name : "unknown", rc); return (rc); } else if (name) bus_describe_intr(dev, res, tag, "%s", name); irq->ii_tag = tag; return (0); } /********************************************************************* * * Allocate memory for tx_buffer structures. The tx_buffer stores all * the information needed to transmit a packet on the wire. This is * called only once at attach, setup is done every reset. * **********************************************************************/ static int iflib_txsd_alloc(iflib_txq_t txq) { if_ctx_t ctx = txq->ift_ctx; if_shared_ctx_t sctx = ctx->ifc_sctx; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; device_t dev = ctx->ifc_dev; int err, nsegments, ntsosegments; nsegments = scctx->isc_tx_nsegments; ntsosegments = scctx->isc_tx_tso_segments_max; MPASS(scctx->isc_ntxd[0] > 0); MPASS(scctx->isc_ntxd[txq->ift_br_offset] > 0); MPASS(nsegments > 0); MPASS(ntsosegments > 0); /* * Setup DMA descriptor areas. */ if ((err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ sctx->isc_tx_maxsize, /* maxsize */ nsegments, /* nsegments */ sctx->isc_tx_maxsegsize, /* maxsegsize */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockfuncarg */ &txq->ift_desc_tag))) { device_printf(dev,"Unable to allocate TX DMA tag: %d\n", err); device_printf(dev,"maxsize: %zd nsegments: %d maxsegsize: %zd\n", sctx->isc_tx_maxsize, nsegments, sctx->isc_tx_maxsegsize); goto fail; } if ((err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ scctx->isc_tx_tso_size_max, /* maxsize */ ntsosegments, /* nsegments */ scctx->isc_tx_tso_segsize_max, /* maxsegsize */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockfuncarg */ &txq->ift_tso_desc_tag))) { device_printf(dev,"Unable to allocate TX TSO DMA tag: %d\n", err); goto fail; } if (!(txq->ift_sds.ifsd_flags = (uint8_t *) malloc(sizeof(uint8_t) * scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate tx_buffer memory\n"); err = ENOMEM; goto fail; } if (!(txq->ift_sds.ifsd_m = (struct mbuf **) malloc(sizeof(struct mbuf *) * scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate tx_buffer memory\n"); err = ENOMEM; goto fail; } /* Create the descriptor buffer dma maps */ #if defined(ACPI_DMAR) || (!(defined(__i386__) && !defined(__amd64__))) if ((ctx->ifc_flags & IFC_DMAR) == 0) return (0); if (!(txq->ift_sds.ifsd_map = (bus_dmamap_t *) malloc(sizeof(bus_dmamap_t) * scctx->isc_ntxd[txq->ift_br_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate tx_buffer map memory\n"); err = ENOMEM; goto fail; } for (int i = 0; i < scctx->isc_ntxd[txq->ift_br_offset]; i++) { err = bus_dmamap_create(txq->ift_desc_tag, 0, &txq->ift_sds.ifsd_map[i]); if (err != 0) { device_printf(dev, "Unable to create TX DMA map\n"); goto fail; } } #endif return (0); fail: /* We free all, it handles case where we are in the middle */ iflib_tx_structures_free(ctx); return (err); } static void iflib_txsd_destroy(if_ctx_t ctx, iflib_txq_t txq, int i) { bus_dmamap_t map; map = NULL; if (txq->ift_sds.ifsd_map != NULL) map = txq->ift_sds.ifsd_map[i]; if (map != NULL) { bus_dmamap_unload(txq->ift_desc_tag, map); bus_dmamap_destroy(txq->ift_desc_tag, map); txq->ift_sds.ifsd_map[i] = NULL; } } static void iflib_txq_destroy(iflib_txq_t txq) { if_ctx_t ctx = txq->ift_ctx; for (int i = 0; i < txq->ift_size; i++) iflib_txsd_destroy(ctx, txq, i); if (txq->ift_sds.ifsd_map != NULL) { free(txq->ift_sds.ifsd_map, M_IFLIB); txq->ift_sds.ifsd_map = NULL; } if (txq->ift_sds.ifsd_m != NULL) { free(txq->ift_sds.ifsd_m, M_IFLIB); txq->ift_sds.ifsd_m = NULL; } if (txq->ift_sds.ifsd_flags != NULL) { free(txq->ift_sds.ifsd_flags, M_IFLIB); txq->ift_sds.ifsd_flags = NULL; } if (txq->ift_desc_tag != NULL) { bus_dma_tag_destroy(txq->ift_desc_tag); txq->ift_desc_tag = NULL; } if (txq->ift_tso_desc_tag != NULL) { bus_dma_tag_destroy(txq->ift_tso_desc_tag); txq->ift_tso_desc_tag = NULL; } } static void iflib_txsd_free(if_ctx_t ctx, iflib_txq_t txq, int i) { struct mbuf **mp; mp = &txq->ift_sds.ifsd_m[i]; if (*mp == NULL) return; if (txq->ift_sds.ifsd_map != NULL) { bus_dmamap_sync(txq->ift_desc_tag, txq->ift_sds.ifsd_map[i], BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(txq->ift_desc_tag, txq->ift_sds.ifsd_map[i]); } m_free(*mp); DBG_COUNTER_INC(tx_frees); *mp = NULL; } static int iflib_txq_setup(iflib_txq_t txq) { if_ctx_t ctx = txq->ift_ctx; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; iflib_dma_info_t di; int i; /* Set number of descriptors available */ txq->ift_qstatus = IFLIB_QUEUE_IDLE; /* Reset indices */ txq->ift_cidx_processed = txq->ift_pidx = txq->ift_cidx = txq->ift_npending = 0; txq->ift_size = scctx->isc_ntxd[txq->ift_br_offset]; for (i = 0, di = txq->ift_ifdi; i < ctx->ifc_nhwtxqs; i++, di++) bzero((void *)di->idi_vaddr, di->idi_size); IFDI_TXQ_SETUP(ctx, txq->ift_id); for (i = 0, di = txq->ift_ifdi; i < ctx->ifc_nhwtxqs; i++, di++) bus_dmamap_sync(di->idi_tag, di->idi_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); return (0); } /********************************************************************* * * Allocate memory for rx_buffer structures. Since we use one * rx_buffer per received packet, the maximum number of rx_buffer's * that we'll need is equal to the number of receive descriptors * that we've allocated. * **********************************************************************/ static int iflib_rxsd_alloc(iflib_rxq_t rxq) { if_ctx_t ctx = rxq->ifr_ctx; if_shared_ctx_t sctx = ctx->ifc_sctx; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; device_t dev = ctx->ifc_dev; iflib_fl_t fl; int err; MPASS(scctx->isc_nrxd[0] > 0); MPASS(scctx->isc_nrxd[rxq->ifr_fl_offset] > 0); fl = rxq->ifr_fl; for (int i = 0; i < rxq->ifr_nfl; i++, fl++) { fl->ifl_size = scctx->isc_nrxd[rxq->ifr_fl_offset]; /* this isn't necessarily the same */ err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ sctx->isc_rx_maxsize, /* maxsize */ sctx->isc_rx_nsegments, /* nsegments */ sctx->isc_rx_maxsegsize, /* maxsegsize */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockarg */ &fl->ifl_desc_tag); if (err) { device_printf(dev, "%s: bus_dma_tag_create failed %d\n", __func__, err); goto fail; } if (!(fl->ifl_sds.ifsd_flags = (uint8_t *) malloc(sizeof(uint8_t) * scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate tx_buffer memory\n"); err = ENOMEM; goto fail; } if (!(fl->ifl_sds.ifsd_m = (struct mbuf **) malloc(sizeof(struct mbuf *) * scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate tx_buffer memory\n"); err = ENOMEM; goto fail; } if (!(fl->ifl_sds.ifsd_cl = (caddr_t *) malloc(sizeof(caddr_t) * scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate tx_buffer memory\n"); err = ENOMEM; goto fail; } /* Create the descriptor buffer dma maps */ #if defined(ACPI_DMAR) || (!(defined(__i386__) && !defined(__amd64__))) if ((ctx->ifc_flags & IFC_DMAR) == 0) continue; if (!(fl->ifl_sds.ifsd_map = (bus_dmamap_t *) malloc(sizeof(bus_dmamap_t) * scctx->isc_nrxd[rxq->ifr_fl_offset], M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate tx_buffer map memory\n"); err = ENOMEM; goto fail; } for (int i = 0; i < scctx->isc_nrxd[rxq->ifr_fl_offset]; i++) { err = bus_dmamap_create(fl->ifl_desc_tag, 0, &fl->ifl_sds.ifsd_map[i]); if (err != 0) { device_printf(dev, "Unable to create TX DMA map\n"); goto fail; } } #endif } return (0); fail: iflib_rx_structures_free(ctx); return (err); } /* * Internal service routines */ struct rxq_refill_cb_arg { int error; bus_dma_segment_t seg; int nseg; }; static void _rxq_refill_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) { struct rxq_refill_cb_arg *cb_arg = arg; cb_arg->error = error; cb_arg->seg = segs[0]; cb_arg->nseg = nseg; } #ifdef ACPI_DMAR #define IS_DMAR(ctx) (ctx->ifc_flags & IFC_DMAR) #else #define IS_DMAR(ctx) (0) #endif /** * rxq_refill - refill an rxq free-buffer list * @ctx: the iflib context * @rxq: the free-list to refill * @n: the number of new buffers to allocate * * (Re)populate an rxq free-buffer list with up to @n new packet buffers. * The caller must assure that @n does not exceed the queue's capacity. */ static void _iflib_fl_refill(if_ctx_t ctx, iflib_fl_t fl, int count) { struct mbuf *m; int idx, pidx = fl->ifl_pidx; caddr_t cl, *sd_cl; struct mbuf **sd_m; uint8_t *sd_flags; bus_dmamap_t *sd_map; int n, i = 0; uint64_t bus_addr; int err; sd_m = fl->ifl_sds.ifsd_m; sd_map = fl->ifl_sds.ifsd_map; sd_cl = fl->ifl_sds.ifsd_cl; sd_flags = fl->ifl_sds.ifsd_flags; idx = pidx; n = count; MPASS(n > 0); MPASS(fl->ifl_credits + n <= fl->ifl_size); if (pidx < fl->ifl_cidx) MPASS(pidx + n <= fl->ifl_cidx); if (pidx == fl->ifl_cidx && (fl->ifl_credits < fl->ifl_size)) MPASS(fl->ifl_gen == 0); if (pidx > fl->ifl_cidx) MPASS(n <= fl->ifl_size - pidx + fl->ifl_cidx); DBG_COUNTER_INC(fl_refills); if (n > 8) DBG_COUNTER_INC(fl_refills_large); while (n--) { /* * We allocate an uninitialized mbuf + cluster, mbuf is * initialized after rx. * * If the cluster is still set then we know a minimum sized packet was received */ if ((cl = sd_cl[idx]) == NULL) { if ((cl = sd_cl[idx] = m_cljget(NULL, M_NOWAIT, fl->ifl_buf_size)) == NULL) break; #if MEMORY_LOGGING fl->ifl_cl_enqueued++; #endif } if ((m = m_gethdr(M_NOWAIT, MT_NOINIT)) == NULL) { break; } #if MEMORY_LOGGING fl->ifl_m_enqueued++; #endif DBG_COUNTER_INC(rx_allocs); #ifdef notyet if ((sd_flags[pidx] & RX_SW_DESC_MAP_CREATED) == 0) { int err; if ((err = bus_dmamap_create(fl->ifl_ifdi->idi_tag, 0, &sd_map[idx]))) { log(LOG_WARNING, "bus_dmamap_create failed %d\n", err); uma_zfree(fl->ifl_zone, cl); n = 0; goto done; } sd_flags[idx] |= RX_SW_DESC_MAP_CREATED; } #endif #if defined(__i386__) || defined(__amd64__) if (!IS_DMAR(ctx)) { bus_addr = pmap_kextract((vm_offset_t)cl); } else #endif { struct rxq_refill_cb_arg cb_arg; iflib_rxq_t q; cb_arg.error = 0; q = fl->ifl_rxq; err = bus_dmamap_load(fl->ifl_desc_tag, sd_map[idx], cl, fl->ifl_buf_size, _rxq_refill_cb, &cb_arg, 0); if (err != 0 || cb_arg.error) { /* * !zone_pack ? */ if (fl->ifl_zone == zone_pack) uma_zfree(fl->ifl_zone, cl); m_free(m); n = 0; goto done; } bus_addr = cb_arg.seg.ds_addr; } sd_flags[idx] |= RX_SW_DESC_INUSE; MPASS(sd_m[idx] == NULL); sd_cl[idx] = cl; sd_m[idx] = m; fl->ifl_bus_addrs[i] = bus_addr; fl->ifl_vm_addrs[i] = cl; fl->ifl_credits++; i++; MPASS(fl->ifl_credits <= fl->ifl_size); if (++idx == fl->ifl_size) { fl->ifl_gen = 1; idx = 0; } if (n == 0 || i == IFLIB_MAX_RX_REFRESH) { ctx->isc_rxd_refill(ctx->ifc_softc, fl->ifl_rxq->ifr_id, fl->ifl_id, pidx, fl->ifl_bus_addrs, fl->ifl_vm_addrs, i, fl->ifl_buf_size); i = 0; pidx = idx; } fl->ifl_pidx = idx; } done: DBG_COUNTER_INC(rxd_flush); if (fl->ifl_pidx == 0) pidx = fl->ifl_size - 1; else pidx = fl->ifl_pidx - 1; ctx->isc_rxd_flush(ctx->ifc_softc, fl->ifl_rxq->ifr_id, fl->ifl_id, pidx); } static __inline void __iflib_fl_refill_lt(if_ctx_t ctx, iflib_fl_t fl, int max) { /* we avoid allowing pidx to catch up with cidx as it confuses ixl */ int32_t reclaimable = fl->ifl_size - fl->ifl_credits - 1; #ifdef INVARIANTS int32_t delta = fl->ifl_size - get_inuse(fl->ifl_size, fl->ifl_cidx, fl->ifl_pidx, fl->ifl_gen) - 1; #endif MPASS(fl->ifl_credits <= fl->ifl_size); MPASS(reclaimable == delta); if (reclaimable > 0) _iflib_fl_refill(ctx, fl, min(max, reclaimable)); } static void iflib_fl_bufs_free(iflib_fl_t fl) { iflib_dma_info_t idi = fl->ifl_ifdi; uint32_t i; for (i = 0; i < fl->ifl_size; i++) { struct mbuf **sd_m = &fl->ifl_sds.ifsd_m[i]; uint8_t *sd_flags = &fl->ifl_sds.ifsd_flags[i]; caddr_t *sd_cl = &fl->ifl_sds.ifsd_cl[i]; if (*sd_flags & RX_SW_DESC_INUSE) { if (fl->ifl_sds.ifsd_map != NULL) { bus_dmamap_t sd_map = fl->ifl_sds.ifsd_map[i]; bus_dmamap_unload(fl->ifl_desc_tag, sd_map); bus_dmamap_destroy(fl->ifl_desc_tag, sd_map); } if (*sd_m != NULL) { m_init(*sd_m, M_NOWAIT, MT_DATA, 0); uma_zfree(zone_mbuf, *sd_m); } if (*sd_cl != NULL) uma_zfree(fl->ifl_zone, *sd_cl); *sd_flags = 0; } else { MPASS(*sd_cl == NULL); MPASS(*sd_m == NULL); } #if MEMORY_LOGGING fl->ifl_m_dequeued++; fl->ifl_cl_dequeued++; #endif *sd_cl = NULL; *sd_m = NULL; } /* * Reset free list values */ fl->ifl_credits = fl->ifl_cidx = fl->ifl_pidx = fl->ifl_gen = 0;; bzero(idi->idi_vaddr, idi->idi_size); } /********************************************************************* * * Initialize a receive ring and its buffers. * **********************************************************************/ static int iflib_fl_setup(iflib_fl_t fl) { iflib_rxq_t rxq = fl->ifl_rxq; if_ctx_t ctx = rxq->ifr_ctx; if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; /* ** Free current RX buffer structs and their mbufs */ iflib_fl_bufs_free(fl); /* Now replenish the mbufs */ MPASS(fl->ifl_credits == 0); /* * XXX don't set the max_frame_size to larger * than the hardware can handle */ if (sctx->isc_max_frame_size <= 2048) fl->ifl_buf_size = MCLBYTES; else if (sctx->isc_max_frame_size <= 4096) fl->ifl_buf_size = MJUMPAGESIZE; else if (sctx->isc_max_frame_size <= 9216) fl->ifl_buf_size = MJUM9BYTES; else fl->ifl_buf_size = MJUM16BYTES; if (fl->ifl_buf_size > ctx->ifc_max_fl_buf_size) ctx->ifc_max_fl_buf_size = fl->ifl_buf_size; fl->ifl_cltype = m_gettype(fl->ifl_buf_size); fl->ifl_zone = m_getzone(fl->ifl_buf_size); /* avoid pre-allocating zillions of clusters to an idle card * potentially speeding up attach */ _iflib_fl_refill(ctx, fl, min(128, fl->ifl_size)); MPASS(min(128, fl->ifl_size) == fl->ifl_credits); if (min(128, fl->ifl_size) != fl->ifl_credits) return (ENOBUFS); /* * handle failure */ MPASS(rxq != NULL); MPASS(fl->ifl_ifdi != NULL); bus_dmamap_sync(fl->ifl_ifdi->idi_tag, fl->ifl_ifdi->idi_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); return (0); } /********************************************************************* * * Free receive ring data structures * **********************************************************************/ static void iflib_rx_sds_free(iflib_rxq_t rxq) { iflib_fl_t fl; int i; if (rxq->ifr_fl != NULL) { for (i = 0; i < rxq->ifr_nfl; i++) { fl = &rxq->ifr_fl[i]; if (fl->ifl_desc_tag != NULL) { bus_dma_tag_destroy(fl->ifl_desc_tag); fl->ifl_desc_tag = NULL; } free(fl->ifl_sds.ifsd_m, M_IFLIB); free(fl->ifl_sds.ifsd_cl, M_IFLIB); /* XXX destroy maps first */ free(fl->ifl_sds.ifsd_map, M_IFLIB); fl->ifl_sds.ifsd_m = NULL; fl->ifl_sds.ifsd_cl = NULL; fl->ifl_sds.ifsd_map = NULL; } free(rxq->ifr_fl, M_IFLIB); rxq->ifr_fl = NULL; rxq->ifr_cq_gen = rxq->ifr_cq_cidx = rxq->ifr_cq_pidx = 0; } } /* * MI independent logic * */ static void iflib_timer(void *arg) { iflib_txq_t txq = arg; if_ctx_t ctx = txq->ift_ctx; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) return; /* ** Check on the state of the TX queue(s), this ** can be done without the lock because its RO ** and the HUNG state will be static if set. */ IFDI_TIMER(ctx, txq->ift_id); if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) && (ctx->ifc_pause_frames == 0)) goto hung; if (TXQ_AVAIL(txq) <= 2*scctx->isc_tx_nsegments || ifmp_ring_is_stalled(txq->ift_br[0])) GROUPTASK_ENQUEUE(&txq->ift_task); ctx->ifc_pause_frames = 0; if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, txq->ift_timer.c_cpu); return; hung: CTX_LOCK(ctx); if_setdrvflagbits(ctx->ifc_ifp, 0, IFF_DRV_RUNNING); device_printf(ctx->ifc_dev, "TX(%d) desc avail = %d, pidx = %d\n", txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx); IFDI_WATCHDOG_RESET(ctx); ctx->ifc_watchdog_events++; ctx->ifc_pause_frames = 0; iflib_init_locked(ctx); CTX_UNLOCK(ctx); } static void iflib_init_locked(if_ctx_t ctx) { if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; if_t ifp = ctx->ifc_ifp; iflib_fl_t fl; iflib_txq_t txq; iflib_rxq_t rxq; int i, j, tx_ip_csum_flags, tx_ip6_csum_flags; if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); IFDI_INTR_DISABLE(ctx); tx_ip_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP); tx_ip6_csum_flags = scctx->isc_tx_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_SCTP); /* Set hardware offload abilities */ if_clearhwassist(ifp); if (if_getcapenable(ifp) & IFCAP_TXCSUM) if_sethwassistbits(ifp, tx_ip_csum_flags, 0); if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6) if_sethwassistbits(ifp, tx_ip6_csum_flags, 0); if (if_getcapenable(ifp) & IFCAP_TSO4) if_sethwassistbits(ifp, CSUM_IP_TSO, 0); if (if_getcapenable(ifp) & IFCAP_TSO6) if_sethwassistbits(ifp, CSUM_IP6_TSO, 0); for (i = 0, txq = ctx->ifc_txqs; i < sctx->isc_ntxqsets; i++, txq++) { CALLOUT_LOCK(txq); callout_stop(&txq->ift_timer); callout_stop(&txq->ift_db_check); CALLOUT_UNLOCK(txq); iflib_netmap_txq_init(ctx, txq); } for (i = 0, rxq = ctx->ifc_rxqs; i < sctx->isc_nrxqsets; i++, rxq++) { iflib_netmap_rxq_init(ctx, rxq); } #ifdef INVARIANTS i = if_getdrvflags(ifp); #endif IFDI_INIT(ctx); MPASS(if_getdrvflags(ifp) == i); for (i = 0, rxq = ctx->ifc_rxqs; i < sctx->isc_nrxqsets; i++, rxq++) { for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) { if (iflib_fl_setup(fl)) { device_printf(ctx->ifc_dev, "freelist setup failed - check cluster settings\n"); goto done; } } } done: if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); IFDI_INTR_ENABLE(ctx); txq = ctx->ifc_txqs; for (i = 0; i < sctx->isc_ntxqsets; i++, txq++) callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, txq->ift_timer.c_cpu); } static int iflib_media_change(if_t ifp) { if_ctx_t ctx = if_getsoftc(ifp); int err; CTX_LOCK(ctx); if ((err = IFDI_MEDIA_CHANGE(ctx)) == 0) iflib_init_locked(ctx); CTX_UNLOCK(ctx); return (err); } static void iflib_media_status(if_t ifp, struct ifmediareq *ifmr) { if_ctx_t ctx = if_getsoftc(ifp); CTX_LOCK(ctx); IFDI_UPDATE_ADMIN_STATUS(ctx); IFDI_MEDIA_STATUS(ctx, ifmr); CTX_UNLOCK(ctx); } static void iflib_stop(if_ctx_t ctx) { iflib_txq_t txq = ctx->ifc_txqs; iflib_rxq_t rxq = ctx->ifc_rxqs; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; iflib_dma_info_t di; iflib_fl_t fl; int i, j; /* Tell the stack that the interface is no longer active */ if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); IFDI_INTR_DISABLE(ctx); DELAY(100000); IFDI_STOP(ctx); DELAY(100000); iflib_debug_reset(); /* Wait for current tx queue users to exit to disarm watchdog timer. */ for (i = 0; i < scctx->isc_ntxqsets; i++, txq++) { /* make sure all transmitters have completed before proceeding XXX */ /* clean any enqueued buffers */ iflib_ifmp_purge(txq); /* Free any existing tx buffers. */ for (j = 0; j < txq->ift_size; j++) { iflib_txsd_free(ctx, txq, j); } txq->ift_processed = txq->ift_cleaned = txq->ift_cidx_processed = 0; txq->ift_in_use = txq->ift_gen = txq->ift_cidx = txq->ift_pidx = txq->ift_no_desc_avail = 0; txq->ift_closed = txq->ift_mbuf_defrag = txq->ift_mbuf_defrag_failed = 0; txq->ift_no_tx_dma_setup = txq->ift_txd_encap_efbig = txq->ift_map_failed = 0; txq->ift_pullups = 0; ifmp_ring_reset_stats(txq->ift_br[0]); for (j = 0, di = txq->ift_ifdi; j < ctx->ifc_nhwtxqs; j++, di++) bzero((void *)di->idi_vaddr, di->idi_size); } for (i = 0; i < scctx->isc_nrxqsets; i++, rxq++) { /* make sure all transmitters have completed before proceeding XXX */ for (j = 0, di = txq->ift_ifdi; j < ctx->ifc_nhwrxqs; j++, di++) bzero((void *)di->idi_vaddr, di->idi_size); /* also resets the free lists pidx/cidx */ for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) iflib_fl_bufs_free(fl); } } static inline void prefetch_pkts(iflib_fl_t fl, int cidx) { int nextptr; int nrxd = fl->ifl_size; nextptr = (cidx + CACHE_PTR_INCREMENT) & (nrxd-1); prefetch(&fl->ifl_sds.ifsd_m[nextptr]); prefetch(&fl->ifl_sds.ifsd_cl[nextptr]); prefetch(fl->ifl_sds.ifsd_m[(cidx + 1) & (nrxd-1)]); prefetch(fl->ifl_sds.ifsd_m[(cidx + 2) & (nrxd-1)]); prefetch(fl->ifl_sds.ifsd_m[(cidx + 3) & (nrxd-1)]); prefetch(fl->ifl_sds.ifsd_m[(cidx + 4) & (nrxd-1)]); prefetch(fl->ifl_sds.ifsd_cl[(cidx + 1) & (nrxd-1)]); prefetch(fl->ifl_sds.ifsd_cl[(cidx + 2) & (nrxd-1)]); prefetch(fl->ifl_sds.ifsd_cl[(cidx + 3) & (nrxd-1)]); prefetch(fl->ifl_sds.ifsd_cl[(cidx + 4) & (nrxd-1)]); } static void rxd_frag_to_sd(iflib_rxq_t rxq, if_rxd_frag_t irf, int *cltype, int unload, iflib_fl_t *pfl, int *pcidx) { int flid, cidx; bus_dmamap_t map; iflib_fl_t fl; iflib_dma_info_t di; int next; flid = irf->irf_flid; cidx = irf->irf_idx; fl = &rxq->ifr_fl[flid]; fl->ifl_credits--; #if MEMORY_LOGGING fl->ifl_m_dequeued++; if (cltype) fl->ifl_cl_dequeued++; #endif prefetch_pkts(fl, cidx); if (fl->ifl_sds.ifsd_map != NULL) { next = (cidx + CACHE_PTR_INCREMENT) & (fl->ifl_size-1); prefetch(&fl->ifl_sds.ifsd_map[next]); map = fl->ifl_sds.ifsd_map[cidx]; di = fl->ifl_ifdi; next = (cidx + CACHE_LINE_SIZE) & (fl->ifl_size-1); prefetch(&fl->ifl_sds.ifsd_flags[next]); bus_dmamap_sync(di->idi_tag, di->idi_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); /* not valid assert if bxe really does SGE from non-contiguous elements */ MPASS(fl->ifl_cidx == cidx); if (unload) bus_dmamap_unload(fl->ifl_desc_tag, map); } if (__predict_false(++fl->ifl_cidx == fl->ifl_size)) { fl->ifl_cidx = 0; fl->ifl_gen = 0; } /* YES ick */ if (cltype) *cltype = fl->ifl_cltype; *pfl = fl; *pcidx = cidx; } static struct mbuf * assemble_segments(iflib_rxq_t rxq, if_rxd_info_t ri) { int i, padlen , flags, cltype; struct mbuf *m, *mh, *mt, *sd_m; iflib_fl_t fl; int cidx; caddr_t cl, sd_cl; i = 0; mh = NULL; do { rxd_frag_to_sd(rxq, &ri->iri_frags[i], &cltype, TRUE, &fl, &cidx); sd_m = fl->ifl_sds.ifsd_m[cidx]; sd_cl = fl->ifl_sds.ifsd_cl[cidx]; MPASS(sd_cl != NULL); MPASS(sd_m != NULL); /* Don't include zero-length frags */ if (ri->iri_frags[i].irf_len == 0) { /* XXX we can save the cluster here, but not the mbuf */ m_init(sd_m, M_NOWAIT, MT_DATA, 0); m_free(sd_m); fl->ifl_sds.ifsd_m[cidx] = NULL; continue; } m = sd_m; if (mh == NULL) { flags = M_PKTHDR|M_EXT; mh = mt = m; padlen = ri->iri_pad; } else { flags = M_EXT; mt->m_next = m; mt = m; /* assuming padding is only on the first fragment */ padlen = 0; } fl->ifl_sds.ifsd_m[cidx] = NULL; cl = fl->ifl_sds.ifsd_cl[cidx]; fl->ifl_sds.ifsd_cl[cidx] = NULL; /* Can these two be made one ? */ m_init(m, M_NOWAIT, MT_DATA, flags); m_cljset(m, cl, cltype); /* * These must follow m_init and m_cljset */ m->m_data += padlen; ri->iri_len -= padlen; m->m_len = ri->iri_frags[i].irf_len; } while (++i < ri->iri_nfrags); return (mh); } /* * Process one software descriptor */ static struct mbuf * iflib_rxd_pkt_get(iflib_rxq_t rxq, if_rxd_info_t ri) { struct mbuf *m; iflib_fl_t fl; caddr_t sd_cl; int cidx; /* should I merge this back in now that the two paths are basically duplicated? */ if (ri->iri_nfrags == 1 && ri->iri_frags[0].irf_len <= IFLIB_RX_COPY_THRESH) { rxd_frag_to_sd(rxq, &ri->iri_frags[0], NULL, FALSE, &fl, &cidx); m = fl->ifl_sds.ifsd_m[cidx]; fl->ifl_sds.ifsd_m[cidx] = NULL; sd_cl = fl->ifl_sds.ifsd_cl[cidx]; m_init(m, M_NOWAIT, MT_DATA, M_PKTHDR); memcpy(m->m_data, sd_cl, ri->iri_len); m->m_len = ri->iri_frags[0].irf_len; } else { m = assemble_segments(rxq, ri); } m->m_pkthdr.len = ri->iri_len; m->m_pkthdr.rcvif = ri->iri_ifp; m->m_flags |= ri->iri_flags; m->m_pkthdr.ether_vtag = ri->iri_vtag; m->m_pkthdr.flowid = ri->iri_flowid; M_HASHTYPE_SET(m, ri->iri_rsstype); m->m_pkthdr.csum_flags = ri->iri_csum_flags; m->m_pkthdr.csum_data = ri->iri_csum_data; return (m); } static bool iflib_rxeof(iflib_rxq_t rxq, int budget) { if_ctx_t ctx = rxq->ifr_ctx; if_shared_ctx_t sctx = ctx->ifc_sctx; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; int avail, i; uint16_t *cidxp; struct if_rxd_info ri; int err, budget_left, rx_bytes, rx_pkts; iflib_fl_t fl; struct ifnet *ifp; int lro_enabled; /* * XXX early demux data packets so that if_input processing only handles * acks in interrupt context */ struct mbuf *m, *mh, *mt; if (netmap_rx_irq(ctx->ifc_ifp, rxq->ifr_id, &budget)) { return (FALSE); } mh = mt = NULL; MPASS(budget > 0); rx_pkts = rx_bytes = 0; if (sctx->isc_flags & IFLIB_HAS_RXCQ) cidxp = &rxq->ifr_cq_cidx; else cidxp = &rxq->ifr_fl[0].ifl_cidx; if ((avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget)) == 0) { for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++) __iflib_fl_refill_lt(ctx, fl, budget + 8); DBG_COUNTER_INC(rx_unavail); return (false); } for (budget_left = budget; (budget_left > 0) && (avail > 0); budget_left--, avail--) { if (__predict_false(!CTX_ACTIVE(ctx))) { DBG_COUNTER_INC(rx_ctx_inactive); break; } /* * Reset client set fields to their default values */ bzero(&ri, sizeof(ri)); ri.iri_qsidx = rxq->ifr_id; ri.iri_cidx = *cidxp; ri.iri_ifp = ctx->ifc_ifp; ri.iri_frags = rxq->ifr_frags; err = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri); /* in lieu of handling correctly - make sure it isn't being unhandled */ MPASS(err == 0); if (sctx->isc_flags & IFLIB_HAS_RXCQ) { *cidxp = ri.iri_cidx; /* Update our consumer index */ while (rxq->ifr_cq_cidx >= scctx->isc_nrxd[0]) { rxq->ifr_cq_cidx -= scctx->isc_nrxd[0]; rxq->ifr_cq_gen = 0; } /* was this only a completion queue message? */ if (__predict_false(ri.iri_nfrags == 0)) continue; } MPASS(ri.iri_nfrags != 0); MPASS(ri.iri_len != 0); /* will advance the cidx on the corresponding free lists */ m = iflib_rxd_pkt_get(rxq, &ri); if (avail == 0 && budget_left) avail = iflib_rxd_avail(ctx, rxq, *cidxp, budget_left); if (__predict_false(m == NULL)) { DBG_COUNTER_INC(rx_mbuf_null); continue; } /* imm_pkt: -- cxgb */ if (mh == NULL) mh = mt = m; else { mt->m_nextpkt = m; mt = m; } } /* make sure that we can refill faster than drain */ for (i = 0, fl = &rxq->ifr_fl[0]; i < sctx->isc_nfl; i++, fl++) __iflib_fl_refill_lt(ctx, fl, budget + 8); ifp = ctx->ifc_ifp; lro_enabled = (if_getcapenable(ifp) & IFCAP_LRO); while (mh != NULL) { m = mh; mh = mh->m_nextpkt; m->m_nextpkt = NULL; rx_bytes += m->m_pkthdr.len; rx_pkts++; #if defined(INET6) || defined(INET) if (lro_enabled && tcp_lro_rx(&rxq->ifr_lc, m, 0) == 0) continue; #endif DBG_COUNTER_INC(rx_if_input); ifp->if_input(ifp, m); } if_inc_counter(ifp, IFCOUNTER_IBYTES, rx_bytes); if_inc_counter(ifp, IFCOUNTER_IPACKETS, rx_pkts); /* * Flush any outstanding LRO work */ #if defined(INET6) || defined(INET) tcp_lro_flush_all(&rxq->ifr_lc); #endif if (avail) return true; return (iflib_rxd_avail(ctx, rxq, *cidxp, 1)); } #define M_CSUM_FLAGS(m) ((m)->m_pkthdr.csum_flags) #define M_HAS_VLANTAG(m) (m->m_flags & M_VLANTAG) #define TXQ_MAX_DB_DEFERRED(size) (size >> 5) #define TXQ_MAX_DB_CONSUMED(size) (size >> 4) static __inline void iflib_txd_db_check(if_ctx_t ctx, iflib_txq_t txq, int ring) { uint32_t dbval; if (ring || txq->ift_db_pending >= TXQ_MAX_DB_DEFERRED(txq->ift_size)) { /* the lock will only ever be contended in the !min_latency case */ if (!TXDB_TRYLOCK(txq)) return; dbval = txq->ift_npending ? txq->ift_npending : txq->ift_pidx; ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, dbval); txq->ift_db_pending = txq->ift_npending = 0; TXDB_UNLOCK(txq); } } static void iflib_txd_deferred_db_check(void * arg) { iflib_txq_t txq = arg; /* simple non-zero boolean so use bitwise OR */ if ((txq->ift_db_pending | txq->ift_npending) && txq->ift_db_pending >= txq->ift_db_pending_queued) iflib_txd_db_check(txq->ift_ctx, txq, TRUE); txq->ift_db_pending_queued = 0; if (ifmp_ring_is_stalled(txq->ift_br[0])) iflib_txq_check_drain(txq, 4); } #ifdef PKT_DEBUG static void print_pkt(if_pkt_info_t pi) { printf("pi len: %d qsidx: %d nsegs: %d ndescs: %d flags: %x pidx: %d\n", pi->ipi_len, pi->ipi_qsidx, pi->ipi_nsegs, pi->ipi_ndescs, pi->ipi_flags, pi->ipi_pidx); printf("pi new_pidx: %d csum_flags: %lx tso_segsz: %d mflags: %x vtag: %d\n", pi->ipi_new_pidx, pi->ipi_csum_flags, pi->ipi_tso_segsz, pi->ipi_mflags, pi->ipi_vtag); printf("pi etype: %d ehdrlen: %d ip_hlen: %d ipproto: %d\n", pi->ipi_etype, pi->ipi_ehdrlen, pi->ipi_ip_hlen, pi->ipi_ipproto); } #endif #define IS_TSO4(pi) ((pi)->ipi_csum_flags & CSUM_IP_TSO) #define IS_TSO6(pi) ((pi)->ipi_csum_flags & CSUM_IP6_TSO) static int iflib_parse_header(iflib_txq_t txq, if_pkt_info_t pi, struct mbuf **mp) { if_shared_ctx_t sctx = txq->ift_ctx->ifc_sctx; struct ether_vlan_header *eh; struct mbuf *m, *n; n = m = *mp; if ((sctx->isc_flags & IFLIB_NEED_SCRATCH) && M_WRITABLE(m) == 0) { if ((m = m_dup(m, M_NOWAIT)) == NULL) { return (ENOMEM); } else { m_freem(*mp); n = *mp = m; } } /* * Determine where frame payload starts. * Jump over vlan headers if already present, * helpful for QinQ too. */ if (__predict_false(m->m_len < sizeof(*eh))) { txq->ift_pullups++; if (__predict_false((m = m_pullup(m, sizeof(*eh))) == NULL)) return (ENOMEM); } eh = mtod(m, struct ether_vlan_header *); if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { pi->ipi_etype = ntohs(eh->evl_proto); pi->ipi_ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; } else { pi->ipi_etype = ntohs(eh->evl_encap_proto); pi->ipi_ehdrlen = ETHER_HDR_LEN; } switch (pi->ipi_etype) { #ifdef INET case ETHERTYPE_IP: { struct ip *ip = NULL; struct tcphdr *th = NULL; int minthlen; minthlen = min(m->m_pkthdr.len, pi->ipi_ehdrlen + sizeof(*ip) + sizeof(*th)); if (__predict_false(m->m_len < minthlen)) { /* * if this code bloat is causing too much of a hit * move it to a separate function and mark it noinline */ if (m->m_len == pi->ipi_ehdrlen) { n = m->m_next; MPASS(n); if (n->m_len >= sizeof(*ip)) { ip = (struct ip *)n->m_data; if (n->m_len >= (ip->ip_hl << 2) + sizeof(*th)) th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); } else { txq->ift_pullups++; if (__predict_false((m = m_pullup(m, minthlen)) == NULL)) return (ENOMEM); ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen); } } else { txq->ift_pullups++; if (__predict_false((m = m_pullup(m, minthlen)) == NULL)) return (ENOMEM); ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen); if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th)) th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); } } else { ip = (struct ip *)(m->m_data + pi->ipi_ehdrlen); if (m->m_len >= (ip->ip_hl << 2) + sizeof(*th)) th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); } pi->ipi_ip_hlen = ip->ip_hl << 2; pi->ipi_ipproto = ip->ip_p; pi->ipi_flags |= IPI_TX_IPV4; if (pi->ipi_csum_flags & CSUM_IP) ip->ip_sum = 0; if (pi->ipi_ipproto == IPPROTO_TCP) { if (__predict_false(th == NULL)) { txq->ift_pullups++; if (__predict_false((m = m_pullup(m, (ip->ip_hl << 2) + sizeof(*th))) == NULL)) return (ENOMEM); th = (struct tcphdr *)((caddr_t)ip + pi->ipi_ip_hlen); } pi->ipi_tcp_hflags = th->th_flags; pi->ipi_tcp_hlen = th->th_off << 2; pi->ipi_tcp_seq = th->th_seq; } if (IS_TSO4(pi)) { if (__predict_false(ip->ip_p != IPPROTO_TCP)) return (ENXIO); th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, htons(IPPROTO_TCP)); pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz; if (sctx->isc_flags & IFLIB_TSO_INIT_IP) { ip->ip_sum = 0; ip->ip_len = htons(pi->ipi_ip_hlen + pi->ipi_tcp_hlen + pi->ipi_tso_segsz); } } break; } #endif #ifdef INET6 case ETHERTYPE_IPV6: { struct ip6_hdr *ip6 = (struct ip6_hdr *)(m->m_data + pi->ipi_ehdrlen); struct tcphdr *th; pi->ipi_ip_hlen = sizeof(struct ip6_hdr); if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) { if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) == NULL)) return (ENOMEM); } th = (struct tcphdr *)((caddr_t)ip6 + pi->ipi_ip_hlen); /* XXX-BZ this will go badly in case of ext hdrs. */ pi->ipi_ipproto = ip6->ip6_nxt; pi->ipi_flags |= IPI_TX_IPV6; if (pi->ipi_ipproto == IPPROTO_TCP) { if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) { if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) == NULL)) return (ENOMEM); } pi->ipi_tcp_hflags = th->th_flags; pi->ipi_tcp_hlen = th->th_off << 2; } if (IS_TSO6(pi)) { if (__predict_false(ip6->ip6_nxt != IPPROTO_TCP)) return (ENXIO); /* * The corresponding flag is set by the stack in the IPv4 * TSO case, but not in IPv6 (at least in FreeBSD 10.2). * So, set it here because the rest of the flow requires it. */ pi->ipi_csum_flags |= CSUM_TCP_IPV6; th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz; } break; } #endif default: pi->ipi_csum_flags &= ~CSUM_OFFLOAD; pi->ipi_ip_hlen = 0; break; } *mp = m; return (0); } static __noinline struct mbuf * collapse_pkthdr(struct mbuf *m0) { struct mbuf *m, *m_next, *tmp; m = m0; m_next = m->m_next; while (m_next != NULL && m_next->m_len == 0) { m = m_next; m->m_next = NULL; m_free(m); m_next = m_next->m_next; } m = m0; m->m_next = m_next; if ((m_next->m_flags & M_EXT) == 0) { m = m_defrag(m, M_NOWAIT); } else { tmp = m_next->m_next; memcpy(m_next, m, MPKTHSIZE); m = m_next; m->m_next = tmp; } return (m); } /* * If dodgy hardware rejects the scatter gather chain we've handed it * we'll need to remove the mbuf chain from ifsg_m[] before we can add the * m_defrag'd mbufs */ static __noinline struct mbuf * iflib_remove_mbuf(iflib_txq_t txq) { int ntxd, i, pidx; struct mbuf *m, *mh, **ifsd_m; pidx = txq->ift_pidx; ifsd_m = txq->ift_sds.ifsd_m; ntxd = txq->ift_size; mh = m = ifsd_m[pidx]; ifsd_m[pidx] = NULL; #if MEMORY_LOGGING txq->ift_dequeued++; #endif i = 1; while (m) { ifsd_m[(pidx + i) & (ntxd -1)] = NULL; #if MEMORY_LOGGING txq->ift_dequeued++; #endif m = m->m_next; i++; } return (mh); } static int iflib_busdma_load_mbuf_sg(iflib_txq_t txq, bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **m0, bus_dma_segment_t *segs, int *nsegs, int max_segs, int flags) { if_ctx_t ctx; if_shared_ctx_t sctx; if_softc_ctx_t scctx; int i, next, pidx, mask, err, maxsegsz, ntxd, count; struct mbuf *m, *tmp, **ifsd_m, **mp; m = *m0; /* * Please don't ever do this */ if (__predict_false(m->m_len == 0)) *m0 = m = collapse_pkthdr(m); ctx = txq->ift_ctx; sctx = ctx->ifc_sctx; scctx = &ctx->ifc_softc_ctx; ifsd_m = txq->ift_sds.ifsd_m; ntxd = txq->ift_size; pidx = txq->ift_pidx; if (map != NULL) { uint8_t *ifsd_flags = txq->ift_sds.ifsd_flags; err = bus_dmamap_load_mbuf_sg(tag, map, *m0, segs, nsegs, BUS_DMA_NOWAIT); if (err) return (err); ifsd_flags[pidx] |= TX_SW_DESC_MAPPED; i = 0; next = pidx; mask = (txq->ift_size-1); m = *m0; do { mp = &ifsd_m[next]; *mp = m; m = m->m_next; if (__predict_false((*mp)->m_len == 0)) { m_free(*mp); *mp = NULL; } else next = (pidx + i) & (ntxd-1); } while (m != NULL); } else { int buflen, sgsize, max_sgsize; vm_offset_t vaddr; vm_paddr_t curaddr; count = i = 0; maxsegsz = sctx->isc_tx_maxsize; m = *m0; do { if (__predict_false(m->m_len <= 0)) { tmp = m; m = m->m_next; tmp->m_next = NULL; m_free(tmp); continue; } buflen = m->m_len; vaddr = (vm_offset_t)m->m_data; /* * see if we can't be smarter about physically * contiguous mappings */ next = (pidx + count) & (ntxd-1); MPASS(ifsd_m[next] == NULL); #if MEMORY_LOGGING txq->ift_enqueued++; #endif ifsd_m[next] = m; while (buflen > 0) { max_sgsize = MIN(buflen, maxsegsz); curaddr = pmap_kextract(vaddr); sgsize = PAGE_SIZE - (curaddr & PAGE_MASK); sgsize = MIN(sgsize, max_sgsize); segs[i].ds_addr = curaddr; segs[i].ds_len = sgsize; vaddr += sgsize; buflen -= sgsize; i++; if (i >= max_segs) goto err; } count++; tmp = m; m = m->m_next; } while (m != NULL); *nsegs = i; } return (0); err: *m0 = iflib_remove_mbuf(txq); return (EFBIG); } static int iflib_encap(iflib_txq_t txq, struct mbuf **m_headp) { if_ctx_t ctx; if_shared_ctx_t sctx; if_softc_ctx_t scctx; bus_dma_segment_t *segs; struct mbuf *m_head; bus_dmamap_t map; struct if_pkt_info pi; int remap = 0; int err, nsegs, ndesc, max_segs, pidx, cidx, next, ntxd; bus_dma_tag_t desc_tag; segs = txq->ift_segs; ctx = txq->ift_ctx; sctx = ctx->ifc_sctx; scctx = &ctx->ifc_softc_ctx; segs = txq->ift_segs; ntxd = txq->ift_size; m_head = *m_headp; map = NULL; /* * If we're doing TSO the next descriptor to clean may be quite far ahead */ cidx = txq->ift_cidx; pidx = txq->ift_pidx; next = (cidx + CACHE_PTR_INCREMENT) & (ntxd-1); /* prefetch the next cache line of mbuf pointers and flags */ prefetch(&txq->ift_sds.ifsd_m[next]); if (txq->ift_sds.ifsd_map != NULL) { prefetch(&txq->ift_sds.ifsd_map[next]); map = txq->ift_sds.ifsd_map[pidx]; next = (cidx + CACHE_LINE_SIZE) & (ntxd-1); prefetch(&txq->ift_sds.ifsd_flags[next]); } if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { desc_tag = txq->ift_tso_desc_tag; max_segs = scctx->isc_tx_tso_segments_max; } else { desc_tag = txq->ift_desc_tag; max_segs = scctx->isc_tx_nsegments; } m_head = *m_headp; bzero(&pi, sizeof(pi)); pi.ipi_len = m_head->m_pkthdr.len; pi.ipi_mflags = (m_head->m_flags & (M_VLANTAG|M_BCAST|M_MCAST)); pi.ipi_csum_flags = m_head->m_pkthdr.csum_flags; pi.ipi_vtag = (m_head->m_flags & M_VLANTAG) ? m_head->m_pkthdr.ether_vtag : 0; pi.ipi_pidx = pidx; pi.ipi_qsidx = txq->ift_id; /* deliberate bitwise OR to make one condition */ if (__predict_true((pi.ipi_csum_flags | pi.ipi_vtag))) { if (__predict_false((err = iflib_parse_header(txq, &pi, m_headp)) != 0)) return (err); m_head = *m_headp; } retry: err = iflib_busdma_load_mbuf_sg(txq, desc_tag, map, m_headp, segs, &nsegs, max_segs, BUS_DMA_NOWAIT); defrag: if (__predict_false(err)) { switch (err) { case EFBIG: /* try collapse once and defrag once */ if (remap == 0) m_head = m_collapse(*m_headp, M_NOWAIT, max_segs); if (remap == 1) m_head = m_defrag(*m_headp, M_NOWAIT); remap++; if (__predict_false(m_head == NULL)) goto defrag_failed; txq->ift_mbuf_defrag++; *m_headp = m_head; goto retry; break; case ENOMEM: txq->ift_no_tx_dma_setup++; break; default: txq->ift_no_tx_dma_setup++; m_freem(*m_headp); DBG_COUNTER_INC(tx_frees); *m_headp = NULL; break; } txq->ift_map_failed++; DBG_COUNTER_INC(encap_load_mbuf_fail); return (err); } /* * XXX assumes a 1 to 1 relationship between segments and * descriptors - this does not hold true on all drivers, e.g. * cxgb */ if (__predict_false(nsegs + 2 > TXQ_AVAIL(txq))) { txq->ift_no_desc_avail++; if (map != NULL) bus_dmamap_unload(desc_tag, map); DBG_COUNTER_INC(encap_txq_avail_fail); if ((txq->ift_task.gt_task.ta_flags & TASK_ENQUEUED) == 0) GROUPTASK_ENQUEUE(&txq->ift_task); return (ENOBUFS); } pi.ipi_segs = segs; pi.ipi_nsegs = nsegs; MPASS(pidx >= 0 && pidx < txq->ift_size); #ifdef PKT_DEBUG print_pkt(&pi); #endif if ((err = ctx->isc_txd_encap(ctx->ifc_softc, &pi)) == 0) { bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); DBG_COUNTER_INC(tx_encap); MPASS(pi.ipi_new_pidx >= 0 && pi.ipi_new_pidx < txq->ift_size); ndesc = pi.ipi_new_pidx - pi.ipi_pidx; if (pi.ipi_new_pidx < pi.ipi_pidx) { ndesc += txq->ift_size; txq->ift_gen = 1; } /* * drivers can need as many as * two sentinels */ MPASS(ndesc <= pi.ipi_nsegs + 2); MPASS(pi.ipi_new_pidx != pidx); MPASS(ndesc > 0); txq->ift_in_use += ndesc; /* * We update the last software descriptor again here because there may * be a sentinel and/or there may be more mbufs than segments */ txq->ift_pidx = pi.ipi_new_pidx; txq->ift_npending += pi.ipi_ndescs; } else if (__predict_false(err == EFBIG && remap < 2)) { *m_headp = m_head = iflib_remove_mbuf(txq); remap = 1; txq->ift_txd_encap_efbig++; goto defrag; } else DBG_COUNTER_INC(encap_txd_encap_fail); return (err); defrag_failed: txq->ift_mbuf_defrag_failed++; txq->ift_map_failed++; m_freem(*m_headp); DBG_COUNTER_INC(tx_frees); *m_headp = NULL; return (ENOMEM); } /* forward compatibility for cxgb */ #define FIRST_QSET(ctx) 0 #define NTXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_ntxqsets) #define NRXQSETS(ctx) ((ctx)->ifc_softc_ctx.isc_nrxqsets) #define QIDX(ctx, m) ((((m)->m_pkthdr.flowid & ctx->ifc_softc_ctx.isc_rss_table_mask) % NTXQSETS(ctx)) + FIRST_QSET(ctx)) #define DESC_RECLAIMABLE(q) ((int)((q)->ift_processed - (q)->ift_cleaned - (q)->ift_ctx->ifc_softc_ctx.isc_tx_nsegments)) #define RECLAIM_THRESH(ctx) ((ctx)->ifc_sctx->isc_tx_reclaim_thresh) #define MAX_TX_DESC(ctx) ((ctx)->ifc_softc_ctx.isc_tx_tso_segments_max) /* if there are more than TXQ_MIN_OCCUPANCY packets pending we consider deferring * doorbell writes * * ORing with 2 assures that min occupancy is never less than 2 without any conditional logic */ #define TXQ_MIN_OCCUPANCY(size) ((size >> 6)| 0x2) static inline int iflib_txq_min_occupancy(iflib_txq_t txq) { if_ctx_t ctx; ctx = txq->ift_ctx; return (get_inuse(txq->ift_size, txq->ift_cidx, txq->ift_pidx, txq->ift_gen) < TXQ_MIN_OCCUPANCY(txq->ift_size) + MAX_TX_DESC(ctx)); } static void iflib_tx_desc_free(iflib_txq_t txq, int n) { int hasmap; uint32_t qsize, cidx, mask, gen; struct mbuf *m, **ifsd_m; uint8_t *ifsd_flags; bus_dmamap_t *ifsd_map; cidx = txq->ift_cidx; gen = txq->ift_gen; qsize = txq->ift_size; mask = qsize-1; hasmap = txq->ift_sds.ifsd_map != NULL; ifsd_flags = txq->ift_sds.ifsd_flags; ifsd_m = txq->ift_sds.ifsd_m; ifsd_map = txq->ift_sds.ifsd_map; while (n--) { prefetch(ifsd_m[(cidx + 3) & mask]); prefetch(ifsd_m[(cidx + 4) & mask]); if (ifsd_m[cidx] != NULL) { prefetch(&ifsd_m[(cidx + CACHE_PTR_INCREMENT) & mask]); prefetch(&ifsd_flags[(cidx + CACHE_PTR_INCREMENT) & mask]); if (hasmap && (ifsd_flags[cidx] & TX_SW_DESC_MAPPED)) { /* * does it matter if it's not the TSO tag? If so we'll * have to add the type to flags */ bus_dmamap_unload(txq->ift_desc_tag, ifsd_map[cidx]); ifsd_flags[cidx] &= ~TX_SW_DESC_MAPPED; } if ((m = ifsd_m[cidx]) != NULL) { /* XXX we don't support any drivers that batch packets yet */ MPASS(m->m_nextpkt == NULL); m_free(m); ifsd_m[cidx] = NULL; #if MEMORY_LOGGING txq->ift_dequeued++; #endif DBG_COUNTER_INC(tx_frees); } } if (__predict_false(++cidx == qsize)) { cidx = 0; gen = 0; } } txq->ift_cidx = cidx; txq->ift_gen = gen; } static __inline int iflib_completed_tx_reclaim(iflib_txq_t txq, int thresh) { int reclaim; if_ctx_t ctx = txq->ift_ctx; KASSERT(thresh >= 0, ("invalid threshold to reclaim")); MPASS(thresh /*+ MAX_TX_DESC(txq->ift_ctx) */ < txq->ift_size); /* * Need a rate-limiting check so that this isn't called every time */ iflib_tx_credits_update(ctx, txq); reclaim = DESC_RECLAIMABLE(txq); if (reclaim <= thresh /* + MAX_TX_DESC(txq->ift_ctx) */) { #ifdef INVARIANTS if (iflib_verbose_debug) { printf("%s processed=%ju cleaned=%ju tx_nsegments=%d reclaim=%d thresh=%d\n", __FUNCTION__, txq->ift_processed, txq->ift_cleaned, txq->ift_ctx->ifc_softc_ctx.isc_tx_nsegments, reclaim, thresh); } #endif return (0); } iflib_tx_desc_free(txq, reclaim); txq->ift_cleaned += reclaim; txq->ift_in_use -= reclaim; if (txq->ift_active == FALSE) txq->ift_active = TRUE; return (reclaim); } static struct mbuf ** _ring_peek_one(struct ifmp_ring *r, int cidx, int offset) { return (__DEVOLATILE(struct mbuf **, &r->items[(cidx + offset) & (r->size-1)])); } static void iflib_txq_check_drain(iflib_txq_t txq, int budget) { ifmp_ring_check_drainage(txq->ift_br[0], budget); } static uint32_t iflib_txq_can_drain(struct ifmp_ring *r) { iflib_txq_t txq = r->cookie; if_ctx_t ctx = txq->ift_ctx; return ((TXQ_AVAIL(txq) > MAX_TX_DESC(ctx) + 2) || ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, txq->ift_cidx_processed, false)); } static uint32_t iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) { iflib_txq_t txq = r->cookie; if_ctx_t ctx = txq->ift_ctx; if_t ifp = ctx->ifc_ifp; struct mbuf **mp, *m; int i, count, consumed, pkt_sent, bytes_sent, mcast_sent, avail, err, in_use_prev, desc_used; if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) || !LINK_ACTIVE(ctx))) { DBG_COUNTER_INC(txq_drain_notready); return (0); } avail = IDXDIFF(pidx, cidx, r->size); if (__predict_false(ctx->ifc_flags & IFC_QFLUSH)) { DBG_COUNTER_INC(txq_drain_flushing); for (i = 0; i < avail; i++) { m_free(r->items[(cidx + i) & (r->size-1)]); r->items[(cidx + i) & (r->size-1)] = NULL; } return (avail); } iflib_completed_tx_reclaim(txq, RECLAIM_THRESH(ctx)); if (__predict_false(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE)) { txq->ift_qstatus = IFLIB_QUEUE_IDLE; CALLOUT_LOCK(txq); callout_stop(&txq->ift_timer); callout_stop(&txq->ift_db_check); CALLOUT_UNLOCK(txq); DBG_COUNTER_INC(txq_drain_oactive); return (0); } consumed = mcast_sent = bytes_sent = pkt_sent = 0; count = MIN(avail, TX_BATCH_SIZE); #ifdef INVARIANTS if (iflib_verbose_debug) printf("%s avail=%d ifc_flags=%x txq_avail=%d ", __FUNCTION__, avail, ctx->ifc_flags, TXQ_AVAIL(txq)); #endif for (desc_used = i = 0; i < count && TXQ_AVAIL(txq) > MAX_TX_DESC(ctx) + 2; i++) { mp = _ring_peek_one(r, cidx, i); MPASS(mp != NULL && *mp != NULL); in_use_prev = txq->ift_in_use; if ((err = iflib_encap(txq, mp)) == ENOBUFS) { DBG_COUNTER_INC(txq_drain_encapfail); /* no room - bail out */ break; } consumed++; if (err) { DBG_COUNTER_INC(txq_drain_encapfail); /* we can't send this packet - skip it */ continue; } pkt_sent++; m = *mp; DBG_COUNTER_INC(tx_sent); bytes_sent += m->m_pkthdr.len; if (m->m_flags & M_MCAST) mcast_sent++; txq->ift_db_pending += (txq->ift_in_use - in_use_prev); desc_used += (txq->ift_in_use - in_use_prev); iflib_txd_db_check(ctx, txq, FALSE); ETHER_BPF_MTAP(ifp, m); if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))) break; if (desc_used >= TXQ_MAX_DB_CONSUMED(txq->ift_size)) break; } if ((iflib_min_tx_latency || iflib_txq_min_occupancy(txq)) && txq->ift_db_pending) iflib_txd_db_check(ctx, txq, TRUE); else if ((txq->ift_db_pending || TXQ_AVAIL(txq) <= MAX_TX_DESC(ctx) + 2) && (callout_pending(&txq->ift_db_check) == 0)) { txq->ift_db_pending_queued = txq->ift_db_pending; callout_reset_on(&txq->ift_db_check, 1, iflib_txd_deferred_db_check, txq, txq->ift_db_check.c_cpu); } if_inc_counter(ifp, IFCOUNTER_OBYTES, bytes_sent); if_inc_counter(ifp, IFCOUNTER_OPACKETS, pkt_sent); if (mcast_sent) if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast_sent); #ifdef INVARIANTS if (iflib_verbose_debug) printf("consumed=%d\n", consumed); #endif return (consumed); } static uint32_t iflib_txq_drain_always(struct ifmp_ring *r) { return (1); } static uint32_t iflib_txq_drain_free(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) { int i, avail; struct mbuf **mp; iflib_txq_t txq; txq = r->cookie; txq->ift_qstatus = IFLIB_QUEUE_IDLE; CALLOUT_LOCK(txq); callout_stop(&txq->ift_timer); callout_stop(&txq->ift_db_check); CALLOUT_UNLOCK(txq); avail = IDXDIFF(pidx, cidx, r->size); for (i = 0; i < avail; i++) { mp = _ring_peek_one(r, cidx, i); m_freem(*mp); } MPASS(ifmp_ring_is_stalled(r) == 0); return (avail); } static void iflib_ifmp_purge(iflib_txq_t txq) { struct ifmp_ring *r; r = txq->ift_br[0]; r->drain = iflib_txq_drain_free; r->can_drain = iflib_txq_drain_always; ifmp_ring_check_drainage(r, r->size); r->drain = iflib_txq_drain; r->can_drain = iflib_txq_can_drain; } static void _task_fn_tx(void *context) { iflib_txq_t txq = context; if_ctx_t ctx = txq->ift_ctx; #ifdef IFLIB_DIAGNOSTICS txq->ift_cpu_exec_count[curcpu]++; #endif if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) return; ifmp_ring_check_drainage(txq->ift_br[0], TX_BATCH_SIZE); } static void _task_fn_rx(void *context) { iflib_rxq_t rxq = context; if_ctx_t ctx = rxq->ifr_ctx; bool more; int rc; #ifdef IFLIB_DIAGNOSTICS rxq->ifr_cpu_exec_count[curcpu]++; #endif DBG_COUNTER_INC(task_fn_rxs); if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))) return; if ((more = iflib_rxeof(rxq, 16 /* XXX */)) == false) { if (ctx->ifc_flags & IFC_LEGACY) IFDI_INTR_ENABLE(ctx); else { DBG_COUNTER_INC(rx_intr_enables); rc = IFDI_QUEUE_INTR_ENABLE(ctx, rxq->ifr_id); KASSERT(rc != ENOTSUP, ("MSI-X support requires queue_intr_enable, but not implemented in driver")); } } if (__predict_false(!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))) return; if (more) GROUPTASK_ENQUEUE(&rxq->ifr_task); } static void _task_fn_admin(void *context) { if_ctx_t ctx = context; if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; iflib_txq_t txq; int i; if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) return; CTX_LOCK(ctx); for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) { CALLOUT_LOCK(txq); callout_stop(&txq->ift_timer); CALLOUT_UNLOCK(txq); } IFDI_UPDATE_ADMIN_STATUS(ctx); for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, txq->ift_timer.c_cpu); IFDI_LINK_INTR_ENABLE(ctx); CTX_UNLOCK(ctx); if (LINK_ACTIVE(ctx) == 0) return; for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET); } static void _task_fn_iov(void *context) { if_ctx_t ctx = context; if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) return; CTX_LOCK(ctx); IFDI_VFLR_HANDLE(ctx); CTX_UNLOCK(ctx); } static int iflib_sysctl_int_delay(SYSCTL_HANDLER_ARGS) { int err; if_int_delay_info_t info; if_ctx_t ctx; info = (if_int_delay_info_t)arg1; ctx = info->iidi_ctx; info->iidi_req = req; info->iidi_oidp = oidp; CTX_LOCK(ctx); err = IFDI_SYSCTL_INT_DELAY(ctx, info); CTX_UNLOCK(ctx); return (err); } /********************************************************************* * * IFNET FUNCTIONS * **********************************************************************/ static void iflib_if_init_locked(if_ctx_t ctx) { iflib_stop(ctx); iflib_init_locked(ctx); } static void iflib_if_init(void *arg) { if_ctx_t ctx = arg; CTX_LOCK(ctx); iflib_if_init_locked(ctx); CTX_UNLOCK(ctx); } static int iflib_if_transmit(if_t ifp, struct mbuf *m) { if_ctx_t ctx = if_getsoftc(ifp); iflib_txq_t txq; int err, qidx; if (__predict_false((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || !LINK_ACTIVE(ctx))) { DBG_COUNTER_INC(tx_frees); m_freem(m); return (ENOBUFS); } MPASS(m->m_nextpkt == NULL); qidx = 0; if ((NTXQSETS(ctx) > 1) && M_HASHTYPE_GET(m)) qidx = QIDX(ctx, m); /* * XXX calculate buf_ring based on flowid (divvy up bits?) */ txq = &ctx->ifc_txqs[qidx]; #ifdef DRIVER_BACKPRESSURE if (txq->ift_closed) { while (m != NULL) { next = m->m_nextpkt; m->m_nextpkt = NULL; m_freem(m); m = next; } return (ENOBUFS); } #endif #ifdef notyet qidx = count = 0; mp = marr; next = m; do { count++; next = next->m_nextpkt; } while (next != NULL); if (count > nitems(marr)) if ((mp = malloc(count*sizeof(struct mbuf *), M_IFLIB, M_NOWAIT)) == NULL) { /* XXX check nextpkt */ m_freem(m); /* XXX simplify for now */ DBG_COUNTER_INC(tx_frees); return (ENOBUFS); } for (next = m, i = 0; next != NULL; i++) { mp[i] = next; next = next->m_nextpkt; mp[i]->m_nextpkt = NULL; } #endif DBG_COUNTER_INC(tx_seen); err = ifmp_ring_enqueue(txq->ift_br[0], (void **)&m, 1, TX_BATCH_SIZE); if (err) { GROUPTASK_ENQUEUE(&txq->ift_task); /* support forthcoming later */ #ifdef DRIVER_BACKPRESSURE txq->ift_closed = TRUE; #endif ifmp_ring_check_drainage(txq->ift_br[0], TX_BATCH_SIZE); m_freem(m); } else if (TXQ_AVAIL(txq) < (txq->ift_size >> 1)) { GROUPTASK_ENQUEUE(&txq->ift_task); } return (err); } static void iflib_if_qflush(if_t ifp) { if_ctx_t ctx = if_getsoftc(ifp); iflib_txq_t txq = ctx->ifc_txqs; int i; CTX_LOCK(ctx); ctx->ifc_flags |= IFC_QFLUSH; CTX_UNLOCK(ctx); for (i = 0; i < NTXQSETS(ctx); i++, txq++) while (!(ifmp_ring_is_idle(txq->ift_br[0]) || ifmp_ring_is_stalled(txq->ift_br[0]))) iflib_txq_check_drain(txq, 0); CTX_LOCK(ctx); ctx->ifc_flags &= ~IFC_QFLUSH; CTX_UNLOCK(ctx); if_qflush(ifp); } #define IFCAP_FLAGS (IFCAP_TXCSUM_IPV6 | IFCAP_RXCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \ IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTAGGING | \ IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | IFCAP_VLAN_HWTSO) static int iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) { if_ctx_t ctx = if_getsoftc(ifp); struct ifreq *ifr = (struct ifreq *)data; #if defined(INET) || defined(INET6) struct ifaddr *ifa = (struct ifaddr *)data; #endif bool avoid_reset = FALSE; int err = 0, reinit = 0, bits; switch (command) { case SIOCSIFADDR: #ifdef INET if (ifa->ifa_addr->sa_family == AF_INET) avoid_reset = TRUE; #endif #ifdef INET6 if (ifa->ifa_addr->sa_family == AF_INET6) avoid_reset = TRUE; #endif /* ** Calling init results in link renegotiation, ** so we avoid doing it when possible. */ if (avoid_reset) { if_setflagbits(ifp, IFF_UP,0); if (!(if_getdrvflags(ifp)& IFF_DRV_RUNNING)) reinit = 1; #ifdef INET if (!(if_getflags(ifp) & IFF_NOARP)) arp_ifinit(ifp, ifa); #endif } else err = ether_ioctl(ifp, command, data); break; case SIOCSIFMTU: CTX_LOCK(ctx); if (ifr->ifr_mtu == if_getmtu(ifp)) { CTX_UNLOCK(ctx); break; } bits = if_getdrvflags(ifp); /* stop the driver and free any clusters before proceeding */ iflib_stop(ctx); if ((err = IFDI_MTU_SET(ctx, ifr->ifr_mtu)) == 0) { if (ifr->ifr_mtu > ctx->ifc_max_fl_buf_size) ctx->ifc_flags |= IFC_MULTISEG; else ctx->ifc_flags &= ~IFC_MULTISEG; err = if_setmtu(ifp, ifr->ifr_mtu); } iflib_init_locked(ctx); if_setdrvflags(ifp, bits); CTX_UNLOCK(ctx); break; case SIOCSIFFLAGS: CTX_LOCK(ctx); if (if_getflags(ifp) & IFF_UP) { if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { if ((if_getflags(ifp) ^ ctx->ifc_if_flags) & (IFF_PROMISC | IFF_ALLMULTI)) { err = IFDI_PROMISC_SET(ctx, if_getflags(ifp)); } } else reinit = 1; } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { iflib_stop(ctx); } ctx->ifc_if_flags = if_getflags(ifp); CTX_UNLOCK(ctx); break; - - break; case SIOCADDMULTI: case SIOCDELMULTI: if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { CTX_LOCK(ctx); IFDI_INTR_DISABLE(ctx); IFDI_MULTI_SET(ctx); IFDI_INTR_ENABLE(ctx); CTX_UNLOCK(ctx); } break; case SIOCSIFMEDIA: CTX_LOCK(ctx); IFDI_MEDIA_SET(ctx); CTX_UNLOCK(ctx); /* falls thru */ case SIOCGIFMEDIA: err = ifmedia_ioctl(ifp, ifr, &ctx->ifc_media, command); break; case SIOCGI2C: { struct ifi2creq i2c; err = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); if (err != 0) break; if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { err = EINVAL; break; } if (i2c.len > sizeof(i2c.data)) { err = EINVAL; break; } if ((err = IFDI_I2C_REQ(ctx, &i2c)) == 0) err = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); break; } case SIOCSIFCAP: { int mask, setmask; mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); setmask = 0; #ifdef TCP_OFFLOAD setmask |= mask & (IFCAP_TOE4|IFCAP_TOE6); #endif setmask |= (mask & IFCAP_FLAGS); if (setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) setmask |= (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); if ((mask & IFCAP_WOL) && (if_getcapabilities(ifp) & IFCAP_WOL) != 0) setmask |= (mask & (IFCAP_WOL_MCAST|IFCAP_WOL_MAGIC)); if_vlancap(ifp); /* * want to ensure that traffic has stopped before we change any of the flags */ if (setmask) { CTX_LOCK(ctx); bits = if_getdrvflags(ifp); if (bits & IFF_DRV_RUNNING) iflib_stop(ctx); if_togglecapenable(ifp, setmask); if (bits & IFF_DRV_RUNNING) iflib_init_locked(ctx); if_setdrvflags(ifp, bits); CTX_UNLOCK(ctx); } break; } case SIOCGPRIVATE_0: case SIOCSDRVSPEC: case SIOCGDRVSPEC: CTX_LOCK(ctx); err = IFDI_PRIV_IOCTL(ctx, command, data); CTX_UNLOCK(ctx); break; default: err = ether_ioctl(ifp, command, data); break; } if (reinit) iflib_if_init(ctx); return (err); } static uint64_t iflib_if_get_counter(if_t ifp, ift_counter cnt) { if_ctx_t ctx = if_getsoftc(ifp); return (IFDI_GET_COUNTER(ctx, cnt)); } /********************************************************************* * * OTHER FUNCTIONS EXPORTED TO THE STACK * **********************************************************************/ static void iflib_vlan_register(void *arg, if_t ifp, uint16_t vtag) { if_ctx_t ctx = if_getsoftc(ifp); if ((void *)ctx != arg) return; if ((vtag == 0) || (vtag > 4095)) return; CTX_LOCK(ctx); IFDI_VLAN_REGISTER(ctx, vtag); /* Re-init to load the changes */ if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) iflib_init_locked(ctx); CTX_UNLOCK(ctx); } static void iflib_vlan_unregister(void *arg, if_t ifp, uint16_t vtag) { if_ctx_t ctx = if_getsoftc(ifp); if ((void *)ctx != arg) return; if ((vtag == 0) || (vtag > 4095)) return; CTX_LOCK(ctx); IFDI_VLAN_UNREGISTER(ctx, vtag); /* Re-init to load the changes */ if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) iflib_init_locked(ctx); CTX_UNLOCK(ctx); } static void iflib_led_func(void *arg, int onoff) { if_ctx_t ctx = arg; CTX_LOCK(ctx); IFDI_LED_FUNC(ctx, onoff); CTX_UNLOCK(ctx); } /********************************************************************* * * BUS FUNCTION DEFINITIONS * **********************************************************************/ int iflib_device_probe(device_t dev) { pci_vendor_info_t *ent; uint16_t pci_vendor_id, pci_device_id; uint16_t pci_subvendor_id, pci_subdevice_id; uint16_t pci_rev_id; if_shared_ctx_t sctx; if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC) return (ENOTSUP); pci_vendor_id = pci_get_vendor(dev); pci_device_id = pci_get_device(dev); pci_subvendor_id = pci_get_subvendor(dev); pci_subdevice_id = pci_get_subdevice(dev); pci_rev_id = pci_get_revid(dev); if (sctx->isc_parse_devinfo != NULL) sctx->isc_parse_devinfo(&pci_device_id, &pci_subvendor_id, &pci_subdevice_id, &pci_rev_id); ent = sctx->isc_vendor_info; while (ent->pvi_vendor_id != 0) { if (pci_vendor_id != ent->pvi_vendor_id) { ent++; continue; } if ((pci_device_id == ent->pvi_device_id) && ((pci_subvendor_id == ent->pvi_subvendor_id) || (ent->pvi_subvendor_id == 0)) && ((pci_subdevice_id == ent->pvi_subdevice_id) || (ent->pvi_subdevice_id == 0)) && ((pci_rev_id == ent->pvi_rev_id) || (ent->pvi_rev_id == 0))) { device_set_desc_copy(dev, ent->pvi_name); /* this needs to be changed to zero if the bus probing code * ever stops re-probing on best match because the sctx * may have its values over written by register calls * in subsequent probes */ return (BUS_PROBE_DEFAULT); } ent++; } return (ENXIO); } int iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ctxp) { int err, rid, msix, msix_bar; if_ctx_t ctx; if_t ifp; if_softc_ctx_t scctx; int i; uint16_t main_txq; uint16_t main_rxq; ctx = malloc(sizeof(* ctx), M_IFLIB, M_WAITOK|M_ZERO); if (sc == NULL) { sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK|M_ZERO); device_set_softc(dev, ctx); ctx->ifc_flags |= IFC_SC_ALLOCATED; } ctx->ifc_sctx = sctx; ctx->ifc_dev = dev; ctx->ifc_softc = sc; if ((err = iflib_register(ctx)) != 0) { device_printf(dev, "iflib_register failed %d\n", err); return (err); } iflib_add_device_sysctl_pre(ctx); scctx = &ctx->ifc_softc_ctx; ifp = ctx->ifc_ifp; /* * XXX sanity check that ntxd & nrxd are a power of 2 */ if (ctx->ifc_sysctl_ntxqs != 0) scctx->isc_ntxqsets = ctx->ifc_sysctl_ntxqs; if (ctx->ifc_sysctl_nrxqs != 0) scctx->isc_nrxqsets = ctx->ifc_sysctl_nrxqs; for (i = 0; i < sctx->isc_ntxqs; i++) { if (ctx->ifc_sysctl_ntxds[i] != 0) scctx->isc_ntxd[i] = ctx->ifc_sysctl_ntxds[i]; else scctx->isc_ntxd[i] = sctx->isc_ntxd_default[i]; } for (i = 0; i < sctx->isc_nrxqs; i++) { if (ctx->ifc_sysctl_nrxds[i] != 0) scctx->isc_nrxd[i] = ctx->ifc_sysctl_nrxds[i]; else scctx->isc_nrxd[i] = sctx->isc_nrxd_default[i]; } for (i = 0; i < sctx->isc_nrxqs; i++) { if (scctx->isc_nrxd[i] < sctx->isc_nrxd_min[i]) { device_printf(dev, "nrxd%d: %d less than nrxd_min %d - resetting to min\n", i, scctx->isc_nrxd[i], sctx->isc_nrxd_min[i]); scctx->isc_nrxd[i] = sctx->isc_nrxd_min[i]; } if (scctx->isc_nrxd[i] > sctx->isc_nrxd_max[i]) { device_printf(dev, "nrxd%d: %d greater than nrxd_max %d - resetting to max\n", i, scctx->isc_nrxd[i], sctx->isc_nrxd_max[i]); scctx->isc_nrxd[i] = sctx->isc_nrxd_max[i]; } } for (i = 0; i < sctx->isc_ntxqs; i++) { if (scctx->isc_ntxd[i] < sctx->isc_ntxd_min[i]) { device_printf(dev, "ntxd%d: %d less than ntxd_min %d - resetting to min\n", i, scctx->isc_ntxd[i], sctx->isc_ntxd_min[i]); scctx->isc_ntxd[i] = sctx->isc_ntxd_min[i]; } if (scctx->isc_ntxd[i] > sctx->isc_ntxd_max[i]) { device_printf(dev, "ntxd%d: %d greater than ntxd_max %d - resetting to max\n", i, scctx->isc_ntxd[i], sctx->isc_ntxd_max[i]); scctx->isc_ntxd[i] = sctx->isc_ntxd_max[i]; } } if ((err = IFDI_ATTACH_PRE(ctx)) != 0) { device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err); return (err); } _iflib_pre_assert(scctx); ctx->ifc_txrx = *scctx->isc_txrx; #ifdef INVARIANTS MPASS(scctx->isc_capenable); if (scctx->isc_capenable & IFCAP_TXCSUM) MPASS(scctx->isc_tx_csum_flags); #endif if_setcapabilities(ifp, scctx->isc_capenable); if_setcapenable(ifp, scctx->isc_capenable); if (scctx->isc_ntxqsets == 0 || (scctx->isc_ntxqsets_max && scctx->isc_ntxqsets_max < scctx->isc_ntxqsets)) scctx->isc_ntxqsets = scctx->isc_ntxqsets_max; if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets)) scctx->isc_nrxqsets = scctx->isc_nrxqsets_max; #ifdef ACPI_DMAR if (dmar_get_dma_tag(device_get_parent(dev), dev) != NULL) ctx->ifc_flags |= IFC_DMAR; #endif msix_bar = scctx->isc_msix_bar; if(sctx->isc_flags & IFLIB_HAS_TXCQ) main_txq = 1; else main_txq = 0; if(sctx->isc_flags & IFLIB_HAS_RXCQ) main_rxq = 1; else main_rxq = 0; /* XXX change for per-queue sizes */ device_printf(dev, "using %d tx descriptors and %d rx descriptors\n", scctx->isc_ntxd[main_txq], scctx->isc_nrxd[main_rxq]); for (i = 0; i < sctx->isc_nrxqs; i++) { if (!powerof2(scctx->isc_nrxd[i])) { /* round down instead? */ device_printf(dev, "# rx descriptors must be a power of 2\n"); err = EINVAL; goto fail; } } for (i = 0; i < sctx->isc_ntxqs; i++) { if (!powerof2(scctx->isc_ntxd[i])) { device_printf(dev, "# tx descriptors must be a power of 2"); err = EINVAL; goto fail; } } if (scctx->isc_tx_nsegments > scctx->isc_ntxd[main_txq] / MAX_SINGLE_PACKET_FRACTION) scctx->isc_tx_nsegments = max(1, scctx->isc_ntxd[main_txq] / MAX_SINGLE_PACKET_FRACTION); if (scctx->isc_tx_tso_segments_max > scctx->isc_ntxd[main_txq] / MAX_SINGLE_PACKET_FRACTION) scctx->isc_tx_tso_segments_max = max(1, scctx->isc_ntxd[main_txq] / MAX_SINGLE_PACKET_FRACTION); /* * Protect the stack against modern hardware */ if (scctx->isc_tx_tso_size_max > FREEBSD_TSO_SIZE_MAX) scctx->isc_tx_tso_size_max = FREEBSD_TSO_SIZE_MAX; /* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */ ifp->if_hw_tsomaxsegcount = scctx->isc_tx_tso_segments_max; ifp->if_hw_tsomax = scctx->isc_tx_tso_size_max; ifp->if_hw_tsomaxsegsize = scctx->isc_tx_tso_segsize_max; if (scctx->isc_rss_table_size == 0) scctx->isc_rss_table_size = 64; scctx->isc_rss_table_mask = scctx->isc_rss_table_size-1; GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx); /* XXX format name */ taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx, -1, "admin"); /* ** Now setup MSI or MSI/X, should ** return us the number of supported ** vectors. (Will be 1 for MSI) */ if (sctx->isc_flags & IFLIB_SKIP_MSIX) { msix = scctx->isc_vectors; } else if (scctx->isc_msix_bar != 0) /* * The simple fact that isc_msix_bar is not 0 does not mean we * we have a good value there that is known to work. */ msix = iflib_msix_init(ctx); else { scctx->isc_vectors = 1; scctx->isc_ntxqsets = 1; scctx->isc_nrxqsets = 1; scctx->isc_intr = IFLIB_INTR_LEGACY; msix = 0; } /* Get memory for the station queues */ if ((err = iflib_queues_alloc(ctx))) { device_printf(dev, "Unable to allocate queue memory\n"); goto fail; } if ((err = iflib_qset_structures_setup(ctx))) { device_printf(dev, "qset structure setup failed %d\n", err); goto fail_queues; } /* * Group taskqueues aren't properly set up until SMP is started, * so we disable interrupts until we can handle them post * SI_SUB_SMP. * * XXX: disabling interrupts doesn't actually work, at least for * the non-MSI case. When they occur before SI_SUB_SMP completes, * we do null handling and depend on this not causing too large an * interrupt storm. */ IFDI_INTR_DISABLE(ctx); if (msix > 1 && (err = IFDI_MSIX_INTR_ASSIGN(ctx, msix)) != 0) { device_printf(dev, "IFDI_MSIX_INTR_ASSIGN failed %d\n", err); goto fail_intr_free; } if (msix <= 1) { rid = 0; if (scctx->isc_intr == IFLIB_INTR_MSI) { MPASS(msix == 1); rid = 1; } if ((err = iflib_legacy_setup(ctx, ctx->isc_legacy_intr, ctx->ifc_softc, &rid, "irq0")) != 0) { device_printf(dev, "iflib_legacy_setup failed %d\n", err); goto fail_intr_free; } } ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac); if ((err = IFDI_ATTACH_POST(ctx)) != 0) { device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err); goto fail_detach; } if ((err = iflib_netmap_attach(ctx))) { device_printf(ctx->ifc_dev, "netmap attach failed: %d\n", err); goto fail_detach; } *ctxp = ctx; if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter); iflib_add_device_sysctl_post(ctx); ctx->ifc_flags |= IFC_INIT_DONE; return (0); fail_detach: ether_ifdetach(ctx->ifc_ifp); fail_intr_free: if (scctx->isc_intr == IFLIB_INTR_MSIX || scctx->isc_intr == IFLIB_INTR_MSI) pci_release_msi(ctx->ifc_dev); fail_queues: /* XXX free queues */ fail: IFDI_DETACH(ctx); return (err); } int iflib_device_attach(device_t dev) { if_ctx_t ctx; if_shared_ctx_t sctx; if ((sctx = DEVICE_REGISTER(dev)) == NULL || sctx->isc_magic != IFLIB_MAGIC) return (ENOTSUP); pci_enable_busmaster(dev); return (iflib_device_register(dev, NULL, sctx, &ctx)); } int iflib_device_deregister(if_ctx_t ctx) { if_t ifp = ctx->ifc_ifp; iflib_txq_t txq; iflib_rxq_t rxq; device_t dev = ctx->ifc_dev; int i; struct taskqgroup *tqg; /* Make sure VLANS are not using driver */ if (if_vlantrunkinuse(ifp)) { device_printf(dev,"Vlan in use, detach first\n"); return (EBUSY); } CTX_LOCK(ctx); ctx->ifc_in_detach = 1; iflib_stop(ctx); CTX_UNLOCK(ctx); /* Unregister VLAN events */ if (ctx->ifc_vlan_attach_event != NULL) EVENTHANDLER_DEREGISTER(vlan_config, ctx->ifc_vlan_attach_event); if (ctx->ifc_vlan_detach_event != NULL) EVENTHANDLER_DEREGISTER(vlan_unconfig, ctx->ifc_vlan_detach_event); iflib_netmap_detach(ifp); ether_ifdetach(ifp); /* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/ CTX_LOCK_DESTROY(ctx); if (ctx->ifc_led_dev != NULL) led_destroy(ctx->ifc_led_dev); /* XXX drain any dependent tasks */ tqg = qgroup_if_io_tqg; for (txq = ctx->ifc_txqs, i = 0; i < NTXQSETS(ctx); i++, txq++) { callout_drain(&txq->ift_timer); callout_drain(&txq->ift_db_check); if (txq->ift_task.gt_uniq != NULL) taskqgroup_detach(tqg, &txq->ift_task); } for (i = 0, rxq = ctx->ifc_rxqs; i < NRXQSETS(ctx); i++, rxq++) { if (rxq->ifr_task.gt_uniq != NULL) taskqgroup_detach(tqg, &rxq->ifr_task); } tqg = qgroup_if_config_tqg; if (ctx->ifc_admin_task.gt_uniq != NULL) taskqgroup_detach(tqg, &ctx->ifc_admin_task); if (ctx->ifc_vflr_task.gt_uniq != NULL) taskqgroup_detach(tqg, &ctx->ifc_vflr_task); IFDI_DETACH(ctx); device_set_softc(ctx->ifc_dev, NULL); if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_LEGACY) { pci_release_msi(dev); } if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_MSIX) { iflib_irq_free(ctx, &ctx->ifc_legacy_irq); } if (ctx->ifc_msix_mem != NULL) { bus_release_resource(ctx->ifc_dev, SYS_RES_MEMORY, ctx->ifc_softc_ctx.isc_msix_bar, ctx->ifc_msix_mem); ctx->ifc_msix_mem = NULL; } bus_generic_detach(dev); if_free(ifp); iflib_tx_structures_free(ctx); iflib_rx_structures_free(ctx); if (ctx->ifc_flags & IFC_SC_ALLOCATED) free(ctx->ifc_softc, M_IFLIB); free(ctx, M_IFLIB); return (0); } int iflib_device_detach(device_t dev) { if_ctx_t ctx = device_get_softc(dev); return (iflib_device_deregister(ctx)); } int iflib_device_suspend(device_t dev) { if_ctx_t ctx = device_get_softc(dev); CTX_LOCK(ctx); IFDI_SUSPEND(ctx); CTX_UNLOCK(ctx); return bus_generic_suspend(dev); } int iflib_device_shutdown(device_t dev) { if_ctx_t ctx = device_get_softc(dev); CTX_LOCK(ctx); IFDI_SHUTDOWN(ctx); CTX_UNLOCK(ctx); return bus_generic_suspend(dev); } int iflib_device_resume(device_t dev) { if_ctx_t ctx = device_get_softc(dev); iflib_txq_t txq = ctx->ifc_txqs; CTX_LOCK(ctx); IFDI_RESUME(ctx); iflib_init_locked(ctx); CTX_UNLOCK(ctx); for (int i = 0; i < NTXQSETS(ctx); i++, txq++) iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET); return (bus_generic_resume(dev)); } int iflib_device_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) { int error; if_ctx_t ctx = device_get_softc(dev); CTX_LOCK(ctx); error = IFDI_IOV_INIT(ctx, num_vfs, params); CTX_UNLOCK(ctx); return (error); } void iflib_device_iov_uninit(device_t dev) { if_ctx_t ctx = device_get_softc(dev); CTX_LOCK(ctx); IFDI_IOV_UNINIT(ctx); CTX_UNLOCK(ctx); } int iflib_device_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) { int error; if_ctx_t ctx = device_get_softc(dev); CTX_LOCK(ctx); error = IFDI_IOV_VF_ADD(ctx, vfnum, params); CTX_UNLOCK(ctx); return (error); } /********************************************************************* * * MODULE FUNCTION DEFINITIONS * **********************************************************************/ /* * - Start a fast taskqueue thread for each core * - Start a taskqueue for control operations */ static int iflib_module_init(void) { return (0); } static int iflib_module_event_handler(module_t mod, int what, void *arg) { int err; switch (what) { case MOD_LOAD: if ((err = iflib_module_init()) != 0) return (err); break; case MOD_UNLOAD: return (EBUSY); default: return (EOPNOTSUPP); } return (0); } /********************************************************************* * * PUBLIC FUNCTION DEFINITIONS * ordered as in iflib.h * **********************************************************************/ static void _iflib_assert(if_shared_ctx_t sctx) { MPASS(sctx->isc_tx_maxsize); MPASS(sctx->isc_tx_maxsegsize); MPASS(sctx->isc_rx_maxsize); MPASS(sctx->isc_rx_nsegments); MPASS(sctx->isc_rx_maxsegsize); MPASS(sctx->isc_nrxd_min[0]); MPASS(sctx->isc_nrxd_max[0]); MPASS(sctx->isc_nrxd_default[0]); MPASS(sctx->isc_ntxd_min[0]); MPASS(sctx->isc_ntxd_max[0]); MPASS(sctx->isc_ntxd_default[0]); } static void _iflib_pre_assert(if_softc_ctx_t scctx) { MPASS(scctx->isc_txrx->ift_txd_encap); MPASS(scctx->isc_txrx->ift_txd_flush); MPASS(scctx->isc_txrx->ift_txd_credits_update); MPASS(scctx->isc_txrx->ift_rxd_available); MPASS(scctx->isc_txrx->ift_rxd_pkt_get); MPASS(scctx->isc_txrx->ift_rxd_refill); MPASS(scctx->isc_txrx->ift_rxd_flush); } static int iflib_register(if_ctx_t ctx) { if_shared_ctx_t sctx = ctx->ifc_sctx; driver_t *driver = sctx->isc_driver; device_t dev = ctx->ifc_dev; if_t ifp; _iflib_assert(sctx); CTX_LOCK_INIT(ctx, device_get_nameunit(ctx->ifc_dev)); ifp = ctx->ifc_ifp = if_gethandle(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "can not allocate ifnet structure\n"); return (ENOMEM); } /* * Initialize our context's device specific methods */ kobj_init((kobj_t) ctx, (kobj_class_t) driver); kobj_class_compile((kobj_class_t) driver); driver->refs++; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); if_setsoftc(ifp, ctx); if_setdev(ifp, dev); if_setinitfn(ifp, iflib_if_init); if_setioctlfn(ifp, iflib_if_ioctl); if_settransmitfn(ifp, iflib_if_transmit); if_setqflushfn(ifp, iflib_if_qflush); if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); ctx->ifc_vlan_attach_event = EVENTHANDLER_REGISTER(vlan_config, iflib_vlan_register, ctx, EVENTHANDLER_PRI_FIRST); ctx->ifc_vlan_detach_event = EVENTHANDLER_REGISTER(vlan_unconfig, iflib_vlan_unregister, ctx, EVENTHANDLER_PRI_FIRST); ifmedia_init(&ctx->ifc_media, IFM_IMASK, iflib_media_change, iflib_media_status); return (0); } static int iflib_queues_alloc(if_ctx_t ctx) { if_shared_ctx_t sctx = ctx->ifc_sctx; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; device_t dev = ctx->ifc_dev; int nrxqsets = scctx->isc_nrxqsets; int ntxqsets = scctx->isc_ntxqsets; iflib_txq_t txq; iflib_rxq_t rxq; iflib_fl_t fl = NULL; int i, j, cpu, err, txconf, rxconf; iflib_dma_info_t ifdip; uint32_t *rxqsizes = scctx->isc_rxqsizes; uint32_t *txqsizes = scctx->isc_txqsizes; uint8_t nrxqs = sctx->isc_nrxqs; uint8_t ntxqs = sctx->isc_ntxqs; int nfree_lists = sctx->isc_nfl ? sctx->isc_nfl : 1; caddr_t *vaddrs; uint64_t *paddrs; struct ifmp_ring **brscp; int nbuf_rings = 1; /* XXX determine dynamically */ KASSERT(ntxqs > 0, ("number of queues per qset must be at least 1")); KASSERT(nrxqs > 0, ("number of queues per qset must be at least 1")); brscp = NULL; txq = NULL; rxq = NULL; /* Allocate the TX ring struct memory */ if (!(txq = (iflib_txq_t) malloc(sizeof(struct iflib_txq) * ntxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate TX ring memory\n"); err = ENOMEM; goto fail; } /* Now allocate the RX */ if (!(rxq = (iflib_rxq_t) malloc(sizeof(struct iflib_rxq) * nrxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate RX ring memory\n"); err = ENOMEM; goto rx_fail; } if (!(brscp = malloc(sizeof(void *) * nbuf_rings * nrxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to buf_ring_sc * memory\n"); err = ENOMEM; goto rx_fail; } ctx->ifc_txqs = txq; ctx->ifc_rxqs = rxq; /* * XXX handle allocation failure */ for (txconf = i = 0, cpu = CPU_FIRST(); i < ntxqsets; i++, txconf++, txq++, cpu = CPU_NEXT(cpu)) { /* Set up some basics */ if ((ifdip = malloc(sizeof(struct iflib_dma_info) * ntxqs, M_IFLIB, M_WAITOK|M_ZERO)) == NULL) { device_printf(dev, "failed to allocate iflib_dma_info\n"); err = ENOMEM; goto err_tx_desc; } txq->ift_ifdi = ifdip; for (j = 0; j < ntxqs; j++, ifdip++) { if (iflib_dma_alloc(ctx, txqsizes[j], ifdip, BUS_DMA_NOWAIT)) { device_printf(dev, "Unable to allocate Descriptor memory\n"); err = ENOMEM; goto err_tx_desc; } bzero((void *)ifdip->idi_vaddr, txqsizes[j]); } txq->ift_ctx = ctx; txq->ift_id = i; if (sctx->isc_flags & IFLIB_HAS_TXCQ) { txq->ift_br_offset = 1; } else { txq->ift_br_offset = 0; } /* XXX fix this */ txq->ift_timer.c_cpu = cpu; txq->ift_db_check.c_cpu = cpu; txq->ift_nbr = nbuf_rings; if (iflib_txsd_alloc(txq)) { device_printf(dev, "Critical Failure setting up TX buffers\n"); err = ENOMEM; goto err_tx_desc; } /* Initialize the TX lock */ snprintf(txq->ift_mtx_name, MTX_NAME_LEN, "%s:tx(%d):callout", device_get_nameunit(dev), txq->ift_id); mtx_init(&txq->ift_mtx, txq->ift_mtx_name, NULL, MTX_DEF); callout_init_mtx(&txq->ift_timer, &txq->ift_mtx, 0); callout_init_mtx(&txq->ift_db_check, &txq->ift_mtx, 0); snprintf(txq->ift_db_mtx_name, MTX_NAME_LEN, "%s:tx(%d):db", device_get_nameunit(dev), txq->ift_id); TXDB_LOCK_INIT(txq); txq->ift_br = brscp + i*nbuf_rings; for (j = 0; j < nbuf_rings; j++) { err = ifmp_ring_alloc(&txq->ift_br[j], 2048, txq, iflib_txq_drain, iflib_txq_can_drain, M_IFLIB, M_WAITOK); if (err) { /* XXX free any allocated rings */ device_printf(dev, "Unable to allocate buf_ring\n"); goto err_tx_desc; } } } for (rxconf = i = 0; i < nrxqsets; i++, rxconf++, rxq++) { /* Set up some basics */ if ((ifdip = malloc(sizeof(struct iflib_dma_info) * nrxqs, M_IFLIB, M_WAITOK|M_ZERO)) == NULL) { device_printf(dev, "failed to allocate iflib_dma_info\n"); err = ENOMEM; goto err_tx_desc; } rxq->ifr_ifdi = ifdip; for (j = 0; j < nrxqs; j++, ifdip++) { if (iflib_dma_alloc(ctx, rxqsizes[j], ifdip, BUS_DMA_NOWAIT)) { device_printf(dev, "Unable to allocate Descriptor memory\n"); err = ENOMEM; goto err_tx_desc; } bzero((void *)ifdip->idi_vaddr, rxqsizes[j]); } rxq->ifr_ctx = ctx; rxq->ifr_id = i; if (sctx->isc_flags & IFLIB_HAS_RXCQ) { rxq->ifr_fl_offset = 1; } else { rxq->ifr_fl_offset = 0; } rxq->ifr_nfl = nfree_lists; if (!(fl = (iflib_fl_t) malloc(sizeof(struct iflib_fl) * nfree_lists, M_IFLIB, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate free list memory\n"); err = ENOMEM; goto err_tx_desc; } rxq->ifr_fl = fl; for (j = 0; j < nfree_lists; j++) { rxq->ifr_fl[j].ifl_rxq = rxq; rxq->ifr_fl[j].ifl_id = j; rxq->ifr_fl[j].ifl_ifdi = &rxq->ifr_ifdi[j + rxq->ifr_fl_offset]; } /* Allocate receive buffers for the ring*/ if (iflib_rxsd_alloc(rxq)) { device_printf(dev, "Critical Failure setting up receive buffers\n"); err = ENOMEM; goto err_rx_desc; } } /* TXQs */ vaddrs = malloc(sizeof(caddr_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK); paddrs = malloc(sizeof(uint64_t)*ntxqsets*ntxqs, M_IFLIB, M_WAITOK); for (i = 0; i < ntxqsets; i++) { iflib_dma_info_t di = ctx->ifc_txqs[i].ift_ifdi; for (j = 0; j < ntxqs; j++, di++) { vaddrs[i*ntxqs + j] = di->idi_vaddr; paddrs[i*ntxqs + j] = di->idi_paddr; } } if ((err = IFDI_TX_QUEUES_ALLOC(ctx, vaddrs, paddrs, ntxqs, ntxqsets)) != 0) { device_printf(ctx->ifc_dev, "device queue allocation failed\n"); iflib_tx_structures_free(ctx); free(vaddrs, M_IFLIB); free(paddrs, M_IFLIB); goto err_rx_desc; } free(vaddrs, M_IFLIB); free(paddrs, M_IFLIB); /* RXQs */ vaddrs = malloc(sizeof(caddr_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK); paddrs = malloc(sizeof(uint64_t)*nrxqsets*nrxqs, M_IFLIB, M_WAITOK); for (i = 0; i < nrxqsets; i++) { iflib_dma_info_t di = ctx->ifc_rxqs[i].ifr_ifdi; for (j = 0; j < nrxqs; j++, di++) { vaddrs[i*nrxqs + j] = di->idi_vaddr; paddrs[i*nrxqs + j] = di->idi_paddr; } } if ((err = IFDI_RX_QUEUES_ALLOC(ctx, vaddrs, paddrs, nrxqs, nrxqsets)) != 0) { device_printf(ctx->ifc_dev, "device queue allocation failed\n"); iflib_tx_structures_free(ctx); free(vaddrs, M_IFLIB); free(paddrs, M_IFLIB); goto err_rx_desc; } free(vaddrs, M_IFLIB); free(paddrs, M_IFLIB); return (0); /* XXX handle allocation failure changes */ err_rx_desc: err_tx_desc: if (ctx->ifc_rxqs != NULL) free(ctx->ifc_rxqs, M_IFLIB); ctx->ifc_rxqs = NULL; if (ctx->ifc_txqs != NULL) free(ctx->ifc_txqs, M_IFLIB); ctx->ifc_txqs = NULL; rx_fail: if (brscp != NULL) free(brscp, M_IFLIB); if (rxq != NULL) free(rxq, M_IFLIB); if (txq != NULL) free(txq, M_IFLIB); fail: return (err); } static int iflib_tx_structures_setup(if_ctx_t ctx) { iflib_txq_t txq = ctx->ifc_txqs; int i; for (i = 0; i < NTXQSETS(ctx); i++, txq++) iflib_txq_setup(txq); return (0); } static void iflib_tx_structures_free(if_ctx_t ctx) { iflib_txq_t txq = ctx->ifc_txqs; int i, j; for (i = 0; i < NTXQSETS(ctx); i++, txq++) { iflib_txq_destroy(txq); for (j = 0; j < ctx->ifc_nhwtxqs; j++) iflib_dma_free(&txq->ift_ifdi[j]); } free(ctx->ifc_txqs, M_IFLIB); ctx->ifc_txqs = NULL; IFDI_QUEUES_FREE(ctx); } /********************************************************************* * * Initialize all receive rings. * **********************************************************************/ static int iflib_rx_structures_setup(if_ctx_t ctx) { iflib_rxq_t rxq = ctx->ifc_rxqs; int q; #if defined(INET6) || defined(INET) int i, err; #endif for (q = 0; q < ctx->ifc_softc_ctx.isc_nrxqsets; q++, rxq++) { #if defined(INET6) || defined(INET) tcp_lro_free(&rxq->ifr_lc); if ((err = tcp_lro_init_args(&rxq->ifr_lc, ctx->ifc_ifp, TCP_LRO_ENTRIES, min(1024, ctx->ifc_softc_ctx.isc_nrxd[rxq->ifr_fl_offset]))) != 0) { device_printf(ctx->ifc_dev, "LRO Initialization failed!\n"); goto fail; } rxq->ifr_lro_enabled = TRUE; #endif IFDI_RXQ_SETUP(ctx, rxq->ifr_id); } return (0); #if defined(INET6) || defined(INET) fail: /* * Free RX software descriptors allocated so far, we will only handle * the rings that completed, the failing case will have * cleaned up for itself. 'q' failed, so its the terminus. */ rxq = ctx->ifc_rxqs; for (i = 0; i < q; ++i, rxq++) { iflib_rx_sds_free(rxq); rxq->ifr_cq_gen = rxq->ifr_cq_cidx = rxq->ifr_cq_pidx = 0; } return (err); #endif } /********************************************************************* * * Free all receive rings. * **********************************************************************/ static void iflib_rx_structures_free(if_ctx_t ctx) { iflib_rxq_t rxq = ctx->ifc_rxqs; for (int i = 0; i < ctx->ifc_softc_ctx.isc_nrxqsets; i++, rxq++) { iflib_rx_sds_free(rxq); } } static int iflib_qset_structures_setup(if_ctx_t ctx) { int err; if ((err = iflib_tx_structures_setup(ctx)) != 0) return (err); if ((err = iflib_rx_structures_setup(ctx)) != 0) { device_printf(ctx->ifc_dev, "iflib_rx_structures_setup failed: %d\n", err); iflib_tx_structures_free(ctx); iflib_rx_structures_free(ctx); } return (err); } int iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid, driver_filter_t filter, void *filter_arg, driver_intr_t handler, void *arg, char *name) { return (_iflib_irq_alloc(ctx, irq, rid, filter, handler, arg, name)); } static int find_nth(if_ctx_t ctx, cpuset_t *cpus, int qid) { int i, cpuid, eqid, count; CPU_COPY(&ctx->ifc_cpus, cpus); count = CPU_COUNT(&ctx->ifc_cpus); eqid = qid % count; /* clear up to the qid'th bit */ for (i = 0; i < eqid; i++) { cpuid = CPU_FFS(cpus); MPASS(cpuid != 0); CPU_CLR(cpuid-1, cpus); } cpuid = CPU_FFS(cpus); MPASS(cpuid != 0); return (cpuid-1); } int iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid, iflib_intr_type_t type, driver_filter_t *filter, void *filter_arg, int qid, char *name) { struct grouptask *gtask; struct taskqgroup *tqg; iflib_filter_info_t info; cpuset_t cpus; gtask_fn_t *fn; int tqrid, err, cpuid; void *q; info = &ctx->ifc_filter_info; tqrid = rid; switch (type) { /* XXX merge tx/rx for netmap? */ case IFLIB_INTR_TX: q = &ctx->ifc_txqs[qid]; info = &ctx->ifc_txqs[qid].ift_filter_info; gtask = &ctx->ifc_txqs[qid].ift_task; tqg = qgroup_if_io_tqg; fn = _task_fn_tx; GROUPTASK_INIT(gtask, 0, fn, q); break; case IFLIB_INTR_RX: q = &ctx->ifc_rxqs[qid]; info = &ctx->ifc_rxqs[qid].ifr_filter_info; gtask = &ctx->ifc_rxqs[qid].ifr_task; tqg = qgroup_if_io_tqg; fn = _task_fn_rx; GROUPTASK_INIT(gtask, 0, fn, q); break; case IFLIB_INTR_ADMIN: q = ctx; tqrid = -1; info = &ctx->ifc_filter_info; gtask = &ctx->ifc_admin_task; tqg = qgroup_if_config_tqg; fn = _task_fn_admin; break; default: panic("unknown net intr type"); } info->ifi_filter = filter; info->ifi_filter_arg = filter_arg; info->ifi_task = gtask; info->ifi_ctx = ctx; err = _iflib_irq_alloc(ctx, irq, rid, iflib_fast_intr, NULL, info, name); if (err != 0) { device_printf(ctx->ifc_dev, "_iflib_irq_alloc failed %d\n", err); return (err); } if (type == IFLIB_INTR_ADMIN) return (0); if (tqrid != -1) { cpuid = find_nth(ctx, &cpus, qid); taskqgroup_attach_cpu(tqg, gtask, q, cpuid, irq->ii_rid, name); } else { taskqgroup_attach(tqg, gtask, q, tqrid, name); } return (0); } void iflib_softirq_alloc_generic(if_ctx_t ctx, int rid, iflib_intr_type_t type, void *arg, int qid, char *name) { struct grouptask *gtask; struct taskqgroup *tqg; gtask_fn_t *fn; void *q; switch (type) { case IFLIB_INTR_TX: q = &ctx->ifc_txqs[qid]; gtask = &ctx->ifc_txqs[qid].ift_task; tqg = qgroup_if_io_tqg; fn = _task_fn_tx; break; case IFLIB_INTR_RX: q = &ctx->ifc_rxqs[qid]; gtask = &ctx->ifc_rxqs[qid].ifr_task; tqg = qgroup_if_io_tqg; fn = _task_fn_rx; break; case IFLIB_INTR_IOV: q = ctx; gtask = &ctx->ifc_vflr_task; tqg = qgroup_if_config_tqg; rid = -1; fn = _task_fn_iov; break; default: panic("unknown net intr type"); } GROUPTASK_INIT(gtask, 0, fn, q); taskqgroup_attach(tqg, gtask, q, rid, name); } void iflib_irq_free(if_ctx_t ctx, if_irq_t irq) { if (irq->ii_tag) bus_teardown_intr(ctx->ifc_dev, irq->ii_res, irq->ii_tag); if (irq->ii_res) bus_release_resource(ctx->ifc_dev, SYS_RES_IRQ, irq->ii_rid, irq->ii_res); } static int iflib_legacy_setup(if_ctx_t ctx, driver_filter_t filter, void *filter_arg, int *rid, char *name) { iflib_txq_t txq = ctx->ifc_txqs; iflib_rxq_t rxq = ctx->ifc_rxqs; if_irq_t irq = &ctx->ifc_legacy_irq; iflib_filter_info_t info; struct grouptask *gtask; struct taskqgroup *tqg; gtask_fn_t *fn; int tqrid; void *q; int err; q = &ctx->ifc_rxqs[0]; info = &rxq[0].ifr_filter_info; gtask = &rxq[0].ifr_task; tqg = qgroup_if_io_tqg; tqrid = irq->ii_rid = *rid; fn = _task_fn_rx; ctx->ifc_flags |= IFC_LEGACY; info->ifi_filter = filter; info->ifi_filter_arg = filter_arg; info->ifi_task = gtask; info->ifi_ctx = ctx; /* We allocate a single interrupt resource */ if ((err = _iflib_irq_alloc(ctx, irq, tqrid, iflib_fast_intr, NULL, info, name)) != 0) return (err); GROUPTASK_INIT(gtask, 0, fn, q); taskqgroup_attach(tqg, gtask, q, tqrid, name); GROUPTASK_INIT(&txq->ift_task, 0, _task_fn_tx, txq); taskqgroup_attach(qgroup_if_io_tqg, &txq->ift_task, txq, tqrid, "tx"); return (0); } void iflib_led_create(if_ctx_t ctx) { ctx->ifc_led_dev = led_create(iflib_led_func, ctx, device_get_nameunit(ctx->ifc_dev)); } void iflib_tx_intr_deferred(if_ctx_t ctx, int txqid) { GROUPTASK_ENQUEUE(&ctx->ifc_txqs[txqid].ift_task); } void iflib_rx_intr_deferred(if_ctx_t ctx, int rxqid) { GROUPTASK_ENQUEUE(&ctx->ifc_rxqs[rxqid].ifr_task); } void iflib_admin_intr_deferred(if_ctx_t ctx) { #ifdef INVARIANTS struct grouptask *gtask; gtask = &ctx->ifc_admin_task; MPASS(gtask->gt_taskqueue != NULL); #endif GROUPTASK_ENQUEUE(&ctx->ifc_admin_task); } void iflib_iov_intr_deferred(if_ctx_t ctx) { GROUPTASK_ENQUEUE(&ctx->ifc_vflr_task); } void iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu, char *name) { taskqgroup_attach_cpu(qgroup_if_io_tqg, gt, uniq, cpu, -1, name); } void iflib_config_gtask_init(if_ctx_t ctx, struct grouptask *gtask, gtask_fn_t *fn, char *name) { GROUPTASK_INIT(gtask, 0, fn, ctx); taskqgroup_attach(qgroup_if_config_tqg, gtask, gtask, -1, name); } void iflib_config_gtask_deinit(struct grouptask *gtask) { taskqgroup_detach(qgroup_if_config_tqg, gtask); } void iflib_link_state_change(if_ctx_t ctx, int link_state, uint64_t baudrate) { if_t ifp = ctx->ifc_ifp; iflib_txq_t txq = ctx->ifc_txqs; if_setbaudrate(ifp, baudrate); /* If link down, disable watchdog */ if ((ctx->ifc_link_state == LINK_STATE_UP) && (link_state == LINK_STATE_DOWN)) { for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxqsets; i++, txq++) txq->ift_qstatus = IFLIB_QUEUE_IDLE; } ctx->ifc_link_state = link_state; if_link_state_change(ifp, link_state); } static int iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq) { int credits; #ifdef INVARIANTS int credits_pre = txq->ift_cidx_processed; #endif if (ctx->isc_txd_credits_update == NULL) return (0); if ((credits = ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, txq->ift_cidx_processed, true)) == 0) return (0); txq->ift_processed += credits; txq->ift_cidx_processed += credits; MPASS(credits_pre + credits == txq->ift_cidx_processed); if (txq->ift_cidx_processed >= txq->ift_size) txq->ift_cidx_processed -= txq->ift_size; return (credits); } static int iflib_rxd_avail(if_ctx_t ctx, iflib_rxq_t rxq, int cidx, int budget) { return (ctx->isc_rxd_available(ctx->ifc_softc, rxq->ifr_id, cidx, budget)); } void iflib_add_int_delay_sysctl(if_ctx_t ctx, const char *name, const char *description, if_int_delay_info_t info, int offset, int value) { info->iidi_ctx = ctx; info->iidi_offset = offset; info->iidi_value = value; SYSCTL_ADD_PROC(device_get_sysctl_ctx(ctx->ifc_dev), SYSCTL_CHILDREN(device_get_sysctl_tree(ctx->ifc_dev)), OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, info, 0, iflib_sysctl_int_delay, "I", description); } struct mtx * iflib_ctx_lock_get(if_ctx_t ctx) { return (&ctx->ifc_mtx); } static int iflib_msix_init(if_ctx_t ctx) { device_t dev = ctx->ifc_dev; if_shared_ctx_t sctx = ctx->ifc_sctx; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; int vectors, queues, rx_queues, tx_queues, queuemsgs, msgs; int iflib_num_tx_queues, iflib_num_rx_queues; int err, admincnt, bar; iflib_num_tx_queues = scctx->isc_ntxqsets; iflib_num_rx_queues = scctx->isc_nrxqsets; device_printf(dev, "msix_init qsets capped at %d\n", iflib_num_tx_queues); bar = ctx->ifc_softc_ctx.isc_msix_bar; admincnt = sctx->isc_admin_intrcnt; /* Override by tuneable */ if (enable_msix == 0) goto msi; /* ** When used in a virtualized environment ** PCI BUSMASTER capability may not be set ** so explicity set it here and rewrite ** the ENABLE in the MSIX control register ** at this point to cause the host to ** successfully initialize us. */ { int msix_ctrl, rid; pci_enable_busmaster(dev); rid = 0; if (pci_find_cap(dev, PCIY_MSIX, &rid) == 0 && rid != 0) { rid += PCIR_MSIX_CTRL; msix_ctrl = pci_read_config(dev, rid, 2); msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; pci_write_config(dev, rid, msix_ctrl, 2); } else { device_printf(dev, "PCIY_MSIX capability not found; " "or rid %d == 0.\n", rid); goto msi; } } /* * bar == -1 => "trust me I know what I'm doing" * https://www.youtube.com/watch?v=nnwWKkNau4I * Some drivers are for hardware that is so shoddily * documented that no one knows which bars are which * so the developer has to map all bars. This hack * allows shoddy garbage to use msix in this framework. */ if (bar != -1) { ctx->ifc_msix_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &bar, RF_ACTIVE); if (ctx->ifc_msix_mem == NULL) { /* May not be enabled */ device_printf(dev, "Unable to map MSIX table \n"); goto msi; } } /* First try MSI/X */ if ((msgs = pci_msix_count(dev)) == 0) { /* system has msix disabled */ device_printf(dev, "System has MSIX disabled \n"); bus_release_resource(dev, SYS_RES_MEMORY, bar, ctx->ifc_msix_mem); ctx->ifc_msix_mem = NULL; goto msi; } #if IFLIB_DEBUG /* use only 1 qset in debug mode */ queuemsgs = min(msgs - admincnt, 1); #else queuemsgs = msgs - admincnt; #endif if (bus_get_cpus(dev, INTR_CPUS, sizeof(ctx->ifc_cpus), &ctx->ifc_cpus) == 0) { #ifdef RSS queues = imin(queuemsgs, rss_getnumbuckets()); #else queues = queuemsgs; #endif queues = imin(CPU_COUNT(&ctx->ifc_cpus), queues); device_printf(dev, "pxm cpus: %d queue msgs: %d admincnt: %d\n", CPU_COUNT(&ctx->ifc_cpus), queuemsgs, admincnt); } else { device_printf(dev, "Unable to fetch CPU list\n"); /* Figure out a reasonable auto config value */ queues = min(queuemsgs, mp_ncpus); } #ifdef RSS /* If we're doing RSS, clamp at the number of RSS buckets */ if (queues > rss_getnumbuckets()) queues = rss_getnumbuckets(); #endif if (iflib_num_rx_queues > 0 && iflib_num_rx_queues < queuemsgs - admincnt) rx_queues = iflib_num_rx_queues; else rx_queues = queues; /* * We want this to be all logical CPUs by default */ if (iflib_num_tx_queues > 0 && iflib_num_tx_queues < queues) tx_queues = iflib_num_tx_queues; else tx_queues = mp_ncpus; if (ctx->ifc_sysctl_qs_eq_override == 0) { #ifdef INVARIANTS if (tx_queues != rx_queues) device_printf(dev, "queue equality override not set, capping rx_queues at %d and tx_queues at %d\n", min(rx_queues, tx_queues), min(rx_queues, tx_queues)); #endif tx_queues = min(rx_queues, tx_queues); rx_queues = min(rx_queues, tx_queues); } device_printf(dev, "using %d rx queues %d tx queues \n", rx_queues, tx_queues); vectors = rx_queues + admincnt; if ((err = pci_alloc_msix(dev, &vectors)) == 0) { device_printf(dev, "Using MSIX interrupts with %d vectors\n", vectors); scctx->isc_vectors = vectors; scctx->isc_nrxqsets = rx_queues; scctx->isc_ntxqsets = tx_queues; scctx->isc_intr = IFLIB_INTR_MSIX; return (vectors); } else { device_printf(dev, "failed to allocate %d msix vectors, err: %d - using MSI\n", vectors, err); } msi: vectors = pci_msi_count(dev); scctx->isc_nrxqsets = 1; scctx->isc_ntxqsets = 1; scctx->isc_vectors = vectors; if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) { device_printf(dev,"Using an MSI interrupt\n"); scctx->isc_intr = IFLIB_INTR_MSI; } else { device_printf(dev,"Using a Legacy interrupt\n"); scctx->isc_intr = IFLIB_INTR_LEGACY; } return (vectors); } char * ring_states[] = { "IDLE", "BUSY", "STALLED", "ABDICATED" }; static int mp_ring_state_handler(SYSCTL_HANDLER_ARGS) { int rc; uint16_t *state = ((uint16_t *)oidp->oid_arg1); struct sbuf *sb; char *ring_state = "UNKNOWN"; /* XXX needed ? */ rc = sysctl_wire_old_buffer(req, 0); MPASS(rc == 0); if (rc != 0) return (rc); sb = sbuf_new_for_sysctl(NULL, NULL, 80, req); MPASS(sb != NULL); if (sb == NULL) return (ENOMEM); if (state[3] <= 3) ring_state = ring_states[state[3]]; sbuf_printf(sb, "pidx_head: %04hd pidx_tail: %04hd cidx: %04hd state: %s", state[0], state[1], state[2], ring_state); rc = sbuf_finish(sb); sbuf_delete(sb); return(rc); } enum iflib_ndesc_handler { IFLIB_NTXD_HANDLER, IFLIB_NRXD_HANDLER, }; static int mp_ndesc_handler(SYSCTL_HANDLER_ARGS) { if_ctx_t ctx = (void *)arg1; enum iflib_ndesc_handler type = arg2; char buf[256] = {0}; uint16_t *ndesc; char *p, *next; int nqs, rc, i; MPASS(type == IFLIB_NTXD_HANDLER || type == IFLIB_NRXD_HANDLER); nqs = 8; switch(type) { case IFLIB_NTXD_HANDLER: ndesc = ctx->ifc_sysctl_ntxds; if (ctx->ifc_sctx) nqs = ctx->ifc_sctx->isc_ntxqs; break; case IFLIB_NRXD_HANDLER: ndesc = ctx->ifc_sysctl_nrxds; if (ctx->ifc_sctx) nqs = ctx->ifc_sctx->isc_nrxqs; break; } if (nqs == 0) nqs = 8; for (i=0; i<8; i++) { if (i >= nqs) break; if (i) strcat(buf, ","); sprintf(strchr(buf, 0), "%d", ndesc[i]); } rc = sysctl_handle_string(oidp, buf, sizeof(buf), req); if (rc || req->newptr == NULL) return rc; for (i = 0, next = buf, p = strsep(&next, " ,"); i < 8 && p; i++, p = strsep(&next, " ,")) { ndesc[i] = strtoul(p, NULL, 10); } return(rc); } #define NAME_BUFLEN 32 static void iflib_add_device_sysctl_pre(if_ctx_t ctx) { device_t dev = iflib_get_dev(ctx); struct sysctl_oid_list *child, *oid_list; struct sysctl_ctx_list *ctx_list; struct sysctl_oid *node; ctx_list = device_get_sysctl_ctx(dev); child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); ctx->ifc_sysctl_node = node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, "iflib", CTLFLAG_RD, NULL, "IFLIB fields"); oid_list = SYSCTL_CHILDREN(node); SYSCTL_ADD_STRING(ctx_list, oid_list, OID_AUTO, "driver_version", CTLFLAG_RD, ctx->ifc_sctx->isc_driver_version, 0, "driver version"); SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_ntxqs", CTLFLAG_RWTUN, &ctx->ifc_sysctl_ntxqs, 0, "# of txqs to use, 0 => use default #"); SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_nrxqs", CTLFLAG_RWTUN, &ctx->ifc_sysctl_nrxqs, 0, "# of rxqs to use, 0 => use default #"); SYSCTL_ADD_U16(ctx_list, oid_list, OID_AUTO, "override_qs_enable", CTLFLAG_RWTUN, &ctx->ifc_sysctl_qs_eq_override, 0, "permit #txq != #rxq"); /* XXX change for per-queue sizes */ SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_ntxds", CTLTYPE_STRING|CTLFLAG_RWTUN, ctx, IFLIB_NTXD_HANDLER, mp_ndesc_handler, "A", "list of # of tx descriptors to use, 0 = use default #"); SYSCTL_ADD_PROC(ctx_list, oid_list, OID_AUTO, "override_nrxds", CTLTYPE_STRING|CTLFLAG_RWTUN, ctx, IFLIB_NRXD_HANDLER, mp_ndesc_handler, "A", "list of # of rx descriptors to use, 0 = use default #"); } static void iflib_add_device_sysctl_post(if_ctx_t ctx) { if_shared_ctx_t sctx = ctx->ifc_sctx; if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; device_t dev = iflib_get_dev(ctx); struct sysctl_oid_list *child; struct sysctl_ctx_list *ctx_list; iflib_fl_t fl; iflib_txq_t txq; iflib_rxq_t rxq; int i, j; char namebuf[NAME_BUFLEN]; char *qfmt; struct sysctl_oid *queue_node, *fl_node, *node; struct sysctl_oid_list *queue_list, *fl_list; ctx_list = device_get_sysctl_ctx(dev); node = ctx->ifc_sysctl_node; child = SYSCTL_CHILDREN(node); if (scctx->isc_ntxqsets > 100) qfmt = "txq%03d"; else if (scctx->isc_ntxqsets > 10) qfmt = "txq%02d"; else qfmt = "txq%d"; for (i = 0, txq = ctx->ifc_txqs; i < scctx->isc_ntxqsets; i++, txq++) { snprintf(namebuf, NAME_BUFLEN, qfmt, i); queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf, CTLFLAG_RD, NULL, "Queue Name"); queue_list = SYSCTL_CHILDREN(queue_node); #if MEMORY_LOGGING SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_dequeued", CTLFLAG_RD, &txq->ift_dequeued, "total mbufs freed"); SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_enqueued", CTLFLAG_RD, &txq->ift_enqueued, "total mbufs enqueued"); #endif SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag", CTLFLAG_RD, &txq->ift_mbuf_defrag, "# of times m_defrag was called"); SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "m_pullups", CTLFLAG_RD, &txq->ift_pullups, "# of times m_pullup was called"); SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "mbuf_defrag_failed", CTLFLAG_RD, &txq->ift_mbuf_defrag_failed, "# of times m_defrag failed"); SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_desc_avail", CTLFLAG_RD, &txq->ift_no_desc_avail, "# of times no descriptors were available"); SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "tx_map_failed", CTLFLAG_RD, &txq->ift_map_failed, "# of times dma map failed"); SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txd_encap_efbig", CTLFLAG_RD, &txq->ift_txd_encap_efbig, "# of times txd_encap returned EFBIG"); SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "no_tx_dma_setup", CTLFLAG_RD, &txq->ift_no_tx_dma_setup, "# of times map failed for other than EFBIG"); SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_pidx", CTLFLAG_RD, &txq->ift_pidx, 1, "Producer Index"); SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx", CTLFLAG_RD, &txq->ift_cidx, 1, "Consumer Index"); SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_cidx_processed", CTLFLAG_RD, &txq->ift_cidx_processed, 1, "Consumer Index seen by credit update"); SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "txq_in_use", CTLFLAG_RD, &txq->ift_in_use, 1, "descriptors in use"); SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_processed", CTLFLAG_RD, &txq->ift_processed, "descriptors procesed for clean"); SYSCTL_ADD_QUAD(ctx_list, queue_list, OID_AUTO, "txq_cleaned", CTLFLAG_RD, &txq->ift_cleaned, "total cleaned"); SYSCTL_ADD_PROC(ctx_list, queue_list, OID_AUTO, "ring_state", CTLTYPE_STRING | CTLFLAG_RD, __DEVOLATILE(uint64_t *, &txq->ift_br[0]->state), 0, mp_ring_state_handler, "A", "soft ring state"); SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_enqueues", CTLFLAG_RD, &txq->ift_br[0]->enqueues, "# of enqueues to the mp_ring for this queue"); SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_drops", CTLFLAG_RD, &txq->ift_br[0]->drops, "# of drops in the mp_ring for this queue"); SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_starts", CTLFLAG_RD, &txq->ift_br[0]->starts, "# of normal consumer starts in the mp_ring for this queue"); SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_stalls", CTLFLAG_RD, &txq->ift_br[0]->stalls, "# of consumer stalls in the mp_ring for this queue"); SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_restarts", CTLFLAG_RD, &txq->ift_br[0]->restarts, "# of consumer restarts in the mp_ring for this queue"); SYSCTL_ADD_COUNTER_U64(ctx_list, queue_list, OID_AUTO, "r_abdications", CTLFLAG_RD, &txq->ift_br[0]->abdications, "# of consumer abdications in the mp_ring for this queue"); } if (scctx->isc_nrxqsets > 100) qfmt = "rxq%03d"; else if (scctx->isc_nrxqsets > 10) qfmt = "rxq%02d"; else qfmt = "rxq%d"; for (i = 0, rxq = ctx->ifc_rxqs; i < scctx->isc_nrxqsets; i++, rxq++) { snprintf(namebuf, NAME_BUFLEN, qfmt, i); queue_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, namebuf, CTLFLAG_RD, NULL, "Queue Name"); queue_list = SYSCTL_CHILDREN(queue_node); if (sctx->isc_flags & IFLIB_HAS_RXCQ) { SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "rxq_cq_pidx", CTLFLAG_RD, &rxq->ifr_cq_pidx, 1, "Producer Index"); SYSCTL_ADD_U16(ctx_list, queue_list, OID_AUTO, "rxq_cq_cidx", CTLFLAG_RD, &rxq->ifr_cq_cidx, 1, "Consumer Index"); } for (j = 0, fl = rxq->ifr_fl; j < rxq->ifr_nfl; j++, fl++) { snprintf(namebuf, NAME_BUFLEN, "rxq_fl%d", j); fl_node = SYSCTL_ADD_NODE(ctx_list, queue_list, OID_AUTO, namebuf, CTLFLAG_RD, NULL, "freelist Name"); fl_list = SYSCTL_CHILDREN(fl_node); SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "pidx", CTLFLAG_RD, &fl->ifl_pidx, 1, "Producer Index"); SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "cidx", CTLFLAG_RD, &fl->ifl_cidx, 1, "Consumer Index"); SYSCTL_ADD_U16(ctx_list, fl_list, OID_AUTO, "credits", CTLFLAG_RD, &fl->ifl_credits, 1, "credits available"); #if MEMORY_LOGGING SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_enqueued", CTLFLAG_RD, &fl->ifl_m_enqueued, "mbufs allocated"); SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_m_dequeued", CTLFLAG_RD, &fl->ifl_m_dequeued, "mbufs freed"); SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_enqueued", CTLFLAG_RD, &fl->ifl_cl_enqueued, "clusters allocated"); SYSCTL_ADD_QUAD(ctx_list, fl_list, OID_AUTO, "fl_cl_dequeued", CTLFLAG_RD, &fl->ifl_cl_dequeued, "clusters freed"); #endif } } } Index: projects/ipsec/sys/net/netisr.c =================================================================== --- projects/ipsec/sys/net/netisr.c (revision 313312) +++ projects/ipsec/sys/net/netisr.c (revision 313313) @@ -1,1531 +1,1532 @@ /*- * Copyright (c) 2007-2009 Robert N. M. Watson * Copyright (c) 2010-2011 Juniper Networks, Inc. * All rights reserved. * * This software was developed by Robert N. M. Watson under contract * to Juniper Networks, Inc. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); /* * netisr is a packet dispatch service, allowing synchronous (directly * dispatched) and asynchronous (deferred dispatch) processing of packets by * registered protocol handlers. Callers pass a protocol identifier and * packet to netisr, along with a direct dispatch hint, and work will either * be immediately processed by the registered handler, or passed to a * software interrupt (SWI) thread for deferred dispatch. Callers will * generally select one or the other based on: * * - Whether directly dispatching a netisr handler lead to code reentrance or * lock recursion, such as entering the socket code from the socket code. * - Whether directly dispatching a netisr handler lead to recursive * processing, such as when decapsulating several wrapped layers of tunnel * information (IPSEC within IPSEC within ...). * * Maintaining ordering for protocol streams is a critical design concern. * Enforcing ordering limits the opportunity for concurrency, but maintains * the strong ordering requirements found in some protocols, such as TCP. Of * related concern is CPU affinity--it is desirable to process all data * associated with a particular stream on the same CPU over time in order to * avoid acquiring locks associated with the connection on different CPUs, * keep connection data in one cache, and to generally encourage associated * user threads to live on the same CPU as the stream. It's also desirable * to avoid lock migration and contention where locks are associated with * more than one flow. * * netisr supports several policy variations, represented by the * NETISR_POLICY_* constants, allowing protocols to play various roles in * identifying flows, assigning work to CPUs, etc. These are described in * netisr.h. */ #include "opt_ddb.h" #include "opt_device_polling.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DDB #include #endif #define _WANT_NETISR_INTERNAL /* Enable definitions from netisr_internal.h */ #include #include #include #include #include /*- * Synchronize use and modification of the registered netisr data structures; * acquire a read lock while modifying the set of registered protocols to * prevent partially registered or unregistered protocols from being run. * * The following data structures and fields are protected by this lock: * * - The netisr_proto array, including all fields of struct netisr_proto. * - The nws array, including all fields of struct netisr_worker. * - The nws_array array. * * Note: the NETISR_LOCKING define controls whether read locks are acquired * in packet processing paths requiring netisr registration stability. This * is disabled by default as it can lead to measurable performance * degradation even with rmlocks (3%-6% for loopback ping-pong traffic), and * because netisr registration and unregistration is extremely rare at * runtime. If it becomes more common, this decision should be revisited. * * XXXRW: rmlocks don't support assertions. */ static struct rmlock netisr_rmlock; #define NETISR_LOCK_INIT() rm_init_flags(&netisr_rmlock, "netisr", \ RM_NOWITNESS) #define NETISR_LOCK_ASSERT() #define NETISR_RLOCK(tracker) rm_rlock(&netisr_rmlock, (tracker)) #define NETISR_RUNLOCK(tracker) rm_runlock(&netisr_rmlock, (tracker)) #define NETISR_WLOCK() rm_wlock(&netisr_rmlock) #define NETISR_WUNLOCK() rm_wunlock(&netisr_rmlock) /* #define NETISR_LOCKING */ static SYSCTL_NODE(_net, OID_AUTO, isr, CTLFLAG_RW, 0, "netisr"); /*- * Three global direct dispatch policies are supported: * * NETISR_DISPATCH_DEFERRED: All work is deferred for a netisr, regardless of * context (may be overriden by protocols). * * NETISR_DISPATCH_HYBRID: If the executing context allows direct dispatch, * and we're running on the CPU the work would be performed on, then direct * dispatch it if it wouldn't violate ordering constraints on the workstream. * * NETISR_DISPATCH_DIRECT: If the executing context allows direct dispatch, * always direct dispatch. (The default.) * * Notice that changing the global policy could lead to short periods of * misordered processing, but this is considered acceptable as compared to * the complexity of enforcing ordering during policy changes. Protocols can * override the global policy (when they're not doing that, they select * NETISR_DISPATCH_DEFAULT). */ #define NETISR_DISPATCH_POLICY_DEFAULT NETISR_DISPATCH_DIRECT #define NETISR_DISPATCH_POLICY_MAXSTR 20 /* Used for temporary buffers. */ static u_int netisr_dispatch_policy = NETISR_DISPATCH_POLICY_DEFAULT; static int sysctl_netisr_dispatch_policy(SYSCTL_HANDLER_ARGS); SYSCTL_PROC(_net_isr, OID_AUTO, dispatch, CTLTYPE_STRING | CTLFLAG_RWTUN, 0, 0, sysctl_netisr_dispatch_policy, "A", "netisr dispatch policy"); /* * Allow the administrator to limit the number of threads (CPUs) to use for * netisr. We don't check netisr_maxthreads before creating the thread for * CPU 0. This must be set at boot. We will create at most one thread per CPU. * By default we initialize this to 1 which would assign just 1 cpu (cpu0) and * therefore only 1 workstream. If set to -1, netisr would use all cpus * (mp_ncpus) and therefore would have those many workstreams. One workstream * per thread (CPU). */ static int netisr_maxthreads = 1; /* Max number of threads. */ SYSCTL_INT(_net_isr, OID_AUTO, maxthreads, CTLFLAG_RDTUN, &netisr_maxthreads, 0, "Use at most this many CPUs for netisr processing"); static int netisr_bindthreads = 0; /* Bind threads to CPUs. */ SYSCTL_INT(_net_isr, OID_AUTO, bindthreads, CTLFLAG_RDTUN, &netisr_bindthreads, 0, "Bind netisr threads to CPUs."); /* * Limit per-workstream mbuf queue limits s to at most net.isr.maxqlimit, * both for initial configuration and later modification using * netisr_setqlimit(). */ #define NETISR_DEFAULT_MAXQLIMIT 10240 static u_int netisr_maxqlimit = NETISR_DEFAULT_MAXQLIMIT; SYSCTL_UINT(_net_isr, OID_AUTO, maxqlimit, CTLFLAG_RDTUN, &netisr_maxqlimit, 0, "Maximum netisr per-protocol, per-CPU queue depth."); /* * The default per-workstream mbuf queue limit for protocols that don't * initialize the nh_qlimit field of their struct netisr_handler. If this is * set above netisr_maxqlimit, we truncate it to the maximum during boot. */ #define NETISR_DEFAULT_DEFAULTQLIMIT 256 static u_int netisr_defaultqlimit = NETISR_DEFAULT_DEFAULTQLIMIT; SYSCTL_UINT(_net_isr, OID_AUTO, defaultqlimit, CTLFLAG_RDTUN, &netisr_defaultqlimit, 0, "Default netisr per-protocol, per-CPU queue limit if not set by protocol"); /* * Store and export the compile-time constant NETISR_MAXPROT limit on the * number of protocols that can register with netisr at a time. This is * required for crashdump analysis, as it sizes netisr_proto[]. */ static u_int netisr_maxprot = NETISR_MAXPROT; SYSCTL_UINT(_net_isr, OID_AUTO, maxprot, CTLFLAG_RD, &netisr_maxprot, 0, "Compile-time limit on the number of protocols supported by netisr."); /* * The netisr_proto array describes all registered protocols, indexed by * protocol number. See netisr_internal.h for more details. */ static struct netisr_proto netisr_proto[NETISR_MAXPROT]; #ifdef VIMAGE /* * The netisr_enable array describes a per-VNET flag for registered * protocols on whether this netisr is active in this VNET or not. * netisr_register() will automatically enable the netisr for the * default VNET and all currently active instances. * netisr_unregister() will disable all active VNETs, including vnet0. * Individual network stack instances can be enabled/disabled by the * netisr_(un)register _vnet() functions. * With this we keep the one netisr_proto per protocol but add a * mechanism to stop netisr processing for vnet teardown. * Apart from that we expect a VNET to always be enabled. */ static VNET_DEFINE(u_int, netisr_enable[NETISR_MAXPROT]); #define V_netisr_enable VNET(netisr_enable) #endif /* * Per-CPU workstream data. See netisr_internal.h for more details. */ DPCPU_DEFINE(struct netisr_workstream, nws); /* * Map contiguous values between 0 and nws_count into CPU IDs appropriate for * accessing workstreams. This allows constructions of the form * DPCPU_ID_GET(nws_array[arbitraryvalue % nws_count], nws). */ static u_int nws_array[MAXCPU]; /* * Number of registered workstreams. Will be at most the number of running * CPUs once fully started. */ static u_int nws_count; SYSCTL_UINT(_net_isr, OID_AUTO, numthreads, CTLFLAG_RD, &nws_count, 0, "Number of extant netisr threads."); /* * Synchronization for each workstream: a mutex protects all mutable fields * in each stream, including per-protocol state (mbuf queues). The SWI is * woken up if asynchronous dispatch is required. */ #define NWS_LOCK(s) mtx_lock(&(s)->nws_mtx) #define NWS_LOCK_ASSERT(s) mtx_assert(&(s)->nws_mtx, MA_OWNED) #define NWS_UNLOCK(s) mtx_unlock(&(s)->nws_mtx) #define NWS_SIGNAL(s) swi_sched((s)->nws_swi_cookie, 0) /* * Utility routines for protocols that implement their own mapping of flows * to CPUs. */ u_int netisr_get_cpucount(void) { return (nws_count); } u_int netisr_get_cpuid(u_int cpunumber) { return (nws_array[cpunumber % nws_count]); } /* * The default implementation of flow -> CPU ID mapping. * * Non-static so that protocols can use it to map their own work to specific * CPUs in a manner consistent to netisr for affinity purposes. */ u_int netisr_default_flow2cpu(u_int flowid) { return (nws_array[flowid % nws_count]); } /* * Dispatch tunable and sysctl configuration. */ struct netisr_dispatch_table_entry { u_int ndte_policy; const char *ndte_policy_str; }; static const struct netisr_dispatch_table_entry netisr_dispatch_table[] = { { NETISR_DISPATCH_DEFAULT, "default" }, { NETISR_DISPATCH_DEFERRED, "deferred" }, { NETISR_DISPATCH_HYBRID, "hybrid" }, { NETISR_DISPATCH_DIRECT, "direct" }, }; static void netisr_dispatch_policy_to_str(u_int dispatch_policy, char *buffer, u_int buflen) { const struct netisr_dispatch_table_entry *ndtep; const char *str; u_int i; str = "unknown"; for (i = 0; i < nitems(netisr_dispatch_table); i++) { ndtep = &netisr_dispatch_table[i]; if (ndtep->ndte_policy == dispatch_policy) { str = ndtep->ndte_policy_str; break; } } snprintf(buffer, buflen, "%s", str); } static int netisr_dispatch_policy_from_str(const char *str, u_int *dispatch_policyp) { const struct netisr_dispatch_table_entry *ndtep; u_int i; for (i = 0; i < nitems(netisr_dispatch_table); i++) { ndtep = &netisr_dispatch_table[i]; if (strcmp(ndtep->ndte_policy_str, str) == 0) { *dispatch_policyp = ndtep->ndte_policy; return (0); } } return (EINVAL); } static int sysctl_netisr_dispatch_policy(SYSCTL_HANDLER_ARGS) { char tmp[NETISR_DISPATCH_POLICY_MAXSTR]; u_int dispatch_policy; int error; netisr_dispatch_policy_to_str(netisr_dispatch_policy, tmp, sizeof(tmp)); error = sysctl_handle_string(oidp, tmp, sizeof(tmp), req); if (error == 0 && req->newptr != NULL) { error = netisr_dispatch_policy_from_str(tmp, &dispatch_policy); if (error == 0 && dispatch_policy == NETISR_DISPATCH_DEFAULT) error = EINVAL; if (error == 0) netisr_dispatch_policy = dispatch_policy; } return (error); } /* * Register a new netisr handler, which requires initializing per-protocol * fields for each workstream. All netisr work is briefly suspended while * the protocol is installed. */ void netisr_register(const struct netisr_handler *nhp) { VNET_ITERATOR_DECL(vnet_iter); struct netisr_work *npwp; const char *name; u_int i, proto; proto = nhp->nh_proto; name = nhp->nh_name; /* * Test that the requested registration is valid. */ KASSERT(nhp->nh_name != NULL, ("%s: nh_name NULL for %u", __func__, proto)); KASSERT(nhp->nh_handler != NULL, ("%s: nh_handler NULL for %s", __func__, name)); KASSERT(nhp->nh_policy == NETISR_POLICY_SOURCE || nhp->nh_policy == NETISR_POLICY_FLOW || nhp->nh_policy == NETISR_POLICY_CPU, ("%s: unsupported nh_policy %u for %s", __func__, nhp->nh_policy, name)); KASSERT(nhp->nh_policy == NETISR_POLICY_FLOW || nhp->nh_m2flow == NULL, ("%s: nh_policy != FLOW but m2flow defined for %s", __func__, name)); KASSERT(nhp->nh_policy == NETISR_POLICY_CPU || nhp->nh_m2cpuid == NULL, ("%s: nh_policy != CPU but m2cpuid defined for %s", __func__, name)); KASSERT(nhp->nh_policy != NETISR_POLICY_CPU || nhp->nh_m2cpuid != NULL, ("%s: nh_policy == CPU but m2cpuid not defined for %s", __func__, name)); KASSERT(nhp->nh_dispatch == NETISR_DISPATCH_DEFAULT || nhp->nh_dispatch == NETISR_DISPATCH_DEFERRED || nhp->nh_dispatch == NETISR_DISPATCH_HYBRID || nhp->nh_dispatch == NETISR_DISPATCH_DIRECT, ("%s: invalid nh_dispatch (%u)", __func__, nhp->nh_dispatch)); KASSERT(proto < NETISR_MAXPROT, ("%s(%u, %s): protocol too big", __func__, proto, name)); /* * Test that no existing registration exists for this protocol. */ NETISR_WLOCK(); KASSERT(netisr_proto[proto].np_name == NULL, ("%s(%u, %s): name present", __func__, proto, name)); KASSERT(netisr_proto[proto].np_handler == NULL, ("%s(%u, %s): handler present", __func__, proto, name)); netisr_proto[proto].np_name = name; netisr_proto[proto].np_handler = nhp->nh_handler; netisr_proto[proto].np_m2flow = nhp->nh_m2flow; netisr_proto[proto].np_m2cpuid = nhp->nh_m2cpuid; netisr_proto[proto].np_drainedcpu = nhp->nh_drainedcpu; if (nhp->nh_qlimit == 0) netisr_proto[proto].np_qlimit = netisr_defaultqlimit; else if (nhp->nh_qlimit > netisr_maxqlimit) { printf("%s: %s requested queue limit %u capped to " "net.isr.maxqlimit %u\n", __func__, name, nhp->nh_qlimit, netisr_maxqlimit); netisr_proto[proto].np_qlimit = netisr_maxqlimit; } else netisr_proto[proto].np_qlimit = nhp->nh_qlimit; netisr_proto[proto].np_policy = nhp->nh_policy; netisr_proto[proto].np_dispatch = nhp->nh_dispatch; CPU_FOREACH(i) { npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; bzero(npwp, sizeof(*npwp)); npwp->nw_qlimit = netisr_proto[proto].np_qlimit; } #ifdef VIMAGE /* * Test that we are in vnet0 and have a curvnet set. */ KASSERT(curvnet != NULL, ("%s: curvnet is NULL", __func__)); KASSERT(IS_DEFAULT_VNET(curvnet), ("%s: curvnet %p is not vnet0 %p", __func__, curvnet, vnet0)); VNET_LIST_RLOCK_NOSLEEP(); VNET_FOREACH(vnet_iter) { CURVNET_SET(vnet_iter); V_netisr_enable[proto] = 1; CURVNET_RESTORE(); } VNET_LIST_RUNLOCK_NOSLEEP(); #endif NETISR_WUNLOCK(); } /* * Clear drop counters across all workstreams for a protocol. */ void netisr_clearqdrops(const struct netisr_handler *nhp) { struct netisr_work *npwp; #ifdef INVARIANTS const char *name; #endif u_int i, proto; proto = nhp->nh_proto; #ifdef INVARIANTS name = nhp->nh_name; #endif KASSERT(proto < NETISR_MAXPROT, ("%s(%u): protocol too big for %s", __func__, proto, name)); NETISR_WLOCK(); KASSERT(netisr_proto[proto].np_handler != NULL, ("%s(%u): protocol not registered for %s", __func__, proto, name)); CPU_FOREACH(i) { npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; npwp->nw_qdrops = 0; } NETISR_WUNLOCK(); } /* * Query current drop counters across all workstreams for a protocol. */ void netisr_getqdrops(const struct netisr_handler *nhp, u_int64_t *qdropp) { struct netisr_work *npwp; struct rm_priotracker tracker; #ifdef INVARIANTS const char *name; #endif u_int i, proto; *qdropp = 0; proto = nhp->nh_proto; #ifdef INVARIANTS name = nhp->nh_name; #endif KASSERT(proto < NETISR_MAXPROT, ("%s(%u): protocol too big for %s", __func__, proto, name)); NETISR_RLOCK(&tracker); KASSERT(netisr_proto[proto].np_handler != NULL, ("%s(%u): protocol not registered for %s", __func__, proto, name)); CPU_FOREACH(i) { npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; *qdropp += npwp->nw_qdrops; } NETISR_RUNLOCK(&tracker); } /* * Query current per-workstream queue limit for a protocol. */ void netisr_getqlimit(const struct netisr_handler *nhp, u_int *qlimitp) { struct rm_priotracker tracker; #ifdef INVARIANTS const char *name; #endif u_int proto; proto = nhp->nh_proto; #ifdef INVARIANTS name = nhp->nh_name; #endif KASSERT(proto < NETISR_MAXPROT, ("%s(%u): protocol too big for %s", __func__, proto, name)); NETISR_RLOCK(&tracker); KASSERT(netisr_proto[proto].np_handler != NULL, ("%s(%u): protocol not registered for %s", __func__, proto, name)); *qlimitp = netisr_proto[proto].np_qlimit; NETISR_RUNLOCK(&tracker); } /* * Update the queue limit across per-workstream queues for a protocol. We * simply change the limits, and don't drain overflowed packets as they will * (hopefully) take care of themselves shortly. */ int netisr_setqlimit(const struct netisr_handler *nhp, u_int qlimit) { struct netisr_work *npwp; #ifdef INVARIANTS const char *name; #endif u_int i, proto; if (qlimit > netisr_maxqlimit) return (EINVAL); proto = nhp->nh_proto; #ifdef INVARIANTS name = nhp->nh_name; #endif KASSERT(proto < NETISR_MAXPROT, ("%s(%u): protocol too big for %s", __func__, proto, name)); NETISR_WLOCK(); KASSERT(netisr_proto[proto].np_handler != NULL, ("%s(%u): protocol not registered for %s", __func__, proto, name)); netisr_proto[proto].np_qlimit = qlimit; CPU_FOREACH(i) { npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; npwp->nw_qlimit = qlimit; } NETISR_WUNLOCK(); return (0); } /* * Drain all packets currently held in a particular protocol work queue. */ static void netisr_drain_proto(struct netisr_work *npwp) { struct mbuf *m; /* * We would assert the lock on the workstream but it's not passed in. */ while ((m = npwp->nw_head) != NULL) { npwp->nw_head = m->m_nextpkt; m->m_nextpkt = NULL; if (npwp->nw_head == NULL) npwp->nw_tail = NULL; npwp->nw_len--; m_freem(m); } KASSERT(npwp->nw_tail == NULL, ("%s: tail", __func__)); KASSERT(npwp->nw_len == 0, ("%s: len", __func__)); } /* * Remove the registration of a network protocol, which requires clearing * per-protocol fields across all workstreams, including freeing all mbufs in * the queues at time of unregister. All work in netisr is briefly suspended * while this takes place. */ void netisr_unregister(const struct netisr_handler *nhp) { VNET_ITERATOR_DECL(vnet_iter); struct netisr_work *npwp; #ifdef INVARIANTS const char *name; #endif u_int i, proto; proto = nhp->nh_proto; #ifdef INVARIANTS name = nhp->nh_name; #endif KASSERT(proto < NETISR_MAXPROT, ("%s(%u): protocol too big for %s", __func__, proto, name)); NETISR_WLOCK(); KASSERT(netisr_proto[proto].np_handler != NULL, ("%s(%u): protocol not registered for %s", __func__, proto, name)); #ifdef VIMAGE VNET_LIST_RLOCK_NOSLEEP(); VNET_FOREACH(vnet_iter) { CURVNET_SET(vnet_iter); V_netisr_enable[proto] = 0; CURVNET_RESTORE(); } VNET_LIST_RUNLOCK_NOSLEEP(); #endif netisr_proto[proto].np_name = NULL; netisr_proto[proto].np_handler = NULL; netisr_proto[proto].np_m2flow = NULL; netisr_proto[proto].np_m2cpuid = NULL; netisr_proto[proto].np_qlimit = 0; netisr_proto[proto].np_policy = 0; CPU_FOREACH(i) { npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; netisr_drain_proto(npwp); bzero(npwp, sizeof(*npwp)); } NETISR_WUNLOCK(); } #ifdef VIMAGE void netisr_register_vnet(const struct netisr_handler *nhp) { u_int proto; proto = nhp->nh_proto; KASSERT(curvnet != NULL, ("%s: curvnet is NULL", __func__)); KASSERT(proto < NETISR_MAXPROT, ("%s(%u): protocol too big for %s", __func__, proto, nhp->nh_name)); NETISR_WLOCK(); KASSERT(netisr_proto[proto].np_handler != NULL, ("%s(%u): protocol not registered for %s", __func__, proto, nhp->nh_name)); V_netisr_enable[proto] = 1; NETISR_WUNLOCK(); } static void netisr_drain_proto_vnet(struct vnet *vnet, u_int proto) { struct netisr_workstream *nwsp; struct netisr_work *npwp; struct mbuf *m, *mp, *n, *ne; u_int i; KASSERT(vnet != NULL, ("%s: vnet is NULL", __func__)); NETISR_LOCK_ASSERT(); CPU_FOREACH(i) { nwsp = DPCPU_ID_PTR(i, nws); if (nwsp->nws_intr_event == NULL) continue; npwp = &nwsp->nws_work[proto]; NWS_LOCK(nwsp); /* * Rather than dissecting and removing mbufs from the middle * of the chain, we build a new chain if the packet stays and * update the head and tail pointers at the end. All packets * matching the given vnet are freed. */ m = npwp->nw_head; n = ne = NULL; while (m != NULL) { mp = m; m = m->m_nextpkt; mp->m_nextpkt = NULL; if (mp->m_pkthdr.rcvif->if_vnet != vnet) { if (n == NULL) { n = ne = mp; } else { ne->m_nextpkt = mp; ne = mp; } continue; } /* This is a packet in the selected vnet. Free it. */ npwp->nw_len--; m_freem(mp); } npwp->nw_head = n; npwp->nw_tail = ne; NWS_UNLOCK(nwsp); } } void netisr_unregister_vnet(const struct netisr_handler *nhp) { u_int proto; proto = nhp->nh_proto; KASSERT(curvnet != NULL, ("%s: curvnet is NULL", __func__)); KASSERT(proto < NETISR_MAXPROT, ("%s(%u): protocol too big for %s", __func__, proto, nhp->nh_name)); NETISR_WLOCK(); KASSERT(netisr_proto[proto].np_handler != NULL, ("%s(%u): protocol not registered for %s", __func__, proto, nhp->nh_name)); V_netisr_enable[proto] = 0; netisr_drain_proto_vnet(curvnet, proto); NETISR_WUNLOCK(); } #endif /* * Compose the global and per-protocol policies on dispatch, and return the * dispatch policy to use. */ static u_int netisr_get_dispatch(struct netisr_proto *npp) { /* * Protocol-specific configuration overrides the global default. */ if (npp->np_dispatch != NETISR_DISPATCH_DEFAULT) return (npp->np_dispatch); return (netisr_dispatch_policy); } /* * Look up the workstream given a packet and source identifier. Do this by * checking the protocol's policy, and optionally call out to the protocol * for assistance if required. */ static struct mbuf * netisr_select_cpuid(struct netisr_proto *npp, u_int dispatch_policy, uintptr_t source, struct mbuf *m, u_int *cpuidp) { struct ifnet *ifp; u_int policy; NETISR_LOCK_ASSERT(); /* * In the event we have only one worker, shortcut and deliver to it * without further ado. */ if (nws_count == 1) { *cpuidp = nws_array[0]; return (m); } /* * What happens next depends on the policy selected by the protocol. * If we want to support per-interface policies, we should do that * here first. */ policy = npp->np_policy; if (policy == NETISR_POLICY_CPU) { m = npp->np_m2cpuid(m, source, cpuidp); if (m == NULL) return (NULL); /* * It's possible for a protocol not to have a good idea about * where to process a packet, in which case we fall back on * the netisr code to decide. In the hybrid case, return the * current CPU ID, which will force an immediate direct * dispatch. In the queued case, fall back on the SOURCE * policy. */ if (*cpuidp != NETISR_CPUID_NONE) { *cpuidp = netisr_get_cpuid(*cpuidp); return (m); } if (dispatch_policy == NETISR_DISPATCH_HYBRID) { *cpuidp = netisr_get_cpuid(curcpu); return (m); } policy = NETISR_POLICY_SOURCE; } if (policy == NETISR_POLICY_FLOW) { if (M_HASHTYPE_GET(m) == M_HASHTYPE_NONE && npp->np_m2flow != NULL) { m = npp->np_m2flow(m, source); if (m == NULL) return (NULL); } if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { *cpuidp = netisr_default_flow2cpu(m->m_pkthdr.flowid); return (m); } policy = NETISR_POLICY_SOURCE; } KASSERT(policy == NETISR_POLICY_SOURCE, ("%s: invalid policy %u for %s", __func__, npp->np_policy, npp->np_name)); ifp = m->m_pkthdr.rcvif; if (ifp != NULL) *cpuidp = nws_array[(ifp->if_index + source) % nws_count]; else *cpuidp = nws_array[source % nws_count]; return (m); } /* * Process packets associated with a workstream and protocol. For reasons of * fairness, we process up to one complete netisr queue at a time, moving the * queue to a stack-local queue for processing, but do not loop refreshing * from the global queue. The caller is responsible for deciding whether to * loop, and for setting the NWS_RUNNING flag. The passed workstream will be * locked on entry and relocked before return, but will be released while * processing. The number of packets processed is returned. */ static u_int netisr_process_workstream_proto(struct netisr_workstream *nwsp, u_int proto) { struct netisr_work local_npw, *npwp; u_int handled; struct mbuf *m; NETISR_LOCK_ASSERT(); NWS_LOCK_ASSERT(nwsp); KASSERT(nwsp->nws_flags & NWS_RUNNING, ("%s(%u): not running", __func__, proto)); KASSERT(proto >= 0 && proto < NETISR_MAXPROT, ("%s(%u): invalid proto\n", __func__, proto)); npwp = &nwsp->nws_work[proto]; if (npwp->nw_len == 0) return (0); /* * Move the global work queue to a thread-local work queue. * * Notice that this means the effective maximum length of the queue * is actually twice that of the maximum queue length specified in * the protocol registration call. */ handled = npwp->nw_len; local_npw = *npwp; npwp->nw_head = NULL; npwp->nw_tail = NULL; npwp->nw_len = 0; nwsp->nws_pendingbits &= ~(1 << proto); NWS_UNLOCK(nwsp); while ((m = local_npw.nw_head) != NULL) { local_npw.nw_head = m->m_nextpkt; m->m_nextpkt = NULL; if (local_npw.nw_head == NULL) local_npw.nw_tail = NULL; local_npw.nw_len--; VNET_ASSERT(m->m_pkthdr.rcvif != NULL, ("%s:%d rcvif == NULL: m=%p", __func__, __LINE__, m)); CURVNET_SET(m->m_pkthdr.rcvif->if_vnet); netisr_proto[proto].np_handler(m); CURVNET_RESTORE(); } KASSERT(local_npw.nw_len == 0, ("%s(%u): len %u", __func__, proto, local_npw.nw_len)); if (netisr_proto[proto].np_drainedcpu) netisr_proto[proto].np_drainedcpu(nwsp->nws_cpu); NWS_LOCK(nwsp); npwp->nw_handled += handled; return (handled); } /* * SWI handler for netisr -- processes packets in a set of workstreams that * it owns, woken up by calls to NWS_SIGNAL(). If this workstream is already * being direct dispatched, go back to sleep and wait for the dispatching * thread to wake us up again. */ static void swi_net(void *arg) { #ifdef NETISR_LOCKING struct rm_priotracker tracker; #endif struct netisr_workstream *nwsp; u_int bits, prot; nwsp = arg; #ifdef DEVICE_POLLING KASSERT(nws_count == 1, ("%s: device_polling but nws_count != 1", __func__)); netisr_poll(); #endif #ifdef NETISR_LOCKING NETISR_RLOCK(&tracker); #endif NWS_LOCK(nwsp); KASSERT(!(nwsp->nws_flags & NWS_RUNNING), ("swi_net: running")); if (nwsp->nws_flags & NWS_DISPATCHING) goto out; nwsp->nws_flags |= NWS_RUNNING; nwsp->nws_flags &= ~NWS_SCHEDULED; while ((bits = nwsp->nws_pendingbits) != 0) { while ((prot = ffs(bits)) != 0) { prot--; bits &= ~(1 << prot); (void)netisr_process_workstream_proto(nwsp, prot); } } nwsp->nws_flags &= ~NWS_RUNNING; out: NWS_UNLOCK(nwsp); #ifdef NETISR_LOCKING NETISR_RUNLOCK(&tracker); #endif #ifdef DEVICE_POLLING netisr_pollmore(); #endif } static int netisr_queue_workstream(struct netisr_workstream *nwsp, u_int proto, struct netisr_work *npwp, struct mbuf *m, int *dosignalp) { NWS_LOCK_ASSERT(nwsp); *dosignalp = 0; if (npwp->nw_len < npwp->nw_qlimit) { m->m_nextpkt = NULL; if (npwp->nw_head == NULL) { npwp->nw_head = m; npwp->nw_tail = m; } else { npwp->nw_tail->m_nextpkt = m; npwp->nw_tail = m; } npwp->nw_len++; if (npwp->nw_len > npwp->nw_watermark) npwp->nw_watermark = npwp->nw_len; /* * We must set the bit regardless of NWS_RUNNING, so that * swi_net() keeps calling netisr_process_workstream_proto(). */ nwsp->nws_pendingbits |= (1 << proto); if (!(nwsp->nws_flags & (NWS_RUNNING | NWS_DISPATCHING | NWS_SCHEDULED))) { nwsp->nws_flags |= NWS_SCHEDULED; *dosignalp = 1; /* Defer until unlocked. */ } npwp->nw_queued++; return (0); } else { m_freem(m); npwp->nw_qdrops++; return (ENOBUFS); } } static int netisr_queue_internal(u_int proto, struct mbuf *m, u_int cpuid) { struct netisr_workstream *nwsp; struct netisr_work *npwp; int dosignal, error; #ifdef NETISR_LOCKING NETISR_LOCK_ASSERT(); #endif KASSERT(cpuid <= mp_maxid, ("%s: cpuid too big (%u, %u)", __func__, cpuid, mp_maxid)); KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__, cpuid)); dosignal = 0; error = 0; nwsp = DPCPU_ID_PTR(cpuid, nws); npwp = &nwsp->nws_work[proto]; NWS_LOCK(nwsp); error = netisr_queue_workstream(nwsp, proto, npwp, m, &dosignal); NWS_UNLOCK(nwsp); if (dosignal) NWS_SIGNAL(nwsp); return (error); } int netisr_queue_src(u_int proto, uintptr_t source, struct mbuf *m) { #ifdef NETISR_LOCKING struct rm_priotracker tracker; #endif u_int cpuid; int error; KASSERT(proto < NETISR_MAXPROT, ("%s: invalid proto %u", __func__, proto)); #ifdef NETISR_LOCKING NETISR_RLOCK(&tracker); #endif KASSERT(netisr_proto[proto].np_handler != NULL, ("%s: invalid proto %u", __func__, proto)); #ifdef VIMAGE if (V_netisr_enable[proto] == 0) { m_freem(m); return (ENOPROTOOPT); } #endif m = netisr_select_cpuid(&netisr_proto[proto], NETISR_DISPATCH_DEFERRED, source, m, &cpuid); if (m != NULL) { KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__, cpuid)); error = netisr_queue_internal(proto, m, cpuid); } else error = ENOBUFS; #ifdef NETISR_LOCKING NETISR_RUNLOCK(&tracker); #endif return (error); } int netisr_queue(u_int proto, struct mbuf *m) { return (netisr_queue_src(proto, 0, m)); } /* * Dispatch a packet for netisr processing; direct dispatch is permitted by * calling context. */ int netisr_dispatch_src(u_int proto, uintptr_t source, struct mbuf *m) { #ifdef NETISR_LOCKING struct rm_priotracker tracker; #endif struct netisr_workstream *nwsp; struct netisr_proto *npp; struct netisr_work *npwp; int dosignal, error; u_int cpuid, dispatch_policy; KASSERT(proto < NETISR_MAXPROT, ("%s: invalid proto %u", __func__, proto)); #ifdef NETISR_LOCKING NETISR_RLOCK(&tracker); #endif npp = &netisr_proto[proto]; KASSERT(npp->np_handler != NULL, ("%s: invalid proto %u", __func__, proto)); #ifdef VIMAGE if (V_netisr_enable[proto] == 0) { m_freem(m); return (ENOPROTOOPT); } #endif dispatch_policy = netisr_get_dispatch(npp); if (dispatch_policy == NETISR_DISPATCH_DEFERRED) return (netisr_queue_src(proto, source, m)); /* * If direct dispatch is forced, then unconditionally dispatch * without a formal CPU selection. Borrow the current CPU's stats, * even if there's no worker on it. In this case we don't update * nws_flags because all netisr processing will be source ordered due * to always being forced to directly dispatch. */ if (dispatch_policy == NETISR_DISPATCH_DIRECT) { nwsp = DPCPU_PTR(nws); npwp = &nwsp->nws_work[proto]; npwp->nw_dispatched++; npwp->nw_handled++; netisr_proto[proto].np_handler(m); error = 0; goto out_unlock; } KASSERT(dispatch_policy == NETISR_DISPATCH_HYBRID, ("%s: unknown dispatch policy (%u)", __func__, dispatch_policy)); /* * Otherwise, we execute in a hybrid mode where we will try to direct * dispatch if we're on the right CPU and the netisr worker isn't * already running. */ sched_pin(); m = netisr_select_cpuid(&netisr_proto[proto], NETISR_DISPATCH_HYBRID, source, m, &cpuid); if (m == NULL) { error = ENOBUFS; goto out_unpin; } KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__, cpuid)); if (cpuid != curcpu) goto queue_fallback; nwsp = DPCPU_PTR(nws); npwp = &nwsp->nws_work[proto]; /*- * We are willing to direct dispatch only if three conditions hold: * * (1) The netisr worker isn't already running, * (2) Another thread isn't already directly dispatching, and * (3) The netisr hasn't already been woken up. */ NWS_LOCK(nwsp); if (nwsp->nws_flags & (NWS_RUNNING | NWS_DISPATCHING | NWS_SCHEDULED)) { error = netisr_queue_workstream(nwsp, proto, npwp, m, &dosignal); NWS_UNLOCK(nwsp); if (dosignal) NWS_SIGNAL(nwsp); goto out_unpin; } /* * The current thread is now effectively the netisr worker, so set * the dispatching flag to prevent concurrent processing of the * stream from another thread (even the netisr worker), which could * otherwise lead to effective misordering of the stream. */ nwsp->nws_flags |= NWS_DISPATCHING; NWS_UNLOCK(nwsp); netisr_proto[proto].np_handler(m); NWS_LOCK(nwsp); nwsp->nws_flags &= ~NWS_DISPATCHING; npwp->nw_handled++; npwp->nw_hybrid_dispatched++; /* * If other work was enqueued by another thread while we were direct * dispatching, we need to signal the netisr worker to do that work. * In the future, we might want to do some of that work in the * current thread, rather than trigger further context switches. If * so, we'll want to establish a reasonable bound on the work done in * the "borrowed" context. */ if (nwsp->nws_pendingbits != 0) { nwsp->nws_flags |= NWS_SCHEDULED; dosignal = 1; } else dosignal = 0; NWS_UNLOCK(nwsp); if (dosignal) NWS_SIGNAL(nwsp); error = 0; goto out_unpin; queue_fallback: error = netisr_queue_internal(proto, m, cpuid); out_unpin: sched_unpin(); out_unlock: #ifdef NETISR_LOCKING NETISR_RUNLOCK(&tracker); #endif return (error); } int netisr_dispatch(u_int proto, struct mbuf *m) { return (netisr_dispatch_src(proto, 0, m)); } #ifdef DEVICE_POLLING /* * Kernel polling borrows a netisr thread to run interface polling in; this * function allows kernel polling to request that the netisr thread be * scheduled even if no packets are pending for protocols. */ void netisr_sched_poll(void) { struct netisr_workstream *nwsp; nwsp = DPCPU_ID_PTR(nws_array[0], nws); NWS_SIGNAL(nwsp); } #endif static void netisr_start_swi(u_int cpuid, struct pcpu *pc) { char swiname[12]; struct netisr_workstream *nwsp; int error; KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__, cpuid)); nwsp = DPCPU_ID_PTR(cpuid, nws); mtx_init(&nwsp->nws_mtx, "netisr_mtx", NULL, MTX_DEF); nwsp->nws_cpu = cpuid; snprintf(swiname, sizeof(swiname), "netisr %u", cpuid); error = swi_add(&nwsp->nws_intr_event, swiname, swi_net, nwsp, SWI_NET, INTR_MPSAFE, &nwsp->nws_swi_cookie); if (error) panic("%s: swi_add %d", __func__, error); pc->pc_netisr = nwsp->nws_intr_event; if (netisr_bindthreads) { error = intr_event_bind(nwsp->nws_intr_event, cpuid); if (error != 0) printf("%s: cpu %u: intr_event_bind: %d", __func__, cpuid, error); } NETISR_WLOCK(); nws_array[nws_count] = nwsp->nws_cpu; nws_count++; NETISR_WUNLOCK(); } /* * Initialize the netisr subsystem. We rely on BSS and static initialization * of most fields in global data structures. * * Start a worker thread for the boot CPU so that we can support network * traffic immediately in case the network stack is used before additional * CPUs are started (for example, diskless boot). */ static void netisr_init(void *arg) { +#ifdef EARLY_AP_STARTUP struct pcpu *pc; +#endif NETISR_LOCK_INIT(); if (netisr_maxthreads == 0 || netisr_maxthreads < -1 ) netisr_maxthreads = 1; /* default behavior */ else if (netisr_maxthreads == -1) netisr_maxthreads = mp_ncpus; /* use max cpus */ if (netisr_maxthreads > mp_ncpus) { printf("netisr_init: forcing maxthreads from %d to %d\n", netisr_maxthreads, mp_ncpus); netisr_maxthreads = mp_ncpus; } if (netisr_defaultqlimit > netisr_maxqlimit) { printf("netisr_init: forcing defaultqlimit from %d to %d\n", netisr_defaultqlimit, netisr_maxqlimit); netisr_defaultqlimit = netisr_maxqlimit; } #ifdef DEVICE_POLLING /* * The device polling code is not yet aware of how to deal with * multiple netisr threads, so for the time being compiling in device * polling disables parallel netisr workers. */ if (netisr_maxthreads != 1 || netisr_bindthreads != 0) { printf("netisr_init: forcing maxthreads to 1 and " "bindthreads to 0 for device polling\n"); netisr_maxthreads = 1; netisr_bindthreads = 0; } #endif #ifdef EARLY_AP_STARTUP STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { if (nws_count >= netisr_maxthreads) break; netisr_start_swi(pc->pc_cpuid, pc); } #else - pc = get_pcpu(); - netisr_start_swi(pc->pc_cpuid, pc); + netisr_start_swi(curcpu, pcpu_find(curcpu)); #endif } SYSINIT(netisr_init, SI_SUB_SOFTINTR, SI_ORDER_FIRST, netisr_init, NULL); #ifndef EARLY_AP_STARTUP /* * Start worker threads for additional CPUs. No attempt to gracefully handle * work reassignment, we don't yet support dynamic reconfiguration. */ static void netisr_start(void *arg) { struct pcpu *pc; STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { if (nws_count >= netisr_maxthreads) break; /* Worker will already be present for boot CPU. */ if (pc->pc_netisr != NULL) continue; netisr_start_swi(pc->pc_cpuid, pc); } } SYSINIT(netisr_start, SI_SUB_SMP, SI_ORDER_MIDDLE, netisr_start, NULL); #endif /* * Sysctl monitoring for netisr: query a list of registered protocols. */ static int sysctl_netisr_proto(SYSCTL_HANDLER_ARGS) { struct rm_priotracker tracker; struct sysctl_netisr_proto *snpp, *snp_array; struct netisr_proto *npp; u_int counter, proto; int error; if (req->newptr != NULL) return (EINVAL); snp_array = malloc(sizeof(*snp_array) * NETISR_MAXPROT, M_TEMP, M_ZERO | M_WAITOK); counter = 0; NETISR_RLOCK(&tracker); for (proto = 0; proto < NETISR_MAXPROT; proto++) { npp = &netisr_proto[proto]; if (npp->np_name == NULL) continue; snpp = &snp_array[counter]; snpp->snp_version = sizeof(*snpp); strlcpy(snpp->snp_name, npp->np_name, NETISR_NAMEMAXLEN); snpp->snp_proto = proto; snpp->snp_qlimit = npp->np_qlimit; snpp->snp_policy = npp->np_policy; snpp->snp_dispatch = npp->np_dispatch; if (npp->np_m2flow != NULL) snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW; if (npp->np_m2cpuid != NULL) snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID; if (npp->np_drainedcpu != NULL) snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU; counter++; } NETISR_RUNLOCK(&tracker); KASSERT(counter <= NETISR_MAXPROT, ("sysctl_netisr_proto: counter too big (%d)", counter)); error = SYSCTL_OUT(req, snp_array, sizeof(*snp_array) * counter); free(snp_array, M_TEMP); return (error); } SYSCTL_PROC(_net_isr, OID_AUTO, proto, CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_proto, "S,sysctl_netisr_proto", "Return list of protocols registered with netisr"); /* * Sysctl monitoring for netisr: query a list of workstreams. */ static int sysctl_netisr_workstream(SYSCTL_HANDLER_ARGS) { struct rm_priotracker tracker; struct sysctl_netisr_workstream *snwsp, *snws_array; struct netisr_workstream *nwsp; u_int counter, cpuid; int error; if (req->newptr != NULL) return (EINVAL); snws_array = malloc(sizeof(*snws_array) * MAXCPU, M_TEMP, M_ZERO | M_WAITOK); counter = 0; NETISR_RLOCK(&tracker); CPU_FOREACH(cpuid) { nwsp = DPCPU_ID_PTR(cpuid, nws); if (nwsp->nws_intr_event == NULL) continue; NWS_LOCK(nwsp); snwsp = &snws_array[counter]; snwsp->snws_version = sizeof(*snwsp); /* * For now, we equate workstream IDs and CPU IDs in the * kernel, but expose them independently to userspace in case * that assumption changes in the future. */ snwsp->snws_wsid = cpuid; snwsp->snws_cpu = cpuid; if (nwsp->nws_intr_event != NULL) snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR; NWS_UNLOCK(nwsp); counter++; } NETISR_RUNLOCK(&tracker); KASSERT(counter <= MAXCPU, ("sysctl_netisr_workstream: counter too big (%d)", counter)); error = SYSCTL_OUT(req, snws_array, sizeof(*snws_array) * counter); free(snws_array, M_TEMP); return (error); } SYSCTL_PROC(_net_isr, OID_AUTO, workstream, CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_workstream, "S,sysctl_netisr_workstream", "Return list of workstreams implemented by netisr"); /* * Sysctl monitoring for netisr: query per-protocol data across all * workstreams. */ static int sysctl_netisr_work(SYSCTL_HANDLER_ARGS) { struct rm_priotracker tracker; struct sysctl_netisr_work *snwp, *snw_array; struct netisr_workstream *nwsp; struct netisr_proto *npp; struct netisr_work *nwp; u_int counter, cpuid, proto; int error; if (req->newptr != NULL) return (EINVAL); snw_array = malloc(sizeof(*snw_array) * MAXCPU * NETISR_MAXPROT, M_TEMP, M_ZERO | M_WAITOK); counter = 0; NETISR_RLOCK(&tracker); CPU_FOREACH(cpuid) { nwsp = DPCPU_ID_PTR(cpuid, nws); if (nwsp->nws_intr_event == NULL) continue; NWS_LOCK(nwsp); for (proto = 0; proto < NETISR_MAXPROT; proto++) { npp = &netisr_proto[proto]; if (npp->np_name == NULL) continue; nwp = &nwsp->nws_work[proto]; snwp = &snw_array[counter]; snwp->snw_version = sizeof(*snwp); snwp->snw_wsid = cpuid; /* See comment above. */ snwp->snw_proto = proto; snwp->snw_len = nwp->nw_len; snwp->snw_watermark = nwp->nw_watermark; snwp->snw_dispatched = nwp->nw_dispatched; snwp->snw_hybrid_dispatched = nwp->nw_hybrid_dispatched; snwp->snw_qdrops = nwp->nw_qdrops; snwp->snw_queued = nwp->nw_queued; snwp->snw_handled = nwp->nw_handled; counter++; } NWS_UNLOCK(nwsp); } KASSERT(counter <= MAXCPU * NETISR_MAXPROT, ("sysctl_netisr_work: counter too big (%d)", counter)); NETISR_RUNLOCK(&tracker); error = SYSCTL_OUT(req, snw_array, sizeof(*snw_array) * counter); free(snw_array, M_TEMP); return (error); } SYSCTL_PROC(_net_isr, OID_AUTO, work, CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_work, "S,sysctl_netisr_work", "Return list of per-workstream, per-protocol work in netisr"); #ifdef DDB DB_SHOW_COMMAND(netisr, db_show_netisr) { struct netisr_workstream *nwsp; struct netisr_work *nwp; int first, proto; u_int cpuid; db_printf("%3s %6s %5s %5s %5s %8s %8s %8s %8s\n", "CPU", "Proto", "Len", "WMark", "Max", "Disp", "HDisp", "Drop", "Queue"); CPU_FOREACH(cpuid) { nwsp = DPCPU_ID_PTR(cpuid, nws); if (nwsp->nws_intr_event == NULL) continue; first = 1; for (proto = 0; proto < NETISR_MAXPROT; proto++) { if (netisr_proto[proto].np_handler == NULL) continue; nwp = &nwsp->nws_work[proto]; if (first) { db_printf("%3d ", cpuid); first = 0; } else db_printf("%3s ", ""); db_printf( "%6s %5d %5d %5d %8ju %8ju %8ju %8ju\n", netisr_proto[proto].np_name, nwp->nw_len, nwp->nw_watermark, nwp->nw_qlimit, nwp->nw_dispatched, nwp->nw_hybrid_dispatched, nwp->nw_qdrops, nwp->nw_queued); } } } #endif Index: projects/ipsec/sys/powerpc/include/_types.h =================================================================== --- projects/ipsec/sys/powerpc/include/_types.h (revision 313312) +++ projects/ipsec/sys/powerpc/include/_types.h (revision 313313) @@ -1,165 +1,163 @@ /*- * Copyright (c) 2002 Mike Barcroft * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From: @(#)ansi.h 8.2 (Berkeley) 1/4/94 * From: @(#)types.h 8.3 (Berkeley) 1/5/94 * $FreeBSD$ */ #ifndef _MACHINE__TYPES_H_ #define _MACHINE__TYPES_H_ #ifndef _SYS_CDEFS_H_ #error this file needs sys/cdefs.h as a prerequisite #endif /* * Basic types upon which most other types are built. */ typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; typedef unsigned short __uint16_t; typedef int __int32_t; typedef unsigned int __uint32_t; #ifdef __LP64__ typedef long __int64_t; typedef unsigned long __uint64_t; #else #ifndef lint __extension__ #endif /* LONGLONG */ typedef long long __int64_t; #ifndef lint __extension__ #endif /* LONGLONG */ typedef unsigned long long __uint64_t; #endif /* * Standard type definitions. */ typedef __uint32_t __clock_t; /* clock()... */ typedef double __double_t; typedef float __float_t; #ifdef __LP64__ typedef __int64_t __critical_t; typedef __int64_t __intfptr_t; typedef __int64_t __intptr_t; #else typedef __int32_t __critical_t; typedef __int32_t __intfptr_t; typedef __int32_t __intptr_t; #endif typedef __int64_t __intmax_t; typedef __int32_t __int_fast8_t; typedef __int32_t __int_fast16_t; typedef __int32_t __int_fast32_t; typedef __int64_t __int_fast64_t; typedef __int8_t __int_least8_t; typedef __int16_t __int_least16_t; typedef __int32_t __int_least32_t; typedef __int64_t __int_least64_t; #ifdef __LP64__ typedef __int64_t __ptrdiff_t; /* ptr1 - ptr2 */ typedef __int64_t __register_t; typedef __int64_t __segsz_t; /* segment size (in pages) */ typedef __uint64_t __size_t; /* sizeof() */ typedef __int64_t __ssize_t; /* byte count or error */ typedef __int64_t __time_t; /* time()... */ typedef __uint64_t __uintfptr_t; typedef __uint64_t __uintptr_t; #else typedef __int32_t __ptrdiff_t; /* ptr1 - ptr2 */ typedef __int32_t __register_t; typedef __int32_t __segsz_t; /* segment size (in pages) */ typedef __uint32_t __size_t; /* sizeof() */ typedef __int32_t __ssize_t; /* byte count or error */ typedef __int32_t __time_t; /* time()... */ typedef __uint32_t __uintfptr_t; typedef __uint32_t __uintptr_t; #endif typedef __uint64_t __uintmax_t; typedef __uint32_t __uint_fast8_t; typedef __uint32_t __uint_fast16_t; typedef __uint32_t __uint_fast32_t; typedef __uint64_t __uint_fast64_t; typedef __uint8_t __uint_least8_t; typedef __uint16_t __uint_least16_t; typedef __uint32_t __uint_least32_t; typedef __uint64_t __uint_least64_t; #ifdef __LP64__ typedef __uint64_t __u_register_t; typedef __uint64_t __vm_offset_t; typedef __uint64_t __vm_paddr_t; typedef __uint64_t __vm_size_t; #else typedef __uint32_t __u_register_t; typedef __uint32_t __vm_offset_t; #ifdef BOOKE typedef __uint64_t __vm_paddr_t; #else typedef __uint32_t __vm_paddr_t; #endif typedef __uint32_t __vm_size_t; #endif -typedef __int64_t __vm_ooffset_t; -typedef __uint64_t __vm_pindex_t; typedef int ___wchar_t; #define __WCHAR_MIN __INT_MIN /* min value for a wchar_t */ #define __WCHAR_MAX __INT_MAX /* max value for a wchar_t */ /* * Unusual type definitions. */ #if defined(__GNUCLIKE_BUILTIN_VARARGS) typedef __builtin_va_list __va_list; /* internally known to gcc */ #else typedef struct { char __gpr; char __fpr; char __pad[2]; char *__stack; char *__base; } __va_list; #endif /* post GCC 2.95 */ #if defined(__GNUC_VA_LIST_COMPATIBILITY) && !defined(__GNUC_VA_LIST) \ && !defined(__NO_GNUC_VA_LIST) #define __GNUC_VA_LIST typedef __va_list __gnuc_va_list; /* compatibility w/GNU headers*/ #endif #endif /* !_MACHINE__TYPES_H_ */ Index: projects/ipsec/sys/powerpc/include/cpufunc.h =================================================================== --- projects/ipsec/sys/powerpc/include/cpufunc.h (revision 313312) +++ projects/ipsec/sys/powerpc/include/cpufunc.h (revision 313313) @@ -1,215 +1,215 @@ /*- * Copyright (c) 1998 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _MACHINE_CPUFUNC_H_ #define _MACHINE_CPUFUNC_H_ #ifdef _KERNEL #include #include #include struct thread; #ifdef KDB void breakpoint(void); #else static __inline void breakpoint(void) { return; } #endif /* CPU register mangling inlines */ static __inline void mtmsr(register_t value) { __asm __volatile ("mtmsr %0; isync" :: "r"(value)); } #ifdef __powerpc64__ static __inline void mtmsrd(register_t value) { __asm __volatile ("mtmsrd %0; isync" :: "r"(value)); } #endif static __inline register_t mfmsr(void) { register_t value; __asm __volatile ("mfmsr %0" : "=r"(value)); return (value); } #ifndef __powerpc64__ static __inline void mtsrin(vm_offset_t va, register_t value) { __asm __volatile ("mtsrin %0,%1; isync" :: "r"(value), "r"(va)); } static __inline register_t mfsrin(vm_offset_t va) { register_t value; __asm __volatile ("mfsrin %0,%1" : "=r"(value) : "r"(va)); return (value); } #endif static __inline register_t mfctrl(void) { register_t value; __asm __volatile ("mfspr %0,136" : "=r"(value)); return (value); } static __inline void mtdec(register_t value) { __asm __volatile ("mtdec %0" :: "r"(value)); } static __inline register_t mfdec(void) { register_t value; __asm __volatile ("mfdec %0" : "=r"(value)); return (value); } static __inline register_t mfpvr(void) { register_t value; __asm __volatile ("mfpvr %0" : "=r"(value)); return (value); } static __inline u_quad_t mftb(void) { u_quad_t tb; #ifdef __powerpc64__ __asm __volatile ("mftb %0" : "=r"(tb)); #else uint32_t *tbup = (uint32_t *)&tb; uint32_t *tblp = tbup + 1; do { *tbup = mfspr(TBR_TBU); *tblp = mfspr(TBR_TBL); } while (*tbup != mfspr(TBR_TBU)); #endif return (tb); } static __inline void mttb(u_quad_t time) { mtspr(TBR_TBWL, 0); mtspr(TBR_TBWU, (uint32_t)(time >> 32)); mtspr(TBR_TBWL, (uint32_t)(time & 0xffffffff)); } static __inline void eieio(void) { __asm __volatile ("eieio" : : : "memory"); } static __inline void isync(void) { __asm __volatile ("isync" : : : "memory"); } static __inline void powerpc_sync(void) { __asm __volatile ("sync" : : : "memory"); } static __inline register_t intr_disable(void) { register_t msr; msr = mfmsr(); mtmsr(msr & ~PSL_EE); return (msr); } static __inline void intr_restore(register_t msr) { mtmsr(msr); } static __inline struct pcpu * -get_pcpu(void) +powerpc_get_pcpup(void) { struct pcpu *ret; __asm __volatile("mfsprg %0, 0" : "=r"(ret)); return (ret); } #endif /* _KERNEL */ #endif /* !_MACHINE_CPUFUNC_H_ */ Index: projects/ipsec/sys/powerpc/include/pcpu.h =================================================================== --- projects/ipsec/sys/powerpc/include/pcpu.h (revision 313312) +++ projects/ipsec/sys/powerpc/include/pcpu.h (revision 313313) @@ -1,173 +1,173 @@ /*- * Copyright (c) 1999 Luoqi Chen * Copyright (c) Peter Wemm * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _MACHINE_PCPU_H_ #define _MACHINE_PCPU_H_ #include #include #include struct pmap; struct pvo_entry; #define CPUSAVE_LEN 9 #define PCPU_MD_COMMON_FIELDS \ int pc_inside_intr; \ struct pmap *pc_curpmap; /* current pmap */ \ struct thread *pc_fputhread; /* current fpu user */ \ struct thread *pc_vecthread; /* current vec user */ \ uintptr_t pc_hwref; \ uint32_t pc_pir; \ int pc_bsp; \ volatile int pc_awake; \ uint32_t pc_ipimask; \ register_t pc_tempsave[CPUSAVE_LEN]; \ register_t pc_disisave[CPUSAVE_LEN]; \ register_t pc_dbsave[CPUSAVE_LEN]; \ void *pc_restore; #define PCPU_MD_AIM32_FIELDS \ vm_offset_t pc_qmap_addr; \ struct pvo_entry *pc_qmap_pvo; \ struct mtx pc_qmap_lock; \ /* char __pad[0] */ #define PCPU_MD_AIM64_FIELDS \ struct slb pc_slb[64]; \ struct slb **pc_userslb; \ register_t pc_slbsave[18]; \ uint8_t pc_slbstack[1024]; \ vm_offset_t pc_qmap_addr; \ struct pvo_entry *pc_qmap_pvo; \ struct mtx pc_qmap_lock; \ char __pad[1121 - sizeof(struct mtx)] #ifdef __powerpc64__ #define PCPU_MD_AIM_FIELDS PCPU_MD_AIM64_FIELDS #else #define PCPU_MD_AIM_FIELDS PCPU_MD_AIM32_FIELDS #endif #define BOOKE_CRITSAVE_LEN (CPUSAVE_LEN + 2) #define BOOKE_TLB_MAXNEST 3 #define BOOKE_TLB_SAVELEN 16 #define BOOKE_TLBSAVE_LEN (BOOKE_TLB_SAVELEN * BOOKE_TLB_MAXNEST) #define PCPU_MD_BOOKE_FIELDS \ register_t pc_booke_critsave[BOOKE_CRITSAVE_LEN]; \ register_t pc_booke_mchksave[CPUSAVE_LEN]; \ register_t pc_booke_tlbsave[BOOKE_TLBSAVE_LEN]; \ register_t pc_booke_tlb_level; \ vm_offset_t pc_qmap_addr; \ uint32_t *pc_booke_tlb_lock; \ int pc_tid_next; \ char __pad[173] /* Definitions for register offsets within the exception tmp save areas */ #define CPUSAVE_R27 0 /* where r27 gets saved */ #define CPUSAVE_R28 1 /* where r28 gets saved */ #define CPUSAVE_R29 2 /* where r29 gets saved */ #define CPUSAVE_R30 3 /* where r30 gets saved */ #define CPUSAVE_R31 4 /* where r31 gets saved */ #define CPUSAVE_AIM_DAR 5 /* where SPR_DAR gets saved */ #define CPUSAVE_AIM_DSISR 6 /* where SPR_DSISR gets saved */ #define CPUSAVE_BOOKE_DEAR 5 /* where SPR_DEAR gets saved */ #define CPUSAVE_BOOKE_ESR 6 /* where SPR_ESR gets saved */ #define CPUSAVE_SRR0 7 /* where SRR0 gets saved */ #define CPUSAVE_SRR1 8 /* where SRR1 gets saved */ /* Book-E TLBSAVE is more elaborate */ #define TLBSAVE_BOOKE_LR 0 #define TLBSAVE_BOOKE_CR 1 #define TLBSAVE_BOOKE_SRR0 2 #define TLBSAVE_BOOKE_SRR1 3 #define TLBSAVE_BOOKE_R20 4 #define TLBSAVE_BOOKE_R21 5 #define TLBSAVE_BOOKE_R22 6 #define TLBSAVE_BOOKE_R23 7 #define TLBSAVE_BOOKE_R24 8 #define TLBSAVE_BOOKE_R25 9 #define TLBSAVE_BOOKE_R26 10 #define TLBSAVE_BOOKE_R27 11 #define TLBSAVE_BOOKE_R28 12 #define TLBSAVE_BOOKE_R29 13 #define TLBSAVE_BOOKE_R30 14 #define TLBSAVE_BOOKE_R31 15 #ifdef AIM #define PCPU_MD_FIELDS \ PCPU_MD_COMMON_FIELDS \ PCPU_MD_AIM_FIELDS #endif #if defined(BOOKE) #define PCPU_MD_FIELDS \ PCPU_MD_COMMON_FIELDS \ PCPU_MD_BOOKE_FIELDS #endif /* * Catch-all for ports (e.g. lsof, used by gtop) */ #ifndef PCPU_MD_FIELDS #define PCPU_MD_FIELDS \ int pc_md_placeholder[32] #endif #ifdef _KERNEL -#define pcpup (get_pcpu()) +#define pcpup ((struct pcpu *) powerpc_get_pcpup()) static __inline __pure2 struct thread * __curthread(void) { struct thread *td; #ifdef __powerpc64__ __asm __volatile("mr %0,13" : "=r"(td)); #else __asm __volatile("mr %0,2" : "=r"(td)); #endif return (td); } #define curthread (__curthread()) #define PCPU_GET(member) (pcpup->pc_ ## member) /* * XXX The implementation of this operation should be made atomic * with respect to preemption. */ #define PCPU_ADD(member, value) (pcpup->pc_ ## member += (value)) #define PCPU_INC(member) PCPU_ADD(member, 1) #define PCPU_PTR(member) (&pcpup->pc_ ## member) #define PCPU_SET(member,value) (pcpup->pc_ ## member = (value)) #endif /* _KERNEL */ #endif /* !_MACHINE_PCPU_H_ */ Index: projects/ipsec/sys/riscv/include/_types.h =================================================================== --- projects/ipsec/sys/riscv/include/_types.h (revision 313312) +++ projects/ipsec/sys/riscv/include/_types.h (revision 313313) @@ -1,114 +1,112 @@ /*- * Copyright (c) 2002 Mike Barcroft * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From: @(#)ansi.h 8.2 (Berkeley) 1/4/94 * From: @(#)types.h 8.3 (Berkeley) 1/5/94 * $FreeBSD$ */ #ifndef _MACHINE__TYPES_H_ #define _MACHINE__TYPES_H_ #ifndef _SYS_CDEFS_H_ #error this file needs sys/cdefs.h as a prerequisite #endif /* * Basic types upon which most other types are built. */ typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; typedef unsigned short __uint16_t; typedef int __int32_t; typedef unsigned int __uint32_t; typedef long __int64_t; typedef unsigned long __uint64_t; /* * Standard type definitions. */ typedef __int32_t __clock_t; /* clock()... */ typedef __int64_t __critical_t; typedef double __double_t; typedef float __float_t; typedef __int64_t __intfptr_t; typedef __int64_t __intmax_t; typedef __int64_t __intptr_t; typedef __int32_t __int_fast8_t; typedef __int32_t __int_fast16_t; typedef __int32_t __int_fast32_t; typedef __int64_t __int_fast64_t; typedef __int8_t __int_least8_t; typedef __int16_t __int_least16_t; typedef __int32_t __int_least32_t; typedef __int64_t __int_least64_t; typedef __int64_t __ptrdiff_t; /* ptr1 - ptr2 */ typedef __int64_t __register_t; typedef __int64_t __segsz_t; /* segment size (in pages) */ typedef __uint64_t __size_t; /* sizeof() */ typedef __int64_t __ssize_t; /* byte count or error */ typedef __int64_t __time_t; /* time()... */ typedef __uint64_t __uintfptr_t; typedef __uint64_t __uintmax_t; typedef __uint64_t __uintptr_t; typedef __uint32_t __uint_fast8_t; typedef __uint32_t __uint_fast16_t; typedef __uint32_t __uint_fast32_t; typedef __uint64_t __uint_fast64_t; typedef __uint8_t __uint_least8_t; typedef __uint16_t __uint_least16_t; typedef __uint32_t __uint_least32_t; typedef __uint64_t __uint_least64_t; typedef __uint64_t __u_register_t; typedef __uint64_t __vm_offset_t; -typedef __int64_t __vm_ooffset_t; typedef __uint64_t __vm_paddr_t; -typedef __uint64_t __vm_pindex_t; typedef __uint64_t __vm_size_t; typedef int ___wchar_t; #define __WCHAR_MIN __INT_MIN /* min value for a wchar_t */ #define __WCHAR_MAX __INT_MAX /* max value for a wchar_t */ /* * Unusual type definitions. */ #ifdef __GNUCLIKE_BUILTIN_VARARGS typedef __builtin_va_list __va_list; /* internally known to gcc */ #else typedef char * __va_list; #endif /* __GNUCLIKE_BUILTIN_VARARGS */ #if defined(__GNUCLIKE_BUILTIN_VAALIST) && !defined(__GNUC_VA_LIST) \ && !defined(__NO_GNUC_VA_LIST) #define __GNUC_VA_LIST typedef __va_list __gnuc_va_list; /* compatibility w/GNU headers*/ #endif #endif /* !_MACHINE__TYPES_H_ */ Index: projects/ipsec/sys/riscv/include/atomic.h =================================================================== --- projects/ipsec/sys/riscv/include/atomic.h (revision 313312) +++ projects/ipsec/sys/riscv/include/atomic.h (revision 313313) @@ -1,461 +1,562 @@ /*- * Copyright (c) 2015 Ruslan Bukin * All rights reserved. * * Portions of this software were developed by SRI International and the * University of Cambridge Computer Laboratory under DARPA/AFRL contract * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. * * Portions of this software were developed by the University of Cambridge * Computer Laboratory as part of the CTSRD Project, with support from the * UK Higher Education Innovation Fund (HEIF). * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _MACHINE_ATOMIC_H_ #define _MACHINE_ATOMIC_H_ #define fence() __asm __volatile("fence" ::: "memory"); #define mb() fence() #define rmb() fence() #define wmb() fence() #define ATOMIC_ACQ_REL(NAME, WIDTH) \ static __inline void \ atomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ { \ atomic_##NAME##_##WIDTH(p, v); \ fence(); \ } \ \ static __inline void \ atomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ { \ fence(); \ atomic_##NAME##_##WIDTH(p, v); \ } static __inline void atomic_add_32(volatile uint32_t *p, uint32_t val) { __asm __volatile("amoadd.w zero, %1, %0" : "+A" (*p) : "r" (val) : "memory"); } static __inline void atomic_subtract_32(volatile uint32_t *p, uint32_t val) { __asm __volatile("amoadd.w zero, %1, %0" : "+A" (*p) : "r" (-val) : "memory"); } static __inline void atomic_set_32(volatile uint32_t *p, uint32_t val) { __asm __volatile("amoor.w zero, %1, %0" : "+A" (*p) : "r" (val) : "memory"); } static __inline void atomic_clear_32(volatile uint32_t *p, uint32_t val) { __asm __volatile("amoand.w zero, %1, %0" : "+A" (*p) : "r" (~val) : "memory"); } static __inline int atomic_cmpset_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval) { uint32_t tmp; int res; res = 0; __asm __volatile( "0:" "li %1, 1\n" /* Preset to fail */ "lr.w %0, %2\n" "bne %0, %z3, 1f\n" "sc.w %1, %z4, %2\n" "bnez %1, 0b\n" "1:" : "=&r" (tmp), "=&r" (res), "+A" (*p) : "rJ" (cmpval), "rJ" (newval) : "memory"); return (!res); } +static __inline int +atomic_fcmpset_32(volatile uint32_t *p, uint32_t *cmpval, uint32_t newval) +{ + uint32_t tmp; + int res; + + res = 0; + + __asm __volatile( + "0:" + "li %1, 1\n" /* Preset to fail */ + "lr.w %0, %2\n" /* Load old value */ + "bne %0, %z4, 1f\n" /* Compare */ + "sc.w %1, %z5, %2\n" /* Try to store new value */ + "j 2f\n" + "1:" + "sw %0, %3\n" /* Save old value */ + "2:" + : "=&r" (tmp), "=&r" (res), "+A" (*p), "+A" (*cmpval) + : "rJ" (*cmpval), "rJ" (newval) + : "memory"); + + return (!res); +} + static __inline uint32_t atomic_fetchadd_32(volatile uint32_t *p, uint32_t val) { uint32_t ret; __asm __volatile("amoadd.w %0, %2, %1" : "=&r" (ret), "+A" (*p) : "r" (val) : "memory"); return (ret); } static __inline uint32_t atomic_readandclear_32(volatile uint32_t *p) { uint32_t ret; uint32_t val; val = 0; __asm __volatile("amoswap.w %0, %2, %1" : "=&r"(ret), "+A" (*p) : "r" (val) : "memory"); return (ret); } #define atomic_add_int atomic_add_32 #define atomic_clear_int atomic_clear_32 #define atomic_cmpset_int atomic_cmpset_32 +#define atomic_fcmpset_int atomic_fcmpset_32 #define atomic_fetchadd_int atomic_fetchadd_32 #define atomic_readandclear_int atomic_readandclear_32 #define atomic_set_int atomic_set_32 #define atomic_subtract_int atomic_subtract_32 ATOMIC_ACQ_REL(set, 32) ATOMIC_ACQ_REL(clear, 32) ATOMIC_ACQ_REL(add, 32) ATOMIC_ACQ_REL(subtract, 32) static __inline int atomic_cmpset_acq_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval) { int res; res = atomic_cmpset_32(p, cmpval, newval); fence(); return (res); } static __inline int atomic_cmpset_rel_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval) { fence(); return (atomic_cmpset_32(p, cmpval, newval)); } +static __inline int +atomic_fcmpset_acq_32(volatile uint32_t *p, uint32_t *cmpval, uint32_t newval) +{ + int res; + + res = atomic_fcmpset_32(p, cmpval, newval); + + fence(); + + return (res); +} + +static __inline int +atomic_fcmpset_rel_32(volatile uint32_t *p, uint32_t *cmpval, uint32_t newval) +{ + + fence(); + + return (atomic_fcmpset_32(p, cmpval, newval)); +} + static __inline uint32_t atomic_load_acq_32(volatile uint32_t *p) { uint32_t ret; ret = *p; fence(); return (ret); } static __inline void atomic_store_rel_32(volatile uint32_t *p, uint32_t val) { fence(); *p = val; } #define atomic_add_acq_int atomic_add_acq_32 #define atomic_clear_acq_int atomic_clear_acq_32 #define atomic_cmpset_acq_int atomic_cmpset_acq_32 +#define atomic_fcmpset_acq_int atomic_fcmpset_acq_32 #define atomic_load_acq_int atomic_load_acq_32 #define atomic_set_acq_int atomic_set_acq_32 #define atomic_subtract_acq_int atomic_subtract_acq_32 #define atomic_add_rel_int atomic_add_rel_32 #define atomic_clear_rel_int atomic_add_rel_32 #define atomic_cmpset_rel_int atomic_cmpset_rel_32 +#define atomic_fcmpset_rel_int atomic_fcmpset_rel_32 #define atomic_set_rel_int atomic_set_rel_32 #define atomic_subtract_rel_int atomic_subtract_rel_32 #define atomic_store_rel_int atomic_store_rel_32 static __inline void atomic_add_64(volatile uint64_t *p, uint64_t val) { __asm __volatile("amoadd.d zero, %1, %0" : "+A" (*p) : "r" (val) : "memory"); } static __inline void atomic_subtract_64(volatile uint64_t *p, uint64_t val) { __asm __volatile("amoadd.d zero, %1, %0" : "+A" (*p) : "r" (-val) : "memory"); } static __inline void atomic_set_64(volatile uint64_t *p, uint64_t val) { __asm __volatile("amoor.d zero, %1, %0" : "+A" (*p) : "r" (val) : "memory"); } static __inline void atomic_clear_64(volatile uint64_t *p, uint64_t val) { __asm __volatile("amoand.d zero, %1, %0" : "+A" (*p) : "r" (~val) : "memory"); } static __inline int atomic_cmpset_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval) { uint64_t tmp; int res; res = 0; __asm __volatile( "0:" "li %1, 1\n" /* Preset to fail */ "lr.d %0, %2\n" "bne %0, %z3, 1f\n" "sc.d %1, %z4, %2\n" "bnez %1, 0b\n" "1:" : "=&r" (tmp), "=&r" (res), "+A" (*p) : "rJ" (cmpval), "rJ" (newval) : "memory"); return (!res); } +static __inline int +atomic_fcmpset_64(volatile uint64_t *p, uint64_t *cmpval, uint64_t newval) +{ + uint64_t tmp; + int res; + + res = 0; + + __asm __volatile( + "0:" + "li %1, 1\n" /* Preset to fail */ + "lr.d %0, %2\n" /* Load old value */ + "bne %0, %z4, 1f\n" /* Compare */ + "sc.d %1, %z5, %2\n" /* Try to store new value */ + "j 2f\n" + "1:" + "sd %0, %3\n" /* Save old value */ + "2:" + : "=&r" (tmp), "=&r" (res), "+A" (*p), "+A" (*cmpval) + : "rJ" (*cmpval), "rJ" (newval) + : "memory"); + + return (!res); +} + static __inline uint64_t atomic_fetchadd_64(volatile uint64_t *p, uint64_t val) { uint64_t ret; __asm __volatile("amoadd.d %0, %2, %1" : "=&r" (ret), "+A" (*p) : "r" (val) : "memory"); return (ret); } static __inline uint64_t atomic_readandclear_64(volatile uint64_t *p) { uint64_t ret; uint64_t val; val = 0; __asm __volatile("amoswap.d %0, %2, %1" : "=&r"(ret), "+A" (*p) : "r" (val) : "memory"); return (ret); } static __inline uint32_t atomic_swap_32(volatile uint32_t *p, uint32_t val) { uint32_t old; __asm __volatile("amoswap.w %0, %2, %1" : "=&r"(old), "+A" (*p) : "r" (val) : "memory"); return (old); } static __inline uint64_t atomic_swap_64(volatile uint64_t *p, uint64_t val) { uint64_t old; __asm __volatile("amoswap.d %0, %2, %1" : "=&r"(old), "+A" (*p) : "r" (val) : "memory"); return (old); } #define atomic_add_long atomic_add_64 #define atomic_clear_long atomic_clear_64 #define atomic_cmpset_long atomic_cmpset_64 +#define atomic_fcmpset_long atomic_fcmpset_64 #define atomic_fetchadd_long atomic_fetchadd_64 #define atomic_readandclear_long atomic_readandclear_64 #define atomic_set_long atomic_set_64 #define atomic_subtract_long atomic_subtract_64 #define atomic_add_ptr atomic_add_64 #define atomic_clear_ptr atomic_clear_64 #define atomic_cmpset_ptr atomic_cmpset_64 +#define atomic_fcmpset_ptr atomic_fcmpset_64 #define atomic_fetchadd_ptr atomic_fetchadd_64 #define atomic_readandclear_ptr atomic_readandclear_64 #define atomic_set_ptr atomic_set_64 #define atomic_subtract_ptr atomic_subtract_64 ATOMIC_ACQ_REL(set, 64) ATOMIC_ACQ_REL(clear, 64) ATOMIC_ACQ_REL(add, 64) ATOMIC_ACQ_REL(subtract, 64) static __inline int atomic_cmpset_acq_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval) { int res; res = atomic_cmpset_64(p, cmpval, newval); fence(); return (res); } static __inline int atomic_cmpset_rel_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval) { fence(); return (atomic_cmpset_64(p, cmpval, newval)); } +static __inline int +atomic_fcmpset_acq_64(volatile uint64_t *p, uint64_t *cmpval, uint64_t newval) +{ + int res; + + res = atomic_fcmpset_64(p, cmpval, newval); + + fence(); + + return (res); +} + +static __inline int +atomic_fcmpset_rel_64(volatile uint64_t *p, uint64_t *cmpval, uint64_t newval) +{ + + fence(); + + return (atomic_fcmpset_64(p, cmpval, newval)); +} + static __inline uint64_t atomic_load_acq_64(volatile uint64_t *p) { uint64_t ret; ret = *p; fence(); return (ret); } static __inline void atomic_store_rel_64(volatile uint64_t *p, uint64_t val) { fence(); *p = val; } #define atomic_add_acq_long atomic_add_acq_64 #define atomic_clear_acq_long atomic_add_acq_64 #define atomic_cmpset_acq_long atomic_cmpset_acq_64 +#define atomic_fcmpset_acq_long atomic_fcmpset_acq_64 #define atomic_load_acq_long atomic_load_acq_64 #define atomic_set_acq_long atomic_set_acq_64 #define atomic_subtract_acq_long atomic_subtract_acq_64 #define atomic_add_acq_ptr atomic_add_acq_64 #define atomic_clear_acq_ptr atomic_add_acq_64 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_64 +#define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_64 #define atomic_load_acq_ptr atomic_load_acq_64 #define atomic_set_acq_ptr atomic_set_acq_64 #define atomic_subtract_acq_ptr atomic_subtract_acq_64 static __inline void atomic_thread_fence_acq(void) { fence(); } static __inline void atomic_thread_fence_rel(void) { fence(); } static __inline void atomic_thread_fence_acq_rel(void) { fence(); } static __inline void atomic_thread_fence_seq_cst(void) { fence(); } #define atomic_add_rel_long atomic_add_rel_64 #define atomic_clear_rel_long atomic_clear_rel_64 #define atomic_add_rel_long atomic_add_rel_64 #define atomic_clear_rel_long atomic_clear_rel_64 #define atomic_cmpset_rel_long atomic_cmpset_rel_64 +#define atomic_fcmpset_rel_long atomic_fcmpset_rel_64 #define atomic_set_rel_long atomic_set_rel_64 #define atomic_subtract_rel_long atomic_subtract_rel_64 #define atomic_store_rel_long atomic_store_rel_64 #define atomic_add_rel_ptr atomic_add_rel_64 #define atomic_clear_rel_ptr atomic_clear_rel_64 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_64 +#define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_64 #define atomic_set_rel_ptr atomic_set_rel_64 #define atomic_subtract_rel_ptr atomic_subtract_rel_64 #define atomic_store_rel_ptr atomic_store_rel_64 #endif /* _MACHINE_ATOMIC_H_ */ Index: projects/ipsec/sys/sparc64/include/_types.h =================================================================== --- projects/ipsec/sys/sparc64/include/_types.h (revision 313312) +++ projects/ipsec/sys/sparc64/include/_types.h (revision 313313) @@ -1,114 +1,112 @@ /*- * Copyright (c) 2002 Mike Barcroft * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From: @(#)ansi.h 8.2 (Berkeley) 1/4/94 * From: @(#)types.h 8.3 (Berkeley) 1/5/94 * $FreeBSD$ */ #ifndef _MACHINE__TYPES_H_ #define _MACHINE__TYPES_H_ #ifndef _SYS_CDEFS_H_ #error this file needs sys/cdefs.h as a prerequisite #endif /* * Basic types upon which most other types are built. */ typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; typedef unsigned short __uint16_t; typedef int __int32_t; typedef unsigned int __uint32_t; typedef long __int64_t; typedef unsigned long __uint64_t; /* * Standard type definitions. */ typedef __int32_t __clock_t; /* clock()... */ typedef __int64_t __critical_t; typedef double __double_t; typedef float __float_t; typedef __int64_t __intfptr_t; typedef __int64_t __intmax_t; typedef __int64_t __intptr_t; typedef __int32_t __int_fast8_t; typedef __int32_t __int_fast16_t; typedef __int32_t __int_fast32_t; typedef __int64_t __int_fast64_t; typedef __int8_t __int_least8_t; typedef __int16_t __int_least16_t; typedef __int32_t __int_least32_t; typedef __int64_t __int_least64_t; typedef __int64_t __ptrdiff_t; /* ptr1 - ptr2 */ typedef __int64_t __register_t; typedef __int64_t __segsz_t; /* segment size (in pages) */ typedef __uint64_t __size_t; /* sizeof() */ typedef __int64_t __ssize_t; /* byte count or error */ typedef __int64_t __time_t; /* time()... */ typedef __uint64_t __uintfptr_t; typedef __uint64_t __uintmax_t; typedef __uint64_t __uintptr_t; typedef __uint32_t __uint_fast8_t; typedef __uint32_t __uint_fast16_t; typedef __uint32_t __uint_fast32_t; typedef __uint64_t __uint_fast64_t; typedef __uint8_t __uint_least8_t; typedef __uint16_t __uint_least16_t; typedef __uint32_t __uint_least32_t; typedef __uint64_t __uint_least64_t; typedef __uint64_t __u_register_t; typedef __uint64_t __vm_offset_t; -typedef __int64_t __vm_ooffset_t; typedef __uint64_t __vm_paddr_t; -typedef __uint64_t __vm_pindex_t; typedef __uint64_t __vm_size_t; typedef int ___wchar_t; #define __WCHAR_MIN __INT_MIN /* min value for a wchar_t */ #define __WCHAR_MAX __INT_MAX /* max value for a wchar_t */ /* * Unusual type definitions. */ #ifdef __GNUCLIKE_BUILTIN_VARARGS typedef __builtin_va_list __va_list; /* internally known to gcc */ #else typedef char * __va_list; #endif /* __GNUCLIKE_BUILTIN_VARARGS */ #if defined(__GNUCLIKE_BUILTIN_VAALIST) && !defined(__GNUC_VA_LIST) \ && !defined(__NO_GNUC_VA_LIST) #define __GNUC_VA_LIST typedef __va_list __gnuc_va_list; /* compatibility w/GNU headers*/ #endif #endif /* !_MACHINE__TYPES_H_ */ Index: projects/ipsec/sys/sparc64/include/pcpu.h =================================================================== --- projects/ipsec/sys/sparc64/include/pcpu.h (revision 313312) +++ projects/ipsec/sys/sparc64/include/pcpu.h (revision 313313) @@ -1,101 +1,100 @@ /*- * Copyright (c) 1999 Luoqi Chen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: FreeBSD: src/sys/i386/include/globaldata.h,v 1.27 2001/04/27 * $FreeBSD$ */ #ifndef _MACHINE_PCPU_H_ #define _MACHINE_PCPU_H_ #include #include #include #include #define ALT_STACK_SIZE 128 struct pmap; /* * Inside the kernel, the globally reserved register g7 is used to * point at the globaldata structure. */ #define PCPU_MD_FIELDS \ struct cacheinfo pc_cache; \ struct intr_request pc_irpool[IR_FREE]; \ struct intr_request *pc_irhead; \ struct intr_request **pc_irtail; \ struct intr_request *pc_irfree; \ struct pmap *pc_pmap; \ vm_offset_t pc_addr; \ vm_offset_t pc_qmap_addr; \ u_long pc_tickref; \ u_long pc_tickadj; \ u_long pc_tickincrement; \ u_int pc_clock; \ u_int pc_impl; \ u_int pc_mid; \ u_int pc_node; \ u_int pc_tlb_ctx; \ u_int pc_tlb_ctx_max; \ u_int pc_tlb_ctx_min; \ char __pad[397] #ifdef _KERNEL extern void *dpcpu0; struct pcb; struct pcpu; register struct pcb *curpcb __asm__(__XSTRING(PCB_REG)); register struct pcpu *pcpup __asm__(__XSTRING(PCPU_REG)); -#define get_pcpu() (pcpup) #define PCPU_GET(member) (pcpup->pc_ ## member) static __inline __pure2 struct thread * __curthread(void) { struct thread *td; __asm("ldx [%" __XSTRING(PCPU_REG) "], %0" : "=r" (td)); return (td); } #define curthread (__curthread()) /* * XXX The implementation of this operation should be made atomic * with respect to preemption. */ #define PCPU_ADD(member, value) (pcpup->pc_ ## member += (value)) #define PCPU_INC(member) PCPU_ADD(member, 1) #define PCPU_PTR(member) (&pcpup->pc_ ## member) #define PCPU_SET(member,value) (pcpup->pc_ ## member = (value)) #endif /* _KERNEL */ #endif /* !_MACHINE_PCPU_H_ */ Index: projects/ipsec/sys/sys/lockstat.h =================================================================== --- projects/ipsec/sys/sys/lockstat.h (revision 313312) +++ projects/ipsec/sys/sys/lockstat.h (revision 313313) @@ -1,135 +1,143 @@ /*- * Copyright (c) 2008-2009 Stacey Son * * 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. * * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. * * $FreeBSD$ */ /* * DTrace lockstat provider definitions */ #ifndef _SYS_LOCKSTAT_H #define _SYS_LOCKSTAT_H #ifdef _KERNEL #include #include #include SDT_PROVIDER_DECLARE(lockstat); SDT_PROBE_DECLARE(lockstat, , , adaptive__acquire); SDT_PROBE_DECLARE(lockstat, , , adaptive__release); SDT_PROBE_DECLARE(lockstat, , , adaptive__spin); SDT_PROBE_DECLARE(lockstat, , , adaptive__block); SDT_PROBE_DECLARE(lockstat, , , spin__acquire); SDT_PROBE_DECLARE(lockstat, , , spin__release); SDT_PROBE_DECLARE(lockstat, , , spin__spin); SDT_PROBE_DECLARE(lockstat, , , rw__acquire); SDT_PROBE_DECLARE(lockstat, , , rw__release); SDT_PROBE_DECLARE(lockstat, , , rw__block); SDT_PROBE_DECLARE(lockstat, , , rw__spin); SDT_PROBE_DECLARE(lockstat, , , rw__upgrade); SDT_PROBE_DECLARE(lockstat, , , rw__downgrade); SDT_PROBE_DECLARE(lockstat, , , sx__acquire); SDT_PROBE_DECLARE(lockstat, , , sx__release); SDT_PROBE_DECLARE(lockstat, , , sx__block); SDT_PROBE_DECLARE(lockstat, , , sx__spin); SDT_PROBE_DECLARE(lockstat, , , sx__upgrade); SDT_PROBE_DECLARE(lockstat, , , sx__downgrade); SDT_PROBE_DECLARE(lockstat, , , thread__spin); #define LOCKSTAT_WRITER 0 #define LOCKSTAT_READER 1 extern int lockstat_enabled; #ifdef KDTRACE_HOOKS #define LOCKSTAT_RECORD0(probe, lp) \ SDT_PROBE1(lockstat, , , probe, lp) #define LOCKSTAT_RECORD1(probe, lp, arg1) \ SDT_PROBE2(lockstat, , , probe, lp, arg1) #define LOCKSTAT_RECORD2(probe, lp, arg1, arg2) \ SDT_PROBE3(lockstat, , , probe, lp, arg1, arg2) #define LOCKSTAT_RECORD3(probe, lp, arg1, arg2, arg3) \ SDT_PROBE4(lockstat, , , probe, lp, arg1, arg2, arg3) #define LOCKSTAT_RECORD4(probe, lp, arg1, arg2, arg3, arg4) \ SDT_PROBE5(lockstat, , , probe, lp, arg1, arg2, arg3, arg4) #define LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(probe, lp, c, wt, f, l) do { \ lock_profile_obtain_lock_success(&(lp)->lock_object, c, wt, f, l); \ LOCKSTAT_RECORD0(probe, lp); \ } while (0) #define LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(probe, lp, c, wt, f, l, a) do { \ lock_profile_obtain_lock_success(&(lp)->lock_object, c, wt, f, l); \ LOCKSTAT_RECORD1(probe, lp, a); \ } while (0) #define LOCKSTAT_PROFILE_RELEASE_LOCK(probe, lp) do { \ lock_profile_release_lock(&(lp)->lock_object); \ LOCKSTAT_RECORD0(probe, lp); \ } while (0) #define LOCKSTAT_PROFILE_RELEASE_RWLOCK(probe, lp, a) do { \ lock_profile_release_lock(&(lp)->lock_object); \ LOCKSTAT_RECORD1(probe, lp, a); \ } while (0) +#ifndef LOCK_PROFILING +#define LOCKSTAT_PROFILE_ENABLED(probe) SDT_PROBE_ENABLED(lockstat, , , probe) +#endif + struct lock_object; uint64_t lockstat_nsecs(struct lock_object *); #else /* !KDTRACE_HOOKS */ #define LOCKSTAT_RECORD0(probe, lp) #define LOCKSTAT_RECORD1(probe, lp, arg1) #define LOCKSTAT_RECORD2(probe, lp, arg1, arg2) #define LOCKSTAT_RECORD3(probe, lp, arg1, arg2, arg3) #define LOCKSTAT_RECORD4(probe, lp, arg1, arg2, arg3, arg4) #define LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(probe, lp, c, wt, f, l) \ lock_profile_obtain_lock_success(&(lp)->lock_object, c, wt, f, l) #define LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(probe, lp, c, wt, f, l, a) \ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(probe, lp, c, wt, f, l) #define LOCKSTAT_PROFILE_RELEASE_LOCK(probe, lp) \ lock_profile_release_lock(&(lp)->lock_object) #define LOCKSTAT_PROFILE_RELEASE_RWLOCK(probe, lp, a) \ LOCKSTAT_PROFILE_RELEASE_LOCK(probe, lp) + +#ifndef LOCK_PROFILING +#define LOCKSTAT_PROFILE_ENABLED(probe) 0 +#endif #endif /* !KDTRACE_HOOKS */ #endif /* _KERNEL */ #endif /* _SYS_LOCKSTAT_H */ Index: projects/ipsec/sys/sys/mutex.h =================================================================== --- projects/ipsec/sys/sys/mutex.h (revision 313312) +++ projects/ipsec/sys/sys/mutex.h (revision 313313) @@ -1,513 +1,515 @@ /*- * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Berkeley Software Design Inc's name may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``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 BERKELEY SOFTWARE DESIGN INC BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from BSDI $Id: mutex.h,v 2.7.2.35 2000/04/27 03:10:26 cp Exp $ * $FreeBSD$ */ #ifndef _SYS_MUTEX_H_ #define _SYS_MUTEX_H_ #include #include #include #ifdef _KERNEL #include #include #include #include #include /* * Mutex types and options passed to mtx_init(). MTX_QUIET and MTX_DUPOK * can also be passed in. */ #define MTX_DEF 0x00000000 /* DEFAULT (sleep) lock */ #define MTX_SPIN 0x00000001 /* Spin lock (disables interrupts) */ #define MTX_RECURSE 0x00000004 /* Option: lock allowed to recurse */ #define MTX_NOWITNESS 0x00000008 /* Don't do any witness checking. */ #define MTX_NOPROFILE 0x00000020 /* Don't profile this lock */ #define MTX_NEW 0x00000040 /* Don't check for double-init */ /* * Option flags passed to certain lock/unlock routines, through the use * of corresponding mtx_{lock,unlock}_flags() interface macros. */ #define MTX_QUIET LOP_QUIET /* Don't log a mutex event */ #define MTX_DUPOK LOP_DUPOK /* Don't log a duplicate acquire */ /* * State bits kept in mutex->mtx_lock, for the DEFAULT lock type. None of this, * with the exception of MTX_UNOWNED, applies to spin locks. */ #define MTX_RECURSED 0x00000001 /* lock recursed (for MTX_DEF only) */ #define MTX_CONTESTED 0x00000002 /* lock contested (for MTX_DEF only) */ #define MTX_UNOWNED 0x00000004 /* Cookie for free mutex */ #define MTX_FLAGMASK (MTX_RECURSED | MTX_CONTESTED | MTX_UNOWNED) /* * Value stored in mutex->mtx_lock to denote a destroyed mutex. */ #define MTX_DESTROYED (MTX_CONTESTED | MTX_UNOWNED) /* * Prototypes * * NOTE: Functions prepended with `_' (underscore) are exported to other parts * of the kernel via macros, thus allowing us to use the cpp LOCK_FILE * and LOCK_LINE or for hiding the lock cookie crunching to the * consumers. These functions should not be called directly by any * code using the API. Their macros cover their functionality. * Functions with a `_' suffix are the entrypoint for the common * KPI covering both compat shims and fast path case. These can be * used by consumers willing to pass options, file and line * informations, in an option-independent way. * * [See below for descriptions] * */ void _mtx_init(volatile uintptr_t *c, const char *name, const char *type, int opts); void _mtx_destroy(volatile uintptr_t *c); void mtx_sysinit(void *arg); int _mtx_trylock_flags_(volatile uintptr_t *c, int opts, const char *file, int line); void mutex_init(void); -void __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t tid, int opts, - const char *file, int line); +void __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t v, uintptr_t tid, + int opts, const char *file, int line); void __mtx_unlock_sleep(volatile uintptr_t *c, int opts, const char *file, int line); #ifdef SMP -void _mtx_lock_spin_cookie(volatile uintptr_t *c, uintptr_t tid, int opts, - const char *file, int line); +void _mtx_lock_spin_cookie(volatile uintptr_t *c, uintptr_t v, uintptr_t tid, + int opts, const char *file, int line); #endif void __mtx_lock_flags(volatile uintptr_t *c, int opts, const char *file, int line); void __mtx_unlock_flags(volatile uintptr_t *c, int opts, const char *file, int line); void __mtx_lock_spin_flags(volatile uintptr_t *c, int opts, const char *file, int line); int __mtx_trylock_spin_flags(volatile uintptr_t *c, int opts, const char *file, int line); void __mtx_unlock_spin_flags(volatile uintptr_t *c, int opts, const char *file, int line); #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT) void __mtx_assert(const volatile uintptr_t *c, int what, const char *file, int line); #endif void thread_lock_flags_(struct thread *, int, const char *, int); #define thread_lock(tdp) \ thread_lock_flags_((tdp), 0, __FILE__, __LINE__) #define thread_lock_flags(tdp, opt) \ thread_lock_flags_((tdp), (opt), __FILE__, __LINE__) #define thread_unlock(tdp) \ mtx_unlock_spin((tdp)->td_lock) /* * Top-level macros to provide lock cookie once the actual mtx is passed. * They will also prevent passing a malformed object to the mtx KPI by * failing compilation as the mtx_lock reserved member will not be found. */ #define mtx_init(m, n, t, o) \ _mtx_init(&(m)->mtx_lock, n, t, o) #define mtx_destroy(m) \ _mtx_destroy(&(m)->mtx_lock) #define mtx_trylock_flags_(m, o, f, l) \ _mtx_trylock_flags_(&(m)->mtx_lock, o, f, l) -#define _mtx_lock_sleep(m, t, o, f, l) \ - __mtx_lock_sleep(&(m)->mtx_lock, t, o, f, l) +#define _mtx_lock_sleep(m, v, t, o, f, l) \ + __mtx_lock_sleep(&(m)->mtx_lock, v, t, o, f, l) #define _mtx_unlock_sleep(m, o, f, l) \ __mtx_unlock_sleep(&(m)->mtx_lock, o, f, l) #ifdef SMP -#define _mtx_lock_spin(m, t, o, f, l) \ - _mtx_lock_spin_cookie(&(m)->mtx_lock, t, o, f, l) +#define _mtx_lock_spin(m, v, t, o, f, l) \ + _mtx_lock_spin_cookie(&(m)->mtx_lock, v, t, o, f, l) #endif #define _mtx_lock_flags(m, o, f, l) \ __mtx_lock_flags(&(m)->mtx_lock, o, f, l) #define _mtx_unlock_flags(m, o, f, l) \ __mtx_unlock_flags(&(m)->mtx_lock, o, f, l) #define _mtx_lock_spin_flags(m, o, f, l) \ __mtx_lock_spin_flags(&(m)->mtx_lock, o, f, l) #define _mtx_trylock_spin_flags(m, o, f, l) \ __mtx_trylock_spin_flags(&(m)->mtx_lock, o, f, l) #define _mtx_unlock_spin_flags(m, o, f, l) \ __mtx_unlock_spin_flags(&(m)->mtx_lock, o, f, l) #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT) #define _mtx_assert(m, w, f, l) \ __mtx_assert(&(m)->mtx_lock, w, f, l) #endif #define mtx_recurse lock_object.lo_data /* Very simple operations on mtx_lock. */ /* Try to obtain mtx_lock once. */ #define _mtx_obtain_lock(mp, tid) \ atomic_cmpset_acq_ptr(&(mp)->mtx_lock, MTX_UNOWNED, (tid)) +#define _mtx_obtain_lock_fetch(mp, vp, tid) \ + atomic_fcmpset_rel_ptr(&(mp)->mtx_lock, vp, (tid)) + /* Try to release mtx_lock if it is unrecursed and uncontested. */ #define _mtx_release_lock(mp, tid) \ atomic_cmpset_rel_ptr(&(mp)->mtx_lock, (tid), MTX_UNOWNED) /* Release mtx_lock quickly, assuming we own it. */ #define _mtx_release_lock_quick(mp) \ atomic_store_rel_ptr(&(mp)->mtx_lock, MTX_UNOWNED) /* * Full lock operations that are suitable to be inlined in non-debug * kernels. If the lock cannot be acquired or released trivially then * the work is deferred to another function. */ /* Lock a normal mutex. */ #define __mtx_lock(mp, tid, opts, file, line) do { \ uintptr_t _tid = (uintptr_t)(tid); \ + uintptr_t _v = MTX_UNOWNED; \ \ - if (((mp)->mtx_lock != MTX_UNOWNED || !_mtx_obtain_lock((mp), _tid)))\ - _mtx_lock_sleep((mp), _tid, (opts), (file), (line)); \ - else \ - LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(adaptive__acquire, \ - mp, 0, 0, file, line); \ + if (__predict_false(LOCKSTAT_PROFILE_ENABLED(adaptive__acquire) ||\ + !_mtx_obtain_lock_fetch((mp), &_v, _tid))) \ + _mtx_lock_sleep((mp), _v, _tid, (opts), (file), (line));\ } while (0) /* * Lock a spin mutex. For spinlocks, we handle recursion inline (it * turns out that function calls can be significantly expensive on * some architectures). Since spin locks are not _too_ common, * inlining this code is not too big a deal. */ #ifdef SMP #define __mtx_lock_spin(mp, tid, opts, file, line) do { \ uintptr_t _tid = (uintptr_t)(tid); \ + uintptr_t _v = MTX_UNOWNED; \ \ spinlock_enter(); \ - if (((mp)->mtx_lock != MTX_UNOWNED || !_mtx_obtain_lock((mp), _tid))) {\ - if ((mp)->mtx_lock == _tid) \ + if (!_mtx_obtain_lock_fetch((mp), &_v, _tid)) { \ + if (_v == _tid) \ (mp)->mtx_recurse++; \ else \ - _mtx_lock_spin((mp), _tid, (opts), (file), (line)); \ + _mtx_lock_spin((mp), _v, _tid, (opts), (file), (line));\ } else \ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, \ mp, 0, 0, file, line); \ } while (0) #define __mtx_trylock_spin(mp, tid, opts, file, line) __extension__ ({ \ uintptr_t _tid = (uintptr_t)(tid); \ int _ret; \ \ spinlock_enter(); \ if (((mp)->mtx_lock != MTX_UNOWNED || !_mtx_obtain_lock((mp), _tid))) {\ spinlock_exit(); \ _ret = 0; \ } else { \ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, \ mp, 0, 0, file, line); \ _ret = 1; \ } \ _ret; \ }) #else /* SMP */ #define __mtx_lock_spin(mp, tid, opts, file, line) do { \ uintptr_t _tid = (uintptr_t)(tid); \ \ spinlock_enter(); \ if ((mp)->mtx_lock == _tid) \ (mp)->mtx_recurse++; \ else { \ KASSERT((mp)->mtx_lock == MTX_UNOWNED, ("corrupt spinlock")); \ (mp)->mtx_lock = _tid; \ } \ } while (0) #define __mtx_trylock_spin(mp, tid, opts, file, line) __extension__ ({ \ uintptr_t _tid = (uintptr_t)(tid); \ int _ret; \ \ spinlock_enter(); \ if ((mp)->mtx_lock != MTX_UNOWNED) { \ spinlock_exit(); \ _ret = 0; \ } else { \ (mp)->mtx_lock = _tid; \ _ret = 1; \ } \ _ret; \ }) #endif /* SMP */ /* Unlock a normal mutex. */ #define __mtx_unlock(mp, tid, opts, file, line) do { \ uintptr_t _tid = (uintptr_t)(tid); \ \ - if ((mp)->mtx_recurse == 0) \ - LOCKSTAT_PROFILE_RELEASE_LOCK(adaptive__release, mp); \ - if ((mp)->mtx_lock != _tid || !_mtx_release_lock((mp), _tid)) \ + if (__predict_false(LOCKSTAT_PROFILE_ENABLED(adaptive__release) ||\ + !_mtx_release_lock((mp), _tid))) \ _mtx_unlock_sleep((mp), (opts), (file), (line)); \ } while (0) /* * Unlock a spin mutex. For spinlocks, we can handle everything * inline, as it's pretty simple and a function call would be too * expensive (at least on some architectures). Since spin locks are * not _too_ common, inlining this code is not too big a deal. * * Since we always perform a spinlock_enter() when attempting to acquire a * spin lock, we need to always perform a matching spinlock_exit() when * releasing a spin lock. This includes the recursion cases. */ #ifdef SMP #define __mtx_unlock_spin(mp) do { \ if (mtx_recursed((mp))) \ (mp)->mtx_recurse--; \ else { \ LOCKSTAT_PROFILE_RELEASE_LOCK(spin__release, mp); \ _mtx_release_lock_quick((mp)); \ } \ spinlock_exit(); \ } while (0) #else /* SMP */ #define __mtx_unlock_spin(mp) do { \ if (mtx_recursed((mp))) \ (mp)->mtx_recurse--; \ else { \ LOCKSTAT_PROFILE_RELEASE_LOCK(spin__release, mp); \ (mp)->mtx_lock = MTX_UNOWNED; \ } \ spinlock_exit(); \ } while (0) #endif /* SMP */ /* * Exported lock manipulation interface. * * mtx_lock(m) locks MTX_DEF mutex `m' * * mtx_lock_spin(m) locks MTX_SPIN mutex `m' * * mtx_unlock(m) unlocks MTX_DEF mutex `m' * * mtx_unlock_spin(m) unlocks MTX_SPIN mutex `m' * * mtx_lock_spin_flags(m, opts) and mtx_lock_flags(m, opts) locks mutex `m' * and passes option flags `opts' to the "hard" function, if required. * With these routines, it is possible to pass flags such as MTX_QUIET * to the appropriate lock manipulation routines. * * mtx_trylock(m) attempts to acquire MTX_DEF mutex `m' but doesn't sleep if * it cannot. Rather, it returns 0 on failure and non-zero on success. * It does NOT handle recursion as we assume that if a caller is properly * using this part of the interface, he will know that the lock in question * is _not_ recursed. * * mtx_trylock_flags(m, opts) is used the same way as mtx_trylock() but accepts * relevant option flags `opts.' * * mtx_trylock_spin(m) attempts to acquire MTX_SPIN mutex `m' but doesn't * spin if it cannot. Rather, it returns 0 on failure and non-zero on * success. It always returns failure for recursed lock attempts. * * mtx_initialized(m) returns non-zero if the lock `m' has been initialized. * * mtx_owned(m) returns non-zero if the current thread owns the lock `m' * * mtx_recursed(m) returns non-zero if the lock `m' is presently recursed. */ #define mtx_lock(m) mtx_lock_flags((m), 0) #define mtx_lock_spin(m) mtx_lock_spin_flags((m), 0) #define mtx_trylock(m) mtx_trylock_flags((m), 0) #define mtx_trylock_spin(m) mtx_trylock_spin_flags((m), 0) #define mtx_unlock(m) mtx_unlock_flags((m), 0) #define mtx_unlock_spin(m) mtx_unlock_spin_flags((m), 0) struct mtx_pool; struct mtx_pool *mtx_pool_create(const char *mtx_name, int pool_size, int opts); void mtx_pool_destroy(struct mtx_pool **poolp); struct mtx *mtx_pool_find(struct mtx_pool *pool, void *ptr); struct mtx *mtx_pool_alloc(struct mtx_pool *pool); #define mtx_pool_lock(pool, ptr) \ mtx_lock(mtx_pool_find((pool), (ptr))) #define mtx_pool_lock_spin(pool, ptr) \ mtx_lock_spin(mtx_pool_find((pool), (ptr))) #define mtx_pool_unlock(pool, ptr) \ mtx_unlock(mtx_pool_find((pool), (ptr))) #define mtx_pool_unlock_spin(pool, ptr) \ mtx_unlock_spin(mtx_pool_find((pool), (ptr))) /* * mtxpool_sleep is a general purpose pool of sleep mutexes. */ extern struct mtx_pool *mtxpool_sleep; #ifndef LOCK_DEBUG #error LOCK_DEBUG not defined, include before #endif #if LOCK_DEBUG > 0 || defined(MUTEX_NOINLINE) #define mtx_lock_flags_(m, opts, file, line) \ _mtx_lock_flags((m), (opts), (file), (line)) #define mtx_unlock_flags_(m, opts, file, line) \ _mtx_unlock_flags((m), (opts), (file), (line)) #define mtx_lock_spin_flags_(m, opts, file, line) \ _mtx_lock_spin_flags((m), (opts), (file), (line)) #define mtx_trylock_spin_flags_(m, opts, file, line) \ _mtx_trylock_spin_flags((m), (opts), (file), (line)) #define mtx_unlock_spin_flags_(m, opts, file, line) \ _mtx_unlock_spin_flags((m), (opts), (file), (line)) #else /* LOCK_DEBUG == 0 && !MUTEX_NOINLINE */ #define mtx_lock_flags_(m, opts, file, line) \ __mtx_lock((m), curthread, (opts), (file), (line)) #define mtx_unlock_flags_(m, opts, file, line) \ __mtx_unlock((m), curthread, (opts), (file), (line)) #define mtx_lock_spin_flags_(m, opts, file, line) \ __mtx_lock_spin((m), curthread, (opts), (file), (line)) #define mtx_trylock_spin_flags_(m, opts, file, line) \ __mtx_trylock_spin((m), curthread, (opts), (file), (line)) #define mtx_unlock_spin_flags_(m, opts, file, line) \ __mtx_unlock_spin((m)) #endif /* LOCK_DEBUG > 0 || MUTEX_NOINLINE */ #ifdef INVARIANTS #define mtx_assert_(m, what, file, line) \ _mtx_assert((m), (what), (file), (line)) #define GIANT_REQUIRED mtx_assert_(&Giant, MA_OWNED, __FILE__, __LINE__) #else /* INVARIANTS */ #define mtx_assert_(m, what, file, line) (void)0 #define GIANT_REQUIRED #endif /* INVARIANTS */ #define mtx_lock_flags(m, opts) \ mtx_lock_flags_((m), (opts), LOCK_FILE, LOCK_LINE) #define mtx_unlock_flags(m, opts) \ mtx_unlock_flags_((m), (opts), LOCK_FILE, LOCK_LINE) #define mtx_lock_spin_flags(m, opts) \ mtx_lock_spin_flags_((m), (opts), LOCK_FILE, LOCK_LINE) #define mtx_unlock_spin_flags(m, opts) \ mtx_unlock_spin_flags_((m), (opts), LOCK_FILE, LOCK_LINE) #define mtx_trylock_flags(m, opts) \ mtx_trylock_flags_((m), (opts), LOCK_FILE, LOCK_LINE) #define mtx_trylock_spin_flags(m, opts) \ mtx_trylock_spin_flags_((m), (opts), LOCK_FILE, LOCK_LINE) #define mtx_assert(m, what) \ mtx_assert_((m), (what), __FILE__, __LINE__) #define mtx_sleep(chan, mtx, pri, wmesg, timo) \ _sleep((chan), &(mtx)->lock_object, (pri), (wmesg), \ tick_sbt * (timo), 0, C_HARDCLOCK) #define MTX_READ_VALUE(m) ((m)->mtx_lock) #define mtx_initialized(m) lock_initialized(&(m)->lock_object) #define lv_mtx_owner(v) ((struct thread *)((v) & ~MTX_FLAGMASK)) #define mtx_owner(m) lv_mtx_owner(MTX_READ_VALUE(m)) #define mtx_owned(m) (mtx_owner(m) == curthread) #define mtx_recursed(m) ((m)->mtx_recurse != 0) #define mtx_name(m) ((m)->lock_object.lo_name) /* * Global locks. */ extern struct mtx Giant; extern struct mtx blocked_lock; /* * Giant lock manipulation and clean exit macros. * Used to replace return with an exit Giant and return. * * Note that DROP_GIANT*() needs to be paired with PICKUP_GIANT() * The #ifndef is to allow lint-like tools to redefine DROP_GIANT. */ #ifndef DROP_GIANT #define DROP_GIANT() \ do { \ int _giantcnt = 0; \ WITNESS_SAVE_DECL(Giant); \ \ if (mtx_owned(&Giant)) { \ WITNESS_SAVE(&Giant.lock_object, Giant); \ for (_giantcnt = 0; mtx_owned(&Giant) && \ !SCHEDULER_STOPPED(); _giantcnt++) \ mtx_unlock(&Giant); \ } #define PICKUP_GIANT() \ PARTIAL_PICKUP_GIANT(); \ } while (0) #define PARTIAL_PICKUP_GIANT() \ mtx_assert(&Giant, MA_NOTOWNED); \ if (_giantcnt > 0) { \ while (_giantcnt--) \ mtx_lock(&Giant); \ WITNESS_RESTORE(&Giant.lock_object, Giant); \ } #endif struct mtx_args { void *ma_mtx; const char *ma_desc; int ma_opts; }; #define MTX_SYSINIT(name, mtx, desc, opts) \ static struct mtx_args name##_args = { \ (mtx), \ (desc), \ (opts) \ }; \ SYSINIT(name##_mtx_sysinit, SI_SUB_LOCK, SI_ORDER_MIDDLE, \ mtx_sysinit, &name##_args); \ SYSUNINIT(name##_mtx_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE, \ _mtx_destroy, __DEVOLATILE(void *, &(mtx)->mtx_lock)) /* * The INVARIANTS-enabled mtx_assert() functionality. * * The constants need to be defined for INVARIANT_SUPPORT infrastructure * support as _mtx_assert() itself uses them and the latter implies that * _mtx_assert() must build. */ #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT) #define MA_OWNED LA_XLOCKED #define MA_NOTOWNED LA_UNLOCKED #define MA_RECURSED LA_RECURSED #define MA_NOTRECURSED LA_NOTRECURSED #endif /* * Common lock type names. */ #define MTX_NETWORK_LOCK "network driver" #endif /* _KERNEL */ #endif /* _SYS_MUTEX_H_ */ Index: projects/ipsec/sys/sys/rwlock.h =================================================================== --- projects/ipsec/sys/sys/rwlock.h (revision 313312) +++ projects/ipsec/sys/sys/rwlock.h (revision 313313) @@ -1,288 +1,289 @@ /*- * Copyright (c) 2006 John Baldwin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _SYS_RWLOCK_H_ #define _SYS_RWLOCK_H_ #include #include #include #include #ifdef _KERNEL #include #include #endif /* * The rw_lock field consists of several fields. The low bit indicates * if the lock is locked with a read (shared) or write (exclusive) lock. * A value of 0 indicates a write lock, and a value of 1 indicates a read * lock. Bit 1 is a boolean indicating if there are any threads waiting * for a read lock. Bit 2 is a boolean indicating if there are any threads * waiting for a write lock. The rest of the variable's definition is * dependent on the value of the first bit. For a write lock, it is a * pointer to the thread holding the lock, similar to the mtx_lock field of * mutexes. For read locks, it is a count of read locks that are held. * * When the lock is not locked by any thread, it is encoded as a read lock * with zero waiters. */ #define RW_LOCK_READ 0x01 #define RW_LOCK_READ_WAITERS 0x02 #define RW_LOCK_WRITE_WAITERS 0x04 #define RW_LOCK_WRITE_SPINNER 0x08 #define RW_LOCK_FLAGMASK \ (RW_LOCK_READ | RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS | \ RW_LOCK_WRITE_SPINNER) #define RW_LOCK_WAITERS (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS) #define RW_OWNER(x) ((x) & ~RW_LOCK_FLAGMASK) #define RW_READERS_SHIFT 4 #define RW_READERS(x) (RW_OWNER((x)) >> RW_READERS_SHIFT) #define RW_READERS_LOCK(x) ((x) << RW_READERS_SHIFT | RW_LOCK_READ) #define RW_ONE_READER (1 << RW_READERS_SHIFT) #define RW_UNLOCKED RW_READERS_LOCK(0) #define RW_DESTROYED (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS) #ifdef _KERNEL #define rw_recurse lock_object.lo_data #define RW_READ_VALUE(x) ((x)->rw_lock) /* Very simple operations on rw_lock. */ /* Try to obtain a write lock once. */ #define _rw_write_lock(rw, tid) \ atomic_cmpset_acq_ptr(&(rw)->rw_lock, RW_UNLOCKED, (tid)) +#define _rw_write_lock_fetch(rw, vp, tid) \ + atomic_fcmpset_acq_ptr(&(rw)->rw_lock, vp, (tid)) + /* Release a write lock quickly if there are no waiters. */ #define _rw_write_unlock(rw, tid) \ atomic_cmpset_rel_ptr(&(rw)->rw_lock, (tid), RW_UNLOCKED) /* * Full lock operations that are suitable to be inlined in non-debug * kernels. If the lock cannot be acquired or released trivially then * the work is deferred to another function. */ /* Acquire a write lock. */ #define __rw_wlock(rw, tid, file, line) do { \ uintptr_t _tid = (uintptr_t)(tid); \ + uintptr_t _v = RW_UNLOCKED; \ \ - if ((rw)->rw_lock != RW_UNLOCKED || !_rw_write_lock((rw), _tid))\ - _rw_wlock_hard((rw), _tid, (file), (line)); \ - else \ - LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(rw__acquire, rw, \ - 0, 0, file, line, LOCKSTAT_WRITER); \ + if (__predict_false(LOCKSTAT_PROFILE_ENABLED(rw__acquire) || \ + !_rw_write_lock_fetch((rw), &_v, _tid))) \ + _rw_wlock_hard((rw), _v, _tid, (file), (line)); \ } while (0) /* Release a write lock. */ #define __rw_wunlock(rw, tid, file, line) do { \ uintptr_t _tid = (uintptr_t)(tid); \ \ if ((rw)->rw_recurse) \ (rw)->rw_recurse--; \ else { \ - LOCKSTAT_PROFILE_RELEASE_RWLOCK(rw__release, rw, \ - LOCKSTAT_WRITER); \ - if ((rw)->rw_lock != _tid || !_rw_write_unlock((rw), _tid))\ + if (__predict_false(LOCKSTAT_PROFILE_ENABLED(rw__release) ||\ + !_rw_write_unlock((rw), _tid))) \ _rw_wunlock_hard((rw), _tid, (file), (line)); \ } \ } while (0) /* * Function prototypes. Routines that start with _ are not part of the * external API and should not be called directly. Wrapper macros should * be used instead. */ void _rw_init_flags(volatile uintptr_t *c, const char *name, int opts); void _rw_destroy(volatile uintptr_t *c); void rw_sysinit(void *arg); void rw_sysinit_flags(void *arg); int _rw_wowned(const volatile uintptr_t *c); void _rw_wlock_cookie(volatile uintptr_t *c, const char *file, int line); int __rw_try_wlock(volatile uintptr_t *c, const char *file, int line); void _rw_wunlock_cookie(volatile uintptr_t *c, const char *file, int line); void __rw_rlock(volatile uintptr_t *c, const char *file, int line); int __rw_try_rlock(volatile uintptr_t *c, const char *file, int line); void _rw_runlock_cookie(volatile uintptr_t *c, const char *file, int line); -void __rw_wlock_hard(volatile uintptr_t *c, uintptr_t tid, const char *file, - int line); +void __rw_wlock_hard(volatile uintptr_t *c, uintptr_t v, uintptr_t tid, + const char *file, int line); void __rw_wunlock_hard(volatile uintptr_t *c, uintptr_t tid, const char *file, int line); int __rw_try_upgrade(volatile uintptr_t *c, const char *file, int line); void __rw_downgrade(volatile uintptr_t *c, const char *file, int line); #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT) void __rw_assert(const volatile uintptr_t *c, int what, const char *file, int line); #endif /* * Top-level macros to provide lock cookie once the actual rwlock is passed. * They will also prevent passing a malformed object to the rwlock KPI by * failing compilation as the rw_lock reserved member will not be found. */ #define rw_init(rw, n) \ _rw_init_flags(&(rw)->rw_lock, n, 0) #define rw_init_flags(rw, n, o) \ _rw_init_flags(&(rw)->rw_lock, n, o) #define rw_destroy(rw) \ _rw_destroy(&(rw)->rw_lock) #define rw_wowned(rw) \ _rw_wowned(&(rw)->rw_lock) #define _rw_wlock(rw, f, l) \ _rw_wlock_cookie(&(rw)->rw_lock, f, l) #define _rw_try_wlock(rw, f, l) \ __rw_try_wlock(&(rw)->rw_lock, f, l) #define _rw_wunlock(rw, f, l) \ _rw_wunlock_cookie(&(rw)->rw_lock, f, l) #define _rw_rlock(rw, f, l) \ __rw_rlock(&(rw)->rw_lock, f, l) #define _rw_try_rlock(rw, f, l) \ __rw_try_rlock(&(rw)->rw_lock, f, l) #define _rw_runlock(rw, f, l) \ _rw_runlock_cookie(&(rw)->rw_lock, f, l) -#define _rw_wlock_hard(rw, t, f, l) \ - __rw_wlock_hard(&(rw)->rw_lock, t, f, l) +#define _rw_wlock_hard(rw, v, t, f, l) \ + __rw_wlock_hard(&(rw)->rw_lock, v, t, f, l) #define _rw_wunlock_hard(rw, t, f, l) \ __rw_wunlock_hard(&(rw)->rw_lock, t, f, l) #define _rw_try_upgrade(rw, f, l) \ __rw_try_upgrade(&(rw)->rw_lock, f, l) #define _rw_downgrade(rw, f, l) \ __rw_downgrade(&(rw)->rw_lock, f, l) #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT) #define _rw_assert(rw, w, f, l) \ __rw_assert(&(rw)->rw_lock, w, f, l) #endif /* * Public interface for lock operations. */ #ifndef LOCK_DEBUG #error LOCK_DEBUG not defined, include before #endif #if LOCK_DEBUG > 0 || defined(RWLOCK_NOINLINE) #define rw_wlock(rw) _rw_wlock((rw), LOCK_FILE, LOCK_LINE) #define rw_wunlock(rw) _rw_wunlock((rw), LOCK_FILE, LOCK_LINE) #else #define rw_wlock(rw) \ __rw_wlock((rw), curthread, LOCK_FILE, LOCK_LINE) #define rw_wunlock(rw) \ __rw_wunlock((rw), curthread, LOCK_FILE, LOCK_LINE) #endif #define rw_rlock(rw) _rw_rlock((rw), LOCK_FILE, LOCK_LINE) #define rw_runlock(rw) _rw_runlock((rw), LOCK_FILE, LOCK_LINE) #define rw_try_rlock(rw) _rw_try_rlock((rw), LOCK_FILE, LOCK_LINE) #define rw_try_upgrade(rw) _rw_try_upgrade((rw), LOCK_FILE, LOCK_LINE) #define rw_try_wlock(rw) _rw_try_wlock((rw), LOCK_FILE, LOCK_LINE) #define rw_downgrade(rw) _rw_downgrade((rw), LOCK_FILE, LOCK_LINE) #define rw_unlock(rw) do { \ if (rw_wowned(rw)) \ rw_wunlock(rw); \ else \ rw_runlock(rw); \ } while (0) #define rw_sleep(chan, rw, pri, wmesg, timo) \ _sleep((chan), &(rw)->lock_object, (pri), (wmesg), \ tick_sbt * (timo), 0, C_HARDCLOCK) #define rw_initialized(rw) lock_initialized(&(rw)->lock_object) struct rw_args { void *ra_rw; const char *ra_desc; }; struct rw_args_flags { void *ra_rw; const char *ra_desc; int ra_flags; }; #define RW_SYSINIT(name, rw, desc) \ static struct rw_args name##_args = { \ (rw), \ (desc), \ }; \ SYSINIT(name##_rw_sysinit, SI_SUB_LOCK, SI_ORDER_MIDDLE, \ rw_sysinit, &name##_args); \ SYSUNINIT(name##_rw_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE, \ _rw_destroy, __DEVOLATILE(void *, &(rw)->rw_lock)) #define RW_SYSINIT_FLAGS(name, rw, desc, flags) \ static struct rw_args_flags name##_args = { \ (rw), \ (desc), \ (flags), \ }; \ SYSINIT(name##_rw_sysinit, SI_SUB_LOCK, SI_ORDER_MIDDLE, \ rw_sysinit_flags, &name##_args); \ SYSUNINIT(name##_rw_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE, \ _rw_destroy, __DEVOLATILE(void *, &(rw)->rw_lock)) /* * Options passed to rw_init_flags(). */ #define RW_DUPOK 0x01 #define RW_NOPROFILE 0x02 #define RW_NOWITNESS 0x04 #define RW_QUIET 0x08 #define RW_RECURSE 0x10 #define RW_NEW 0x20 /* * The INVARIANTS-enabled rw_assert() functionality. * * The constants need to be defined for INVARIANT_SUPPORT infrastructure * support as _rw_assert() itself uses them and the latter implies that * _rw_assert() must build. */ #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT) #define RA_LOCKED LA_LOCKED #define RA_RLOCKED LA_SLOCKED #define RA_WLOCKED LA_XLOCKED #define RA_UNLOCKED LA_UNLOCKED #define RA_RECURSED LA_RECURSED #define RA_NOTRECURSED LA_NOTRECURSED #endif #ifdef INVARIANTS #define rw_assert(rw, what) _rw_assert((rw), (what), LOCK_FILE, LOCK_LINE) #else #define rw_assert(rw, what) #endif #endif /* _KERNEL */ #endif /* !_SYS_RWLOCK_H_ */ Index: projects/ipsec/sys/sys/sdt.h =================================================================== --- projects/ipsec/sys/sys/sdt.h (revision 313312) +++ projects/ipsec/sys/sys/sdt.h (revision 313313) @@ -1,425 +1,428 @@ /*- * Copyright 2006-2008 John Birrell * * 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. * * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. * * $FreeBSD$ * * Statically Defined Tracing (SDT) definitions. * */ #ifndef _SYS_SDT_H #define _SYS_SDT_H #ifndef _KERNEL #define _DTRACE_VERSION 1 #define DTRACE_PROBE(prov, name) { \ extern void __dtrace_##prov##___##name(void); \ __dtrace_##prov##___##name(); \ } #define DTRACE_PROBE1(prov, name, arg1) { \ extern void __dtrace_##prov##___##name(unsigned long); \ __dtrace_##prov##___##name((unsigned long)arg1); \ } #define DTRACE_PROBE2(prov, name, arg1, arg2) { \ extern void __dtrace_##prov##___##name(unsigned long, \ unsigned long); \ __dtrace_##prov##___##name((unsigned long)arg1, \ (unsigned long)arg2); \ } #define DTRACE_PROBE3(prov, name, arg1, arg2, arg3) { \ extern void __dtrace_##prov##___##name(unsigned long, \ unsigned long, unsigned long); \ __dtrace_##prov##___##name((unsigned long)arg1, \ (unsigned long)arg2, (unsigned long)arg3); \ } #define DTRACE_PROBE4(prov, name, arg1, arg2, arg3, arg4) { \ extern void __dtrace_##prov##___##name(unsigned long, \ unsigned long, unsigned long, unsigned long); \ __dtrace_##prov##___##name((unsigned long)arg1, \ (unsigned long)arg2, (unsigned long)arg3, \ (unsigned long)arg4); \ } #define DTRACE_PROBE5(prov, name, arg1, arg2, arg3, arg4, arg5) { \ extern void __dtrace_##prov##___##name(unsigned long, \ unsigned long, unsigned long, unsigned long, unsigned long);\ __dtrace_##prov##___##name((unsigned long)arg1, \ (unsigned long)arg2, (unsigned long)arg3, \ (unsigned long)arg4, (unsigned long)arg5); \ } #else /* _KERNEL */ #include #include #ifndef KDTRACE_HOOKS #define SDT_PROVIDER_DEFINE(prov) #define SDT_PROVIDER_DECLARE(prov) #define SDT_PROBE_DEFINE(prov, mod, func, name) #define SDT_PROBE_DECLARE(prov, mod, func, name) #define SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) #define SDT_PROBE_ARGTYPE(prov, mod, func, name, num, type, xtype) #define SDT_PROBE_DEFINE0(prov, mod, func, name) #define SDT_PROBE_DEFINE1(prov, mod, func, name, arg0) #define SDT_PROBE_DEFINE2(prov, mod, func, name, arg0, arg1) #define SDT_PROBE_DEFINE3(prov, mod, func, name, arg0, arg1, arg2) #define SDT_PROBE_DEFINE4(prov, mod, func, name, arg0, arg1, arg2, arg3) #define SDT_PROBE_DEFINE5(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) #define SDT_PROBE_DEFINE6(prov, mod, func, name, arg0, arg1, arg2, \ arg3, arg4, arg5) #define SDT_PROBE_DEFINE7(prov, mod, func, name, arg0, arg1, arg2, \ arg3, arg4, arg5, arg6) #define SDT_PROBE0(prov, mod, func, name) #define SDT_PROBE1(prov, mod, func, name, arg0) #define SDT_PROBE2(prov, mod, func, name, arg0, arg1) #define SDT_PROBE3(prov, mod, func, name, arg0, arg1, arg2) #define SDT_PROBE4(prov, mod, func, name, arg0, arg1, arg2, arg3) #define SDT_PROBE5(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) #define SDT_PROBE6(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4, arg5) #define SDT_PROBE7(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4, arg5, \ arg6) #define SDT_PROBE_DEFINE0_XLATE(prov, mod, func, name) #define SDT_PROBE_DEFINE1_XLATE(prov, mod, func, name, arg0, xarg0) #define SDT_PROBE_DEFINE2_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1) #define SDT_PROBE_DEFINE3_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2) #define SDT_PROBE_DEFINE4_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2, arg3, xarg3) #define SDT_PROBE_DEFINE5_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4) #define SDT_PROBE_DEFINE6_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4, arg5, xarg5) #define SDT_PROBE_DEFINE7_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4, arg5, xarg5, arg6, \ xarg6) #define DTRACE_PROBE(name) #define DTRACE_PROBE1(name, type0, arg0) #define DTRACE_PROBE2(name, type0, arg0, type1, arg1) #define DTRACE_PROBE3(name, type0, arg0, type1, arg1, type2, arg2) #define DTRACE_PROBE4(name, type0, arg0, type1, arg1, type2, arg2, type3, arg3) #define DTRACE_PROBE5(name, type0, arg0, type1, arg1, type2, arg2, type3, arg3,\ type4, arg4) #else SET_DECLARE(sdt_providers_set, struct sdt_provider); SET_DECLARE(sdt_probes_set, struct sdt_probe); SET_DECLARE(sdt_argtypes_set, struct sdt_argtype); #define SDT_PROVIDER_DEFINE(prov) \ struct sdt_provider sdt_provider_##prov[1] = { \ { #prov, { NULL, NULL }, 0, 0 } \ }; \ DATA_SET(sdt_providers_set, sdt_provider_##prov); #define SDT_PROVIDER_DECLARE(prov) \ extern struct sdt_provider sdt_provider_##prov[1] #define SDT_PROBE_DEFINE(prov, mod, func, name) \ struct sdt_probe sdt_##prov##_##mod##_##func##_##name[1] = { \ { sizeof(struct sdt_probe), sdt_provider_##prov, \ { NULL, NULL }, { NULL, NULL }, #mod, #func, #name, 0, 0, \ NULL } \ }; \ DATA_SET(sdt_probes_set, sdt_##prov##_##mod##_##func##_##name); #define SDT_PROBE_DECLARE(prov, mod, func, name) \ extern struct sdt_probe sdt_##prov##_##mod##_##func##_##name[1] +#define SDT_PROBE_ENABLED(prov, mod, func, name) \ + __predict_false((sdt_##prov##_##mod##_##func##_##name->id)) + #define SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) do { \ if (__predict_false(sdt_##prov##_##mod##_##func##_##name->id)) \ (*sdt_probe_func)(sdt_##prov##_##mod##_##func##_##name->id, \ (uintptr_t) arg0, (uintptr_t) arg1, (uintptr_t) arg2, \ (uintptr_t) arg3, (uintptr_t) arg4); \ } while (0) #define SDT_PROBE_ARGTYPE(prov, mod, func, name, num, type, xtype) \ static struct sdt_argtype sdta_##prov##_##mod##_##func##_##name##num[1] \ = { { num, type, xtype, { NULL, NULL }, \ sdt_##prov##_##mod##_##func##_##name } \ }; \ DATA_SET(sdt_argtypes_set, sdta_##prov##_##mod##_##func##_##name##num); #define SDT_PROBE_DEFINE0(prov, mod, func, name) \ SDT_PROBE_DEFINE(prov, mod, func, name) #define SDT_PROBE_DEFINE1(prov, mod, func, name, arg0) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, NULL) #define SDT_PROBE_DEFINE2(prov, mod, func, name, arg0, arg1) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, NULL) #define SDT_PROBE_DEFINE3(prov, mod, func, name, arg0, arg1, arg2)\ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, NULL) #define SDT_PROBE_DEFINE4(prov, mod, func, name, arg0, arg1, arg2, arg3) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, NULL) #define SDT_PROBE_DEFINE5(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, NULL) #define SDT_PROBE_DEFINE6(prov, mod, func, name, arg0, arg1, arg2, arg3,\ arg4, arg5) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 5, arg5, NULL) #define SDT_PROBE_DEFINE7(prov, mod, func, name, arg0, arg1, arg2, arg3,\ arg4, arg5, arg6) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 5, arg5, NULL); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 6, arg6, NULL) #define SDT_PROBE_DEFINE0_XLATE(prov, mod, func, name) \ SDT_PROBE_DEFINE(prov, mod, func, name) #define SDT_PROBE_DEFINE1_XLATE(prov, mod, func, name, arg0, xarg0) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, xarg0) #define SDT_PROBE_DEFINE2_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, xarg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, xarg1) #define SDT_PROBE_DEFINE3_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, xarg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, xarg1); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, xarg2) #define SDT_PROBE_DEFINE4_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2, arg3, xarg3) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, xarg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, xarg1); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, xarg2); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, xarg3) #define SDT_PROBE_DEFINE5_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, xarg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, xarg1); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, xarg2); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, xarg3); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, xarg4) #define SDT_PROBE_DEFINE6_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4, arg5, xarg5) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, xarg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, xarg1); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, xarg2); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, xarg3); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, xarg4); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 5, arg5, xarg5) #define SDT_PROBE_DEFINE7_XLATE(prov, mod, func, name, arg0, xarg0, \ arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4, arg5, xarg5, arg6, \ xarg6) \ SDT_PROBE_DEFINE(prov, mod, func, name); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, xarg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, xarg1); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, xarg2); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, xarg3); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, xarg4); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 5, arg5, xarg5); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 6, arg6, xarg6) #define SDT_PROBE0(prov, mod, func, name) \ SDT_PROBE(prov, mod, func, name, 0, 0, 0, 0, 0) #define SDT_PROBE1(prov, mod, func, name, arg0) \ SDT_PROBE(prov, mod, func, name, arg0, 0, 0, 0, 0) #define SDT_PROBE2(prov, mod, func, name, arg0, arg1) \ SDT_PROBE(prov, mod, func, name, arg0, arg1, 0, 0, 0) #define SDT_PROBE3(prov, mod, func, name, arg0, arg1, arg2) \ SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, 0, 0) #define SDT_PROBE4(prov, mod, func, name, arg0, arg1, arg2, arg3) \ SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, arg3, 0) #define SDT_PROBE5(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) \ SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) #define SDT_PROBE6(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4, arg5) \ do { \ if (sdt_##prov##_##mod##_##func##_##name->id) \ (*(void (*)(uint32_t, uintptr_t, uintptr_t, uintptr_t, \ uintptr_t, uintptr_t, uintptr_t))sdt_probe_func)( \ sdt_##prov##_##mod##_##func##_##name->id, \ (uintptr_t)arg0, (uintptr_t)arg1, (uintptr_t)arg2, \ (uintptr_t)arg3, (uintptr_t)arg4, (uintptr_t)arg5);\ } while (0) #define SDT_PROBE7(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4, arg5, \ arg6) \ do { \ if (sdt_##prov##_##mod##_##func##_##name->id) \ (*(void (*)(uint32_t, uintptr_t, uintptr_t, uintptr_t, \ uintptr_t, uintptr_t, uintptr_t, uintptr_t)) \ sdt_probe_func)( \ sdt_##prov##_##mod##_##func##_##name->id, \ (uintptr_t)arg0, (uintptr_t)arg1, (uintptr_t)arg2, \ (uintptr_t)arg3, (uintptr_t)arg4, (uintptr_t)arg5, \ (uintptr_t)arg6); \ } while (0) #define DTRACE_PROBE_IMPL_START(name, arg0, arg1, arg2, arg3, arg4) do { \ static SDT_PROBE_DEFINE(sdt, , , name); \ SDT_PROBE(sdt, , , name, arg0, arg1, arg2, arg3, arg4); #define DTRACE_PROBE_IMPL_END } while (0) #define DTRACE_PROBE(name) \ DTRACE_PROBE_IMPL_START(name, 0, 0, 0, 0, 0) \ DTRACE_PROBE_IMPL_END #define DTRACE_PROBE1(name, type0, arg0) \ DTRACE_PROBE_IMPL_START(name, arg0, 0, 0, 0, 0) \ SDT_PROBE_ARGTYPE(sdt, , , name, 0, #type0, NULL); \ DTRACE_PROBE_IMPL_END #define DTRACE_PROBE2(name, type0, arg0, type1, arg1) \ DTRACE_PROBE_IMPL_START(name, arg0, arg1, 0, 0, 0) \ SDT_PROBE_ARGTYPE(sdt, , , name, 0, #type0, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 1, #type1, NULL); \ DTRACE_PROBE_IMPL_END #define DTRACE_PROBE3(name, type0, arg0, type1, arg1, type2, arg2) \ DTRACE_PROBE_IMPL_START(name, arg0, arg1, arg2, 0, 0) \ SDT_PROBE_ARGTYPE(sdt, , , name, 0, #type0, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 1, #type1, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 2, #type2, NULL); \ DTRACE_PROBE_IMPL_END #define DTRACE_PROBE4(name, type0, arg0, type1, arg1, type2, arg2, type3, arg3) \ DTRACE_PROBE_IMPL_START(name, arg0, arg1, arg2, arg3, 0) \ SDT_PROBE_ARGTYPE(sdt, , , name, 0, #type0, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 1, #type1, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 2, #type2, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 3, #type3, NULL); \ DTRACE_PROBE_IMPL_END #define DTRACE_PROBE5(name, type0, arg0, type1, arg1, type2, arg2, type3, arg3, \ type4, arg4) \ DTRACE_PROBE_IMPL_START(name, arg0, arg1, arg2, arg3, arg4) \ SDT_PROBE_ARGTYPE(sdt, , , name, 0, #type0, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 1, #type1, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 2, #type2, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 3, #type3, NULL); \ SDT_PROBE_ARGTYPE(sdt, , , name, 4, #type4, NULL); \ DTRACE_PROBE_IMPL_END #endif /* KDTRACE_HOOKS */ /* * This type definition must match that of dtrace_probe. It is defined this * way to avoid having to rely on CDDL code. */ typedef void (*sdt_probe_func_t)(uint32_t, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4); /* * The 'sdt' provider will set it to dtrace_probe when it loads. */ extern sdt_probe_func_t sdt_probe_func; struct sdt_probe; struct sdt_provider; struct linker_file; struct sdt_argtype { int ndx; /* Argument index. */ const char *type; /* Argument type string. */ const char *xtype; /* Translated argument type. */ TAILQ_ENTRY(sdt_argtype) argtype_entry; /* Argument type list entry. */ struct sdt_probe *probe; /* Ptr to the probe structure. */ }; struct sdt_probe { int version; /* Set to sizeof(struct sdt_probe). */ struct sdt_provider *prov; /* Ptr to the provider structure. */ TAILQ_ENTRY(sdt_probe) probe_entry; /* SDT probe list entry. */ TAILQ_HEAD(, sdt_argtype) argtype_list; const char *mod; const char *func; const char *name; id_t id; /* DTrace probe ID. */ int n_args; /* Number of arguments. */ struct linker_file *sdtp_lf; /* Module in which we're defined. */ }; struct sdt_provider { char *name; /* Provider name. */ TAILQ_ENTRY(sdt_provider) prov_entry; /* SDT provider list entry. */ uintptr_t id; /* DTrace provider ID. */ int sdt_refs; /* Number of module references. */ }; void sdt_probe_stub(uint32_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); SDT_PROVIDER_DECLARE(sdt); #endif /* _KERNEL */ #endif /* _SYS_SDT_H */ Index: projects/ipsec/sys/sys/sx.h =================================================================== --- projects/ipsec/sys/sys/sx.h (revision 313312) +++ projects/ipsec/sys/sys/sx.h (revision 313313) @@ -1,329 +1,283 @@ /*- * Copyright (c) 2007 Attilio Rao * Copyright (c) 2001 Jason Evans * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice(s), this list of conditions and the following disclaimer as * the first lines of this file unmodified other than the possible * addition of one or more copyright notices. * 2. Redistributions in binary form must reproduce the above copyright * notice(s), this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. * * $FreeBSD$ */ #ifndef _SYS_SX_H_ #define _SYS_SX_H_ #include #include #ifdef _KERNEL #include #include #include #include #endif /* * In general, the sx locks and rwlocks use very similar algorithms. * The main difference in the implementations is how threads are * blocked when a lock is unavailable. For this, sx locks use sleep * queues which do not support priority propagation, and rwlocks use * turnstiles which do. * * The sx_lock field consists of several fields. The low bit * indicates if the lock is locked with a shared or exclusive lock. A * value of 0 indicates an exclusive lock, and a value of 1 indicates * a shared lock. Bit 1 is a boolean indicating if there are any * threads waiting for a shared lock. Bit 2 is a boolean indicating * if there are any threads waiting for an exclusive lock. Bit 3 is a * boolean indicating if an exclusive lock is recursively held. The * rest of the variable's definition is dependent on the value of the * first bit. For an exclusive lock, it is a pointer to the thread * holding the lock, similar to the mtx_lock field of mutexes. For * shared locks, it is a count of read locks that are held. * * When the lock is not locked by any thread, it is encoded as a * shared lock with zero waiters. */ #define SX_LOCK_SHARED 0x01 #define SX_LOCK_SHARED_WAITERS 0x02 #define SX_LOCK_EXCLUSIVE_WAITERS 0x04 #define SX_LOCK_RECURSED 0x08 #define SX_LOCK_FLAGMASK \ (SX_LOCK_SHARED | SX_LOCK_SHARED_WAITERS | \ SX_LOCK_EXCLUSIVE_WAITERS | SX_LOCK_RECURSED) #define SX_OWNER(x) ((x) & ~SX_LOCK_FLAGMASK) #define SX_SHARERS_SHIFT 4 #define SX_SHARERS(x) (SX_OWNER(x) >> SX_SHARERS_SHIFT) #define SX_SHARERS_LOCK(x) \ ((x) << SX_SHARERS_SHIFT | SX_LOCK_SHARED) #define SX_ONE_SHARER (1 << SX_SHARERS_SHIFT) #define SX_LOCK_UNLOCKED SX_SHARERS_LOCK(0) #define SX_LOCK_DESTROYED \ (SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS) #ifdef _KERNEL #define sx_recurse lock_object.lo_data #define SX_READ_VALUE(sx) ((sx)->sx_lock) #define lv_sx_owner(v) \ ((v & SX_LOCK_SHARED) ? NULL : (struct thread *)SX_OWNER(v)) /* * Function prototipes. Routines that start with an underscore are not part * of the public interface and are wrappered with a macro. */ void sx_sysinit(void *arg); #define sx_init(sx, desc) sx_init_flags((sx), (desc), 0) void sx_init_flags(struct sx *sx, const char *description, int opts); void sx_destroy(struct sx *sx); int sx_try_slock_(struct sx *sx, const char *file, int line); int sx_try_xlock_(struct sx *sx, const char *file, int line); int sx_try_upgrade_(struct sx *sx, const char *file, int line); void sx_downgrade_(struct sx *sx, const char *file, int line); int _sx_slock(struct sx *sx, int opts, const char *file, int line); int _sx_xlock(struct sx *sx, int opts, const char *file, int line); void _sx_sunlock(struct sx *sx, const char *file, int line); void _sx_xunlock(struct sx *sx, const char *file, int line); -int _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, +int _sx_xlock_hard(struct sx *sx, uintptr_t v, uintptr_t tid, int opts, const char *file, int line); -int _sx_slock_hard(struct sx *sx, int opts, const char *file, int line); void _sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line); -void _sx_sunlock_hard(struct sx *sx, const char *file, int line); #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT) void _sx_assert(const struct sx *sx, int what, const char *file, int line); #endif #ifdef DDB int sx_chain(struct thread *td, struct thread **ownerp); #endif struct sx_args { struct sx *sa_sx; const char *sa_desc; int sa_flags; }; #define SX_SYSINIT_FLAGS(name, sxa, desc, flags) \ static struct sx_args name##_args = { \ (sxa), \ (desc), \ (flags) \ }; \ SYSINIT(name##_sx_sysinit, SI_SUB_LOCK, SI_ORDER_MIDDLE, \ sx_sysinit, &name##_args); \ SYSUNINIT(name##_sx_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE, \ sx_destroy, (sxa)) #define SX_SYSINIT(name, sxa, desc) SX_SYSINIT_FLAGS(name, sxa, desc, 0) /* * Full lock operations that are suitable to be inlined in non-debug kernels. * If the lock can't be acquired or released trivially then the work is * deferred to 'tougher' functions. */ +#if (LOCK_DEBUG == 0) && !defined(SX_NOINLINE) /* Acquire an exclusive lock. */ static __inline int __sx_xlock(struct sx *sx, struct thread *td, int opts, const char *file, int line) { uintptr_t tid = (uintptr_t)td; + uintptr_t v = SX_LOCK_UNLOCKED; int error = 0; - if (sx->sx_lock != SX_LOCK_UNLOCKED || - !atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, tid)) - error = _sx_xlock_hard(sx, tid, opts, file, line); - else - LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(sx__acquire, sx, - 0, 0, file, line, LOCKSTAT_WRITER); + if (__predict_false(LOCKSTAT_PROFILE_ENABLED(sx__acquire) || + !atomic_fcmpset_acq_ptr(&sx->sx_lock, &v, tid))) + error = _sx_xlock_hard(sx, v, tid, opts, file, line); return (error); } /* Release an exclusive lock. */ static __inline void __sx_xunlock(struct sx *sx, struct thread *td, const char *file, int line) { uintptr_t tid = (uintptr_t)td; - if (sx->sx_recurse == 0) - LOCKSTAT_PROFILE_RELEASE_RWLOCK(sx__release, sx, - LOCKSTAT_WRITER); - if (sx->sx_lock != tid || - !atomic_cmpset_rel_ptr(&sx->sx_lock, tid, SX_LOCK_UNLOCKED)) + if (__predict_false(LOCKSTAT_PROFILE_ENABLED(sx__release) || + !atomic_cmpset_rel_ptr(&sx->sx_lock, tid, SX_LOCK_UNLOCKED))) _sx_xunlock_hard(sx, tid, file, line); } +#endif -/* Acquire a shared lock. */ -static __inline int -__sx_slock(struct sx *sx, int opts, const char *file, int line) -{ - uintptr_t x = sx->sx_lock; - int error = 0; - - if (!(x & SX_LOCK_SHARED) || - !atomic_cmpset_acq_ptr(&sx->sx_lock, x, x + SX_ONE_SHARER)) - error = _sx_slock_hard(sx, opts, file, line); - else - LOCKSTAT_PROFILE_OBTAIN_RWLOCK_SUCCESS(sx__acquire, sx, - 0, 0, file, line, LOCKSTAT_READER); - - return (error); -} - /* - * Release a shared lock. We can just drop a single shared lock so - * long as we aren't trying to drop the last shared lock when other - * threads are waiting for an exclusive lock. This takes advantage of - * the fact that an unlocked lock is encoded as a shared lock with a - * count of 0. - */ -static __inline void -__sx_sunlock(struct sx *sx, const char *file, int line) -{ - uintptr_t x = sx->sx_lock; - - LOCKSTAT_PROFILE_RELEASE_RWLOCK(sx__release, sx, LOCKSTAT_READER); - if (x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS) || - !atomic_cmpset_rel_ptr(&sx->sx_lock, x, x - SX_ONE_SHARER)) - _sx_sunlock_hard(sx, file, line); -} - -/* * Public interface for lock operations. */ #ifndef LOCK_DEBUG #error "LOCK_DEBUG not defined, include before " #endif #if (LOCK_DEBUG > 0) || defined(SX_NOINLINE) #define sx_xlock_(sx, file, line) \ (void)_sx_xlock((sx), 0, (file), (line)) #define sx_xlock_sig_(sx, file, line) \ _sx_xlock((sx), SX_INTERRUPTIBLE, (file), (line)) #define sx_xunlock_(sx, file, line) \ _sx_xunlock((sx), (file), (line)) -#define sx_slock_(sx, file, line) \ - (void)_sx_slock((sx), 0, (file), (line)) -#define sx_slock_sig_(sx, file, line) \ - _sx_slock((sx), SX_INTERRUPTIBLE, (file) , (line)) -#define sx_sunlock_(sx, file, line) \ - _sx_sunlock((sx), (file), (line)) #else #define sx_xlock_(sx, file, line) \ (void)__sx_xlock((sx), curthread, 0, (file), (line)) #define sx_xlock_sig_(sx, file, line) \ __sx_xlock((sx), curthread, SX_INTERRUPTIBLE, (file), (line)) #define sx_xunlock_(sx, file, line) \ __sx_xunlock((sx), curthread, (file), (line)) +#endif /* LOCK_DEBUG > 0 || SX_NOINLINE */ #define sx_slock_(sx, file, line) \ - (void)__sx_slock((sx), 0, (file), (line)) + (void)_sx_slock((sx), 0, (file), (line)) #define sx_slock_sig_(sx, file, line) \ - __sx_slock((sx), SX_INTERRUPTIBLE, (file), (line)) + _sx_slock((sx), SX_INTERRUPTIBLE, (file) , (line)) #define sx_sunlock_(sx, file, line) \ - __sx_sunlock((sx), (file), (line)) -#endif /* LOCK_DEBUG > 0 || SX_NOINLINE */ + _sx_sunlock((sx), (file), (line)) #define sx_try_slock(sx) sx_try_slock_((sx), LOCK_FILE, LOCK_LINE) #define sx_try_xlock(sx) sx_try_xlock_((sx), LOCK_FILE, LOCK_LINE) #define sx_try_upgrade(sx) sx_try_upgrade_((sx), LOCK_FILE, LOCK_LINE) #define sx_downgrade(sx) sx_downgrade_((sx), LOCK_FILE, LOCK_LINE) #ifdef INVARIANTS #define sx_assert_(sx, what, file, line) \ _sx_assert((sx), (what), (file), (line)) #else #define sx_assert_(sx, what, file, line) (void)0 #endif #define sx_xlock(sx) sx_xlock_((sx), LOCK_FILE, LOCK_LINE) #define sx_xlock_sig(sx) sx_xlock_sig_((sx), LOCK_FILE, LOCK_LINE) #define sx_xunlock(sx) sx_xunlock_((sx), LOCK_FILE, LOCK_LINE) #define sx_slock(sx) sx_slock_((sx), LOCK_FILE, LOCK_LINE) #define sx_slock_sig(sx) sx_slock_sig_((sx), LOCK_FILE, LOCK_LINE) #define sx_sunlock(sx) sx_sunlock_((sx), LOCK_FILE, LOCK_LINE) #define sx_assert(sx, what) sx_assert_((sx), (what), __FILE__, __LINE__) /* * Return a pointer to the owning thread if the lock is exclusively * locked. */ #define sx_xholder(sx) \ ((sx)->sx_lock & SX_LOCK_SHARED ? NULL : \ (struct thread *)SX_OWNER((sx)->sx_lock)) #define sx_xlocked(sx) \ (((sx)->sx_lock & ~(SX_LOCK_FLAGMASK & ~SX_LOCK_SHARED)) == \ (uintptr_t)curthread) #define sx_unlock_(sx, file, line) do { \ if (sx_xlocked(sx)) \ sx_xunlock_(sx, file, line); \ else \ sx_sunlock_(sx, file, line); \ } while (0) #define sx_unlock(sx) sx_unlock_((sx), LOCK_FILE, LOCK_LINE) #define sx_sleep(chan, sx, pri, wmesg, timo) \ _sleep((chan), &(sx)->lock_object, (pri), (wmesg), \ tick_sbt * (timo), 0, C_HARDCLOCK) /* * Options passed to sx_init_flags(). */ #define SX_DUPOK 0x01 #define SX_NOPROFILE 0x02 #define SX_NOWITNESS 0x04 #define SX_QUIET 0x08 #define SX_NOADAPTIVE 0x10 #define SX_RECURSE 0x20 #define SX_NEW 0x40 /* * Options passed to sx_*lock_hard(). */ #define SX_INTERRUPTIBLE 0x40 #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT) #define SA_LOCKED LA_LOCKED #define SA_SLOCKED LA_SLOCKED #define SA_XLOCKED LA_XLOCKED #define SA_UNLOCKED LA_UNLOCKED #define SA_RECURSED LA_RECURSED #define SA_NOTRECURSED LA_NOTRECURSED /* Backwards compatibility. */ #define SX_LOCKED LA_LOCKED #define SX_SLOCKED LA_SLOCKED #define SX_XLOCKED LA_XLOCKED #define SX_UNLOCKED LA_UNLOCKED #define SX_RECURSED LA_RECURSED #define SX_NOTRECURSED LA_NOTRECURSED #endif #endif /* _KERNEL */ #endif /* !_SYS_SX_H_ */ Index: projects/ipsec/sys/sys/syscallsubr.h =================================================================== --- projects/ipsec/sys/sys/syscallsubr.h (revision 313312) +++ projects/ipsec/sys/sys/syscallsubr.h (revision 313313) @@ -1,275 +1,281 @@ /*- * Copyright (c) 2002 Ian Dowse. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $FreeBSD$ */ #ifndef _SYS_SYSCALLSUBR_H_ #define _SYS_SYSCALLSUBR_H_ #include #include #include #include #include +#include struct file; struct filecaps; enum idtype; struct itimerval; struct image_args; struct jail; struct kevent; struct kevent_copyops; struct kld_file_stat; struct ksiginfo; struct mbuf; struct msghdr; struct msqid_ds; struct pollfd; struct ogetdirentries_args; struct rlimit; struct rusage; union semun; struct sockaddr; struct stat; struct thr_param; struct sched_param; struct __wrusage; int kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, u_int buflen, u_int path_max); int kern_accept(struct thread *td, int s, struct sockaddr **name, socklen_t *namelen, struct file **fp); int kern_accept4(struct thread *td, int s, struct sockaddr **name, socklen_t *namelen, int flags, struct file **fp); int kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int flags, int mode); int kern_adjtime(struct thread *td, struct timeval *delta, struct timeval *olddelta); int kern_alternate_path(struct thread *td, const char *prefix, const char *path, enum uio_seg pathseg, char **pathbuf, int create, int dirfd); int kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa); int kern_cap_ioctls_limit(struct thread *td, int fd, u_long *cmds, size_t ncmds); int kern_cap_rights_limit(struct thread *td, int fd, cap_rights_t *rights); int kern_chdir(struct thread *td, char *path, enum uio_seg pathseg); int kern_clock_getcpuclockid2(struct thread *td, id_t id, int which, clockid_t *clk_id); int kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts); int kern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec *ats); int kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats); int kern_close(struct thread *td, int fd); int kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa); +int kern_cpuset_getaffinity(struct thread *td, cpulevel_t level, + cpuwhich_t which, id_t id, size_t cpusetsize, cpuset_t *maskp); +int kern_cpuset_setaffinity(struct thread *td, cpulevel_t level, + cpuwhich_t which, id_t id, size_t cpusetsize, + const cpuset_t *maskp); int kern_cpuset_getid(struct thread *td, cpulevel_t level, cpuwhich_t which, id_t id, cpusetid_t *setid); int kern_cpuset_setid(struct thread *td, cpuwhich_t which, id_t id, cpusetid_t setid); int kern_dup(struct thread *td, u_int mode, int flags, int old, int new); int kern_execve(struct thread *td, struct image_args *args, struct mac *mac_p); int kern_fchmodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, mode_t mode, int flag); int kern_fchownat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int uid, int gid, int flag); int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg); int kern_fcntl_freebsd(struct thread *td, int fd, int cmd, long arg); int kern_fhstat(struct thread *td, fhandle_t fh, struct stat *buf); int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf); int kern_fstat(struct thread *td, int fd, struct stat *sbp); int kern_fstatfs(struct thread *td, int fd, struct statfs *buf); int kern_fsync(struct thread *td, int fd, bool fullsync); int kern_ftruncate(struct thread *td, int fd, off_t length); int kern_futimes(struct thread *td, int fd, struct timeval *tptr, enum uio_seg tptrseg); int kern_futimens(struct thread *td, int fd, struct timespec *tptr, enum uio_seg tptrseg); int kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, long *basep, ssize_t *residp, enum uio_seg bufseg); int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize, size_t *countp, enum uio_seg bufseg, int mode); int kern_getitimer(struct thread *, u_int, struct itimerval *); int kern_getppid(struct thread *); int kern_getpeername(struct thread *td, int fd, struct sockaddr **sa, socklen_t *alen); int kern_getrusage(struct thread *td, int who, struct rusage *rup); int kern_getsockname(struct thread *td, int fd, struct sockaddr **sa, socklen_t *alen); int kern_getsockopt(struct thread *td, int s, int level, int name, void *optval, enum uio_seg valseg, socklen_t *valsize); int kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data); int kern_jail(struct thread *td, struct jail *j); int kern_jail_get(struct thread *td, struct uio *options, int flags); int kern_jail_set(struct thread *td, struct uio *options, int flags); int kern_kevent(struct thread *td, int fd, int nchanges, int nevents, struct kevent_copyops *k_ops, const struct timespec *timeout); int kern_kevent_anonymous(struct thread *td, int nevents, struct kevent_copyops *k_ops); int kern_kevent_fp(struct thread *td, struct file *fp, int nchanges, int nevents, struct kevent_copyops *k_ops, const struct timespec *timeout); int kern_kqueue(struct thread *td, int flags, struct filecaps *fcaps); int kern_kldload(struct thread *td, const char *file, int *fileid); int kern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat); int kern_kldunload(struct thread *td, int fileid, int flags); int kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2, enum uio_seg segflg, int follow); int kern_listen(struct thread *td, int s, int backlog); int kern_lseek(struct thread *td, int fd, off_t offset, int whence); int kern_lutimes(struct thread *td, char *path, enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg); int kern_mkdirat(struct thread *td, int fd, char *path, enum uio_seg segflg, int mode); int kern_mkfifoat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int mode); int kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int mode, int dev); int kern_msgctl(struct thread *, int, int, struct msqid_ds *); int kern_msgsnd(struct thread *, int, const void *, size_t, int, long); int kern_msgrcv(struct thread *, int, void *, size_t, long, int, long *); int kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt); int kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap, long *ploff); int kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int flags, int mode); int kern_pathconf(struct thread *td, char *path, enum uio_seg pathseg, int name, u_long flags); int kern_pipe(struct thread *td, int fildes[2], int flags, struct filecaps *fcaps1, struct filecaps *fcaps2); int kern_poll(struct thread *td, struct pollfd *fds, u_int nfds, struct timespec *tsp, sigset_t *uset); int kern_posix_error(struct thread *td, int error); int kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len, int advice); int kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len); int kern_procctl(struct thread *td, enum idtype idtype, id_t id, int com, void *data); int kern_pread(struct thread *td, int fd, void *buf, size_t nbyte, off_t offset); int kern_preadv(struct thread *td, int fd, struct uio *auio, off_t offset); int kern_pselect(struct thread *td, int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tvp, sigset_t *uset, int abi_nfdbits); int kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data); int kern_pwrite(struct thread *td, int fd, const void *buf, size_t nbyte, off_t offset); int kern_pwritev(struct thread *td, int fd, struct uio *auio, off_t offset); int kern_readlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg, char *buf, enum uio_seg bufseg, size_t count); int kern_readv(struct thread *td, int fd, struct uio *auio); int kern_recvit(struct thread *td, int s, struct msghdr *mp, enum uio_seg fromseg, struct mbuf **controlp); int kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, enum uio_seg pathseg); int kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg); int kern_sched_getparam(struct thread *td, struct thread *targettd, struct sched_param *param); int kern_sched_getscheduler(struct thread *td, struct thread *targettd, int *policy); int kern_sched_setparam(struct thread *td, struct thread *targettd, struct sched_param *param); int kern_sched_setscheduler(struct thread *td, struct thread *targettd, int policy, struct sched_param *param); int kern_sched_rr_get_interval(struct thread *td, pid_t pid, struct timespec *ts); int kern_sched_rr_get_interval_td(struct thread *td, struct thread *targettd, struct timespec *ts); int kern_semctl(struct thread *td, int semid, int semnum, int cmd, union semun *arg, register_t *rval); int kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou, fd_set *fd_ex, struct timeval *tvp, int abi_nfdbits); int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags, struct mbuf *control, enum uio_seg segflg); int kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups); int kern_setitimer(struct thread *, u_int, struct itimerval *, struct itimerval *); int kern_setrlimit(struct thread *, u_int, struct rlimit *); int kern_setsockopt(struct thread *td, int s, int level, int name, void *optval, enum uio_seg valseg, socklen_t valsize); int kern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp); int kern_shm_open(struct thread *td, const char *userpath, int flags, mode_t mode, struct filecaps *fcaps); int kern_shmat(struct thread *td, int shmid, const void *shmaddr, int shmflg); int kern_shmctl(struct thread *td, int shmid, int cmd, void *buf, size_t *bufsz); int kern_shutdown(struct thread *td, int s, int how); int kern_sigaction(struct thread *td, int sig, const struct sigaction *act, struct sigaction *oact, int flags); int kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss); int kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset, int flags); int kern_sigsuspend(struct thread *td, sigset_t mask); int kern_sigtimedwait(struct thread *td, sigset_t waitset, struct ksiginfo *ksi, struct timespec *timeout); int kern_socket(struct thread *td, int domain, int type, int protocol); int kern_statat(struct thread *td, int flag, int fd, char *path, enum uio_seg pathseg, struct stat *sbp, void (*hook)(struct vnode *vp, struct stat *sbp)); int kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, struct statfs *buf); int kern_symlinkat(struct thread *td, char *path1, int fd, char *path2, enum uio_seg segflg); int kern_ktimer_create(struct thread *td, clockid_t clock_id, struct sigevent *evp, int *timerid, int preset_id); int kern_ktimer_delete(struct thread *, int); int kern_ktimer_settime(struct thread *td, int timer_id, int flags, struct itimerspec *val, struct itimerspec *oval); int kern_ktimer_gettime(struct thread *td, int timer_id, struct itimerspec *val); int kern_ktimer_getoverrun(struct thread *td, int timer_id); int kern_thr_alloc(struct proc *, int pages, struct thread **); int kern_thr_exit(struct thread *td); int kern_thr_new(struct thread *td, struct thr_param *param); int kern_thr_suspend(struct thread *td, struct timespec *tsp); int kern_truncate(struct thread *td, char *path, enum uio_seg pathseg, off_t length); int kern_unlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg, ino_t oldinum); int kern_utimesat(struct thread *td, int fd, char *path, enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg); int kern_utimensat(struct thread *td, int fd, char *path, enum uio_seg pathseg, struct timespec *tptr, enum uio_seg tptrseg, int follow); int kern_wait(struct thread *td, pid_t pid, int *status, int options, struct rusage *rup); int kern_wait6(struct thread *td, enum idtype idtype, id_t id, int *status, int options, struct __wrusage *wrup, siginfo_t *sip); int kern_writev(struct thread *td, int fd, struct uio *auio); int kern_socketpair(struct thread *td, int domain, int type, int protocol, int *rsv); /* flags for kern_sigaction */ #define KSA_OSIGSET 0x0001 /* uses osigact_t */ #define KSA_FREEBSD4 0x0002 /* uses ucontext4 */ #endif /* !_SYS_SYSCALLSUBR_H_ */ Index: projects/ipsec/sys/sys/types.h =================================================================== --- projects/ipsec/sys/sys/types.h (revision 313312) +++ projects/ipsec/sys/sys/types.h (revision 313313) @@ -1,404 +1,404 @@ /*- * Copyright (c) 1982, 1986, 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)types.h 8.6 (Berkeley) 2/19/95 * $FreeBSD$ */ #ifndef _SYS_TYPES_H_ #define _SYS_TYPES_H_ #include /* Machine type dependent parameters. */ #include #include #include #if __BSD_VISIBLE typedef unsigned char u_char; typedef unsigned short u_short; typedef unsigned int u_int; typedef unsigned long u_long; #ifndef _KERNEL typedef unsigned short ushort; /* Sys V compatibility */ typedef unsigned int uint; /* Sys V compatibility */ #endif #endif /* * XXX POSIX sized integrals that should appear only in . */ #include typedef __uint8_t u_int8_t; /* unsigned integrals (deprecated) */ typedef __uint16_t u_int16_t; typedef __uint32_t u_int32_t; typedef __uint64_t u_int64_t; typedef __uint64_t u_quad_t; /* quads (deprecated) */ typedef __int64_t quad_t; typedef quad_t * qaddr_t; typedef char * caddr_t; /* core address */ typedef const char * c_caddr_t; /* core address, pointer to const */ #ifndef _BLKSIZE_T_DECLARED typedef __blksize_t blksize_t; #define _BLKSIZE_T_DECLARED #endif typedef __cpuwhich_t cpuwhich_t; typedef __cpulevel_t cpulevel_t; typedef __cpusetid_t cpusetid_t; #ifndef _BLKCNT_T_DECLARED typedef __blkcnt_t blkcnt_t; #define _BLKCNT_T_DECLARED #endif #ifndef _CLOCK_T_DECLARED typedef __clock_t clock_t; #define _CLOCK_T_DECLARED #endif #ifndef _CLOCKID_T_DECLARED typedef __clockid_t clockid_t; #define _CLOCKID_T_DECLARED #endif typedef __critical_t critical_t; /* Critical section value */ typedef __int64_t daddr_t; /* disk address */ #ifndef _DEV_T_DECLARED typedef __dev_t dev_t; /* device number or struct cdev */ #define _DEV_T_DECLARED #endif #ifndef _FFLAGS_T_DECLARED typedef __fflags_t fflags_t; /* file flags */ #define _FFLAGS_T_DECLARED #endif typedef __fixpt_t fixpt_t; /* fixed point number */ #ifndef _FSBLKCNT_T_DECLARED /* for statvfs() */ typedef __fsblkcnt_t fsblkcnt_t; typedef __fsfilcnt_t fsfilcnt_t; #define _FSBLKCNT_T_DECLARED #endif #ifndef _GID_T_DECLARED typedef __gid_t gid_t; /* group id */ #define _GID_T_DECLARED #endif #ifndef _IN_ADDR_T_DECLARED typedef __uint32_t in_addr_t; /* base type for internet address */ #define _IN_ADDR_T_DECLARED #endif #ifndef _IN_PORT_T_DECLARED typedef __uint16_t in_port_t; #define _IN_PORT_T_DECLARED #endif #ifndef _ID_T_DECLARED typedef __id_t id_t; /* can hold a uid_t or pid_t */ #define _ID_T_DECLARED #endif #ifndef _INO_T_DECLARED typedef __ino_t ino_t; /* inode number */ #define _INO_T_DECLARED #endif #ifndef _KEY_T_DECLARED typedef __key_t key_t; /* IPC key (for Sys V IPC) */ #define _KEY_T_DECLARED #endif #ifndef _LWPID_T_DECLARED typedef __lwpid_t lwpid_t; /* Thread ID (a.k.a. LWP) */ #define _LWPID_T_DECLARED #endif #ifndef _MODE_T_DECLARED typedef __mode_t mode_t; /* permissions */ #define _MODE_T_DECLARED #endif #ifndef _ACCMODE_T_DECLARED typedef __accmode_t accmode_t; /* access permissions */ #define _ACCMODE_T_DECLARED #endif #ifndef _NLINK_T_DECLARED typedef __nlink_t nlink_t; /* link count */ #define _NLINK_T_DECLARED #endif #ifndef _OFF_T_DECLARED typedef __off_t off_t; /* file offset */ #define _OFF_T_DECLARED #endif #ifndef _OFF64_T_DECLARED typedef __off64_t off64_t; /* file offset (alias) */ #define _OFF64_T_DECLARED #endif #ifndef _PID_T_DECLARED typedef __pid_t pid_t; /* process id */ #define _PID_T_DECLARED #endif typedef __register_t register_t; #ifndef _RLIM_T_DECLARED typedef __rlim_t rlim_t; /* resource limit */ #define _RLIM_T_DECLARED #endif typedef __int64_t sbintime_t; typedef __segsz_t segsz_t; /* segment size (in pages) */ #ifndef _SIZE_T_DECLARED typedef __size_t size_t; #define _SIZE_T_DECLARED #endif #ifndef _SSIZE_T_DECLARED typedef __ssize_t ssize_t; #define _SSIZE_T_DECLARED #endif #ifndef _SUSECONDS_T_DECLARED typedef __suseconds_t suseconds_t; /* microseconds (signed) */ #define _SUSECONDS_T_DECLARED #endif #ifndef _TIME_T_DECLARED typedef __time_t time_t; #define _TIME_T_DECLARED #endif #ifndef _TIMER_T_DECLARED typedef __timer_t timer_t; #define _TIMER_T_DECLARED #endif #ifndef _MQD_T_DECLARED typedef __mqd_t mqd_t; #define _MQD_T_DECLARED #endif typedef __u_register_t u_register_t; #ifndef _UID_T_DECLARED typedef __uid_t uid_t; /* user id */ #define _UID_T_DECLARED #endif #ifndef _USECONDS_T_DECLARED typedef __useconds_t useconds_t; /* microseconds (unsigned) */ #define _USECONDS_T_DECLARED #endif #ifndef _CAP_IOCTL_T_DECLARED #define _CAP_IOCTL_T_DECLARED typedef unsigned long cap_ioctl_t; #endif #ifndef _CAP_RIGHTS_T_DECLARED #define _CAP_RIGHTS_T_DECLARED struct cap_rights; typedef struct cap_rights cap_rights_t; #endif typedef __vm_offset_t vm_offset_t; -typedef __vm_ooffset_t vm_ooffset_t; +typedef __int64_t vm_ooffset_t; typedef __vm_paddr_t vm_paddr_t; -typedef __vm_pindex_t vm_pindex_t; +typedef __uint64_t vm_pindex_t; typedef __vm_size_t vm_size_t; typedef __rman_res_t rman_res_t; #ifdef _KERNEL typedef int boolean_t; typedef struct device *device_t; typedef __intfptr_t intfptr_t; /* * XXX this is fixed width for historical reasons. It should have had type * __int_fast32_t. Fixed-width types should not be used unless binary * compatibility is essential. Least-width types should be used even less * since they provide smaller benefits. * * XXX should be MD. * * XXX this is bogus in -current, but still used for spl*(). */ typedef __uint32_t intrmask_t; /* Interrupt mask (spl, xxx_imask...) */ typedef __uintfptr_t uintfptr_t; typedef __uint64_t uoff_t; typedef char vm_memattr_t; /* memory attribute codes */ typedef struct vm_page *vm_page_t; #if !defined(__bool_true_false_are_defined) && !defined(__cplusplus) #define __bool_true_false_are_defined 1 #define false 0 #define true 1 #if __STDC_VERSION__ < 199901L && __GNUC__ < 3 && !defined(__INTEL_COMPILER) typedef int _Bool; #endif typedef _Bool bool; #endif /* !__bool_true_false_are_defined && !__cplusplus */ #define offsetof(type, field) __offsetof(type, field) #endif /* !_KERNEL */ /* * The following are all things that really shouldn't exist in this header, * since its purpose is to provide typedefs, not miscellaneous doodads. */ #ifdef __POPCNT__ #define __bitcount64(x) __builtin_popcountll((__uint64_t)(x)) #define __bitcount32(x) __builtin_popcount((__uint32_t)(x)) #define __bitcount16(x) __builtin_popcount((__uint16_t)(x)) #define __bitcountl(x) __builtin_popcountl((unsigned long)(x)) #define __bitcount(x) __builtin_popcount((unsigned int)(x)) #else /* * Population count algorithm using SWAR approach * - "SIMD Within A Register". */ static __inline __uint16_t __bitcount16(__uint16_t _x) { _x = (_x & 0x5555) + ((_x & 0xaaaa) >> 1); _x = (_x & 0x3333) + ((_x & 0xcccc) >> 2); _x = (_x + (_x >> 4)) & 0x0f0f; _x = (_x + (_x >> 8)) & 0x00ff; return (_x); } static __inline __uint32_t __bitcount32(__uint32_t _x) { _x = (_x & 0x55555555) + ((_x & 0xaaaaaaaa) >> 1); _x = (_x & 0x33333333) + ((_x & 0xcccccccc) >> 2); _x = (_x + (_x >> 4)) & 0x0f0f0f0f; _x = (_x + (_x >> 8)); _x = (_x + (_x >> 16)) & 0x000000ff; return (_x); } #ifdef __LP64__ static __inline __uint64_t __bitcount64(__uint64_t _x) { _x = (_x & 0x5555555555555555) + ((_x & 0xaaaaaaaaaaaaaaaa) >> 1); _x = (_x & 0x3333333333333333) + ((_x & 0xcccccccccccccccc) >> 2); _x = (_x + (_x >> 4)) & 0x0f0f0f0f0f0f0f0f; _x = (_x + (_x >> 8)); _x = (_x + (_x >> 16)); _x = (_x + (_x >> 32)) & 0x000000ff; return (_x); } #define __bitcountl(x) __bitcount64((unsigned long)(x)) #else static __inline __uint64_t __bitcount64(__uint64_t _x) { return (__bitcount32(_x >> 32) + __bitcount32(_x)); } #define __bitcountl(x) __bitcount32((unsigned long)(x)) #endif #define __bitcount(x) __bitcount32((unsigned int)(x)) #endif #if __BSD_VISIBLE #include /* * minor() gives a cookie instead of an index since we don't want to * change the meanings of bits 0-15 or waste time and space shifting * bits 16-31 for devices that don't use them. */ #define major(x) ((int)(((u_int)(x) >> 8)&0xff)) /* major number */ #define minor(x) ((int)((x)&0xffff00ff)) /* minor number */ #define makedev(x,y) ((dev_t)(((x) << 8) | (y))) /* create dev_t */ /* * These declarations belong elsewhere, but are repeated here and in * to give broken programs a better chance of working with * 64-bit off_t's. */ #ifndef _KERNEL __BEGIN_DECLS #ifndef _FTRUNCATE_DECLARED #define _FTRUNCATE_DECLARED int ftruncate(int, off_t); #endif #ifndef _LSEEK_DECLARED #define _LSEEK_DECLARED off_t lseek(int, off_t, int); #endif #ifndef _MMAP_DECLARED #define _MMAP_DECLARED void * mmap(void *, size_t, int, int, int, off_t); #endif #ifndef _TRUNCATE_DECLARED #define _TRUNCATE_DECLARED int truncate(const char *, off_t); #endif __END_DECLS #endif /* !_KERNEL */ #endif /* __BSD_VISIBLE */ #endif /* !_SYS_TYPES_H_ */ Index: projects/ipsec/sys/vm/vm_object.h =================================================================== --- projects/ipsec/sys/vm/vm_object.h (revision 313312) +++ projects/ipsec/sys/vm/vm_object.h (revision 313313) @@ -1,316 +1,316 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University. * * 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)vm_object.h 8.3 (Berkeley) 1/12/94 * * * Copyright (c) 1987, 1990 Carnegie-Mellon University. * All rights reserved. * * Authors: Avadis Tevanian, Jr., Michael Wayne Young * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * * $FreeBSD$ */ /* * Virtual memory object module definitions. */ #ifndef _VM_OBJECT_ #define _VM_OBJECT_ #include #include #include #include #include /* * Types defined: * * vm_object_t Virtual memory object. * * List of locks * (c) const until freed * (o) per-object lock * (f) free pages queue mutex * */ struct vm_object { struct rwlock lock; TAILQ_ENTRY(vm_object) object_list; /* list of all objects */ LIST_HEAD(, vm_object) shadow_head; /* objects that this is a shadow for */ LIST_ENTRY(vm_object) shadow_list; /* chain of shadow objects */ TAILQ_HEAD(respgs, vm_page) memq; /* list of resident pages */ struct vm_radix rtree; /* root of the resident page radix trie*/ vm_pindex_t size; /* Object size */ int generation; /* generation ID */ int ref_count; /* How many refs?? */ int shadow_count; /* how many objects that this is a shadow for */ vm_memattr_t memattr; /* default memory attribute for pages */ objtype_t type; /* type of pager */ u_short flags; /* see below */ u_short pg_color; /* (c) color of first page in obj */ u_int paging_in_progress; /* Paging (in or out) so don't collapse or destroy */ int resident_page_count; /* number of resident pages */ struct vm_object *backing_object; /* object that I'm a shadow of */ vm_ooffset_t backing_object_offset;/* Offset in backing object */ TAILQ_ENTRY(vm_object) pager_object_list; /* list of all objects of this pager type */ LIST_HEAD(, vm_reserv) rvq; /* list of reservations */ void *handle; union { /* * VNode pager * * vnp_size - current size of file */ struct { off_t vnp_size; vm_ooffset_t writemappings; } vnp; /* * Device pager * * devp_pglist - list of allocated pages */ struct { TAILQ_HEAD(, vm_page) devp_pglist; struct cdev_pager_ops *ops; struct cdev *dev; } devp; /* * SG pager * * sgp_pglist - list of allocated pages */ struct { TAILQ_HEAD(, vm_page) sgp_pglist; } sgp; /* * Swap pager * * swp_tmpfs - back-pointer to the tmpfs vnode, * if any, which uses the vm object * as backing store. The handle * cannot be reused for linking, * because the vnode can be * reclaimed and recreated, making * the handle changed and hash-chain * invalid. * * swp_bcount - number of swap 'swblock' metablocks, each * contains up to 16 swapblk assignments. * see vm/swap_pager.h */ struct { void *swp_tmpfs; int swp_bcount; } swp; } un_pager; struct ucred *cred; vm_ooffset_t charge; void *umtx_data; }; /* * Flags */ #define OBJ_FICTITIOUS 0x0001 /* (c) contains fictitious pages */ #define OBJ_UNMANAGED 0x0002 /* (c) contains unmanaged pages */ #define OBJ_POPULATE 0x0004 /* pager implements populate() */ #define OBJ_DEAD 0x0008 /* dead objects (during rundown) */ #define OBJ_NOSPLIT 0x0010 /* dont split this object */ #define OBJ_UMTXDEAD 0x0020 /* umtx pshared was terminated */ #define OBJ_PIPWNT 0x0040 /* paging in progress wanted */ #define OBJ_MIGHTBEDIRTY 0x0100 /* object might be dirty, only for vnode */ #define OBJ_TMPFS_NODE 0x0200 /* object belongs to tmpfs VREG node */ #define OBJ_TMPFS_DIRTY 0x0400 /* dirty tmpfs obj */ #define OBJ_COLORED 0x1000 /* pg_color is defined */ #define OBJ_ONEMAPPING 0x2000 /* One USE (a single, non-forked) mapping flag */ #define OBJ_DISCONNECTWNT 0x4000 /* disconnect from vnode wanted */ #define OBJ_TMPFS 0x8000 /* has tmpfs vnode allocated */ -#define IDX_TO_OFF(idx) (((vm_ooffset_t)(idx)) << PAGE_SHIFT) -#define OFF_TO_IDX(off) ((vm_pindex_t)(((vm_ooffset_t)(off)) >> PAGE_SHIFT)) +#define IDX_TO_OFF(idx) (((vm_ooffset_t)(idx)) << PAGE_SHIFT) +#define OFF_TO_IDX(off) ((vm_pindex_t)(((vm_ooffset_t)(off)) >> PAGE_SHIFT)) #ifdef _KERNEL #define OBJPC_SYNC 0x1 /* sync I/O */ #define OBJPC_INVAL 0x2 /* invalidate */ #define OBJPC_NOSYNC 0x4 /* skip if VPO_NOSYNC */ /* * The following options are supported by vm_object_page_remove(). */ #define OBJPR_CLEANONLY 0x1 /* Don't remove dirty pages. */ #define OBJPR_NOTMAPPED 0x2 /* Don't unmap pages. */ TAILQ_HEAD(object_q, vm_object); extern struct object_q vm_object_list; /* list of allocated objects */ extern struct mtx vm_object_list_mtx; /* lock for object list and count */ extern struct vm_object kernel_object_store; extern struct vm_object kmem_object_store; #define kernel_object (&kernel_object_store) #define kmem_object (&kmem_object_store) #define VM_OBJECT_ASSERT_LOCKED(object) \ rw_assert(&(object)->lock, RA_LOCKED) #define VM_OBJECT_ASSERT_RLOCKED(object) \ rw_assert(&(object)->lock, RA_RLOCKED) #define VM_OBJECT_ASSERT_WLOCKED(object) \ rw_assert(&(object)->lock, RA_WLOCKED) #define VM_OBJECT_ASSERT_UNLOCKED(object) \ rw_assert(&(object)->lock, RA_UNLOCKED) #define VM_OBJECT_LOCK_DOWNGRADE(object) \ rw_downgrade(&(object)->lock) #define VM_OBJECT_RLOCK(object) \ rw_rlock(&(object)->lock) #define VM_OBJECT_RUNLOCK(object) \ rw_runlock(&(object)->lock) #define VM_OBJECT_SLEEP(object, wchan, pri, wmesg, timo) \ rw_sleep((wchan), &(object)->lock, (pri), (wmesg), (timo)) #define VM_OBJECT_TRYRLOCK(object) \ rw_try_rlock(&(object)->lock) #define VM_OBJECT_TRYWLOCK(object) \ rw_try_wlock(&(object)->lock) #define VM_OBJECT_TRYUPGRADE(object) \ rw_try_upgrade(&(object)->lock) #define VM_OBJECT_WLOCK(object) \ rw_wlock(&(object)->lock) #define VM_OBJECT_WOWNED(object) \ rw_wowned(&(object)->lock) #define VM_OBJECT_WUNLOCK(object) \ rw_wunlock(&(object)->lock) /* * The object must be locked or thread private. */ static __inline void vm_object_set_flag(vm_object_t object, u_short bits) { object->flags |= bits; } /* * Conditionally set the object's color, which (1) enables the allocation * of physical memory reservations for anonymous objects and larger-than- * superpage-sized named objects and (2) determines the first page offset * within the object at which a reservation may be allocated. In other * words, the color determines the alignment of the object with respect * to the largest superpage boundary. When mapping named objects, like * files or POSIX shared memory objects, the color should be set to zero * before a virtual address is selected for the mapping. In contrast, * for anonymous objects, the color may be set after the virtual address * is selected. * * The object must be locked. */ static __inline void vm_object_color(vm_object_t object, u_short color) { if ((object->flags & OBJ_COLORED) == 0) { object->pg_color = color; object->flags |= OBJ_COLORED; } } void vm_object_clear_flag(vm_object_t object, u_short bits); void vm_object_pip_add(vm_object_t object, short i); void vm_object_pip_subtract(vm_object_t object, short i); void vm_object_pip_wakeup(vm_object_t object); void vm_object_pip_wakeupn(vm_object_t object, short i); void vm_object_pip_wait(vm_object_t object, char *waitid); void umtx_shm_object_init(vm_object_t object); void umtx_shm_object_terminated(vm_object_t object); extern int umtx_shm_vnobj_persistent; vm_object_t vm_object_allocate (objtype_t, vm_pindex_t); boolean_t vm_object_coalesce(vm_object_t, vm_ooffset_t, vm_size_t, vm_size_t, boolean_t); void vm_object_collapse (vm_object_t); void vm_object_deallocate (vm_object_t); void vm_object_destroy (vm_object_t); void vm_object_terminate (vm_object_t); void vm_object_set_writeable_dirty (vm_object_t); void vm_object_init (void); void vm_object_madvise(vm_object_t, vm_pindex_t, vm_pindex_t, int); boolean_t vm_object_page_clean(vm_object_t object, vm_ooffset_t start, vm_ooffset_t end, int flags); void vm_object_page_noreuse(vm_object_t object, vm_pindex_t start, vm_pindex_t end); void vm_object_page_remove(vm_object_t object, vm_pindex_t start, vm_pindex_t end, int options); boolean_t vm_object_populate(vm_object_t, vm_pindex_t, vm_pindex_t); void vm_object_print(long addr, boolean_t have_addr, long count, char *modif); void vm_object_reference (vm_object_t); void vm_object_reference_locked(vm_object_t); int vm_object_set_memattr(vm_object_t object, vm_memattr_t memattr); void vm_object_shadow (vm_object_t *, vm_ooffset_t *, vm_size_t); void vm_object_split(vm_map_entry_t); boolean_t vm_object_sync(vm_object_t, vm_ooffset_t, vm_size_t, boolean_t, boolean_t); void vm_object_unwire(vm_object_t object, vm_ooffset_t offset, vm_size_t length, uint8_t queue); struct vnode *vm_object_vnode(vm_object_t object); #endif /* _KERNEL */ #endif /* _VM_OBJECT_ */ Index: projects/ipsec/sys/x86/include/_types.h =================================================================== --- projects/ipsec/sys/x86/include/_types.h (revision 313312) +++ projects/ipsec/sys/x86/include/_types.h (revision 313313) @@ -1,174 +1,172 @@ /*- * Copyright (c) 2002 Mike Barcroft * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From: @(#)ansi.h 8.2 (Berkeley) 1/4/94 * From: @(#)types.h 8.3 (Berkeley) 1/5/94 * $FreeBSD$ */ #ifndef _MACHINE__TYPES_H_ #define _MACHINE__TYPES_H_ #ifndef _SYS_CDEFS_H_ #error this file needs sys/cdefs.h as a prerequisite #endif #include #define __NO_STRICT_ALIGNMENT /* * Basic types upon which most other types are built. */ typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; typedef unsigned short __uint16_t; typedef int __int32_t; typedef unsigned int __uint32_t; #ifdef __LP64__ typedef long __int64_t; typedef unsigned long __uint64_t; #else #ifndef lint __extension__ #endif /* LONGLONG */ typedef long long __int64_t; #ifndef lint __extension__ #endif /* LONGLONG */ typedef unsigned long long __uint64_t; #endif /* * Standard type definitions. */ #ifdef __LP64__ typedef __int32_t __clock_t; /* clock()... */ typedef __int64_t __critical_t; typedef double __double_t; typedef float __float_t; typedef __int64_t __intfptr_t; typedef __int64_t __intptr_t; #else typedef unsigned long __clock_t; typedef __int32_t __critical_t; typedef long double __double_t; typedef long double __float_t; typedef __int32_t __intfptr_t; typedef __int32_t __intptr_t; #endif typedef __int64_t __intmax_t; typedef __int32_t __int_fast8_t; typedef __int32_t __int_fast16_t; typedef __int32_t __int_fast32_t; typedef __int64_t __int_fast64_t; typedef __int8_t __int_least8_t; typedef __int16_t __int_least16_t; typedef __int32_t __int_least32_t; typedef __int64_t __int_least64_t; #ifdef __LP64__ typedef __int64_t __ptrdiff_t; /* ptr1 - ptr2 */ typedef __int64_t __register_t; typedef __int64_t __segsz_t; /* segment size (in pages) */ typedef __uint64_t __size_t; /* sizeof() */ typedef __int64_t __ssize_t; /* byte count or error */ typedef __int64_t __time_t; /* time()... */ typedef __uint64_t __uintfptr_t; typedef __uint64_t __uintptr_t; #else typedef __int32_t __ptrdiff_t; typedef __int32_t __register_t; typedef __int32_t __segsz_t; typedef __uint32_t __size_t; typedef __int32_t __ssize_t; typedef __int32_t __time_t; typedef __uint32_t __uintfptr_t; typedef __uint32_t __uintptr_t; #endif typedef __uint64_t __uintmax_t; typedef __uint32_t __uint_fast8_t; typedef __uint32_t __uint_fast16_t; typedef __uint32_t __uint_fast32_t; typedef __uint64_t __uint_fast64_t; typedef __uint8_t __uint_least8_t; typedef __uint16_t __uint_least16_t; typedef __uint32_t __uint_least32_t; typedef __uint64_t __uint_least64_t; #ifdef __LP64__ typedef __uint64_t __u_register_t; typedef __uint64_t __vm_offset_t; typedef __uint64_t __vm_paddr_t; typedef __uint64_t __vm_size_t; #else typedef __uint32_t __u_register_t; typedef __uint32_t __vm_offset_t; #ifdef PAE typedef __uint64_t __vm_paddr_t; #else typedef __uint32_t __vm_paddr_t; #endif typedef __uint32_t __vm_size_t; #endif -typedef __int64_t __vm_ooffset_t; -typedef __uint64_t __vm_pindex_t; typedef int ___wchar_t; #define __WCHAR_MIN __INT_MIN /* min value for a wchar_t */ #define __WCHAR_MAX __INT_MAX /* max value for a wchar_t */ /* * Unusual type definitions. */ #ifdef __GNUCLIKE_BUILTIN_VARARGS typedef __builtin_va_list __va_list; /* internally known to gcc */ #else #ifdef __LP64__ struct __s_va_list { __uint32_t _pad1[2]; /* gp_offset, fp_offset */ __uint64_t _pad2[2]; /* overflow_arg_area, reg_save_area */ }; typedef struct __s_va_list __va_list; #else typedef char * __va_list; #endif #endif #if defined(__GNUC_VA_LIST_COMPATIBILITY) && !defined(__GNUC_VA_LIST) \ && !defined(__NO_GNUC_VA_LIST) #define __GNUC_VA_LIST typedef __va_list __gnuc_va_list; /* compatibility w/GNU headers*/ #endif #endif /* !_MACHINE__TYPES_H_ */ Index: projects/ipsec/tools/tools/nanobsd/embedded/rpi2.cfg =================================================================== --- projects/ipsec/tools/tools/nanobsd/embedded/rpi2.cfg (revision 313312) +++ projects/ipsec/tools/tools/nanobsd/embedded/rpi2.cfg (revision 313313) @@ -1,36 +1,35 @@ # $FreeBSD$ #- # Copyright (c) 2015 Warner Losh. All Rights Reserved. # Copyright (c) 2010-2011 iXsystems, Inc., All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 iXsystems, Inc. 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. # NANO_ARCH=armv6 NANO_KERNEL=RPI2 NANO_DRIVE=mmcsd0 NANO_NAME=rpi2 NANO_BOOT_PKG=u-boot-rpi2 -NANO_CPUTYPE=cortex-a7 . common # Pull in common definitions, keep last Index: projects/ipsec/usr.bin/sed/main.c =================================================================== --- projects/ipsec/usr.bin/sed/main.c (revision 313312) +++ projects/ipsec/usr.bin/sed/main.c (revision 313313) @@ -1,542 +1,542 @@ /*- * Copyright (c) 2013 Johann 'Myrkraverk' Oskarsson. * Copyright (c) 1992 Diomidis Spinellis. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Diomidis Spinellis of Imperial College, University of London. * * 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1992, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif #ifndef lint static const char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defs.h" #include "extern.h" /* * Linked list of units (strings and files) to be compiled */ struct s_compunit { struct s_compunit *next; enum e_cut {CU_FILE, CU_STRING} type; char *s; /* Pointer to string or fname */ }; /* * Linked list pointer to compilation units and pointer to current * next pointer. */ static struct s_compunit *script, **cu_nextp = &script; /* * Linked list of files to be processed */ struct s_flist { char *fname; struct s_flist *next; }; /* * Linked list pointer to files and pointer to current * next pointer. */ static struct s_flist *files, **fl_nextp = &files; FILE *infile; /* Current input file */ FILE *outfile; /* Current output file */ int aflag, eflag, nflag; int rflags = 0; static int rval; /* Exit status */ static int ispan; /* Whether inplace editing spans across files */ /* * Current file and line number; line numbers restart across compilation * units, but span across input files. The latter is optional if editing * in place. */ const char *fname; /* File name. */ const char *outfname; /* Output file name */ static char oldfname[PATH_MAX]; /* Old file name (for in-place editing) */ static char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */ static const char *inplace; /* Inplace edit file extension. */ u_long linenum; static void add_compunit(enum e_cut, char *); static void add_file(char *); static void usage(void); int main(int argc, char *argv[]) { int c, fflag; char *temp_arg; (void) setlocale(LC_ALL, ""); fflag = 0; inplace = NULL; while ((c = getopt(argc, argv, "EI:ae:f:i:lnru")) != -1) switch (c) { case 'r': /* Gnu sed compat */ case 'E': rflags = REG_EXTENDED; break; case 'I': inplace = optarg; ispan = 1; /* span across input files */ break; case 'a': aflag = 1; break; case 'e': eflag = 1; if ((temp_arg = malloc(strlen(optarg) + 2)) == NULL) err(1, "malloc"); strcpy(temp_arg, optarg); strcat(temp_arg, "\n"); add_compunit(CU_STRING, temp_arg); break; case 'f': fflag = 1; add_compunit(CU_FILE, optarg); break; case 'i': inplace = optarg; ispan = 0; /* don't span across input files */ break; case 'l': if(setvbuf(stdout, NULL, _IOLBF, 0) != 0) warnx("setting line buffered output failed"); break; case 'n': nflag = 1; break; case 'u': if(setvbuf(stdout, NULL, _IONBF, 0) != 0) warnx("setting unbuffered output failed"); break; default: case '?': usage(); } argc -= optind; argv += optind; /* First usage case; script is the first arg */ if (!eflag && !fflag && *argv) { add_compunit(CU_STRING, *argv); argv++; } compile(); /* Continue with first and start second usage */ if (*argv) for (; *argv; argv++) add_file(*argv); else add_file(NULL); process(); cfclose(prog, NULL); if (fclose(stdout)) err(1, "stdout"); exit(rval); } static void usage(void) { (void)fprintf(stderr, "usage: %s script [-Ealnru] [-i extension] [file ...]\n" "\t%s [-Ealnu] [-i extension] [-e script] ... [-f script_file]" " ... [file ...]\n", getprogname(), getprogname()); exit(1); } /* * Like fgets, but go through the chain of compilation units chaining them * together. Empty strings and files are ignored. */ char * cu_fgets(char *buf, int n, int *more) { static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; static FILE *f; /* Current open file */ static char *s; /* Current pointer inside string */ static char string_ident[30]; char *p; again: switch (state) { case ST_EOF: if (script == NULL) { if (more != NULL) *more = 0; return (NULL); } linenum = 0; switch (script->type) { case CU_FILE: if ((f = fopen(script->s, "r")) == NULL) err(1, "%s", script->s); fname = script->s; state = ST_FILE; goto again; case CU_STRING: if (((size_t)snprintf(string_ident, sizeof(string_ident), "\"%s\"", script->s)) >= sizeof(string_ident) - 1) (void)strcpy(string_ident + sizeof(string_ident) - 6, " ...\""); fname = string_ident; s = script->s; state = ST_STRING; goto again; } case ST_FILE: if ((p = fgets(buf, n, f)) != NULL) { linenum++; if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') nflag = 1; if (more != NULL) *more = !feof(f); return (p); } script = script->next; (void)fclose(f); state = ST_EOF; goto again; case ST_STRING: if (linenum == 0 && s[0] == '#' && s[1] == 'n') nflag = 1; p = buf; for (;;) { if (n-- <= 1) { *p = '\0'; linenum++; if (more != NULL) *more = 1; return (buf); } switch (*s) { case '\0': state = ST_EOF; if (s == script->s) { script = script->next; goto again; } else { script = script->next; *p = '\0'; linenum++; if (more != NULL) *more = 0; return (buf); } case '\n': *p++ = '\n'; *p = '\0'; s++; linenum++; if (more != NULL) *more = 0; return (buf); default: *p++ = *s++; } } } /* NOTREACHED */ return (NULL); } /* * Like fgets, but go through the list of files chaining them together. * Set len to the length of the line. */ int mf_fgets(SPACE *sp, enum e_spflag spflag) { struct stat sb; ssize_t len; char *dirbuf, *basebuf; static char *p = NULL; static size_t plen = 0; int c; static int firstfile; if (infile == NULL) { /* stdin? */ if (files->fname == NULL) { if (inplace != NULL) errx(1, "-I or -i may not be used with stdin"); infile = stdin; fname = "stdin"; outfile = stdout; outfname = "stdout"; } firstfile = 1; } for (;;) { if (infile != NULL && (c = getc(infile)) != EOF) { (void)ungetc(c, infile); break; } /* If we are here then either eof or no files are open yet */ if (infile == stdin) { sp->len = 0; return (0); } if (infile != NULL) { fclose(infile); if (*oldfname != '\0') { /* if there was a backup file, remove it */ unlink(oldfname); /* * Backup the original. Note that hard links * are not supported on all filesystems. */ if ((link(fname, oldfname) != 0) && (rename(fname, oldfname) != 0)) { warn("rename()"); if (*tmpfname) unlink(tmpfname); exit(1); } *oldfname = '\0'; } if (*tmpfname != '\0') { if (outfile != NULL && outfile != stdout) if (fclose(outfile) != 0) { warn("fclose()"); unlink(tmpfname); exit(1); } outfile = NULL; if (rename(tmpfname, fname) != 0) { /* this should not happen really! */ warn("rename()"); unlink(tmpfname); exit(1); } *tmpfname = '\0'; } outfname = NULL; } if (firstfile == 0) files = files->next; else firstfile = 0; if (files == NULL) { sp->len = 0; return (0); } fname = files->fname; if (inplace != NULL) { if (lstat(fname, &sb) != 0) err(1, "%s", fname); - if (!(sb.st_mode & S_IFREG)) + if (!S_ISREG(sb.st_mode)) errx(1, "%s: %s %s", fname, "in-place editing only", "works for regular files"); if (*inplace != '\0') { strlcpy(oldfname, fname, sizeof(oldfname)); len = strlcat(oldfname, inplace, sizeof(oldfname)); if (len > (ssize_t)sizeof(oldfname)) errx(1, "%s: name too long", fname); } if ((dirbuf = strdup(fname)) == NULL || (basebuf = strdup(fname)) == NULL) err(1, "strdup"); len = snprintf(tmpfname, sizeof(tmpfname), "%s/.!%ld!%s", dirname(dirbuf), (long)getpid(), basename(basebuf)); free(dirbuf); free(basebuf); if (len >= (ssize_t)sizeof(tmpfname)) errx(1, "%s: name too long", fname); unlink(tmpfname); if (outfile != NULL && outfile != stdout) fclose(outfile); if ((outfile = fopen(tmpfname, "w")) == NULL) err(1, "%s", fname); fchown(fileno(outfile), sb.st_uid, sb.st_gid); fchmod(fileno(outfile), sb.st_mode & ALLPERMS); outfname = tmpfname; if (!ispan) { linenum = 0; resetstate(); } } else { outfile = stdout; outfname = "stdout"; } if ((infile = fopen(fname, "r")) == NULL) { warn("%s", fname); rval = 1; continue; } } /* * We are here only when infile is open and we still have something * to read from it. * * Use getline() so that we can handle essentially infinite input * data. The p and plen are static so each invocation gives * getline() the same buffer which is expanded as needed. */ len = getline(&p, &plen, infile); if (len == -1) err(1, "%s", fname); if (len != 0 && p[len - 1] == '\n') { sp->append_newline = 1; len--; } else if (!lastline()) { sp->append_newline = 1; } else { sp->append_newline = 0; } cspace(sp, p, len, spflag); linenum++; return (1); } /* * Add a compilation unit to the linked list */ static void add_compunit(enum e_cut type, char *s) { struct s_compunit *cu; if ((cu = malloc(sizeof(struct s_compunit))) == NULL) err(1, "malloc"); cu->type = type; cu->s = s; cu->next = NULL; *cu_nextp = cu; cu_nextp = &cu->next; } /* * Add a file to the linked list */ static void add_file(char *s) { struct s_flist *fp; if ((fp = malloc(sizeof(struct s_flist))) == NULL) err(1, "malloc"); fp->next = NULL; *fl_nextp = fp; fp->fname = s; fl_nextp = &fp->next; } static int next_files_have_lines(void) { struct s_flist *file; FILE *file_fd; int ch; file = files; while ((file = file->next) != NULL) { if ((file_fd = fopen(file->fname, "r")) == NULL) continue; if ((ch = getc(file_fd)) != EOF) { /* * This next file has content, therefore current * file doesn't contains the last line. */ ungetc(ch, file_fd); fclose(file_fd); return (1); } fclose(file_fd); } return (0); } int lastline(void) { int ch; if (feof(infile)) { return !( (inplace == NULL || ispan) && next_files_have_lines()); } if ((ch = getc(infile)) == EOF) { return !( (inplace == NULL || ispan) && next_files_have_lines()); } ungetc(ch, infile); return (0); } Index: projects/ipsec =================================================================== --- projects/ipsec (revision 313312) +++ projects/ipsec (revision 313313) Property changes on: projects/ipsec ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r313187-313312