summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorDan McDonald <danmcd@mnx.io>2022-09-12 13:07:56 -0400
committerDan McDonald <danmcd@mnx.io>2022-09-12 13:07:56 -0400
commit920ee8aa55ad6d75d178844ba75e28ef7f3010ca (patch)
tree1f9c5497c4e5423aaa8467c001caf1fbd4828e05 /usr/src
parentade9f3397df3a9ce9857bfb480ae00df04ce9933 (diff)
parentf8e9c7b3ba7100b047717589235b6d05ec43646c (diff)
downloadillumos-joyent-920ee8aa55ad6d75d178844ba75e28ef7f3010ca.tar.gz
[illumos-gate merge]
commit f8e9c7b3ba7100b047717589235b6d05ec43646c 14925 plumb DFv4 into amdzen(4D) commit ba215efe42e70993d3838f7af671f9d9fc0ebc33 14936 need a better SMN addressing mechanism commit 56726c7e321b6e5ecb2f10215f5386016547e68c 14821 Add additional AVX512 capabilities 14822 Need new word of hardware capabilities 14823 aux vector feature mapping should use x86_featureset commit f2ae17ede4a9a93585872a9aa83120497285bdd0 14077 Want wrapper for external SMB server tests commit 544783ca6fcbe20a0c82b42aabd4e88a9ac69e68 14960 mountd: cleaning up some build gags commit 153f3212c5a48deec74be10ba87dd04bc99edbbb 14815 nvmeadm: identify support for namespace management Conflicts: manifest usr/src/cmd/sgs/libconv/common/corenote.c usr/src/cmd/sgs/libconv/common/corenote.msg usr/src/cmd/sgs/rtld/common/globals.c usr/src/cmd/sgs/rtld/common/rtld.msg usr/src/cmd/sgs/rtld/common/setup.c usr/src/uts/common/exec/elf/elf.c usr/src/uts/common/os/exec.c usr/src/uts/common/sys/user.h usr/src/uts/intel/os/cpuid.c usr/src/uts/intel/os/driver_aliases
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fs.d/Makefile4
-rw-r--r--usr/src/cmd/fs.d/nfs/lib/nfs_sec.c29
-rw-r--r--usr/src/cmd/fs.d/nfs/lib/smfcfg.c28
-rw-r--r--usr/src/cmd/fs.d/nfs/mountd/Makefile16
-rw-r--r--usr/src/cmd/fs.d/nfs/mountd/mountd.c48
-rw-r--r--usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c4
-rw-r--r--usr/src/cmd/isainfo/isainfo.c35
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm.c473
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm.h9
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm_dev.c18
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm_print.c263
-rw-r--r--usr/src/cmd/ptools/pargs/pargs.c13
-rw-r--r--usr/src/cmd/sgs/Makefile6
-rw-r--r--usr/src/cmd/sgs/elfcap.chk/Makefile53
-rw-r--r--usr/src/cmd/sgs/elfcap.chk/elfcap_chk.c160
-rw-r--r--usr/src/cmd/sgs/elfdump/common/corenote.c28
-rw-r--r--usr/src/cmd/sgs/elfedit/common/elfconst.c3
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/cap.c61
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/cap.msg33
-rw-r--r--usr/src/cmd/sgs/include/conv.h21
-rw-r--r--usr/src/cmd/sgs/include/debug.h2
-rw-r--r--usr/src/cmd/sgs/include/elfedit.h7
-rw-r--r--usr/src/cmd/sgs/include/libld.h3
-rw-r--r--usr/src/cmd/sgs/include/rtld.h2
-rw-r--r--usr/src/cmd/sgs/include/sgs.h4
-rw-r--r--usr/src/cmd/sgs/libconv/common/cap.c49
-rw-r--r--usr/src/cmd/sgs/libconv/common/cap.msg4
-rw-r--r--usr/src/cmd/sgs/libconv/common/cap_machelf.c19
-rw-r--r--usr/src/cmd/sgs/libconv/common/corenote.c12
-rw-r--r--usr/src/cmd/sgs/libconv/common/corenote.msg3
-rw-r--r--usr/src/cmd/sgs/libconv/common/elf.c2
-rw-r--r--usr/src/cmd/sgs/libld/common/files.c30
-rw-r--r--usr/src/cmd/sgs/libld/common/globals.c6
-rw-r--r--usr/src/cmd/sgs/libld/common/libld.msg4
-rw-r--r--usr/src/cmd/sgs/libld/common/map_support.c6
-rw-r--r--usr/src/cmd/sgs/libld/common/map_v2.c25
-rw-r--r--usr/src/cmd/sgs/libld/common/sections.c20
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/cap.c11
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/files.c13
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/liblddbg.msg9
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/syms.c10
-rw-r--r--usr/src/cmd/sgs/rtld/amd64/_setup.c7
-rw-r--r--usr/src/cmd/sgs/rtld/common/cap.c128
-rw-r--r--usr/src/cmd/sgs/rtld/common/elf.c4
-rw-r--r--usr/src/cmd/sgs/rtld/common/globals.c12
-rw-r--r--usr/src/cmd/sgs/rtld/common/rtld.msg6
-rw-r--r--usr/src/cmd/sgs/rtld/common/setup.c2
-rw-r--r--usr/src/cmd/sgs/rtld/i386/_setup.c7
-rw-r--r--usr/src/cmd/sgs/tools/SUNWonld-README1
-rw-r--r--usr/src/common/elfcap/elfcap.c81
-rw-r--r--usr/src/common/elfcap/elfcap.h19
-rw-r--r--usr/src/lib/fm/topo/modules/common/disk/disk_nvme.c7
-rw-r--r--usr/src/lib/libc/port/gen/getisax.c13
-rw-r--r--usr/src/man/man4d/amdzen.4d12
-rw-r--r--usr/src/man/man8/nvmeadm.897
-rw-r--r--usr/src/pkg/manifests/driver-cpu-amd-zen.p5m44
-rw-r--r--usr/src/pkg/manifests/system-test-elftest.p5m3
-rw-r--r--usr/src/pkg/manifests/system-test-smbsrvtest.p5m33
-rw-r--r--usr/src/test/Makefile3
-rw-r--r--usr/src/test/elf-tests/runfiles/default.run3
-rw-r--r--usr/src/test/elf-tests/tests/Makefile1
-rw-r--r--usr/src/test/elf-tests/tests/capabilities/Makefile41
-rw-r--r--usr/src/test/elf-tests/tests/capabilities/objcap.ksh351
-rw-r--r--usr/src/test/elf-tests/tests/capabilities/symcap.ksh269
-rw-r--r--usr/src/test/smbsrv-tests/Makefile20
-rw-r--r--usr/src/test/smbsrv-tests/Makefile.com69
-rw-r--r--usr/src/test/smbsrv-tests/cmd/Makefile26
-rw-r--r--usr/src/test/smbsrv-tests/cmd/run_smbtorture.py244
-rw-r--r--usr/src/test/smbsrv-tests/cmd/smbsrvtests.ksh55
-rw-r--r--usr/src/test/smbsrv-tests/doc/Makefile36
-rw-r--r--usr/src/test/smbsrv-tests/doc/README84
-rw-r--r--usr/src/test/smbsrv-tests/include/Makefile21
-rw-r--r--usr/src/test/smbsrv-tests/include/default.cfg23
-rw-r--r--usr/src/test/smbsrv-tests/include/smbtor-excl-smb2.txt33
-rw-r--r--usr/src/test/smbsrv-tests/tests/Makefile17
-rw-r--r--usr/src/test/smbsrv-tests/tests/smbtorture/Makefile22
-rw-r--r--usr/src/test/smbsrv-tests/tests/smbtorture/runst-smb2.ksh83
-rwxr-xr-xusr/src/tools/quick/make-smbsrv19
-rw-r--r--usr/src/uts/common/exec/elf/elf.c29
-rw-r--r--usr/src/uts/common/io/cpuid_drv.c3
-rw-r--r--usr/src/uts/common/io/nvme/nvme.c130
-rw-r--r--usr/src/uts/common/io/nvme/nvme_reg.h19
-rw-r--r--usr/src/uts/common/os/exec.c3
-rw-r--r--usr/src/uts/common/sys/auxv.h4
-rw-r--r--usr/src/uts/common/sys/auxv_386.h16
-rw-r--r--usr/src/uts/common/sys/cpuid_drv.h5
-rw-r--r--usr/src/uts/common/sys/elf.h5
-rw-r--r--usr/src/uts/common/sys/nvme.h54
-rw-r--r--usr/src/uts/common/sys/user.h5
-rw-r--r--usr/src/uts/intel/io/amdzen/amdzen.c37
-rw-r--r--usr/src/uts/intel/io/amdzen/amdzen_client.h5
-rw-r--r--usr/src/uts/intel/io/amdzen/smntemp.c5
-rw-r--r--usr/src/uts/intel/io/amdzen/usmn.c8
-rw-r--r--usr/src/uts/intel/io/amdzen/zen_umc.c203
-rw-r--r--usr/src/uts/intel/os/archdep.c12
-rw-r--r--usr/src/uts/intel/os/cpuid.c583
-rw-r--r--usr/src/uts/intel/os/driver_aliases35
-rw-r--r--usr/src/uts/intel/sys/amdzen/df.h4
-rw-r--r--usr/src/uts/intel/sys/amdzen/smn.h461
-rw-r--r--usr/src/uts/intel/sys/amdzen/umc.h368
-rw-r--r--usr/src/uts/intel/sys/x86_archext.h58
101 files changed, 4655 insertions, 839 deletions
diff --git a/usr/src/cmd/fs.d/Makefile b/usr/src/cmd/fs.d/Makefile
index febbdfafaa..91507ef2ed 100644
--- a/usr/src/cmd/fs.d/Makefile
+++ b/usr/src/cmd/fs.d/Makefile
@@ -53,7 +53,6 @@ all:= TARGET= all
install:= TARGET= install
clean:= TARGET= clean
clobber:= TARGET= clobber
-lint:= TARGET= lint
_msg:= TARGET= catalog
USRSBINF= df clri fsck volcopy ff
@@ -66,6 +65,7 @@ USRBIN2USRSBIN= df
USRXPG4BIN2USRSBIN= df
FSLIB= fslib.o
+CLEANFILES += $(FSLIB)
ROOTSBINPROG = $(ROOTFS_PROG:%=$(ROOTSBIN)/%)
ROOTUSRSBINLINKS = $(ROOTFS_PROG:%=$(ROOTUSRSBIN)/%)
@@ -200,8 +200,6 @@ clobber_local: clean_local
$(RM) $(PROG) $(ROOTFS_PROG) $(SPPROG) $(MNTTAB) $(DEFAULTFILES) \
$(CLOBBERFILES)
-lint:
-
$(SUBDIRS): FRC
@cd $@; pwd; $(MAKE) $(TARGET)
diff --git a/usr/src/cmd/fs.d/nfs/lib/nfs_sec.c b/usr/src/cmd/fs.d/nfs/lib/nfs_sec.c
index af83923825..1890010fc3 100644
--- a/usr/src/cmd/fs.d/nfs/lib/nfs_sec.c
+++ b/usr/src/cmd/fs.d/nfs/lib/nfs_sec.c
@@ -87,8 +87,7 @@ extern bool_t rpc_gss_qop_to_num(char *, char *, uint_t *);
* blank() returns true if the line is a blank line, 0 otherwise
*/
static int
-blank(cp)
-char *cp;
+blank(char *cp)
{
while (*cp && isspace(*cp)) {
cp++;
@@ -100,8 +99,7 @@ char *cp;
* comment() returns true if the line is a comment, 0 otherwise.
*/
static int
-comment(cp)
-char *cp;
+comment(char *cp)
{
while (*cp && isspace(*cp)) {
cp++;
@@ -115,9 +113,7 @@ char *cp;
* and returns the integer value associated with the string.
*/
static unsigned long
-getvalue(cp, sc_data)
-char *cp;
-struct sc_data sc_data[];
+getvalue(char *cp, struct sc_data sc_data[])
{
int i; /* used to index through the given struct sc_data array */
@@ -134,8 +130,7 @@ struct sc_data sc_data[];
* the left.
*/
static void
-shift1left(p)
-char *p;
+shift1left(char *p)
{
for (; *p; p++)
*p = *(p + 1);
@@ -150,9 +145,7 @@ char *p;
* XXX We should make this MT-hot by making it more like strtok_r().
*/
static char *
-gettoken(cp, skip)
-char *cp;
-int skip;
+gettoken(char *cp, int skip)
{
static char *savep; /* the place where we left off */
register char *p; /* the beginning of the new token */
@@ -704,7 +697,7 @@ nfs_sec_nego(rpcprog_t vers, CLIENT *clnt, char *fspath, struct snego_t *snego)
/* ARGSUSED */
static int
get_seconfig(int whichway, char *name, int num,
- rpc_gss_service_t service, seconfig_t *entryp)
+ rpc_gss_service_t service, seconfig_t *entryp)
{
char line[BUFSIZ]; /* holds each line of NFSSEC_CONF */
FILE *fp; /* file stream for NFSSEC_CONF */
@@ -866,7 +859,7 @@ nfs_free_secdata(sec_data_t *secdata)
*/
sec_data_t *
nfs_clnt_secdata(seconfig_t *secp, char *hostname, struct knetconfig *knconf,
- struct netbuf *syncaddr, int flags)
+ struct netbuf *syncaddr, int flags)
{
char netname[MAXNETNAMELEN+1];
sec_data_t *secdata;
@@ -1064,16 +1057,16 @@ nfs_syslog_scerr(int scerror, char msg[])
{
switch (scerror) {
case SC_NOMEM :
- sprintf(msg, "%s : no memory", NFSSEC_CONF);
+ (void) sprintf(msg, "%s : no memory", NFSSEC_CONF);
return (0);
case SC_OPENFAIL :
- sprintf(msg, "can not open %s", NFSSEC_CONF);
+ (void) sprintf(msg, "can not open %s", NFSSEC_CONF);
return (0);
case SC_NOTFOUND :
- sprintf(msg, "has no entry in %s", NFSSEC_CONF);
+ (void) sprintf(msg, "has no entry in %s", NFSSEC_CONF);
return (0);
case SC_BADENTRIES :
- sprintf(msg, "bad entry in %s", NFSSEC_CONF);
+ (void) sprintf(msg, "bad entry in %s", NFSSEC_CONF);
return (0);
default:
msg[0] = '\0';
diff --git a/usr/src/cmd/fs.d/nfs/lib/smfcfg.c b/usr/src/cmd/fs.d/nfs/lib/smfcfg.c
index 4f9399143c..da196077e3 100644
--- a/usr/src/cmd/fs.d/nfs/lib/smfcfg.c
+++ b/usr/src/cmd/fs.d/nfs/lib/smfcfg.c
@@ -41,7 +41,7 @@ fs_smf_init(char *fmri, char *instance)
* svc name is of the form svc://network/fs/server:instance1
* FMRI portion is /network/fs/server
*/
- snprintf(srv, MAXPATHLEN, "%s", fmri + strlen("svc:/"));
+ (void) snprintf(srv, MAXPATHLEN, "%s", fmri + strlen("svc:/"));
svcname = strrchr(srv, ':');
if (svcname != NULL)
*svcname = '\0';
@@ -97,7 +97,7 @@ fs_smf_fini(fs_smfhandle_t *handle)
scf_property_destroy(handle->fs_property);
scf_value_destroy(handle->fs_value);
if (handle->fs_handle != NULL) {
- scf_handle_unbind(handle->fs_handle);
+ (void) scf_handle_unbind(handle->fs_handle);
scf_handle_destroy(handle->fs_handle);
}
free(handle);
@@ -126,15 +126,15 @@ fs_smf_set_prop(smf_fstype_t fstype, char *prop_name, char *valbuf,
* The SVC names we are using currently are already
* appended by default. Fix this for instances project.
*/
- snprintf(srv, MAXPATHLEN, "%s", fmri);
+ (void) snprintf(srv, MAXPATHLEN, "%s", fmri);
p = strstr(fmri, ":default");
if (p == NULL) {
- strcat(srv, ":");
+ (void) strcat(srv, ":");
if (instance == NULL)
instance = "default";
if (strlen(srv) + strlen(instance) > MAXPATHLEN)
goto out;
- strncat(srv, instance, strlen(instance));
+ (void) strncat(srv, instance, strlen(instance));
}
svcname = srv;
phandle = fs_smf_init(fmri, instance);
@@ -224,9 +224,11 @@ fs_smf_set_prop(smf_fstype_t fstype, char *prop_name, char *valbuf,
ret = SMF_SYSTEM_ERR;
}
break;
+ default:
+ break;
}
if (ret != SMF_SYSTEM_ERR)
- scf_transaction_commit(tran);
+ (void) scf_transaction_commit(tran);
}
out:
if (tran != NULL)
@@ -257,15 +259,15 @@ fs_smf_get_prop(smf_fstype_t fstype, char *prop_name, char *cbuf,
* The SVC names we are using currently are already
* appended by default. Fix this for instances project.
*/
- snprintf(srv, MAXPATHLEN, "%s", fmri);
+ (void) snprintf(srv, MAXPATHLEN, "%s", fmri);
p = strstr(fmri, ":default");
if (p == NULL) {
- strcat(srv, ":");
+ (void) strcat(srv, ":");
if (instance == NULL)
instance = "default";
if (strlen(srv) + strlen(instance) > MAXPATHLEN)
goto out;
- strncat(srv, instance, strlen(instance));
+ (void) strncat(srv, instance, strlen(instance));
}
svcname = srv;
phandle = fs_smf_init(fmri, instance);
@@ -313,7 +315,7 @@ fs_smf_get_prop(smf_fstype_t fstype, char *prop_name, char *cbuf,
}
ret = 0;
*bufsz = len;
- break;
+ break;
case SCF_TYPE_INTEGER:
if (scf_value_get_integer(val, &valint) != 0) {
ret = scf_error();
@@ -325,7 +327,7 @@ fs_smf_get_prop(smf_fstype_t fstype, char *prop_name, char *cbuf,
goto out;
}
ret = 0;
- break;
+ break;
case SCF_TYPE_BOOLEAN:
if (scf_value_get_boolean(val, &bval) != 0) {
ret = scf_error();
@@ -340,7 +342,9 @@ fs_smf_get_prop(smf_fstype_t fstype, char *prop_name, char *cbuf,
ret = SA_BAD_VALUE;
goto out;
}
- break;
+ break;
+ default:
+ break;
}
} else {
ret = scf_error();
diff --git a/usr/src/cmd/fs.d/nfs/mountd/Makefile b/usr/src/cmd/fs.d/nfs/mountd/Makefile
index 2daa3f38ba..505ab301e3 100644
--- a/usr/src/cmd/fs.d/nfs/mountd/Makefile
+++ b/usr/src/cmd/fs.d/nfs/mountd/Makefile
@@ -31,10 +31,10 @@ ATTMK = $(TYPEPROG)
include ../../Makefile.fstype
-COMMON = $(FSLIB) nfs_sec.o sharetab.o daemon.o smfcfg.o
+COMMON = nfs_sec.o sharetab.o daemon.o smfcfg.o
LOCAL = mountd.o netgroup.o rmtab.o nfsauth.o \
nfsauth_xdr.o exportlist.o hashset.o nfs_cmd.o
-OBJS = $(LOCAL) $(COMMON)
+OBJS = $(FSLIB) $(LOCAL) $(COMMON)
SRCS = $(LOCAL:%.o=%.c) $(FSLIBSRC) ../lib/nfs_sec.c \
../lib/sharetab.c ../lib/daemon.c ../lib/smfcfg.c
DSRC = mountd_dt.d
@@ -43,10 +43,9 @@ LDLIBS += -lrpcsvc -lnsl -lbsm -lsocket -ltsnet -ltsol -lnvpair -lscf -lumem
CPPFLAGS += -D_REENTRANT -I../lib
CERRWARN += $(CNOWARN_UNINIT)
-CERRWARN += -_gcc=-Wno-switch
-# not linted
-SMATCH=off
+# unreachable code in mountd.c is to please the C compiler.
+mountd.o := SMOFF += check_unreachable
$(TYPEPROG): $(OBJS)
$(COMPILE.d) -s $(DSRC) -o $(DOBJ) $(OBJS)
@@ -65,8 +64,5 @@ daemon.o: ../lib/daemon.c
smfcfg.o: ../lib/smfcfg.c
$(COMPILE.c) ../lib/smfcfg.c
-lint:
- $(LINT.c) $(SRCS) $(LDLIBS)
-
-clean:
- $(RM) $(OBJS) $(DOBJ)
+clean:
+ $(RM) $(COMMON) $(LOCAL) $(DOBJ)
diff --git a/usr/src/cmd/fs.d/nfs/mountd/mountd.c b/usr/src/cmd/fs.d/nfs/mountd/mountd.c
index 4ccc82f4a0..1816deabc6 100644
--- a/usr/src/cmd/fs.d/nfs/mountd/mountd.c
+++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.c
@@ -26,7 +26,7 @@
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
@@ -150,9 +150,8 @@ static logging_data *logging_tail = NULL;
static long ngroups_max; /* _SC_NGROUPS_MAX */
static long pw_size; /* _SC_GETPW_R_SIZE_MAX */
-/* ARGSUSED */
static void *
-nfsauth_svc(void *arg)
+nfsauth_svc(void *arg __unused)
{
int doorfd = -1;
uint_t darg;
@@ -327,7 +326,7 @@ do_logging_queue(logging_data *lq)
}
static void *
-logging_svc(void *arg)
+logging_svc(void *arg __unused)
{
logging_data *lq;
@@ -349,22 +348,6 @@ logging_svc(void *arg)
return (NULL);
}
-static int
-convert_int(int *val, char *str)
-{
- long lval;
-
- if (str == NULL || !isdigit(*str))
- return (-1);
-
- lval = strtol(str, &str, 10);
- if (*str != '\0' || lval > INT_MAX)
- return (-2);
-
- *val = (int)lval;
- return (0);
-}
-
/*
* This function is called for each configured network type to
* bind and register our RPC service programs.
@@ -396,7 +379,7 @@ md_svc_tp_create(struct netconfig *nconf)
strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
int err;
- snprintf(port_str, sizeof (port_str), "%u",
+ (void) snprintf(port_str, sizeof (port_str), "%u",
(unsigned short)mountd_port);
hs.h_host = HOST_SELF_BIND;
@@ -460,7 +443,7 @@ main(int argc, char *argv[])
int tmp;
struct netconfig *nconf;
NCONF_HANDLE *nc;
-
+ const char *errstr;
int pipe_fd = -1;
/*
@@ -523,19 +506,20 @@ main(int argc, char *argv[])
rejecting = 1;
break;
case 'm':
- if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
+ tmp = strtonum(optarg, 1, INT_MAX, &errstr);
+ if (errstr != NULL) {
(void) fprintf(stderr, "%s: invalid "
- "max_threads option, using defaults\n",
- argv[0]);
+ "max_threads option: %s, using defaults\n",
+ argv[0], errstr);
break;
}
max_threads = tmp;
break;
case 'p':
- if (convert_int(&tmp, optarg) != 0 || tmp < 1 ||
- tmp > UINT16_MAX) {
+ tmp = strtonum(optarg, 1, UINT16_MAX, &errstr);
+ if (errstr != NULL) {
(void) fprintf(stderr, "%s: invalid port "
- "number\n", argv[0]);
+ "number: %s\n", argv[0], errstr);
break;
}
mountd_port = tmp;
@@ -939,7 +923,7 @@ done:
if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p))
log_cant_reply(transp);
if (path != NULL)
- svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
+ (void) svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
}
/*
@@ -1572,7 +1556,7 @@ reply:
}
if (path != NULL)
- svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
+ (void) svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
if (sh)
sharefree(sh);
@@ -3230,7 +3214,7 @@ umount(struct svc_req *rqstp)
* Without the hostname we can't do audit or delete
* this host from the mount entries.
*/
- svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
+ (void) svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
return;
}
@@ -3250,7 +3234,7 @@ umount(struct svc_req *rqstp)
cln_fini(&cln);
- svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
+ (void) svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
}
/*
diff --git a/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c b/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c
index b92a862d91..6bc35072f3 100644
--- a/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c
+++ b/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c
@@ -185,7 +185,7 @@ nfscmd_charmap_lookup(door_desc_t *dp, nfscmd_arg_t *args)
name = charmap_search(&nb, sh->sh_opts);
if (name != NULL) {
- strcpy(res.result.charmap.codeset, name);
+ (void) strcpy(res.result.charmap.codeset, name);
res.result.charmap.apply = B_TRUE;
res.error = NFSCMD_ERR_SUCCESS;
free(name);
@@ -231,7 +231,7 @@ nfscmd_vers_1(door_desc_t *dp, nfscmd_arg_t *args, size_t size)
void
nfscmd_func(void *cookie, char *dataptr, size_t arg_size,
- door_desc_t *dp, uint_t n_desc)
+ door_desc_t *dp, uint_t n_desc)
{
nfscmd_arg_t *args;
diff --git a/usr/src/cmd/isainfo/isainfo.c b/usr/src/cmd/isainfo/isainfo.c
index dcc07197cd..393b854bdf 100644
--- a/usr/src/cmd/isainfo/isainfo.c
+++ b/usr/src/cmd/isainfo/isainfo.c
@@ -25,6 +25,7 @@
/*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/types.h>
@@ -147,31 +148,53 @@ static void
report_hwcap(int d, const char *isa)
{
struct cpuid_get_hwcap __cgh, *cgh = &__cgh;
- char buffer[1024], cap2[1024];
+ char cap1[ELFCAP_HW1_BUFSIZE];
+ char cap2[ELFCAP_HW2_BUFSIZE];
+ char cap3[ELFCAP_HW3_BUFSIZE];
cgh->cgh_archname = (char *)isa;
if (ioctl(d, CPUID_GET_HWCAP, cgh) != 0)
return;
(void) elfcap_hw1_to_str(ELFCAP_STYLE_LC, cgh->cgh_hwcap[0],
- buffer, sizeof (buffer), ELFCAP_FMT_SNGSPACE, machtype(isa));
+ cap1, sizeof (cap1), ELFCAP_FMT_SNGSPACE, machtype(isa));
- if (cgh->cgh_hwcap[1] != 0)
+ if (cgh->cgh_hwcap[1] != 0) {
(void) elfcap_hw2_to_str(ELFCAP_STYLE_LC, cgh->cgh_hwcap[1],
cap2, sizeof (cap2), ELFCAP_FMT_SNGSPACE, machtype(isa));
- else
+ } else {
cap2[0] = '\0';
+ }
+
+ if (cgh->cgh_hwcap[2] != 0) {
+ (void) elfcap_hw3_to_str(ELFCAP_STYLE_LC, cgh->cgh_hwcap[2],
+ cap3, sizeof (cap3), ELFCAP_FMT_SNGSPACE, machtype(isa));
+ } else {
+ cap3[0] = '\0';
+ }
if (mode & EXTN_MODE) {
(void) printf(":");
+ if (cgh->cgh_hwcap[2] != 0)
+ (void) printf(" %s", cap3);
if (cgh->cgh_hwcap[1] != 0)
(void) printf(" %s", cap2);
- (void) printf(" %s", buffer);
+ (void) printf(" %s", cap1);
(void) printf("\n");
} else {
char *p;
int linecnt = 0;
+ for (p = strtok(cap3, " "); p; p = strtok(NULL, " ")) {
+ if (linecnt + strlen(p) > 68) {
+ (void) printf("\n");
+ linecnt = 0;
+ }
+ if (linecnt == 0)
+ linecnt = printf("\t");
+ linecnt += printf("%s ", p);
+ }
+
for (p = strtok(cap2, " "); p; p = strtok(NULL, " ")) {
if (linecnt + strlen(p) > 68) {
(void) printf("\n");
@@ -182,7 +205,7 @@ report_hwcap(int d, const char *isa)
linecnt += printf("%s ", p);
}
- for (p = strtok(buffer, " "); p; p = strtok(NULL, " ")) {
+ for (p = strtok(cap1, " "); p; p = strtok(NULL, " ")) {
if (linecnt + strlen(p) > 68) {
(void) printf("\n");
linecnt = 0;
diff --git a/usr/src/cmd/nvmeadm/nvmeadm.c b/usr/src/cmd/nvmeadm/nvmeadm.c
index 18b1117a89..74803baacb 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm.c
@@ -35,6 +35,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
@@ -47,6 +48,36 @@
#include "nvmeadm.h"
+/*
+ * Assertions to make sure that we've properly captured various aspects of the
+ * packed structures and haven't broken them during updates.
+ */
+CTASSERT(sizeof (nvme_identify_ctrl_t) == NVME_IDENTIFY_BUFSIZE);
+CTASSERT(offsetof(nvme_identify_ctrl_t, id_oacs) == 256);
+CTASSERT(offsetof(nvme_identify_ctrl_t, id_sqes) == 512);
+CTASSERT(offsetof(nvme_identify_ctrl_t, id_oncs) == 520);
+CTASSERT(offsetof(nvme_identify_ctrl_t, id_subnqn) == 768);
+CTASSERT(offsetof(nvme_identify_ctrl_t, id_nvmof) == 1792);
+CTASSERT(offsetof(nvme_identify_ctrl_t, id_psd) == 2048);
+CTASSERT(offsetof(nvme_identify_ctrl_t, id_vs) == 3072);
+
+CTASSERT(sizeof (nvme_identify_nsid_t) == NVME_IDENTIFY_BUFSIZE);
+CTASSERT(offsetof(nvme_identify_nsid_t, id_fpi) == 32);
+CTASSERT(offsetof(nvme_identify_nsid_t, id_anagrpid) == 92);
+CTASSERT(offsetof(nvme_identify_nsid_t, id_nguid) == 104);
+CTASSERT(offsetof(nvme_identify_nsid_t, id_lbaf) == 128);
+CTASSERT(offsetof(nvme_identify_nsid_t, id_vs) == 384);
+
+CTASSERT(sizeof (nvme_identify_nsid_list_t) == NVME_IDENTIFY_BUFSIZE);
+CTASSERT(sizeof (nvme_identify_ctrl_list_t) == NVME_IDENTIFY_BUFSIZE);
+
+CTASSERT(sizeof (nvme_identify_primary_caps_t) == NVME_IDENTIFY_BUFSIZE);
+CTASSERT(offsetof(nvme_identify_primary_caps_t, nipc_vqfrt) == 32);
+CTASSERT(offsetof(nvme_identify_primary_caps_t, nipc_vifrt) == 64);
+
+CTASSERT(sizeof (nvme_nschange_list_t) == 4096);
+
+
struct nvme_feature {
char *f_name;
char *f_short;
@@ -84,6 +115,8 @@ static int nvme_process(di_node_t, di_minor_t, void *);
static int do_list(int, const nvme_process_arg_t *);
static int do_identify(int, const nvme_process_arg_t *);
+static int do_identify_ctrl(int, const nvme_process_arg_t *);
+static int do_identify_ns(int, const nvme_process_arg_t *);
static int do_get_logpage_error(int, const nvme_process_arg_t *);
static int do_get_logpage_health(int, const nvme_process_arg_t *);
static int do_get_logpage_fwslot(int, const nvme_process_arg_t *);
@@ -103,10 +136,15 @@ static int do_firmware_commit(int, const nvme_process_arg_t *);
static int do_firmware_activate(int, const nvme_process_arg_t *);
static void optparse_list(nvme_process_arg_t *);
+static void optparse_identify(nvme_process_arg_t *);
+static void optparse_identify_ctrl(nvme_process_arg_t *);
+static void optparse_identify_ns(nvme_process_arg_t *);
static void optparse_secure_erase(nvme_process_arg_t *);
static void usage_list(const char *);
static void usage_identify(const char *);
+static void usage_identify_ctrl(const char *);
+static void usage_identify_ns(const char *);
static void usage_get_logpage(const char *);
static void usage_get_features(const char *);
static void usage_format(const char *);
@@ -122,8 +160,21 @@ int debug;
#define NVMEADM_O_SE_CRYPTO 0x00000004
+#define NVMEADM_O_ID_NSID_LIST 0x00000008
+#define NVMEADM_O_ID_COMMON_NS 0x00000010
+#define NVMEADM_O_ID_CTRL_LIST 0x00000020
+#define NVMEADM_O_ID_DESC_LIST 0x00000040
+#define NVMEADM_O_ID_ALLOC_NS 0x00000080
+
static int exitcode;
+/*
+ * Nvmeadm subcommand definitons.
+ *
+ * When adding a new subcommand, please check that the commands still
+ * line up in the usage() message, and adjust the format string in
+ * usage() below if necessary.
+ */
static const nvmeadm_cmd_t nvmeadm_cmds[] = {
{
"list",
@@ -136,8 +187,30 @@ static const nvmeadm_cmd_t nvmeadm_cmds[] = {
{
"identify",
"identify controllers and/or namespaces",
- NULL,
- do_identify, usage_identify, NULL,
+ " -C\t\tget Common Namespace Identification\n"
+ " -a\t\tget only allocated namespace information\n"
+ " -c\t\tget controller identifier list\n"
+ " -d\t\tget namespace identification descriptors list\n"
+ " -n\t\tget namespaces identifier list\n",
+ do_identify, usage_identify, optparse_identify,
+ NVMEADM_C_MULTI
+ },
+ {
+ "identify-controller",
+ "identify controllers",
+ " -C\t\tget Common Namespace Identification\n"
+ " -a\t\tget only allocated namespace information\n"
+ " -c\t\tget controller identifier list\n"
+ " -n\t\tget namespaces identifier list\n",
+ do_identify_ctrl, usage_identify_ctrl, optparse_identify_ctrl,
+ NVMEADM_C_MULTI
+ },
+ {
+ "identify-namespace",
+ "identify namespaces",
+ " -c\t\tget attached controller identifier list\n"
+ " -d\t\tget namespace identification descriptors list\n",
+ do_identify_ns, usage_identify_ns, optparse_identify_ns,
NVMEADM_C_MULTI
},
{
@@ -276,12 +349,15 @@ main(int argc, char **argv)
case 'd':
debug++;
break;
+
case 'v':
verbose++;
break;
+
case 'h':
help++;
break;
+
case '?':
usage(NULL);
exit(-1);
@@ -426,9 +502,15 @@ usage(const nvmeadm_cmd_t *cmd)
"\n Manage NVMe controllers and namespaces.\n");
(void) fprintf(stderr, "\ncommands:\n");
- for (cmd = &nvmeadm_cmds[0]; cmd->c_name != NULL; cmd++)
- (void) fprintf(stderr, " %-18s - %s\n",
+ for (cmd = &nvmeadm_cmds[0]; cmd->c_name != NULL; cmd++) {
+ /*
+ * The longest nvmeadm subcommand is 19 characters long.
+ * The format string needs to be updated every time a
+ * longer subcommand is added.
+ */
+ (void) fprintf(stderr, " %-19s - %s\n",
cmd->c_name, cmd->c_desc);
+ }
}
(void) fprintf(stderr, "\n%s flags:\n"
" -h\t\tprint usage information\n"
@@ -559,11 +641,22 @@ nvme_process(di_node_t node, di_minor_t minor, void *arg)
if (npa->npa_version == NULL)
goto out;
- npa->npa_idctl = nvme_identify_ctrl(fd);
+ npa->npa_idctl = nvme_identify(fd, NVME_IDENTIFY_CTRL);
if (npa->npa_idctl == NULL)
goto out;
- npa->npa_idns = nvme_identify_nsid(fd);
+ if (nvme_version_check(npa->npa_version, 1, 2) &&
+ npa->npa_idctl->id_oacs.oa_nsmgmt != 0 &&
+ npa->npa_isns) {
+ /*
+ * We prefer NVME_IDENTIFY_NSID_ALLOC when supported as that can
+ * return data on inactive namespaces, too.
+ */
+ npa->npa_idns = nvme_identify(fd, NVME_IDENTIFY_NSID_ALLOC);
+ } else {
+ npa->npa_idns = nvme_identify(fd, NVME_IDENTIFY_NSID);
+ }
+
if (npa->npa_idns == NULL)
goto out;
@@ -630,17 +723,17 @@ optparse_list(nvme_process_arg_t *npa)
case 'o':
fields = optarg;
break;
+
case 'p':
parse = B_TRUE;
oflags |= OFMT_PARSABLE;
break;
+
case '?':
- errx(-1, "unknown list option: -%c", optopt);
- break;
+ errx(-1, "unknown option: -%c", optopt);
+
case ':':
errx(-1, "option -%c requires an argument", optopt);
- default:
- break;
}
}
@@ -741,17 +834,155 @@ do_list(int fd, const nvme_process_arg_t *npa)
}
static void
-usage_identify(const char *c_name)
+optparse_identify_ctrl(nvme_process_arg_t *npa)
+{
+ int c;
+
+ optind = 0;
+ while ((c = getopt(npa->npa_argc, npa->npa_argv, ":Cacn")) != -1) {
+ switch (c) {
+ case 'C':
+ npa->npa_cmdflags |= NVMEADM_O_ID_COMMON_NS;
+ break;
+
+ case 'a':
+ npa->npa_cmdflags |= NVMEADM_O_ID_ALLOC_NS;
+ break;
+
+ case 'c':
+ npa->npa_cmdflags |= NVMEADM_O_ID_CTRL_LIST;
+ break;
+
+ case 'n':
+ npa->npa_cmdflags |= NVMEADM_O_ID_NSID_LIST;
+ break;
+
+ case '?':
+ errx(-1, "unknown option: -%c", optopt);
+
+ case ':':
+ errx(-1, "option -%c requires an argument", optopt);
+ }
+ }
+
+ npa->npa_argc -= optind;
+ npa->npa_argv += optind;
+}
+
+static void
+usage_identify_ctrl(const char *c_name)
{
- (void) fprintf(stderr, "%s <ctl>[/<ns>][,...]\n\n"
+ (void) fprintf(stderr, "%s [-C | -c | [-a] -n] <ctl>[,...]\n\n"
" Print detailed information about the specified NVMe "
- "controllers and/or name-\n spaces.\n", c_name);
+ "controllers.\n", c_name);
}
static int
-do_identify(int fd, const nvme_process_arg_t *npa)
+do_identify_ctrl(int fd, const nvme_process_arg_t *npa)
{
- if (!npa->npa_isns) {
+ boolean_t alloc = B_FALSE;
+
+ if (npa->npa_isns)
+ errx(-1, "identify-controller cannot be used on namespaces");
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_COMMON_NS) != 0 &&
+ npa->npa_cmdflags != NVMEADM_O_ID_COMMON_NS) {
+ errx(-1, "-C cannot be combined with other flags");
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_CTRL_LIST) != 0 &&
+ npa->npa_cmdflags != NVMEADM_O_ID_CTRL_LIST) {
+ errx(-1, "-c cannot be combined with other flags");
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_ALLOC_NS) != 0 &&
+ npa->npa_cmdflags !=
+ (NVMEADM_O_ID_ALLOC_NS | NVMEADM_O_ID_NSID_LIST)) {
+ errx(-1, "-a can only be used together with -n");
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_ALLOC_NS) != 0) {
+ if (!nvme_version_check(npa->npa_version, 1, 2)) {
+ warnx("%s: -a is not supported on NVMe v%u.%u",
+ npa->npa_name, npa->npa_version->v_major,
+ npa->npa_version->v_minor);
+ return (-1);
+ }
+
+ if (npa->npa_idctl->id_oacs.oa_nsmgmt == 0) {
+ warnx("%s: Namespace Management not supported",
+ npa->npa_name);
+ return (-1);
+ }
+
+ alloc = B_TRUE;
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_COMMON_NS) != 0) {
+ if (!nvme_version_check(npa->npa_version, 1, 2)) {
+ warnx("%s: -C is not supported on NVMe v%u.%u",
+ npa->npa_name, npa->npa_version->v_major,
+ npa->npa_version->v_minor);
+ return (-1);
+ }
+
+ if (npa->npa_idctl->id_oacs.oa_nsmgmt == 0) {
+ warnx("%s: Namespace Management not supported",
+ npa->npa_name);
+ return (-1);
+ }
+
+ (void) printf("%s: ", npa->npa_name);
+ nvme_print_identify_nsid(npa->npa_idns, npa->npa_version);
+ } else if ((npa->npa_cmdflags & NVMEADM_O_ID_NSID_LIST) != 0) {
+ char *caption = "Identify Active Namespace List";
+ nvme_identify_nsid_list_t *idnslist;
+
+ if (!nvme_version_check(npa->npa_version, 1, 1)) {
+ warnx("%s: -n is not supported on NVMe v%u.%u",
+ npa->npa_name, npa->npa_version->v_major,
+ npa->npa_version->v_minor);
+ return (-1);
+ }
+
+ idnslist = nvme_identify(fd, alloc ?
+ NVME_IDENTIFY_NSID_ALLOC_LIST : NVME_IDENTIFY_NSID_LIST);
+
+ if (idnslist == NULL)
+ return (-1);
+
+ if (alloc)
+ caption = "Identify Allocated Namespace List";
+
+ (void) printf("%s: ", npa->npa_name);
+
+ nvme_print_identify_nsid_list(caption, idnslist);
+ free(idnslist);
+ } else if ((npa->npa_cmdflags & NVMEADM_O_ID_CTRL_LIST) != 0) {
+ nvme_identify_ctrl_list_t *ctlist;
+
+ if (!nvme_version_check(npa->npa_version, 1, 2)) {
+ warnx("%s: -c is not supported on NVMe v%u.%u",
+ npa->npa_name, npa->npa_version->v_major,
+ npa->npa_version->v_minor);
+ return (-1);
+ }
+
+ if (npa->npa_idctl->id_oacs.oa_nsmgmt == 0) {
+ warnx("%s: Namespace Management not supported",
+ npa->npa_name);
+ return (-1);
+ }
+
+ ctlist = nvme_identify(fd, NVME_IDENTIFY_CTRL_LIST);
+ if (ctlist == NULL)
+ return (-1);
+
+ (void) printf("%s: ", npa->npa_name);
+ nvme_print_identify_ctrl_list("Identify Controller List",
+ ctlist);
+ free(ctlist);
+ } else {
nvme_capabilities_t *cap;
cap = nvme_capabilities(fd);
@@ -759,21 +990,217 @@ do_identify(int fd, const nvme_process_arg_t *npa)
return (-1);
(void) printf("%s: ", npa->npa_name);
- nvme_print_identify_ctrl(npa->npa_idctl, cap,
- npa->npa_version);
+ nvme_print_identify_ctrl(npa->npa_idctl, cap, npa->npa_version);
free(cap);
+ }
+
+ return (0);
+}
+
+static void
+optparse_identify_ns(nvme_process_arg_t *npa)
+{
+ int c;
+
+ optind = 0;
+ while ((c = getopt(npa->npa_argc, npa->npa_argv, ":cd")) != -1) {
+ switch (c) {
+ case 'c':
+ npa->npa_cmdflags |= NVMEADM_O_ID_CTRL_LIST;
+ break;
+
+ case 'd':
+ npa->npa_cmdflags |= NVMEADM_O_ID_DESC_LIST;
+ break;
+
+ case '?':
+ errx(-1, "unknown option: -%c", optopt);
+
+ case ':':
+ errx(-1, "option -%c requires an argument", optopt);
+ }
+ }
+
+ npa->npa_argc -= optind;
+ npa->npa_argv += optind;
+}
+
+static void
+usage_identify_ns(const char *c_name)
+{
+ (void) fprintf(stderr, "%s [-c | -d ] <ctl>/<ns>[,...]\n\n"
+ " Print detailed information about the specified NVMe "
+ "namespaces.\n", c_name);
+}
+
+static int
+do_identify_ns(int fd, const nvme_process_arg_t *npa)
+{
+ if (!npa->npa_isns)
+ errx(-1, "identify-namespace cannot be used on controllers");
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_CTRL_LIST) != 0 &&
+ npa->npa_cmdflags != NVMEADM_O_ID_CTRL_LIST) {
+ errx(-1, "-c cannot be combined with other flags");
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_DESC_LIST) != 0 &&
+ npa->npa_cmdflags != NVMEADM_O_ID_DESC_LIST) {
+ errx(-1, "-d cannot be combined with other flags");
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_ALLOC_NS) != 0) {
+ errx(-1, "-a cannot be used on namespaces");
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_CTRL_LIST) != 0) {
+ nvme_identify_ctrl_list_t *ctlist;
+
+ if (!nvme_version_check(npa->npa_version, 1, 2)) {
+ warnx("%s: -c is not supported on NVMe v%u.%u",
+ npa->npa_name, npa->npa_version->v_major,
+ npa->npa_version->v_minor);
+ return (-1);
+ }
+
+ if (npa->npa_idctl->id_oacs.oa_nsmgmt == 0) {
+ warnx("%s: Namespace Management not supported",
+ npa->npa_name);
+ return (-1);
+ }
+
+ ctlist = nvme_identify(fd, NVME_IDENTIFY_NSID_CTRL_LIST);
+ if (ctlist == NULL)
+ return (-1);
+
+ (void) printf("%s/%s: ", npa->npa_name,
+ di_minor_name(npa->npa_minor));
+ nvme_print_identify_ctrl_list(
+ "Identify Attached Controller List", ctlist);
+ free(ctlist);
+ } else if ((npa->npa_cmdflags & NVMEADM_O_ID_DESC_LIST) != 0) {
+ nvme_identify_nsid_desc_t *nsdesc;
+
+ if (!nvme_version_check(npa->npa_version, 1, 3)) {
+ warnx("%s: -d is not supported on NVMe v%u.%u",
+ npa->npa_name, npa->npa_version->v_major,
+ npa->npa_version->v_minor);
+ return (-1);
+ }
+
+ nsdesc = nvme_identify(fd, NVME_IDENTIFY_NSID_DESC);
+ if (nsdesc == NULL)
+ return (-1);
+
+ (void) printf("%s/%s: ", npa->npa_name,
+ di_minor_name(npa->npa_minor));
+ nvme_print_identify_nsid_desc(nsdesc);
+ free(nsdesc);
} else {
(void) printf("%s/%s: ", npa->npa_name,
di_minor_name(npa->npa_minor));
- nvme_print_identify_nsid(npa->npa_idns,
- npa->npa_version);
+ nvme_print_identify_nsid(npa->npa_idns, npa->npa_version);
}
return (0);
}
static void
+optparse_identify(nvme_process_arg_t *npa)
+{
+ int c;
+
+ optind = 0;
+ while ((c = getopt(npa->npa_argc, npa->npa_argv, ":Cacdn")) != -1) {
+ switch (c) {
+ case 'C':
+ npa->npa_cmdflags |= NVMEADM_O_ID_COMMON_NS;
+ break;
+
+ case 'a':
+ npa->npa_cmdflags |= NVMEADM_O_ID_ALLOC_NS;
+ break;
+
+ case 'c':
+ npa->npa_cmdflags |= NVMEADM_O_ID_CTRL_LIST;
+ break;
+
+ case 'd':
+ npa->npa_cmdflags |= NVMEADM_O_ID_DESC_LIST;
+ break;
+
+ case 'n':
+ npa->npa_cmdflags |= NVMEADM_O_ID_NSID_LIST;
+ break;
+
+ case '?':
+ errx(-1, "unknown option: -%c", optopt);
+
+ case ':':
+ errx(-1, "option -%c requires an argument", optopt);
+
+ }
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_ALLOC_NS) != 0 &&
+ (npa->npa_cmdflags &
+ ~(NVMEADM_O_ID_ALLOC_NS | NVMEADM_O_ID_NSID_LIST)) != 0) {
+ errx(-1, "-a can only be used alone or together with -n");
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_COMMON_NS) != 0 &&
+ npa->npa_cmdflags != NVMEADM_O_ID_COMMON_NS) {
+ errx(-1, "-C cannot be combined with other flags");
+
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_CTRL_LIST) != 0 &&
+ npa->npa_cmdflags != NVMEADM_O_ID_CTRL_LIST) {
+ errx(-1, "-c cannot be combined with other flags");
+ }
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_DESC_LIST) != 0 &&
+ npa->npa_cmdflags != NVMEADM_O_ID_DESC_LIST) {
+ errx(-1, "-d cannot be combined with other flags");
+ }
+
+ npa->npa_argc -= optind;
+ npa->npa_argv += optind;
+}
+
+static void
+usage_identify(const char *c_name)
+{
+ (void) fprintf(stderr,
+ "%s [ -C | -c | -d | [-a] -n ] <ctl>[/<ns>][,...]\n\n"
+ " Print detailed information about the specified NVMe "
+ "controllers and/or name-\n spaces.\n", c_name);
+}
+
+static int
+do_identify(int fd, const nvme_process_arg_t *npa)
+{
+ if (npa->npa_isns) {
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_COMMON_NS) != 0)
+ errx(-1, "-C cannot be used on namespaces");
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_ALLOC_NS) != 0)
+ errx(-1, "-a cannot be used on namespaces");
+
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_NSID_LIST) != 0)
+ errx(-1, "-n cannot be used on namespaces");
+
+ return (do_identify_ns(fd, npa));
+ } else {
+ if ((npa->npa_cmdflags & NVMEADM_O_ID_DESC_LIST) != 0)
+ errx(-1, "-d cannot be used on controllers");
+
+ return (do_identify_ctrl(fd, npa));
+ }
+}
+
+static void
usage_get_logpage(const char *c_name)
{
(void) fprintf(stderr, "%s <ctl>[/<ns>][,...] <logpage>\n\n"
@@ -1273,9 +1700,13 @@ optparse_secure_erase(nvme_process_arg_t *npa)
case 'c':
npa->npa_cmdflags |= NVMEADM_O_SE_CRYPTO;
break;
+
case '?':
- errx(-1, "unknown secure-erase option: -%c", optopt);
- break;
+ errx(-1, "unknown option: -%c", optopt);
+
+ case ':':
+ errx(-1, "option -%c requires an argument", optopt);
+
}
}
diff --git a/usr/src/cmd/nvmeadm/nvmeadm.h b/usr/src/cmd/nvmeadm/nvmeadm.h
index 0be877305f..97f3e6a677 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm.h
+++ b/usr/src/cmd/nvmeadm/nvmeadm.h
@@ -53,6 +53,7 @@ struct nvme_process_arg {
uint32_t npa_ns_state;
nvme_identify_ctrl_t *npa_idctl;
nvme_identify_nsid_t *npa_idns;
+ nvme_identify_nsid_list_t *npa_idnslist;
nvme_version_t *npa_version;
ofmt_handle_t npa_ofmt;
};
@@ -68,6 +69,11 @@ extern void nvme_print_nsid_summary(nvme_identify_nsid_t *);
extern void nvme_print_identify_ctrl(nvme_identify_ctrl_t *,
nvme_capabilities_t *, nvme_version_t *);
extern void nvme_print_identify_nsid(nvme_identify_nsid_t *, nvme_version_t *);
+extern void nvme_print_identify_nsid_list(const char *,
+ nvme_identify_nsid_list_t *);
+extern void nvme_print_identify_nsid_desc(void *);
+extern void nvme_print_identify_ctrl_list(const char *,
+ nvme_identify_ctrl_list_t *);
extern void nvme_print_error_log(int, nvme_error_log_entry_t *,
nvme_version_t *);
extern void nvme_print_health_log(nvme_health_log_t *, nvme_identify_ctrl_t *,
@@ -107,8 +113,7 @@ extern int nvme_open(di_minor_t, boolean_t);
extern void nvme_close(int);
extern nvme_version_t *nvme_version(int);
extern nvme_capabilities_t *nvme_capabilities(int);
-extern nvme_identify_ctrl_t *nvme_identify_ctrl(int);
-extern nvme_identify_nsid_t *nvme_identify_nsid(int);
+extern void *nvme_identify(int, uint8_t);
extern void *nvme_get_logpage(int, uint8_t, size_t *);
extern boolean_t nvme_get_feature(int, uint8_t, uint32_t, uint64_t *, size_t *,
void **);
diff --git a/usr/src/cmd/nvmeadm/nvmeadm_dev.c b/usr/src/cmd/nvmeadm/nvmeadm_dev.c
index a86224c973..ce3bc96e22 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm_dev.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm_dev.c
@@ -104,29 +104,17 @@ nvme_version(int fd)
return (vs);
}
-nvme_identify_ctrl_t *
-nvme_identify_ctrl(int fd)
+void *
+nvme_identify(int fd, uint8_t cns)
{
void *idctl = NULL;
size_t bufsize = NVME_IDENTIFY_BUFSIZE;
- (void) nvme_ioctl(fd, NVME_IOC_IDENTIFY_CTRL, &bufsize, &idctl, 0,
- NULL);
+ (void) nvme_ioctl(fd, NVME_IOC_IDENTIFY, &bufsize, &idctl, cns, NULL);
return (idctl);
}
-nvme_identify_nsid_t *
-nvme_identify_nsid(int fd)
-{
- void *idns = NULL;
- size_t bufsize = NVME_IDENTIFY_BUFSIZE;
-
- (void) nvme_ioctl(fd, NVME_IOC_IDENTIFY_NSID, &bufsize, &idns, 0, NULL);
-
- return (idns);
-}
-
void *
nvme_get_logpage(int fd, uint8_t logpage, size_t *bufsize)
{
diff --git a/usr/src/cmd/nvmeadm/nvmeadm_print.c b/usr/src/cmd/nvmeadm/nvmeadm_print.c
index dacdbfad70..1acd66860b 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm_print.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm_print.c
@@ -19,6 +19,7 @@
* functions for printing of NVMe data structures and their members
*/
+#include <sys/sysmacros.h>
#include <sys/byteorder.h>
#include <sys/types.h>
#include <inttypes.h>
@@ -41,8 +42,10 @@ static void nvme_print_uint128(int, const char *, nvme_uint128_t, const char *,
int, int);
static void nvme_print_bit(int, const char *, boolean_t, uint_t, const char *,
const char *);
-
-#define ARRAYSIZE(x) (sizeof (x) / sizeof (*(x)))
+static void nvme_print_hexbuf(int, const char *, const uint8_t *, size_t);
+static void nvme_print_eui64(int, const char *, const uint8_t *);
+static void nvme_print_guid(int, const char *, const uint8_t *);
+static void nvme_print_uuid(int, const char *, const uint8_t *);
static const char *generic_status_codes[] = {
"Successful Completion",
@@ -196,6 +199,10 @@ static const char *lba_range_types[] = {
"Reserved", "Filesystem", "RAID", "Cache", "Page/Swap File"
};
+static const char *ns_identifier_type[] = {
+ "Reserved", "IEEE Extended Unique Identifier", "Namespace GUID", "UUID"
+};
+
/*
* nvme_print
*
@@ -214,9 +221,12 @@ static const char *lba_range_types[] = {
void
nvme_print(int indent, const char *name, int index, const char *fmt, ...)
{
- int align = NVME_PRINT_ALIGN - (indent + strlen(name) + 1);
+ int align = NVME_PRINT_ALIGN - (indent + 1);
va_list ap;
+ if (name != NULL)
+ align -= strlen(name);
+
if (index >= 0)
align -= snprintf(NULL, 0, " %d", index);
@@ -225,13 +235,17 @@ nvme_print(int indent, const char *name, int index, const char *fmt, ...)
va_start(ap, fmt);
- (void) printf("%*s%s", indent, "", name);
+ (void) printf("%*s%s", indent, "", name != NULL ? name : "");
if (index >= 0)
(void) printf(" %d", index);
if (fmt != NULL) {
- (void) printf(": %*s", align, "");
+ if (name != NULL || index >= 0)
+ (void) printf(": ");
+ else
+ (void) printf(" ");
+ (void) printf("%*s", align, "");
(void) vprintf(fmt, ap);
}
@@ -463,6 +477,78 @@ nvme_print_bit(int indent, const char *name, boolean_t valid_vers, uint_t value,
}
/*
+ * nvme_print_hexbuf -- print a buffer of bytes as a hex dump
+ */
+static void
+nvme_print_hexbuf(int indent, const char *name, const uint8_t *buf, size_t len)
+{
+ /*
+ * The format string is kept in this variable so it can be cut
+ * short to print the remainder after the loop.
+ */
+ char fmt[] = { "%02x %02x %02x %02x %02x %02x %02x %02x" };
+ size_t lines = len / 8;
+ size_t rem = len % 8;
+ size_t i;
+
+ for (i = 0; i < lines; i++) {
+ nvme_print(indent, name, -1, fmt,
+ buf[i*8 + 0], buf[i*8 + 1], buf[i*8 + 2], buf[i*8 + 3],
+ buf[i*8 + 4], buf[i*8 + 5], buf[i*8 + 6], buf[i*8 + 7]);
+ name = NULL;
+ }
+
+ if (rem > 0) {
+ fmt[rem * 5] = '\0';
+
+ nvme_print(indent, name, -1, fmt,
+ buf[i*8 + 0], buf[i*8 + 1], buf[i*8 + 2], buf[i*8 + 3],
+ buf[i*8 + 4], buf[i*8 + 5], buf[i*8 + 6], buf[i*8 + 7]);
+ }
+}
+
+/*
+ * nvme_print_uuid -- print a UUID in canonical form
+ */
+static void
+nvme_print_uuid(int indent, const char *name, const uint8_t *uuid)
+{
+ nvme_print(indent, name, -1,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x",
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+}
+
+/*
+ * nvme_print_guid -- print a namespace GUID
+ */
+static void
+nvme_print_guid(int indent, const char *name, const uint8_t *guid)
+{
+ nvme_print(indent, name, -1,
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ guid[0], guid[1], guid[2], guid[3],
+ guid[4], guid[5], guid[6], guid[7],
+ guid[8], guid[9], guid[10], guid[11],
+ guid[12], guid[13], guid[14], guid[15]);
+}
+
+/*
+ * nvme_print_eui64 -- print a namespace EUI64
+ */
+static void
+nvme_print_eui64(int indent, const char *name, const uint8_t *eui64)
+{
+ nvme_print(indent, name, -1,
+ "%02X%02X%02X%02X%02X%02X%02X%02X",
+ eui64[0], eui64[1], eui64[2], eui64[3],
+ eui64[4], eui64[5], eui64[6], eui64[7]);
+}
+
+/*
* nvme_print_version -- print a uint32_t encoded nvme version
*/
static void
@@ -562,7 +648,7 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
if (nvme_version_check(version, 1, 1)) {
nvme_print_uint64(4, "Unique Controller Identifier",
- idctl->id_cntlid, "0x%0.4"PRIx64, NULL);
+ idctl->id_cntlid, NULL, NULL);
}
if (nvme_version_check(version, 1, 2)) {
@@ -719,16 +805,7 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
uint8_t zguid[16] = { 0 };
if (memcmp(zguid, idctl->id_frguid, sizeof (zguid)) != 0) {
- nvme_print(4, "FRU GUID", -1, "%02x%02x%02x%02x%02x%02x"
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
- idctl->id_frguid[0], idctl->id_frguid[1],
- idctl->id_frguid[2], idctl->id_frguid[3],
- idctl->id_frguid[4], idctl->id_frguid[5],
- idctl->id_frguid[6], idctl->id_frguid[7],
- idctl->id_frguid[8], idctl->id_frguid[9],
- idctl->id_frguid[10], idctl->id_frguid[11],
- idctl->id_frguid[12], idctl->id_frguid[13],
- idctl->id_frguid[14], idctl->id_frguid[15]);
+ nvme_print_guid(4, "FRU GUID", idctl->id_frguid);
} else {
nvme_print_str(4, "FRU GUID", -1, "unsupported", 0);
}
@@ -912,19 +989,21 @@ nvme_print_identify_ctrl(nvme_identify_ctrl_t *idctl,
nvme_print_str(4, "Host Memory Buffer Minimum Size",
-1, "unsupported", 0);
}
+ }
- if (idctl->id_oacs.oa_nsmgmt != 0) {
- nvme_print_uint128(4, "Total NVM Capacity",
- idctl->ap_tnvmcap, "B", 0, 0);
- nvme_print_uint128(4, "Unallocated NVM Capacity",
- idctl->ap_unvmcap, "B", 0, 0);
- } else {
- nvme_print_str(4, "Total NVM Capacity", -1,
- "unsupported", 0);
- nvme_print_str(4, "Unallocated NVM Capacity", -1,
- "unsupported", 0);
- }
+ if (idctl->id_oacs.oa_nsmgmt != 0) {
+ nvme_print_uint128(4, "Total NVM Capacity",
+ idctl->ap_tnvmcap, "B", 0, 0);
+ nvme_print_uint128(4, "Unallocated NVM Capacity",
+ idctl->ap_unvmcap, "B", 0, 0);
+ } else if (verbose) {
+ nvme_print_str(4, "Total NVM Capacity", -1,
+ "unsupported", 0);
+ nvme_print_str(4, "Unallocated NVM Capacity", -1,
+ "unsupported", 0);
+ }
+ if (verbose) {
if (idctl->ap_rpmbs.rpmbs_units != 0) {
nvme_print(4, "Replay Protected Memory Block", -1,
NULL);
@@ -1609,16 +1688,7 @@ nvme_print_identify_nsid(nvme_identify_nsid_t *idns, nvme_version_t *version)
if (nvme_version_check(version, 1, 2)) {
uint8_t guid[16] = { 0 };
if (memcmp(guid, idns->id_nguid, sizeof (guid) != 0)) {
- nvme_print(4, "Namespace GUID", -1, "%02x%02x%02x"
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x", idns->id_nguid[0], idns->id_nguid[1],
- idns->id_nguid[2], idns->id_nguid[3],
- idns->id_nguid[4], idns->id_nguid[5],
- idns->id_nguid[6], idns->id_nguid[7],
- idns->id_nguid[8], idns->id_nguid[9],
- idns->id_nguid[10], idns->id_nguid[11],
- idns->id_nguid[12], idns->id_nguid[13],
- idns->id_nguid[14], idns->id_nguid[15]);
+ nvme_print_guid(4, "Namespace GUID", idns->id_nguid);
} else {
nvme_print_str(4, "Namespace GUID",
-1, "unsupported", 0);
@@ -1631,12 +1701,8 @@ nvme_print_identify_nsid(nvme_identify_nsid_t *idns, nvme_version_t *version)
if (nvme_version_check(version, 1, 1)) {
uint8_t oui[8] = { 0 };
if (memcmp(oui, idns->id_eui64, sizeof (oui)) != 0) {
- nvme_print(4, "IEEE Extended Unique Identifier", -1,
- "%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X",
- idns->id_eui64[0], idns->id_eui64[1],
- idns->id_eui64[2], idns->id_eui64[3],
- idns->id_eui64[4], idns->id_eui64[5],
- idns->id_eui64[6], idns->id_eui64[7]);
+ nvme_print_eui64(4, "IEEE Extended Unique Identifier",
+ idns->id_eui64);
} else {
nvme_print_str(4, "IEEE Extended Unique Identifier",
-1, "unsupported", 0);
@@ -1661,6 +1727,99 @@ nvme_print_identify_nsid(nvme_identify_nsid_t *idns, nvme_version_t *version)
}
/*
+ * nvme_print_identify_nsid_list
+ *
+ * Print a NVMe Namespace List.
+ */
+void
+nvme_print_identify_nsid_list(const char *header,
+ nvme_identify_nsid_list_t *nslist)
+{
+ uint32_t i;
+
+ nvme_print(0, header, -1, NULL);
+
+ /*
+ * The namespace ID list is ordered, unused entries are 0.
+ */
+ for (i = 0;
+ i < ARRAY_SIZE(nslist->nl_nsid) && nslist->nl_nsid[i] != 0;
+ i++) {
+ nvme_print_uint64(2, "Namespace Identifier", nslist->nl_nsid[i],
+ NULL, NULL);
+ }
+}
+
+/*
+ * nvme_print_identify_nsid_desc
+ *
+ * Print a NVMe Namespace Identifier Descriptor list.
+ */
+void
+nvme_print_identify_nsid_desc(void *nsdesc)
+{
+ nvme_identify_nsid_desc_t *desc = nsdesc;
+ int i = 0;
+ uintptr_t ptr, end;
+
+ nvme_print(0, "Namespace Identification Descriptors", -1, NULL);
+
+ for (ptr = (uintptr_t)desc, end = ptr + NVME_IDENTIFY_BUFSIZE;
+ desc->nd_nidl != 0 && ptr + desc->nd_nidl + 4 <= end;
+ desc = (nvme_identify_nsid_desc_t *)(ptr += desc->nd_nidl + 4)) {
+ const char *nidt;
+
+ if (desc->nd_nidt >= ARRAY_SIZE(ns_identifier_type))
+ nidt = "Reserved";
+ else
+ nidt = ns_identifier_type[desc->nd_nidt];
+
+ nvme_print(2, "Namespace Identifier Descriptor", i++, NULL);
+ nvme_print_str(4, "Namespace Identifier Type", -1, nidt, 0);
+ nvme_print_uint64(4, "Namespace Identifier Length",
+ desc->nd_nidl, NULL, NULL);
+
+ if (desc->nd_nidt == NVME_NSID_DESC_EUI64 &&
+ desc->nd_nidl == NVME_NSID_DESC_LEN_EUI64) {
+ nvme_print_eui64(4, "IEEE Extended Unique Identifier",
+ desc->nd_nid);
+ } else if (desc->nd_nidt == NVME_NSID_DESC_NGUID &&
+ desc->nd_nidl == NVME_NSID_DESC_LEN_NGUID) {
+ nvme_print_guid(4, "Namespace GUID", desc->nd_nid);
+ } else if (desc->nd_nidt == NVME_NSID_DESC_NUUID &&
+ desc->nd_nidl == NVME_NSID_DESC_LEN_NUUID) {
+ nvme_print_uuid(4, "Namespace UUID", desc->nd_nid);
+ } else if (desc->nd_nidt < NVME_NSID_DESC_MIN ||
+ desc->nd_nidt > NVME_NSID_DESC_MAX) {
+ nvme_print_hexbuf(4, "Raw Bytes", desc->nd_nid,
+ desc->nd_nidl);
+ } else {
+ nvme_print_hexbuf(4,
+ "Raw Bytes (Invalid Descriptor Length)",
+ desc->nd_nid, desc->nd_nidl);
+ }
+ }
+}
+
+/*
+ * nvme_print_identify_ctrl_list
+ *
+ * Print a NVMe Controller List.
+ */
+void
+nvme_print_identify_ctrl_list(const char *header,
+ nvme_identify_ctrl_list_t *ctlist)
+{
+ int i;
+
+ nvme_print(0, header, -1, NULL);
+ for (i = 0; i != ctlist->cl_nid; i++) {
+ nvme_print_uint64(2, "Controller Identifier",
+ ctlist->cl_ctlid[i], NULL, NULL);
+ }
+}
+
+/*
* nvme_print_error_log
*
* This function pretty-prints all non-zero error log entries, or all entries
@@ -1687,35 +1846,35 @@ nvme_print_error_log(int nlog, nvme_error_log_entry_t *elog,
switch (elog[i].el_sf.sf_sct) {
case 0: /* Generic Command Status */
- if (sc < ARRAYSIZE(generic_status_codes)) {
+ if (sc < ARRAY_SIZE(generic_status_codes)) {
sc_str = generic_status_codes[sc];
} else if (sc >= 0x80 &&
- sc - 0x80 < ARRAYSIZE(generic_nvm_status_codes)) {
+ sc - 0x80 < ARRAY_SIZE(generic_nvm_status_codes)) {
sc_str = generic_nvm_status_codes[sc - 0x80];
}
break;
case 1: /* Specific Command Status */
- if (sc < ARRAYSIZE(specific_status_codes)) {
+ if (sc < ARRAY_SIZE(specific_status_codes)) {
sc_str = specific_status_codes[sc];
} else if (sc >= 0x80 &&
- sc - 0x80 < ARRAYSIZE(specific_nvm_status_codes)) {
+ sc - 0x80 < ARRAY_SIZE(specific_nvm_status_codes)) {
sc_str = specific_nvm_status_codes[sc - 0x80];
}
break;
case 2: /* Media Errors */
if (sc >= 0x80 &&
- sc - 0x80 < ARRAYSIZE(media_nvm_status_codes)) {
+ sc - 0x80 < ARRAY_SIZE(media_nvm_status_codes)) {
sc_str = media_nvm_status_codes[sc - 0x80];
}
break;
case 3: /* Path Related Status */
- if (sc < ARRAYSIZE(path_status_codes)) {
+ if (sc < ARRAY_SIZE(path_status_codes)) {
sc_str = path_status_codes[sc];
} else if (sc >= 0x60 &&
- sc - 0x60 < ARRAYSIZE(path_controller_codes)) {
+ sc - 0x60 < ARRAY_SIZE(path_controller_codes)) {
sc_str = path_controller_codes[sc - 0x60];
} else if (sc >= 0x70 &&
- sc - 0x70 < ARRAYSIZE(path_host_codes)) {
+ sc - 0x70 < ARRAY_SIZE(path_host_codes)) {
sc_str = path_host_codes[sc - 0x70];
}
break;
@@ -2006,7 +2165,7 @@ nvme_print_feat_lba_range(uint64_t res, void *buf, size_t bufsize,
continue;
nvme_print(4, "LBA Range", i, NULL);
- if (lr[i].lr_type < ARRAYSIZE(lba_range_types))
+ if (lr[i].lr_type < ARRAY_SIZE(lba_range_types))
nvme_print_str(6, "Type", -1,
lba_range_types[lr[i].lr_type], 0);
else
diff --git a/usr/src/cmd/ptools/pargs/pargs.c b/usr/src/cmd/ptools/pargs/pargs.c
index 2f8e069a10..83335db976 100644
--- a/usr/src/cmd/ptools/pargs/pargs.c
+++ b/usr/src/cmd/ptools/pargs/pargs.c
@@ -24,6 +24,7 @@
*/
/*
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -754,6 +755,17 @@ at_hwcap2(long val, char *instr, size_t n, char *str)
#endif
}
+/*ARGSUSED*/
+static void
+at_hwcap3(long val, char *instr, size_t n, char *str)
+{
+#if defined(__i386) || defined(__amd64)
+ (void) elfcap_hw3_to_str(ELFCAP_STYLE_UC, val, str, n,
+ ELFCAP_FMT_PIPSPACE, EM_386);
+#else
+#error "port me"
+#endif
+}
/*ARGSUSED*/
static void
@@ -836,6 +848,7 @@ static struct aux_id aux_arr[] = {
{ AT_SUN_EXECNAME, "AT_SUN_EXECNAME", at_str },
{ AT_SUN_HWCAP, "AT_SUN_HWCAP", at_hwcap },
{ AT_SUN_HWCAP2, "AT_SUN_HWCAP2", at_hwcap2 },
+ { AT_SUN_HWCAP3, "AT_SUN_HWCAP3", at_hwcap3 },
{ AT_SUN_IFLUSH, "AT_SUN_IFLUSH", at_null },
{ AT_SUN_CPU, "AT_SUN_CPU", at_null },
{ AT_SUN_MMU, "AT_SUN_MMU", at_null },
diff --git a/usr/src/cmd/sgs/Makefile b/usr/src/cmd/sgs/Makefile
index 203246897e..3d645521a7 100644
--- a/usr/src/cmd/sgs/Makefile
+++ b/usr/src/cmd/sgs/Makefile
@@ -60,6 +60,7 @@ SUBDIRS= libconv \
crle \
ar \
dump \
+ elfcap.chk \
elfdump \
elfedit \
elfwrap \
@@ -94,6 +95,8 @@ MSGSUBDIRS= ld ldd libld liblddbg \
elfedit crle moe lari \
librtld_db elfwrap ar
+CHKSUBDIRS= elfcap.chk
+
MSGDIR= messages
all := TARGET= all
@@ -104,6 +107,7 @@ _msg := TARGET= catalog
_msg_gettext := TARGET= catalog
_msg_sgsmsg := TARGET= catalog
chkmsg := TARGET= chkmsg
+check := TARGET= check
.KEEP_STATE:
@@ -134,7 +138,7 @@ $(MSGDIR): $(MSGSUBDIRS) FRC
chkmsg: libconv $(MSGSUBDIRS) FRC
-check: chkmsg
+check: chkmsg $(CHKSUBDIRS)
# built from lib/Makefile
install_lib: FRC
diff --git a/usr/src/cmd/sgs/elfcap.chk/Makefile b/usr/src/cmd/sgs/elfcap.chk/Makefile
new file mode 100644
index 0000000000..9e446ff0e3
--- /dev/null
+++ b/usr/src/cmd/sgs/elfcap.chk/Makefile
@@ -0,0 +1,53 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2022 Oxide Computer Company
+#
+
+PROG = elfcap.chk
+OBJS = elfcap_chk.o elfcap.o
+
+include $(SRC)/Makefile.master
+include $(SRC)/Makefile.master.64
+include ../Makefile.com
+
+CSTD = $(GNU_C99)
+NATIVE_LIBS += libc.so
+CPPFLAGS = $(CPPFLAGS.native)
+CFLAGS = $(NATIVE_CFLAGS)
+CC = $(NATIVECC)
+LDCHECKS =
+
+CPPFLAGS += -I$(ELFCAP)
+
+all: $(PROG)
+
+install:
+
+check: $(PROG)
+ ./$(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS)
+ $(POST_PROCESS)
+
+%.o: %.c
+ $(COMPILE.c) $<
+
+%.o: $(ELFCAP)/%.c
+ $(COMPILE.c) $<
+
+clean:
+ $(RM) $(OBJS)
+
+clobber: clean
+ $(RM) $(PROG)
diff --git a/usr/src/cmd/sgs/elfcap.chk/elfcap_chk.c b/usr/src/cmd/sgs/elfcap.chk/elfcap_chk.c
new file mode 100644
index 0000000000..5598e59972
--- /dev/null
+++ b/usr/src/cmd/sgs/elfcap.chk/elfcap_chk.c
@@ -0,0 +1,160 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2022 Oxide Computer Company
+ */
+
+/*
+ * This tool is used to try and figure out what the value of various static
+ * buffers should be and if the current compile time defaults are correct. In
+ * particular, this covers the various elfcap values and is used to drive how we
+ * calculate the overall size definition.
+ *
+ * To calculate this, we assume the following:
+ *
+ * o We are using the ELFCAP_FMT_PIPSPACE as that is the longest. We don't
+ * have access to the actual strings right now.
+ * o We are using the ELFCAP_STYLE_FULL variant of the name as that's the
+ * longest.
+ * o We are going to have leftover bits that we don't know (unless we have
+ * 32-bits defined). This uses the 0x%x format and therefore is 10
+ * characters.
+ * o We check all architectures set of values and take the largest.
+ *
+ * While elfcap related information is in multiple places in the build, sgs and
+ * libconv are the places that seem most intertwined. In particular, we believe
+ * it's important that this program execute as part of make check and also get
+ * rebuilt normally as part of a build. This also allows one to iterate in
+ * cmd/sgs which is the most common place that you're working in when adding new
+ * hardware capabilities. By making it a part of the cmd/sgs suite, that also
+ * ensures that normal build logic always rebuilds this program with changes to
+ * elfcap.[ch].
+ */
+
+#include <stdio.h>
+#include <elfcap.h>
+#include <sys/sysmacros.h>
+#include <stdlib.h>
+
+/*
+ * The length of 0x%x.
+ */
+#define ECS_UNKNOWN 10
+
+typedef const elfcap_desc_t *(*elfcap_getdesc_f)(void);
+
+typedef struct elfcap_getdesc {
+ uint32_t eg_nents;
+ elfcap_getdesc_f eg_func;
+} elfcap_getdesc_t;
+
+typedef struct elfcap_case {
+ const char *ec_tag;
+ size_t ec_header;
+ elfcap_getdesc_t ec_descs[2];
+} elfcap_case_t;
+
+const elfcap_case_t elfcaps[] = {
+ { "ELFCAP_SF1_BUFSIZE", ELFCAP_SF1_BUFSIZE, {
+ { ELFCAP_NUM_SF1, elfcap_getdesc_sf1 },
+ { 0, NULL }
+ } },
+ { "ELFCAP_HW1_BUFSIZE", ELFCAP_HW1_BUFSIZE, {
+ { ELFCAP_NUM_HW1_386, elfcap_getdesc_hw1_386 },
+ { ELFCAP_NUM_HW1_SPARC, elfcap_getdesc_hw1_sparc }
+ } },
+ { "ELFCAP_HW1_BUFSIZE", ELFCAP_HW2_BUFSIZE, {
+ { ELFCAP_NUM_HW2_386, elfcap_getdesc_hw2_386 },
+ { 0, NULL }
+ } },
+ { "ELFCAP_HW1_BUFSIZE", ELFCAP_HW3_BUFSIZE, {
+ { ELFCAP_NUM_HW3_386, elfcap_getdesc_hw3_386 },
+ { 0, NULL }
+ } },
+};
+
+static size_t
+elfcap_calc_len(const elfcap_desc_t *desc, uint32_t nents, size_t space)
+{
+ size_t len = 0;
+
+ for (uint32_t i = 0; i < nents; i++) {
+ len += desc[i].c_full.s_len;
+ if (i > 0) {
+ len += space;
+ }
+ }
+
+ if (nents < 32) {
+ len += space + ECS_UNKNOWN;
+ }
+
+ /*
+ * Finally, add one for a terminator and we add an 8 character buffer in
+ * case we screwed up.
+ */
+ len += 9;
+
+ return (len);
+}
+
+static size_t
+elfcap_max_len(const elfcap_case_t *ec, size_t slen)
+{
+ size_t max = 0;
+
+ for (size_t i = 0; i < ARRAY_SIZE(ec->ec_descs); i++) {
+ const elfcap_desc_t *desc;
+ size_t len;
+
+ if (ec->ec_descs[i].eg_func == NULL)
+ continue;
+
+ desc = ec->ec_descs[i].eg_func();
+ len = elfcap_calc_len(desc, ec->ec_descs[i].eg_nents, slen);
+ if (len > max)
+ max = len;
+ }
+
+ return (max);
+}
+
+int
+main(void)
+{
+ size_t slen;
+ const elfcap_str_t *strs;
+ int ret = EXIT_SUCCESS;
+
+ strs = elfcap_getdesc_formats();
+ slen = strs[ELFCAP_FMT_PIPSPACE].s_len;
+
+ for (size_t i = 0; i < ARRAY_SIZE(elfcaps); i++) {
+ size_t out = elfcap_max_len(&elfcaps[i], slen);
+
+ if (out != elfcaps[i].ec_header) {
+ (void) fprintf(stderr, "elfcap size for %s is not "
+ "expected value!\n\tCurrent value is %zu, should "
+ "be %zu\n", elfcaps[i].ec_tag, elfcaps[i].ec_header,
+ out);
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ if (ret != EXIT_SUCCESS) {
+ (void) fprintf(stderr, "please update $SRC/common/elfcap/"
+ "elfcap.h and $SRC/cmd/sgs/include/conv.h with the new "
+ "values reported above\n");
+ }
+
+ return (ret);
+}
diff --git a/usr/src/cmd/sgs/elfdump/common/corenote.c b/usr/src/cmd/sgs/elfdump/common/corenote.c
index d848221648..b06b3bf2cf 100644
--- a/usr/src/cmd/sgs/elfdump/common/corenote.c
+++ b/usr/src/cmd/sgs/elfdump/common/corenote.c
@@ -26,7 +26,7 @@
/*
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
- * Copyright 2020 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
#include <stdlib.h>
@@ -46,7 +46,7 @@
/*
* This module contains the code that displays data from the note
- * sections found in Solaris core files. The format of these
+ * sections found in illumos core files. The format of these
* note sections are described in the core(5) manpage.
*/
@@ -470,6 +470,7 @@ dump_auxv(note_state_t *state, const char *title)
union {
Conv_cap_val_hw1_buf_t hw1;
Conv_cap_val_hw2_buf_t hw2;
+ Conv_cap_val_hw3_buf_t hw3;
Conv_cnote_auxv_af_buf_t auxv_af;
Conv_ehdr_flags_buf_t ehdr_flags;
Conv_secflags_buf_t secflags;
@@ -586,8 +587,27 @@ dump_auxv(note_state_t *state, const char *title)
vstr = NULL;
num_fmt = SL_FMT_NUM_HEX;
break;
-
-
+ case AT_SUN_HWCAP3:
+ w = extract_as_word(state, &layout->a_val);
+ vstr = conv_cap_val_hw3(w, state->ns_mach,
+ 0, &conv_buf.hw3);
+ /*
+ * conv_cap_val_hw3() produces output like:
+ *
+ * 0xfff [ flg1 flg2 0xff]
+ *
+ * where the first hex value is the complete value,
+ * and the second is the leftover bits. We only
+ * want the part in brackets, and failing that,
+ * would rather fall back to formatting the full
+ * value ourselves.
+ */
+ while ((*vstr != '\0') && (*vstr != '['))
+ vstr++;
+ if (*vstr != '[')
+ vstr = NULL;
+ num_fmt = SL_FMT_NUM_HEX;
+ break;
case AT_SUN_AUXFLAGS:
w = extract_as_word(state, &layout->a_val);
diff --git a/usr/src/cmd/sgs/elfedit/common/elfconst.c b/usr/src/cmd/sgs/elfedit/common/elfconst.c
index 0ee1e7158d..b550222a9a 100644
--- a/usr/src/cmd/sgs/elfedit/common/elfconst.c
+++ b/usr/src/cmd/sgs/elfedit/common/elfconst.c
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2022 Oxide Computer Company
*/
#include <stdlib.h>
@@ -411,6 +413,7 @@ init_libconv_strings(conv_iter_osabi_t *osabi, Half *mach)
LC_MACH(ELFEDIT_CONST_HW1_SUNW, conv_iter_cap_val_hw1);
LC(ELFEDIT_CONST_SF1_SUNW, conv_iter_cap_val_sf1);
LC_MACH(ELFEDIT_CONST_HW2_SUNW, conv_iter_cap_val_hw2);
+ LC_MACH(ELFEDIT_CONST_HW3_SUNW, conv_iter_cap_val_hw3);
#undef LC
#undef LC_OS
diff --git a/usr/src/cmd/sgs/elfedit/modules/common/cap.c b/usr/src/cmd/sgs/elfedit/modules/common/cap.c
index 7430d4d84f..0cde92f90a 100644
--- a/usr/src/cmd/sgs/elfedit/modules/common/cap.c
+++ b/usr/src/cmd/sgs/elfedit/modules/common/cap.c
@@ -23,6 +23,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <ctype.h>
@@ -60,6 +61,7 @@ typedef enum {
CAP_CMD_T_HW1 = 5, /* cap:hw1 */
CAP_CMD_T_SF1 = 6, /* cap:sf1 */
CAP_CMD_T_HW2 = 7, /* cap:hw2 */
+ CAP_CMD_T_HW3 = 8, /* cap:hw3 */
} CAP_CMD_T;
@@ -532,6 +534,14 @@ print_cap(CAP_CMD_T cmd, int autoprint, ARGSTATE *argstate,
ELFEDIT_MSG_ERR, 0));
printed = 1;
continue;
+ case CA_SUNW_HW_3:
+ elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
+ conv_cap_val_hw3(cap->c_un.c_val,
+ argstate->obj_state->os_ehdr->
+ e_machine, CONV_FMT_NOBKT,
+ &cap_val_buf.cap_val_hw3_buf));
+ printed = 1;
+ continue;
}
}
elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
@@ -843,6 +853,13 @@ cmd_body(CAP_CMD_T cmd, elfedit_obj_state_t *obj_state,
MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
break;
+ case CAP_CMD_T_HW3:
+ print_only = (argstate.argc == 0);
+ ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
+ ELFEDIT_CONST_CA, CA_SUNW_HW_3, 1),
+ MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
+ break;
+
default:
/* Note expected: All commands should have been caught above */
elfedit_command_usage();
@@ -1024,6 +1041,14 @@ cmd_body(CAP_CMD_T cmd, elfedit_obj_state_t *obj_state,
CA_SUNW_HW_2, ELFEDIT_CONST_HW2_SUNW);
}
break;
+
+ case CAP_CMD_T_HW3:
+ {
+ ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
+ CA_SUNW_HW_3, ELFEDIT_CONST_HW3_SUNW);
+ }
+ break;
+
}
/*
@@ -1180,6 +1205,19 @@ cpl_hw2(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_HW2_SUNW);
}
+static void
+cpl_hw3(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
+ const char *argv[], int num_opt)
+{
+ /* -capid id_name */
+ if (argc <= num_opt) {
+ cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
+ return;
+ }
+
+ /* This routine allows multiple flags to be specified */
+ elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_HW3_SUNW);
+}
/*
* Implementation functions for the commands
*/
@@ -1231,6 +1269,12 @@ cmd_hw2(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
return (cmd_body(CAP_CMD_T_HW2, obj_state, argc, argv));
}
+static elfedit_cmdret_t
+cmd_hw3(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(CAP_CMD_T_HW3, obj_state, argc, argv));
+}
+
/*ARGSUSED*/
elfedit_module_t *
elfedit_init(elfedit_module_version_t version)
@@ -1406,6 +1450,15 @@ elfedit_init(elfedit_module_version_t version)
{ NULL }
};
+ /* cap:hw3 */
+ static const char *name_hw3[] = { MSG_ORIG(MSG_CMD_HW3), NULL };
+ static elfedit_cmd_optarg_t arg_hw3[] = {
+ { MSG_ORIG(MSG_STR_VALUE),
+ /* MSG_INTL(MSG_A1_HW3_VALUE) */
+ ELFEDIT_I18NHDL(MSG_A1_HW3_VALUE),
+ ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
+ { NULL }
+ };
static elfedit_cmd_t cmds[] = {
/* cap:dump */
@@ -1472,6 +1525,14 @@ elfedit_init(elfedit_module_version_t version)
ELFEDIT_I18NHDL(MSG_HELP_HW2),
opt_ostyle_capid_bitop, arg_hw2 },
+ /* cap:hw3 */
+ { cmd_hw3, cpl_hw3, name_hw3,
+ /* MSG_INTL(MSG_DESC_HW3) */
+ ELFEDIT_I18NHDL(MSG_DESC_HW3),
+ /* MSG_INTL(MSG_HELP_HW3) */
+ ELFEDIT_I18NHDL(MSG_HELP_HW3),
+ opt_ostyle_capid_bitop, arg_hw3 },
+
{ NULL }
};
diff --git a/usr/src/cmd/sgs/elfedit/modules/common/cap.msg b/usr/src/cmd/sgs/elfedit/modules/common/cap.msg
index cd311144a0..da6e062df1 100644
--- a/usr/src/cmd/sgs/elfedit/modules/common/cap.msg
+++ b/usr/src/cmd/sgs/elfedit/modules/common/cap.msg
@@ -23,6 +23,8 @@
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2022 Oxide Computer Company
+#
@ _START_
@@ -76,6 +78,7 @@
@ MSG_DESC_HW1 "Hardware capabilities (CA_SUNW_HW_1) bit values"
@ MSG_DESC_SF1 "Software capabilities (CA_SUNW_SF_1) bit values"
@ MSG_DESC_HW2 "Hardware capabilities (CA_SUNW_HW_2) bit values"
+@ MSG_DESC_HW3 "Hardware capabilities (CA_SUNW_HW_3) bit values"
# Command option description strings
@@ -160,9 +163,14 @@
/usr/include/sys/elf.h.\n"
@ MSG_A1_HW2_VALUE "\
- Hardware capability (CA_SUNW_HW_2) values. This is available for\n\
- future expansion.\n"
+ Hardware capability (CA_SUNW_HW_2) values. This can be an integer\n\
+ value, any of the AV_386_2_ symbolic constants defined in\n\
+ /usr/include/sys/auxv_386.h.\n"
+@ MSG_A1_HW3_VALUE "\
+ Hardware capability (CA_SUNW_HW_3) values. This can be an integer\n\
+ value, any of the AV_386_3_ symbolic constants defined in\n\
+ /usr/include/sys/auxv_386.h.\n"
# Help strings
@@ -266,6 +274,26 @@
\tspecified, the new value is OR'd against the existing\n\
\tvalue. If neither -and or -or are specified, the new value\n\
\treplaces the existing value.\n"
+
+@ MSG_HELP_HW3 " \
+ The cap:hw3 command is used to display or alter the\n\
+ value of the hardware capabilities element (CA_SUNW_HW_3).\n\
+ \n\
+ If cap:hw3 is called without arguments, the current\n\
+ value is shown. If one or more value arguments are present,\n\
+ the following steps are taken:\n\
+ \n \
+ o\tAll the value arguments are OR'd together.\n\
+ \n \
+ o\tIf the -cmp option has been specified, the new value\n\
+ \tis complemented.\n\
+ \n \
+ o\tThe CA_SUNW_HW_3 element of the capabilities section is\n\
+ \tupdated with the new value. If -and is specified, the new\n\
+ \tvalue is AND'd against the existing value. If -or is\n\
+ \tspecified, the new value is OR'd against the existing\n\
+ \tvalue. If neither -and or -or are specified, the new value\n\
+ \treplaces the existing value.\n"
@ _END_
@@ -306,3 +334,4 @@
@ MSG_CMD_HW1 "hw1"
@ MSG_CMD_SF1 "sf1"
@ MSG_CMD_HW2 "hw2"
+@ MSG_CMD_HW3 "hw3"
diff --git a/usr/src/cmd/sgs/include/conv.h b/usr/src/cmd/sgs/include/conv.h
index fda54cea4c..f9e649d6cb 100644
--- a/usr/src/cmd/sgs/include/conv.h
+++ b/usr/src/cmd/sgs/include/conv.h
@@ -27,7 +27,7 @@
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
* Copyright 2016 RackTop Systems.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _CONV_H
@@ -166,30 +166,37 @@ typedef union {
* These sizes are based on the maximum number of capabilities that exist.
* See common/elfcap.
*/
-#define CONV_CAP_VAL_HW1_BUFSIZE 195
+#define CONV_CAP_VAL_HW1_BUFSIZE 528
typedef union {
Conv_inv_buf_t inv_buf;
char buf[CONV_CAP_VAL_HW1_BUFSIZE];
} Conv_cap_val_hw1_buf_t;
-#define CONV_CAP_VAL_HW2_BUFSIZE 350
+#define CONV_CAP_VAL_HW2_BUFSIZE 632
typedef union {
Conv_inv_buf_t inv_buf;
char buf[CONV_CAP_VAL_HW2_BUFSIZE];
} Conv_cap_val_hw2_buf_t;
-#define CONV_CAP_VAL_SF1_BUFSIZE 45
+#define CONV_CAP_VAL_SF1_BUFSIZE 73
typedef union {
Conv_inv_buf_t inv_buf;
char buf[CONV_CAP_VAL_SF1_BUFSIZE];
} Conv_cap_val_sf1_buf_t;
+#define CONV_CAP_VAL_HW3_BUFSIZE 66
+typedef union {
+ Conv_inv_buf_t inv_buf;
+ char buf[CONV_CAP_VAL_HW3_BUFSIZE];
+} Conv_cap_val_hw3_buf_t;
+
/* conv_cap_val_buf() */
typedef union {
Conv_inv_buf_t inv_buf;
Conv_cap_val_hw1_buf_t cap_val_hw1_buf;
Conv_cap_val_sf1_buf_t cap_val_sf1_buf;
Conv_cap_val_hw2_buf_t cap_val_hw2_buf;
+ Conv_cap_val_hw3_buf_t cap_val_hw3_buf;
} Conv_cap_val_buf_t;
/* conv_config_feat() */
@@ -962,6 +969,8 @@ extern conv_iter_ret_t conv_iter_cap_val_hw2(Half, Conv_fmt_flags_t,
conv_iter_cb_t, void *);
extern conv_iter_ret_t conv_iter_cap_val_sf1(Conv_fmt_flags_t, conv_iter_cb_t,
void *);
+extern conv_iter_ret_t conv_iter_cap_val_hw3(Half, Conv_fmt_flags_t,
+ conv_iter_cb_t, void *);
extern conv_iter_ret_t conv_iter_dyn_feature1(Conv_fmt_flags_t, conv_iter_cb_t,
void *);
@@ -1027,6 +1036,7 @@ extern conv_iter_ret_t conv_iter_syminfo_flags(Conv_fmt_flags_t,
#define conv_cap_val conv64_cap_val
#define conv_cap_val_hw1 conv64_cap_val_hw1
#define conv_cap_val_hw2 conv64_cap_val_hw2
+#define conv_cap_val_hw3 conv64_cap_val_hw3
#define conv_cap_val_sf1 conv64_cap_val_sf1
#define conv_dyn_feature1 conv64_dyn_feature1
#define conv_dyn_flag1 conv64_dyn_flag1
@@ -1045,6 +1055,7 @@ extern conv_iter_ret_t conv_iter_syminfo_flags(Conv_fmt_flags_t,
#define conv_cap_val conv32_cap_val
#define conv_cap_val_hw1 conv32_cap_val_hw1
#define conv_cap_val_hw2 conv32_cap_val_hw2
+#define conv_cap_val_hw3 conv32_cap_val_hw3
#define conv_cap_val_sf1 conv32_cap_val_sf1
#define conv_dyn_feature1 conv32_dyn_feature1
#define conv_dyn_flag1 conv32_dyn_flag1
@@ -1082,6 +1093,8 @@ extern const char *conv_cap_val_hw1(Xword, Half, Conv_fmt_flags_t,
Conv_cap_val_hw1_buf_t *);
extern const char *conv_cap_val_hw2(Xword, Half, Conv_fmt_flags_t,
Conv_cap_val_hw2_buf_t *);
+extern const char *conv_cap_val_hw3(Xword, Half, Conv_fmt_flags_t,
+ Conv_cap_val_hw3_buf_t *);
extern const char *conv_cap_val_sf1(Xword, Half, Conv_fmt_flags_t,
Conv_cap_val_sf1_buf_t *);
extern const char *conv_dyn_flag1(Xword, Conv_fmt_flags_t,
diff --git a/usr/src/cmd/sgs/include/debug.h b/usr/src/cmd/sgs/include/debug.h
index 4df1885e33..d1e49a94ed 100644
--- a/usr/src/cmd/sgs/include/debug.h
+++ b/usr/src/cmd/sgs/include/debug.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _DEBUG_H
@@ -152,6 +153,7 @@ extern "C" {
#define DBG_CAP_HW_2 6
#define DBG_CAP_PLAT 7
#define DBG_CAP_MACH 8
+#define DBG_CAP_HW_3 9
#define DBG_REL_START 1
#define DBG_REL_FINISH 2
diff --git a/usr/src/cmd/sgs/include/elfedit.h b/usr/src/cmd/sgs/include/elfedit.h
index 6c5a204f1a..16f3657905 100644
--- a/usr/src/cmd/sgs/include/elfedit.h
+++ b/usr/src/cmd/sgs/include/elfedit.h
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _ELFEDIT_H
@@ -455,7 +457,7 @@ typedef struct {
elfedit_i18nhdl_t oa_help; /* Help text for option */
elfedit_cmd_oa_flag_t oa_flags; /* Additional attributes */
elfedit_cmd_oa_mask_t oa_idmask; /* Unique id, returned by */
- /* elfedit_getopt */
+ /* elfedit_getopt */
/* for use by caller */
elfedit_cmd_oa_mask_t oa_excmask; /* Mutual exclusion mask */
} elfedit_cmd_optarg_t;
@@ -739,8 +741,9 @@ typedef enum {
ELFEDIT_CONST_HW1_SUNW = 33, /* hardware capabilities */
ELFEDIT_CONST_SF1_SUNW = 34, /* software capabilities */
ELFEDIT_CONST_HW2_SUNW = 35, /* hardware capabilities */
+ ELFEDIT_CONST_HW3_SUNW = 36, /* hardware capabilities */
- ELFEDIT_CONST_NUM = 36, /* # of constant types */
+ ELFEDIT_CONST_NUM = 37, /* # of constant types */
} elfedit_const_t;
/*
diff --git a/usr/src/cmd/sgs/include/libld.h b/usr/src/cmd/sgs/include/libld.h
index bf451f8f2a..67c877c082 100644
--- a/usr/src/cmd/sgs/include/libld.h
+++ b/usr/src/cmd/sgs/include/libld.h
@@ -24,6 +24,7 @@
* All Rights Reserved
*
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _LIBLD_H
@@ -210,6 +211,7 @@ typedef struct {
Caplist oc_plat; /* CA_SUNW_PLAT capabilities */
Caplist oc_mach; /* CA_SUNW_MACH capabilities */
Capstr oc_id; /* CA_SUNW_ID capability */
+ Capmask oc_hw_3; /* CA_SUNW_HW_3 capabilities */
oc_flag_t oc_flags;
} Objcapset;
@@ -524,6 +526,7 @@ struct ofl_desc {
#define FLG_OF1_OVMACHCAP 0x0800000000 /* override CA_SUNW_MACH capability */
#define FLG_OF1_OVPLATCAP 0x1000000000 /* override CA_SUNW_PLAT capability */
#define FLG_OF1_OVIDCAP 0x2000000000 /* override CA_SUNW_ID capability */
+#define FLG_OF1_OVHWCAP3 0x4000000000 /* override CA_SUNW_HW_3 capabilities */
/*
* Guidance flags. The flags with the FLG_OFG_NO_ prefix are used to suppress
diff --git a/usr/src/cmd/sgs/include/rtld.h b/usr/src/cmd/sgs/include/rtld.h
index 052cb109ee..4fe123c47d 100644
--- a/usr/src/cmd/sgs/include/rtld.h
+++ b/usr/src/cmd/sgs/include/rtld.h
@@ -22,6 +22,7 @@
/*
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _RTLD_H
#define _RTLD_H
@@ -1119,6 +1120,7 @@ typedef struct {
elfcap_mask_t sc_hw_1; /* CA_SUNW_HW_1 capabilities */
elfcap_mask_t sc_sf_1; /* CA_SUNW_SF_1 capabilities */
elfcap_mask_t sc_hw_2; /* CA_SUNW_HW_2 capabilities */
+ elfcap_mask_t sc_hw_3; /* CA_SUNW_HW_3 capabilities */
char *sc_plat; /* CA_SUNW_PLAT capability */
size_t sc_platsz; /* and size */
char *sc_mach; /* CA_SUNW_MACH capability */
diff --git a/usr/src/cmd/sgs/include/sgs.h b/usr/src/cmd/sgs/include/sgs.h
index 4480d78470..54d3f60722 100644
--- a/usr/src/cmd/sgs/include/sgs.h
+++ b/usr/src/cmd/sgs/include/sgs.h
@@ -25,6 +25,7 @@
*
*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*
* Global include file for all sgs.
*/
@@ -195,7 +196,8 @@ typedef struct {
#define SGS_REJ_HWCAP_2 17 /* hardware capabilities mismatch */
#define SGS_REJ_ARCHIVE 18 /* archive used in invalid context */
#define SGS_REJ_KMOD 19 /* object is a kernel module */
-#define SGS_REJ_NUM 20
+#define SGS_REJ_HWCAP_3 20 /* hardware capabilities mismatch */
+#define SGS_REJ_NUM 21
#define FLG_REJ_ALTER 0x01 /* object name is an alternative */
diff --git a/usr/src/cmd/sgs/libconv/common/cap.c b/usr/src/cmd/sgs/libconv/common/cap.c
index 750bb36c56..c3197cf57d 100644
--- a/usr/src/cmd/sgs/libconv/common/cap.c
+++ b/usr/src/cmd/sgs/libconv/common/cap.c
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -33,23 +35,43 @@
#include "cap_msg.h"
#include "_conv.h"
+/*
+ * These are assertions that the various sizes that are dependent on elfcap.c
+ * are actually all the same.
+ */
+#if CONV_CAP_VAL_HW1_BUFSIZE != ELFCAP_HW1_BUFSIZE
+#error "libconv needs to update CONV_CAP_VAL_HW1_BUFSIZE to match elfcap.h"
+#endif
+
+#if CONV_CAP_VAL_HW2_BUFSIZE != ELFCAP_HW2_BUFSIZE
+#error "libconv needs to update CONV_CAP_VAL_HW2_BUFSIZE to match elfcap.h"
+#endif
+
+#if CONV_CAP_VAL_HW3_BUFSIZE != ELFCAP_HW3_BUFSIZE
+#error "libconv needs to update CONV_CAP_VAL_HW3_BUFSIZE to match elfcap.h"
+#endif
+
+#if CONV_CAP_VAL_SF1_BUFSIZE != ELFCAP_SF1_BUFSIZE
+#error "libconv needs to update CONV_CAP_VAL_SF1_BUFSIZE to match elfcap.h"
+#endif
+
const conv_ds_t **
conv_cap_tag_strings(Conv_fmt_flags_t fmt_flags)
{
-#if (CA_SUNW_NUM != (CA_SUNW_ID + 1))
+#if (CA_SUNW_NUM != (CA_SUNW_HW_3 + 1))
#error "CA_SUNW_NUM has grown"
#endif
static const Msg tags_cf[] = {
MSG_CA_SUNW_NULL_CF, MSG_CA_SUNW_HW_1_CF,
MSG_CA_SUNW_SF_1_CF, MSG_CA_SUNW_HW_2_CF,
MSG_CA_SUNW_PLAT_CF, MSG_CA_SUNW_MACH_CF,
- MSG_CA_SUNW_ID_CF
+ MSG_CA_SUNW_ID_CF, MSG_CA_SUNW_HW_3_CF
};
static const Msg tags_nf[] = {
MSG_CA_SUNW_NULL_NF, MSG_CA_SUNW_HW_1_NF,
MSG_CA_SUNW_SF_1_NF, MSG_CA_SUNW_HW_2_NF,
MSG_CA_SUNW_PLAT_NF, MSG_CA_SUNW_MACH_NF,
- MSG_CA_SUNW_ID_NF
+ MSG_CA_SUNW_ID_NF, MSG_CA_SUNW_HW_3_NF
};
static const conv_ds_msg_t ds_tags_cf = {
CONV_DS_MSG_INIT(ELFCLASSNONE, tags_cf) };
@@ -140,6 +162,13 @@ conv_iter_ret_t
conv_iter_cap_val_hw2(Half mach, Conv_fmt_flags_t fmt_flags,
conv_iter_cb_t func, void *uvalue)
{
+ if ((mach == EM_386) || (mach == EM_486) ||
+ (mach == EM_AMD64) || (mach == CONV_MACH_ALL))
+ if (conv_iter_elfcap(elfcap_getdesc_hw2_386(),
+ ELFCAP_NUM_HW2_386, fmt_flags, func, uvalue) ==
+ CONV_ITER_DONE)
+ return (CONV_ITER_DONE);
+
return (CONV_ITER_DONE);
}
@@ -153,3 +182,17 @@ conv_iter_cap_val_sf1(Conv_fmt_flags_t fmt_flags, conv_iter_cb_t func,
return (conv_iter_elfcap(elfcap_getdesc_sf1(), ELFCAP_NUM_SF1,
fmt_flags, func, uvalue));
}
+
+conv_iter_ret_t
+conv_iter_cap_val_hw3(Half mach, Conv_fmt_flags_t fmt_flags,
+ conv_iter_cb_t func, void *uvalue)
+{
+ if ((mach == EM_386) || (mach == EM_486) ||
+ (mach == EM_AMD64) || (mach == CONV_MACH_ALL))
+ if (conv_iter_elfcap(elfcap_getdesc_hw3_386(),
+ ELFCAP_NUM_HW3_386, fmt_flags, func, uvalue) ==
+ CONV_ITER_DONE)
+ return (CONV_ITER_DONE);
+
+ return (CONV_ITER_DONE);
+}
diff --git a/usr/src/cmd/sgs/libconv/common/cap.msg b/usr/src/cmd/sgs/libconv/common/cap.msg
index ce07a0e001..5e0c56782c 100644
--- a/usr/src/cmd/sgs/libconv/common/cap.msg
+++ b/usr/src/cmd/sgs/libconv/common/cap.msg
@@ -2,6 +2,8 @@
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2022 Oxide Computer Company
+#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
@@ -38,6 +40,8 @@
@ MSG_CA_SUNW_MACH_NF "mach"
@ MSG_CA_SUNW_ID_CF "CA_SUNW_ID" # 6
@ MSG_CA_SUNW_ID_NF "id"
+@ MSG_CA_SUNW_HW_3_CF "CA_SUNW_HW_3" # 7
+@ MSG_CA_SUNW_HW_3_NF "hw_3"
@ MSG_GBL_ZERO "0"
@ MSG_GBL_OSQBRKT "0x%llx [ "
diff --git a/usr/src/cmd/sgs/libconv/common/cap_machelf.c b/usr/src/cmd/sgs/libconv/common/cap_machelf.c
index d572e29409..ce8bbbde47 100644
--- a/usr/src/cmd/sgs/libconv/common/cap_machelf.c
+++ b/usr/src/cmd/sgs/libconv/common/cap_machelf.c
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -108,6 +110,19 @@ conv_cap_val_sf1(Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
}
const char *
+conv_cap_val_hw3(Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
+ Conv_cap_val_hw3_buf_t *cap_val_hw3_buf)
+{
+ if (val == 0)
+ return (MSG_ORIG(MSG_GBL_ZERO));
+
+ if (conv_cap(val, cap_val_hw3_buf->buf, sizeof (cap_val_hw3_buf->buf),
+ mach, fmt_flags, elfcap_hw3_to_str) == 0)
+ return (conv_invalid_val(&cap_val_hw3_buf->inv_buf, val, 0));
+ return ((const char *)cap_val_hw3_buf->buf);
+}
+
+const char *
conv_cap_tag(Xword tag, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf)
{
#ifdef _ELF64
@@ -144,6 +159,10 @@ conv_cap_val(Xword tag, Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
return (conv_cap_val_hw2(val, mach, fmt_flags,
&cap_val_buf->cap_val_hw2_buf));
+ case CA_SUNW_HW_3:
+ return (conv_cap_val_hw3(val, mach, fmt_flags,
+ &cap_val_buf->cap_val_hw3_buf));
+
default:
return (conv_invalid_val(&cap_val_buf->inv_buf, val, 0));
}
diff --git a/usr/src/cmd/sgs/libconv/common/corenote.c b/usr/src/cmd/sgs/libconv/common/corenote.c
index 0b8510a95a..d7403991ed 100644
--- a/usr/src/cmd/sgs/libconv/common/corenote.c
+++ b/usr/src/cmd/sgs/libconv/common/corenote.c
@@ -27,7 +27,7 @@
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2018 Joyent, Inc.
* Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -109,7 +109,7 @@ conv_cnote_auxv_type(Word type, Conv_fmt_flags_t fmt_flags,
static const conv_ds_msg_t ds_types_2000_2011 = {
CONV_DS_MSG_INIT(2000, types_2000_2011) };
- static const Msg types_2014_2028[] = {
+ static const Msg types_2014_2029[] = {
MSG_AUXV_AT_SUN_EXECNAME, MSG_AUXV_AT_SUN_MMU,
MSG_AUXV_AT_SUN_LDDATA, MSG_AUXV_AT_SUN_AUXFLAGS,
MSG_AUXV_AT_SUN_EMULATOR, MSG_AUXV_AT_SUN_BRANDNAME,
@@ -117,14 +117,14 @@ conv_cnote_auxv_type(Word type, Conv_fmt_flags_t fmt_flags,
MSG_AUXV_AT_SUN_BRAND_AUX3, MSG_AUXV_AT_SUN_HWCAP2,
MSG_AUXV_AT_SUN_BRAND_NROOT, MSG_AUXV_AT_SUN_BRAND_AUX4,
MSG_AUXV_AT_SUN_COMMPAGE, MSG_AUXV_AT_SUN_FPTYPE,
- MSG_AUXV_AT_SUN_FPSIZE
+ MSG_AUXV_AT_SUN_FPSIZE, MSG_AUXV_AT_SUN_HWCAP3
};
- static const conv_ds_msg_t ds_types_2014_2028 = {
- CONV_DS_MSG_INIT(2014, types_2014_2028) };
+ static const conv_ds_msg_t ds_types_2014_2029 = {
+ CONV_DS_MSG_INIT(2014, types_2014_2029) };
static const conv_ds_t *ds[] = {
CONV_DS_ADDR(ds_types_0_25), CONV_DS_ADDR(ds_types_2000_2011),
- CONV_DS_ADDR(ds_types_2014_2028), NULL };
+ CONV_DS_ADDR(ds_types_2014_2029), NULL };
return (conv_map_ds(ELFOSABI_NONE, EM_NONE, type, ds, fmt_flags,
inv_buf));
diff --git a/usr/src/cmd/sgs/libconv/common/corenote.msg b/usr/src/cmd/sgs/libconv/common/corenote.msg
index c202c1c62c..981c0800ce 100644
--- a/usr/src/cmd/sgs/libconv/common/corenote.msg
+++ b/usr/src/cmd/sgs/libconv/common/corenote.msg
@@ -26,7 +26,7 @@
# Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
# Copyright (c) 2018 Joyent, Inc.
# Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
-# Copyright 2021 Oxide Computer Company
+# Copyright 2022 Oxide Computer Company
#
@ MSG_NT_PRSTATUS "[ NT_PRSTATUS ]"
@@ -113,6 +113,7 @@
@ MSG_AUXV_AT_SUN_COMMPAGE "SUN_COMMPAGE"
@ MSG_AUXV_AT_SUN_FPTYPE "SUN_FPTYPE"
@ MSG_AUXV_AT_SUN_FPSIZE "SUN_FPSIZE"
+@ MSG_AUXV_AT_SUN_HWCAP3 "SUN_HWCAP3"
@ MSG_CC_CONTENT_STACK "STACK"
diff --git a/usr/src/cmd/sgs/libconv/common/elf.c b/usr/src/cmd/sgs/libconv/common/elf.c
index 2ef1f55963..a61cc5450e 100644
--- a/usr/src/cmd/sgs/libconv/common/elf.c
+++ b/usr/src/cmd/sgs/libconv/common/elf.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -1217,6 +1218,7 @@ conv_reject_desc(Rej_desc * rej, Conv_reject_desc_buf_t *reject_desc_buf,
case SGS_REJ_HWCAP_1:
case SGS_REJ_SFCAP_1:
case SGS_REJ_HWCAP_2:
+ case SGS_REJ_HWCAP_3:
case SGS_REJ_MACHCAP:
case SGS_REJ_PLATCAP:
if (rej->rej_str)
diff --git a/usr/src/cmd/sgs/libld/common/files.c b/usr/src/cmd/sgs/libld/common/files.c
index a3277b4bf1..4ae59398b1 100644
--- a/usr/src/cmd/sgs/libld/common/files.c
+++ b/usr/src/cmd/sgs/libld/common/files.c
@@ -25,6 +25,7 @@
*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -389,12 +390,21 @@ hw_cap(Ofl_desc *ofl, Xword tag, Xword val)
elfcap_mask_t *hwcap;
ofl_flag_t flags1;
- if (tag == CA_SUNW_HW_1) {
+ switch (tag) {
+ case CA_SUNW_HW_1:
hwcap = &ofl->ofl_ocapset.oc_hw_1.cm_val;
flags1 = FLG_OF1_OVHWCAP1;
- } else {
+ break;
+ case CA_SUNW_HW_2:
hwcap = &ofl->ofl_ocapset.oc_hw_2.cm_val;
flags1 = FLG_OF1_OVHWCAP2;
+ break;
+ case CA_SUNW_HW_3:
+ hwcap = &ofl->ofl_ocapset.oc_hw_3.cm_val;
+ flags1 = FLG_OF1_OVHWCAP3;
+ break;
+ default:
+ assert(0);
}
/*
@@ -547,6 +557,9 @@ ld_cap_move_symtoobj(Ofl_desc *ofl)
CA_SUNW_MACH, &ofl->ofl_ocapset.oc_mach);
}
}
+ if (scapset->oc_hw_3.cm_val)
+ hw_cap(ofl, CA_SUNW_HW_3, scapset->oc_hw_3.cm_val);
+
if (scapset->oc_hw_2.cm_val)
hw_cap(ofl, CA_SUNW_HW_2, scapset->oc_hw_2.cm_val);
@@ -599,6 +612,8 @@ get_cap_group(Objcapset *ocapset, Word cnum, Ofl_desc *ofl, Is_desc *isp)
continue;
if (cgp->cg_set.oc_hw_2.cm_val != ocapset->oc_hw_2.cm_val)
continue;
+ if (cgp->cg_set.oc_hw_3.cm_val != ocapset->oc_hw_3.cm_val)
+ continue;
calp = cgp->cg_set.oc_plat.cl_val;
oalp = ocapset->oc_plat.cl_val;
@@ -898,6 +913,7 @@ process_cap(Ofl_desc *ofl, Ifl_desc *ifl, Is_desc *cisp)
case CA_SUNW_HW_1:
case CA_SUNW_SF_1:
case CA_SUNW_HW_2:
+ case CA_SUNW_HW_3:
/*
* If this is the start of a new group, save it.
*/
@@ -1099,7 +1115,8 @@ process_cap(Ofl_desc *ofl, Ifl_desc *ifl, Is_desc *cisp)
*/
ocapset.oc_hw_1.cm_val =
ocapset.oc_sf_1.cm_val =
- ocapset.oc_hw_2.cm_val = 0;
+ ocapset.oc_hw_2.cm_val =
+ ocapset.oc_hw_3.cm_val = 0;
if (ocapset.oc_plat.cl_val) {
free((void *)ocapset.oc_plat.cl_val);
ocapset.oc_plat.cl_val = NULL;
@@ -1157,6 +1174,13 @@ process_cap(Ofl_desc *ofl, Ifl_desc *ifl, Is_desc *cisp)
DBG_STATE_ORIGINAL, CA_SUNW_ID,
ocapset.oc_id.cs_str));
break;
+
+ case CA_SUNW_HW_3:
+ ocapset.oc_hw_3.cm_val = data->c_un.c_val;
+ DBG_CALL(Dbg_cap_val_entry(ofl->ofl_lml,
+ DBG_STATE_ORIGINAL, CA_SUNW_HW_3,
+ ocapset.oc_hw_3.cm_val, ld_targ.t_m.m_mach));
+ break;
}
/*
diff --git a/usr/src/cmd/sgs/libld/common/globals.c b/usr/src/cmd/sgs/libld/common/globals.c
index 71dda65bf2..c57dafc426 100644
--- a/usr/src/cmd/sgs/libld/common/globals.c
+++ b/usr/src/cmd/sgs/libld/common/globals.c
@@ -24,6 +24,7 @@
* All Rights Reserved
*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -77,9 +78,10 @@ reject[SGS_REJ_NUM] = {
MSG_REJ_PLATCAP, /* MSG_INTL(MSG_REJ_PLATCAP) */
MSG_REJ_HWCAP_2, /* MSG_INTL(MSG_REJ_HWCAP_2) */
MSG_REJ_ARCHIVE, /* MSG_INTL(MSG_REJ_ARCHIVE) */
- MSG_REJ_KMOD /* MSG_INTL(MSG_REJ_KMOD) */
+ MSG_REJ_KMOD, /* MSG_INTL(MSG_REJ_KMOD) */
+ MSG_REJ_HWCAP_3 /* MSG_INTL(MSG_REJ_HWCAP_3) */
};
-#if SGS_REJ_NUM != (SGS_REJ_KMOD + 1)
+#if SGS_REJ_NUM != (SGS_REJ_HWCAP_3 + 1)
#error SGS_REJ_NUM has changed
#endif
diff --git a/usr/src/cmd/sgs/libld/common/libld.msg b/usr/src/cmd/sgs/libld/common/libld.msg
index 659c40bf73..e575a263f0 100644
--- a/usr/src/cmd/sgs/libld/common/libld.msg
+++ b/usr/src/cmd/sgs/libld/common/libld.msg
@@ -23,6 +23,7 @@
# Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
# Copyright 2017 RackTop Systems.
+# Copyright 2022 Oxide Computer Company
#
@ _START_
@@ -693,6 +694,8 @@
unsupported: %s"
@ MSG_REJ_ARCHIVE "file %s: invalid archive use"
@ MSG_REJ_KMOD "file %s: kernel modules can't be link-edit input"
+@ MSG_REJ_HWCAP_3 "file %s: hardware capability (CA_SUNW_HW_3) \
+ unsupported: %s"
# Guidance messages
@ MSG_GUIDE_UNKNOWN "unrecognized -z guidance item: %s"
@@ -1617,6 +1620,7 @@
@ MSG_MAPKW_HW "HW"
@ MSG_MAPKW_HW_1 "HW_1"
@ MSG_MAPKW_HW_2 "HW_2"
+@ MSG_MAPKW_HW_3 "HW_3"
@ MSG_MAPKW_INTERPOSE "INTERPOSE"
@ MSG_MAPKW_IS_NAME "IS_NAME"
@ MSG_MAPKW_IS_ORDER "IS_ORDER"
diff --git a/usr/src/cmd/sgs/libld/common/map_support.c b/usr/src/cmd/sgs/libld/common/map_support.c
index 61d64b7fd9..ea11c8aefb 100644
--- a/usr/src/cmd/sgs/libld/common/map_support.c
+++ b/usr/src/cmd/sgs/libld/common/map_support.c
@@ -29,6 +29,7 @@
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -203,9 +204,10 @@ ld_map_cap_set_ovflag(Mapfile *mf, Word type)
FLG_OF1_OVHWCAP2, /* CA_SUNW_HW_2 */
FLG_OF1_OVPLATCAP, /* CA_SUNW_PLAT */
FLG_OF1_OVMACHCAP, /* CA_SUNW_MACH */
- FLG_OF1_OVIDCAP /* CA_SUNW_ID */
+ FLG_OF1_OVIDCAP, /* CA_SUNW_ID */
+ FLG_OF1_OVHWCAP3 /* CA_SUNW_HW_3 */
};
-#if CA_SUNW_NUM != (CA_SUNW_ID + 1)
+#if CA_SUNW_NUM != (CA_SUNW_HW_3 + 1)
#error "CA_SUNW_NUM has grown"
#endif
mf->mf_ofl->ofl_flags1 |= override_flag[type];
diff --git a/usr/src/cmd/sgs/libld/common/map_v2.c b/usr/src/cmd/sgs/libld/common/map_v2.c
index 791ad34971..c3e8ef77eb 100644
--- a/usr/src/cmd/sgs/libld/common/map_v2.c
+++ b/usr/src/cmd/sgs/libld/common/map_v2.c
@@ -26,6 +26,7 @@
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -1063,7 +1064,7 @@ at_cap_hw(Mapfile *mf, Token eq_tok, void *uvalue)
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
- Word hw1 = 0, hw2 = 0;
+ Word hw1 = 0, hw2 = 0, hw3 = 0;
uint64_t v;
for (done = 0; done == 0; ) {
@@ -1082,6 +1083,12 @@ at_cap_hw(Mapfile *mf, Token eq_tok, void *uvalue)
hw2 |= v;
break;
}
+
+ if ((v = elfcap_hw3_from_str(ELFCAP_STYLE,
+ tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+ hw3 |= v;
+ break;
+ }
goto bad_flag;
case TK_SEMICOLON:
@@ -1103,6 +1110,9 @@ at_cap_hw(Mapfile *mf, Token eq_tok, void *uvalue)
if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.oc_hw_2, eq_tok,
CA_SUNW_HW_2, hw2, FALSE))
return (TK_ERROR);
+ if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.oc_hw_3, eq_tok,
+ CA_SUNW_HW_3, hw3, FALSE))
+ return (TK_ERROR);
return (tok);
}
@@ -1209,6 +1219,17 @@ at_cap_plat(Mapfile *mf, Token eq_tok, void *uvalue)
}
/*
+ * CAPABILITY [capid] { HW_3 = value ;
+ * ---------------------------^
+ */
+static Token
+at_cap_hw_3(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_hw_3,
+ CA_SUNW_HW_3, elfcap_hw3_from_str));
+}
+
+/*
* Top Level Directive:
*
* CAPABILITY [capid] { ...
@@ -1222,6 +1243,7 @@ dir_capability(Mapfile *mf)
{ MSG_ORIG(MSG_MAPKW_HW), at_cap_hw, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_HW_1), at_cap_hw_1, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_HW_2), at_cap_hw_2, ATTR_FMT_EQ_ALL },
+ { MSG_ORIG(MSG_MAPKW_HW_3), at_cap_hw_3, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_MACHINE), at_cap_mach, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_PLATFORM), at_cap_plat, ATTR_FMT_EQ_ALL },
@@ -1241,6 +1263,7 @@ dir_capability(Mapfile *mf)
KW_NAME_SIZE(MSG_MAPKW_HW) +
KW_NAME_SIZE(MSG_MAPKW_HW_1) +
KW_NAME_SIZE(MSG_MAPKW_HW_2) +
+ KW_NAME_SIZE(MSG_MAPKW_HW_3) +
KW_NAME_SIZE(MSG_MAPKW_MACHINE) +
KW_NAME_SIZE(MSG_MAPKW_PLATFORM) +
KW_NAME_SIZE(MSG_MAPKW_SF) +
diff --git a/usr/src/cmd/sgs/libld/common/sections.c b/usr/src/cmd/sgs/libld/common/sections.c
index 984c3c9b8e..5ff110e346 100644
--- a/usr/src/cmd/sgs/libld/common/sections.c
+++ b/usr/src/cmd/sgs/libld/common/sections.c
@@ -24,6 +24,7 @@
* All Rights Reserved
*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -1494,6 +1495,14 @@ is_cap_redundant(Objcapset *ocapset, Objcapset *scapset)
* could be considered to be less important than lower ones. However,
* this is the only reasonable non-subjective definition.
*/
+ omsk = ocapset->oc_hw_3.cm_val;
+ smsk = scapset->oc_hw_3.cm_val;
+ if ((omsk > smsk) || (omsk && (omsk == smsk)))
+ return (1);
+ if (omsk < smsk)
+ return (0);
+
+
omsk = ocapset->oc_hw_2.cm_val;
smsk = scapset->oc_hw_2.cm_val;
if ((omsk > smsk) || (omsk && (omsk == smsk)))
@@ -1650,6 +1659,7 @@ make_cap(Ofl_desc *ofl, Word shtype, const char *shname, int ident)
*/
capstr_value(ofl->ofl_lml, CA_SUNW_PLAT, &ocapset->oc_plat, &title);
capstr_value(ofl->ofl_lml, CA_SUNW_MACH, &ocapset->oc_mach, &title);
+ capmask_value(ofl->ofl_lml, CA_SUNW_HW_3, &ocapset->oc_hw_3, &title);
capmask_value(ofl->ofl_lml, CA_SUNW_HW_2, &ocapset->oc_hw_2, &title);
capmask_value(ofl->ofl_lml, CA_SUNW_HW_1, &ocapset->oc_hw_1, &title);
capmask_value(ofl->ofl_lml, CA_SUNW_SF_1, &ocapset->oc_sf_1, &title);
@@ -1659,6 +1669,8 @@ make_cap(Ofl_desc *ofl, Word shtype, const char *shname, int ident)
*/
size += alist_nitems(ocapset->oc_plat.cl_val);
size += alist_nitems(ocapset->oc_mach.cl_val);
+ if (ocapset->oc_hw_3.cm_val)
+ size++;
if (ocapset->oc_hw_2.cm_val)
size++;
if (ocapset->oc_hw_1.cm_val)
@@ -1750,6 +1762,10 @@ make_cap(Ofl_desc *ofl, Word shtype, const char *shname, int ident)
CAP_UPDATE(cap, capndx, CA_SUNW_MACH, 0);
}
}
+ if (ocapset->oc_hw_3.cm_val) {
+ ofl->ofl_flags |= FLG_OF_PTCAP;
+ CAP_UPDATE(cap, capndx, CA_SUNW_HW_3, ocapset->oc_hw_3.cm_val);
+ }
if (ocapset->oc_hw_2.cm_val) {
ofl->ofl_flags |= FLG_OF_PTCAP;
CAP_UPDATE(cap, capndx, CA_SUNW_HW_2, ocapset->oc_hw_2.cm_val);
@@ -1830,6 +1846,10 @@ make_cap(Ofl_desc *ofl, Word shtype, const char *shname, int ident)
CA_SUNW_MACH, 0);
}
}
+ if (scapset->oc_hw_3.cm_val) {
+ CAP_UPDATE(cap, capndx, CA_SUNW_HW_3,
+ scapset->oc_hw_3.cm_val);
+ }
if (scapset->oc_hw_2.cm_val) {
CAP_UPDATE(cap, capndx, CA_SUNW_HW_2,
scapset->oc_hw_2.cm_val);
diff --git a/usr/src/cmd/sgs/liblddbg/common/cap.c b/usr/src/cmd/sgs/liblddbg/common/cap.c
index d1429920c7..0e5f12ad16 100644
--- a/usr/src/cmd/sgs/liblddbg/common/cap.c
+++ b/usr/src/cmd/sgs/liblddbg/common/cap.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <stdio.h>
@@ -82,6 +83,11 @@ Dbg_cap_val(Lm_list *lml, Syscapset *sys, Syscapset *alt, Half mach)
if (sys->sc_mach) {
dbg_print(lml, MSG_INTL(MSG_CAP_SYS_MACH), sys->sc_mach);
}
+ if (sys->sc_hw_3) {
+ dbg_print(lml, MSG_INTL(MSG_CAP_SYS_HW_3),
+ conv_cap_val_hw3(sys->sc_hw_3, mach, 0,
+ &cap_val_buf.cap_val_hw3_buf));
+ }
if (sys->sc_hw_2) {
dbg_print(lml, MSG_INTL(MSG_CAP_SYS_HW_2),
conv_cap_val_hw2(sys->sc_hw_2, mach, 0,
@@ -108,6 +114,11 @@ Dbg_cap_val(Lm_list *lml, Syscapset *sys, Syscapset *alt, Half mach)
dbg_print(lml, MSG_INTL(MSG_CAP_ALT_MACH),
alt->sc_mach);
}
+ if (alt->sc_hw_3 != sys->sc_hw_3) {
+ dbg_print(lml, MSG_INTL(MSG_CAP_ALT_HW_3),
+ conv_cap_val_hw3(alt->sc_hw_3, mach, 0,
+ &cap_val_buf.cap_val_hw3_buf));
+ }
if (alt->sc_hw_2 != sys->sc_hw_2) {
dbg_print(lml, MSG_INTL(MSG_CAP_ALT_HW_2),
conv_cap_val_hw2(alt->sc_hw_2, mach, 0,
diff --git a/usr/src/cmd/sgs/liblddbg/common/files.c b/usr/src/cmd/sgs/liblddbg/common/files.c
index b44aabd116..5e167103a0 100644
--- a/usr/src/cmd/sgs/liblddbg/common/files.c
+++ b/usr/src/cmd/sgs/liblddbg/common/files.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/auxv.h>
@@ -652,8 +653,11 @@ Dbg_file_generic(Lm_list *lml, Ifl_desc *ifl)
ifl->ifl_ehdr->e_type, 0, &inv_buf));
}
-static const Msg
-reject[] = {
+#if SGS_REJ_NUM != (SGS_REJ_HWCAP_3 + 1)
+#error SGS_REJ_NUM has changed
+#endif
+
+static const Msg reject[SGS_REJ_NUM] = {
MSG_STR_EMPTY,
MSG_REJ_MACH, /* MSG_INTL(MSG_REJ_MACH) */
MSG_REJ_CLASS, /* MSG_INTL(MSG_REJ_CLASS) */
@@ -671,7 +675,10 @@ reject[] = {
MSG_REJ_SFCAP_1, /* MSG_INTL(MSG_REJ_SFCAP_1) */
MSG_REJ_MACHCAP, /* MSG_INTL(MSG_REJ_MACHCAP) */
MSG_REJ_PLATCAP, /* MSG_INTL(MSG_REJ_PLATCAP) */
- MSG_REJ_HWCAP_2 /* MSG_INTL(MSG_REJ_HWCAP_2) */
+ MSG_REJ_HWCAP_2, /* MSG_INTL(MSG_REJ_HWCAP_2) */
+ MSG_REJ_ARCHIVE, /* MSG_INTL(MSG_REJ_ARCHIVE) */
+ MSG_REJ_KMOD, /* MSG_INTL(MSG_REJ_KMOD) */
+ MSG_REJ_HWCAP_3 /* MSG_INTL(MSG_REJ_HWCAP_3) */
};
void
diff --git a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
index 74619ae699..56c4f0ada6 100644
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
@@ -21,6 +21,7 @@
#
# Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2022 Oxide Computer Company
#
@ _START_
@@ -751,6 +752,10 @@
unsupported: %s"
@ MSG_REJ_HWCAP_2 "obj=%s; rejected: hardware capability (CA_SUNW_HW_2) \
unsupported: %s"
+@ MSG_REJ_ARCHIVE "obj=%s; rejected: archive unsed incorrectly"
+@ MSG_REJ_KMOD "obj=%s; rejected: kernel module"
+@ MSG_REJ_HWCAP_3 "obj=%s; rejected: hardware capability (CA_SUNW_HW_3) \
+ unsupported: %s"
# Libs messages
@@ -996,6 +1001,8 @@
(CA_SUNW_PLAT): [ %s ]"
@ MSG_CAP_SYM_HW_2 " symbol=%s[%u]: capability specific \
(CA_SUNW_HW_2): [ %s ]"
+@ MSG_CAP_SYM_HW_3 " symbol=%s[%u]: capability specific \
+ (CA_SUNW_HW_3): [ %s ]"
@ MSG_SYM_LAZY_RESCAN "rescanning for lazy dependencies for symbol: %s"
@@ -1181,12 +1188,14 @@
@ MSG_CAP_SYS_MACH "machine capability (CA_SUNW_MACH) - %s"
@ MSG_CAP_SYS_PLAT "platform capability (CA_SUNW_PLAT) - %s"
@ MSG_CAP_SYS_HW_2 "hardware capabilities (CA_SUNW_HW_2) - %s"
+@ MSG_CAP_SYS_HW_3 "hardware capabilities (CA_SUNW_HW_3) - %s"
@ MSG_CAP_ALT_HW_1 "alternative hardware capabilities (CA_SUNW_HW_1) - %s"
@ MSG_CAP_ALT_SF_1 "alternative software capabilities (CA_SUNW_SF_1) - %s"
@ MSG_CAP_ALT_MACH "alternative machine capability (CA_SUNW_MACH) - %s"
@ MSG_CAP_ALT_PLAT "alternative platform capability (CA_SUNW_PLAT) - %s"
@ MSG_CAP_ALT_HW_2 "alternative hardware capabilities (CA_SUNW_HW_2) - %s"
+@ MSG_CAP_ALT_HW_3 "alternative hardware capabilities (CA_SUNW_HW_3) - %s"
@ MSG_CAP_SEC_TITLE "capabilities; input file=%s"
@ MSG_CAP_SEC_ENTRY "%12.12s %-15.15s %s"
diff --git a/usr/src/cmd/sgs/liblddbg/common/syms.c b/usr/src/cmd/sgs/liblddbg/common/syms.c
index be3315243a..446499b6e5 100644
--- a/usr/src/cmd/sgs/liblddbg/common/syms.c
+++ b/usr/src/cmd/sgs/liblddbg/common/syms.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <stdio.h>
@@ -40,7 +41,7 @@ Dbg_syms_lookup(Rt_map *lmp, const char *name, const char *type)
NAME(lmp), type);
}
-static const Msg captype[DBG_CAP_MACH + 1] = {
+static const Msg captype[DBG_CAP_HW_3 + 1] = {
MSG_CAP_SYM_DEFAULT, /* MSG_INTL(MSG_CAP_SYM_DEFAULT) */
MSG_CAP_SYM_USED, /* MSG_INTL(MSG_CAP_SYM_USED) */
MSG_CAP_SYM_CANDIDATE, /* MSG_INTL(MSG_CAP_SYM_CANDIDATE) */
@@ -49,7 +50,8 @@ static const Msg captype[DBG_CAP_MACH + 1] = {
MSG_CAP_SYM_SF_1, /* MSG_INTL(MSG_CAP_SYM_SF_1) */
MSG_CAP_SYM_HW_2, /* MSG_INTL(MSG_CAP_SYM_HW_2) */
MSG_CAP_SYM_PLAT, /* MSG_INTL(MSG_CAP_SYM_PLAT) */
- MSG_CAP_SYM_MACH /* MSG_INTL(MSG_CAP_SYM_MACH) */
+ MSG_CAP_SYM_MACH, /* MSG_INTL(MSG_CAP_SYM_MACH) */
+ MSG_CAP_SYM_HW_3 /* MSG_INTL(MSG_CAP_SYM_HW_3) */
};
void
@@ -82,6 +84,10 @@ Dbg_syms_cap_lookup(Rt_map *lmp, uint_t type, const char *name, uint_t ndx,
case DBG_CAP_PLAT:
str = scapset->sc_plat;
break;
+ case DBG_CAP_HW_3:
+ str = conv_cap_val_hw3(scapset->sc_hw_3, mach, 0,
+ &cap_val_buf.cap_val_hw3_buf);
+ break;
}
dbg_print(lml, MSG_INTL(captype[type]), Dbg_demangle_name(name),
diff --git a/usr/src/cmd/sgs/rtld/amd64/_setup.c b/usr/src/cmd/sgs/rtld/amd64/_setup.c
index e48db1cc11..1d45699da2 100644
--- a/usr/src/cmd/sgs/rtld/amd64/_setup.c
+++ b/usr/src/cmd/sgs/rtld/amd64/_setup.c
@@ -25,6 +25,7 @@
*/
/*
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -121,7 +122,7 @@ _setup(Boot *ebp, Dyn *ld_dyn)
char *_rt_name, **_envp, **_argv;
int _syspagsz = 0, fd = -1;
uint_t _flags = 0;
- uint_t hwcap[2] = { 0, 0 };
+ uint_t hwcap[3] = { 0, 0, 0 };
Dyn *dyn_ptr;
Phdr *phdr = NULL;
Rt_map *lmp;
@@ -217,6 +218,10 @@ _setup(Boot *ebp, Dyn *ld_dyn)
/* hardware capabilities */
hwcap[1] = (uint_t)auxv->a_un.a_val;
break;
+ case AT_SUN_HWCAP3:
+ /* hardware capabilities */
+ hwcap[2] = (uint_t)auxv->a_un.a_val;
+ break;
case AT_SUN_EMULATOR:
/* name of emulation library, if any */
_emulator = auxv->a_un.a_ptr;
diff --git a/usr/src/cmd/sgs/rtld/common/cap.c b/usr/src/cmd/sgs/rtld/common/cap.c
index 47abbc78bc..0c4109c97a 100644
--- a/usr/src/cmd/sgs/rtld/common/cap.c
+++ b/usr/src/cmd/sgs/rtld/common/cap.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/types.h>
@@ -69,9 +70,19 @@ compare(const void *vp_a, const void *vp_b)
return (-1);
if (strcap_b && (strcap_a == NULL))
return (1);
+ /*
+ * Third, investigate any CA_SUNW_HW_3 hardware capabilities.
+ */
+ hwcap_a = fdp_a->fd_scapset.sc_hw_3;
+ hwcap_b = fdp_b->fd_scapset.sc_hw_3;
+
+ if (hwcap_a > hwcap_b)
+ return (-1);
+ if (hwcap_a < hwcap_b)
+ return (1);
/*
- * Third, investigate any CA_SUNW_HW_2 hardware capabilities.
+ * Fourth, investigate any CA_SUNW_HW_2 hardware capabilities.
*/
hwcap_a = fdp_a->fd_scapset.sc_hw_2;
hwcap_b = fdp_b->fd_scapset.sc_hw_2;
@@ -160,6 +171,30 @@ hwcap2_check(Syscapset *scapset, Xword val, Rej_desc *rej)
}
/*
+ * Determine whether HWCAP3 capabilities value is supported.
+ */
+int
+hwcap3_check(Syscapset *scapset, Xword val, Rej_desc *rej)
+{
+ Xword mval;
+
+ /*
+ * Ensure that the kernel can cope with the required capabilities.
+ */
+ if ((mval = (val & ~scapset->sc_hw_3)) != 0) {
+ if (rej) {
+ static Conv_cap_val_hw3_buf_t cap_buf;
+
+ rej->rej_type = SGS_REJ_HWCAP_3;
+ rej->rej_str = conv_cap_val_hw3(mval,
+ M_MACH, 0, &cap_buf);
+ }
+ return (0);
+ }
+ return (1);
+}
+
+/*
* Process any software capabilities.
*/
/* ARGSUSED0 */
@@ -343,6 +378,12 @@ cap_check(Cap *cptr, char *strs, int alt, Fdesc *fdp, Rej_desc *rej)
* the system. They are ignored.
*/
break;
+ case CA_SUNW_HW_3:
+ if (hwcap3_check(scapset, val, rej) == 0)
+ return (0);
+ if (fdp)
+ fdp->fd_scapset.sc_hw_3 = val;
+ break;
default:
rej->rej_type = SGS_REJ_UNKCAP;
rej->rej_info = cptr->c_tag;
@@ -837,15 +878,28 @@ typedef enum {
CAP_DISABLE = 2 /* disable capabilities */
} cap_mode;
+/*
+ * The override indexes originally followed the values of CA_SUNW_HW_1, SF_1,
+ * etc.
+ */
+typedef enum {
+ CAP_OVR_HW_1 = 0,
+ CAP_OVR_SF_1,
+ CAP_OVR_HW_2,
+ CAP_OVR_HW_3,
+ CAP_OVR_MAX
+} cap_index_t;
+
static struct {
elfcap_mask_t cs_val[3]; /* value settings, and indicator for */
int cs_set[3]; /* OVERRIDE, ENABLE and DISABLE */
elfcap_mask_t *cs_aval; /* alternative variable for final */
/* update */
-} cap_settings[3] = {
+} cap_settings[CAP_OVR_MAX] = {
{ { 0, 0, 0 }, { 0, 0, 0 }, NULL }, /* CA_SUNW_HW_1 */
{ { 0, 0, 0 }, { 0, 0, 0 }, NULL }, /* CA_SUNW_SF_1 */
- { { 0, 0, 0 }, { 0, 0, 0 }, NULL } /* CA_SUNW_HW_2 */
+ { { 0, 0, 0 }, { 0, 0, 0 }, NULL }, /* CA_SUNW_HW_2 */
+ { { 0, 0, 0 }, { 0, 0, 0 }, NULL } /* CA_SUNW_HW_3 */
};
static int
@@ -853,7 +907,7 @@ cap_modify(Xword tag, const char *str)
{
char *caps, *ptr, *next;
cap_mode mode = CAP_OVERRIDE;
- Xword ndx;
+ cap_index_t ndx;
if ((caps = strdup(str)) == NULL)
return (0);
@@ -885,16 +939,22 @@ cap_modify(Xword tag, const char *str)
* a known hardware capability mask. Note, the caller
* indicates that these are hardware capabilities by
* passing in the CA_SUNW_HW_1 tag. However, the
- * tokens could be CA_SUNW_HW_1 or CA_SUNW_HW_2.
+ * tokens could be CA_SUNW_HW_1, CA_SUNW_HW_2, or
+ * CA_SUNW_HW_3.
*/
+ if ((val = (Xword)elfcap_hw3_from_str(ELFCAP_STYLE,
+ ptr, M_MACH)) != 0) {
+ ndx = CAP_OVR_HW_3;
+ break;
+ }
if ((val = (Xword)elfcap_hw2_from_str(ELFCAP_STYLE,
ptr, M_MACH)) != 0) {
- ndx = CA_SUNW_HW_2;
+ ndx = CAP_OVR_HW_2;
break;
}
if ((val = (Xword)elfcap_hw1_from_str(ELFCAP_STYLE,
ptr, M_MACH)) != 0)
- ndx = CA_SUNW_HW_1;
+ ndx = CAP_OVR_HW_1;
break;
case CA_SUNW_SF_1:
/*
@@ -906,7 +966,7 @@ cap_modify(Xword tag, const char *str)
*/
if ((val = (Xword)elfcap_sf1_from_str(ELFCAP_STYLE,
ptr, M_MACH)) != 0)
- ndx = CA_SUNW_SF_1;
+ ndx = CAP_OVR_SF_1;
break;
}
@@ -918,6 +978,7 @@ cap_modify(Xword tag, const char *str)
*
* LD_HWCAP=[1]0x40 sets CA_SUNW_HW_1 with 0x40
* LD_HWCAP=[2]0x80 sets CA_SUNW_HW_2 with 0x80
+ * LD_HWCAP=[3]0x44 sets CA_SUNW_HW_3 with 0x44
*
* Invalid indexes are ignored.
*/
@@ -926,11 +987,19 @@ cap_modify(Xword tag, const char *str)
if ((*ptr == '[') && (*(ptr + 2) == ']')) {
if (*(ptr + 1) == '1') {
- ndx = tag;
+ ndx = CAP_OVR_HW_1;
ptr += 3;
+ } else if (*(ptr + 1) == '3') {
+ if (tag == CA_SUNW_HW_1) {
+ ndx = CAP_OVR_HW_3;
+ ptr += 3;
+ } else {
+ /* invalid index */
+ continue;
+ }
} else if (*(ptr + 1) == '2') {
if (tag == CA_SUNW_HW_1) {
- ndx = CA_SUNW_HW_2;
+ ndx = CAP_OVR_HW_2;
ptr += 3;
} else {
/* invalid index */
@@ -940,8 +1009,9 @@ cap_modify(Xword tag, const char *str)
/* invalid index */
continue;
}
- } else
- ndx = tag;
+ } else {
+ ndx = tag - 1;
+ }
errno = 0;
if (((val = strtol(ptr, &end, 16)) == 0) && errno)
@@ -959,8 +1029,8 @@ cap_modify(Xword tag, const char *str)
}
}
- cap_settings[ndx - 1].cs_val[mode] |= val;
- cap_settings[ndx - 1].cs_set[mode]++;
+ cap_settings[ndx].cs_val[mode] |= val;
+ cap_settings[ndx].cs_set[mode]++;
}
@@ -968,7 +1038,7 @@ cap_modify(Xword tag, const char *str)
* If the "override" token was supplied, set the alternative
* system capabilities, then enable or disable others.
*/
- for (ndx = 0; ndx < CA_SUNW_HW_2; ndx++) {
+ for (ndx = 0; ndx < CAP_OVR_MAX; ndx++) {
if (cap_settings[ndx].cs_set[CAP_OVERRIDE])
*(cap_settings[ndx].cs_aval) =
cap_settings[ndx].cs_val[CAP_OVERRIDE];
@@ -1046,9 +1116,10 @@ cap_alternative(void)
return (0);
*alt_scapset = *org_scapset;
- cap_settings[CA_SUNW_HW_1 - 1].cs_aval = &alt_scapset->sc_hw_1;
- cap_settings[CA_SUNW_SF_1 - 1].cs_aval = &alt_scapset->sc_sf_1;
- cap_settings[CA_SUNW_HW_2 - 1].cs_aval = &alt_scapset->sc_hw_2;
+ cap_settings[CAP_OVR_HW_1].cs_aval = &alt_scapset->sc_hw_1;
+ cap_settings[CAP_OVR_SF_1].cs_aval = &alt_scapset->sc_sf_1;
+ cap_settings[CAP_OVR_HW_2].cs_aval = &alt_scapset->sc_hw_2;
+ cap_settings[CAP_OVR_HW_3].cs_aval = &alt_scapset->sc_hw_3;
/*
* Process any replaceable variables.
@@ -1203,6 +1274,15 @@ sym_cap_check(Cap *cptr, uint_t cndx, Syscapset *bestcapset, Rt_map *lmp,
ivlmach++;
}
break;
+ case CA_SUNW_HW_3:
+ bestcapset->sc_hw_3 = val;
+ DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_3,
+ name, ndx, M_MACH, bestcapset));
+
+ if (hwcap3_check(scapset, val, NULL) == 0)
+ capfail++;
+ break;
+
default:
break;
}
@@ -1269,12 +1349,18 @@ is_sym_the_best(Syscapset *bestcapset, Syscapset *symcapset)
return (1);
/*
- * Check the hardware capabilities. If the best symbols CA_SUNW_HW_2
+ * Check the hardware capabilities. If the best symbols CA_SUNW_HW_3
* capabilities are greater than the new symbols capabilities, then
- * retain the best capabilities group. If the new symbols CA_SUNW_HW_2
+ * retain the best capabilities group. If the new symbols CA_SUNW_HW_3
* capabilities are greater than the best symbol, then the new symbol
- * needs to be taken.
+ * needs to be taken. Repeat the same process for CA_SUNW_HW_2.
*/
+ if (bestcapset->sc_hw_3 > symcapset->sc_hw_3)
+ return (0);
+
+ if (bestcapset->sc_hw_3 < symcapset->sc_hw_3)
+ return (1);
+
if (bestcapset->sc_hw_2 > symcapset->sc_hw_2)
return (0);
diff --git a/usr/src/cmd/sgs/rtld/common/elf.c b/usr/src/cmd/sgs/rtld/common/elf.c
index d1d5ae3c59..31e57eeedd 100644
--- a/usr/src/cmd/sgs/rtld/common/elf.c
+++ b/usr/src/cmd/sgs/rtld/common/elf.c
@@ -27,6 +27,7 @@
*/
/*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -2312,6 +2313,9 @@ elf_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize,
CAPSET(lmp).sc_mach = STRTAB(lmp) +
cap->c_un.c_ptr;
break;
+ case CA_SUNW_HW_3:
+ CAPSET(lmp).sc_hw_3 = cap->c_un.c_val;
+ break;
}
cap++;
}
diff --git a/usr/src/cmd/sgs/rtld/common/globals.c b/usr/src/cmd/sgs/rtld/common/globals.c
index 45c08f8286..88cdfd409c 100644
--- a/usr/src/cmd/sgs/rtld/common/globals.c
+++ b/usr/src/cmd/sgs/rtld/common/globals.c
@@ -25,6 +25,7 @@
*
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/types.h>
@@ -235,9 +236,10 @@ ldd_reject[SGS_REJ_NUM] = {
MSG_LDD_REJ_PLATCAP, /* MSG_INTL(MSG_LDD_REJ_PLATCAP) */
MSG_LDD_REJ_HWCAP_2, /* MSG_INTL(MSG_LDD_REJ_HWCAP_2) */
MSG_LDD_REJ_ARCHIVE, /* MSG_INTL(MSG_LDD_REJ_ARCHIVE) */
- MSG_LDD_REJ_KMOD /* MSG_INTL(MSG_LDD_REJ_KMOD) */
+ MSG_LDD_REJ_KMOD, /* MSG_INTL(MSG_LDD_REJ_KMOD) */
+ MSG_LDD_REJ_HWCAP_3 /* MSG_INTL(MSG_LDD_REJ_HWCAP_3) */
};
-#if SGS_REJ_NUM != (SGS_REJ_KMOD + 1)
+#if SGS_REJ_NUM != (SGS_REJ_HWCAP_3 + 1)
#error SGS_REJ_NUM has changed
#endif
@@ -263,8 +265,9 @@ err_reject[SGS_REJ_NUM] = {
MSG_ERR_REJ_HWCAP_2, /* MSG_INTL(MSG_ERR_REJ_HWCAP_2) */
MSG_ERR_REJ_ARCHIVE, /* MSG_INTL(MSG_ERR_REJ_ARCHIVE) */
MSG_ERR_REJ_KMOD, /* MSG_INTL(MSG_ERR_REJ_KMOD) */
+ MSG_ERR_REJ_HWCAP_3 /* MSG_INTL(MSG_ERR_REJ_HWCAP_3) */
};
-#if SGS_REJ_NUM != (SGS_REJ_KMOD + 1)
+#if SGS_REJ_NUM != (SGS_REJ_HWCAP_3 + 1)
#error SGS_REJ_NUM has changed
#endif
@@ -290,7 +293,8 @@ ldd_warn[SGS_REJ_NUM] = {
MSG_LDD_WARN_HWCAP_2, /* MSG_INTL(MSG_LDD_WARN_HWCAP_2) */
MSG_STR_EMPTY,
MSG_STR_EMPTY,
+ MSG_LDD_WARN_HWCAP_3 /* MSG_INTL(MSG_LDD_WARN_HWCAP_3) */
};
-#if SGS_REJ_NUM != (SGS_REJ_KMOD + 1)
+#if SGS_REJ_NUM != (SGS_REJ_HWCAP_3 + 1)
#error SGS_REJ_NUM has changed
#endif
diff --git a/usr/src/cmd/sgs/rtld/common/rtld.msg b/usr/src/cmd/sgs/rtld/common/rtld.msg
index 937a58dae7..9d0876ba1b 100644
--- a/usr/src/cmd/sgs/rtld/common/rtld.msg
+++ b/usr/src/cmd/sgs/rtld/common/rtld.msg
@@ -21,7 +21,7 @@
#
# Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright (c) 2014, Joyent, Inc. All rights reserved.
+# Copyright 2022 Oxide Computer Company
#
@ _START_
@@ -199,6 +199,7 @@
@ MSG_LDD_REJ_MACHCAP " - machine capability (CA_SUNW_MACH) unsupported: %s"
@ MSG_LDD_REJ_PLATCAP " - platform capability (CA_SUNW_PLAT) unsupported: %s"
@ MSG_LDD_REJ_HWCAP_2 " - hardware capability (CA_SUNW_HW_2) unsupported: %s"
+@ MSG_LDD_REJ_HWCAP_3 " - hardware capability (CA_SUNW_HW_3) unsupported: %s"
@ MSG_LDD_REJ_ARCHIVE " - invalid archive use"
@ MSG_LDD_REJ_KMOD " - invalid kernel module use"
@@ -213,6 +214,8 @@
unsupported: %s\n"
@ MSG_LDD_WARN_HWCAP_2 "%s: warning: hardware capability (CA_SUNW_HW_2) \
unsupported: %s\n"
+@ MSG_LDD_WARN_HWCAP_3 "%s: warning: hardware capability (CA_SUNW_HW_3) \
+ unsupported: %s\n"
# Error rejection messages.
@@ -235,6 +238,7 @@
@ MSG_ERR_REJ_HWCAP_2 "%s: hardware capability (CA_SUNW_HW_2) unsupported: %s"
@ MSG_ERR_REJ_ARCHIVE "%s: invalid archive use"
@ MSG_ERR_REJ_KMOD "%s: invalid kernel module use"
+@ MSG_ERR_REJ_HWCAP_3 "%s: hardware capability (CA_SUNW_HW_3) unsupported: %s"
# Error TLS failures
diff --git a/usr/src/cmd/sgs/rtld/common/setup.c b/usr/src/cmd/sgs/rtld/common/setup.c
index 8be1fe2486..96835607c1 100644
--- a/usr/src/cmd/sgs/rtld/common/setup.c
+++ b/usr/src/cmd/sgs/rtld/common/setup.c
@@ -29,6 +29,7 @@
*/
/*
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -407,6 +408,7 @@ setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz,
rtld_flags2 |= RT_FL2_HWCAP;
org_scapset->sc_hw_1 = (Xword)hwcap[0];
org_scapset->sc_hw_2 = (Xword)hwcap[1];
+ org_scapset->sc_hw_3 = (Xword)hwcap[2];
}
/*
diff --git a/usr/src/cmd/sgs/rtld/i386/_setup.c b/usr/src/cmd/sgs/rtld/i386/_setup.c
index da208c45cd..aaa1bca08e 100644
--- a/usr/src/cmd/sgs/rtld/i386/_setup.c
+++ b/usr/src/cmd/sgs/rtld/i386/_setup.c
@@ -30,6 +30,7 @@
*/
/*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -64,7 +65,7 @@ _setup(Boot *ebp, Dyn *ld_dyn)
char *_rt_name, **_envp, **_argv;
int _syspagsz = 0, fd = -1;
uint_t _flags = 0;
- uint_t hwcap[2] = { 0, 0 };
+ uint_t hwcap[3] = { 0, 0, 0 };
Dyn *dyn_ptr;
Phdr *phdr = NULL;
Rt_map *lmp;
@@ -159,6 +160,10 @@ _setup(Boot *ebp, Dyn *ld_dyn)
/* hardware capabilities */
hwcap[1] = (uint_t)auxv->a_un.a_val;
break;
+ case AT_SUN_HWCAP3:
+ /* hardware capabilities */
+ hwcap[2] = (uint_t)auxv->a_un.a_val;
+ break;
case AT_SUN_EMULATOR:
/* name of emulation library, if any */
_emulator = auxv->a_un.a_ptr;
diff --git a/usr/src/cmd/sgs/tools/SUNWonld-README b/usr/src/cmd/sgs/tools/SUNWonld-README
index 288d18aafc..13f33502da 100644
--- a/usr/src/cmd/sgs/tools/SUNWonld-README
+++ b/usr/src/cmd/sgs/tools/SUNWonld-README
@@ -1691,3 +1691,4 @@ Bugid Risk Synopsis
14722 ld should keep group members in separate output sections
14770 ld(1) should be 64bit only
14901 remove remaining a.out support from sgs
+14822 Need new word of hardware capabilities
diff --git a/usr/src/common/elfcap/elfcap.c b/usr/src/common/elfcap/elfcap.c
index ef9fb8d6b4..53eeb21104 100644
--- a/usr/src/common/elfcap/elfcap.c
+++ b/usr/src/common/elfcap/elfcap.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2019, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
/* LINTLIBRARY */
@@ -70,7 +71,8 @@
/*
* Define separators for output string processing. This must be kept in
- * sync with the elfcap_fmt_t values in elfcap.h.
+ * sync with the elfcap_fmt_t values in elfcap.h. If something is added here
+ * that is longer than ELFCAP_FMT_PIPSPACE, please update elfcap_chk.c.
*/
static const elfcap_str_t format[] = {
STRDESC(" "), /* ELFCAP_FMT_SNGSPACE */
@@ -488,6 +490,29 @@ static const elfcap_desc_t hw2_386[ELFCAP_NUM_HW2_386] = {
{ /* 0x10000000 */
AV_386_2_VAES, STRDESC("AV_386_2_VAES"),
STRDESC("VAES"), STRDESC("vaes")
+ },
+ { /* 0x20000000 */
+ AV_386_2_GFNI, STRDESC("AV_386_2_GFNI"),
+ STRDESC("GFNI"), STRDESC("gfni")
+ },
+ { /* 0x40000000 */
+ AV_386_2_AVX512_VP2INT, STRDESC("AV_386_2_AVX512_VP2INT"),
+ STRDESC("AVX512_VP2INT"), STRDESC("avx512_vp2int")
+ },
+ { /* 0x80000000 */
+ AV_386_2_AVX512_BITALG, STRDESC("AV_386_2_AVX512_BITALG"),
+ STRDESC("AVX512_BITALG"), STRDESC("avx512_bitalg")
+ }
+};
+
+static const elfcap_desc_t hw3_386[ELFCAP_NUM_HW3_386] = {
+ { /* 0x00000001 */
+ AV_386_3_AVX512_VBMI2, STRDESC("AV_386_3_AVX512_VBMI2"),
+ STRDESC("AVX512_VBMI2"), STRDESC("avx512_vbmi2")
+ },
+ { /* 0x00000002 */
+ AV_386_3_AVX512_BF16, STRDESC("AV_386_3_AVX512_BF16"),
+ STRDESC("AVX512_BF16"), STRDESC("avx512_bf16")
}
};
@@ -624,6 +649,27 @@ elfcap_hw2_to_str(elfcap_style_t style, elfcap_mask_t val, char *str,
}
/*
+ * Expand a CA_SUNW_HW_3 value.
+ */
+elfcap_err_t
+elfcap_hw3_to_str(elfcap_style_t style, elfcap_mask_t val, char *str,
+ size_t len, elfcap_fmt_t fmt, ushort_t mach)
+{
+ /*
+ * Initialize the string buffer, and validate the format request.
+ */
+ *str = '\0';
+ if ((fmt < 0) || (fmt >= FORMAT_NELTS))
+ return (ELFCAP_ERR_INVFMT);
+
+ if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
+ return (expand(style, val, &hw3_386[0], ELFCAP_NUM_HW3_386,
+ str, len, fmt));
+
+ return (expand(style, val, NULL, 0, str, len, fmt));
+}
+
+/*
* Expand a CA_SUNW_SF_1 value. Note, that at present these capabilities are
* common across all platforms. The use of "mach" is therefore redundant, but
* is retained for compatibility with the interface of elfcap_hw1_to_str(), and
@@ -661,6 +707,9 @@ elfcap_tag_to_str(elfcap_style_t style, uint64_t tag, elfcap_mask_t val,
case CA_SUNW_HW_2:
return (elfcap_hw2_to_str(style, val, str, len, fmt, mach));
+ case CA_SUNW_HW_3:
+ return (elfcap_hw3_to_str(style, val, str, len, fmt, mach));
+
}
return (ELFCAP_ERR_UNKTAG);
@@ -725,6 +774,15 @@ elfcap_hw2_from_str(elfcap_style_t style, const char *str, ushort_t mach)
return (0);
}
+elfcap_mask_t
+elfcap_hw3_from_str(elfcap_style_t style, const char *str, ushort_t mach)
+{
+ if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
+ return (value(style, str, &hw3_386[0], ELFCAP_NUM_HW3_386));
+
+ return (0);
+}
+
/*
* Given a capability tag type and value, return the capabilities values
@@ -743,6 +801,9 @@ elfcap_tag_from_str(elfcap_style_t style, uint64_t tag, const char *str,
case CA_SUNW_HW_2:
return (elfcap_hw2_from_str(style, str, mach));
+
+ case CA_SUNW_HW_3:
+ return (elfcap_hw3_from_str(style, str, mach));
}
return (0);
@@ -752,6 +813,12 @@ elfcap_tag_from_str(elfcap_style_t style, uint64_t tag, const char *str,
* These functions allow the caller to get direct access to the
* cap descriptors.
*/
+const elfcap_str_t *
+elfcap_getdesc_formats(void)
+{
+ return (format);
+}
+
const elfcap_desc_t *
elfcap_getdesc_hw1_sparc(void)
{
@@ -769,3 +836,15 @@ elfcap_getdesc_sf1(void)
{
return (sf1);
}
+
+const elfcap_desc_t *
+elfcap_getdesc_hw2_386(void)
+{
+ return (hw2_386);
+}
+
+const elfcap_desc_t *
+elfcap_getdesc_hw3_386(void)
+{
+ return (hw3_386);
+}
diff --git a/usr/src/common/elfcap/elfcap.h b/usr/src/common/elfcap/elfcap.h
index 0d508d02cc..ee18e7bd74 100644
--- a/usr/src/common/elfcap/elfcap.h
+++ b/usr/src/common/elfcap/elfcap.h
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2019, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _ELFCAP_DOT_H
@@ -115,8 +116,19 @@ typedef enum {
#define ELFCAP_NUM_SF1 3
#define ELFCAP_NUM_HW1_SPARC 30
#define ELFCAP_NUM_HW1_386 32
-#define ELFCAP_NUM_HW2_386 29
+#define ELFCAP_NUM_HW2_386 32
+#define ELFCAP_NUM_HW3_386 2
+/*
+ * String buffer lengths that should be sufficient for elfcap values today. This
+ * is used because this is compiled into programs. Do not assume it won't change
+ * or make it part of an ABI. This uses the worst case values as calculated by
+ * the elfcap_chk program that is run in sgs and checked as part of the build.
+ */
+#define ELFCAP_SF1_BUFSIZE 73
+#define ELFCAP_HW1_BUFSIZE 528
+#define ELFCAP_HW2_BUFSIZE 632
+#define ELFCAP_HW3_BUFSIZE 66
/*
* Given a capability section tag and value, call the proper underlying
@@ -134,6 +146,7 @@ typedef elfcap_err_t elfcap_to_str_func_t(elfcap_style_t, elfcap_mask_t, char *,
extern elfcap_to_str_func_t elfcap_hw1_to_str;
extern elfcap_to_str_func_t elfcap_hw2_to_str;
+extern elfcap_to_str_func_t elfcap_hw3_to_str;
extern elfcap_to_str_func_t elfcap_sf1_to_str;
/*
@@ -153,6 +166,7 @@ extern elfcap_mask_t elfcap_tag_from_str(elfcap_style_t, uint64_t,
extern elfcap_from_str_func_t elfcap_hw1_from_str;
extern elfcap_from_str_func_t elfcap_hw2_from_str;
extern elfcap_from_str_func_t elfcap_sf1_from_str;
+extern elfcap_from_str_func_t elfcap_hw3_from_str;
/*
* These functions give access to the individual descriptor arrays.
@@ -161,8 +175,11 @@ extern elfcap_from_str_func_t elfcap_sf1_from_str;
* of making the arrays directly visible to preclude copy relocations in
* non-pic code.
*/
+extern const elfcap_str_t *elfcap_getdesc_formats(void);
extern const elfcap_desc_t *elfcap_getdesc_hw1_sparc(void);
extern const elfcap_desc_t *elfcap_getdesc_hw1_386(void);
+extern const elfcap_desc_t *elfcap_getdesc_hw2_386(void);
+extern const elfcap_desc_t *elfcap_getdesc_hw3_386(void);
extern const elfcap_desc_t *elfcap_getdesc_sf1(void);
#ifdef __cplusplus
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_nvme.c b/usr/src/lib/fm/topo/modules/common/disk/disk_nvme.c
index a50705070e..79a2a6c1e2 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk_nvme.c
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk_nvme.c
@@ -11,6 +11,7 @@
/*
* Copyright 2020 Joyent, Inc.
+ * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -584,9 +585,10 @@ discover_nvme_ctl(di_node_t node, di_minor_t minor, void *arg)
}
nioc.n_len = NVME_IDENTIFY_BUFSIZE;
nioc.n_buf = (uintptr_t)idctl;
+ nioc.n_arg = NVME_IDENTIFY_CTRL;
- if (ioctl(fd, NVME_IOC_IDENTIFY_CTRL, &nioc) != 0) {
- topo_mod_dprintf(mod, "NVME_IOC_IDENTIFY_CTRL ioctl "
+ if (ioctl(fd, NVME_IOC_IDENTIFY, &nioc) != 0) {
+ topo_mod_dprintf(mod, "NVME_IOC_IDENTIFY ioctl "
"failed: %s", strerror(errno));
(void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
goto error;
@@ -594,6 +596,7 @@ discover_nvme_ctl(di_node_t node, di_minor_t minor, void *arg)
nioc.n_len = sizeof (nvme_version_t);
nioc.n_buf = (uintptr_t)&nvme_info.nei_vers;
+ nioc.n_arg = 0;
if (ioctl(fd, NVME_IOC_VERSION, &nioc) != 0) {
topo_mod_dprintf(mod, "NVME_IOC_VERSION ioctl failed: %s",
diff --git a/usr/src/lib/libc/port/gen/getisax.c b/usr/src/lib/libc/port/gen/getisax.c
index c721528fb3..85d60eb192 100644
--- a/usr/src/lib/libc/port/gen/getisax.c
+++ b/usr/src/lib/libc/port/gen/getisax.c
@@ -25,6 +25,7 @@
*/
/*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#pragma weak _getisax = getisax
@@ -48,10 +49,12 @@ getisax(uint32_t *array, uint_t n)
int i;
static uint32_t auxv_hwcap;
static uint32_t auxv_hwcap_2;
+ static uint32_t auxv_hwcap_3;
if (auxv_hwcap == 0) {
auxv_hwcap = (uint32_t)___getauxval(AT_SUN_HWCAP);
auxv_hwcap_2 = (uint32_t)___getauxval(AT_SUN_HWCAP2);
+ auxv_hwcap_3 = (uint32_t)___getauxval(AT_SUN_HWCAP3);
}
if (n > 0) {
@@ -59,9 +62,15 @@ getisax(uint32_t *array, uint_t n)
array[0] = auxv_hwcap;
if (n >= 2)
array[1] = auxv_hwcap_2;
- for (i = 2; i < n; i++)
+ if (n >= 3)
+ array[2] = auxv_hwcap_3;
+ for (i = 3; i < n; i++)
array[i] = 0;
}
- return (auxv_hwcap == 0 ? 0 : n >= 2 ? 2 : 1);
+ if (auxv_hwcap == 0) {
+ return (0);
+ }
+
+ return (n >= 3 ? 3 : n);
}
diff --git a/usr/src/man/man4d/amdzen.4d b/usr/src/man/man4d/amdzen.4d
index 7d17a6a9d4..e8ee713c85 100644
--- a/usr/src/man/man4d/amdzen.4d
+++ b/usr/src/man/man4d/amdzen.4d
@@ -9,9 +9,9 @@
.\" http://www.illumos.org/license/CDDL.
.\"
.\"
-.\" Copyright 2021 Oxide Computer Company
+.\" Copyright 2022 Oxide Computer Company
.\"
-.Dd September 26, 2020
+.Dd August 6, 2022
.Dt AMDZEN 4D
.Os
.Sh NAME
@@ -34,11 +34,17 @@ AMD Zen Naples, Summit Ridge, Whitehaven
AMD Zen+ Colfax, Picasso, and Pinnacle Ridge
.Pq Family 17h
.It
-AMD Zen 2 Castle Peak, Matisse, Rome, and Renoir
+AMD Zen 2 Castle Peak, Matisse, Mendocino, Rome, Renoir, and Van Gogh
.Pq Family 17h
.It
AMD Zen 3 Cezanne, Milan, and Vermeer
.Pq Family 19h
+.It
+AMD Zen 3+ Rembrandt
+.Pq Family 19h
+.It
+AMD Zen 4 Genoa and Raphael
+.Pq Family 19h
.El
.Pp
This driver is a nexus driver and facilitates access to the northbridge,
diff --git a/usr/src/man/man8/nvmeadm.8 b/usr/src/man/man8/nvmeadm.8
index 009b89bcf4..04508b2c22 100644
--- a/usr/src/man/man8/nvmeadm.8
+++ b/usr/src/man/man8/nvmeadm.8
@@ -33,9 +33,20 @@
.Nm
.Op Fl dv
.Cm identify
+.Op Fl C | c | d | Oo Fl a Oc Fl n
.Ar ctl[/ns] Ns [,...]
.Nm
.Op Fl dv
+.Cm identify-controller
+.Op Fl C | c | Oo Fl a Oc Fl n
+.Ar ctl Ns [,...]
+.Nm
+.Op Fl dv
+.Cm identify-namespace
+.Op Fl c | d
+.Ar ctl/ns Ns [,...]
+.Nm
+.Op Fl dv
.Cm get-logpage
.Ar ctl[/ns] Ns [,...]
.Ar logpage
@@ -247,17 +258,87 @@ The name of the disk device that corresponds to the namespace, if any.
.El
.It Xo
.Nm
-.Cm identify
-.Ar ctl[/ns] Ns [,...]
+.Cm identify-controller
+.Op Fl C | c | Oo Fl a Oc Fl n
+.Ar ctl Ns [,...]
.Xc
-Print detailed information about the specified controllers and/or
-namespaces.
-The information returned differs depending on whether a controller or
-a namespace is specified.
-For an explanation of the data printed by this command refer to the
-description of the
+Print detailed information about the specified controllers.
+For an explanation of the data printed by this command refer to the description
+of the
+.Qq IDENTIFY
+admin command in the NVMe specification.
+.Pp
+By default, a relevant subset of the
+.Qq IDENTIFY CONTROLLER
+data structure is printed.
+The full data structure is only printed when verbose output is requested.
+.Pp
+The following options can be used to print other
+.Qq IDENTIFY
+information:
+.Bl -tag -width Fl
+.It Fl C
+Print the Common Namespace Identification of the controller.
+.It Fl a
+Alter the output of the
+.Fl n
+option to print the list allocated namespace identifiers.
+Can only be specified together with the
+.Fl n
+option.
+.It Fl c
+Print the list of all unique controller identifiers in the NVMe subsystem the
+specified controller belongs to.
+.It Fl n
+Print the list of active namespace identifiers of the controller.
+.El
+.It Xo
+.Nm
+.Cm identify-namespace
+.Op Fl c | d
+.Ar ctl/ns Ns [,...]
+.Xc
+Print detailed information about the specified namespace.
+For an explanation of the data printed by this command refer to the description
+of the
.Qq IDENTIFY
admin command in the NVMe specification.
+.Pp
+By default, a relevant subset of the
+.Qq IDENTIFY NAMESPACE
+data structure is printed.
+The full data structure is only printed when verbose output is requested.
+.Pp
+The following options can be used to print other
+.Qq IDENTIFY
+information:
+.Bl -tag -width Fl
+.It Fl c
+Print the list of all unique controller identifiers in the NVMe subsystem the
+specified namespace belongs to and which are currently attached to this
+namespace.
+.It Fl d
+Print the list of namespace identification descriptors of the namespace.
+.El
+.It Xo
+.Nm
+.Cm identify
+.Op Fl C | c | d | Oo Fl a Oc Fl n
+.Ar ctl[/ns] Ns [,...]
+.Xc
+Short-hand for the
+.Cm identify-controller
+and
+.Cm identify-namespace
+commands, prints the same information about the specified controllers and/or
+namespaces, depending on whether a controller or a namespace was specified.
+.Pp
+For a description of the various optional flags refer to the above description
+of the
+.Cm identify-controller
+and
+.Cm identify-namespace
+commands.
.It Xo
.Nm
.Cm get-logpage
diff --git a/usr/src/pkg/manifests/driver-cpu-amd-zen.p5m b/usr/src/pkg/manifests/driver-cpu-amd-zen.p5m
index 1fcd24c4bf..9bfbbf04ba 100644
--- a/usr/src/pkg/manifests/driver-cpu-amd-zen.p5m
+++ b/usr/src/pkg/manifests/driver-cpu-amd-zen.p5m
@@ -38,11 +38,18 @@ driver name=amdzen
# 1460-1467: f17h m00-0f df
# 1480: f17h m30-3f/70-7f, f19h m00-0f, m20-2f nb
# 1490-1497: f17h m30-3f df
+# 14a4: f19h m10-1f nb
+# 14ad-14b4: f19h m10-1fh df
+# 14b5: f17h ma0-af, f19h m40-4f nb
+# 14d8: f19h m60-6f nb
+# 14e0-14e7: f19h m60-6f df
# 15d0: f17h m10-m2f nb
# 15e8-15ef: f17h m10-m2f df
# 1630: f17h m60-6f, f19h m50-5f nb
# 1650-1657: f19h m00-0f df
# 166a-1671: f19h m50-5f df
+# 1679-1680: f19h m40-4f df
+# 1724-172b: f17h ma0-af df
#
driver name=amdzen_stub \
alias=pci1022,1440,p \
@@ -79,6 +86,25 @@ driver name=amdzen_stub \
alias=pci1022,1495,p \
alias=pci1022,1496,p \
alias=pci1022,1497,p \
+ alias=pci1022,14a4,p \
+ alias=pci1022,14ad,p \
+ alias=pci1022,14ae,p \
+ alias=pci1022,14af,p \
+ alias=pci1022,14b0,p \
+ alias=pci1022,14b1,p \
+ alias=pci1022,14b2,p \
+ alias=pci1022,14b3,p \
+ alias=pci1022,14b4,p \
+ alias=pci1022,14b5,p \
+ alias=pci1022,14d8,p \
+ alias=pci1022,14e0,p \
+ alias=pci1022,14e1,p \
+ alias=pci1022,14e2,p \
+ alias=pci1022,14e3,p \
+ alias=pci1022,14e4,p \
+ alias=pci1022,14e5,p \
+ alias=pci1022,14e6,p \
+ alias=pci1022,14e7,p \
alias=pci1022,15d0,p \
alias=pci1022,15e8,p \
alias=pci1022,15e9,p \
@@ -104,6 +130,22 @@ driver name=amdzen_stub \
alias=pci1022,166e,p \
alias=pci1022,166f,p \
alias=pci1022,1670,p \
- alias=pci1022,1671,p
+ alias=pci1022,1671,p \
+ alias=pci1022,1679,p \
+ alias=pci1022,167a,p \
+ alias=pci1022,167b,p \
+ alias=pci1022,167c,p \
+ alias=pci1022,167d,p \
+ alias=pci1022,167e,p \
+ alias=pci1022,167f,p \
+ alias=pci1022,1680,p \
+ alias=pci1022,1724,p \
+ alias=pci1022,1725,p \
+ alias=pci1022,1726,p \
+ alias=pci1022,1727,p \
+ alias=pci1022,1728,p \
+ alias=pci1022,1729,p \
+ alias=pci1022,172a,p \
+ alias=pci1022,172b,p
driver name=zen_umc
license lic_CDDL license=lic_CDDL
diff --git a/usr/src/pkg/manifests/system-test-elftest.p5m b/usr/src/pkg/manifests/system-test-elftest.p5m
index 108876ce67..a57ba44404 100644
--- a/usr/src/pkg/manifests/system-test-elftest.p5m
+++ b/usr/src/pkg/manifests/system-test-elftest.p5m
@@ -27,6 +27,9 @@ dir path=opt/elf-tests/tests
dir path=opt/elf-tests/tests/assert-deflib
file path=opt/elf-tests/tests/assert-deflib/link.c mode=0444
file path=opt/elf-tests/tests/assert-deflib/test-deflib mode=0555
+dir path=opt/elf-tests/tests/capabilities
+file path=opt/elf-tests/tests/capabilities/objcap mode=0555
+file path=opt/elf-tests/tests/capabilities/symcap mode=0555
dir path=opt/elf-tests/tests/groups
dir path=opt/elf-tests/tests/groups/no-relobj-group-merge
file path=opt/elf-tests/tests/groups/no-relobj-group-merge/README.md mode=0444
diff --git a/usr/src/pkg/manifests/system-test-smbsrvtest.p5m b/usr/src/pkg/manifests/system-test-smbsrvtest.p5m
new file mode 100644
index 0000000000..cfcf885aeb
--- /dev/null
+++ b/usr/src/pkg/manifests/system-test-smbsrvtest.p5m
@@ -0,0 +1,33 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+
+set name=pkg.fmri value=pkg:/system/test/smbsrvtest@$(PKGVERS)
+set name=pkg.summary value="SMB Server Functional Tests"
+set name=pkg.description value="SMB Server Test Suite"
+set name=info.classification \
+ value=org.opensolaris.category.2008:Development/System
+set name=variant.arch value=$(ARCH)
+dir path=opt/smbsrv-tests
+file path=opt/smbsrv-tests/README mode=0444
+dir path=opt/smbsrv-tests/bin
+file path=opt/smbsrv-tests/bin/run_smbtorture mode=0555
+file path=opt/smbsrv-tests/bin/smbsrvtests mode=0555
+dir path=opt/smbsrv-tests/include
+file path=opt/smbsrv-tests/include/default.cfg mode=0444
+file path=opt/smbsrv-tests/include/smbtor-excl-smb2.txt mode=0444
+dir path=opt/smbsrv-tests/tests
+dir path=opt/smbsrv-tests/tests/smbtorture
+file path=opt/smbsrv-tests/tests/smbtorture/runst-smb2 mode=0555
+license lic_CDDL license=lic_CDDL
+depend type=optional fmri=service/network/samba
+depend type=require fmri=runtime/python$(PYTHON3_PKGVERS)
diff --git a/usr/src/test/Makefile b/usr/src/test/Makefile
index a2d6343f76..412288d483 100644
--- a/usr/src/test/Makefile
+++ b/usr/src/test/Makefile
@@ -13,7 +13,7 @@
# Copyright (c) 2012 by Delphix. All rights reserved.
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
# Copyright 2019 Joyent, Inc.
-# Copyright 2020 Tintri by DDN, Inc. All rights reserved.
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
# Copyright 2022 Oxide Computer Company
#
@@ -29,6 +29,7 @@ SUBDIRS = \
os-tests \
smartos-test \
smbclient-tests \
+ smbsrv-tests \
test-runner \
util-tests \
zfs-tests
diff --git a/usr/src/test/elf-tests/runfiles/default.run b/usr/src/test/elf-tests/runfiles/default.run
index 0005b8976b..0978c05c89 100644
--- a/usr/src/test/elf-tests/runfiles/default.run
+++ b/usr/src/test/elf-tests/runfiles/default.run
@@ -22,6 +22,9 @@ outputdir = /var/tmp/test_results
[/opt/elf-tests/tests/assert-deflib]
tests = ['test-deflib']
+[/opt/elf-tests/tests/capabilities]
+tests = ['objcap', 'symcap']
+
[/opt/elf-tests/tests/groups/no-relobj-group-merge]
tests = ['no-relobj-group-merge']
diff --git a/usr/src/test/elf-tests/tests/Makefile b/usr/src/test/elf-tests/tests/Makefile
index 74f358d77a..7e14f57497 100644
--- a/usr/src/test/elf-tests/tests/Makefile
+++ b/usr/src/test/elf-tests/tests/Makefile
@@ -16,6 +16,7 @@
SUBDIRS = \
assert-deflib \
+ capabilities \
groups \
linker-sets \
mapfiles \
diff --git a/usr/src/test/elf-tests/tests/capabilities/Makefile b/usr/src/test/elf-tests/tests/capabilities/Makefile
new file mode 100644
index 0000000000..8b344c0793
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/capabilities/Makefile
@@ -0,0 +1,41 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+# Copyright 2022 Oxide Computer Company
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROGS = symcap objcap
+
+ROOTOPTPKG = $(ROOT)/opt/elf-tests
+TESTDIR = $(ROOTOPTPKG)/tests/capabilities
+
+CMDS = $(PROGS:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+all:
+
+install: all $(CMDS)
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(CLEANFILES)
+
+$(CMDS): $(TESTDIR)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %.ksh
+ $(INS.rename)
diff --git a/usr/src/test/elf-tests/tests/capabilities/objcap.ksh b/usr/src/test/elf-tests/tests/capabilities/objcap.ksh
new file mode 100644
index 0000000000..806f85ea52
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/capabilities/objcap.ksh
@@ -0,0 +1,351 @@
+#!/usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# souroc. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/liocnse/CDDL.
+#
+
+#
+# Copyright 2022 Oxide Computer Company
+#
+
+#
+# This test focuses around the generation of files with object capabilities and
+# verifies that tools like elfedit, elfdump, ld, and ld.so.1 can deal with them
+# all appropriately.
+#
+
+export LC_ALL=C.UTF-8
+unalias -a
+set -o pipefail
+
+oc_arg0=$(basename $0)
+oc_tmpdir=/tmp/objcap.$$
+oc_prog_nocap="$oc_tmpdir/prog.nocap"
+oc_prog_hw1="$oc_tmpdir/prog.hw1"
+oc_prog_hw3="$oc_tmpdir/prog.hw3"
+oc_prog_hw123="$oc_tmpdir/prog.hw123"
+oc_cap_hw1="0x42"
+oc_cap_hw2="0x169"
+oc_cap_hw3="0x7777"
+oc_err=0
+
+pass()
+{
+ typeset msg="$*"
+ echo "TEST PASSED: $msg"
+}
+
+warn()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "TEST FAILED: $msg" >&2
+ oc_err=1
+}
+
+fatal()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "$oc_arg0: $msg" >&2
+ exit 1
+}
+
+cleanup()
+{
+ rm -rf "$oc_tmpdir"
+}
+
+#
+# Set up our test environment. This generally requires us to create the
+# source file, mapfiles, and related contents that the test requires.
+#
+setup()
+{
+ typeset cfile="$oc_tmpdir/test.c"
+ typeset mapfile_hw1="$oc_tmpdir/test.mapfile.hw1"
+ typeset mapfile_hw3="$oc_tmpdir/test.mapfile.hw3"
+ typeset mapfile_hw123="$oc_tmpdir/test.mapfile.hw123"
+
+ if ! mkdir "$oc_tmpdir"; then
+ fatal "failed to make directory $oc_tmpdir"
+ fi
+
+ trap 'cleanup' EXIT
+
+ cat > $cfile <<EOF
+int
+main(void)
+{
+ return (0);
+}
+EOF
+ if (( $? != 0 )); then
+ fatal "failed to write token C file to $cfile"
+ fi
+
+ cat > $mapfile_hw1 <<EOF
+\$mapfile_version 2
+CAPABILITY {
+ HW_1 += $oc_cap_hw1;
+};
+EOF
+
+ if (( $? != 0 )); then
+ fatal "failed to write out $mapfile_hw1"
+ fi
+
+ cat > $mapfile_hw3 <<EOF
+\$mapfile_version 2
+CAPABILITY {
+ HW_3 += $oc_cap_hw3;
+};
+EOF
+
+ if (( $? != 0 )); then
+ fatal "failed to write out $mapfile_hw3"
+ fi
+
+ cat > $mapfile_hw123 <<EOF
+\$mapfile_version 2
+CAPABILITY {
+ HW_1 += $oc_cap_hw1;
+ HW_2 += $oc_cap_hw2;
+ HW_3 += $oc_cap_hw3;
+};
+EOF
+
+ if (( $? != 0 )); then
+ fatal "failed to write out $mapfile_hw3"
+ fi
+
+ if ! gcc -m64 -o $oc_prog_nocap $cfile; then
+ fatal "failed to create $oc_prog_nocap"
+ fi
+
+ if ! gcc -m64 -o $oc_prog_hw1 $cfile -Wl,-M$mapfile_hw1; then
+ fatal "failed to create $oc_prog_hw1"
+ fi
+
+ if ! gcc -m64 -o $oc_prog_hw3 $cfile -Wl,-M$mapfile_hw3; then
+ fatal "failed to create $oc_prog_hw1"
+ fi
+
+ if ! gcc -m64 -o $oc_prog_hw123 $cfile -Wl,-M$mapfile_hw123; then
+ fatal "failed to create $oc_prog_hw1"
+ fi
+}
+
+verify_caps()
+{
+ typeset file="$1"
+ typeset data="$2"
+ typeset -a vals=($3 $4 $5)
+ typeset -a caps=("CA_SUNW_HW_1" "CA_SUNW_HW_2" "CA_SUNW_HW_3")
+ typeset -a ee=("cap:hw1" "cap:hw2" "cap:hw3")
+ typeset out=
+ typeset ee_out=
+ typeset i=
+
+ out=$(elfdump -H $file 2>&1)
+ if (( $? != 0 )); then
+ warn "elfdump -H $file failed with $?"
+ return
+ fi
+
+ #
+ # If we don't expect a object capability, then we're done here.
+ #
+ if (( data == 0 )); then
+ if [[ -n "$out" ]]; then
+ fail "elfdump -H $file had unexpected output: $out"
+ else
+ pass "elfdump -H $file contained no output"
+ fi
+ return
+ fi
+
+ if [[ -z "$out" ]]; then
+ fail "elfdump -H $file had no output, but expected caps"
+ return
+ fi
+
+ #
+ # At this point, for each hw cap, if there is a value, check that we
+ # have an elfdump output line and then verify that we have the expected
+ # value via elfedit.
+ #
+ for ((i = 0; i < 3; i++)); do
+ if [[ "${vals[$i]}" == "0" ]]; then
+ continue;
+ fi
+
+ if ! echo $out | grep -q ${caps[$i]}; then
+ warn "elfdump -H $file missing ${caps[$i]}"
+ else
+ pass "elfdump -H $file has ${caps[$i]}"
+ fi
+
+ ee_out=$(elfedit -e "${ee[$i]} -o num" $file)
+ if [[ -z $ee_out ]]; then
+ warn "failed to dump ${ee[$i]} from $file via elfedit"
+ continue
+ fi
+
+ if [[ "$ee_out" != "${vals[$i]}" ]]; then
+ warn "mismatched value for ${ee[$i]} in $file: found " \
+ "$out, expected ${vals[$i]}"
+ else
+ pass "elfedit has correct value for ${ee[$i]} in $file"
+ fi
+ done
+}
+
+#
+# Attempt to execute a program with symbol capabilities. We override the
+# symbol capabilities in the system for the specified file to the ones
+# indicated in the function. We need to restrict to the program we're
+# calling so that way we don't accidentally tell ld not to load a system
+# library.
+#
+run_prog()
+{
+ typeset prog="$1"
+ typeset run=$2
+ typeset cap="$3"
+ typeset case="$4"
+ typeset ret=
+
+ LD_CAP_FILES=$prog LD_HWCAP=$3 $prog 2>/dev/null 1>/dev/null
+ ret=$?
+ if (( run != 0 && ret == 0 )); then
+ pass "exec prog $case"
+ elif (( run != 0 && ret != 0 )); then
+ warn "exec prog $case returned $ret, expected 0"
+ elif (( run == 0 && ret == 0 )); then
+ warn "exec prog $case returned $ret, expected non-zero"
+ else
+ pass "exec prog $case"
+ fi
+}
+
+#
+# Use elfedit to modify a specific hwcap and make sure we see the new value.
+#
+edit_prog()
+{
+ typeset input="$1"
+ typeset pass="$2"
+ typeset cap="$3"
+ typeset cmd="$4"
+ typeset exp="$5"
+ typeset ret=
+
+ rm -f "$input.edit"
+ elfedit -e "$cap $cmd" "$input" "$input.edit" >/dev/null 2>/dev/null
+ ret=$?
+
+ if (( pass == 0 )); then
+ if (( ret == 0 )); then
+ warn "elfedit -e $cap $cmd $input worked, expected failure"
+ else
+ pass "elfedit -e $cap $cmd $input failed correctly"
+ fi
+ return
+ fi
+
+ if (( ret != 0 )); then
+ warn "elfedit -e $cap $cmd $input failed with $ret, expected success"
+ return
+ fi
+
+ ret=$(elfedit -e "$cap -o num" "$input.edit")
+ if (( $? != 0 )); then
+ warn "failed to extract hwcap after elfedit -e $cap $cmd $input"
+ fi
+
+ if [[ "$ret" != "$exp" ]]; then
+ warn "elfedit -e $cap $cmd $input had wrong output " \
+ "expected $exp, found $val"
+ else
+ pass "elfedit -e $cap $cmd $input"
+ fi
+}
+
+setup
+verify_caps "$oc_prog_nocap" 0
+verify_caps "$oc_prog_hw1" 1 $oc_cap_hw1 0 0
+verify_caps "$oc_prog_hw3" 1 0 0 $oc_cap_hw3
+verify_caps "$oc_prog_hw123" 1 $oc_cap_hw1 $oc_cap_hw2 $oc_cap_hw3
+
+#
+# Now that we've verified the caps in these files, try to run them in a
+# given alternate symbol cap env.
+#
+run_prog "$oc_prog_nocap" 1 "[1]0,[2]0,[3]0" "no need, no caps"
+run_prog "$oc_prog_hw1" 0 "[1]0,[2]0,[3]0" "need hw1, no caps"
+run_prog "$oc_prog_hw3" 0 "[1]0,[2]0,[3]0" "need hw3, no caps"
+run_prog "$oc_prog_hw123" 0 "[1]0,[2]0,[3]0" "need hw{123}, no caps"
+
+run_prog "$oc_prog_nocap" 1 "[1]0x42,[2]0,[3]0" "no need, hw1=0x42"
+run_prog "$oc_prog_hw1" 1 "[1]0x42,[2]0,[3]0" "need hw1, hw1=0x42"
+run_prog "$oc_prog_hw3" 0 "[1]0x42,[2]0,[3]0" "need hw3, hw1=0x42"
+run_prog "$oc_prog_hw123" 0 "[1]0x42,[2]0,[3]0" "need hw{123}, hw1=0x42"
+
+run_prog "$oc_prog_nocap" 1 "[1]0,[2]0,[3]0x7777" "no need, hw3=0x7777"
+run_prog "$oc_prog_hw1" 0 "[1]0,[2]0,[3]0x7777" "need hw1, hw3=0x7777"
+run_prog "$oc_prog_hw3" 1 "[1]0,[2]0,[3]0x7777" "need hw3, hw3=0x7777"
+run_prog "$oc_prog_hw123" 0 "[1]0,[2]0,[3]0x7777" "need hw{123}, hw3=0x7777"
+
+run_prog "$oc_prog_nocap" 1 "[1]0,[2]0x1369,[3]0" "no need, hw2=0x1369"
+run_prog "$oc_prog_hw1" 0 "[1]0,[2]0x1369,[3]0" "need hw1, hw2=0x1369"
+run_prog "$oc_prog_hw3" 0 "[1]0,[2]0x1369,[3]0" "need hw3, hw2=0x1369"
+run_prog "$oc_prog_hw123" 0 "[1]0,[2]0x1369,[3]0" "need hw{123}, hw2=0x1369"
+
+run_prog "$oc_prog_nocap" 1 "[1]0x42,[2]0,[3]0x7777" \
+ "no need, hw1=0x42,hw3=0x7777"
+run_prog "$oc_prog_hw1" 1 "[1]0x42,[2]0,[3]0x7777" \
+ "need hw1, hw1=0x42,hw3=0x7777"
+run_prog "$oc_prog_hw3" 1 "[1]0x42,[2]0,[3]0x7777" \
+ "need hw3, hw1=0x42,hw3=0x7777"
+run_prog "$oc_prog_hw123" 0 "[1]0x42,[2]0,[3]0x7777" \
+ "need hw{123}, hw1=0x42,hw3=0x7777"
+
+run_prog "$oc_prog_nocap" 1 "[1]0x42,[2]0x1369,[3]0x7777" \
+ "no need, hw1=0x42,hw2=0x1369,hw3=0x7777"
+run_prog "$oc_prog_hw1" 1 "[1]0x42,[2]0x1369,[3]0x7777" \
+ "need hw1, hw1=0x42,hw2=0x1369,hw3=0x7777"
+run_prog "$oc_prog_hw3" 1 "[1]0x42,[2]0x1369,[3]0x7777" \
+ "need hw3, hw1=0x42,hw2=0x1369,hw3=0x7777"
+run_prog "$oc_prog_hw123" 1 "[1]0x42,[2]0x1369,[3]0x7777" \
+ "need hw{123}, hw1=0x42,hw2=0x1369,hw3=0x7777"
+
+edit_prog "$oc_prog_hw1" 1 "cap:hw1" "-or 0x1000" "0x1042"
+edit_prog "$oc_prog_hw1" 1 "cap:hw1" "-and 0x1000" "0"
+edit_prog "$oc_prog_hw1" 1 "cap:hw1" "-cmp 0x42" "0xffffffbd"
+edit_prog "$oc_prog_hw3" 1 "cap:hw3" "-and 0x643f" "0x6437"
+edit_prog "$oc_prog_hw123" 1 "cap:hw2" "0x12345" "0x12345"
+
+#
+# Failure cases here are meant to cover missing capaibilities and bad strings.
+#
+edit_prog "$oc_prog_hw1" 0 "cap:hw1" "-or zelda"
+edit_prog "$oc_prog_hw1" 0 "cap:hw2" "-or 0x100"
+edit_prog "$oc_prog_nocap" 0 "cap:hw1" "-or 0x1"
+edit_prog "$oc_prog_hw3" 0 "cap:hw1" "-and 0xff"
+edit_prog "$oc_prog_hw3" 0 "cap:hw2" "-and 0xff"
+edit_prog "$oc_prog_hw3" 0 "cap:hw3" "-and link"
+edit_prog "$oc_prog_hw123" 0 "cap:hw2" "ganondorf"
+
+if (( oc_err == 0 )); then
+ printf "All tests passed successfully\n"
+fi
+
+exit $oc_err
diff --git a/usr/src/test/elf-tests/tests/capabilities/symcap.ksh b/usr/src/test/elf-tests/tests/capabilities/symcap.ksh
new file mode 100644
index 0000000000..7f58191938
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/capabilities/symcap.ksh
@@ -0,0 +1,269 @@
+#!/usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# souroc. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/liocnse/CDDL.
+#
+
+#
+# Copyright 2022 Oxide Computer Company
+#
+
+#
+# This test generates a binary with a lot of different symbol capabilities and
+# then selects different capability environments to try and ensure that the
+# rules for what we pick are honored.
+#
+
+export LC_ALL=C.UTF-8
+unalias -a
+set -o pipefail
+
+sc_arg0=$(basename $0)
+sc_err=0
+sc_tmpdir=/tmp/symcap.$$
+sc_prog="$sc_tmpdir/symcap"
+
+#
+# To build symbol caps, we need to annotate a .o file with object caps and then
+# turn that into a symbol cap with ld. The following arrays are used to create
+# this for us. sc_obj_hw1, sc_obj_hw2, and sc_obj_hw3 are the set of object
+# capabilities that we want to use and then eventually turn into symbol
+# capabilities. Each symbol capability prints out its own index when executed.
+# This means we can see which thing ld resolved to run based on the output.
+# The following summarizes our goals with each case:
+#
+# 0: none
+# 1: only hwcap 1
+# 2: only hwcap 1, but greater than (1)
+# 3: only hwcap 2
+# 4: only hwcap 2, but greater than (3)
+# 5: only hwcap 3
+# 6: only hwcap 3, but greater than (5)
+# 7: uses all 3
+# 8: differs from (7) in hwcap1
+#
+sc_obj_hw1=( "0x0" "0x5" "0x42" "0x0" "0x0" "0x0" "0x0"
+ "0x3" "0x8" )
+sc_obj_hw2=( "0x0" "0x0" "0x0" "0x23" "0xff00" "0x0" "0x0"
+ "0xff7ff6" "0xff7ff6" )
+sc_obj_hw3=( "0x0" "0x0" "0x0" "0x0" "0x0" "0x12345" "0x7000000"
+ "0x87654321" "0x87654321" )
+
+pass()
+{
+ typeset msg="$*"
+ echo "TEST PASSED: $msg"
+}
+
+warn()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "TEST FAILED: $msg" >&2
+ sc_err=1
+}
+
+fatal()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "$sc_arg0: $msg" >&2
+ exit 1
+}
+
+cleanup()
+{
+ rm -rf "$sc_tmpdir"
+}
+
+sanity_check()
+{
+ if (( ${#sc_obj_hw1[@]} != ${#sc_obj_hw2[@]} )); then
+ fatal "sc_obj_hw1 does not match length of sc_obj_hw2"
+ fi
+
+ if (( ${#sc_obj_hw2[@]} != ${#sc_obj_hw3[@]} )); then
+ fatal "sc_obj_hw1 does not match length of sc_obj_hw2"
+ fi
+}
+
+setup()
+{
+ typeset tolink=
+
+ if ! mkdir "$sc_tmpdir"; then
+ fatal "failed to make directory $sc_tmpdir"
+ fi
+
+ trap 'cleanup' EXIT
+
+ cat > $sc_tmpdir/main.c <<EOF
+extern void symcap_print(void);
+
+int
+main(void)
+{
+ symcap_print();
+ return (0);
+}
+EOF
+ if (( $? != 0 )); then
+ fatal "failed to write main.c"
+ fi
+
+ tolink="$sc_tmpdir/main.c"
+
+ for (( i = 0; i < ${#sc_obj_hw1[@]}; i++)); do
+ typeset in="$sc_tmpdir/$i.c"
+ typeset map="$sc_tmpdir/$i.map"
+ typeset ofile="$sc_tmpdir/$i.o"
+ typeset obj="$sc_tmpdir/$i.o.obj"
+ typeset sym="$sc_tmpdir/$i.o.sym"
+
+ cat > $in <<EOF
+#include <stdio.h>
+
+void
+symcap_print(void)
+{
+ printf("%u\n", $i);
+}
+EOF
+ if (( $? != 0 )); then
+ fatal "failed to write $in"
+ fi
+
+ cat > $map <<EOF
+\$mapfile_version 2
+CAPABILITY {
+ HW_1 += ${sc_obj_hw1[$i]};
+ HW_2 += ${sc_obj_hw2[$i]};
+ HW_3 += ${sc_obj_hw3[$i]};
+};
+EOF
+ if (( $? != 0 )); then
+ fatal "failed to write $map"
+ fi
+
+ #
+ # There are three steps to creating a symbol capability due to
+ # the world we're in. First we need to make the normal .o. Then
+ # we use a mapfile to add the object caps, while reducing
+ # visibility. Then we turn the object cap into a symbol cap.
+ #
+ if ! gcc -m64 -o $ofile -c $in; then
+ fatal "failed to create object file $ofile"
+ fi
+
+ #
+ # If the entry has a zero for all cases (e.g. our default case),
+ # then skip the rest of this processing and append the .o.
+ #
+ if (( sc_obj_hw1[i] == 0 && sc_obj_hw2[i] == 0 &&
+ sc_obj_hw3[i] == 0 )); then
+ tolink="$tolink $ofile"
+ continue
+ fi
+
+ if ! ld -r -o $obj $ofile -M$map -Breduce; then
+ fatal "failed to create object cap file $obj"
+ fi
+
+ if ! ld -r -o $sym -z symbolcap $obj; then
+ fatal "failed to create symbol cap file $sym"
+ fi
+
+ tolink="$tolink $sym"
+ done
+
+ if ! gcc -m64 -o $sc_prog $tolink; then
+ fatal "failed to create $sc_prog"
+ fi
+}
+
+#
+# Given a set of caps, indicate which index we expect to be printed out and
+# check for that.
+#
+run_one()
+{
+ typeset index="$1"
+ typeset caps="$2"
+ typeset out=
+
+ out=$(LD_CAP_FILES=$sc_prog LD_HWCAP="$caps" $sc_prog)
+ if (( $? != 0 )); then
+ warn "failed to execute $sc_prog with cap $caps"
+ return
+ fi
+
+ if [[ "$out" != "$index" ]]; then
+ warn "$caps had wrong output, found $out, expected $index"
+ else
+ pass "LD_HWCAP=$caps"
+ fi
+}
+
+sanity_check
+setup
+
+#
+# First, go through and verify that if we match the caps exactly for this, we'll
+# choose this symbol.
+#
+run_one 0 "[1]0x0,[2]0x0,[3]0x0"
+run_one 1 "[1]0x5,[2]0x0,[3]0x0"
+run_one 2 "[1]0x42,[2]0x0,[3]0x0"
+run_one 3 "[1]0x0,[2]0x23,[3]0x0"
+run_one 4 "[1]0x0,[2]0xff00,[3]0x0"
+run_one 5 "[1]0x0,[2]0x0,[3]0x12345"
+run_one 6 "[1]0x0,[2]0x0,[3]0x7000000"
+run_one 7 "[1]0x3,[2]0xff7ff6,[3]0x87654321"
+run_one 8 "[1]0x8,[2]0xff7ff6,[3]0x87654321"
+
+#
+# For cases where we have multiple symbol caps at a given level, show that we
+# pick a sub one when we're between the two.
+#
+run_one 0 "[1]0x40,[2]0x0,[3]0x0"
+run_one 1 "[1]0x45,[2]0x0,[3]0x0"
+run_one 1 "[1]0x45,[2]0x10,[3]0x0"
+run_one 2 "[1]0x142,[2]0x10,[3]0x0"
+run_one 3 "[1]0x1,[2]0x137,[3]0x0"
+
+#
+# We expect the system to pick the "best" aka highest capability. So for the
+# next round we attempt to combine multiple values and see which we pick. In
+# particular here we're trying to pick between things at the same level and also
+# ensure we pick the one that is higher (e.g. hw3 > hw2 > hw1)
+#
+run_one 6 "[1]0x47,[2]0xff23,[3]0x7012345"
+run_one 5 "[1]0x47,[2]0xff23,[3]0x6012345"
+run_one 5 "[1]0x47,[2]0xff23,[3]0x1012345"
+run_one 4 "[1]0x47,[2]0xff23,[3]0x1002345"
+run_one 3 "[1]0x47,[2]0x7723,[3]0x1002345"
+run_one 3 "[1]0x47,[2]0x0f23,[3]0x1002345"
+run_one 3 "[1]0x47,[2]0x0023,[3]0x1002345"
+run_one 2 "[1]0x47,[2]0x0003,[3]0x1002345"
+run_one 2 "[1]0x46,[2]0x0003,[3]0x1002345"
+run_one 1 "[1]0x35,[2]0x0003,[3]0x1002345"
+run_one 1 "[1]0x15,[2]0x0003,[3]0x1002345"
+run_one 0 "[1]0x10,[2]0x0003,[3]0x1002345"
+
+#
+# Finally we want a few tests that verify that when things match, the lowest bit
+# of it decides.
+#
+run_one 8 "[1]0xb,[2]0xff7ff6,[3]0x87654321"
+run_one 8 "[1]0x3b,[2]0xff7ff6,[3]0x87654321"
+run_one 8 "[1]0xffffffff,[2]0xffffffff,[3]0xffffffff"
+run_one 7 "[1]0xfffffff7,[2]0xffffffff,[3]0xffffffff"
+
+exit $sc_err
diff --git a/usr/src/test/smbsrv-tests/Makefile b/usr/src/test/smbsrv-tests/Makefile
new file mode 100644
index 0000000000..c148fa93e8
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/Makefile
@@ -0,0 +1,20 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+#
+
+.PARALLEL: $(SUBDIRS)
+
+SUBDIRS:sh = find ./* -maxdepth 0 -type d
+
+include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/smbsrv-tests/Makefile.com b/usr/src/test/smbsrv-tests/Makefile.com
new file mode 100644
index 0000000000..988bbae0b6
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/Makefile.com
@@ -0,0 +1,69 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2016, 2017 by Delphix. All rights reserved.
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+# The following file name generation rules allow the addition of tests,
+# libraries and other miscellaneous files without having to specify them
+# all individually in lower level Makefiles.
+PROGS:sh = find . -maxdepth 1 -type f \( \
+ -name "*.ksh" -o \
+ -name "*.py" -o \
+ -name "*.sh" \)
+FILES:sh = find . -maxdepth 1 -type f \( \
+ -name "*.Z" -o \
+ -name "*.bz2" -o \
+ -name "*.cfg" -o \
+ -name "*.d" -o \
+ -name "*.err" -o \
+ -name "*.fio" -o \
+ -name "*.out" -o \
+ -name "*.run" -o \
+ -name "*shlib" -o \
+ -name "*.txt" -o \
+ -name "*.zcp" \)
+
+CMDS = $(PROGS:%.sh=$(TARGETDIR)/%)
+CMDS += $(PROGS:%.ksh=$(TARGETDIR)/%)
+CMDS += $(PROGS:%.py=$(TARGETDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+LIBS = $(FILES:%=$(TARGETDIR)/%)
+$(LIBS) := FILEMODE = 0444
+
+all clean clobber:
+
+install: $(CMDS) $(LIBS)
+
+$(CMDS): $(TARGETDIR)
+
+$(LIBS): $(TARGETDIR)
+
+$(TARGETDIR):
+ $(INS.dir)
+
+$(TARGETDIR)/%: %.sh
+ $(INS.rename)
+
+$(TARGETDIR)/%: %.ksh
+ $(INS.rename)
+
+$(TARGETDIR)/%: %.py
+ $(INS.pyfile)
+
+$(TARGETDIR)/%: %
+ $(INS.file)
+
+.PARALLEL: $(SUBDIRS)
+SUBDIRS:sh = find ./* -maxdepth 0 -type d ; exit 0
diff --git a/usr/src/test/smbsrv-tests/cmd/Makefile b/usr/src/test/smbsrv-tests/cmd/Makefile
new file mode 100644
index 0000000000..d28988e431
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/cmd/Makefile
@@ -0,0 +1,26 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+include $(SRC)/Makefile.master
+
+# The python code in here required python3 or later.
+PYSHEBANG = $(PYTHON3)
+PYVER = $(PYTHON3_VERSION)
+PYSUFFIX = $(PYTHON3_SUFFIX)
+
+ROOTOPTPKG = $(ROOT)/opt/smbsrv-tests
+TARGETDIR = $(ROOTOPTPKG)/bin
+
+include $(SRC)/test/smbsrv-tests/Makefile.com
diff --git a/usr/src/test/smbsrv-tests/cmd/run_smbtorture.py b/usr/src/test/smbsrv-tests/cmd/run_smbtorture.py
new file mode 100644
index 0000000000..fd008f7b19
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/cmd/run_smbtorture.py
@@ -0,0 +1,244 @@
+#!@PYTHON@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+#
+# Run tests provided by smbtorture.
+#
+
+import subprocess
+import argparse
+import re
+import fnmatch
+
+from enum import Enum
+from datetime import datetime
+from tempfile import TemporaryFile
+
+def stripped_file(f):
+ """Strips trailing whitespace from lines in f"""
+
+ for line in f:
+ yield line.strip()
+
+def parse_tests(f):
+ """Returns test names from f, skipping commented lines"""
+
+ yield from (line for line in f
+ if line and not line.startswith('#'))
+
+def matched_suites(m):
+ """Gets all smbtorture tests that match pattern m"""
+
+ with TemporaryFile('w+') as tmp:
+ subprocess.run(['smbtorture', '--list'], stdout=tmp,
+ universal_newlines=True)
+ tmp.seek(0)
+ yield from (line for line in stripped_file(tmp)
+ if not line.startswith('smbtorture') and
+ m.match(line))
+
+class TestResult(Enum):
+ PASS = 0
+ FAIL = 1
+ UNKNOWN = 2
+ SKIP = 3
+ KILLED = 4
+
+ def __str__(self):
+ return self.name
+
+ def __len__(self):
+ return len(self.name)
+
+class TestCase:
+ """A particular instance of an smbtorture test"""
+
+ __slots__ = 'name', 'result'
+
+ def __init__(self, name, skip=False):
+ self.name = name
+ self.result = TestResult.SKIP if skip else TestResult.UNKNOWN
+
+ def __str__(self):
+ return '{0.name} | {0.result}'.format(self)
+
+ def run(self, rfd, wfd, timeout, cmd):
+ """Run cmd, setting the last element to the test name, and setting result
+ based on rfd. Output is sent to wfd, and the test is killed based on timeout."""
+
+ def finish(self, start, wfd):
+ timediff = datetime.now() - start
+ wfd.write('END | {} | {}\n'.format(self, timediff))
+ return self.result
+
+ starttime = datetime.now()
+ wfd.write('START | {} | {}\n'.format(self.name, starttime.time()))
+ if self.result == TestResult.SKIP:
+ return finish(self, starttime, wfd)
+
+ cmd[-1] = self.name
+ try:
+ subprocess.run(cmd, universal_newlines=True, stdout=wfd,
+ stderr=subprocess.STDOUT, timeout=timeout)
+ for line in stripped_file(rfd):
+ if self.result != TestResult.UNKNOWN:
+ continue
+ elif line.startswith('failure:') or line.startswith('error:'):
+ self.result = TestResult.FAIL
+ elif line.startswith('success:'):
+ self.result = TestResult.PASS
+ elif line.startswith('skip:'):
+ self.result = TestResult.SKIP
+ except subprocess.TimeoutExpired:
+ self.result = TestResult.KILLED
+ wfd.write('\nKilled due to timeout\n')
+ rfd.read()
+
+ return finish(self, starttime, wfd)
+
+def should_skip(test, pattern, verbose):
+ """Returns whether test matches pattern, indicating it should be skipped."""
+
+ if not pattern or not pattern.match(test):
+ return False
+
+ if verbose:
+ print('{} matches exception pattern; marking as skipped'.format(test))
+ return True
+
+def fnm2regex(fnm_pat):
+ """Maps an fnmatch(7) pattern to a regex pattern that will match against
+ any suite that encapsulates the test name"""
+
+ rpat = fnmatch.translate(fnm_pat)
+ return r'{}|{}'.format(rpat, rpat.replace(r'\Z', r'\.'))
+
+def combine_patterns(iterable, verbose):
+ """Combines patterns in an iterable into a single REGEX"""
+
+ pat = re.compile('|'.join(map(fnm2regex, iterable)),
+ flags=re.DEBUG if verbose > 1 else 0)
+ if verbose > 1:
+ print('final pattern: {}'.format(pat.pattern))
+ return pat
+
+class ArgumentFile(argparse.FileType):
+ """argparse.FileType, but wrapped in stripped_file()"""
+
+ def __call__(self, *args, **kwargs):
+ return stripped_file(argparse.FileType.__call__(self, *args, **kwargs))
+
+
+def main():
+ parser = argparse.ArgumentParser(description=
+ 'Run a set of smbtorture tests, parsing the results.')
+
+ parser.add_argument('server', help='The target server')
+ parser.add_argument('share', help='The target share')
+ parser.add_argument('user', help='Username for smbtorture')
+ parser.add_argument('password', help='Password for user')
+
+ parser.add_argument('--except', '-e',
+ type=ArgumentFile('r'), metavar='EXCEPTIONS_FILE', dest='skip_list',
+ help='A file containing fnmatch(5) patterns of tests to skip')
+ parser.add_argument('--list', '-l',
+ type=ArgumentFile('r'), metavar='LIST_FILE',
+ help='A file containing the list of tests to run')
+ parser.add_argument('--match', '-m',
+ action='append', metavar='FNMATCH',
+ help='An fnmatch(5) pattern to select tests from smbtorture --list')
+ parser.add_argument('--output', '-o',
+ default='/tmp/lastrun.log', metavar='LOG_FILE',
+ help='Location to store full smbtorture output')
+ parser.add_argument('--seed', '-s',
+ type=int,
+ help='Seed passed to smbtorture')
+ parser.add_argument('--timeout', '-t',
+ default=120, type=float,
+ help='Timeout after which test is killed')
+ parser.add_argument('--verbose', '-v',
+ action='count', default=0,
+ help='Verbose output')
+
+ args = parser.parse_args()
+
+ if (args.match == None) == (args.list == None):
+ print('Must provide one of -l and -m')
+ return
+
+ server = args.server
+ share = args.share
+ user = args.user
+ pswd = args.password
+ fout = args.output
+
+ if args.match != None:
+ if args.verbose > 1:
+ print('Patterns to match:')
+ print(*args.match)
+
+ testgen = matched_suites(combine_patterns(args.match, args.verbose))
+ else:
+ testgen = args.list
+
+ if args.skip_list != None:
+ skip_pat = combine_patterns(parse_tests(args.skip_list), args.verbose)
+ if args.verbose > 1:
+ print('Exceptions pattern (in REGEX): {}'.format(skip_pat.pattern))
+ else:
+ skip_pat = None
+
+ tests = [TestCase(line, should_skip(line, skip_pat, args.verbose))
+ for line in parse_tests(testgen)]
+
+ if args.verbose:
+ print('Tests to run:')
+ for test in tests:
+ if test.result != TestResult.SKIP:
+ print(test.name)
+
+ outw = open(fout, 'w', buffering=1)
+ outr = open(fout, 'r')
+
+ cmd = 'smbtorture //{srv}/{shr} -U{usr}%{pswd}'.format(
+ srv=server, shr=share, usr=user, pswd=pswd).split()
+ if args.seed != None:
+ cmd.append('--seed={}'.format(args.seed))
+ cmd.append('TEST_HERE')
+
+ if args.verbose:
+ print('Command to run:')
+ print(*cmd)
+
+ results = {res: 0 for res in TestResult}
+ for test in tests:
+ print(test.name, end=': ', flush=True)
+ res = test.run(outr, outw, args.timeout, cmd)
+ results[res] += 1
+ print(res, flush=True)
+
+ print('\n\nRESULTS:')
+ print('=' * 22)
+ for res in TestResult:
+ print('{}: {:>{}}'.format(res, results[res], 20 - len(res)))
+ print('=' * 22)
+ print('Total: {:>15}'.format(len(tests)))
+
+if __name__ == '__main__':
+ try:
+ main()
+ except KeyboardInterrupt:
+ print('Terminated by KeyboardInterrupt.')
diff --git a/usr/src/test/smbsrv-tests/cmd/smbsrvtests.ksh b/usr/src/test/smbsrv-tests/cmd/smbsrvtests.ksh
new file mode 100644
index 0000000000..934f4e26ed
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/cmd/smbsrvtests.ksh
@@ -0,0 +1,55 @@
+#!/usr/bin/ksh
+
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+# Run all the smbsrv-tests
+
+export PATH="/usr/bin"
+export SMBSRV_TESTS="/opt/smbsrv-tests"
+
+export CFGFILE=$SMBSRV_TESTS/include/default.cfg
+export OUTDIR=/var/tmp/test_results/smbsrv-tests
+
+function fail
+{
+ echo $1
+ exit ${2:-1}
+}
+
+while getopts b:c:o:t: c; do
+ case $c in
+ 'b')
+ export BASEFILE=$OPTARG
+ [[ -f $BASEFILE ]] || fail "Cannot read file: $BASEFILE"
+ ;;
+ 'c')
+ CFGFILE=$OPTARG
+ [[ -f $CFGFILE ]] || fail "Cannot read file: $CFGFILE"
+ ;;
+ 'o')
+ OUTDIR=$OPTARG
+ ;;
+ 't')
+ export TIMEOUT=$OPTARG
+ ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+set -x
+
+# Just one test for now. More to come.
+$SMBSRV_TESTS/tests/smbtorture/runst-smb2
diff --git a/usr/src/test/smbsrv-tests/doc/Makefile b/usr/src/test/smbsrv-tests/doc/Makefile
new file mode 100644
index 0000000000..d3ceeef7f2
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/doc/Makefile
@@ -0,0 +1,36 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+include $(SRC)/Makefile.master
+
+READMES = README
+
+ROOTOPTPKG = $(ROOT)/opt/smbsrv-tests
+
+FILES = $(READMES:%=$(ROOTOPTPKG)/%)
+$(FILES) := FILEMODE = 0444
+
+all: $(READMES)
+
+install: $(ROOTOPTPKG) $(FILES)
+
+clean clobber:
+
+$(ROOTOPTPKG):
+ $(INS.dir)
+
+$(ROOTOPTPKG)/%: %
+ $(INS.file)
diff --git a/usr/src/test/smbsrv-tests/doc/README b/usr/src/test/smbsrv-tests/doc/README
new file mode 100644
index 0000000000..e83affbb9b
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/doc/README
@@ -0,0 +1,84 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+SMB Server Test Suite README
+
+1. Building and installing the SMB Server Test Suite
+2. Running the SMB Server Test Suite
+3. Test Results
+
+--------------------------------------------------------------------------------
+
+1. Building and installing the SMB Server Test Suite
+
+The SMB Server test suite uses external programs including:
+ smbtorture (and more to come)
+which is installed via a package dependency on:
+ service/network/samba
+Those are run by python and ksh wrappers found here.
+
+To build, just do:
+ cd $SRC/test/smbsrv-tests
+ make install
+
+To install the full suite, run:
+ pkg install pkg:/system/test/smbsrvtest
+
+--------------------------------------------------------------------------------
+
+2. Running the SMB Server Test Suite
+
+The default configuration:
+ /opt/smbsrv-tests/include/default.cfg
+runs tests against a server instance on "localhost",
+using a share named "test" and user=test, pw=test
+
+It's common to copy that default.cfg to something new
+and modify the SMBT_... variables to specify different
+host, share, user, etc.
+
+To run all tests using the default configuration run:
+ /opt/smbsrv-tests/bin/smbsrvtests
+
+To run all tests using a different configuration:
+ /opt/smbsrv-tests/bin/smbsrvtests -c config_file
+
+You can also run individual tests found under:
+ /opt/smbsrv-tests/tests/*
+For example:
+ /opt/smbsrv-tests/tests/smbtorture/runst-smb2
+
+These take similar options (eg. -c config_file).
+
+To run only a subset of the tests, you can pass match patterns
+as additional arguments to the individual test, eg
+ /opt/smbsrv-tests/tests/smbtorture/runst-smb2 smb2.lease
+
+--------------------------------------------------------------------------------
+
+3. Test Results
+
+While the SMB Server Test Suite is running, one informational line is
+printed for each test, ending with one of:
+ PASS, FAIL, SKIP, KILLED, UNKNOWN
+
+The test outputs can be found in:
+ /var/tmp/test_results/smbsrv-tests/
+For example:
+ smbtor-smb2-20210317T162827.summary
+ smbtor-smb2-20210317T162827.log
+
+The *.summary file is the same as what's shown while the test runs.
+The *.log file is the detailed output from the test program(s).
diff --git a/usr/src/test/smbsrv-tests/include/Makefile b/usr/src/test/smbsrv-tests/include/Makefile
new file mode 100644
index 0000000000..039d796e84
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/include/Makefile
@@ -0,0 +1,21 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/smbsrv-tests
+TARGETDIR = $(ROOTOPTPKG)/include
+
+include $(SRC)/test/smbsrv-tests/Makefile.com
diff --git a/usr/src/test/smbsrv-tests/include/default.cfg b/usr/src/test/smbsrv-tests/include/default.cfg
new file mode 100644
index 0000000000..1ce658ed2d
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/include/default.cfg
@@ -0,0 +1,23 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+# Sample configuration. Either edit this,
+# provide your own with: smbsrvtest -c ...
+
+export SMBT_HOST="localhost"
+export SMBT_SHARE="test"
+export SMBT_USER="test"
+export SMBT_PASS="test"
+export SMBTOR="/usr/bin/smbtorture"
diff --git a/usr/src/test/smbsrv-tests/include/smbtor-excl-smb2.txt b/usr/src/test/smbsrv-tests/include/smbtor-excl-smb2.txt
new file mode 100644
index 0000000000..05b69d1c9b
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/include/smbtor-excl-smb2.txt
@@ -0,0 +1,33 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+# Copyright 2022 RackTop Systems, Inc.
+#
+
+#
+# smbtorture tests we choose to skip, either because the
+# tests hang, or we disagree with the test, or whatever.
+#
+
+smb2.aio_delay
+smb2.bench-oplock
+smb2.change_notify_disabled
+smb2.check-sharemode
+smb2.hold-sharemode
+smb2.hold-oplock
+smb2.maxfid
+smb2.multichannel
+smb2.notify.invalid-reauth
+smb2.replay
+smb2.scan
+smb2.session.reauth*
+smb2.timestamps
diff --git a/usr/src/test/smbsrv-tests/tests/Makefile b/usr/src/test/smbsrv-tests/tests/Makefile
new file mode 100644
index 0000000000..0d4ee56fbb
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/tests/Makefile
@@ -0,0 +1,17 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+include $(SRC)/test/smbsrv-tests/Makefile.com
+include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/smbsrv-tests/tests/smbtorture/Makefile b/usr/src/test/smbsrv-tests/tests/smbtorture/Makefile
new file mode 100644
index 0000000000..53169748ef
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/tests/smbtorture/Makefile
@@ -0,0 +1,22 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/smbsrv-tests
+TARGETDIR = $(ROOTOPTPKG)/tests/smbtorture
+
+include $(SRC)/test/smbsrv-tests/Makefile.com
+include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/smbsrv-tests/tests/smbtorture/runst-smb2.ksh b/usr/src/test/smbsrv-tests/tests/smbtorture/runst-smb2.ksh
new file mode 100644
index 0000000000..6f8e51ffd1
--- /dev/null
+++ b/usr/src/test/smbsrv-tests/tests/smbtorture/runst-smb2.ksh
@@ -0,0 +1,83 @@
+#!/usr/bin/ksh
+
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+export SMBSRV_TESTS="/opt/smbsrv-tests"
+export SMBTOR="/usr/bin/smbtorture"
+
+runsmbtor=$SMBSRV_TESTS/bin/run_smbtorture
+excl_file=$SMBSRV_TESTS/include/smbtor-excl-smb2.txt
+
+cfgfile=${CFGFILE:-$SMBSRV_TESTS/include/default.cfg}
+outdir=${OUTDIR:-/var/tmp/test_results/smbsrv-tests}
+
+function fail
+{
+ echo $1
+ exit ${2:-1}
+}
+
+while getopts c:o:t: c; do
+ case $c in
+ 'c')
+ cfgfile=$OPTARG
+ [[ -f $cfgfile ]] || fail "Cannot read file: $cfgfile"
+ ;;
+ 'o')
+ outdir=$OPTARG
+ ;;
+ 't')
+ timeout="-t $OPTARG"
+ ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+. $cfgfile
+
+export PATH="$(dirname $SMBTOR):$PATH"
+
+mkdir -p $outdir
+cd $outdir
+
+tstamp=$(date +'%Y%m%dT%H%M%S')
+logfile=$outdir/smbtor-smb2-${tstamp}.log
+outfile=$outdir/smbtor-smb2-${tstamp}.summary
+
+if [[ -z "$timeout" && -n "$TIMEOUT" ]]; then
+ timeout="-t $TIMEOUT"
+fi
+
+# Non-option args taken as list of match patterns
+if [ -z "$1" ] ; then
+ match="-m smb2"
+fi
+for m
+do
+ match="$match -m $m"
+done
+
+# Make sure we can connect, otherwise we'll report every test as failing.
+$SMBTOR -U "$SMBT_USER%${SMBT_PASS}" //$SMBT_HOST/$SMBT_SHARE smb2.dir.find \
+ > /dev/null 2>&1 || \
+ fail "Cannot connect to //$SMBT_HOST/$SMBT_SHARE"
+
+echo "Running smbtorture/smb2 tests with //$SMBT_HOST/$SMBT_SHARE"
+$runsmbtor $match -e $excl_file -o $logfile $timeout \
+ "$SMBT_HOST" "$SMBT_SHARE" "$SMBT_USER" "${SMBT_PASS}" |
+ tee $outfile
+
+exit 0
diff --git a/usr/src/tools/quick/make-smbsrv b/usr/src/tools/quick/make-smbsrv
index b04ab47721..c2436ed021 100755
--- a/usr/src/tools/quick/make-smbsrv
+++ b/usr/src/tools/quick/make-smbsrv
@@ -152,6 +152,7 @@ do_kern() {
*) targ=$1 ;;
esac
( unset SOURCEDEBUG ;
+ export NO_GENUNIX_UNIQUIFY= ;
(cd $SRC/uts/$x/smbsrv && $make $targ) )
}
@@ -217,6 +218,7 @@ do_libs() {
for lib in \
libfakekernel \
libads \
+ libidmap \
libsmbfs \
libmlrpc
do
@@ -271,6 +273,16 @@ done
}
################################################################
+
+do_tests() {
+
+ for d in test/test-runner test/libmlrpc-tests test/smbsrv-tests
+ do
+ [ -f $SRC/$d/Makefile ] && (cd $SRC/$d && $make $1)
+ done
+}
+
+################################################################
# This builds $SRC/TAGS (and cscope.files) in a helpful order.
do_tags() {
@@ -346,6 +358,7 @@ do
do_kern $arg
do_libs $arg
do_cmds $arg
+ do_tests $arg
;;
lint)
do_hdrs $arg
@@ -354,17 +367,19 @@ do
do_cmds $arg
;;
clean)
- # intentionally skip: lib1, hdrs, tools
+ # intentionally skip: deplib, hdrs, tools
+ do_tests $arg
do_cmds $arg
do_libs $arg
do_kern $arg
;;
clobber)
+ do_tests $arg
do_cmds $arg
do_libs $arg
+ do_deplibs $arg
do_kern $arg
do_hdrs $arg
- do_deplibs $arg
clobber_tools
;;
deplibs)
diff --git a/usr/src/uts/common/exec/elf/elf.c b/usr/src/uts/common/exec/elf/elf.c
index de0616fe57..984c1b454a 100644
--- a/usr/src/uts/common/exec/elf/elf.c
+++ b/usr/src/uts/common/exec/elf/elf.c
@@ -27,7 +27,7 @@
/* All Rights Reserved */
/*
* Copyright 2019 Joyent, Inc.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/types.h>
@@ -550,11 +550,12 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* AT_SUN_AUXFLAGS
* AT_SUN_HWCAP
* AT_SUN_HWCAP2
- * AT_SUN_PLATFORM (added in stk_copyout)
- * AT_SUN_EXECNAME (added in stk_copyout)
+ * AT_SUN_HWCAP3
+ * AT_SUN_PLATFORM (added in stk_copyout)
+ * AT_SUN_EXECNAME (added in stk_copyout)
* AT_NULL
*
- * total == 10
+ * total == 11
*/
if (hasintp && hasu) {
/*
@@ -569,7 +570,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
*
* total = 5
*/
- args->auxsize = (10 + 5) * sizeof (aux_entry_t);
+ args->auxsize = (11 + 5) * sizeof (aux_entry_t);
} else if (hasintp) {
/*
* Has PT_INTERP but no PT_PHDR
@@ -579,9 +580,9 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
*
* total = 2
*/
- args->auxsize = (10 + 2) * sizeof (aux_entry_t);
+ args->auxsize = (11 + 2) * sizeof (aux_entry_t);
} else {
- args->auxsize = 10 * sizeof (aux_entry_t);
+ args->auxsize = 11 * sizeof (aux_entry_t);
}
} else {
args->auxsize = 0;
@@ -629,10 +630,10 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
if ((*brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
branded = 1;
/*
- * We will be adding 5 entries to the aux vectors. One for
- * the the brandname and 4 for the brand specific aux vectors.
+ * We will be adding 6 entries to the aux vectors. One for
+ * the the brandname and 5 for the brand specific aux vectors.
*/
- args->auxsize += 5 * sizeof (aux_entry_t);
+ args->auxsize += 6 * sizeof (aux_entry_t);
}
/* If the binary has an explicit ASLR flag, it must be honoured */
@@ -1025,18 +1026,16 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* Used for choosing faster library routines.
* (Potentially different between 32-bit and 64-bit ABIs)
*/
-#if defined(_LP64)
if (args->to_model == DATAMODEL_NATIVE) {
ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
+ ADDAUX(aux, AT_SUN_HWCAP3, auxv_hwcap_3)
} else {
ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap32)
ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap32_2)
+ ADDAUX(aux, AT_SUN_HWCAP3, auxv_hwcap32_3)
}
-#else
- ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
- ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
-#endif
+
if (branded) {
/*
* Reserve space for the brand-private aux vectors,
diff --git a/usr/src/uts/common/io/cpuid_drv.c b/usr/src/uts/common/io/cpuid_drv.c
index ef3a21793f..5711258f9e 100644
--- a/usr/src/uts/common/io/cpuid_drv.c
+++ b/usr/src/uts/common/io/cpuid_drv.c
@@ -169,14 +169,17 @@ cpuid_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval)
if (strcmp(areq, architecture) == 0) {
STRUCT_FSET(h, cgh_hwcap[0], auxv_hwcap);
STRUCT_FSET(h, cgh_hwcap[1], auxv_hwcap_2);
+ STRUCT_FSET(h, cgh_hwcap[2], auxv_hwcap_3);
#if defined(_SYSCALL32_IMPL)
} else if (strcmp(areq, architecture_32) == 0) {
STRUCT_FSET(h, cgh_hwcap[0], auxv_hwcap32);
STRUCT_FSET(h, cgh_hwcap[1], auxv_hwcap32_2);
+ STRUCT_FSET(h, cgh_hwcap[2], auxv_hwcap32_3);
#endif
} else {
STRUCT_FSET(h, cgh_hwcap[0], 0);
STRUCT_FSET(h, cgh_hwcap[1], 0);
+ STRUCT_FSET(h, cgh_hwcap[2], 0);
}
if (ddi_copyout(STRUCT_BUF(h),
(void *)arg, STRUCT_SIZE(h), mode))
diff --git a/usr/src/uts/common/io/nvme/nvme.c b/usr/src/uts/common/io/nvme/nvme.c
index 9710dd5728..d76fa48d1b 100644
--- a/usr/src/uts/common/io/nvme/nvme.c
+++ b/usr/src/uts/common/io/nvme/nvme.c
@@ -353,7 +353,7 @@
* Assertions to make sure that we've properly captured various aspects of the
* packed structures and haven't broken them during updates.
*/
-CTASSERT(sizeof (nvme_identify_ctrl_t) == 0x1000);
+CTASSERT(sizeof (nvme_identify_ctrl_t) == NVME_IDENTIFY_BUFSIZE);
CTASSERT(offsetof(nvme_identify_ctrl_t, id_oacs) == 256);
CTASSERT(offsetof(nvme_identify_ctrl_t, id_sqes) == 512);
CTASSERT(offsetof(nvme_identify_ctrl_t, id_oncs) == 520);
@@ -362,17 +362,22 @@ CTASSERT(offsetof(nvme_identify_ctrl_t, id_nvmof) == 1792);
CTASSERT(offsetof(nvme_identify_ctrl_t, id_psd) == 2048);
CTASSERT(offsetof(nvme_identify_ctrl_t, id_vs) == 3072);
-CTASSERT(sizeof (nvme_identify_nsid_t) == 0x1000);
+CTASSERT(sizeof (nvme_identify_nsid_t) == NVME_IDENTIFY_BUFSIZE);
CTASSERT(offsetof(nvme_identify_nsid_t, id_fpi) == 32);
CTASSERT(offsetof(nvme_identify_nsid_t, id_anagrpid) == 92);
CTASSERT(offsetof(nvme_identify_nsid_t, id_nguid) == 104);
CTASSERT(offsetof(nvme_identify_nsid_t, id_lbaf) == 128);
CTASSERT(offsetof(nvme_identify_nsid_t, id_vs) == 384);
-CTASSERT(sizeof (nvme_identify_primary_caps_t) == 0x1000);
+CTASSERT(sizeof (nvme_identify_nsid_list_t) == NVME_IDENTIFY_BUFSIZE);
+CTASSERT(sizeof (nvme_identify_ctrl_list_t) == NVME_IDENTIFY_BUFSIZE);
+
+CTASSERT(sizeof (nvme_identify_primary_caps_t) == NVME_IDENTIFY_BUFSIZE);
CTASSERT(offsetof(nvme_identify_primary_caps_t, nipc_vqfrt) == 32);
CTASSERT(offsetof(nvme_identify_primary_caps_t, nipc_vifrt) == 64);
+CTASSERT(sizeof (nvme_nschange_list_t) == 4096);
+
/* NVMe spec version supported */
static const int nvme_version_major = 1;
@@ -436,7 +441,7 @@ static int nvme_format_nvm(nvme_t *, boolean_t, uint32_t, uint8_t, boolean_t,
uint8_t, boolean_t, uint8_t);
static int nvme_get_logpage(nvme_t *, boolean_t, void **, size_t *, uint8_t,
...);
-static int nvme_identify(nvme_t *, boolean_t, uint32_t, void **);
+static int nvme_identify(nvme_t *, boolean_t, uint32_t, uint8_t, void **);
static int nvme_set_features(nvme_t *, boolean_t, uint32_t, uint8_t, uint32_t,
uint32_t *);
static int nvme_get_features(nvme_t *, boolean_t, uint32_t, uint8_t, uint32_t *,
@@ -2266,7 +2271,8 @@ fail:
}
static int
-nvme_identify(nvme_t *nvme, boolean_t user, uint32_t nsid, void **buf)
+nvme_identify(nvme_t *nvme, boolean_t user, uint32_t nsid, uint8_t cns,
+ void **buf)
{
nvme_cmd_t *cmd = nvme_alloc_cmd(nvme, KM_SLEEP);
int ret;
@@ -2278,7 +2284,7 @@ nvme_identify(nvme_t *nvme, boolean_t user, uint32_t nsid, void **buf)
cmd->nc_callback = nvme_wakeup_cmd;
cmd->nc_sqe.sqe_opc = NVME_OPC_IDENTIFY;
cmd->nc_sqe.sqe_nsid = nsid;
- cmd->nc_sqe.sqe_cdw10 = nsid ? NVME_IDENTIFY_NSID : NVME_IDENTIFY_CTRL;
+ cmd->nc_sqe.sqe_cdw10 = cns;
if (nvme_zalloc_dma(nvme, NVME_IDENTIFY_BUFSIZE, DDI_DMA_READ,
&nvme->n_prp_dma_attr, &cmd->nc_dma) != DDI_SUCCESS) {
@@ -2974,7 +2980,8 @@ nvme_init_ns(nvme_t *nvme, int nsid)
ASSERT(MUTEX_HELD(&nvme->n_mgmt_mutex));
- if (nvme_identify(nvme, B_FALSE, nsid, (void **)&idns) != 0) {
+ if (nvme_identify(nvme, B_FALSE, nsid, NVME_IDENTIFY_NSID,
+ (void **)&idns) != 0) {
dev_err(nvme->n_dip, CE_WARN,
"!failed to identify namespace %d", nsid);
return (DDI_FAILURE);
@@ -3332,7 +3339,8 @@ nvme_init(nvme_t *nvme)
/*
* Identify Controller
*/
- if (nvme_identify(nvme, B_FALSE, 0, (void **)&nvme->n_idctl) != 0) {
+ if (nvme_identify(nvme, B_FALSE, 0, NVME_IDENTIFY_CTRL,
+ (void **)&nvme->n_idctl) != 0) {
dev_err(nvme->n_dip, CE_WARN,
"!failed to identify controller");
goto fail;
@@ -4799,7 +4807,94 @@ nvme_ioctl_identify(nvme_t *nvme, int nsid, nvme_ioctl_t *nioc, int mode,
if (nioc->n_len < NVME_IDENTIFY_BUFSIZE)
return (EINVAL);
- if ((rv = nvme_identify(nvme, B_TRUE, nsid, (void **)&idctl)) != 0)
+ switch (nioc->n_arg) {
+ case NVME_IDENTIFY_NSID:
+ /*
+ * If we support namespace management, set the nsid to -1 to
+ * retrieve the common namespace capabilities. Otherwise
+ * have a best guess by returning identify data for namespace 1.
+ */
+ if (nsid == 0)
+ nsid = nvme->n_idctl->id_oacs.oa_nsmgmt == 1 ? -1 : 1;
+ break;
+
+ case NVME_IDENTIFY_CTRL:
+ /*
+ * Let NVME_IDENTIFY_CTRL work the same on devctl and attachment
+ * point nodes.
+ */
+ nsid = 0;
+ break;
+
+ case NVME_IDENTIFY_NSID_LIST:
+ if (!NVME_VERSION_ATLEAST(&nvme->n_version, 1, 1))
+ return (ENOTSUP);
+
+ /*
+ * For now, always try to get the list of active NSIDs starting
+ * at the first namespace. This will have to be revisited should
+ * the need arise to support more than 1024 namespaces.
+ */
+ nsid = 0;
+ break;
+
+ case NVME_IDENTIFY_NSID_DESC:
+ if (!NVME_VERSION_ATLEAST(&nvme->n_version, 1, 3))
+ return (ENOTSUP);
+ break;
+
+ case NVME_IDENTIFY_NSID_ALLOC:
+ if (!NVME_VERSION_ATLEAST(&nvme->n_version, 1, 2) ||
+ (nvme->n_idctl->id_oacs.oa_nsmgmt == 0))
+ return (ENOTSUP);
+
+ /*
+ * To make this work on a devctl node, make this return the
+ * identify data for namespace 1. We assume that any NVMe
+ * device supports at least one namespace, which has ID 1.
+ */
+ if (nsid == 0)
+ nsid = 1;
+ break;
+
+ case NVME_IDENTIFY_NSID_ALLOC_LIST:
+ if (!NVME_VERSION_ATLEAST(&nvme->n_version, 1, 2) ||
+ (nvme->n_idctl->id_oacs.oa_nsmgmt == 0))
+ return (ENOTSUP);
+
+ /*
+ * For now, always try to get the list of allocated NSIDs
+ * starting at the first namespace. This will have to be
+ * revisited should the need arise to support more than 1024
+ * namespaces.
+ */
+ nsid = 0;
+ break;
+
+ case NVME_IDENTIFY_NSID_CTRL_LIST:
+ if (!NVME_VERSION_ATLEAST(&nvme->n_version, 1, 2) ||
+ (nvme->n_idctl->id_oacs.oa_nsmgmt == 0))
+ return (ENOTSUP);
+
+ if (nsid == 0)
+ return (EINVAL);
+ break;
+
+ case NVME_IDENTIFY_CTRL_LIST:
+ if (!NVME_VERSION_ATLEAST(&nvme->n_version, 1, 2) ||
+ (nvme->n_idctl->id_oacs.oa_nsmgmt == 0))
+ return (ENOTSUP);
+
+ if (nsid != 0)
+ return (EINVAL);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ if ((rv = nvme_identify(nvme, B_TRUE, nsid, nioc->n_arg & 0xff,
+ (void **)&idctl)) != 0)
return (rv);
if (ddi_copyout(idctl, (void *)nioc->n_buf, NVME_IDENTIFY_BUFSIZE, mode)
@@ -5728,7 +5823,7 @@ nvme_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
int (*nvme_ioctl[])(nvme_t *, int, nvme_ioctl_t *, int, cred_t *) = {
NULL,
nvme_ioctl_identify,
- nvme_ioctl_identify,
+ NULL,
nvme_ioctl_capabilities,
nvme_ioctl_get_logpage,
nvme_ioctl_get_features,
@@ -5777,21 +5872,6 @@ nvme_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
if (nvme->n_dead && cmd != NVME_IOC_DETACH)
return (EIO);
-
- if (cmd == NVME_IOC_IDENTIFY_CTRL) {
- /*
- * This makes NVME_IOC_IDENTIFY_CTRL work the same on devctl and
- * attachment point nodes.
- */
- nsid = 0;
- } else if (cmd == NVME_IOC_IDENTIFY_NSID && nsid == 0) {
- /*
- * This makes NVME_IOC_IDENTIFY_NSID work on a devctl node, it
- * will always return identify data for namespace 1.
- */
- nsid = 1;
- }
-
if (IS_NVME_IOC(cmd) && nvme_ioctl[NVME_IOC_CMD(cmd)] != NULL)
rv = nvme_ioctl[NVME_IOC_CMD(cmd)](nvme, nsid, &nioc, mode,
cred_p);
diff --git a/usr/src/uts/common/io/nvme/nvme_reg.h b/usr/src/uts/common/io/nvme/nvme_reg.h
index 9c981cf33a..8fb3252aa6 100644
--- a/usr/src/uts/common/io/nvme/nvme_reg.h
+++ b/usr/src/uts/common/io/nvme/nvme_reg.h
@@ -10,9 +10,8 @@
*/
/*
- * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright 2020 Joyent, Inc.
- * Copyright 2019 Western Digital Corporation
+ * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
* Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -396,21 +395,6 @@ typedef union {
} nvme_create_sq_dw11_t;
/*
- * NVMe Identify
- */
-
-/* NVMe Identify parameters (cdw10) */
-#define NVME_IDENTIFY_NSID 0x0 /* Identify Namespace */
-#define NVME_IDENTIFY_CTRL 0x1 /* Identify Controller */
-#define NVME_IDENTIFY_LIST 0x2 /* Identify List Namespaces */
-
-#define NVME_IDENTIFY_NSID_ALLOC_LIST 0x10 /* List Allocated NSID */
-#define NVME_IDENTIFY_NSID_ALLOC 0x11 /* Identify Allocated NSID */
-#define NVME_IDENTIFY_NSID_CTRL_LIST 0x12 /* List Controllers on NSID */
-#define NVME_IDENTIFY_CTRL_LIST 0x13 /* Controller List */
-#define NVME_IDENTIFY_PRIMARY_CAPS 0x14 /* Primary Controller Caps */
-
-/*
* NVMe Abort Command
*/
typedef union {
@@ -421,7 +405,6 @@ typedef union {
uint32_t r;
} nvme_abort_cmd_t;
-
/*
* NVMe Get Log Page
*/
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c
index 62d1e298dd..0f9e4ea6dd 100644
--- a/usr/src/uts/common/os/exec.c
+++ b/usr/src/uts/common/os/exec.c
@@ -27,6 +27,7 @@
/* All Rights Reserved */
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/types.h>
@@ -93,9 +94,11 @@ static int hold_execsw(struct execsw *);
uint_t auxv_hwcap = 0; /* auxv AT_SUN_HWCAP value; determined on the fly */
uint_t auxv_hwcap_2 = 0; /* AT_SUN_HWCAP2 */
+uint_t auxv_hwcap_3 = 0; /* AT_SUN_HWCAP3 */
#if defined(_SYSCALL32_IMPL)
uint_t auxv_hwcap32 = 0; /* 32-bit version of auxv_hwcap */
uint_t auxv_hwcap32_2 = 0; /* 32-bit version of auxv_hwcap2 */
+uint_t auxv_hwcap32_3 = 0; /* 32-bit version of auxv_hwcap3 */
#endif
#define PSUIDFLAGS (SNOCD|SUGID)
diff --git a/usr/src/uts/common/sys/auxv.h b/usr/src/uts/common/sys/auxv.h
index b3b2898987..203b884cd3 100644
--- a/usr/src/uts/common/sys/auxv.h
+++ b/usr/src/uts/common/sys/auxv.h
@@ -30,6 +30,7 @@
*/
/*
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _SYS_AUXV_H
@@ -153,6 +154,7 @@ typedef struct {
*/
#define AT_SUN_HWCAP 2009
#define AT_SUN_HWCAP2 2023
+#define AT_SUN_HWCAP3 2029
#if defined(_KERNEL)
/*
@@ -161,9 +163,11 @@ typedef struct {
*/
extern uint_t auxv_hwcap;
extern uint_t auxv_hwcap_2;
+extern uint_t auxv_hwcap_3;
#if defined(_SYSCALL32)
extern uint_t auxv_hwcap32;
extern uint_t auxv_hwcap32_2;
+extern uint_t auxv_hwcap32_3;
#endif /* _SYSCALL32 */
#else
extern uint_t getisax(uint32_t *, uint_t);
diff --git a/usr/src/uts/common/sys/auxv_386.h b/usr/src/uts/common/sys/auxv_386.h
index 3654474787..d8e6938be0 100644
--- a/usr/src/uts/common/sys/auxv_386.h
+++ b/usr/src/uts/common/sys/auxv_386.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2019, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _SYS_AUXV_386_H
@@ -115,9 +116,13 @@ extern "C" {
#define AV_386_2_AVX512_VNNI 0x04000000 /* AVX512_VNNI */
#define AV_386_2_VPCLMULQDQ 0x08000000 /* VPCLMULQDQ */
#define AV_386_2_VAES 0x10000000 /* VAES */
+#define AV_386_2_GFNI 0x20000000 /* GFNI */
+#define AV_386_2_AVX512_VP2INT 0x40000000 /* AVX512 VP2INTERESECT */
+#define AV_386_2_AVX512_BITALG 0x80000000 /* AVX512 BITALG */
#define FMT_AV_386_2 \
- "\035vaes\034vpclmulqdq\033avx512_vnni" \
+ "\040avx512_vbmi2\037avx512_vp2intersect" \
+ "\036gfni\035vaes\034vpclmulqdq\033avx512_vnni" \
"\032clzero\031monitorx\030clwb\027clflushopt\026fsgsbase" \
"\025sha\024avx512_4fmaps\023avx512_4nniw\022avx512vpopcntdq" \
"\021avx512vbmi\020avx512vl\017avx512bw\016avx512cd" \
@@ -125,6 +130,15 @@ extern "C" {
"\010rdseed\07adx\06avx2\05fma\04bmi2\03bmi1\02rdrand\01f16c"
/*
+ * Flags used in AT_SUN_HWCAP3 elements
+ */
+#define AV_386_3_AVX512_VBMI2 0x00000001 /* AVX512_VBMI2 */
+#define AV_386_3_AVX512_BF16 0x00000002 /* AVX512_BF16 */
+
+#define FMT_AV_386_3 \
+ "\02avx512_bf16\01avx512_vbmi2"
+
+/*
* Flags used in AT_SUN_FPTYPE on x86.
*
* We don't currently support xsavec in illumos. However, when we do, then we
diff --git a/usr/src/uts/common/sys/cpuid_drv.h b/usr/src/uts/common/sys/cpuid_drv.h
index c26bc7e422..2321f2446f 100644
--- a/usr/src/uts/common/sys/cpuid_drv.h
+++ b/usr/src/uts/common/sys/cpuid_drv.h
@@ -25,6 +25,7 @@
*/
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _SYS_CPUID_DRV_H
@@ -68,7 +69,7 @@ extern "C" {
struct cpuid_get_hwcap {
char *cgh_archname;
- uint_t cgh_hwcap[2];
+ uint_t cgh_hwcap[3];
};
struct cpuid_rdmsr {
@@ -82,7 +83,7 @@ struct cpuid_rdmsr {
struct cpuid_get_hwcap32 {
caddr32_t cgh_archname;
- uint32_t cgh_hwcap[2];
+ uint32_t cgh_hwcap[3];
};
#endif /* _SYSCALL32_IMPL */
diff --git a/usr/src/uts/common/sys/elf.h b/usr/src/uts/common/sys/elf.h
index 8cb36da033..556a49c60f 100644
--- a/usr/src/uts/common/sys/elf.h
+++ b/usr/src/uts/common/sys/elf.h
@@ -21,7 +21,7 @@
/*
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
- * Copyright 2020 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
@@ -1000,7 +1000,8 @@ typedef Elf64_Word Elf64_Capchain;
#define CA_SUNW_PLAT 4 /* platform capability entry */
#define CA_SUNW_MACH 5 /* machine capability entry */
#define CA_SUNW_ID 6 /* capability identifier */
-#define CA_SUNW_NUM 7
+#define CA_SUNW_HW_3 7 /* third hardware capabilities entry */
+#define CA_SUNW_NUM 8
/*
* Define software capabilities (CA_SUNW_SF_1 values). Note, hardware
diff --git a/usr/src/uts/common/sys/nvme.h b/usr/src/uts/common/sys/nvme.h
index 04f39057e2..e7a685bd2f 100644
--- a/usr/src/uts/common/sys/nvme.h
+++ b/usr/src/uts/common/sys/nvme.h
@@ -21,10 +21,12 @@
#define _SYS_NVME_H
#include <sys/types.h>
+#include <sys/debug.h>
#ifdef _KERNEL
#include <sys/types32.h>
#else
+#include <sys/uuid.h>
#include <stdint.h>
#endif
@@ -41,8 +43,7 @@ extern "C" {
*/
#define NVME_IOC (('N' << 24) | ('V' << 16) | ('M' << 8))
-#define NVME_IOC_IDENTIFY_CTRL (NVME_IOC | 1)
-#define NVME_IOC_IDENTIFY_NSID (NVME_IOC | 2)
+#define NVME_IOC_IDENTIFY (NVME_IOC | 1)
#define NVME_IOC_CAPABILITIES (NVME_IOC | 3)
#define NVME_IOC_GET_LOGPAGE (NVME_IOC | 4)
#define NVME_IOC_GET_FEATURES (NVME_IOC | 5)
@@ -112,6 +113,19 @@ typedef struct {
#define NVME_IDENTIFY_BUFSIZE 4096 /* buffer size for Identify */
+/* NVMe Identify parameters (cdw10) */
+#define NVME_IDENTIFY_NSID 0x0 /* Identify Namespace */
+#define NVME_IDENTIFY_CTRL 0x1 /* Identify Controller */
+#define NVME_IDENTIFY_NSID_LIST 0x2 /* List Active Namespaces */
+#define NVME_IDENTIFY_NSID_DESC 0x3 /* Namespace ID Descriptors */
+
+#define NVME_IDENTIFY_NSID_ALLOC_LIST 0x10 /* List Allocated NSID */
+#define NVME_IDENTIFY_NSID_ALLOC 0x11 /* Identify Allocated NSID */
+#define NVME_IDENTIFY_NSID_CTRL_LIST 0x12 /* List Controllers on NSID */
+#define NVME_IDENTIFY_CTRL_LIST 0x13 /* Controller List */
+#define NVME_IDENTIFY_PRIMARY_CAPS 0x14 /* Primary Controller Caps */
+
+
/* NVMe Queue Entry Size bitfield */
typedef struct {
uint8_t qes_min:4; /* minimum entry size */
@@ -518,6 +532,37 @@ typedef struct {
uint8_t id_vs[4096 - 384]; /* Vendor Specific */
} nvme_identify_nsid_t;
+/* NVMe Identify Namespace ID List */
+typedef struct {
+ /* Ordered list of Namespace IDs */
+ uint32_t nl_nsid[NVME_IDENTIFY_BUFSIZE / sizeof (uint32_t)];
+} nvme_identify_nsid_list_t;
+
+/* NVME Identify Controller ID List */
+typedef struct {
+ uint16_t cl_nid; /* Number of controller entries */
+ /* unique controller identifiers */
+ uint16_t cl_ctlid[NVME_IDENTIFY_BUFSIZE / sizeof (uint16_t) - 1];
+} nvme_identify_ctrl_list_t;
+
+/* NVMe Identify Namespace Descriptor */
+typedef struct {
+ uint8_t nd_nidt; /* Namespace Identifier Type */
+ uint8_t nd_nidl; /* Namespace Identifier Length */
+ uint8_t nd_resv[2];
+ uint8_t nd_nid[]; /* Namespace Identifier */
+} nvme_identify_nsid_desc_t;
+
+#define NVME_NSID_DESC_EUI64 1
+#define NVME_NSID_DESC_NGUID 2
+#define NVME_NSID_DESC_NUUID 3
+#define NVME_NSID_DESC_MIN NVME_NSID_DESC_EUI64
+#define NVME_NSID_DESC_MAX NVME_NSID_DESC_NUUID
+
+#define NVME_NSID_DESC_LEN_EUI64 8
+#define NVME_NSID_DESC_LEN_NGUID 16
+#define NVME_NSID_DESC_LEN_NUUID UUID_LEN
+
/* NVMe Identify Primary Controller Capabilities */
typedef struct {
uint16_t nipc_cntlid; /* Controller ID */
@@ -645,10 +690,7 @@ typedef struct {
typedef struct {
uint32_t nscl_ns[NVME_NSCHANGE_LIST_SIZE];
-} __packed nvme_nschange_list_t;
-
-/* CSTYLED */
-_Static_assert(sizeof (nvme_nschange_list_t) == 4096, "bad size for nvme_nschange_list_t");
+} nvme_nschange_list_t;
/*
* NVMe Format NVM
diff --git a/usr/src/uts/common/sys/user.h b/usr/src/uts/common/sys/user.h
index 0b17066632..90fde4ef98 100644
--- a/usr/src/uts/common/sys/user.h
+++ b/usr/src/uts/common/sys/user.h
@@ -27,6 +27,7 @@
/* All Rights Reserved */
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
@@ -111,7 +112,7 @@ typedef struct uf_entry {
short uf_busy; /* file is allocated [grow, fork] */
kcondvar_t uf_wanted_cv; /* waiting for setf() [never copied] */
kcondvar_t uf_closing_cv; /* waiting for close() [never copied] */
- struct portfd *uf_portfd; /* associated with port [grow] */
+ struct portfd *uf_portfd; /* associated with port [grow] */
uf_entry_gen_t uf_gen; /* assigned fd generation [grow,fork] */
/* Avoid false sharing - pad to coherency granularity (64 bytes) */
char uf_pad[64 - sizeof (kmutex_t) - 2 * sizeof (void*) -
@@ -204,7 +205,7 @@ typedef struct { /* kernel syscall set type */
#if defined(__sparc)
#define __KERN_NAUXV_IMPL 24
#elif defined(__i386) || defined(__amd64)
-#define __KERN_NAUXV_IMPL 28
+#define __KERN_NAUXV_IMPL 29
#endif
struct execsw;
diff --git a/usr/src/uts/intel/io/amdzen/amdzen.c b/usr/src/uts/intel/io/amdzen/amdzen.c
index c3617c9742..8f430a6f6a 100644
--- a/usr/src/uts/intel/io/amdzen/amdzen.c
+++ b/usr/src/uts/intel/io/amdzen/amdzen.c
@@ -171,8 +171,14 @@ static const uint16_t amdzen_nb_ids[] = {
0x15d0,
/* Family 17h/19h Rome, Milan, Matisse, Vermeer Zen 2/Zen 3 uarch */
0x1480,
- /* Family 17h/19h Renoir, Cezanne Zen 2/3 uarch) */
- 0x1630
+ /* Family 17h/19h Renoir, Cezanne, Van Gogh Zen 2/3 uarch */
+ 0x1630,
+ /* Family 19h Genoa */
+ 0x14a4,
+ /* Family 17h Mendocino, Family 19h Rembrandt */
+ 0x14b5,
+ /* Family 19h Raphael */
+ 0x14d8
};
typedef struct {
@@ -277,18 +283,19 @@ amdzen_df_read32_bcast(amdzen_t *azn, amdzen_df_t *df, const df_reg_def_t def)
static uint32_t
-amdzen_smn_read32(amdzen_t *azn, amdzen_df_t *df, uint32_t reg)
+amdzen_smn_read32(amdzen_t *azn, amdzen_df_t *df, const smn_reg_t reg)
{
VERIFY(MUTEX_HELD(&azn->azn_mutex));
- amdzen_stub_put32(df->adf_nb, AMDZEN_NB_SMN_ADDR, reg);
+ amdzen_stub_put32(df->adf_nb, AMDZEN_NB_SMN_ADDR, SMN_REG_ADDR(reg));
return (amdzen_stub_get32(df->adf_nb, AMDZEN_NB_SMN_DATA));
}
static void
-amdzen_smn_write32(amdzen_t *azn, amdzen_df_t *df, uint32_t reg, uint32_t val)
+amdzen_smn_write32(amdzen_t *azn, amdzen_df_t *df, const smn_reg_t reg,
+ const uint32_t val)
{
VERIFY(MUTEX_HELD(&azn->azn_mutex));
- amdzen_stub_put32(df->adf_nb, AMDZEN_NB_SMN_ADDR, reg);
+ amdzen_stub_put32(df->adf_nb, AMDZEN_NB_SMN_ADDR, SMN_REG_ADDR(reg));
amdzen_stub_put32(df->adf_nb, AMDZEN_NB_SMN_DATA, val);
}
@@ -321,7 +328,7 @@ amdzen_df_find(amdzen_t *azn, uint_t dfno)
* Client functions that are used by nexus children.
*/
int
-amdzen_c_smn_read32(uint_t dfno, uint32_t reg, uint32_t *valp)
+amdzen_c_smn_read32(uint_t dfno, const smn_reg_t reg, uint32_t *valp)
{
amdzen_df_t *df;
amdzen_t *azn = amdzen_data;
@@ -344,7 +351,7 @@ amdzen_c_smn_read32(uint_t dfno, uint32_t reg, uint32_t *valp)
}
int
-amdzen_c_smn_write32(uint_t dfno, uint32_t reg, uint32_t val)
+amdzen_c_smn_write32(uint_t dfno, const smn_reg_t reg, const uint32_t val)
{
amdzen_df_t *df;
amdzen_t *azn = amdzen_data;
@@ -486,17 +493,13 @@ amdzen_c_df_iter(uint_t dfno, zen_df_type_t type, amdzen_c_iter_f func,
}
break;
case ZEN_DF_TYPE_CCM_CPU:
- df_type = DF_TYPE_CCM;
/*
- * In the Genoa/DFv4 timeframe, with the introduction of CXL and
- * related, a subtype was added here where as previously it was
- * always zero.
+ * While the wording of the PPR is a little weird, the CCM still
+ * has subtype 0 in DFv4 systems; however, what's said to be for
+ * the CPU appears to apply to the ACM.
*/
- if (df->adf_major >= 4) {
- df_subtype = DF_CCM_SUBTYPE_CPU;
- } else {
- df_subtype = 0;
- }
+ df_type = DF_TYPE_CCM;
+ df_subtype = 0;
break;
default:
return (EINVAL);
diff --git a/usr/src/uts/intel/io/amdzen/amdzen_client.h b/usr/src/uts/intel/io/amdzen/amdzen_client.h
index 4d937a1321..fc82c1039e 100644
--- a/usr/src/uts/intel/io/amdzen/amdzen_client.h
+++ b/usr/src/uts/intel/io/amdzen/amdzen_client.h
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <sys/amdzen/df.h>
+#include <sys/amdzen/smn.h>
#ifdef __cplusplus
extern "C" {
@@ -51,8 +52,8 @@ extern int amdzen_c_df_fabric_decomp(df_fabric_decomp_t *);
/*
* SMN and DF access routines.
*/
-extern int amdzen_c_smn_read32(uint_t, uint32_t, uint32_t *);
-extern int amdzen_c_smn_write32(uint_t, uint32_t, uint32_t);
+extern int amdzen_c_smn_read32(uint_t, const smn_reg_t, uint32_t *);
+extern int amdzen_c_smn_write32(uint_t, const smn_reg_t, const uint32_t);
extern int amdzen_c_df_read32(uint_t, uint8_t, const df_reg_def_t, uint32_t *);
extern int amdzen_c_df_read64(uint_t, uint8_t, const df_reg_def_t, uint64_t *);
diff --git a/usr/src/uts/intel/io/amdzen/smntemp.c b/usr/src/uts/intel/io/amdzen/smntemp.c
index aa595f5ce5..94b7aa8b83 100644
--- a/usr/src/uts/intel/io/amdzen/smntemp.c
+++ b/usr/src/uts/intel/io/amdzen/smntemp.c
@@ -11,7 +11,7 @@
/*
* Copyright 2019, Joyent, Inc.
- * Copyright 2020 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -31,6 +31,7 @@
#include <sys/cpuvar.h>
#include <sys/sensors.h>
#include <sys/sysmacros.h>
+#include <sys/amdzen/smn.h>
#include <amdzen_client.h>
/*
@@ -39,7 +40,7 @@
* accessed through the northbridge. They are not addresses in PCI configuration
* space.
*/
-#define SMN_SMU_THERMAL_CURTEMP 0x00059800
+#define SMN_SMU_THERMAL_CURTEMP SMN_MAKE_REG(0x00059800)
#define SMN_SMU_THERMAL_CURTEMP_TEMPERATURE(x) ((x) >> 21)
#define SMN_SMU_THERMAL_CURTEMP_RANGE_SEL (1 << 19)
diff --git a/usr/src/uts/intel/io/amdzen/usmn.c b/usr/src/uts/intel/io/amdzen/usmn.c
index d5050def92..789e15830e 100644
--- a/usr/src/uts/intel/io/amdzen/usmn.c
+++ b/usr/src/uts/intel/io/amdzen/usmn.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -101,7 +101,8 @@ usmn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
return (EINVAL);
}
- ret = amdzen_c_smn_read32(dfno, usr.usr_addr, &usr.usr_data);
+ ret = amdzen_c_smn_read32(dfno, SMN_MAKE_REG(usr.usr_addr),
+ &usr.usr_data);
if (ret != 0) {
return (ret);
}
@@ -112,7 +113,8 @@ usmn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
return (EINVAL);
}
- ret = amdzen_c_smn_write32(dfno, usr.usr_addr, usr.usr_data);
+ ret = amdzen_c_smn_write32(dfno, SMN_MAKE_REG(usr.usr_addr),
+ usr.usr_data);
if (ret != 0) {
return (ret);
}
diff --git a/usr/src/uts/intel/io/amdzen/zen_umc.c b/usr/src/uts/intel/io/amdzen/zen_umc.c
index bf5914fae6..947c17b4ff 100644
--- a/usr/src/uts/intel/io/amdzen/zen_umc.c
+++ b/usr/src/uts/intel/io/amdzen/zen_umc.c
@@ -1840,6 +1840,71 @@ zen_umc_fill_ccm_cb(const uint_t dfno, const uint32_t fabid,
}
/*
+ * This is used to fill in the common properties about a DIMM. This should occur
+ * after the rank information has been filled out. The information used is the
+ * same between DDR4 and DDR5 DIMMs. The only major difference is the register
+ * offset.
+ */
+static boolean_t
+zen_umc_fill_dimm_common(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
+ const uint_t dimmno, boolean_t ddr4)
+{
+ umc_dimm_t *dimm;
+ int ret;
+ smn_reg_t reg;
+ uint32_t val;
+ const uint32_t id = chan->chan_logid;
+
+ dimm = &chan->chan_dimms[dimmno];
+ dimm->ud_dimmno = dimmno;
+
+ if (ddr4) {
+ reg = UMC_DIMMCFG_DDR4(id, dimmno);
+ } else {
+ reg = UMC_DIMMCFG_DDR5(id, dimmno);
+ }
+ if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
+ dev_err(umc->umc_dip, CE_WARN, "failed to read DIMM "
+ "configuration register %x: %d", SMN_REG_ADDR(reg), ret);
+ return (B_FALSE);
+ }
+ dimm->ud_dimmcfg_raw = val;
+
+ if (UMC_DIMMCFG_GET_X16(val) != 0) {
+ dimm->ud_width = UMC_DIMM_W_X16;
+ } else if (UMC_DIMMCFG_GET_X4(val) != 0) {
+ dimm->ud_width = UMC_DIMM_W_X4;
+ } else {
+ dimm->ud_width = UMC_DIMM_W_X8;
+ }
+
+ if (UMC_DIMMCFG_GET_3DS(val) != 0) {
+ dimm->ud_kind = UMC_DIMM_K_3DS_RDIMM;
+ } else if (UMC_DIMMCFG_GET_LRDIMM(val) != 0) {
+ dimm->ud_kind = UMC_DIMM_K_LRDIMM;
+ } else if (UMC_DIMMCFG_GET_RDIMM(val) != 0) {
+ dimm->ud_kind = UMC_DIMM_K_RDIMM;
+ } else {
+ dimm->ud_kind = UMC_DIMM_K_UDIMM;
+ }
+
+ /*
+ * DIMM information in a UMC can be somewhat confusing. There are quite
+ * a number of non-zero reset values that are here. Flag whether or not
+ * we think this entry should be usable based on enabled chip-selects.
+ */
+ for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_BASE; i++) {
+ if (dimm->ud_cs[i].ucs_base.udb_valid ||
+ dimm->ud_cs[i].ucs_sec.udb_valid) {
+ dimm->ud_flags |= UMC_DIMM_F_VALID;
+ break;
+ }
+ }
+
+ return (B_TRUE);
+}
+
+/*
* Fill all the information about a DDR4 DIMM. In the DDR4 UMC, some of this
* information is on a per-chip select basis while at other times it is on a
* per-DIMM basis. In general, chip-selects 0/1 correspond to DIMM 0, and
@@ -1856,11 +1921,11 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
umc_cs_t *cs0, *cs1;
const uint32_t id = chan->chan_logid;
int ret;
- uint32_t val, reg;
+ uint32_t val;
+ smn_reg_t reg;
ASSERT3U(dimmno, <, ZEN_UMC_MAX_DIMMS);
dimm = &chan->chan_dimms[dimmno];
- dimm->ud_dimmno = dimmno;
cs0 = &dimm->ud_cs[0];
cs1 = &dimm->ud_cs[1];
@@ -1872,11 +1937,11 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
*/
for (uint_t i = 0; i < ZEN_UMC_MAX_CS_PER_DIMM; i++) {
uint64_t addr;
- const uint32_t reginst = i + dimmno * 2;
+ const uint16_t reginst = i + dimmno * 2;
reg = UMC_BASE(id, reginst);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read base "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -1887,7 +1952,8 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_BASE_SEC(id, reginst);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "secondary base register %x: %d", reg, ret);
+ "secondary base register %x: %d", SMN_REG_ADDR(reg),
+ ret);
return (B_FALSE);
}
@@ -1899,7 +1965,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_MASK_DDR4(id, dimmno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read mask register "
- "%x: %d", reg, ret);
+ "%x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -1915,7 +1981,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_MASK_SEC_DDR4(id, dimmno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read secondary mask "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
cs0->ucs_sec_mask = (uint64_t)UMC_MASK_GET_ADDR(val) <<
@@ -1926,7 +1992,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_ADDRCFG_DDR4(id, dimmno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read address config "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -1962,7 +2028,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_ADDRSEL_DDR4(id, dimmno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read bank address "
- "select register %x: %d", reg, ret);
+ "select register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
cs0->ucs_row_hi_bit = UMC_ADDRSEL_DDR4_GET_ROW_HI(val) +
@@ -1987,7 +2053,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_COLSEL_LO_DDR4(id, dimmno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read column address "
- "select low register %x: %d", reg, ret);
+ "select low register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
for (uint_t i = 0; i < ZEN_UMC_MAX_COLSEL_PER_REG; i++) {
@@ -1998,7 +2064,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_COLSEL_HI_DDR4(id, dimmno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read column address "
- "select high register %x: %d", reg, ret);
+ "select high register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
for (uint_t i = 0; i < ZEN_UMC_MAX_COLSEL_PER_REG; i++) {
@@ -2017,7 +2083,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_RMSEL_DDR4(id, dimmno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read rank address "
- "select register %x: %d", reg, ret);
+ "select register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
cs0->ucs_inv_msbs = UMC_RMSEL_DDR4_GET_INV_MSBE(val);
@@ -2033,7 +2099,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_RMSEL_SEC_DDR4(id, dimmno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read secondary rank "
- "address select register %x: %d", reg, ret);
+ "address select register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
cs0->ucs_inv_msbs_sec = UMC_RMSEL_DDR4_GET_INV_MSBE(val);
@@ -2047,46 +2113,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
bcopy(cs0->ucs_rm_bits_sec, cs1->ucs_rm_bits_sec,
sizeof (cs0->ucs_rm_bits_sec));
- reg = UMC_DIMMCFG_DDR4(id, dimmno);
- if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
- dev_err(umc->umc_dip, CE_WARN, "failed to read DIMM "
- "configuration register %x: %d", reg, ret);
- return (B_FALSE);
- }
- dimm->ud_dimmcfg_raw = val;
-
- if (UMC_DIMMCFG_GET_X16(val) != 0) {
- dimm->ud_width = UMC_DIMM_W_X16;
- } else if (UMC_DIMMCFG_GET_X4(val) != 0) {
- dimm->ud_width = UMC_DIMM_W_X4;
- } else {
- dimm->ud_width = UMC_DIMM_W_X8;
- }
-
- if (UMC_DIMMCFG_GET_3DS(val) != 0) {
- dimm->ud_kind = UMC_DIMM_K_3DS_RDIMM;
- } else if (UMC_DIMMCFG_GET_LRDIMM(val) != 0) {
- dimm->ud_kind = UMC_DIMM_K_LRDIMM;
- } else if (UMC_DIMMCFG_GET_RDIMM(val) != 0) {
- dimm->ud_kind = UMC_DIMM_K_RDIMM;
- } else {
- dimm->ud_kind = UMC_DIMM_K_UDIMM;
- }
-
- /*
- * DIMM information in a UMC can be somewhat confusing. There are quite
- * a number of non-zero reset values that are here. Flag whether or not
- * we think this entry should be usable based on enabled chip-selects.
- */
- for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_BASE; i++) {
- if (dimm->ud_cs[i].ucs_base.udb_valid ||
- dimm->ud_cs[i].ucs_sec.udb_valid) {
- dimm->ud_flags |= UMC_DIMM_F_VALID;
- break;
- }
- }
-
- return (B_TRUE);
+ return (zen_umc_fill_dimm_common(umc, df, chan, dimmno, B_TRUE));
}
/*
@@ -2100,7 +2127,8 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
{
int ret;
umc_cs_t *cs;
- uint32_t reg, val;
+ uint32_t val;
+ smn_reg_t reg;
const uint32_t id = chan->chan_logid;
const uint32_t regno = dimmno * 2 + rankno;
@@ -2111,7 +2139,7 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_BASE(id, regno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read base "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
cs->ucs_base.udb_base = (uint64_t)UMC_BASE_GET_ADDR(val) <<
@@ -2124,7 +2152,8 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) !=
0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "extended base register %x: %d", reg, ret);
+ "extended base register %x: %d", SMN_REG_ADDR(reg),
+ ret);
return (B_FALSE);
}
@@ -2136,7 +2165,7 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_BASE_SEC(id, regno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read secondary base "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
cs->ucs_sec.udb_base = (uint64_t)UMC_BASE_GET_ADDR(val) <<
@@ -2149,8 +2178,8 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) !=
0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "extended secondary base register %x: %d", reg,
- ret);
+ "extended secondary base register %x: %d",
+ SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -2162,7 +2191,7 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_MASK_DDR5(id, regno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read mask "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
cs->ucs_base_mask = (uint64_t)UMC_MASK_GET_ADDR(val) <<
@@ -2175,7 +2204,8 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) !=
0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "extended mask register %x: %d", reg, ret);
+ "extended mask register %x: %d", SMN_REG_ADDR(reg),
+ ret);
return (B_FALSE);
}
@@ -2188,7 +2218,7 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_MASK_SEC_DDR5(id, regno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read secondary mask "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
cs->ucs_sec_mask = (uint64_t)UMC_MASK_GET_ADDR(val) <<
@@ -2201,7 +2231,8 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) !=
0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "extended mask register %x: %d", reg, ret);
+ "extended mask register %x: %d", SMN_REG_ADDR(reg),
+ ret);
return (B_FALSE);
}
@@ -2213,7 +2244,7 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_ADDRCFG_DDR5(id, regno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read address config "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
if ((umc->umc_fdata->zufd_flags & ZEN_UMC_FAM_F_CS_XOR) != 0) {
@@ -2234,7 +2265,7 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_ADDRSEL_DDR5(id, regno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read address select "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
cs->ucs_row_hi_bit = 0;
@@ -2254,7 +2285,7 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_COLSEL_LO_DDR5(id, regno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read column address "
- "select low register %x: %d", reg, ret);
+ "select low register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
for (uint_t i = 0; i < ZEN_UMC_MAX_COLSEL_PER_REG; i++) {
@@ -2265,7 +2296,7 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_COLSEL_HI_DDR5(id, regno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read column address "
- "select high register %x: %d", reg, ret);
+ "select high register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
for (uint_t i = 0; i < ZEN_UMC_MAX_COLSEL_PER_REG; i++) {
@@ -2282,7 +2313,7 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
reg = UMC_RMSEL_DDR5(id, regno);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read rank multiply "
- "select register %x: %d", reg, ret);
+ "select register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -2303,9 +2334,10 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
bcopy(cs->ucs_rm_bits, cs->ucs_rm_bits_sec,
sizeof (cs->ucs_rm_bits));
- return (B_TRUE);
+ return (zen_umc_fill_dimm_common(umc, df, chan, dimmno, B_FALSE));
}
+
static void
zen_umc_fill_ddr_type(zen_umc_chan_t *chan, boolean_t ddr4)
{
@@ -2358,7 +2390,7 @@ zen_umc_fill_chan_hash(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
boolean_t ddr4)
{
int ret;
- uint32_t reg;
+ smn_reg_t reg;
uint32_t val;
const umc_chan_hash_flags_t flags = umc->umc_fdata->zufd_chan_hash;
@@ -2379,7 +2411,8 @@ zen_umc_fill_chan_hash(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg,
&val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "bank hash register %x: %d", reg, ret);
+ "bank hash register %x: %d",
+ SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -2403,7 +2436,8 @@ zen_umc_fill_chan_hash(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg,
&val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "rm hash register %x: %d", reg, ret);
+ "rm hash register %x: %d",
+ SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -2420,7 +2454,8 @@ zen_umc_fill_chan_hash(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg,
&val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "rm hash ext register %x: %d", reg, ret);
+ "rm hash ext register %x: %d",
+ SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -2441,7 +2476,7 @@ zen_umc_fill_chan_hash(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read pc hash "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -2457,7 +2492,7 @@ zen_umc_fill_chan_hash(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read pc hash "
- "2 register %x: %d", reg, ret);
+ "2 register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -2478,7 +2513,7 @@ zen_umc_fill_chan_hash(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg,
&val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "cs hash register %x", reg);
+ "cs hash register %x", SMN_REG_ADDR(reg));
return (B_FALSE);
}
@@ -2495,7 +2530,8 @@ zen_umc_fill_chan_hash(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg,
&val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read "
- "cs hash ext register %x", reg);
+ "cs hash ext register %x",
+ SMN_REG_ADDR(reg));
return (B_FALSE);
}
@@ -2514,7 +2550,8 @@ zen_umc_fill_chan_hash(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
static boolean_t
zen_umc_fill_chan(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan)
{
- uint32_t reg, val;
+ uint32_t val;
+ smn_reg_t reg;
const uint32_t id = chan->chan_logid;
int ret;
boolean_t ddr4;
@@ -2538,7 +2575,7 @@ zen_umc_fill_chan(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan)
reg = UMC_UMCCFG(id);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read UMC "
- "configuration register %x: %d", reg, ret);
+ "configuration register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
@@ -2561,7 +2598,7 @@ zen_umc_fill_chan(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan)
reg = UMC_DATACTL(id);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read data control "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
chan->chan_datactl_raw = val;
@@ -2582,7 +2619,7 @@ zen_umc_fill_chan(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan)
reg = UMC_ECCCTL(id);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read ECC control "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
chan->chan_eccctl_raw = val;
@@ -2594,7 +2631,7 @@ zen_umc_fill_chan(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan)
reg = UMC_UMCCAP(id);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read UMC cap"
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
chan->chan_umccap_raw = val;
@@ -2602,7 +2639,7 @@ zen_umc_fill_chan(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan)
reg = UMC_UMCCAP_HI(id);
if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
dev_err(umc->umc_dip, CE_WARN, "failed to read UMC cap high "
- "register %x: %d", reg, ret);
+ "register %x: %d", SMN_REG_ADDR(reg), ret);
return (B_FALSE);
}
chan->chan_umccap_hi_raw = val;
diff --git a/usr/src/uts/intel/os/archdep.c b/usr/src/uts/intel/os/archdep.c
index eb926ed8e9..1f3f438951 100644
--- a/usr/src/uts/intel/os/archdep.c
+++ b/usr/src/uts/intel/os/archdep.c
@@ -27,6 +27,7 @@
/*
* Copyright (c) 2018, Joyent, Inc.
* Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/param.h>
@@ -876,18 +877,20 @@ uint_t auxv_hwcap32_exclude_2 = 0; /* ditto for 32-bit apps */
*
* We use this seemingly complicated mechanism so that we can ensure
* that /etc/system can be used to override what the system can or
- * cannot discover for itself.
+ * cannot discover for itself. Due to a lack of use, this has not
+ * been extended to the 3rd word.
*/
void
bind_hwcap(void)
{
- uint_t cpu_hwcap_flags[2];
+ uint_t cpu_hwcap_flags[3];
cpuid_execpass(NULL, CPUID_PASS_RESOLVE, cpu_hwcap_flags);
auxv_hwcap = (auxv_hwcap_include | cpu_hwcap_flags[0]) &
~auxv_hwcap_exclude;
auxv_hwcap_2 = (auxv_hwcap_include_2 | cpu_hwcap_flags[1]) &
~auxv_hwcap_exclude_2;
+ auxv_hwcap_3 = cpu_hwcap_flags[2];
/*
* On AMD processors, sysenter just doesn't work at all
@@ -920,6 +923,8 @@ bind_hwcap(void)
cmn_err(CE_CONT, fmt, auxv_hwcap, FMT_AV_386);
fmt = "?user ABI extensions (word 2): %b\n";
cmn_err(CE_CONT, fmt, auxv_hwcap_2, FMT_AV_386_2);
+ fmt = "?user ABI extensions (word 2): %b\n";
+ cmn_err(CE_CONT, fmt, auxv_hwcap_3, FMT_AV_386_3);
}
#if defined(_SYSCALL32_IMPL)
@@ -927,6 +932,7 @@ bind_hwcap(void)
~auxv_hwcap32_exclude;
auxv_hwcap32_2 = (auxv_hwcap32_include_2 | cpu_hwcap_flags[1]) &
~auxv_hwcap32_exclude_2;
+ auxv_hwcap32_3 = auxv_hwcap_3;
/*
* If this is an amd64 architecture machine from Intel, then
@@ -956,6 +962,8 @@ bind_hwcap(void)
cmn_err(CE_CONT, fmt, auxv_hwcap32, FMT_AV_386);
fmt = "?32-bit user ABI extensions (word 2): %b\n";
cmn_err(CE_CONT, fmt, auxv_hwcap32_2, FMT_AV_386_2);
+ fmt = "?32-bit user ABI extensions (word 3): %b\n";
+ cmn_err(CE_CONT, fmt, auxv_hwcap32_3, FMT_AV_386_3);
}
#endif
}
diff --git a/usr/src/uts/intel/os/cpuid.c b/usr/src/uts/intel/os/cpuid.c
index a723ae904e..1459c034b9 100644
--- a/usr/src/uts/intel/os/cpuid.c
+++ b/usr/src/uts/intel/os/cpuid.c
@@ -1634,7 +1634,12 @@ static char *x86_feature_names[NUM_X86_FEATURES] = {
"ppin",
"vaes",
"vpclmulqdq",
- "lfence_serializing"
+ "lfence_serializing",
+ "gfni",
+ "avx512_vp2intersect",
+ "avx512_bitalg",
+ "avx512_vbmi2",
+ "avx512_bf16"
};
boolean_t
@@ -1786,6 +1791,7 @@ struct cpuid_info {
/* Intel fn: 4, AMD fn: 8000001d */
struct cpuid_regs **cpi_cache_leaves; /* Acual leaves from above */
struct cpuid_regs cpi_std[NMAX_CPI_STD]; /* 0 .. 7 */
+ struct cpuid_regs cpi_sub7[1]; /* Leaf 7, sub-leaf 1 */
/*
* extended function information
*/
@@ -1857,6 +1863,7 @@ static struct cpuid_info cpuid_info0;
#define CPI_FEATURES_7_0_EBX(cpi) ((cpi)->cpi_std[7].cp_ebx)
#define CPI_FEATURES_7_0_ECX(cpi) ((cpi)->cpi_std[7].cp_ecx)
#define CPI_FEATURES_7_0_EDX(cpi) ((cpi)->cpi_std[7].cp_edx)
+#define CPI_FEATURES_7_1_EAX(cpi) ((cpi)->cpi_sub7[0].cp_eax)
#define CPI_BRANDID(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 7, 0)
#define CPI_CHUNKS(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 15, 7)
@@ -3386,6 +3393,109 @@ cpuid_basic_thermal(cpu_t *cpu, uchar_t *featureset)
}
/*
+ * This is used when we discover that we have AVX support in cpuid. This
+ * proceeds to scan for the rest of the AVX derived features.
+ */
+static void
+cpuid_basic_avx(cpu_t *cpu, uchar_t *featureset)
+{
+ struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
+
+ /*
+ * If we don't have AVX, don't bother with most of this.
+ */
+ if ((cpi->cpi_std[1].cp_ecx & CPUID_INTC_ECX_AVX) == 0)
+ return;
+
+ add_x86_feature(featureset, X86FSET_AVX);
+
+ /*
+ * Intel says we can't check these without also
+ * checking AVX.
+ */
+ if (cpi->cpi_std[1].cp_ecx & CPUID_INTC_ECX_F16C)
+ add_x86_feature(featureset, X86FSET_F16C);
+
+ if (cpi->cpi_std[1].cp_ecx & CPUID_INTC_ECX_FMA)
+ add_x86_feature(featureset, X86FSET_FMA);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_BMI1)
+ add_x86_feature(featureset, X86FSET_BMI1);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_BMI2)
+ add_x86_feature(featureset, X86FSET_BMI2);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_AVX2)
+ add_x86_feature(featureset, X86FSET_AVX2);
+
+ if (cpi->cpi_std[7].cp_ecx & CPUID_INTC_ECX_7_0_VAES)
+ add_x86_feature(featureset, X86FSET_VAES);
+
+ if (cpi->cpi_std[7].cp_ecx & CPUID_INTC_ECX_7_0_VPCLMULQDQ)
+ add_x86_feature(featureset, X86FSET_VPCLMULQDQ);
+
+ /*
+ * The rest of the AVX features require AVX512. Do not check them unless
+ * it is present.
+ */
+ if ((cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_AVX512F) == 0)
+ return;
+ add_x86_feature(featureset, X86FSET_AVX512F);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_AVX512DQ)
+ add_x86_feature(featureset, X86FSET_AVX512DQ);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_AVX512IFMA)
+ add_x86_feature(featureset, X86FSET_AVX512FMA);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_AVX512PF)
+ add_x86_feature(featureset, X86FSET_AVX512PF);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_AVX512ER)
+ add_x86_feature(featureset, X86FSET_AVX512ER);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_AVX512CD)
+ add_x86_feature(featureset, X86FSET_AVX512CD);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_AVX512BW)
+ add_x86_feature(featureset, X86FSET_AVX512BW);
+
+ if (cpi->cpi_std[7].cp_ebx & CPUID_INTC_EBX_7_0_AVX512VL)
+ add_x86_feature(featureset, X86FSET_AVX512VL);
+
+ if (cpi->cpi_std[7].cp_ecx & CPUID_INTC_ECX_7_0_AVX512VBMI)
+ add_x86_feature(featureset, X86FSET_AVX512VBMI);
+
+ if (cpi->cpi_std[7].cp_ecx & CPUID_INTC_ECX_7_0_AVX512VBMI2)
+ add_x86_feature(featureset, X86FSET_AVX512_VBMI2);
+
+ if (cpi->cpi_std[7].cp_ecx & CPUID_INTC_ECX_7_0_AVX512VNNI)
+ add_x86_feature(featureset, X86FSET_AVX512VNNI);
+
+ if (cpi->cpi_std[7].cp_ecx & CPUID_INTC_ECX_7_0_AVX512BITALG)
+ add_x86_feature(featureset, X86FSET_AVX512_BITALG);
+
+ if (cpi->cpi_std[7].cp_ecx & CPUID_INTC_ECX_7_0_AVX512VPOPCDQ)
+ add_x86_feature(featureset, X86FSET_AVX512VPOPCDQ);
+
+ if (cpi->cpi_std[7].cp_edx & CPUID_INTC_EDX_7_0_AVX5124NNIW)
+ add_x86_feature(featureset, X86FSET_AVX512NNIW);
+
+ if (cpi->cpi_std[7].cp_edx & CPUID_INTC_EDX_7_0_AVX5124FMAPS)
+ add_x86_feature(featureset, X86FSET_AVX512FMAPS);
+
+ /*
+ * More features here are in Leaf 7, subleaf 1. Don't bother checking if
+ * we don't need to.
+ */
+ if (cpi->cpi_std[7].cp_eax < 1)
+ return;
+
+ if (cpi->cpi_sub7[0].cp_eax & CPUID_INTC_EAX_7_1_AVX512_BF16)
+ add_x86_feature(featureset, X86FSET_AVX512_BF16);
+}
+
+/*
* PPIN is the protected processor inventory number. On AMD this is an actual
* feature bit. However, on Intel systems we need to read the platform
* information MSR if we're on a specific model.
@@ -3781,7 +3891,8 @@ cpuid_pass_basic(cpu_t *cpu, void *arg)
/*
* In addition to ecx and edx, Intel and AMD are storing a bunch of
- * instruction set extensions in leaf 7's ebx, ecx, and edx.
+ * instruction set extensions in leaf 7's ebx, ecx, and edx. Note, leaf
+ * 7 has sub-leaves determined by ecx.
*/
if (cpi->cpi_maxeax >= 7) {
struct cpuid_regs *ecp;
@@ -3792,7 +3903,10 @@ cpuid_pass_basic(cpu_t *cpu, void *arg)
/*
* If XSAVE has been disabled, just ignore all of the
- * extended-save-area dependent flags here.
+ * extended-save-area dependent flags here. By removing most of
+ * the leaf 7, sub-leaf 0 flags, that will ensure tha we don't
+ * end up looking at additional xsave dependent leaves right
+ * now.
*/
if (xsave_force_disable) {
ecp->cp_ebx &= ~CPUID_INTC_EBX_7_0_BMI1;
@@ -3804,6 +3918,7 @@ cpuid_pass_basic(cpu_t *cpu, void *arg)
ecp->cp_edx &= ~CPUID_INTC_EDX_7_0_ALL_AVX512;
ecp->cp_ecx &= ~CPUID_INTC_ECX_7_0_VAES;
ecp->cp_ecx &= ~CPUID_INTC_ECX_7_0_VPCLMULQDQ;
+ ecp->cp_ecx &= ~CPUID_INTC_ECX_7_0_GFNI;
}
if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_SMEP)
@@ -3840,13 +3955,27 @@ cpuid_pass_basic(cpu_t *cpu, void *arg)
add_x86_feature(featureset, X86FSET_PKU);
if (ecp->cp_ecx & CPUID_INTC_ECX_7_0_OSPKE)
add_x86_feature(featureset, X86FSET_OSPKE);
+ if (ecp->cp_ecx & CPUID_INTC_ECX_7_0_GFNI)
+ add_x86_feature(featureset, X86FSET_GFNI);
+
+ if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_CLWB)
+ add_x86_feature(featureset, X86FSET_CLWB);
if (cpi->cpi_vendor == X86_VENDOR_Intel) {
if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_MPX)
add_x86_feature(featureset, X86FSET_MPX);
+ }
- if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_CLWB)
- add_x86_feature(featureset, X86FSET_CLWB);
+ /*
+ * If we have subleaf 1 available, grab and store that. This is
+ * used for more AVX and related features.
+ */
+ if (ecp->cp_eax >= 1) {
+ struct cpuid_regs *c71;
+ c71 = &cpi->cpi_sub7[0];
+ c71->cp_eax = 7;
+ c71->cp_ecx = 1;
+ (void) __cpuid_insn(c71);
}
}
@@ -3937,105 +4066,7 @@ cpuid_pass_basic(cpu_t *cpu, void *arg)
add_x86_feature(featureset, X86FSET_XSAVE);
/* We only test AVX & AVX512 when there is XSAVE */
-
- if (cp->cp_ecx & CPUID_INTC_ECX_AVX) {
- add_x86_feature(featureset,
- X86FSET_AVX);
-
- /*
- * Intel says we can't check these without also
- * checking AVX.
- */
- if (cp->cp_ecx & CPUID_INTC_ECX_F16C)
- add_x86_feature(featureset,
- X86FSET_F16C);
-
- if (cp->cp_ecx & CPUID_INTC_ECX_FMA)
- add_x86_feature(featureset,
- X86FSET_FMA);
-
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_BMI1)
- add_x86_feature(featureset,
- X86FSET_BMI1);
-
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_BMI2)
- add_x86_feature(featureset,
- X86FSET_BMI2);
-
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_AVX2)
- add_x86_feature(featureset,
- X86FSET_AVX2);
-
- if (cpi->cpi_std[7].cp_ecx &
- CPUID_INTC_ECX_7_0_VAES)
- add_x86_feature(featureset,
- X86FSET_VAES);
-
- if (cpi->cpi_std[7].cp_ecx &
- CPUID_INTC_ECX_7_0_VPCLMULQDQ)
- add_x86_feature(featureset,
- X86FSET_VPCLMULQDQ);
- }
-
- if (cpi->cpi_vendor == X86_VENDOR_Intel &&
- (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_AVX512F) != 0) {
- add_x86_feature(featureset, X86FSET_AVX512F);
-
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_AVX512DQ)
- add_x86_feature(featureset,
- X86FSET_AVX512DQ);
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_AVX512IFMA)
- add_x86_feature(featureset,
- X86FSET_AVX512FMA);
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_AVX512PF)
- add_x86_feature(featureset,
- X86FSET_AVX512PF);
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_AVX512ER)
- add_x86_feature(featureset,
- X86FSET_AVX512ER);
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_AVX512CD)
- add_x86_feature(featureset,
- X86FSET_AVX512CD);
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_AVX512BW)
- add_x86_feature(featureset,
- X86FSET_AVX512BW);
- if (cpi->cpi_std[7].cp_ebx &
- CPUID_INTC_EBX_7_0_AVX512VL)
- add_x86_feature(featureset,
- X86FSET_AVX512VL);
-
- if (cpi->cpi_std[7].cp_ecx &
- CPUID_INTC_ECX_7_0_AVX512VBMI)
- add_x86_feature(featureset,
- X86FSET_AVX512VBMI);
- if (cpi->cpi_std[7].cp_ecx &
- CPUID_INTC_ECX_7_0_AVX512VNNI)
- add_x86_feature(featureset,
- X86FSET_AVX512VNNI);
- if (cpi->cpi_std[7].cp_ecx &
- CPUID_INTC_ECX_7_0_AVX512VPOPCDQ)
- add_x86_feature(featureset,
- X86FSET_AVX512VPOPCDQ);
-
- if (cpi->cpi_std[7].cp_edx &
- CPUID_INTC_EDX_7_0_AVX5124NNIW)
- add_x86_feature(featureset,
- X86FSET_AVX512NNIW);
- if (cpi->cpi_std[7].cp_edx &
- CPUID_INTC_EDX_7_0_AVX5124FMAPS)
- add_x86_feature(featureset,
- X86FSET_AVX512FMAPS);
- }
+ cpuid_basic_avx(cpu, featureset);
}
}
@@ -4761,36 +4792,16 @@ cpuid_pass_extended(cpu_t *cpu, void *_arg __unused)
X86FSET_VAES);
remove_x86_feature(x86_featureset,
X86FSET_VPCLMULQDQ);
-
- CPI_FEATURES_ECX(cpi) &=
- ~CPUID_INTC_ECX_XSAVE;
- CPI_FEATURES_ECX(cpi) &=
- ~CPUID_INTC_ECX_AVX;
- CPI_FEATURES_ECX(cpi) &=
- ~CPUID_INTC_ECX_F16C;
- CPI_FEATURES_ECX(cpi) &=
- ~CPUID_INTC_ECX_FMA;
- CPI_FEATURES_7_0_EBX(cpi) &=
- ~CPUID_INTC_EBX_7_0_BMI1;
- CPI_FEATURES_7_0_EBX(cpi) &=
- ~CPUID_INTC_EBX_7_0_BMI2;
- CPI_FEATURES_7_0_EBX(cpi) &=
- ~CPUID_INTC_EBX_7_0_AVX2;
- CPI_FEATURES_7_0_EBX(cpi) &=
- ~CPUID_INTC_EBX_7_0_MPX;
- CPI_FEATURES_7_0_EBX(cpi) &=
- ~CPUID_INTC_EBX_7_0_ALL_AVX512;
-
- CPI_FEATURES_7_0_ECX(cpi) &=
- ~CPUID_INTC_ECX_7_0_ALL_AVX512;
-
- CPI_FEATURES_7_0_ECX(cpi) &=
- ~CPUID_INTC_ECX_7_0_VAES;
- CPI_FEATURES_7_0_ECX(cpi) &=
- ~CPUID_INTC_ECX_7_0_VPCLMULQDQ;
-
- CPI_FEATURES_7_0_EDX(cpi) &=
- ~CPUID_INTC_EDX_7_0_ALL_AVX512;
+ remove_x86_feature(x86_featureset,
+ X86FSET_GFNI);
+ remove_x86_feature(x86_featureset,
+ X86FSET_AVX512_VP2INT);
+ remove_x86_feature(x86_featureset,
+ X86FSET_AVX512_BITALG);
+ remove_x86_feature(x86_featureset,
+ X86FSET_AVX512_VBMI2);
+ remove_x86_feature(x86_featureset,
+ X86FSET_AVX512_BF16);
xsave_force_disable = B_TRUE;
} else {
@@ -5420,11 +5431,93 @@ cpuid_pass_dynamic(cpu_t *cpu, void *_arg __unused)
}
}
+typedef struct {
+ uint32_t avm_av;
+ uint32_t avm_feat;
+} av_feat_map_t;
+
+/*
+ * These arrays are used to map features that we should add based on x86
+ * features that are present. As a large number depend on kernel features,
+ * rather than rechecking and clearing CPUID everywhere, we simply map these.
+ * There is an array of these for each hwcap word. Some features aren't tracked
+ * in the kernel x86 featureset and that's ok. They will not show up in here.
+ */
+static const av_feat_map_t x86fset_to_av1[] = {
+ { AV_386_CX8, X86FSET_CX8 },
+ { AV_386_SEP, X86FSET_SEP },
+ { AV_386_AMD_SYSC, X86FSET_ASYSC },
+ { AV_386_CMOV, X86FSET_CMOV },
+ { AV_386_FXSR, X86FSET_SSE },
+ { AV_386_SSE, X86FSET_SSE },
+ { AV_386_SSE2, X86FSET_SSE2 },
+ { AV_386_SSE3, X86FSET_SSE3 },
+ { AV_386_CX16, X86FSET_CX16 },
+ { AV_386_TSCP, X86FSET_TSCP },
+ { AV_386_AMD_SSE4A, X86FSET_SSE4A },
+ { AV_386_SSSE3, X86FSET_SSSE3 },
+ { AV_386_SSE4_1, X86FSET_SSE4_1 },
+ { AV_386_SSE4_2, X86FSET_SSE4_2 },
+ { AV_386_AES, X86FSET_AES },
+ { AV_386_PCLMULQDQ, X86FSET_PCLMULQDQ },
+ { AV_386_XSAVE, X86FSET_XSAVE },
+ { AV_386_AVX, X86FSET_AVX },
+ { AV_386_VMX, X86FSET_VMX },
+ { AV_386_AMD_SVM, X86FSET_SVM }
+};
+
+static const av_feat_map_t x86fset_to_av2[] = {
+ { AV_386_2_F16C, X86FSET_F16C },
+ { AV_386_2_RDRAND, X86FSET_RDRAND },
+ { AV_386_2_BMI1, X86FSET_BMI1 },
+ { AV_386_2_BMI2, X86FSET_BMI2 },
+ { AV_386_2_FMA, X86FSET_FMA },
+ { AV_386_2_AVX2, X86FSET_AVX2 },
+ { AV_386_2_ADX, X86FSET_ADX },
+ { AV_386_2_RDSEED, X86FSET_RDSEED },
+ { AV_386_2_AVX512F, X86FSET_AVX512F },
+ { AV_386_2_AVX512DQ, X86FSET_AVX512DQ },
+ { AV_386_2_AVX512IFMA, X86FSET_AVX512FMA },
+ { AV_386_2_AVX512PF, X86FSET_AVX512PF },
+ { AV_386_2_AVX512ER, X86FSET_AVX512ER },
+ { AV_386_2_AVX512CD, X86FSET_AVX512CD },
+ { AV_386_2_AVX512BW, X86FSET_AVX512BW },
+ { AV_386_2_AVX512VL, X86FSET_AVX512VL },
+ { AV_386_2_AVX512VBMI, X86FSET_AVX512VBMI },
+ { AV_386_2_AVX512VPOPCDQ, X86FSET_AVX512VPOPCDQ },
+ { AV_386_2_SHA, X86FSET_SHA },
+ { AV_386_2_FSGSBASE, X86FSET_FSGSBASE },
+ { AV_386_2_CLFLUSHOPT, X86FSET_CLFLUSHOPT },
+ { AV_386_2_CLWB, X86FSET_CLWB },
+ { AV_386_2_MONITORX, X86FSET_MONITORX },
+ { AV_386_2_CLZERO, X86FSET_CLZERO },
+ { AV_386_2_AVX512_VNNI, X86FSET_AVX512VNNI },
+ { AV_386_2_VPCLMULQDQ, X86FSET_VPCLMULQDQ },
+ { AV_386_2_VAES, X86FSET_VAES },
+ { AV_386_2_GFNI, X86FSET_GFNI },
+ { AV_386_2_AVX512_VP2INT, X86FSET_AVX512_VP2INT },
+ { AV_386_2_AVX512_BITALG, X86FSET_AVX512_BITALG }
+};
+
+static const av_feat_map_t x86fset_to_av3[] = {
+ { AV_386_3_AVX512_VBMI2, X86FSET_AVX512_VBMI2 },
+ { AV_386_3_AVX512_BF16, X86FSET_AVX512_BF16 }
+};
+
/*
* This routine is called out of bind_hwcap() much later in the life
* of the kernel (post_startup()). The job of this routine is to resolve
* the hardware feature support and kernel support for those features into
* what we're actually going to tell applications via the aux vector.
+ *
+ * Most of the aux vector is derived from the x86_featureset array vector where
+ * a given feature indicates that an aux vector should be plumbed through. This
+ * allows the kernel to use one tracking mechanism for these based on whether or
+ * not it has the required hardware support (most often xsave). Most newer
+ * features are added there in case we need them in the kernel. Otherwise,
+ * features are evaluated based on looking at the cpuid features that remain. If
+ * you find yourself wanting to clear out cpuid features for some reason, they
+ * should instead be driven by the feature set so we have a consistent view.
*/
static void
@@ -5432,65 +5525,42 @@ cpuid_pass_resolve(cpu_t *cpu, void *arg)
{
uint_t *hwcap_out = (uint_t *)arg;
struct cpuid_info *cpi;
- uint_t hwcap_flags = 0, hwcap_flags_2 = 0;
+ uint_t hwcap_flags = 0, hwcap_flags_2 = 0, hwcap_flags_3 = 0;
cpi = cpu->cpu_m.mcpu_cpi;
+ for (uint_t i = 0; i < ARRAY_SIZE(x86fset_to_av1); i++) {
+ if (is_x86_feature(x86_featureset,
+ x86fset_to_av1[i].avm_feat)) {
+ hwcap_flags |= x86fset_to_av1[i].avm_av;
+ }
+ }
+
+ for (uint_t i = 0; i < ARRAY_SIZE(x86fset_to_av2); i++) {
+ if (is_x86_feature(x86_featureset,
+ x86fset_to_av2[i].avm_feat)) {
+ hwcap_flags_2 |= x86fset_to_av2[i].avm_av;
+ }
+ }
+
+ for (uint_t i = 0; i < ARRAY_SIZE(x86fset_to_av3); i++) {
+ if (is_x86_feature(x86_featureset,
+ x86fset_to_av3[i].avm_feat)) {
+ hwcap_flags_3 |= x86fset_to_av3[i].avm_av;
+ }
+ }
+
+ /*
+ * From here on out we're working through features that don't have
+ * corresponding kernel feature flags for various reasons that are
+ * mostly just due to the historical implementation.
+ */
if (cpi->cpi_maxeax >= 1) {
uint32_t *edx = &cpi->cpi_support[STD_EDX_FEATURES];
uint32_t *ecx = &cpi->cpi_support[STD_ECX_FEATURES];
- uint32_t *ebx = &cpi->cpi_support[STD_EBX_FEATURES];
*edx = CPI_FEATURES_EDX(cpi);
*ecx = CPI_FEATURES_ECX(cpi);
- *ebx = CPI_FEATURES_7_0_EBX(cpi);
-
- /*
- * [these require explicit kernel support]
- */
- if (!is_x86_feature(x86_featureset, X86FSET_SEP))
- *edx &= ~CPUID_INTC_EDX_SEP;
-
- if (!is_x86_feature(x86_featureset, X86FSET_SSE))
- *edx &= ~(CPUID_INTC_EDX_FXSR|CPUID_INTC_EDX_SSE);
- if (!is_x86_feature(x86_featureset, X86FSET_SSE2))
- *edx &= ~CPUID_INTC_EDX_SSE2;
-
- if (!is_x86_feature(x86_featureset, X86FSET_HTT))
- *edx &= ~CPUID_INTC_EDX_HTT;
-
- if (!is_x86_feature(x86_featureset, X86FSET_SSE3))
- *ecx &= ~CPUID_INTC_ECX_SSE3;
-
- if (!is_x86_feature(x86_featureset, X86FSET_SSSE3))
- *ecx &= ~CPUID_INTC_ECX_SSSE3;
- if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1))
- *ecx &= ~CPUID_INTC_ECX_SSE4_1;
- if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2))
- *ecx &= ~CPUID_INTC_ECX_SSE4_2;
- if (!is_x86_feature(x86_featureset, X86FSET_AES))
- *ecx &= ~CPUID_INTC_ECX_AES;
- if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ))
- *ecx &= ~CPUID_INTC_ECX_PCLMULQDQ;
- if (!is_x86_feature(x86_featureset, X86FSET_XSAVE))
- *ecx &= ~(CPUID_INTC_ECX_XSAVE |
- CPUID_INTC_ECX_OSXSAVE);
- if (!is_x86_feature(x86_featureset, X86FSET_AVX))
- *ecx &= ~CPUID_INTC_ECX_AVX;
- if (!is_x86_feature(x86_featureset, X86FSET_F16C))
- *ecx &= ~CPUID_INTC_ECX_F16C;
- if (!is_x86_feature(x86_featureset, X86FSET_FMA))
- *ecx &= ~CPUID_INTC_ECX_FMA;
- if (!is_x86_feature(x86_featureset, X86FSET_BMI1))
- *ebx &= ~CPUID_INTC_EBX_7_0_BMI1;
- if (!is_x86_feature(x86_featureset, X86FSET_BMI2))
- *ebx &= ~CPUID_INTC_EBX_7_0_BMI2;
- if (!is_x86_feature(x86_featureset, X86FSET_AVX2))
- *ebx &= ~CPUID_INTC_EBX_7_0_AVX2;
- if (!is_x86_feature(x86_featureset, X86FSET_RDSEED))
- *ebx &= ~CPUID_INTC_EBX_7_0_RDSEED;
- if (!is_x86_feature(x86_featureset, X86FSET_ADX))
- *ebx &= ~CPUID_INTC_EBX_7_0_ADX;
/*
* [no explicit support required beyond x87 fp context]
@@ -5502,113 +5572,17 @@ cpuid_pass_resolve(cpu_t *cpu, void *arg)
* Now map the supported feature vector to things that we
* think userland will care about.
*/
- if (*edx & CPUID_INTC_EDX_SEP)
- hwcap_flags |= AV_386_SEP;
- if (*edx & CPUID_INTC_EDX_SSE)
- hwcap_flags |= AV_386_FXSR | AV_386_SSE;
- if (*edx & CPUID_INTC_EDX_SSE2)
- hwcap_flags |= AV_386_SSE2;
- if (*ecx & CPUID_INTC_ECX_SSE3)
- hwcap_flags |= AV_386_SSE3;
- if (*ecx & CPUID_INTC_ECX_SSSE3)
- hwcap_flags |= AV_386_SSSE3;
- if (*ecx & CPUID_INTC_ECX_SSE4_1)
- hwcap_flags |= AV_386_SSE4_1;
- if (*ecx & CPUID_INTC_ECX_SSE4_2)
- hwcap_flags |= AV_386_SSE4_2;
if (*ecx & CPUID_INTC_ECX_MOVBE)
hwcap_flags |= AV_386_MOVBE;
- if (*ecx & CPUID_INTC_ECX_AES)
- hwcap_flags |= AV_386_AES;
- if (*ecx & CPUID_INTC_ECX_PCLMULQDQ)
- hwcap_flags |= AV_386_PCLMULQDQ;
- if ((*ecx & CPUID_INTC_ECX_XSAVE) &&
- (*ecx & CPUID_INTC_ECX_OSXSAVE)) {
- hwcap_flags |= AV_386_XSAVE;
-
- if (*ecx & CPUID_INTC_ECX_AVX) {
- uint32_t *ecx_7 = &CPI_FEATURES_7_0_ECX(cpi);
- uint32_t *edx_7 = &CPI_FEATURES_7_0_EDX(cpi);
-
- hwcap_flags |= AV_386_AVX;
- if (*ecx & CPUID_INTC_ECX_F16C)
- hwcap_flags_2 |= AV_386_2_F16C;
- if (*ecx & CPUID_INTC_ECX_FMA)
- hwcap_flags_2 |= AV_386_2_FMA;
-
- if (*ebx & CPUID_INTC_EBX_7_0_BMI1)
- hwcap_flags_2 |= AV_386_2_BMI1;
- if (*ebx & CPUID_INTC_EBX_7_0_BMI2)
- hwcap_flags_2 |= AV_386_2_BMI2;
- if (*ebx & CPUID_INTC_EBX_7_0_AVX2)
- hwcap_flags_2 |= AV_386_2_AVX2;
- if (*ebx & CPUID_INTC_EBX_7_0_AVX512F)
- hwcap_flags_2 |= AV_386_2_AVX512F;
- if (*ebx & CPUID_INTC_EBX_7_0_AVX512DQ)
- hwcap_flags_2 |= AV_386_2_AVX512DQ;
- if (*ebx & CPUID_INTC_EBX_7_0_AVX512IFMA)
- hwcap_flags_2 |= AV_386_2_AVX512IFMA;
- if (*ebx & CPUID_INTC_EBX_7_0_AVX512PF)
- hwcap_flags_2 |= AV_386_2_AVX512PF;
- if (*ebx & CPUID_INTC_EBX_7_0_AVX512ER)
- hwcap_flags_2 |= AV_386_2_AVX512ER;
- if (*ebx & CPUID_INTC_EBX_7_0_AVX512CD)
- hwcap_flags_2 |= AV_386_2_AVX512CD;
- if (*ebx & CPUID_INTC_EBX_7_0_AVX512BW)
- hwcap_flags_2 |= AV_386_2_AVX512BW;
- if (*ebx & CPUID_INTC_EBX_7_0_AVX512VL)
- hwcap_flags_2 |= AV_386_2_AVX512VL;
-
- if (*ecx_7 & CPUID_INTC_ECX_7_0_AVX512VBMI)
- hwcap_flags_2 |= AV_386_2_AVX512VBMI;
- if (*ecx_7 & CPUID_INTC_ECX_7_0_AVX512VNNI)
- hwcap_flags_2 |= AV_386_2_AVX512_VNNI;
- if (*ecx_7 & CPUID_INTC_ECX_7_0_AVX512VPOPCDQ)
- hwcap_flags_2 |= AV_386_2_AVX512VPOPCDQ;
- if (*ecx_7 & CPUID_INTC_ECX_7_0_VAES)
- hwcap_flags_2 |= AV_386_2_VAES;
- if (*ecx_7 & CPUID_INTC_ECX_7_0_VPCLMULQDQ)
- hwcap_flags_2 |= AV_386_2_VPCLMULQDQ;
-
- if (*edx_7 & CPUID_INTC_EDX_7_0_AVX5124NNIW)
- hwcap_flags_2 |= AV_386_2_AVX512_4NNIW;
- if (*edx_7 & CPUID_INTC_EDX_7_0_AVX5124FMAPS)
- hwcap_flags_2 |= AV_386_2_AVX512_4FMAPS;
- }
- }
- if (*ecx & CPUID_INTC_ECX_VMX)
- hwcap_flags |= AV_386_VMX;
+
if (*ecx & CPUID_INTC_ECX_POPCNT)
hwcap_flags |= AV_386_POPCNT;
if (*edx & CPUID_INTC_EDX_FPU)
hwcap_flags |= AV_386_FPU;
if (*edx & CPUID_INTC_EDX_MMX)
hwcap_flags |= AV_386_MMX;
-
if (*edx & CPUID_INTC_EDX_TSC)
hwcap_flags |= AV_386_TSC;
- if (*edx & CPUID_INTC_EDX_CX8)
- hwcap_flags |= AV_386_CX8;
- if (*edx & CPUID_INTC_EDX_CMOV)
- hwcap_flags |= AV_386_CMOV;
- if (*ecx & CPUID_INTC_ECX_CX16)
- hwcap_flags |= AV_386_CX16;
-
- if (*ecx & CPUID_INTC_ECX_RDRAND)
- hwcap_flags_2 |= AV_386_2_RDRAND;
- if (*ebx & CPUID_INTC_EBX_7_0_ADX)
- hwcap_flags_2 |= AV_386_2_ADX;
- if (*ebx & CPUID_INTC_EBX_7_0_RDSEED)
- hwcap_flags_2 |= AV_386_2_RDSEED;
- if (*ebx & CPUID_INTC_EBX_7_0_SHA)
- hwcap_flags_2 |= AV_386_2_SHA;
- if (*ebx & CPUID_INTC_EBX_7_0_FSGSBASE)
- hwcap_flags_2 |= AV_386_2_FSGSBASE;
- if (*ebx & CPUID_INTC_EBX_7_0_CLWB)
- hwcap_flags_2 |= AV_386_2_CLWB;
- if (*ebx & CPUID_INTC_EBX_7_0_CLFLUSHOPT)
- hwcap_flags_2 |= AV_386_2_CLFLUSHOPT;
-
}
/* Detect systems with a potential CPUID limit */
@@ -5620,14 +5594,10 @@ cpuid_pass_resolve(cpu_t *cpu, void *arg)
/*
* Check a few miscellaneous features.
*/
- if (is_x86_feature(x86_featureset, X86FSET_CLZERO))
- hwcap_flags_2 |= AV_386_2_CLZERO;
-
if (cpi->cpi_xmaxeax < 0x80000001)
goto resolve_done;
switch (cpi->cpi_vendor) {
- struct cpuid_regs cp;
uint32_t *edx, *ecx;
case X86_VENDOR_Intel:
@@ -5648,27 +5618,6 @@ cpuid_pass_resolve(cpu_t *cpu, void *arg)
*ecx = CPI_FEATURES_XTD_ECX(cpi);
/*
- * [these features require explicit kernel support]
- */
- switch (cpi->cpi_vendor) {
- case X86_VENDOR_Intel:
- if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
- *edx &= ~CPUID_AMD_EDX_TSCP;
- break;
-
- case X86_VENDOR_AMD:
- case X86_VENDOR_HYGON:
- if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
- *edx &= ~CPUID_AMD_EDX_TSCP;
- if (!is_x86_feature(x86_featureset, X86FSET_SSE4A))
- *ecx &= ~CPUID_AMD_ECX_SSE4A;
- break;
-
- default:
- break;
- }
-
- /*
* [no explicit support required beyond
* x87 fp context and exception handlers]
*/
@@ -5676,41 +5625,27 @@ cpuid_pass_resolve(cpu_t *cpu, void *arg)
*edx &= ~(CPUID_AMD_EDX_MMXamd |
CPUID_AMD_EDX_3DNow | CPUID_AMD_EDX_3DNowx);
- if (!is_x86_feature(x86_featureset, X86FSET_NX))
- *edx &= ~CPUID_AMD_EDX_NX;
/*
* Now map the supported feature vector to
* things that we think userland will care about.
*/
- if (*edx & CPUID_AMD_EDX_SYSC)
- hwcap_flags |= AV_386_AMD_SYSC;
if (*edx & CPUID_AMD_EDX_MMXamd)
hwcap_flags |= AV_386_AMD_MMX;
if (*edx & CPUID_AMD_EDX_3DNow)
hwcap_flags |= AV_386_AMD_3DNow;
if (*edx & CPUID_AMD_EDX_3DNowx)
hwcap_flags |= AV_386_AMD_3DNowx;
- if (*ecx & CPUID_AMD_ECX_SVM)
- hwcap_flags |= AV_386_AMD_SVM;
switch (cpi->cpi_vendor) {
case X86_VENDOR_AMD:
case X86_VENDOR_HYGON:
- if (*edx & CPUID_AMD_EDX_TSCP)
- hwcap_flags |= AV_386_TSCP;
if (*ecx & CPUID_AMD_ECX_AHF64)
hwcap_flags |= AV_386_AHF;
- if (*ecx & CPUID_AMD_ECX_SSE4A)
- hwcap_flags |= AV_386_AMD_SSE4A;
if (*ecx & CPUID_AMD_ECX_LZCNT)
hwcap_flags |= AV_386_AMD_LZCNT;
- if (*ecx & CPUID_AMD_ECX_MONITORX)
- hwcap_flags_2 |= AV_386_2_MONITORX;
break;
case X86_VENDOR_Intel:
- if (*edx & CPUID_AMD_EDX_TSCP)
- hwcap_flags |= AV_386_TSCP;
if (*ecx & CPUID_AMD_ECX_LZCNT)
hwcap_flags |= AV_386_AMD_LZCNT;
/*
@@ -5720,18 +5655,11 @@ cpuid_pass_resolve(cpu_t *cpu, void *arg)
if (*ecx & CPUID_INTC_ECX_AHF64)
hwcap_flags |= AV_386_AHF;
break;
-
default:
break;
}
break;
- case X86_VENDOR_TM:
- cp.cp_eax = 0x80860001;
- (void) __cpuid_insn(&cp);
- cpi->cpi_support[TM_EDX_FEATURES] = cp.cp_edx;
- break;
-
default:
break;
}
@@ -5740,6 +5668,7 @@ resolve_done:
if (hwcap_out != NULL) {
hwcap_out[0] = hwcap_flags;
hwcap_out[1] = hwcap_flags_2;
+ hwcap_out[2] = hwcap_flags_3;
}
}
diff --git a/usr/src/uts/intel/os/driver_aliases b/usr/src/uts/intel/os/driver_aliases
index 9499f32aaf..e4e004fe15 100644
--- a/usr/src/uts/intel/os/driver_aliases
+++ b/usr/src/uts/intel/os/driver_aliases
@@ -103,6 +103,25 @@ amdzen_stub "pci1022,1494,p"
amdzen_stub "pci1022,1495,p"
amdzen_stub "pci1022,1496,p"
amdzen_stub "pci1022,1497,p"
+amdzen_stub "pci1022,14a4,p"
+amdzen_stub "pci1022,14ad,p"
+amdzen_stub "pci1022,14ae,p"
+amdzen_stub "pci1022,14af,p"
+amdzen_stub "pci1022,14b0,p"
+amdzen_stub "pci1022,14b1,p"
+amdzen_stub "pci1022,14b2,p"
+amdzen_stub "pci1022,14b3,p"
+amdzen_stub "pci1022,14b4,p"
+amdzen_stub "pci1022,14b5,p"
+amdzen_stub "pci1022,14d8,p"
+amdzen_stub "pci1022,14e0,p"
+amdzen_stub "pci1022,14e1,p"
+amdzen_stub "pci1022,14e2,p"
+amdzen_stub "pci1022,14e3,p"
+amdzen_stub "pci1022,14e4,p"
+amdzen_stub "pci1022,14e5,p"
+amdzen_stub "pci1022,14e6,p"
+amdzen_stub "pci1022,14e7,p"
amdzen_stub "pci1022,15d0,p"
amdzen_stub "pci1022,15e8,p"
amdzen_stub "pci1022,15e9,p"
@@ -129,6 +148,22 @@ amdzen_stub "pci1022,166e,p"
amdzen_stub "pci1022,166f,p"
amdzen_stub "pci1022,1670,p"
amdzen_stub "pci1022,1671,p"
+amdzen_stub "pci1022,1679,p"
+amdzen_stub "pci1022,167a,p"
+amdzen_stub "pci1022,167b,p"
+amdzen_stub "pci1022,167c,p"
+amdzen_stub "pci1022,167d,p"
+amdzen_stub "pci1022,167e,p"
+amdzen_stub "pci1022,167f,p"
+amdzen_stub "pci1022,1680,p"
+amdzen_stub "pci1022,1724,p"
+amdzen_stub "pci1022,1725,p"
+amdzen_stub "pci1022,1726,p"
+amdzen_stub "pci1022,1727,p"
+amdzen_stub "pci1022,1728,p"
+amdzen_stub "pci1022,1729,p"
+amdzen_stub "pci1022,172a,p"
+amdzen_stub "pci1022,172b,p"
amdnbtemp "pci1022,1203,p"
amdnbtemp "pci1022,1303,p"
amdnbtemp "pci1022,1403,p"
diff --git a/usr/src/uts/intel/sys/amdzen/df.h b/usr/src/uts/intel/sys/amdzen/df.h
index 6c1e5b5c79..9e165a3db5 100644
--- a/usr/src/uts/intel/sys/amdzen/df.h
+++ b/usr/src/uts/intel/sys/amdzen/df.h
@@ -147,8 +147,8 @@ typedef enum {
* always zero.
*/
typedef enum {
- DF_CCM_SUBTYPE_CPU = 1,
- DF_CCM_SUBTYPE_ACM = 2
+ DF_CCM_SUBTYPE_CPU = 0,
+ DF_CCM_SUBTYPE_ACM = 1
} df_ccm_subtype_v4_t;
#define DF_FBIINFO0_GET_HAS_MCA(r) bitx32(r, 23, 23)
#define DF_FBIINFO0_GET_FTI_DCNT(r) bitx32(r, 21, 20)
diff --git a/usr/src/uts/intel/sys/amdzen/smn.h b/usr/src/uts/intel/sys/amdzen/smn.h
new file mode 100644
index 0000000000..3f8250a158
--- /dev/null
+++ b/usr/src/uts/intel/sys/amdzen/smn.h
@@ -0,0 +1,461 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2022 Oxide Computer Co.
+ */
+
+#ifndef _SYS_AMDZEN_SMN_H
+#define _SYS_AMDZEN_SMN_H
+
+#include <sys/debug.h>
+#include <sys/types.h>
+
+/*
+ * Generic definitions for the system management network (SMN) in Milan and many
+ * other AMD Zen processors. These are shared between the amdzen nexus and its
+ * client drivers and kernel code that may require SMN access to resources.
+ *
+ * ------------------------
+ * Endpoints and Addressing
+ * ------------------------
+ *
+ * SMN addresses are 36 bits long but in practice we can use only 32. Bits
+ * [35:32] identify a destination node, but all consumers instead direct SMN
+ * transactions to a specific node by selecting the address/data register pair
+ * in the NBIO PCI config space corresponding to the destination. Additional
+ * information about nodes and the organisation of devices in the Zen
+ * architecture may be found in the block comments in amdzen.c and cpuid.c.
+ *
+ * The SMN provides access to instances of various functional units present on
+ * or accessed via each node. Some functional units have only a single instance
+ * per node while others may have many. Each functional unit instance has one
+ * or more apertures in which it decodes addresses. The aperture portion of the
+ * address consists of bits [31:20] and the remainder of the address is used to
+ * specify a register instance within that functional unit. To complicate
+ * matters, some functional units have multiple smaller sub-units that decode
+ * smaller regions within its parent's aperture; in some cases, the bits in a
+ * mask describing the sub-unit's registers may not be contiguous. To keep
+ * software relatively simple, we generally treat sub-units and parent units the
+ * same and try to choose collections of registers whose addresses can all be
+ * computed in the same manner to form what we will describe as a unit.
+ *
+ * Each functional unit should typically have its own header containing register
+ * definitions, accessors, and address calculation routines; some functional
+ * units are small and straightforward while others may have numerous complex
+ * sub-units, registers with many instances whose locations are computed in
+ * unusual and nonstandard ways, and other features that need to be declared for
+ * consumers. Those functional units that are present across many processors
+ * and have similar or identical contents across them should live in this
+ * directory; umc.h is such an example. Others may be specific to a particular
+ * processor family (see cpuid.c) or other collection and may require their own
+ * subdirectories, symbol prefixes, and so on. Unlike the DF, the existence,
+ * location, and format of registers accessible over SMN are not versioned nor
+ * are they generally self-discoverable. Each functional unit may be present or
+ * absent, in varying numbers and with varying functionality, across the entire
+ * Zen product range. Therefore, at this time most per-unit headers are
+ * intended for use only by code that will execute on a specific processor
+ * family. Unifying them over time is considered desirable to the extent the
+ * hardware allows it.
+ *
+ * -----
+ * Types
+ * -----
+ *
+ * Practically every last one of us has screwed up the order of arguments to
+ * functions like amdzen_smn_write32() when they take an address and a value of
+ * the same type. Repeatedly. Often. To safety this particularly annoying
+ * footgun, we pass SMN register addresses around in a dedicated struct type
+ * smn_reg_t, intended to be instantiated only by the amdzen_xx_smn_reg() and
+ * analogous kernel functions and the macros that expand to them or, for the
+ * YOLO crew, SMN_MAKE_REG(). Since the struct type and uint32_t are not
+ * compatible, the compiler will always squawk if the register and value
+ * arguments are reversed, leaving us far fewer baffling failures to debug at
+ * runtime. Typical callers don't require any awareness of this at all, but
+ * those that want to pass the address around to e.g. log warnings can obtain
+ * the uint32_t address via SMN_REG_ADDR().
+ *
+ * Register definitions within functional units are provided by objects of type
+ * `const smn_reg_def_t`, the usage of which is described in detail in the next
+ * section. For now these are produced on demand by macros; see additional
+ * notes on conventions below. In time, this mechanism may be extended to
+ * incorporate version information in a manner similar to that used in df.h. An
+ * automated mechanism for creating a single collection of register and field
+ * definitions for C, in CTF, and/or for other language consumers as well as
+ * automated register value decoding remains an open area for future work.
+ *
+ * -----------------------
+ * Instances and Iterators
+ * -----------------------
+ *
+ * Not only do some functional units have many instances, so too do many
+ * registers. AMD documentation describes registers in terms of a series of
+ * iterators over various functional units, subunits, and other entities and
+ * attributes that each multiply the number of register instances. A concrete
+ * example from the publicly-available Naples PPR (publication 54945 rev. 1.14)
+ * may make this simpler to understand. Unfortunately, SMN is not described by
+ * this document, but the register instance syntax used is the same and is
+ * described in additional detail in sections 1.3.3-4. For our example, let us
+ * consider the same MSR that AMD uses in their own example,
+ * Core::X86::MSR::TSC. We are given that this register has the following
+ * instances: lthree[1:0]_core[3:0]_thread[1:0]. We therefore have three
+ * iterators: one for 'lthree's, one for 'core's for each 'lthree', and one for
+ * 'thread's for each 'core'. We can also see that there are 16 total
+ * instances; in fact, there are actually 16 per core-complex die (CCD), which
+ * documents for more recent processors would expose as a fourth iterator. To
+ * keep things relatively simple, we will assume that there are only 16 per
+ * processor. If it were possible to access all of these instances via MMIO,
+ * SMN, or some other flat address space (it isn't, as far as we can tell), a
+ * function for computing the address of each instance would require three
+ * parameters. Let us suppose that this register really were accessible via
+ * SMN; in that case, we would also be provided with a list of instance alias
+ * such as
+ *
+ * _thread[1:0]_core[7:0]_lthree[1:0]_alias_SMN: THREADREGS[1:0]x0000_0010;
+ * THREADREGS[1:0]=COREREGS[7:0]x0000_[4,0]000;
+ * COREREGS[7:0]=L3REGS[1:0]x000[7:0]_5000; L3REGS[1:0]=57[A,6]0_0000
+ *
+ * To compute the address of an instance of this hypothetical register, we would
+ * begin by determining that its top-level functional unit is L3REGS with a base
+ * aperture at 0x5760_0000. There are two instances of this functional unit (01
+ * and 1) and each subsequent instance is offset 0x40_0000 from the previous.
+ * This allows us to compute the base address of each L3REGS block; a similar
+ * process is then used to compute the base address of each COREREGS block, and
+ * finally the address of each THREADREGS block that contains the register
+ * instance. In practice, we might choose instead to consider the COREREGS as
+ * our functional unit, with instances at 0x5760_5000, 0x5761_5000, 0x57A0_5000,
+ * and 0x57A1_5000; whether it is useful to do this depends on whether we need
+ * to consider other registers in the L3REGS unit that may not have per-core
+ * blocks or instances but would otherwise be interleaved with these. This ends
+ * up being something of a judgment call. Let's suppose we want to consider the
+ * entire L3REGS functional unit and write a function to compute the address of
+ * any register (including our hypothetical TSC) in the subordinate THREADREGS
+ * blocks. We'll start by adding the new unit to the smn_unit_t enumeration;
+ * let's call it SMN_UNIT_L3REGS_COREREGS since that's the sub-unit level at
+ * which we can uniformly compute register instance addresses. We have already
+ * determined our base aperture and we know that we have 3 iterators and
+ * therefore three parameters; all SMN address calculators return an smn_reg_t
+ * and must accept an smn_reg_def_t. Therefore our function's signature is:
+ *
+ * smn_reg_t amdzen_smn_l3regs_coreregs_reg(uint8_t l3no,
+ * const smn_reg_def_t def, uint16_t coreinst, uint16_t threadinst);
+ *
+ * We have chosen to use a base aperture of 0x5760_0000 and unit offset
+ * 0x40_0000, so we can begin by computing a COREREGS aperture:
+ *
+ * const uint32_t aperture_base = 0x57600000;
+ * const uint32_t aperture_off = l3no * 0x400000;
+ * const uint32_t coreregs_aperture_base = 0x5000;
+ * const uint32_t coreregs_aperture_off = coreinst * 0x10000;
+ *
+ * We can now consider the smn_reg_def_t our function will be given, which
+ * describes THREADREGS::TSC. Within the COREREGS functional sub-unit, each
+ * thread register has 2 instances present at a stride of 0x4000 bytes (from our
+ * hypothetical register definition), so the register would be defined as
+ * follows:
+ *
+ * #define D_L3REGS_COREREGS_THREAD_TSC (const smn_reg_def_t){ \
+ * .srd_unit = SMN_UNIT_L3REGS_COREREGS, \
+ * .srd_reg = 0x10, \
+ * .srd_nents = 2, \
+ * .srd_stride = 0x4000 \
+ * }
+ *
+ * Note that describing the number of entries and their stride in the register
+ * definition allows us to collapse the last functional sub-unit in our
+ * calculation process: we need not compute the base aperture address of the
+ * THREADREGS sub-unit. Instead, we can follow our previous code with:
+ *
+ * const uint32_t aperture = aperture_base +
+ * coreregs_aperture_base + coreregs_aperture_off;
+ * const uint32_t reg = def.srd_reg + threadinst * def.srd_stride;
+ *
+ * Finally, we convert the aperture address and register offset into the
+ * appropriate type and return it:
+ *
+ * return (SMN_MAKE_REG(aperture + reg));
+ *
+ * As you can see, other registers in THREADREGS would be defined with the same
+ * number entries and stride but a different offset (srd_reg member), while
+ * other registers in the COREREGS block would have a different offset and
+ * stride. For example, if a block of per-core (not per-thread) registers were
+ * located at COREREGS[7:0]x0000_1000, a register called "COREREGS::FrobberCntl"
+ * in that block with a single instance at offset 0x48 might be defined as
+ *
+ * #define D_L3REGS_COREREGS_FROB_CTL (const smn_reg_def_t){ \
+ * .srd_unit = SMN_UNIT_L3REGS_COREREGS, \
+ * .srd_reg = 0x1048, \
+ * .srd_nents = 1 \
+ * }
+ *
+ * You can satisfy yourself that the same calculation function we wrote above
+ * will correctly compute the address of the sole instance (0) of this register.
+ * To further simplify register definitions and callers, the actual address
+ * calculation functions are written to treat srd_nents == 0 to mean a register
+ * with a single instance, and to treat srd_stride == 0 as if it were 4 (the
+ * space occupied by registers accessed by SMN is -- so far as we can tell,
+ * practically always -- 4 bytes in size, even if the register itself is
+ * smaller). Additionally, a large number of assertions should be present in
+ * such functions to guard against foreign unit register definitions,
+ * out-of-bounds unit and register instance parameters, address overflow, and
+ * register instance offsets that overflow improperly into an aperture base
+ * address. All of these conditions indicate either an incorrect register
+ * definition or a bug in the caller. See the template macro at the bottom of
+ * this file and umc.h for additional examples of calculating and checking
+ * register addresses.
+ *
+ * With address computation out of the way, we can then provide an accessor for
+ * each instance this register:
+ *
+ * #define L3REGS_COREREGS_THREAD_TSC(l3, core, thread) \
+ * amdzen_l3regs_coreregs_reg(l3, D_L3REGS_COREREGS_THREAD_TSC, \
+ * core, thread)
+ *
+ * Our other per-core register's accessor would look like:
+ *
+ * #define L3REGS_COREREGS_FROB_CTL(l3, core) \
+ * amdzen_l3regs_coreregs_reg(l3, D_L3REGS_COREREGS_FROB_CTL, core, 0)
+ *
+ * The next section describes these conventions in greater detail.
+ *
+ * -----------
+ * Conventions
+ * -----------
+ *
+ * First, let's consider the names of the register definition and the
+ * convenience macro supplied to obtain an instance of that register: we've
+ * prefixed the global definition of the registers with D_ and the convenience
+ * macros to return a specific instance are simply named for the register
+ * itself. Additionally, the two macros expand to objects of incompatible
+ * types, so that using the wrong one will always be detected at compile time.
+ * Why do we expose both of these? The instance macro is useful for callers who
+ * know at compile-time the name of the register of which they want instances;
+ * this makes it unnecessary to remember the names of functions used to compute
+ * register instance addresses. The definition itself is useful to callers that
+ * accept const smn_reg_def_t arguments referring to registers of which the
+ * immediate caller does not know the names at compile time.
+ *
+ * You may wonder why we don't declare named constants for the definitions.
+ * There are two ways we could do that and both are unfortunate: one would be to
+ * declare them static in the header, the other to separate declarations in the
+ * header from initialisation in a separate source file. Measurements revealed
+ * that the former causes a very substantial increase in data size, which will
+ * be multiplied by the number of registers defined and the number of source
+ * files including the header. As convenient as it is to have these symbolic
+ * constants available to debuggers and other tools at runtime, they're just too
+ * big. However, it is possible to generate code to be compiled into loadable
+ * modules that would contain a single copy of the constants for this purpose as
+ * well as for providing CTF to foreign-language binding generators. The other
+ * option considered here, putting the constants in separate source files, makes
+ * maintenance significantly more challenging and makes it likely not only that
+ * new registers may not be added properly but also that definitions, macros, or
+ * both may be incorrect. Neither of these options is terrible but for now
+ * we've optimised for simplicity of maintenance and minimal data size at the
+ * immediate but not necessarily permanent expense of some debugging
+ * convenience.
+ *
+ * We wish to standardise as much as possible on conventions across all
+ * Zen-related functional units and blocks (including those accessed by SMN,
+ * through the DF directly, and by other means). In general, some register and
+ * field names are shortened from their official names for clarity and brevity;
+ * the official names are always given in the comment above the definition.
+ * AMD's functional units come from many internal teams and presumably several
+ * outside vendors as well; as a result, there is no single convention to be
+ * found throughout the PPRs and other documentation. For example, different
+ * units may have registers containing "CTL", "CNTL", "CTRL", "CNTRL", and
+ * "CONTROL", as well as "FOO_CNTL", "FooCntl", and "Foo_Cntl". Reflecting
+ * longstanding illumos conventions, we collapse all such register names
+ * regardless of case as follows:
+ *
+ * CTL/CTRL/CNTL/CNTRL/CONTROL => CTL
+ * CFG/CONF/CONFIG/CONFIGURATION => CFG
+ * EN/ENAB/ENABLE/ENABLED => EN
+ * DIS/DISAB/DISABLE/DISABLED => DIS
+ *
+ * Note that if collapsing these would result in ambiguity, more of the official
+ * names will be preserved. In addition to collapsing register and field names
+ * in this case-insensitive manner, we also follow standard code style practice
+ * and name macros and constants in SCREAMING_SNAKE_CASE regardless of AMD's
+ * official name. It is similarly reasonable to truncate or abbreviate other
+ * common terms in a consistent manner where doing so preserves uniqueness and
+ * at least some semantic value; without doing so, some official register names
+ * will be excessively unwieldy and may not even fit into 80 columns. Please
+ * maintain these practices and strive for consistency with existing examples
+ * when abbreviation is required.
+ *
+ * As we have done elsewhere throughout the amdzen body of work, register fields
+ * should always be given in order starting with the most significant bits and
+ * working down toward 0; this matches AMD's documentation and makes it easier
+ * for reviewers and other readers to follow. The routines in bitext.h should
+ * be used to extract and set bitfields unless there is a compelling reason to
+ * do otherwise (e.g., assembly consumers). Accessors should be named
+ * UNIT_REG_GET_FIELD and UNIT_REG_SET_FIELD respectively, unless the register
+ * has a single field that has no meaningful name (i.e., the field's name is the
+ * same as the register's or it's otherwise obvious from the context what its
+ * purpose is), in which case UNIT_REG_GET and UNIT_REG_SET are appropriate.
+ * Additional getters and setters that select a particular bit from a register
+ * or field consisting entirely of individual bits describing or controlling the
+ * state of some entity may also be useful. As with register names, be as brief
+ * as possible without sacrificing too much information.
+ *
+ * Constant values associated with a field should be declared immediately
+ * following that field. If a constant or collection of constants is used in
+ * multiple fields of the same register, the definitions should follow the last
+ * such field; similarly, constants used in multiple registers should follow the
+ * last such register, and a comment explaining the scope of their validity is
+ * recommended. Such constants should be named for the common elements of the
+ * fields or registers in which they are valid.
+ *
+ * As noted above, SMN register definitions should omit the srd_nents and
+ * srd_stride members when there is a single instance of the register within the
+ * unit. The srd_stride member should also be elided when the register
+ * instances are contiguous. All address calculation routines should be written
+ * to support these conventions. Each register should have an accessor macro or
+ * function, and should accept instance numbers in order from superior to
+ * inferior (e.g., from the largest functional unit to the smallest, ending with
+ * the register instance itself). This convention is similar to that used in
+ * generic PCIe code in which a register is specified by bus, device, and
+ * function numbers in that order. Register accessor macros or inline functions
+ * should not expose inapplicable taxons to callers; in our example above,
+ * COREREGS_FROB_CTL has an instance for each core but is not associated with a
+ * thread; therefore its accessor should not accept a thread instance argument
+ * even though the address calculation function it uses does.
+ *
+ * Most of these conventions are not specific to registers accessed via SMN;
+ * note also that some registers may be accessed in multiple ways (e.g., SMN and
+ * MMIO, or SMN and the MSR instructions). While the code here is generally
+ * unaware of such aliased access methods, following these conventions will
+ * simplify naming and usage if such a register needs to be accessed in multiple
+ * ways. Sensible additions to macro and symbol names such as the access method
+ * to be used will generally be sufficient to disambiguate while allowing reuse
+ * of associated field accessors, constants, and in some cases even register
+ * offset, instance count, and stride.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMN_APERTURE_MASK 0xfff00000
+
+/*
+ * An instance of an SMN-accessible register.
+ */
+typedef struct smn_reg {
+ uint32_t sr_addr;
+} smn_reg_t;
+
+/*CSTYLED*/
+#define SMN_MAKE_REG(x) ((const smn_reg_t){ .sr_addr = (x) })
+#define SMN_REG_ADDR(x) ((x).sr_addr)
+
+/*
+ * This exists so that address calculation functions can check that the register
+ * definitions they're passed are something they understand how to use. While
+ * many address calculation functions are similar, some functional units define
+ * registers with multiple iterators, have differently-sized apertures, or both;
+ * it's important that we reject foreign register definitions in these
+ * functions. In principle this could be done at compile time, but the
+ * preprocessor gymnastics required to do so are excessively vile and we are
+ * really already hanging it pretty far over the edge in terms of what the C
+ * preprocessor can do for us.
+ */
+typedef enum smn_unit {
+ SMN_UNIT_UNKNOWN,
+ SMN_UNIT_IOAPIC,
+ SMN_UNIT_IOHC,
+ SMN_UNIT_IOHCDEV_PCIE,
+ SMN_UNIT_IOHCDEV_NBIF,
+ SMN_UNIT_IOHCDEV_SB,
+ SMN_UNIT_IOAGR,
+ SMN_UNIT_SDPMUX,
+ SMN_UNIT_UMC,
+ SMN_UNIT_PCIE_CORE,
+ SMN_UNIT_PCIE_PORT,
+ SMN_UNIT_PCIE_RSMU,
+ SMN_UNIT_SCFCTP,
+ SMN_UNIT_SMUPWR,
+ SMN_UNIT_IOMMUL1,
+ SMN_UNIT_IOMMUL2,
+ SMN_UNIT_NBIF,
+ SMN_UNIT_NBIF_ALT,
+ SMN_UNIT_NBIF_FUNC
+} smn_unit_t;
+
+/*
+ * srd_unit and srd_reg are required; they describe the functional unit and the
+ * register's address within that unit's aperture (which may be the SDP-defined
+ * aperture described above or a smaller one if a unit has been broken down
+ * logically into smaller units). srd_nents is optional; if not set, all
+ * existing consumers assume a value of 0 is equivalent to 1: the register has
+ * but a single instance in each unit. srd_stride is ignored if srd_nents is 0
+ * or 1 and optional otherwise; it describes the number of bytes to be added to
+ * the previous instance's address to obtain that of the next instance. If left
+ * at 0 it is assumed to be 4 bytes.
+ *
+ * There are units in which registers have more complicated collections of
+ * instances that cannot be represented perfectly by this simple descriptor;
+ * they require custom address calculation macros and functions that may take
+ * additional arguments, and they may not be able to check their arguments or
+ * the computed addresses as carefully as would be ideal.
+ */
+typedef struct smn_reg_def {
+ smn_unit_t srd_unit;
+ uint32_t srd_reg;
+ uint32_t srd_stride;
+ uint16_t srd_nents;
+} smn_reg_def_t;
+
+/*
+ * This macro may be used by per-functional-unit code to construct an address
+ * calculation function. It is usable by some, BUT NOT ALL, functional units;
+ * see the block comment above for an example that cannot be accommodated. Here
+ * we assume that there are at most 2 iterators in any register's definition.
+ * Use this when possible, as it provides a large number of useful checks on
+ * DEBUG bits. Similar checks should be incorporated into implementations for
+ * nonstandard functional units to the extent possible.
+ */
+
+#define AMDZEN_MAKE_SMN_REG_FN(_fn, _unit, _base, _mask, _nunits, _unitshift) \
+CTASSERT(((_base) & ~(_mask)) == 0); \
+static inline smn_reg_t \
+_fn(const uint8_t unitno, const smn_reg_def_t def, const uint16_t reginst) \
+{ \
+ const uint32_t unit32 = (const uint32_t)unitno; \
+ const uint32_t reginst32 = (const uint32_t)reginst; \
+ const uint32_t stride = (def.srd_stride == 0) ? 4 : def.srd_stride; \
+ const uint32_t nents = (def.srd_nents == 0) ? 1 : \
+ (const uint32_t)def.srd_nents; \
+ \
+ ASSERT3S(def.srd_unit, ==, SMN_UNIT_ ## _unit); \
+ ASSERT3U(unit32, <, (_nunits)); \
+ ASSERT3U(nents, >, reginst32); \
+ ASSERT0(def.srd_reg & (_mask)); \
+ \
+ const uint32_t aperture_base = (_base); \
+ \
+ const uint32_t aperture_off = (unit32 << (_unitshift)); \
+ ASSERT3U(aperture_off, <=, UINT32_MAX - aperture_base); \
+ \
+ const uint32_t aperture = aperture_base + aperture_off; \
+ ASSERT0(aperture & ~(_mask)); \
+ \
+ const uint32_t reg = def.srd_reg + reginst32 * stride; \
+ ASSERT0(reg & (_mask)); \
+ \
+ return (SMN_MAKE_REG(aperture + reg)); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_AMDZEN_SMN_H */
diff --git a/usr/src/uts/intel/sys/amdzen/umc.h b/usr/src/uts/intel/sys/amdzen/umc.h
index 78644442d4..a06c2021eb 100644
--- a/usr/src/uts/intel/sys/amdzen/umc.h
+++ b/usr/src/uts/intel/sys/amdzen/umc.h
@@ -17,6 +17,7 @@
#define _SYS_UMC_H
#include <sys/bitext.h>
+#include <sys/amdzen/smn.h>
/*
* Various register definitions for accessing the AMD Unified Memory Controller
@@ -75,18 +76,38 @@ extern "C" {
* UMC Channel registers. These are in SMN Space. DDR4 and DDR5 based UMCs share
* the same base address, somewhat surprisingly. This constructs the appropriate
* offset and ensures that a caller doesn't exceed the number of known instances
- * of the register.
+ * of the register. See smn.h for additional details on SMN addressing.
*/
-static inline uint32_t
-amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
- uint32_t reginst)
+
+static inline smn_reg_t
+amdzen_umc_smn_reg(const uint8_t umcno, const smn_reg_def_t def,
+ const uint16_t reginst)
{
- ASSERT3U(umcno, <, 12);
- ASSERT3U(nents, >, reginst);
+ const uint32_t APERTURE_BASE = 0x50000;
+ const uint32_t APERTURE_MASK = 0xffffe000;
+
+ const uint32_t umc32 = (const uint32_t)umcno;
+ const uint32_t reginst32 = (const uint32_t)reginst;
+
+ const uint32_t stride = (def.srd_stride == 0) ? 4 : def.srd_stride;
+ const uint32_t nents = (def.srd_nents == 0) ? 1 :
+ (const uint32_t)def.srd_nents;
+
+ ASSERT3S(def.srd_unit, ==, SMN_UNIT_UMC);
+ ASSERT0(def.srd_reg & APERTURE_MASK);
+ ASSERT3U(umc32, <, 12);
+ ASSERT3U(nents, >, reginst32);
+
+ const uint32_t aperture_off = umc32 << 20;
+ ASSERT3U(aperture_off, <=, UINT32_MAX - APERTURE_BASE);
+
+ const uint32_t aperture = APERTURE_BASE + aperture_off;
+ ASSERT0(aperture & ~APERTURE_MASK);
- uint32_t base = 0x50000;
- uint32_t reg = base_reg + reginst * 4;
- return ((umcno << 20) + base + reg);
+ const uint32_t reg = def.srd_reg + reginst32 * stride;
+ ASSERT0(reg & APERTURE_MASK);
+
+ return (SMN_MAKE_REG(aperture + reg));
}
/*
@@ -94,8 +115,20 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* to match a chip select. Instances 0/1 always refer to DIMM 0, while
* instances 2/3 always refer to DIMM 1.
*/
-#define UMC_BASE(u, i) amdzen_umc_smn_addr(u, 0x00, 4, i)
-#define UMC_BASE_SEC(u, i) amdzen_umc_smn_addr(u, 0x10, 4, i)
+/*CSTYLED*/
+#define D_UMC_BASE (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x00, \
+ .srd_nents = 4 \
+}
+/*CSTYLED*/
+#define D_UMC_BASE_SEC (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x10, \
+ .srd_nents = 4 \
+}
+#define UMC_BASE(u, i) amdzen_umc_smn_reg(u, D_UMC_BASE, i)
+#define UMC_BASE_SEC(u, i) amdzen_umc_smn_reg(u, D_UMC_BASE_SEC, i)
#define UMC_BASE_GET_ADDR(r) bitx32(r, 31, 1)
#define UMC_BASE_ADDR_SHIFT 9
#define UMC_BASE_GET_EN(r) bitx32(r, 0, 0)
@@ -105,8 +138,21 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* registers that allow more address bits. Note, only present in some DDR5
* capable SoCs.
*/
-#define UMC_BASE_EXT_DDR5(u, i) amdzen_umc_smn_addr(u, 0xb00, 4, i)
-#define UMC_BASE_EXT_SEC_DDR5(u, i) amdzen_umc_smn_addr(u, 0xb10, 4, i)
+/*CSTYLED*/
+#define D_UMC_BASE_EXT_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xb00, \
+ .srd_nents = 4 \
+}
+/*CSTYLED*/
+#define D_UMC_BASE_EXT_SEC_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xb10, \
+ .srd_nents = 4 \
+}
+#define UMC_BASE_EXT_DDR5(u, i) amdzen_umc_smn_reg(u, D_UMC_BASE_EXT_DDR5, i)
+#define UMC_BASE_EXT_SEC_DDR5(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_BASE_EXT_SEC_DDR5, i)
#define UMC_BASE_EXT_GET_ADDR(r) bitx32(r, 7, 0)
#define UMC_BASE_EXT_ADDR_SHIFT 40
@@ -116,18 +162,55 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* the incoming address to see it matches the base. Tweaking what is used for
* match is often part of the interleaving strategy.
*/
-#define UMC_MASK_DDR4(u, i) amdzen_umc_smn_addr(u, 0x20, 2, i)
-#define UMC_MASK_SEC_DDR4(u, i) amdzen_umc_smn_addr(u, 0x28, 2, i)
-#define UMC_MASK_DDR5(u, i) amdzen_umc_smn_addr(u, 0x20, 4, i)
-#define UMC_MASK_SEC_DDR5(u, i) amdzen_umc_smn_addr(u, 0x30, 4, i)
+/*CSTYLED*/
+#define D_UMC_MASK_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x20, \
+ .srd_nents = 2 \
+}
+/*CSTYLED*/
+#define D_UMC_MASK_SEC_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x28, \
+ .srd_nents = 2 \
+}
+/*CSTYLED*/
+#define D_UMC_MASK_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x20, \
+ .srd_nents = 4 \
+}
+/*CSTYLED*/
+#define D_UMC_MASK_SEC_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x30, \
+ .srd_nents = 4 \
+}
+#define UMC_MASK_DDR4(u, i) amdzen_umc_smn_reg(u, D_UMC_MASK_DDR4, i)
+#define UMC_MASK_SEC_DDR4(u, i) amdzen_umc_smn_reg(u, D_UMC_MASK_SEC_DDR4, i)
+#define UMC_MASK_DDR5(u, i) amdzen_umc_smn_reg(u, D_UMC_MASK_DDR5, i)
+#define UMC_MASK_SEC_DDR5(u, i) amdzen_umc_smn_reg(u, D_UMC_MASK_SEC_DDR5, i)
#define UMC_MASK_GET_ADDR(r) bitx32(r, 31, 1)
#define UMC_MASK_ADDR_SHIFT 9
/*
* UMC::AddrMaskExt, UMC::AddrMaskSecExt -- Extended mask addresses.
*/
-#define UMC_MASK_EXT_DDR5(u, i) amdzen_umc_smn_addr(u, 0xb20, 4, i)
-#define UMC_MASK_EXT_SEC_DDR5(u, i) amdzen_umc_smn_addr(u, 0xb30, 4, i)
+/*CSTYLED*/
+#define D_UMC_MASK_EXT_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xb20, \
+ .srd_nents = 4 \
+}
+/*CSTYLED*/
+#define D_UMC_MASK_EXT_SEC_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xb30, \
+ .srd_nents = 4 \
+}
+#define UMC_MASK_EXT_DDR5(u, i) amdzen_umc_smn_reg(u, D_UMC_MASK_EXT_DDR5, i)
+#define UMC_MASK_EXT_SEC_DDR5(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_MASK_EXT_SEC_DDR5, i)
#define UMC_MASK_EXT_GET_ADDR(r) bitx32(r, 7, 0)
#define UMC_MASK_EXT_ADDR_SHIFT 40
@@ -140,8 +223,20 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* banks/group you must subtract the number of bank group bits from the total
* number of bank bits.
*/
-#define UMC_ADDRCFG_DDR4(u, i) amdzen_umc_smn_addr(u, 0x30, 2, i)
-#define UMC_ADDRCFG_DDR5(u, i) amdzen_umc_smn_addr(u, 0x40, 4, i)
+/*CSTYLED*/
+#define D_UMC_ADDRCFG_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x30, \
+ .srd_nents = 2 \
+}
+/*CSTYLED*/
+#define D_UMC_ADDRCFG_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x40, \
+ .srd_nents = 4 \
+}
+#define UMC_ADDRCFG_DDR4(u, i) amdzen_umc_smn_reg(u, D_UMC_ADDRCFG_DDR4, i)
+#define UMC_ADDRCFG_DDR5(u, i) amdzen_umc_smn_reg(u, D_UMC_ADDRCFG_DDR5, i)
#define UMC_ADDRCFG_GET_NBANK_BITS(r) bitx32(r, 21, 20)
#define UMC_ADDRCFG_NBANK_BITS_BASE 3
#define UMC_ADDRCFG_GET_NCOL_BITS(r) bitx32(r, 19, 16)
@@ -161,8 +256,20 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* which bits in the normalized address are used to construct the bank number,
* row bits are contiguous from the starting number.
*/
-#define UMC_ADDRSEL_DDR4(u, i) amdzen_umc_smn_addr(u, 0x40, 2, i)
-#define UMC_ADDRSEL_DDR5(u, i) amdzen_umc_smn_addr(u, 0x50, 4, i)
+/*CSTYLED*/
+#define D_UMC_ADDRSEL_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x40, \
+ .srd_nents = 2 \
+}
+/*CSTYLED*/
+#define D_UMC_ADDRSEL_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x50, \
+ .srd_nents = 4 \
+}
+#define UMC_ADDRSEL_DDR4(u, i) amdzen_umc_smn_reg(u, D_UMC_ADDRSEL_DDR4, i)
+#define UMC_ADDRSEL_DDR5(u, i) amdzen_umc_smn_reg(u, D_UMC_ADDRSEL_DDR5, i)
#define UMC_ADDRSEL_GET_ROW_LO(r) bitx32(r, 27, 24)
#define UMC_ADDRSEL_ROW_LO_BASE 12
#define UMC_ADDRSEL_GET_BANK4(r) bitx32(r, 19, 16)
@@ -181,20 +288,43 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* the case of DDR4, it's 0x50, 0x54 for DIMM 0 lo, hi. Then 0x58, 0x5c for
* DIMM1. DDR5 based entries do something similar; however, instead of being
* per-DIMM, there is one of these for each CS.
- *
- * This leads to a somewhat odder construction for the maximum number of
- * instances. Because amdzen_umc_smn_addr() assumes each register instance is 4
- * bytes apart, we instead take the actual register instance and multiply it by
- * 2. This means that in the DDR4 case we will always access what
- * amdzen_umc_smn_addr() considers instance 0 and 2. In the DDR5 case this is 0,
- * 2, 4, and 6. This means our maximum instance for both cases has to be one
- * higher than this, 3 and 7 respectively. While technically you could use 4 and
- * 8, this is a tighter bind.
*/
-#define UMC_COLSEL_LO_DDR4(u, i) amdzen_umc_smn_addr(u, 0x50, 3, i * 2)
-#define UMC_COLSEL_HI_DDR4(u, i) amdzen_umc_smn_addr(u, 0x54, 3, i * 2)
-#define UMC_COLSEL_LO_DDR5(u, i) amdzen_umc_smn_addr(u, 0x60, 7, i * 2)
-#define UMC_COLSEL_HI_DDR5(u, i) amdzen_umc_smn_addr(u, 0x64, 7, i * 2)
+/*CSTYLED*/
+#define D_UMC_COLSEL_LO_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x50, \
+ .srd_nents = 2, \
+ .srd_stride = 8 \
+}
+/*CSTYLED*/
+#define D_UMC_COLSEL_HI_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x54, \
+ .srd_nents = 2, \
+ .srd_stride = 8 \
+}
+/*CSTYLED*/
+#define D_UMC_COLSEL_LO_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x60, \
+ .srd_nents = 4, \
+ .srd_stride = 8 \
+}
+/*CSTYLED*/
+#define D_UMC_COLSEL_HI_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x64, \
+ .srd_nents = 4, \
+ .srd_stride = 8 \
+}
+#define UMC_COLSEL_LO_DDR4(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_COLSEL_LO_DDR4, i)
+#define UMC_COLSEL_HI_DDR4(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_COLSEL_HI_DDR4, i)
+#define UMC_COLSEL_LO_DDR5(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_COLSEL_LO_DDR5, i)
+#define UMC_COLSEL_HI_DDR5(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_COLSEL_HI_DDR5, i)
#define UMC_COLSEL_REMAP_GET_COL(r, x) bitx32(r, (3 + (4 * (x))), (4 * ((x))))
#define UMC_COLSEL_LO_BASE 2
@@ -210,8 +340,21 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* In general, APUs have some of the MSBS (most significant bit swap) related
* fields; however, they do not have rank multiplication bits.
*/
-#define UMC_RMSEL_DDR4(u, i) amdzen_umc_smn_addr(u, 0x70, 2, i)
-#define UMC_RMSEL_SEC_DDR4(u, i) amdzen_umc_smn_addr(u, 0x78, 2, i)
+/*CSTYLED*/
+#define D_UMC_RMSEL_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x70, \
+ .srd_nents = 2 \
+}
+/*CSTYLED*/
+#define D_UMC_RMSEL_SEC_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x78, \
+ .srd_nents = 2 \
+}
+#define UMC_RMSEL_DDR4(u, i) amdzen_umc_smn_reg(u, D_UMC_RMSEL_DDR4, i)
+#define UMC_RMSEL_SEC_DDR4(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_RMSEL_SEC_DDR4, i)
#define UMC_RMSEL_DDR4_GET_INV_MSBO(r) bitx32(r, 19, 18)
#define UMC_RMSEL_DDR4_GET_INV_MSBE(r) bitx32(r, 17, 16)
#define UMC_RMSEL_DDR4_GET_RM2(r) bitx32(r, 11, 8)
@@ -219,7 +362,13 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
#define UMC_RMSEL_DDR4_GET_RM0(r) bitx32(r, 3, 0)
#define UMC_RMSEL_BASE 12
-#define UMC_RMSEL_DDR5(u, i) amdzen_umc_smn_addr(u, 0x80, 4, i)
+/*CSTYLED*/
+#define D_UMC_RMSEL_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x80, \
+ .srd_nents = 4 \
+}
+#define UMC_RMSEL_DDR5(u, i) amdzen_umc_smn_reg(u, D_UMC_RMSEL_DDR5, i)
#define UMC_RMSEL_DDR5_GET_INV_MSBS_SEC(r) bitx32(r, 31, 30)
#define UMC_RMSEL_DDR5_GET_INV_MSBS(r) bitx32(r, 29, 28)
#define UMC_RMSEL_DDR5_GET_SUBCHAN(r) bitx32(r, 19, 16)
@@ -234,8 +383,20 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* UMC::CH::DimmCfg -- This describes several properties of the DIMM that is
* installed, such as its overall width or type.
*/
-#define UMC_DIMMCFG_DDR4(u, i) amdzen_umc_smn_addr(u, 0x80, 2, i)
-#define UMC_DIMMCFG_DDR5(u, i) amdzen_umc_smn_addr(u, 0x90, 2, i)
+/*CSTYLED*/
+#define D_UMC_DIMMCFG_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x80, \
+ .srd_nents = 2 \
+}
+/*CSTYLED*/
+#define D_UMC_DIMMCFG_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x90, \
+ .srd_nents = 2 \
+}
+#define UMC_DIMMCFG_DDR4(u, i) amdzen_umc_smn_reg(u, D_UMC_DIMMCFG_DDR4, i)
+#define UMC_DIMMCFG_DDR5(u, i) amdzen_umc_smn_reg(u, D_UMC_DIMMCFG_DDR5, i)
#define UMC_DIMMCFG_GET_PKG_RALIGN(r) bitx32(r, 10, 10)
#define UMC_DIMMCFG_GET_REFRESH_DIS(r) bitx32(r, 9, 9)
#define UMC_DIMMCFG_GET_DQ_SWAP_DIS(r) bitx32(r, 8, 8)
@@ -258,8 +419,22 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* UMC::CH::AddrHashBank -- These registers contain various instructions about
* how to hash an address across a bank to influence which bank is used.
*/
-#define UMC_BANK_HASH_DDR4(u, i) amdzen_umc_smn_addr(u, 0xc8, 5, i)
-#define UMC_BANK_HASH_DDR5(u, i) amdzen_umc_smn_addr(u, 0x98, 5, i)
+/*CSTYLED*/
+#define D_UMC_BANK_HASH_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xc8, \
+ .srd_nents = 5 \
+}
+/*CSTYLED*/
+#define D_UMC_BANK_HASH_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x98, \
+ .srd_nents = 5 \
+}
+#define UMC_BANK_HASH_DDR4(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_BANK_HASH_DDR4, i)
+#define UMC_BANK_HASH_DDR5(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_BANK_HASH_DDR5, i)
#define UMC_BANK_HASH_GET_ROW(r) bitx32(r, 31, 14)
#define UMC_BANK_HASH_GET_COL(r) bitx32(r, 13, 1)
#define UMC_BANK_HASH_GET_EN(r) bitx32(r, 0, 0)
@@ -269,8 +444,22 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* address when trying to do rank hashing. Note, instance 3 is is reserved in
* DDR5 modes.
*/
-#define UMC_RANK_HASH_DDR4(u, i) amdzen_umc_smn_addr(u, 0xdc, 3, i)
-#define UMC_RANK_HASH_DDR5(u, i) amdzen_umc_smn_addr(u, 0xb0, 4, i)
+/*CSTYLED*/
+#define D_UMC_RANK_HASH_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xdc, \
+ .srd_nents = 3 \
+}
+/*CSTYLED*/
+#define D_UMC_RANK_HASH_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xb0, \
+ .srd_nents = 4 \
+}
+#define UMC_RANK_HASH_DDR4(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_RANK_HASH_DDR4, i)
+#define UMC_RANK_HASH_DDR5(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_RANK_HASH_DDR5, i)
#define UMC_RANK_HASH_GET_ADDR(r) bitx32(r, 31, 1)
#define UMC_RANK_HASH_SHIFT 9
#define UMC_RANK_HASH_GET_EN(r) bitx32(r, 0, 0)
@@ -278,7 +467,14 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
/*
* UMC::AddrHashRMExt -- Extended rank hash addresses.
*/
-#define UMC_RANK_HASH_EXT_DDR5(u, i) amdzen_umc_smn_addr(u, 0xbb0, 4, i)
+/*CSTYLED*/
+#define D_UMC_RANK_HASH_EXT_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xbb0, \
+ .srd_nents = 4 \
+}
+#define UMC_RANK_HASH_EXT_DDR5(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_RANK_HASH_EXT_DDR5, i)
#define UMC_RANK_HASH_EXT_GET_ADDR(r) bitx32(r, 7, 0)
#define UMC_RANK_HASH_EXT_ADDR_SHIFT 40
@@ -288,10 +484,20 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* upper two rank hash registers defined above because on the systems where this
* occurs for DDR4, they only have up to one rank hash.
*/
+/*CSTYLED*/
+#define D_UMC_PC_HASH_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xc0 \
+}
+/*CSTYLED*/
+#define D_UMC_PC_HASH2_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xc4 \
+}
#define UMC_PC_HASH_DDR4(u) UMC_RANK_HASH_DDR4(u, 1)
#define UMC_PC_HASH2_DDR4(u) UMC_RANK_HASH_DDR4(u, 2)
-#define UMC_PC_HASH_DDR5(u) amdzen_umc_smn_addr(u, 0xc0, 1, 0)
-#define UMC_PC_HASH2_DDR5(u) amdzen_umc_smn_addr(u, 0xc4, 1, 0)
+#define UMC_PC_HASH_DDR5(u) amdzen_umc_smn_reg(u, D_UMC_PC_HASH_DDR5, 0)
+#define UMC_PC_HASH2_DDR5(u) amdzen_umc_smn_reg(u, D_UMC_PC_HASH2_DDR5, 0)
#define UMC_PC_HASH_GET_ROW(r) bitx32(r, 31, 14)
#define UMC_PC_HASH_GET_COL(r) bitx32(r, 13, 1)
#define UMC_PC_HASH_GET_EN(r) bitx32(r, 0, 0)
@@ -301,8 +507,20 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* UMC::CH::AddrHashCS -- Hashing: chip-select edition. Note, these can
* ultimately cause you to change which DIMM is being actually accessed.
*/
-#define UMC_CS_HASH_DDR4(u, i) amdzen_umc_smn_addr(u, 0xe8, 2, i)
-#define UMC_CS_HASH_DDR5(u, i) amdzen_umc_smn_addr(u, 0xc8, 2, i)
+/*CSTYLED*/
+#define D_UMC_CS_HASH_DDR4 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xe8, \
+ .srd_nents = 2 \
+}
+/*CSTYLED*/
+#define D_UMC_CS_HASH_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xc8, \
+ .srd_nents = 2 \
+}
+#define UMC_CS_HASH_DDR4(u, i) amdzen_umc_smn_reg(u, D_UMC_CS_HASH_DDR4, i)
+#define UMC_CS_HASH_DDR5(u, i) amdzen_umc_smn_reg(u, D_UMC_CS_HASH_DDR5, i)
#define UMC_CS_HASH_GET_ADDR(r) bitx32(r, 31, 1)
#define UMC_CS_HASH_SHIFT 9
#define UMC_CS_HASH_GET_EN(r) bitx32(r, 0, 0)
@@ -310,7 +528,14 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
/*
* UMC::AddrHashExtCS -- Extended chip-select hash addresses.
*/
-#define UMC_CS_HASH_EXT_DDR5(u, i) amdzen_umc_smn_addr(u, 0xbc8, 2, i)
+/*CSTYLED*/
+#define D_UMC_CS_HASH_EXT_DDR5 (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xbc8, \
+ .srd_nents = 2 \
+}
+#define UMC_CS_HASH_EXT_DDR5(u, i) \
+ amdzen_umc_smn_reg(u, D_UMC_CS_HASH_EXT_DDR5, i)
#define UMC_CS_HASH_EXT_GET_ADDR(r) bitx32(r, 7, 0)
#define UMC_CS_HASH_EXT_ADDR_SHIFT 40
@@ -319,7 +544,12 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* For our purposes we mostly care about seeing if ECC is enabled and a DIMM
* type.
*/
-#define UMC_UMCCFG(u) amdzen_umc_smn_addr(u, 0x100, 1, 0)
+/*CSTYLED*/
+#define D_UMC_UMCCFG (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x100 \
+}
+#define UMC_UMCCFG(u) amdzen_umc_smn_reg(u, D_UMC_UMCCFG, 0)
#define UMC_UMCCFG_GET_READY(r) bitx32(r, 31, 31)
#define UMC_UMCCFG_GET_ECC_EN(r) bitx32(r, 12, 12)
#define UMC_UMCCFG_GET_BURST_CTL(r) bitx32(r, 11, 10)
@@ -338,7 +568,12 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* scrambling is enabled. Note, this register really changes a bunch from family
* to family.
*/
-#define UMC_DATACTL(u) amdzen_umc_smn_addr(u, 0x144, 1, 0)
+/*CSTYLED*/
+#define D_UMC_DATACTL (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x144 \
+}
+#define UMC_DATACTL(u) amdzen_umc_smn_reg(u, D_UMC_DATACTL, 0)
#define UMC_DATACTL_GET_ENCR_EN(r) bitx32(r, 8, 8)
#define UMC_DATACTL_GET_SCRAM_EN(r) bitx32(r, 0, 0)
@@ -353,7 +588,12 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
/*
* UMC::CH:EccCtrl -- Various settings around how ECC operates.
*/
-#define UMC_ECCCTL(u) amdzen_umc_smn_addr(u, 0x14c, 1, 0)
+/*CSTYLED*/
+#define D_UMC_ECCCTL (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0x14c \
+}
+#define UMC_ECCCTL(u) amdzen_umc_smn_reg(u, D_UMC_ECCCTL, 0)
#define UMC_ECCCTL_GET_RD_EN(r) bitx32(x, 10, 10)
#define UMC_ECCCTL_GET_X16(r) bitx32(x, 9, 9)
#define UMC_ECCCTL_GET_UC_FATAL(r) bitx32(x, 8, 8)
@@ -368,9 +608,9 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* systems, this is not always present on every SoC and seems to depend on
* something else inside the chip.
*/
-#define UMC_ECCCTL_DDR_GET_PI(r) bitx32(r, 13, 13)
-#define UMC_ECCCTL_DDR_GET_PF_DIS(r) bitx32(r, 12, 12)
-#define UMC_ECCCTL_DDR_GET_SDP_OVR(r) bitx32(x, 11, 11)
+#define UMC_ECCCTL_DDR_GET_PI(r) bitx32(r, 13, 13)
+#define UMC_ECCCTL_DDR_GET_PF_DIS(r) bitx32(r, 12, 12)
+#define UMC_ECCCTL_DDR_GET_SDP_OVR(r) bitx32(x, 11, 11)
#define UMC_ECCCTL_DDR_GET_REPLAY_EN(r) bitx32(x, 1, 1)
#define UMC_ECCCTL_DDR5_GET_PIN_RED(r) bitx32(r, 14, 14)
@@ -380,8 +620,18 @@ amdzen_umc_smn_addr(uint8_t umcno, uint32_t base_reg, uint32_t nents,
* feature disables. We mostly just record these for future us for debugging
* purposes. They aren't used as part of memory decoding.
*/
-#define UMC_UMCCAP(u) amdzen_umc_smn_addr(u, 0xdf0, 1, 0)
-#define UMC_UMCCAP_HI(u) amdzen_umc_smn_addr(u, 0xdf4, 1, 0)
+/*CSTYLED*/
+#define D_UMC_UMCCAP (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xdf0 \
+}
+/*CSTYLED*/
+#define D_UMC_UMCCAP_HI (const smn_reg_def_t){ \
+ .srd_unit = SMN_UNIT_UMC, \
+ .srd_reg = 0xdf4 \
+}
+#define UMC_UMCCAP(u) amdzen_umc_smn_reg(u, D_UMC_UMCCAP, 0)
+#define UMC_UMCCAP_HI(u) amdzen_umc_smn_reg(u, D_UMC_UMCCAP_HI, 0)
#ifdef __cplusplus
}
diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h
index 8202ab3fd0..d1155bc84e 100644
--- a/usr/src/uts/intel/sys/x86_archext.h
+++ b/usr/src/uts/intel/sys/x86_archext.h
@@ -282,7 +282,7 @@ extern "C" {
#define CPUID_INTC_EBX_7_0_BMI1 0x00000008 /* BMI1 instrs */
#define CPUID_INTC_EBX_7_0_HLE 0x00000010 /* HLE */
#define CPUID_INTC_EBX_7_0_AVX2 0x00000020 /* AVX2 supported */
-/* Bit 6 is reserved */
+#define CPUID_INTC_EBX_7_0_FDP_EXCPN 0x00000040 /* FDP on exception */
#define CPUID_INTC_EBX_7_0_SMEP 0x00000080 /* SMEP in CR4 */
#define CPUID_INTC_EBX_7_0_BMI2 0x00000100 /* BMI2 instrs */
#define CPUID_INTC_EBX_7_0_ENH_REP_MOV 0x00000200 /* Enhanced REP MOVSB */
@@ -322,25 +322,27 @@ extern "C" {
#define CPUID_INTC_ECX_7_0_OSPKE 0x00000010 /* OSPKE */
#define CPUID_INTC_ECX_7_0_WAITPKG 0x00000020 /* WAITPKG */
#define CPUID_INTC_ECX_7_0_AVX512VBMI2 0x00000040 /* AVX512 VBMI2 */
-/* bit 7 is reserved */
+#define CPUID_INTC_ECX_7_0_CET_SS 0x00000080 /* CET Shadow Stack */
#define CPUID_INTC_ECX_7_0_GFNI 0x00000100 /* GFNI */
#define CPUID_INTC_ECX_7_0_VAES 0x00000200 /* VAES */
#define CPUID_INTC_ECX_7_0_VPCLMULQDQ 0x00000400 /* VPCLMULQDQ */
#define CPUID_INTC_ECX_7_0_AVX512VNNI 0x00000800 /* AVX512 VNNI */
#define CPUID_INTC_ECX_7_0_AVX512BITALG 0x00001000 /* AVX512 BITALG */
-/* bit 13 is reserved */
+#define CPUID_INTC_ECX_7_0_TME_EN 0x00002000 /* Total Memory Encr. */
#define CPUID_INTC_ECX_7_0_AVX512VPOPCDQ 0x00004000 /* AVX512 VPOPCNTDQ */
-/* bits 15-16 are reserved */
+/* bit 15 is reserved */
+#define CPUID_INTC_ECX_7_0_LA57 0x00010000 /* 57-bit paging */
/* bits 17-21 are the value of MAWAU */
#define CPUID_INTC_ECX_7_0_RDPID 0x00400000 /* RPID, IA32_TSC_AUX */
-/* bits 23-24 are reserved */
+#define CPUID_INTC_ECX_7_0_KLSUP 0x00800000 /* Key Locker */
+/* bit 24 is reserved */
#define CPUID_INTC_ECX_7_0_CLDEMOTE 0x02000000 /* Cache line demote */
/* bit 26 is resrved */
#define CPUID_INTC_ECX_7_0_MOVDIRI 0x08000000 /* MOVDIRI insn */
#define CPUID_INTC_ECX_7_0_MOVDIR64B 0x10000000 /* MOVDIR64B insn */
-/* bit 29 is reserved */
+#define CPUID_INTC_ECX_7_0_ENQCMD 0x20000000 /* Enqueue Stores */
#define CPUID_INTC_ECX_7_0_SGXLC 0x40000000 /* SGX Launch config */
-/* bit 31 is reserved */
+#define CPUID_INTC_ECX_7_0_PKS 0x80000000 /* protection keys */
/*
* While CPUID_INTC_ECX_7_0_GFNI, CPUID_INTC_ECX_7_0_VAES, and
@@ -356,11 +358,24 @@ extern "C" {
#define CPUID_INTC_EDX_7_0_AVX5124NNIW 0x00000004 /* AVX512 4NNIW */
#define CPUID_INTC_EDX_7_0_AVX5124FMAPS 0x00000008 /* AVX512 4FMAPS */
#define CPUID_INTC_EDX_7_0_FSREPMOV 0x00000010 /* fast short rep mov */
-/* bits 5-9 are reserved */
+#define CPUID_INTC_EDX_7_0_UINTR 0x00000020 /* user interrupts */
+/* bits 6-7 are reserved */
+#define CPUID_INTC_EDX_7_0_AVX512VP2INT 0x00000100 /* VP2INTERSECT */
+/* bit 9 is reserved */
#define CPUID_INTC_EDX_7_0_MD_CLEAR 0x00000400 /* MB VERW */
-/* bits 11-17 are reserved */
+/* bits 11-13 are reserved */
+#define CPUID_INTC_EDX_7_0_SERIALIZE 0x00004000 /* Serialize instr */
+#define CPUID_INTC_EDX_7_0_HYBRID 0x00008000 /* Hybrid CPU */
+#define CPUID_INTC_EDX_7_0_TSXLDTRK 0x00010000 /* TSX load track */
+/* bit 17 is reserved */
#define CPUID_INTC_EDX_7_0_PCONFIG 0x00040000 /* PCONFIG */
-/* bits 19-26 are reserved */
+/* bit 19 is reserved */
+#define CPUID_INTC_EDX_7_0_CET_IBT 0x00100000 /* CET ind. branch */
+/* bit 21 is reserved */
+#define CPUID_INTC_EDX_7_0_AMX_BF16 0x00400000 /* Tile F16 */
+#define CPUID_INTC_EDX_7_0_AVX512FP16 0x00800000 /* AVX512 FP16 */
+#define CPUID_INTC_EDX_7_0_AMX_TILE 0x01000000 /* Tile arch */
+#define CPUID_INTC_EDX_7_0_AMX_INT8 0x02000000 /* Tile INT8 */
#define CPUID_INTC_EDX_7_0_SPEC_CTRL 0x04000000 /* Spec, IBPB, IBRS */
#define CPUID_INTC_EDX_7_0_STIBP 0x08000000 /* STIBP */
#define CPUID_INTC_EDX_7_0_FLUSH_CMD 0x10000000 /* IA32_FLUSH_CMD */
@@ -368,7 +383,21 @@ extern "C" {
#define CPUID_INTC_EDX_7_0_SSBD 0x80000000 /* SSBD */
#define CPUID_INTC_EDX_7_0_ALL_AVX512 \
- (CPUID_INTC_EDX_7_0_AVX5124NNIW | CPUID_INTC_EDX_7_0_AVX5124FMAPS)
+ (CPUID_INTC_EDX_7_0_AVX5124NNIW | CPUID_INTC_EDX_7_0_AVX5124FMAPS | \
+ CPUID_INTC_EDX_7_0_AVX512VP2INT | CPUID_INTC_EDX_7_0_AVX512FP16)
+
+/* bits 0-3 are reserved */
+#define CPUID_INTC_EAX_7_1_AVXVNNI 0x00000010 /* VEX VNNI */
+#define CPUID_INTC_EAX_7_1_AVX512_BF16 0x00000020 /* AVX512 BF16 */
+/* bits 6-9 are reserved */
+#define CPUID_INTC_EAX_7_1_ZL_MOVSB 0x00000400 /* zero-length MOVSB */
+#define CPUID_INTC_EAX_7_1_FS_STOSB 0x00000800 /* fast short STOSB */
+#define CPUID_INTC_EAX_7_1_FS_CMPSB 0x00001000 /* fast CMPSB, SCASB */
+/* bits 13-21 are reserved */
+#define CPUID_INTC_EAX_7_1_HRESET 0x00400000 /* History Reset leaf */
+/* bits 23-25 are reserved */
+#define CPUID_INTC_EAX_7_1_LAM 0x02000000 /* Linear addr mask */
+/* bits 27-31 are reserved */
/*
* Intel also uses cpuid leaf 0xd to report additional instructions and features
@@ -762,6 +791,11 @@ extern "C" {
#define X86FSET_VAES 100
#define X86FSET_VPCLMULQDQ 101
#define X86FSET_LFENCE_SER 102
+#define X86FSET_GFNI 103
+#define X86FSET_AVX512_VP2INT 104
+#define X86FSET_AVX512_BITALG 105
+#define X86FSET_AVX512_VBMI2 106
+#define X86FSET_AVX512_BF16 107
/*
* Intel Deep C-State invariant TSC in leaf 0x80000007.
@@ -1349,7 +1383,7 @@ typedef enum x86_uarchrev {
#if defined(_KERNEL) || defined(_KMEMUSER)
-#define NUM_X86_FEATURES 103
+#define NUM_X86_FEATURES 108
extern uchar_t x86_featureset[];
extern void free_x86_featureset(void *featureset);