diff options
author | Dan McDonald <danmcd@mnx.io> | 2022-09-12 13:07:56 -0400 |
---|---|---|
committer | Dan McDonald <danmcd@mnx.io> | 2022-09-12 13:07:56 -0400 |
commit | 920ee8aa55ad6d75d178844ba75e28ef7f3010ca (patch) | |
tree | 1f9c5497c4e5423aaa8467c001caf1fbd4828e05 /usr/src | |
parent | ade9f3397df3a9ce9857bfb480ae00df04ce9933 (diff) | |
parent | f8e9c7b3ba7100b047717589235b6d05ec43646c (diff) | |
download | illumos-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')
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); |