diff options
author | Hans Rosenfeld <hans.rosenfeld@joyent.com> | 2018-07-16 09:03:51 +0000 |
---|---|---|
committer | Patrick Mooney <pmooney@pfmooney.com> | 2020-05-22 14:27:14 +0000 |
commit | eb9a1df2aeb866bf1de4494433b6d7e5fa07b3ae (patch) | |
tree | f9cc894879d944a84aa3e16bfabc9e16a4fcaf6b /usr/src/lib/libppt | |
parent | 3c5f2a9de9c6554ce899ad4ebf7978ea7293994a (diff) | |
download | illumos-gate-eb9a1df2aeb866bf1de4494433b6d7e5fa07b3ae.tar.gz |
12680 want PCI pass-thru in bhyve
Portions contributed by: Patrick Mooney <patrick.mooney@joyent.com>
Portions contributed by: John Levon <john.levon@joyent.com>
Portions contributed by: Andy Fiddaman <omnios@citrus-it.co.uk>
Reviewed by: Patrick Mooney <pmooney@oxide.computer>
Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/lib/libppt')
-rw-r--r-- | usr/src/lib/libppt/Makefile | 44 | ||||
-rw-r--r-- | usr/src/lib/libppt/Makefile.com | 46 | ||||
-rw-r--r-- | usr/src/lib/libppt/amd64/Makefile | 19 | ||||
-rw-r--r-- | usr/src/lib/libppt/common/libppt.c | 506 | ||||
-rw-r--r-- | usr/src/lib/libppt/common/libppt.h | 36 | ||||
-rw-r--r-- | usr/src/lib/libppt/common/llib-lppt | 19 | ||||
-rw-r--r-- | usr/src/lib/libppt/common/mapfile-vers | 40 | ||||
-rw-r--r-- | usr/src/lib/libppt/i386/Makefile | 18 | ||||
-rw-r--r-- | usr/src/lib/libppt/sparc/Makefile | 18 | ||||
-rw-r--r-- | usr/src/lib/libppt/sparcv9/Makefile | 19 |
10 files changed, 765 insertions, 0 deletions
diff --git a/usr/src/lib/libppt/Makefile b/usr/src/lib/libppt/Makefile new file mode 100644 index 0000000000..21c26d447e --- /dev/null +++ b/usr/src/lib/libppt/Makefile @@ -0,0 +1,44 @@ +# +# 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 2018 Joyent, Inc. +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS = $(MACH) $(BUILD64) $(MACH64) + +HDRS = libppt.h +HDRDIR = common + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +install_h: $(ROOTHDRS) + +all install: install_h + +check: $(CHECKHDRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libppt/Makefile.com b/usr/src/lib/libppt/Makefile.com new file mode 100644 index 0000000000..7b2ff4885f --- /dev/null +++ b/usr/src/lib/libppt/Makefile.com @@ -0,0 +1,46 @@ +# +# 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 2018 Joyent, Inc. +# + +LIBRARY = libppt.a +VERS = .1 + +OBJECTS = libppt.o + +include $(SRC)/lib/Makefile.lib + +SRCDIR = ../common + +LIBS = $(DYNLIB) $(LINTLIB) +SRCS = $(SRCDIR)/libppt.c + +CSTD= $(CSTD_GNU99) +C99LMODE= -Xc99=%all + +# +# lint doesn't like %4s in sscanf(). +# +LINTFLAGS += -erroff=E_BAD_FORMAT_ARG_TYPE2 +LINTFLAGS64 += -erroff=E_BAD_FORMAT_ARG_TYPE2 + +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) +LDLIBS += -lpcidb -ldevinfo -lcmdutils -lnvpair -lc + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libppt/amd64/Makefile b/usr/src/lib/libppt/amd64/Makefile new file mode 100644 index 0000000000..5a304d7fe7 --- /dev/null +++ b/usr/src/lib/libppt/amd64/Makefile @@ -0,0 +1,19 @@ +# +# 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 2018 Joyent, Inc. +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libppt/common/libppt.c b/usr/src/lib/libppt/common/libppt.c new file mode 100644 index 0000000000..7e8385da06 --- /dev/null +++ b/usr/src/lib/libppt/common/libppt.c @@ -0,0 +1,506 @@ +/* + * 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 2018 Joyent, Inc. + * + * Convenience routines for identifying current or available devices that are + * suitable for PCI passthrough to a bhyve guest. + */ + +#include <libdevinfo.h> +#include <libppt.h> + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/list.h> +#include <strings.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <pcidb.h> +#include <glob.h> + +typedef struct node_data { + pcidb_hdl_t *nd_db; + list_t nd_matches; + nvlist_t *nd_nvl; + int nd_err; +} node_data_t; + +typedef struct ppt_match { + list_node_t pm_list; + char pm_path[MAXPATHLEN]; + char pm_vendor[5]; + char pm_device[5]; +} ppt_match_t; + +static boolean_t +is_pci(di_node_t di_node) +{ + char *svals; + + if (di_prop_lookup_strings(DDI_DEV_T_ANY, di_parent_node(di_node), + "device_type", &svals) != 1) + return (B_FALSE); + + return (strcmp(svals, "pci") == 0 || strcmp(svals, "pciex") == 0); +} + +static int +populate_int_prop(di_node_t di_node, nvlist_t *nvl, const char *name, int *ival) +{ + char val[20]; + int *ivals; + int err; + + if (di_prop_lookup_ints(DDI_DEV_T_ANY, di_node, name, &ivals) != 1) + return (errno); + + (void) snprintf(val, sizeof (val), "%x", ivals[0]); + + err = nvlist_add_string(nvl, name, val); + + if (err == 0 && ival != NULL) + *ival = ivals[0]; + + return (err); +} + +static int +dev_getlabel(pcidb_hdl_t *db, int vid, int did, char *buf, size_t buflen) +{ + pcidb_vendor_t *vend = NULL; + pcidb_device_t *dev = NULL; + + if ((vend = pcidb_lookup_vendor(db, vid)) == NULL) + return (ENOENT); + + if ((dev = pcidb_lookup_device_by_vendor(vend, did)) == NULL) + return (ENOENT); + + (void) snprintf(buf, buflen, "%s %s", pcidb_vendor_name(vend), + pcidb_device_name(dev)); + + return (0); +} + +static nvlist_t * +dev_getinfo(di_node_t di_node, pcidb_hdl_t *db, + const char *dev, const char *path) +{ + char label[MAXPATHLEN]; + nvlist_t *nvl = NULL; + int vid, did; + int err; + + if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) + goto out; + + if (dev != NULL && (err = nvlist_add_string(nvl, "dev", dev)) != 0) + goto out; + if ((err = nvlist_add_string(nvl, "path", path)) != 0) + goto out; + if ((err = populate_int_prop(di_node, nvl, "vendor-id", &vid)) != 0) + goto out; + if ((err = populate_int_prop(di_node, nvl, "device-id", &did)) != 0) + goto out; + if ((err = populate_int_prop(di_node, nvl, + "subsystem-vendor-id", NULL)) != 0) + goto out; + if ((err = populate_int_prop(di_node, nvl, "subsystem-id", NULL)) != 0) + goto out; + if ((err = populate_int_prop(di_node, nvl, "revision-id", NULL)) != 0) + goto out; + + err = dev_getlabel(db, vid, did, label, sizeof (label)); + + if (err == 0) { + err = nvlist_add_string(nvl, "label", label); + } else if (err == ENOENT) { + err = 0; + } + +out: + if (err) { + nvlist_free(nvl); + errno = err; + return (NULL); + } + + return (nvl); +} + +/* + * /devices/pci0@0/....@0,1:ppt -> /pci0@0/...@0,1 + */ +static const char * +fs_to_phys_path(char *fspath) +{ + const char prefix[] = "/devices"; + char *c; + + if ((c = strrchr(fspath, ':')) != NULL && strcmp(c, ":ppt") == 0) + *c = '\0'; + + c = fspath; + + if (strncmp(c, prefix, sizeof (prefix) - 1) == 0) + c += sizeof (prefix) - 1; + + return (c); +} + +/* + * Return an nvlist representing the mappings of /dev/ppt* devices to physical + * devices. Of the form: + * + * /pci@0,0/... { + * dev: "/dev/ppt0" + * path: "/pci@0,0/..." + * vendor-id: "8086" + * device-id: "1528" + * subsystem-vendor-id: "8086" + * subsystem-id: "1528" + * revision-id: "1" + * label: "Intel Corporation ..." + * }, + * /pci@0,0/... + * + * The nvlist should be freed by the caller. + */ +nvlist_t * +ppt_list_assigned(void) +{ + di_node_t di_root = DI_NODE_NIL; + pcidb_hdl_t *db = NULL; + nvlist_t *nvl = NULL; + glob_t gl; + int err; + + bzero(&gl, sizeof (gl)); + + if ((di_root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) + return (NULL); + + if ((db = pcidb_open(PCIDB_VERSION)) == NULL) { + err = errno; + goto out; + } + + if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) + goto out; + + if ((err = glob("/dev/ppt*", GLOB_KEEPSTAT | GLOB_ERR, + NULL, &gl)) != 0) { + err = (err == GLOB_NOMATCH) ? 0 : errno; + goto out; + } + + for (size_t i = 0; i < gl.gl_pathc; i++) { + char fspath[MAXPATHLEN]; + nvlist_t *info_nvl; + di_node_t di_node; + const char *path; + + if (!S_ISLNK(gl.gl_statv[i]->st_mode)) + continue; + + if (realpath(gl.gl_pathv[i], fspath) == NULL) { + err = errno; + goto out; + } + + path = fs_to_phys_path(fspath); + + /* + * path argument is treated as const. + */ + if ((di_node = di_lookup_node(di_root, (char *)path)) == NULL) { + err = errno; + goto out; + } + + if (!is_pci(di_node)) + continue; + + info_nvl = dev_getinfo(di_node, db, gl.gl_pathv[i], path); + + if (info_nvl == NULL) { + err = errno; + goto out; + } + + err = nvlist_add_nvlist(nvl, path, info_nvl); + nvlist_free(info_nvl); + + if (err) + goto out; + } + +out: + if (di_root != DI_NODE_NIL) + di_fini(di_root); + + pcidb_close(db); + globfree(&gl); + + if (err) { + nvlist_free(nvl); + errno = err; + return (NULL); + } + + return (nvl); +} + +/* + * Read in our list of potential PPT devices. A boot-module provided file + * explicitly over-rides anything delivered. + */ +static int +get_matches(list_t *listp) +{ + int err = 0; + FILE *fp; + + list_create(listp, sizeof (ppt_match_t), + offsetof(ppt_match_t, pm_list)); + + if ((fp = fopen("/system/boot/etc/ppt_matches", "r")) == NULL) { + if (errno != ENOENT) + return (errno); + + if ((fp = fopen("/etc/ppt_matches", "r")) == NULL) { + if (errno == ENOENT) + return (0); + return (errno); + } + } + + for (;;) { + char *line = NULL; + ppt_match_t *pm; + size_t cap = 0; + ssize_t read; + + if ((read = getline(&line, &cap, fp)) <= 0) { + free(line); + break; + } + + if (line[read - 1] == '\n') + line[read - 1] = '\0'; + + if ((pm = malloc(sizeof (*pm))) == NULL) { + err = errno; + free(line); + goto out; + } + + bzero(pm, sizeof (*pm)); + + if (sscanf(line, "pciex%4s,%4s", &pm->pm_vendor, + &pm->pm_device) == 2 || + sscanf(line, "pci%4s,%4s", &pm->pm_vendor, + &pm->pm_device) == 2 || + sscanf(line, "pciex%4s", &pm->pm_vendor) == 1 || + sscanf(line, "pci%4s", &pm->pm_vendor) == 1) { + list_insert_tail(listp, pm); + } else if (line[0] == '/') { + (void) strlcpy(pm->pm_path, line, sizeof (pm->pm_path)); + list_insert_tail(listp, pm); + } else { + /* + * Ignore any line we don't understand. + */ + free(pm); + } + + free(line); + } + +out: + (void) fclose(fp); + return (err); +} + +static boolean_t +match_ppt(list_t *matches, nvlist_t *nvl) +{ + char *vendor; + char *device; + char *path; + + if (nvlist_lookup_string(nvl, "path", &path) != 0 || + nvlist_lookup_string(nvl, "vendor-id", &vendor) != 0 || + nvlist_lookup_string(nvl, "device-id", &device) != 0) + return (B_FALSE); + + for (ppt_match_t *pm = list_head(matches); pm != NULL; + pm = list_next(matches, pm)) { + if (pm->pm_path[0] != '\0' && strcmp(pm->pm_path, path) == 0) + return (B_TRUE); + + if (pm->pm_vendor[0] != '\0' && + strcmp(pm->pm_vendor, vendor) == 0) { + if (pm->pm_device[0] == '\0') + return (B_TRUE); + if (strcmp(pm->pm_device, device) == 0) + return (B_TRUE); + } + } + + return (B_FALSE); +} + +static int +inspect_node(di_node_t di_node, void *arg) +{ + node_data_t *data = arg; + nvlist_t *info_nvl = NULL; + char *devname = NULL; + const char *driver; + char *path = NULL; + + if (!is_pci(di_node)) + return (DI_WALK_CONTINUE); + + driver = di_driver_name(di_node); + + if (driver != NULL && strcmp(driver, "ppt") == 0) { + if (asprintf(&devname, "/dev/ppt%d", + di_instance(di_node)) < 0) { + data->nd_err = errno; + goto out; + } + } + + if ((path = di_devfs_path(di_node)) == NULL) { + data->nd_err = ENOENT; + goto out; + } + + info_nvl = dev_getinfo(di_node, data->nd_db, devname, path); + + if (info_nvl == NULL) + goto out; + + if (devname == NULL && !match_ppt(&data->nd_matches, info_nvl)) + goto out; + + data->nd_err = nvlist_add_nvlist(data->nd_nvl, path, info_nvl); + +out: + free(path); + free(devname); + nvlist_free(info_nvl); + return (data->nd_err ? DI_WALK_TERMINATE : DI_WALK_CONTINUE); +} + +/* + * Like ppt_list_assigned() output, but includes all devices that could be used + * for passthrough, whether assigned or not. + */ +nvlist_t * +ppt_list(void) +{ + node_data_t nd = { NULL, }; + di_node_t di_root; + int err; + + if ((di_root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) + return (NULL); + + if ((err = get_matches(&nd.nd_matches)) != 0) + goto out; + + if ((nd.nd_db = pcidb_open(PCIDB_VERSION)) == NULL) { + err = errno; + goto out; + } + + if ((err = nvlist_alloc(&nd.nd_nvl, NV_UNIQUE_NAME, 0)) != 0) + goto out; + + if ((err = di_walk_node(di_root, DI_WALK_CLDFIRST, + &nd, inspect_node)) != 0) + goto out; + + err = nd.nd_err; + +out: + pcidb_close(nd.nd_db); + + for (ppt_match_t *pm = list_head(&nd.nd_matches); pm != NULL; ) { + ppt_match_t *next = list_next(&nd.nd_matches, pm); + free(pm); + pm = next; + } + + if (di_root != DI_NODE_NIL) + di_fini(di_root); + + if (err) { + nvlist_free(nd.nd_nvl); + errno = err; + return (NULL); + } + + return (nd.nd_nvl); +} + +/* + * Given a physical path such as "/devices/pci0@0...", return the "/dev/pptX" + * that is bound to it, if any. The "/devices/" prefix is optional. The + * physical path may have the ":ppt" minor name suffix. + * + * Returns ENOENT if no such PPT device exists. + */ +int +ppt_devpath_to_dev(const char *inpath, char *buf, size_t buflen) +{ + char fspath[MAXPATHLEN] = ""; + nvpair_t *nvp = NULL; + const char *devpath; + int err = ENOENT; + nvlist_t *nvl; + + if (strlcat(fspath, inpath, sizeof (fspath)) >= sizeof (fspath)) + return (ENAMETOOLONG); + + devpath = fs_to_phys_path(fspath); + + if ((nvl = ppt_list_assigned()) == NULL) + return (errno); + + while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { + const char *name = nvpair_name(nvp); + char *ppt = NULL; + nvlist_t *props; + + (void) nvpair_value_nvlist(nvp, &props); + + if (strcmp(name, devpath) == 0) { + (void) nvlist_lookup_string(props, "dev", &ppt); + + err = 0; + + if (strlcpy(buf, ppt, buflen) >= buflen) + err = ENAMETOOLONG; + break; + } + } + + nvlist_free(nvl); + return (err); +} diff --git a/usr/src/lib/libppt/common/libppt.h b/usr/src/lib/libppt/common/libppt.h new file mode 100644 index 0000000000..efbf2c7b8b --- /dev/null +++ b/usr/src/lib/libppt/common/libppt.h @@ -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 2018 Joyent, Inc. + */ + +#ifndef _LIBPPT_H +#define _LIBPPT_H + +#include <sys/types.h> + +#include <libnvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern int ppt_devpath_to_dev(const char *, char *, size_t); + +extern nvlist_t *ppt_list_assigned(void); + +extern nvlist_t *ppt_list(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBPPT_H */ diff --git a/usr/src/lib/libppt/common/llib-lppt b/usr/src/lib/libppt/common/llib-lppt new file mode 100644 index 0000000000..dadd992a31 --- /dev/null +++ b/usr/src/lib/libppt/common/llib-lppt @@ -0,0 +1,19 @@ +/* + * 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 2018 Joyent, Inc. + */ + +/* LINTLIBRARY */ +/* PROTOLIB1 */ + +#include <libppt.h> diff --git a/usr/src/lib/libppt/common/mapfile-vers b/usr/src/lib/libppt/common/mapfile-vers new file mode 100644 index 0000000000..d9d882874b --- /dev/null +++ b/usr/src/lib/libppt/common/mapfile-vers @@ -0,0 +1,40 @@ +# +# 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 2018 Joyent, Inc. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +$mapfile_version 2 + +SYMBOL_VERSION ILLUMOSprivate { + global: + ppt_devpath_to_dev; + ppt_list_assigned; + ppt_list; + + local: + *; +}; diff --git a/usr/src/lib/libppt/i386/Makefile b/usr/src/lib/libppt/i386/Makefile new file mode 100644 index 0000000000..3f11e556d4 --- /dev/null +++ b/usr/src/lib/libppt/i386/Makefile @@ -0,0 +1,18 @@ +# +# 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 2018 Joyent, Inc. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libppt/sparc/Makefile b/usr/src/lib/libppt/sparc/Makefile new file mode 100644 index 0000000000..3f11e556d4 --- /dev/null +++ b/usr/src/lib/libppt/sparc/Makefile @@ -0,0 +1,18 @@ +# +# 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 2018 Joyent, Inc. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libppt/sparcv9/Makefile b/usr/src/lib/libppt/sparcv9/Makefile new file mode 100644 index 0000000000..5a304d7fe7 --- /dev/null +++ b/usr/src/lib/libppt/sparcv9/Makefile @@ -0,0 +1,19 @@ +# +# 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 2018 Joyent, Inc. +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) |