summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/hv/hv_fcopy_daemon.c3
-rw-r--r--tools/include/tools/endian.h56
-rw-r--r--tools/perf/util/string.c90
-rw-r--r--tools/power/acpi/Makefile5
-rw-r--r--tools/power/acpi/common/cmfsize.c20
-rw-r--r--tools/power/acpi/common/getopt.c14
-rw-r--r--tools/power/acpi/os_specific/service_layers/oslibcfs.c214
-rw-r--r--tools/power/acpi/os_specific/service_layers/oslinuxtbl.c48
-rw-r--r--tools/power/acpi/os_specific/service_layers/osunixxf.c1311
-rw-r--r--tools/power/acpi/tools/acpidump/acpidump.h3
-rw-r--r--tools/power/acpi/tools/acpidump/apdump.c108
-rw-r--r--tools/power/acpi/tools/acpidump/apfiles.c92
-rw-r--r--tools/power/acpi/tools/acpidump/apmain.c96
-rw-r--r--tools/power/cpupower/bench/parse.c39
-rw-r--r--tools/power/cpupower/utils/cpufreq-set.c11
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c2
-rw-r--r--tools/power/cpupower/utils/idle_monitor/mperf_monitor.c2
-rw-r--r--tools/power/x86/turbostat/turbostat.c80
-rwxr-xr-xtools/testing/ktest/ktest.pl61
-rw-r--r--tools/testing/ktest/sample.conf10
-rw-r--r--tools/testing/selftests/Makefile22
-rw-r--r--tools/testing/selftests/README.txt27
-rw-r--r--tools/testing/selftests/cpu-hotplug/Makefile3
-rw-r--r--tools/testing/selftests/cpu-hotplug/on-off-test.sh52
-rw-r--r--tools/testing/selftests/firmware/Makefile27
-rw-r--r--tools/testing/selftests/firmware/fw_filesystem.sh62
-rw-r--r--tools/testing/selftests/firmware/fw_userhelper.sh89
-rw-r--r--tools/testing/selftests/ftrace/Makefile7
-rw-r--r--tools/testing/selftests/ftrace/README82
-rwxr-xr-xtools/testing/selftests/ftrace/ftracetest253
-rw-r--r--tools/testing/selftests/ftrace/samples/fail.tc4
-rw-r--r--tools/testing/selftests/ftrace/samples/pass.tc3
-rw-r--r--tools/testing/selftests/ftrace/samples/unresolved.tc4
-rw-r--r--tools/testing/selftests/ftrace/samples/unsupported.tc3
-rw-r--r--tools/testing/selftests/ftrace/samples/untested.tc3
-rw-r--r--tools/testing/selftests/ftrace/samples/xfail.tc3
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic1.tc3
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic2.tc7
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic3.tc8
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc11
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc13
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc16
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc15
-rw-r--r--tools/testing/selftests/ftrace/test.d/template9
-rw-r--r--tools/testing/selftests/ipc/Makefile6
-rw-r--r--tools/testing/selftests/kcmp/Makefile6
-rw-r--r--tools/testing/selftests/kcmp/kcmp_test.c2
-rw-r--r--tools/testing/selftests/memfd/.gitignore4
-rw-r--r--tools/testing/selftests/memfd/Makefile20
-rw-r--r--tools/testing/selftests/memfd/fuse_mnt.c110
-rw-r--r--tools/testing/selftests/memfd/fuse_test.c311
-rw-r--r--tools/testing/selftests/memfd/memfd_test.c911
-rw-r--r--tools/testing/selftests/memfd/run_fuse_test.sh14
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile3
-rw-r--r--tools/testing/selftests/memory-hotplug/on-off-test.sh8
-rw-r--r--tools/testing/selftests/mount/Makefile17
-rw-r--r--tools/testing/selftests/mount/unprivileged-remount-test.c242
-rw-r--r--tools/testing/selftests/mqueue/Makefile4
-rw-r--r--tools/testing/selftests/mqueue/mq_open_tests.c20
-rw-r--r--tools/testing/selftests/mqueue/mq_perf_tests.c40
-rw-r--r--tools/testing/selftests/powerpc/Makefile12
-rw-r--r--tools/testing/selftests/powerpc/pmu/Makefile19
-rw-r--r--tools/testing/selftests/powerpc/pmu/count_instructions.c30
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/Makefile5
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S271
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c91
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.c261
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.h1
-rw-r--r--tools/testing/selftests/powerpc/pmu/l3_bank_test.c48
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.c50
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.h1
-rw-r--r--tools/testing/selftests/powerpc/pmu/per_event_excludes.c114
-rw-r--r--tools/testing/selftests/powerpc/primitives/Makefile17
l---------tools/testing/selftests/powerpc/primitives/asm/asm-compat.h1
-rw-r--r--tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h0
-rw-r--r--tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c147
l---------tools/testing/selftests/powerpc/primitives/word-at-a-time.h1
-rw-r--r--tools/testing/selftests/ptrace/peeksiginfo.c4
-rwxr-xr-x[-rw-r--r--]tools/testing/selftests/rcutorture/bin/config2frag.sh4
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/configcheck.sh4
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/configinit.sh4
-rw-r--r--tools/testing/selftests/rcutorture/bin/functions.sh20
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-build.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh5
-rwxr-xr-x[-rw-r--r--]tools/testing/selftests/rcutorture/bin/kvm.sh6
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-build.sh5
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-console.sh9
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-torture.sh5
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/CFLIST3
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK026
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK036
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK046
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/CFLIST3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS019
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS025
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS0313
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE014
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE073
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh2
-rw-r--r--tools/testing/selftests/rcutorture/doc/initrd.txt1
-rw-r--r--tools/testing/selftests/vm/Makefile1
-rw-r--r--tools/testing/selftests/vm/transhuge-stress.c144
-rwxr-xr-xtools/time/udelay_test.sh66
-rw-r--r--tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c39
-rw-r--r--tools/usb/ffs-aio-example/multibuff/host_app/test.c27
-rw-r--r--tools/usb/ffs-aio-example/simple/device_app/aio_simple.c39
-rw-r--r--tools/usb/ffs-aio-example/simple/host_app/test.c27
-rw-r--r--tools/usb/ffs-test.c126
-rw-r--r--tools/usb/usbip/.gitignore28
-rw-r--r--tools/usb/usbip/AUTHORS3
-rw-r--r--tools/usb/usbip/COPYING340
-rw-r--r--tools/usb/usbip/INSTALL237
-rw-r--r--tools/usb/usbip/Makefile.am6
-rw-r--r--tools/usb/usbip/README202
-rwxr-xr-xtools/usb/usbip/autogen.sh9
-rwxr-xr-xtools/usb/usbip/cleanup.sh12
-rw-r--r--tools/usb/usbip/configure.ac111
-rw-r--r--tools/usb/usbip/doc/usbip.895
-rw-r--r--tools/usb/usbip/doc/usbipd.891
-rw-r--r--tools/usb/usbip/libsrc/Makefile.am8
-rw-r--r--tools/usb/usbip/libsrc/list.h136
-rw-r--r--tools/usb/usbip/libsrc/names.c504
-rw-r--r--tools/usb/usbip/libsrc/names.h41
-rw-r--r--tools/usb/usbip/libsrc/sysfs_utils.c31
-rw-r--r--tools/usb/usbip/libsrc/sysfs_utils.h8
-rw-r--r--tools/usb/usbip/libsrc/usbip_common.c285
-rw-r--r--tools/usb/usbip/libsrc/usbip_common.h137
-rw-r--r--tools/usb/usbip/libsrc/usbip_host_driver.c280
-rw-r--r--tools/usb/usbip/libsrc/usbip_host_driver.h49
-rw-r--r--tools/usb/usbip/libsrc/vhci_driver.c411
-rw-r--r--tools/usb/usbip/libsrc/vhci_driver.h59
-rw-r--r--tools/usb/usbip/src/Makefile.am11
-rw-r--r--tools/usb/usbip/src/usbip.c201
-rw-r--r--tools/usb/usbip/src/usbip.h40
-rw-r--r--tools/usb/usbip/src/usbip_attach.c241
-rw-r--r--tools/usb/usbip/src/usbip_bind.c214
-rw-r--r--tools/usb/usbip/src/usbip_detach.c110
-rw-r--r--tools/usb/usbip/src/usbip_list.c283
-rw-r--r--tools/usb/usbip/src/usbip_network.c303
-rw-r--r--tools/usb/usbip/src/usbip_network.h185
-rw-r--r--tools/usb/usbip/src/usbip_port.c57
-rw-r--r--tools/usb/usbip/src/usbip_unbind.c141
-rw-r--r--tools/usb/usbip/src/usbipd.c679
-rw-r--r--tools/usb/usbip/src/utils.c52
-rw-r--r--tools/usb/usbip/src/utils.h25
-rw-r--r--tools/vm/page-types.c1
158 files changed, 11338 insertions, 681 deletions
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
index fba1c75..8f96b3e 100644
--- a/tools/hv/hv_fcopy_daemon.c
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -88,7 +88,8 @@ static int hv_start_fcopy(struct hv_start_fcopy *smsg)
}
}
- target_fd = open(target_fname, O_RDWR | O_CREAT | O_CLOEXEC, 0744);
+ target_fd = open(target_fname,
+ O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0744);
if (target_fd == -1) {
syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
goto done;
diff --git a/tools/include/tools/endian.h b/tools/include/tools/endian.h
new file mode 100644
index 0000000..8001194
--- /dev/null
+++ b/tools/include/tools/endian.h
@@ -0,0 +1,56 @@
+#ifndef _TOOLS_ENDIAN_H
+#define _TOOLS_ENDIAN_H
+
+#include <byteswap.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+#ifndef htole16
+#define htole16(x) (x)
+#endif
+#ifndef htole32
+#define htole32(x) (x)
+#endif
+#ifndef htole64
+#define htole64(x) (x)
+#endif
+
+#ifndef le16toh
+#define le16toh(x) (x)
+#endif
+
+#ifndef le32toh
+#define le32toh(x) (x)
+#endif
+
+#ifndef le64toh
+#define le64toh(x) (x)
+#endif
+
+#else /* __BYTE_ORDER */
+
+#ifndef htole16
+#define htole16(x) __bswap_16(x)
+#endif
+#ifndef htole32
+#define htole32(x) __bswap_32(x)
+#endif
+#ifndef htole64
+#define htole64(x) __bswap_64(x)
+#endif
+
+#ifndef le16toh
+#define le16toh(x) __bswap_16(x)
+#endif
+
+#ifndef le32toh
+#define le32toh(x) __bswap_32(x)
+#endif
+
+#ifndef le64toh
+#define le64toh(x) __bswap_64(x)
+#endif
+
+#endif
+
+#endif /* _TOOLS_ENDIAN_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 2553e5b..d87767f 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -9,78 +9,48 @@
*/
s64 perf_atoll(const char *str)
{
- unsigned int i;
- s64 length = -1, unit = 1;
+ s64 length;
+ char *p;
+ char c;
if (!isdigit(str[0]))
goto out_err;
- for (i = 1; i < strlen(str); i++) {
- switch (str[i]) {
- case 'B':
- case 'b':
- break;
- case 'K':
- if (str[i + 1] != 'B')
- goto out_err;
- else
- goto kilo;
- case 'k':
- if (str[i + 1] != 'b')
- goto out_err;
-kilo:
- unit = K;
- break;
- case 'M':
- if (str[i + 1] != 'B')
- goto out_err;
- else
- goto mega;
- case 'm':
- if (str[i + 1] != 'b')
+ length = strtoll(str, &p, 10);
+ switch (c = *p++) {
+ case 'b': case 'B':
+ if (*p)
goto out_err;
-mega:
- unit = K * K;
+ case '\0':
+ return length;
+ default:
+ goto out_err;
+ /* two-letter suffices */
+ case 'k': case 'K':
+ length <<= 10;
break;
- case 'G':
- if (str[i + 1] != 'B')
- goto out_err;
- else
- goto giga;
- case 'g':
- if (str[i + 1] != 'b')
- goto out_err;
-giga:
- unit = K * K * K;
+ case 'm': case 'M':
+ length <<= 20;
break;
- case 'T':
- if (str[i + 1] != 'B')
- goto out_err;
- else
- goto tera;
- case 't':
- if (str[i + 1] != 'b')
- goto out_err;
-tera:
- unit = K * K * K * K;
+ case 'g': case 'G':
+ length <<= 30;
break;
- case '\0': /* only specified figures */
- unit = 1;
+ case 't': case 'T':
+ length <<= 40;
break;
- default:
- if (!isdigit(str[i]))
- goto out_err;
- break;
- }
}
-
- length = atoll(str) * unit;
- goto out;
+ /* we want the cases to match */
+ if (islower(c)) {
+ if (strcmp(p, "b") != 0)
+ goto out_err;
+ } else {
+ if (strcmp(p, "B") != 0)
+ goto out_err;
+ }
+ return length;
out_err:
- length = -1;
-out:
- return length;
+ return -1;
}
/*
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e5a3c4b..3d1537b 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -108,13 +108,18 @@ DUMP_OBJS = \
apmain.o\
osunixdir.o\
osunixmap.o\
+ osunixxf.o\
tbprint.o\
tbxfroot.o\
utbuffer.o\
+ utdebug.o\
utexcep.o\
+ utglobal.o\
utmath.o\
+ utprint.o\
utstring.o\
utxferror.o\
+ oslibcfs.o\
oslinuxtbl.o\
cmfsize.o\
getopt.o
diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c
index 5140e5e..f4b9533 100644
--- a/tools/power/acpi/common/cmfsize.c
+++ b/tools/power/acpi/common/cmfsize.c
@@ -58,44 +58,46 @@ ACPI_MODULE_NAME("cmfsize")
* RETURN: File Size. On error, -1 (ACPI_UINT32_MAX)
*
* DESCRIPTION: Get the size of a file. Uses seek-to-EOF. File must be open.
- * Does not disturb the current file pointer. Uses perror for
- * error messages.
+ * Does not disturb the current file pointer.
*
******************************************************************************/
-u32 cm_get_file_size(FILE * file)
+u32 cm_get_file_size(ACPI_FILE file)
{
long file_size;
long current_offset;
+ acpi_status status;
/* Save the current file pointer, seek to EOF to obtain file size */
- current_offset = ftell(file);
+ current_offset = acpi_os_get_file_offset(file);
if (current_offset < 0) {
goto offset_error;
}
- if (fseek(file, 0, SEEK_END)) {
+ status = acpi_os_set_file_offset(file, 0, ACPI_FILE_END);
+ if (ACPI_FAILURE(status)) {
goto seek_error;
}
- file_size = ftell(file);
+ file_size = acpi_os_get_file_offset(file);
if (file_size < 0) {
goto offset_error;
}
/* Restore original file pointer */
- if (fseek(file, current_offset, SEEK_SET)) {
+ status = acpi_os_set_file_offset(file, current_offset, ACPI_FILE_BEGIN);
+ if (ACPI_FAILURE(status)) {
goto seek_error;
}
return ((u32)file_size);
offset_error:
- perror("Could not get file offset");
+ acpi_log_error("Could not get file offset");
return (ACPI_UINT32_MAX);
seek_error:
- perror("Could not seek file");
+ acpi_log_error("Could not set file offset");
return (ACPI_UINT32_MAX);
}
diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c
index a302f52..2f0f34a 100644
--- a/tools/power/acpi/common/getopt.c
+++ b/tools/power/acpi/common/getopt.c
@@ -51,14 +51,12 @@
* "f|" - Option has required single-char sub-options
*/
-#include <stdio.h>
-#include <string.h>
#include <acpi/acpi.h>
#include "accommon.h"
#include "acapps.h"
#define ACPI_OPTION_ERROR(msg, badchar) \
- if (acpi_gbl_opterr) {fprintf (stderr, "%s%c\n", msg, badchar);}
+ if (acpi_gbl_opterr) {acpi_log_error ("%s%c\n", msg, badchar);}
int acpi_gbl_opterr = 1;
int acpi_gbl_optind = 1;
@@ -113,7 +111,7 @@ int acpi_getopt_argument(int argc, char **argv)
* PARAMETERS: argc, argv - from main
* opts - options info list
*
- * RETURN: Option character or EOF
+ * RETURN: Option character or ACPI_OPT_END
*
* DESCRIPTION: Get the next option
*
@@ -128,10 +126,10 @@ int acpi_getopt(int argc, char **argv, char *opts)
if (acpi_gbl_optind >= argc ||
argv[acpi_gbl_optind][0] != '-' ||
argv[acpi_gbl_optind][1] == '\0') {
- return (EOF);
- } else if (strcmp(argv[acpi_gbl_optind], "--") == 0) {
+ return (ACPI_OPT_END);
+ } else if (ACPI_STRCMP(argv[acpi_gbl_optind], "--") == 0) {
acpi_gbl_optind++;
- return (EOF);
+ return (ACPI_OPT_END);
}
}
@@ -142,7 +140,7 @@ int acpi_getopt(int argc, char **argv, char *opts)
/* Make sure that the option is legal */
if (current_char == ':' ||
- (opts_ptr = strchr(opts, current_char)) == NULL) {
+ (opts_ptr = ACPI_STRCHR(opts, current_char)) == NULL) {
ACPI_OPTION_ERROR("Illegal option: -", current_char);
if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
diff --git a/tools/power/acpi/os_specific/service_layers/oslibcfs.c b/tools/power/acpi/os_specific/service_layers/oslibcfs.c
new file mode 100644
index 0000000..c13ff9c
--- /dev/null
+++ b/tools/power/acpi/os_specific/service_layers/oslibcfs.c
@@ -0,0 +1,214 @@
+/******************************************************************************
+ *
+ * Module Name: oslibcfs - C library OSL for file I/O
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#define _COMPONENT ACPI_OS_SERVICES
+ACPI_MODULE_NAME("oslibcfs")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_open_file
+ *
+ * PARAMETERS: path - File path
+ * modes - File operation type
+ *
+ * RETURN: File descriptor.
+ *
+ * DESCRIPTION: Open a file for reading (ACPI_FILE_READING) or/and writing
+ * (ACPI_FILE_WRITING).
+ *
+ ******************************************************************************/
+ACPI_FILE acpi_os_open_file(const char *path, u8 modes)
+{
+ ACPI_FILE file;
+ u32 i = 0;
+ char modes_str[4];
+
+ if (modes & ACPI_FILE_READING) {
+ modes_str[i++] = 'r';
+ }
+ if (modes & ACPI_FILE_WRITING) {
+ modes_str[i++] = 'w';
+ }
+ if (modes & ACPI_FILE_BINARY) {
+ modes_str[i++] = 'b';
+ }
+
+ modes_str[i++] = '\0';
+
+ file = fopen(path, modes_str);
+ if (!file) {
+ perror("Could not open file");
+ }
+
+ return (file);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_close_file
+ *
+ * PARAMETERS: file - An open file descriptor
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Close a file opened via acpi_os_open_file.
+ *
+ ******************************************************************************/
+
+void acpi_os_close_file(ACPI_FILE file)
+{
+ fclose(file);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_read_file
+ *
+ * PARAMETERS: file - An open file descriptor
+ * buffer - Data buffer
+ * size - Data block size
+ * count - Number of data blocks
+ *
+ * RETURN: Number of bytes actually read.
+ *
+ * DESCRIPTION: Read from a file.
+ *
+ ******************************************************************************/
+
+int
+acpi_os_read_file(ACPI_FILE file, void *buffer, acpi_size size, acpi_size count)
+{
+ int length;
+
+ length = fread(buffer, size, count, file);
+ if (length < 0) {
+ perror("Error reading file");
+ }
+
+ return (length);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_write_file
+ *
+ * PARAMETERS: file - An open file descriptor
+ * buffer - Data buffer
+ * size - Data block size
+ * count - Number of data blocks
+ *
+ * RETURN: Number of bytes actually written.
+ *
+ * DESCRIPTION: Write to a file.
+ *
+ ******************************************************************************/
+
+int
+acpi_os_write_file(ACPI_FILE file,
+ void *buffer, acpi_size size, acpi_size count)
+{
+ int length;
+
+ length = fwrite(buffer, size, count, file);
+ if (length < 0) {
+ perror("Error writing file");
+ }
+
+ return (length);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_get_file_offset
+ *
+ * PARAMETERS: file - An open file descriptor
+ *
+ * RETURN: Current file pointer position.
+ *
+ * DESCRIPTION: Get current file offset.
+ *
+ ******************************************************************************/
+
+long acpi_os_get_file_offset(ACPI_FILE file)
+{
+ long offset;
+
+ offset = ftell(file);
+ return (offset);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_set_file_offset
+ *
+ * PARAMETERS: file - An open file descriptor
+ * offset - New file offset
+ * from - From begin/end of file
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Set current file offset.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_os_set_file_offset(ACPI_FILE file, long offset, u8 from)
+{
+ int ret = 0;
+
+ if (from == ACPI_FILE_BEGIN) {
+ ret = fseek(file, offset, SEEK_SET);
+ }
+ if (from == ACPI_FILE_END) {
+ ret = fseek(file, offset, SEEK_END);
+ }
+
+ if (ret < 0) {
+ return (AE_ERROR);
+ } else {
+ return (AE_OK);
+ }
+}
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
index 28c5200..0dc2485 100644
--- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
+++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
@@ -77,6 +77,9 @@ osl_map_table(acpi_size address,
static void osl_unmap_table(struct acpi_table_header *table);
+static acpi_physical_address
+osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword);
+
static acpi_physical_address osl_find_rsdp_via_efi(void);
static acpi_status osl_load_rsdp(void);
@@ -417,6 +420,38 @@ acpi_os_get_table_by_index(u32 index,
/******************************************************************************
*
+ * FUNCTION: osl_find_rsdp_via_efi_by_keyword
+ *
+ * PARAMETERS: keyword - Character string indicating ACPI GUID version
+ * in the EFI table
+ *
+ * RETURN: RSDP address if found
+ *
+ * DESCRIPTION: Find RSDP address via EFI using keyword indicating the ACPI
+ * GUID version.
+ *
+ *****************************************************************************/
+
+static acpi_physical_address
+osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword)
+{
+ char buffer[80];
+ unsigned long long address = 0;
+ char format[32];
+
+ snprintf(format, 32, "%s=%s", keyword, "%llx");
+ fseek(file, 0, SEEK_SET);
+ while (fgets(buffer, 80, file)) {
+ if (sscanf(buffer, format, &address) == 1) {
+ break;
+ }
+ }
+
+ return ((acpi_physical_address) (address));
+}
+
+/******************************************************************************
+ *
* FUNCTION: osl_find_rsdp_via_efi
*
* PARAMETERS: None
@@ -430,20 +465,19 @@ acpi_os_get_table_by_index(u32 index,
static acpi_physical_address osl_find_rsdp_via_efi(void)
{
FILE *file;
- char buffer[80];
- unsigned long address = 0;
+ acpi_physical_address address = 0;
file = fopen(EFI_SYSTAB, "r");
if (file) {
- while (fgets(buffer, 80, file)) {
- if (sscanf(buffer, "ACPI20=0x%lx", &address) == 1) {
- break;
- }
+ address = osl_find_rsdp_via_efi_by_keyword(file, "ACPI20");
+ if (!address) {
+ address =
+ osl_find_rsdp_via_efi_by_keyword(file, "ACPI");
}
fclose(file);
}
- return ((acpi_physical_address) (address));
+ return (address);
}
/******************************************************************************
diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c
new file mode 100644
index 0000000..60b58cd
--- /dev/null
+++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c
@@ -0,0 +1,1311 @@
+/******************************************************************************
+ *
+ * Module Name: osunixxf - UNIX OSL interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * These interfaces are required in order to compile the ASL compiler and the
+ * various ACPICA tools under Linux or other Unix-like system.
+ */
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acparser.h"
+#include "acdebug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <semaphore.h>
+#include <pthread.h>
+#include <errno.h>
+
+#define _COMPONENT ACPI_OS_SERVICES
+ACPI_MODULE_NAME("osunixxf")
+
+u8 acpi_gbl_debug_timeout = FALSE;
+
+/* Upcalls to acpi_exec */
+
+void
+ae_table_override(struct acpi_table_header *existing_table,
+ struct acpi_table_header **new_table);
+
+typedef void *(*PTHREAD_CALLBACK) (void *);
+
+/* Buffer used by acpi_os_vprintf */
+
+#define ACPI_VPRINTF_BUFFER_SIZE 512
+#define _ASCII_NEWLINE '\n'
+
+/* Terminal support for acpi_exec only */
+
+#ifdef ACPI_EXEC_APP
+#include <termios.h>
+
+struct termios original_term_attributes;
+int term_attributes_were_set = 0;
+
+acpi_status acpi_ut_read_line(char *buffer, u32 buffer_length, u32 *bytes_read);
+
+static void os_enter_line_edit_mode(void);
+
+static void os_exit_line_edit_mode(void);
+
+/******************************************************************************
+ *
+ * FUNCTION: os_enter_line_edit_mode, os_exit_line_edit_mode
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Enter/Exit the raw character input mode for the terminal.
+ *
+ * Interactive line-editing support for the AML debugger. Used with the
+ * common/acgetline module.
+ *
+ * readline() is not used because of non-portability. It is not available
+ * on all systems, and if it is, often the package must be manually installed.
+ *
+ * Therefore, we use the POSIX tcgetattr/tcsetattr and do the minimal line
+ * editing that we need in acpi_os_get_line.
+ *
+ * If the POSIX tcgetattr/tcsetattr interfaces are unavailable, these
+ * calls will also work:
+ * For os_enter_line_edit_mode: system ("stty cbreak -echo")
+ * For os_exit_line_edit_mode: system ("stty cooked echo")
+ *
+ *****************************************************************************/
+
+static void os_enter_line_edit_mode(void)
+{
+ struct termios local_term_attributes;
+
+ /* Get and keep the original attributes */
+
+ if (tcgetattr(STDIN_FILENO, &original_term_attributes)) {
+ fprintf(stderr, "Could not get terminal attributes!\n");
+ return;
+ }
+
+ /* Set the new attributes to enable raw character input */
+
+ memcpy(&local_term_attributes, &original_term_attributes,
+ sizeof(struct termios));
+
+ local_term_attributes.c_lflag &= ~(ICANON | ECHO);
+ local_term_attributes.c_cc[VMIN] = 1;
+ local_term_attributes.c_cc[VTIME] = 0;
+
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &local_term_attributes)) {
+ fprintf(stderr, "Could not set terminal attributes!\n");
+ return;
+ }
+
+ term_attributes_were_set = 1;
+}
+
+static void os_exit_line_edit_mode(void)
+{
+
+ if (!term_attributes_were_set) {
+ return;
+ }
+
+ /* Set terminal attributes back to the original values */
+
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &original_term_attributes)) {
+ fprintf(stderr, "Could not restore terminal attributes!\n");
+ }
+}
+
+#else
+
+/* These functions are not needed for other ACPICA utilities */
+
+#define os_enter_line_edit_mode()
+#define os_exit_line_edit_mode()
+#endif
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_initialize, acpi_os_terminate
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize and terminate this module.
+ *
+ *****************************************************************************/
+
+acpi_status acpi_os_initialize(void)
+{
+ acpi_status status;
+
+ acpi_gbl_output_file = stdout;
+
+ os_enter_line_edit_mode();
+
+ status = acpi_os_create_lock(&acpi_gbl_print_lock);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ return (AE_OK);
+}
+
+acpi_status acpi_os_terminate(void)
+{
+
+ os_exit_line_edit_mode();
+ return (AE_OK);
+}
+
+#ifndef ACPI_USE_NATIVE_RSDP_POINTER
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_get_root_pointer
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: RSDP physical address
+ *
+ * DESCRIPTION: Gets the ACPI root pointer (RSDP)
+ *
+ *****************************************************************************/
+
+acpi_physical_address acpi_os_get_root_pointer(void)
+{
+
+ return (0);
+}
+#endif
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_predefined_override
+ *
+ * PARAMETERS: init_val - Initial value of the predefined object
+ * new_val - The new value for the object
+ *
+ * RETURN: Status, pointer to value. Null pointer returned if not
+ * overriding.
+ *
+ * DESCRIPTION: Allow the OS to override predefined names
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_predefined_override(const struct acpi_predefined_names * init_val,
+ acpi_string * new_val)
+{
+
+ if (!init_val || !new_val) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ *new_val = NULL;
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_table_override
+ *
+ * PARAMETERS: existing_table - Header of current table (probably
+ * firmware)
+ * new_table - Where an entire new table is returned.
+ *
+ * RETURN: Status, pointer to new table. Null pointer returned if no
+ * table is available to override
+ *
+ * DESCRIPTION: Return a different version of a table if one is available
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_table_override(struct acpi_table_header * existing_table,
+ struct acpi_table_header ** new_table)
+{
+
+ if (!existing_table || !new_table) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ *new_table = NULL;
+
+#ifdef ACPI_EXEC_APP
+
+ ae_table_override(existing_table, new_table);
+ return (AE_OK);
+#else
+
+ return (AE_NO_ACPI_TABLES);
+#endif
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_physical_table_override
+ *
+ * PARAMETERS: existing_table - Header of current table (probably firmware)
+ * new_address - Where new table address is returned
+ * (Physical address)
+ * new_table_length - Where new table length is returned
+ *
+ * RETURN: Status, address/length of new table. Null pointer returned
+ * if no table is available to override.
+ *
+ * DESCRIPTION: Returns AE_SUPPORT, function not used in user space.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_physical_table_override(struct acpi_table_header * existing_table,
+ acpi_physical_address * new_address,
+ u32 *new_table_length)
+{
+
+ return (AE_SUPPORT);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_redirect_output
+ *
+ * PARAMETERS: destination - An open file handle/pointer
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Causes redirect of acpi_os_printf and acpi_os_vprintf
+ *
+ *****************************************************************************/
+
+void acpi_os_redirect_output(void *destination)
+{
+
+ acpi_gbl_output_file = destination;
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_printf
+ *
+ * PARAMETERS: fmt, ... - Standard printf format
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Formatted output. Note: very similar to acpi_os_vprintf
+ * (performance), changes should be tracked in both functions.
+ *
+ *****************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE acpi_os_printf(const char *fmt, ...)
+{
+ va_list args;
+ u8 flags;
+
+ flags = acpi_gbl_db_output_flags;
+ if (flags & ACPI_DB_REDIRECTABLE_OUTPUT) {
+
+ /* Output is directable to either a file (if open) or the console */
+
+ if (acpi_gbl_debug_file) {
+
+ /* Output file is open, send the output there */
+
+ va_start(args, fmt);
+ vfprintf(acpi_gbl_debug_file, fmt, args);
+ va_end(args);
+ } else {
+ /* No redirection, send output to console (once only!) */
+
+ flags |= ACPI_DB_CONSOLE_OUTPUT;
+ }
+ }
+
+ if (flags & ACPI_DB_CONSOLE_OUTPUT) {
+ va_start(args, fmt);
+ vfprintf(acpi_gbl_output_file, fmt, args);
+ va_end(args);
+ }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_vprintf
+ *
+ * PARAMETERS: fmt - Standard printf format
+ * args - Argument list
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Formatted output with argument list pointer. Note: very
+ * similar to acpi_os_printf, changes should be tracked in both
+ * functions.
+ *
+ *****************************************************************************/
+
+void acpi_os_vprintf(const char *fmt, va_list args)
+{
+ u8 flags;
+ char buffer[ACPI_VPRINTF_BUFFER_SIZE];
+
+ /*
+ * We build the output string in a local buffer because we may be
+ * outputting the buffer twice. Using vfprintf is problematic because
+ * some implementations modify the args pointer/structure during
+ * execution. Thus, we use the local buffer for portability.
+ *
+ * Note: Since this module is intended for use by the various ACPICA
+ * utilities/applications, we can safely declare the buffer on the stack.
+ * Also, This function is used for relatively small error messages only.
+ */
+ vsnprintf(buffer, ACPI_VPRINTF_BUFFER_SIZE, fmt, args);
+
+ flags = acpi_gbl_db_output_flags;
+ if (flags & ACPI_DB_REDIRECTABLE_OUTPUT) {
+
+ /* Output is directable to either a file (if open) or the console */
+
+ if (acpi_gbl_debug_file) {
+
+ /* Output file is open, send the output there */
+
+ fputs(buffer, acpi_gbl_debug_file);
+ } else {
+ /* No redirection, send output to console (once only!) */
+
+ flags |= ACPI_DB_CONSOLE_OUTPUT;
+ }
+ }
+
+ if (flags & ACPI_DB_CONSOLE_OUTPUT) {
+ fputs(buffer, acpi_gbl_output_file);
+ }
+}
+
+#ifndef ACPI_EXEC_APP
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_get_line
+ *
+ * PARAMETERS: buffer - Where to return the command line
+ * buffer_length - Maximum length of Buffer
+ * bytes_read - Where the actual byte count is returned
+ *
+ * RETURN: Status and actual bytes read
+ *
+ * DESCRIPTION: Get the next input line from the terminal. NOTE: For the
+ * acpi_exec utility, we use the acgetline module instead to
+ * provide line-editing and history support.
+ *
+ *****************************************************************************/
+
+acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
+{
+ int input_char;
+ u32 end_of_line;
+
+ /* Standard acpi_os_get_line for all utilities except acpi_exec */
+
+ for (end_of_line = 0;; end_of_line++) {
+ if (end_of_line >= buffer_length) {
+ return (AE_BUFFER_OVERFLOW);
+ }
+
+ if ((input_char = getchar()) == EOF) {
+ return (AE_ERROR);
+ }
+
+ if (!input_char || input_char == _ASCII_NEWLINE) {
+ break;
+ }
+
+ buffer[end_of_line] = (char)input_char;
+ }
+
+ /* Null terminate the buffer */
+
+ buffer[end_of_line] = 0;
+
+ /* Return the number of bytes in the string */
+
+ if (bytes_read) {
+ *bytes_read = end_of_line;
+ }
+
+ return (AE_OK);
+}
+#endif
+
+#ifndef ACPI_USE_NATIVE_MEMORY_MAPPING
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_map_memory
+ *
+ * PARAMETERS: where - Physical address of memory to be mapped
+ * length - How much memory to map
+ *
+ * RETURN: Pointer to mapped memory. Null on error.
+ *
+ * DESCRIPTION: Map physical memory into caller's address space
+ *
+ *****************************************************************************/
+
+void *acpi_os_map_memory(acpi_physical_address where, acpi_size length)
+{
+
+ return (ACPI_TO_POINTER((acpi_size) where));
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_unmap_memory
+ *
+ * PARAMETERS: where - Logical address of memory to be unmapped
+ * length - How much memory to unmap
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete a previously created mapping. Where and Length must
+ * correspond to a previous mapping exactly.
+ *
+ *****************************************************************************/
+
+void acpi_os_unmap_memory(void *where, acpi_size length)
+{
+
+ return;
+}
+#endif
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_allocate
+ *
+ * PARAMETERS: size - Amount to allocate, in bytes
+ *
+ * RETURN: Pointer to the new allocation. Null on error.
+ *
+ * DESCRIPTION: Allocate memory. Algorithm is dependent on the OS.
+ *
+ *****************************************************************************/
+
+void *acpi_os_allocate(acpi_size size)
+{
+ void *mem;
+
+ mem = (void *)malloc((size_t) size);
+ return (mem);
+}
+
+#ifdef USE_NATIVE_ALLOCATE_ZEROED
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_allocate_zeroed
+ *
+ * PARAMETERS: size - Amount to allocate, in bytes
+ *
+ * RETURN: Pointer to the new allocation. Null on error.
+ *
+ * DESCRIPTION: Allocate and zero memory. Algorithm is dependent on the OS.
+ *
+ *****************************************************************************/
+
+void *acpi_os_allocate_zeroed(acpi_size size)
+{
+ void *mem;
+
+ mem = (void *)calloc(1, (size_t) size);
+ return (mem);
+}
+#endif
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_free
+ *
+ * PARAMETERS: mem - Pointer to previously allocated memory
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Free memory allocated via acpi_os_allocate
+ *
+ *****************************************************************************/
+
+void acpi_os_free(void *mem)
+{
+
+ free(mem);
+}
+
+#ifdef ACPI_SINGLE_THREADED
+/******************************************************************************
+ *
+ * FUNCTION: Semaphore stub functions
+ *
+ * DESCRIPTION: Stub functions used for single-thread applications that do
+ * not require semaphore synchronization. Full implementations
+ * of these functions appear after the stubs.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_create_semaphore(u32 max_units,
+ u32 initial_units, acpi_handle * out_handle)
+{
+ *out_handle = (acpi_handle) 1;
+ return (AE_OK);
+}
+
+acpi_status acpi_os_delete_semaphore(acpi_handle handle)
+{
+ return (AE_OK);
+}
+
+acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
+{
+ return (AE_OK);
+}
+
+acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
+{
+ return (AE_OK);
+}
+
+#else
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_create_semaphore
+ *
+ * PARAMETERS: initial_units - Units to be assigned to the new semaphore
+ * out_handle - Where a handle will be returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create an OS semaphore
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_create_semaphore(u32 max_units,
+ u32 initial_units, acpi_handle * out_handle)
+{
+ sem_t *sem;
+
+ if (!out_handle) {
+ return (AE_BAD_PARAMETER);
+ }
+#ifdef __APPLE__
+ {
+ char *semaphore_name = tmpnam(NULL);
+
+ sem =
+ sem_open(semaphore_name, O_EXCL | O_CREAT, 0755,
+ initial_units);
+ if (!sem) {
+ return (AE_NO_MEMORY);
+ }
+ sem_unlink(semaphore_name); /* This just deletes the name */
+ }
+
+#else
+ sem = acpi_os_allocate(sizeof(sem_t));
+ if (!sem) {
+ return (AE_NO_MEMORY);
+ }
+
+ if (sem_init(sem, 0, initial_units) == -1) {
+ acpi_os_free(sem);
+ return (AE_BAD_PARAMETER);
+ }
+#endif
+
+ *out_handle = (acpi_handle) sem;
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_delete_semaphore
+ *
+ * PARAMETERS: handle - Handle returned by acpi_os_create_semaphore
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete an OS semaphore
+ *
+ *****************************************************************************/
+
+acpi_status acpi_os_delete_semaphore(acpi_handle handle)
+{
+ sem_t *sem = (sem_t *) handle;
+
+ if (!sem) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (sem_destroy(sem) == -1) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_wait_semaphore
+ *
+ * PARAMETERS: handle - Handle returned by acpi_os_create_semaphore
+ * units - How many units to wait for
+ * msec_timeout - How long to wait (milliseconds)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Wait for units
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 msec_timeout)
+{
+ acpi_status status = AE_OK;
+ sem_t *sem = (sem_t *) handle;
+#ifndef ACPI_USE_ALTERNATE_TIMEOUT
+ struct timespec time;
+ int ret_val;
+#endif
+
+ if (!sem) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ switch (msec_timeout) {
+ /*
+ * No Wait:
+ * --------
+ * A zero timeout value indicates that we shouldn't wait - just
+ * acquire the semaphore if available otherwise return AE_TIME
+ * (a.k.a. 'would block').
+ */
+ case 0:
+
+ if (sem_trywait(sem) == -1) {
+ status = (AE_TIME);
+ }
+ break;
+
+ /* Wait Indefinitely */
+
+ case ACPI_WAIT_FOREVER:
+
+ if (sem_wait(sem)) {
+ status = (AE_TIME);
+ }
+ break;
+
+ /* Wait with msec_timeout */
+
+ default:
+
+#ifdef ACPI_USE_ALTERNATE_TIMEOUT
+ /*
+ * Alternate timeout mechanism for environments where
+ * sem_timedwait is not available or does not work properly.
+ */
+ while (msec_timeout) {
+ if (sem_trywait(sem) == 0) {
+
+ /* Got the semaphore */
+ return (AE_OK);
+ }
+
+ if (msec_timeout >= 10) {
+ msec_timeout -= 10;
+ usleep(10 * ACPI_USEC_PER_MSEC); /* ten milliseconds */
+ } else {
+ msec_timeout--;
+ usleep(ACPI_USEC_PER_MSEC); /* one millisecond */
+ }
+ }
+ status = (AE_TIME);
+#else
+ /*
+ * The interface to sem_timedwait is an absolute time, so we need to
+ * get the current time, then add in the millisecond Timeout value.
+ */
+ if (clock_gettime(CLOCK_REALTIME, &time) == -1) {
+ perror("clock_gettime");
+ return (AE_TIME);
+ }
+
+ time.tv_sec += (msec_timeout / ACPI_MSEC_PER_SEC);
+ time.tv_nsec +=
+ ((msec_timeout % ACPI_MSEC_PER_SEC) * ACPI_NSEC_PER_MSEC);
+
+ /* Handle nanosecond overflow (field must be less than one second) */
+
+ if (time.tv_nsec >= ACPI_NSEC_PER_SEC) {
+ time.tv_sec += (time.tv_nsec / ACPI_NSEC_PER_SEC);
+ time.tv_nsec = (time.tv_nsec % ACPI_NSEC_PER_SEC);
+ }
+
+ while (((ret_val = sem_timedwait(sem, &time)) == -1)
+ && (errno == EINTR)) {
+ continue;
+ }
+
+ if (ret_val != 0) {
+ if (errno != ETIMEDOUT) {
+ perror("sem_timedwait");
+ }
+ status = (AE_TIME);
+ }
+#endif
+ break;
+ }
+
+ return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_signal_semaphore
+ *
+ * PARAMETERS: handle - Handle returned by acpi_os_create_semaphore
+ * units - Number of units to send
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Send units
+ *
+ *****************************************************************************/
+
+acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
+{
+ sem_t *sem = (sem_t *) handle;
+
+ if (!sem) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (sem_post(sem) == -1) {
+ return (AE_LIMIT);
+ }
+
+ return (AE_OK);
+}
+
+#endif /* ACPI_SINGLE_THREADED */
+
+/******************************************************************************
+ *
+ * FUNCTION: Spinlock interfaces
+ *
+ * DESCRIPTION: Map these interfaces to semaphore interfaces
+ *
+ *****************************************************************************/
+
+acpi_status acpi_os_create_lock(acpi_spinlock * out_handle)
+{
+
+ return (acpi_os_create_semaphore(1, 1, out_handle));
+}
+
+void acpi_os_delete_lock(acpi_spinlock handle)
+{
+ acpi_os_delete_semaphore(handle);
+}
+
+acpi_cpu_flags acpi_os_acquire_lock(acpi_handle handle)
+{
+ acpi_os_wait_semaphore(handle, 1, 0xFFFF);
+ return (0);
+}
+
+void acpi_os_release_lock(acpi_spinlock handle, acpi_cpu_flags flags)
+{
+ acpi_os_signal_semaphore(handle, 1);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_install_interrupt_handler
+ *
+ * PARAMETERS: interrupt_number - Level handler should respond to.
+ * isr - Address of the ACPI interrupt handler
+ * except_ptr - Where status is returned
+ *
+ * RETURN: Handle to the newly installed handler.
+ *
+ * DESCRIPTION: Install an interrupt handler. Used to install the ACPI
+ * OS-independent handler.
+ *
+ *****************************************************************************/
+
+u32
+acpi_os_install_interrupt_handler(u32 interrupt_number,
+ acpi_osd_handler service_routine,
+ void *context)
+{
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_remove_interrupt_handler
+ *
+ * PARAMETERS: handle - Returned when handler was installed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Uninstalls an interrupt handler.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_remove_interrupt_handler(u32 interrupt_number,
+ acpi_osd_handler service_routine)
+{
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_stall
+ *
+ * PARAMETERS: microseconds - Time to sleep
+ *
+ * RETURN: Blocks until sleep is completed.
+ *
+ * DESCRIPTION: Sleep at microsecond granularity
+ *
+ *****************************************************************************/
+
+void acpi_os_stall(u32 microseconds)
+{
+
+ if (microseconds) {
+ usleep(microseconds);
+ }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_sleep
+ *
+ * PARAMETERS: milliseconds - Time to sleep
+ *
+ * RETURN: Blocks until sleep is completed.
+ *
+ * DESCRIPTION: Sleep at millisecond granularity
+ *
+ *****************************************************************************/
+
+void acpi_os_sleep(u64 milliseconds)
+{
+
+ /* Sleep for whole seconds */
+
+ sleep(milliseconds / ACPI_MSEC_PER_SEC);
+
+ /*
+ * Sleep for remaining microseconds.
+ * Arg to usleep() is in usecs and must be less than 1,000,000 (1 second).
+ */
+ usleep((milliseconds % ACPI_MSEC_PER_SEC) * ACPI_USEC_PER_MSEC);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_get_timer
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Current time in 100 nanosecond units
+ *
+ * DESCRIPTION: Get the current system time
+ *
+ *****************************************************************************/
+
+u64 acpi_os_get_timer(void)
+{
+ struct timeval time;
+
+ /* This timer has sufficient resolution for user-space application code */
+
+ gettimeofday(&time, NULL);
+
+ /* (Seconds * 10^7 = 100ns(10^-7)) + (Microseconds(10^-6) * 10^1 = 100ns) */
+
+ return (((u64)time.tv_sec * ACPI_100NSEC_PER_SEC) +
+ ((u64)time.tv_usec * ACPI_100NSEC_PER_USEC));
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_read_pci_configuration
+ *
+ * PARAMETERS: pci_id - Seg/Bus/Dev
+ * pci_register - Device Register
+ * value - Buffer where value is placed
+ * width - Number of bits
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read data from PCI configuration space
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id,
+ u32 pci_register, u64 *value, u32 width)
+{
+
+ *value = 0;
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_write_pci_configuration
+ *
+ * PARAMETERS: pci_id - Seg/Bus/Dev
+ * pci_register - Device Register
+ * value - Value to be written
+ * width - Number of bits
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Write data to PCI configuration space
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id,
+ u32 pci_register, u64 value, u32 width)
+{
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_read_port
+ *
+ * PARAMETERS: address - Address of I/O port/register to read
+ * value - Where value is placed
+ * width - Number of bits
+ *
+ * RETURN: Value read from port
+ *
+ * DESCRIPTION: Read data from an I/O port or register
+ *
+ *****************************************************************************/
+
+acpi_status acpi_os_read_port(acpi_io_address address, u32 *value, u32 width)
+{
+
+ switch (width) {
+ case 8:
+
+ *value = 0xFF;
+ break;
+
+ case 16:
+
+ *value = 0xFFFF;
+ break;
+
+ case 32:
+
+ *value = 0xFFFFFFFF;
+ break;
+
+ default:
+
+ return (AE_BAD_PARAMETER);
+ }
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_write_port
+ *
+ * PARAMETERS: address - Address of I/O port/register to write
+ * value - Value to write
+ * width - Number of bits
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Write data to an I/O port or register
+ *
+ *****************************************************************************/
+
+acpi_status acpi_os_write_port(acpi_io_address address, u32 value, u32 width)
+{
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_read_memory
+ *
+ * PARAMETERS: address - Physical Memory Address to read
+ * value - Where value is placed
+ * width - Number of bits (8,16,32, or 64)
+ *
+ * RETURN: Value read from physical memory address. Always returned
+ * as a 64-bit integer, regardless of the read width.
+ *
+ * DESCRIPTION: Read data from a physical memory address
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_read_memory(acpi_physical_address address, u64 *value, u32 width)
+{
+
+ switch (width) {
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+
+ *value = 0;
+ break;
+
+ default:
+
+ return (AE_BAD_PARAMETER);
+ }
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_write_memory
+ *
+ * PARAMETERS: address - Physical Memory Address to write
+ * value - Value to write
+ * width - Number of bits (8,16,32, or 64)
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Write data to a physical memory address
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_write_memory(acpi_physical_address address, u64 value, u32 width)
+{
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_readable
+ *
+ * PARAMETERS: pointer - Area to be verified
+ * length - Size of area
+ *
+ * RETURN: TRUE if readable for entire length
+ *
+ * DESCRIPTION: Verify that a pointer is valid for reading
+ *
+ *****************************************************************************/
+
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+
+ return (TRUE);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_writable
+ *
+ * PARAMETERS: pointer - Area to be verified
+ * length - Size of area
+ *
+ * RETURN: TRUE if writable for entire length
+ *
+ * DESCRIPTION: Verify that a pointer is valid for writing
+ *
+ *****************************************************************************/
+
+u8 acpi_os_writable(void *pointer, acpi_size length)
+{
+
+ return (TRUE);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_signal
+ *
+ * PARAMETERS: function - ACPI A signal function code
+ * info - Pointer to function-dependent structure
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Miscellaneous functions. Example implementation only.
+ *
+ *****************************************************************************/
+
+acpi_status acpi_os_signal(u32 function, void *info)
+{
+
+ switch (function) {
+ case ACPI_SIGNAL_FATAL:
+
+ break;
+
+ case ACPI_SIGNAL_BREAKPOINT:
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ return (AE_OK);
+}
+
+/* Optional multi-thread support */
+
+#ifndef ACPI_SINGLE_THREADED
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_get_thread_id
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Id of the running thread
+ *
+ * DESCRIPTION: Get the ID of the current (running) thread
+ *
+ *****************************************************************************/
+
+acpi_thread_id acpi_os_get_thread_id(void)
+{
+ pthread_t thread;
+
+ thread = pthread_self();
+ return (ACPI_CAST_PTHREAD_T(thread));
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_execute
+ *
+ * PARAMETERS: type - Type of execution
+ * function - Address of the function to execute
+ * context - Passed as a parameter to the function
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Execute a new thread
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_execute(acpi_execute_type type,
+ acpi_osd_exec_callback function, void *context)
+{
+ pthread_t thread;
+ int ret;
+
+ ret =
+ pthread_create(&thread, NULL, (PTHREAD_CALLBACK) function, context);
+ if (ret) {
+ acpi_os_printf("Create thread failed");
+ }
+ return (0);
+}
+
+#else /* ACPI_SINGLE_THREADED */
+acpi_thread_id acpi_os_get_thread_id(void)
+{
+ return (1);
+}
+
+acpi_status
+acpi_os_execute(acpi_execute_type type,
+ acpi_osd_exec_callback function, void *context)
+{
+
+ function(context);
+
+ return (AE_OK);
+}
+
+#endif /* ACPI_SINGLE_THREADED */
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_wait_events_complete
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Wait for all asynchronous events to complete. This
+ * implementation does nothing.
+ *
+ *****************************************************************************/
+
+void acpi_os_wait_events_complete(void)
+{
+ return;
+}
diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h
index 46f5195..a2d37d6 100644
--- a/tools/power/acpi/tools/acpidump/acpidump.h
+++ b/tools/power/acpi/tools/acpidump/acpidump.h
@@ -47,7 +47,6 @@
#ifdef _DECLARE_GLOBALS
#define EXTERN
#define INIT_GLOBAL(a,b) a=b
-#define DEFINE_ACPI_GLOBALS 1
#else
#define EXTERN extern
#define INIT_GLOBAL(a,b) a
@@ -69,7 +68,7 @@ EXTERN u8 INIT_GLOBAL(gbl_verbose_mode, FALSE);
EXTERN u8 INIT_GLOBAL(gbl_binary_mode, FALSE);
EXTERN u8 INIT_GLOBAL(gbl_dump_customized_tables, FALSE);
EXTERN u8 INIT_GLOBAL(gbl_do_not_dump_xsdt, FALSE);
-EXTERN FILE INIT_GLOBAL(*gbl_output_file, NULL);
+EXTERN ACPI_FILE INIT_GLOBAL(gbl_output_file, NULL);
EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL);
EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0);
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c
index 3cac123..53cee78 100644
--- a/tools/power/acpi/tools/acpidump/apdump.c
+++ b/tools/power/acpi/tools/acpidump/apdump.c
@@ -69,17 +69,16 @@ u8 ap_is_valid_header(struct acpi_table_header *table)
/* Make sure signature is all ASCII and a valid ACPI name */
if (!acpi_ut_valid_acpi_name(table->signature)) {
- fprintf(stderr,
- "Table signature (0x%8.8X) is invalid\n",
- *(u32 *)table->signature);
+ acpi_log_error("Table signature (0x%8.8X) is invalid\n",
+ *(u32 *)table->signature);
return (FALSE);
}
/* Check for minimum table length */
if (table->length < sizeof(struct acpi_table_header)) {
- fprintf(stderr, "Table length (0x%8.8X) is invalid\n",
- table->length);
+ acpi_log_error("Table length (0x%8.8X) is invalid\n",
+ table->length);
return (FALSE);
}
}
@@ -116,8 +115,8 @@ u8 ap_is_valid_checksum(struct acpi_table_header *table)
}
if (ACPI_FAILURE(status)) {
- fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n",
- table->signature);
+ acpi_log_error("%4.4s: Warning: wrong checksum in table\n",
+ table->signature);
}
return (AE_OK);
@@ -196,12 +195,13 @@ ap_dump_table_buffer(struct acpi_table_header *table,
* Note: simplest to just always emit a 64-bit address. acpi_xtract
* utility can handle this.
*/
- printf("%4.4s @ 0x%8.8X%8.8X\n", table->signature,
- ACPI_FORMAT_UINT64(address));
+ acpi_ut_file_printf(gbl_output_file, "%4.4s @ 0x%8.8X%8.8X\n",
+ table->signature, ACPI_FORMAT_UINT64(address));
- acpi_ut_dump_buffer(ACPI_CAST_PTR(u8, table), table_length,
- DB_BYTE_DISPLAY, 0);
- printf("\n");
+ acpi_ut_dump_buffer_to_file(gbl_output_file,
+ ACPI_CAST_PTR(u8, table), table_length,
+ DB_BYTE_DISPLAY, 0);
+ acpi_ut_file_printf(gbl_output_file, "\n");
return (0);
}
@@ -239,20 +239,20 @@ int ap_dump_all_tables(void)
if (status == AE_LIMIT) {
return (0);
} else if (i == 0) {
- fprintf(stderr,
- "Could not get ACPI tables, %s\n",
- acpi_format_exception(status));
+ acpi_log_error
+ ("Could not get ACPI tables, %s\n",
+ acpi_format_exception(status));
return (-1);
} else {
- fprintf(stderr,
- "Could not get ACPI table at index %u, %s\n",
- i, acpi_format_exception(status));
+ acpi_log_error
+ ("Could not get ACPI table at index %u, %s\n",
+ i, acpi_format_exception(status));
continue;
}
}
table_status = ap_dump_table_buffer(table, instance, address);
- free(table);
+ ACPI_FREE(table);
if (table_status) {
break;
@@ -288,22 +288,22 @@ int ap_dump_table_by_address(char *ascii_address)
status = acpi_ut_strtoul64(ascii_address, 0, &long_address);
if (ACPI_FAILURE(status)) {
- fprintf(stderr, "%s: Could not convert to a physical address\n",
- ascii_address);
+ acpi_log_error("%s: Could not convert to a physical address\n",
+ ascii_address);
return (-1);
}
address = (acpi_physical_address) long_address;
status = acpi_os_get_table_by_address(address, &table);
if (ACPI_FAILURE(status)) {
- fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n",
- ACPI_FORMAT_UINT64(address),
- acpi_format_exception(status));
+ acpi_log_error("Could not get table at 0x%8.8X%8.8X, %s\n",
+ ACPI_FORMAT_UINT64(address),
+ acpi_format_exception(status));
return (-1);
}
table_status = ap_dump_table_buffer(table, 0, address);
- free(table);
+ ACPI_FREE(table);
return (table_status);
}
@@ -329,24 +329,24 @@ int ap_dump_table_by_name(char *signature)
acpi_status status;
int table_status;
- if (strlen(signature) != ACPI_NAME_SIZE) {
- fprintf(stderr,
- "Invalid table signature [%s]: must be exactly 4 characters\n",
- signature);
+ if (ACPI_STRLEN(signature) != ACPI_NAME_SIZE) {
+ acpi_log_error
+ ("Invalid table signature [%s]: must be exactly 4 characters\n",
+ signature);
return (-1);
}
/* Table signatures are expected to be uppercase */
- strcpy(local_signature, signature);
+ ACPI_STRCPY(local_signature, signature);
acpi_ut_strupr(local_signature);
/* To be friendly, handle tables whose signatures do not match the name */
if (ACPI_COMPARE_NAME(local_signature, "FADT")) {
- strcpy(local_signature, ACPI_SIG_FADT);
+ ACPI_STRCPY(local_signature, ACPI_SIG_FADT);
} else if (ACPI_COMPARE_NAME(local_signature, "MADT")) {
- strcpy(local_signature, ACPI_SIG_MADT);
+ ACPI_STRCPY(local_signature, ACPI_SIG_MADT);
}
/* Dump all instances of this signature (to handle multiple SSDTs) */
@@ -362,14 +362,14 @@ int ap_dump_table_by_name(char *signature)
return (0);
}
- fprintf(stderr,
- "Could not get ACPI table with signature [%s], %s\n",
- local_signature, acpi_format_exception(status));
+ acpi_log_error
+ ("Could not get ACPI table with signature [%s], %s\n",
+ local_signature, acpi_format_exception(status));
return (-1);
}
table_status = ap_dump_table_buffer(table, instance, address);
- free(table);
+ ACPI_FREE(table);
if (table_status) {
break;
@@ -409,43 +409,21 @@ int ap_dump_table_from_file(char *pathname)
/* File must be at least as long as the table length */
if (table->length > file_size) {
- fprintf(stderr,
- "Table length (0x%X) is too large for input file (0x%X) %s\n",
- table->length, file_size, pathname);
+ acpi_log_error
+ ("Table length (0x%X) is too large for input file (0x%X) %s\n",
+ table->length, file_size, pathname);
goto exit;
}
if (gbl_verbose_mode) {
- fprintf(stderr,
- "Input file: %s contains table [%4.4s], 0x%X (%u) bytes\n",
- pathname, table->signature, file_size, file_size);
+ acpi_log_error
+ ("Input file: %s contains table [%4.4s], 0x%X (%u) bytes\n",
+ pathname, table->signature, file_size, file_size);
}
table_status = ap_dump_table_buffer(table, 0, 0);
exit:
- free(table);
+ ACPI_FREE(table);
return (table_status);
}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_os* print functions
- *
- * DESCRIPTION: Used for linkage with ACPICA modules
- *
- ******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE acpi_os_printf(const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- vfprintf(stdout, fmt, args);
- va_end(args);
-}
-
-void acpi_os_vprintf(const char *fmt, va_list args)
-{
- vfprintf(stdout, fmt, args);
-}
diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c
index 4488acc..d470046 100644
--- a/tools/power/acpi/tools/acpidump/apfiles.c
+++ b/tools/power/acpi/tools/acpidump/apfiles.c
@@ -44,6 +44,27 @@
#include "acpidump.h"
#include "acapps.h"
+/* Local prototypes */
+
+static int ap_is_existing_file(char *pathname);
+
+static int ap_is_existing_file(char *pathname)
+{
+#ifndef _GNU_EFI
+ struct stat stat_info;
+
+ if (!stat(pathname, &stat_info)) {
+ acpi_log_error("Target path already exists, overwrite? [y|n] ");
+
+ if (getchar() != 'y') {
+ return (-1);
+ }
+ }
+#endif
+
+ return 0;
+}
+
/******************************************************************************
*
* FUNCTION: ap_open_output_file
@@ -59,25 +80,19 @@
int ap_open_output_file(char *pathname)
{
- struct stat stat_info;
- FILE *file;
+ ACPI_FILE file;
/* If file exists, prompt for overwrite */
- if (!stat(pathname, &stat_info)) {
- fprintf(stderr,
- "Target path already exists, overwrite? [y|n] ");
-
- if (getchar() != 'y') {
- return (-1);
- }
+ if (ap_is_existing_file(pathname) != 0) {
+ return (-1);
}
/* Point stdout to the file */
- file = freopen(pathname, "w", stdout);
+ file = acpi_os_open_file(pathname, ACPI_FILE_WRITING);
if (!file) {
- perror("Could not open output file");
+ acpi_log_error("Could not open output file: %s\n", pathname);
return (-1);
}
@@ -106,7 +121,7 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
{
char filename[ACPI_NAME_SIZE + 16];
char instance_str[16];
- FILE *file;
+ ACPI_FILE file;
size_t actual;
u32 table_length;
@@ -130,35 +145,37 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
/* Handle multiple SSDts - create different filenames for each */
if (instance > 0) {
- sprintf(instance_str, "%u", instance);
- strcat(filename, instance_str);
+ acpi_ut_snprintf(instance_str, sizeof(instance_str), "%u",
+ instance);
+ ACPI_STRCAT(filename, instance_str);
}
- strcat(filename, ACPI_TABLE_FILE_SUFFIX);
+ ACPI_STRCAT(filename, ACPI_TABLE_FILE_SUFFIX);
if (gbl_verbose_mode) {
- fprintf(stderr,
- "Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n",
- table->signature, filename, table->length,
- table->length);
+ acpi_log_error
+ ("Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n",
+ table->signature, filename, table->length, table->length);
}
/* Open the file and dump the entire table in binary mode */
- file = fopen(filename, "wb");
+ file = acpi_os_open_file(filename,
+ ACPI_FILE_WRITING | ACPI_FILE_BINARY);
if (!file) {
- perror("Could not open output file");
+ acpi_log_error("Could not open output file: %s\n", filename);
return (-1);
}
- actual = fwrite(table, 1, table_length, file);
+ actual = acpi_os_write_file(file, table, 1, table_length);
if (actual != table_length) {
- perror("Error writing binary output file");
- fclose(file);
+ acpi_log_error("Error writing binary output file: %s\n",
+ filename);
+ acpi_os_close_file(file);
return (-1);
}
- fclose(file);
+ acpi_os_close_file(file);
return (0);
}
@@ -179,15 +196,16 @@ struct acpi_table_header *ap_get_table_from_file(char *pathname,
u32 *out_file_size)
{
struct acpi_table_header *buffer = NULL;
- FILE *file;
+ ACPI_FILE file;
u32 file_size;
size_t actual;
/* Must use binary mode */
- file = fopen(pathname, "rb");
+ file =
+ acpi_os_open_file(pathname, ACPI_FILE_READING | ACPI_FILE_BINARY);
if (!file) {
- perror("Could not open input file");
+ acpi_log_error("Could not open input file: %s\n", pathname);
return (NULL);
}
@@ -195,27 +213,25 @@ struct acpi_table_header *ap_get_table_from_file(char *pathname,
file_size = cm_get_file_size(file);
if (file_size == ACPI_UINT32_MAX) {
- fprintf(stderr,
- "Could not get input file size: %s\n", pathname);
+ acpi_log_error("Could not get input file size: %s\n", pathname);
goto cleanup;
}
/* Allocate a buffer for the entire file */
- buffer = calloc(1, file_size);
+ buffer = ACPI_ALLOCATE_ZEROED(file_size);
if (!buffer) {
- fprintf(stderr,
- "Could not allocate file buffer of size: %u\n",
- file_size);
+ acpi_log_error("Could not allocate file buffer of size: %u\n",
+ file_size);
goto cleanup;
}
/* Read the entire file */
- actual = fread(buffer, 1, file_size, file);
+ actual = acpi_os_read_file(file, buffer, 1, file_size);
if (actual != file_size) {
- fprintf(stderr, "Could not read input file: %s\n", pathname);
- free(buffer);
+ acpi_log_error("Could not read input file: %s\n", pathname);
+ ACPI_FREE(buffer);
buffer = NULL;
goto cleanup;
}
@@ -223,6 +239,6 @@ struct acpi_table_header *ap_get_table_from_file(char *pathname,
*out_file_size = file_size;
cleanup:
- fclose(file);
+ acpi_os_close_file(file);
return (buffer);
}
diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c
index 51e8d63..853b4da 100644
--- a/tools/power/acpi/tools/acpidump/apmain.c
+++ b/tools/power/acpi/tools/acpidump/apmain.c
@@ -72,7 +72,7 @@ static void ap_display_usage(void);
static int ap_do_options(int argc, char **argv);
-static void ap_insert_action(char *argument, u32 to_be_done);
+static int ap_insert_action(char *argument, u32 to_be_done);
/* Table for deferred actions from command line options */
@@ -104,7 +104,7 @@ static void ap_display_usage(void)
ACPI_OPTION("-v", "Display version information");
ACPI_OPTION("-z", "Verbose mode");
- printf("\nTable Options:\n");
+ ACPI_USAGE_TEXT("\nTable Options:\n");
ACPI_OPTION("-a <Address>", "Get table via a physical address");
ACPI_OPTION("-f <BinaryFile>", "Get table via a binary file");
@@ -112,9 +112,9 @@ static void ap_display_usage(void)
ACPI_OPTION("-x", "Do not use but dump XSDT");
ACPI_OPTION("-x -x", "Do not use or dump XSDT");
- printf("\n"
- "Invocation without parameters dumps all available tables\n"
- "Multiple mixed instances of -a, -f, and -n are supported\n\n");
+ ACPI_USAGE_TEXT("\n"
+ "Invocation without parameters dumps all available tables\n"
+ "Multiple mixed instances of -a, -f, and -n are supported\n\n");
}
/******************************************************************************
@@ -124,13 +124,13 @@ static void ap_display_usage(void)
* PARAMETERS: argument - Pointer to the argument for this action
* to_be_done - What to do to process this action
*
- * RETURN: None. Exits program if action table becomes full.
+ * RETURN: Status
*
* DESCRIPTION: Add an action item to the action table
*
******************************************************************************/
-static void ap_insert_action(char *argument, u32 to_be_done)
+static int ap_insert_action(char *argument, u32 to_be_done)
{
/* Insert action and check for table overflow */
@@ -140,10 +140,12 @@ static void ap_insert_action(char *argument, u32 to_be_done)
current_action++;
if (current_action > AP_MAX_ACTIONS) {
- fprintf(stderr, "Too many table options (max %u)\n",
- AP_MAX_ACTIONS);
- exit(-1);
+ acpi_log_error("Too many table options (max %u)\n",
+ AP_MAX_ACTIONS);
+ return (-1);
}
+
+ return (0);
}
/******************************************************************************
@@ -166,7 +168,8 @@ static int ap_do_options(int argc, char **argv)
/* Command line options */
- while ((j = acpi_getopt(argc, argv, AP_SUPPORTED_OPTIONS)) != EOF)
+ while ((j =
+ acpi_getopt(argc, argv, AP_SUPPORTED_OPTIONS)) != ACPI_OPT_END)
switch (j) {
/*
* Global options
@@ -185,12 +188,12 @@ static int ap_do_options(int argc, char **argv)
case '?':
ap_display_usage();
- exit(0);
+ return (1);
case 'o': /* Redirect output to a single file */
if (ap_open_output_file(acpi_gbl_optarg)) {
- exit(-1);
+ return (-1);
}
continue;
@@ -200,10 +203,10 @@ static int ap_do_options(int argc, char **argv)
acpi_ut_strtoul64(acpi_gbl_optarg, 0,
&gbl_rsdp_base);
if (ACPI_FAILURE(status)) {
- fprintf(stderr,
- "%s: Could not convert to a physical address\n",
- acpi_gbl_optarg);
- exit(-1);
+ acpi_log_error
+ ("%s: Could not convert to a physical address\n",
+ acpi_gbl_optarg);
+ return (-1);
}
continue;
@@ -223,13 +226,13 @@ static int ap_do_options(int argc, char **argv)
case 'v': /* Revision/version */
- printf(ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
- exit(0);
+ acpi_os_printf(ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
+ return (1);
case 'z': /* Verbose mode */
gbl_verbose_mode = TRUE;
- fprintf(stderr, ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
+ acpi_log_error(ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
continue;
/*
@@ -237,32 +240,40 @@ static int ap_do_options(int argc, char **argv)
*/
case 'a': /* Get table by physical address */
- ap_insert_action(acpi_gbl_optarg,
- AP_DUMP_TABLE_BY_ADDRESS);
+ if (ap_insert_action
+ (acpi_gbl_optarg, AP_DUMP_TABLE_BY_ADDRESS)) {
+ return (-1);
+ }
break;
case 'f': /* Get table from a file */
- ap_insert_action(acpi_gbl_optarg,
- AP_DUMP_TABLE_BY_FILE);
+ if (ap_insert_action
+ (acpi_gbl_optarg, AP_DUMP_TABLE_BY_FILE)) {
+ return (-1);
+ }
break;
case 'n': /* Get table by input name (signature) */
- ap_insert_action(acpi_gbl_optarg,
- AP_DUMP_TABLE_BY_NAME);
+ if (ap_insert_action
+ (acpi_gbl_optarg, AP_DUMP_TABLE_BY_NAME)) {
+ return (-1);
+ }
break;
default:
ap_display_usage();
- exit(-1);
+ return (-1);
}
/* If there are no actions, this means "get/dump all tables" */
if (current_action == 0) {
- ap_insert_action(NULL, AP_DUMP_ALL_TABLES);
+ if (ap_insert_action(NULL, AP_DUMP_ALL_TABLES)) {
+ return (-1);
+ }
}
return (0);
@@ -280,7 +291,11 @@ static int ap_do_options(int argc, char **argv)
*
******************************************************************************/
+#ifndef _GNU_EFI
int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
+#else
+int ACPI_SYSTEM_XFACE acpi_main(int argc, char *argv[])
+#endif
{
int status = 0;
struct ap_dump_action *action;
@@ -288,11 +303,17 @@ int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
u32 i;
ACPI_DEBUG_INITIALIZE(); /* For debug version only */
+ acpi_os_initialize();
+ gbl_output_file = ACPI_FILE_OUT;
/* Process command line options */
- if (ap_do_options(argc, argv)) {
- return (-1);
+ status = ap_do_options(argc, argv);
+ if (status > 0) {
+ return (0);
+ }
+ if (status < 0) {
+ return (status);
}
/* Get/dump ACPI table(s) as requested */
@@ -322,9 +343,8 @@ int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
default:
- fprintf(stderr,
- "Internal error, invalid action: 0x%X\n",
- action->to_be_done);
+ acpi_log_error("Internal error, invalid action: 0x%X\n",
+ action->to_be_done);
return (-1);
}
@@ -333,18 +353,18 @@ int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
}
}
- if (gbl_output_file) {
+ if (gbl_output_filename) {
if (gbl_verbose_mode) {
/* Summary for the output file */
file_size = cm_get_file_size(gbl_output_file);
- fprintf(stderr,
- "Output file %s contains 0x%X (%u) bytes\n\n",
- gbl_output_filename, file_size, file_size);
+ acpi_log_error
+ ("Output file %s contains 0x%X (%u) bytes\n\n",
+ gbl_output_filename, file_size, file_size);
}
- fclose(gbl_output_file);
+ acpi_os_close_file(gbl_output_file);
}
return (status);
diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c
index 543bba1..f503fb5 100644
--- a/tools/power/cpupower/bench/parse.c
+++ b/tools/power/cpupower/bench/parse.c
@@ -158,14 +158,15 @@ struct config *prepare_default_config()
int prepare_config(const char *path, struct config *config)
{
size_t len = 0;
- char *opt, *val, *line = NULL;
- FILE *configfile = fopen(path, "r");
+ char opt[16], val[32], *line = NULL;
+ FILE *configfile;
if (config == NULL) {
fprintf(stderr, "error: config is NULL\n");
return 1;
}
+ configfile = fopen(path, "r");
if (configfile == NULL) {
perror("fopen");
fprintf(stderr, "error: unable to read configfile\n");
@@ -174,52 +175,54 @@ int prepare_config(const char *path, struct config *config)
}
while (getline(&line, &len, configfile) != -1) {
- if (line[0] == '#' || line[0] == ' ')
+ if (line[0] == '#' || line[0] == ' ' || line[0] == '\n')
continue;
- sscanf(line, "%as = %as", &opt, &val);
+ if (sscanf(line, "%14s = %30s", opt, val) < 2)
+ continue;
dprintf("parsing: %s -> %s\n", opt, val);
- if (strncmp("sleep", opt, strlen(opt)) == 0)
+ if (strcmp("sleep", opt) == 0)
sscanf(val, "%li", &config->sleep);
- else if (strncmp("load", opt, strlen(opt)) == 0)
+ else if (strcmp("load", opt) == 0)
sscanf(val, "%li", &config->load);
- else if (strncmp("load_step", opt, strlen(opt)) == 0)
+ else if (strcmp("load_step", opt) == 0)
sscanf(val, "%li", &config->load_step);
- else if (strncmp("sleep_step", opt, strlen(opt)) == 0)
+ else if (strcmp("sleep_step", opt) == 0)
sscanf(val, "%li", &config->sleep_step);
- else if (strncmp("cycles", opt, strlen(opt)) == 0)
+ else if (strcmp("cycles", opt) == 0)
sscanf(val, "%u", &config->cycles);
- else if (strncmp("rounds", opt, strlen(opt)) == 0)
+ else if (strcmp("rounds", opt) == 0)
sscanf(val, "%u", &config->rounds);
- else if (strncmp("verbose", opt, strlen(opt)) == 0)
+ else if (strcmp("verbose", opt) == 0)
sscanf(val, "%u", &config->verbose);
- else if (strncmp("output", opt, strlen(opt)) == 0)
+ else if (strcmp("output", opt) == 0)
config->output = prepare_output(val);
- else if (strncmp("cpu", opt, strlen(opt)) == 0)
+ else if (strcmp("cpu", opt) == 0)
sscanf(val, "%u", &config->cpu);
- else if (strncmp("governor", opt, 14) == 0)
- strncpy(config->governor, val, 14);
+ else if (strcmp("governor", opt) == 0) {
+ strncpy(config->governor, val,
+ sizeof(config->governor));
+ config->governor[sizeof(config->governor) - 1] = '\0';
+ }
- else if (strncmp("priority", opt, strlen(opt)) == 0) {
+ else if (strcmp("priority", opt) == 0) {
if (string_to_prio(val) != SCHED_ERR)
config->prio = string_to_prio(val);
}
}
free(line);
- free(opt);
- free(val);
return 0;
}
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
index a416de8..f656e58 100644
--- a/tools/power/cpupower/utils/cpufreq-set.c
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -320,12 +320,11 @@ int cmd_freq_set(int argc, char **argv)
printf(_("Setting cpu: %d\n"), cpu);
ret = do_one_cpu(cpu, &new_pol, freq, policychange);
- if (ret)
- break;
+ if (ret) {
+ print_error();
+ return ret;
+ }
}
- if (ret)
- print_error();
-
- return ret;
+ return 0;
}
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 851c7a1..09afe5d 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -81,7 +81,7 @@ int sysfs_is_cpu_online(unsigned int cpu)
close(fd);
value = strtoull(linebuf, &endp, 0);
- if (value > 1 || value < 0)
+ if (value > 1)
return -EINVAL;
return value;
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
index 5650ab5..90a8c4f 100644
--- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
@@ -237,7 +237,7 @@ static int init_maxfreq_mode(void)
unsigned long long hwcr;
unsigned long min;
- if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC)
+ if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC))
goto use_sysfs;
if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) {
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index d0396af..5b1b807 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -267,90 +267,90 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
/*
* Example Format w/ field column widths:
*
- * Package Core CPU Avg_MHz Bzy_MHz TSC_MHz SMI %Busy CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
- * 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567
+ * Package Core CPU Avg_MHz Bzy_MHz TSC_MHz SMI %Busy CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
+ * 123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678
*/
void print_header(void)
{
if (show_pkg)
- outp += sprintf(outp, "Package ");
+ outp += sprintf(outp, " Package");
if (show_core)
- outp += sprintf(outp, " Core ");
+ outp += sprintf(outp, " Core");
if (show_cpu)
- outp += sprintf(outp, " CPU ");
+ outp += sprintf(outp, " CPU");
if (has_aperf)
- outp += sprintf(outp, "Avg_MHz ");
+ outp += sprintf(outp, " Avg_MHz");
if (do_nhm_cstates)
- outp += sprintf(outp, " %%Busy ");
+ outp += sprintf(outp, " %%Busy");
if (has_aperf)
- outp += sprintf(outp, "Bzy_MHz ");
- outp += sprintf(outp, "TSC_MHz ");
+ outp += sprintf(outp, " Bzy_MHz");
+ outp += sprintf(outp, " TSC_MHz");
if (do_smi)
- outp += sprintf(outp, " SMI ");
+ outp += sprintf(outp, " SMI");
if (extra_delta_offset32)
- outp += sprintf(outp, " count 0x%03X ", extra_delta_offset32);
+ outp += sprintf(outp, " count 0x%03X", extra_delta_offset32);
if (extra_delta_offset64)
- outp += sprintf(outp, " COUNT 0x%03X ", extra_delta_offset64);
+ outp += sprintf(outp, " COUNT 0x%03X", extra_delta_offset64);
if (extra_msr_offset32)
- outp += sprintf(outp, " MSR 0x%03X ", extra_msr_offset32);
+ outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset32);
if (extra_msr_offset64)
- outp += sprintf(outp, " MSR 0x%03X ", extra_msr_offset64);
+ outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset64);
if (do_nhm_cstates)
- outp += sprintf(outp, " CPU%%c1 ");
+ outp += sprintf(outp, " CPU%%c1");
if (do_nhm_cstates && !do_slm_cstates)
- outp += sprintf(outp, " CPU%%c3 ");
+ outp += sprintf(outp, " CPU%%c3");
if (do_nhm_cstates)
- outp += sprintf(outp, " CPU%%c6 ");
+ outp += sprintf(outp, " CPU%%c6");
if (do_snb_cstates)
- outp += sprintf(outp, " CPU%%c7 ");
+ outp += sprintf(outp, " CPU%%c7");
if (do_dts)
- outp += sprintf(outp, "CoreTmp ");
+ outp += sprintf(outp, " CoreTmp");
if (do_ptm)
- outp += sprintf(outp, " PkgTmp ");
+ outp += sprintf(outp, " PkgTmp");
if (do_snb_cstates)
- outp += sprintf(outp, "Pkg%%pc2 ");
+ outp += sprintf(outp, " Pkg%%pc2");
if (do_nhm_cstates && !do_slm_cstates)
- outp += sprintf(outp, "Pkg%%pc3 ");
+ outp += sprintf(outp, " Pkg%%pc3");
if (do_nhm_cstates && !do_slm_cstates)
- outp += sprintf(outp, "Pkg%%pc6 ");
+ outp += sprintf(outp, " Pkg%%pc6");
if (do_snb_cstates)
- outp += sprintf(outp, "Pkg%%pc7 ");
+ outp += sprintf(outp, " Pkg%%pc7");
if (do_c8_c9_c10) {
- outp += sprintf(outp, "Pkg%%pc8 ");
- outp += sprintf(outp, "Pkg%%pc9 ");
- outp += sprintf(outp, "Pk%%pc10 ");
+ outp += sprintf(outp, " Pkg%%pc8");
+ outp += sprintf(outp, " Pkg%%pc9");
+ outp += sprintf(outp, " Pk%%pc10");
}
if (do_rapl && !rapl_joules) {
if (do_rapl & RAPL_PKG)
- outp += sprintf(outp, "PkgWatt ");
+ outp += sprintf(outp, " PkgWatt");
if (do_rapl & RAPL_CORES)
- outp += sprintf(outp, "CorWatt ");
+ outp += sprintf(outp, " CorWatt");
if (do_rapl & RAPL_GFX)
- outp += sprintf(outp, "GFXWatt ");
+ outp += sprintf(outp, " GFXWatt");
if (do_rapl & RAPL_DRAM)
- outp += sprintf(outp, "RAMWatt ");
+ outp += sprintf(outp, " RAMWatt");
if (do_rapl & RAPL_PKG_PERF_STATUS)
- outp += sprintf(outp, " PKG_%% ");
+ outp += sprintf(outp, " PKG_%%");
if (do_rapl & RAPL_DRAM_PERF_STATUS)
- outp += sprintf(outp, " RAM_%% ");
+ outp += sprintf(outp, " RAM_%%");
} else {
if (do_rapl & RAPL_PKG)
- outp += sprintf(outp, " Pkg_J ");
+ outp += sprintf(outp, " Pkg_J");
if (do_rapl & RAPL_CORES)
- outp += sprintf(outp, " Cor_J ");
+ outp += sprintf(outp, " Cor_J");
if (do_rapl & RAPL_GFX)
- outp += sprintf(outp, " GFX_J ");
+ outp += sprintf(outp, " GFX_J");
if (do_rapl & RAPL_DRAM)
- outp += sprintf(outp, " RAM_W ");
+ outp += sprintf(outp, " RAM_W");
if (do_rapl & RAPL_PKG_PERF_STATUS)
- outp += sprintf(outp, " PKG_%% ");
+ outp += sprintf(outp, " PKG_%%");
if (do_rapl & RAPL_DRAM_PERF_STATUS)
- outp += sprintf(outp, " RAM_%% ");
- outp += sprintf(outp, " time ");
+ outp += sprintf(outp, " RAM_%%");
+ outp += sprintf(outp, " time");
}
outp += sprintf(outp, "\n");
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 55ab700..bf13981 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -194,6 +194,7 @@ my $config_bisect_check;
my $patchcheck_type;
my $patchcheck_start;
+my $patchcheck_cherry;
my $patchcheck_end;
# set when a test is something other that just building or install
@@ -320,6 +321,7 @@ my %option_map = (
"PATCHCHECK_TYPE" => \$patchcheck_type,
"PATCHCHECK_START" => \$patchcheck_start,
+ "PATCHCHECK_CHERRY" => \$patchcheck_cherry,
"PATCHCHECK_END" => \$patchcheck_end,
);
@@ -1448,6 +1450,12 @@ sub wait_for_monitor {
}
}
print "** Monitor flushed **\n";
+
+ # if stop is defined but wasn't hit, return error
+ # used by reboot (which wants to see a reboot)
+ if (defined($stop) && !$booted) {
+ $bug = 1;
+ }
return $bug;
}
@@ -2336,15 +2344,17 @@ sub success {
sub answer_bisect {
for (;;) {
- doprint "Pass or fail? [p/f]";
+ doprint "Pass, fail, or skip? [p/f/s]";
my $ans = <STDIN>;
chomp $ans;
if ($ans eq "p" || $ans eq "P") {
return 1;
} elsif ($ans eq "f" || $ans eq "F") {
return 0;
+ } elsif ($ans eq "s" || $ans eq "S") {
+ return -1;
} else {
- print "Please answer 'P' or 'F'\n";
+ print "Please answer 'p', 'f', or 's'\n";
}
}
}
@@ -2726,15 +2736,17 @@ sub bisect {
run_command "git bisect start$start_files" or
dodie "could not start bisect";
- run_command "git bisect good $good" or
- dodie "could not set bisect good to $good";
-
- run_git_bisect "git bisect bad $bad" or
- dodie "could not set bisect bad to $bad";
-
if (defined($replay)) {
run_command "git bisect replay $replay" or
dodie "failed to run replay";
+ } else {
+
+ run_command "git bisect good $good" or
+ dodie "could not set bisect good to $good";
+
+ run_git_bisect "git bisect bad $bad" or
+ dodie "could not set bisect bad to $bad";
+
}
if (defined($start)) {
@@ -3181,9 +3193,16 @@ sub patchcheck {
my $start = $patchcheck_start;
+ my $cherry = $patchcheck_cherry;
+ if (!defined($cherry)) {
+ $cherry = 0;
+ }
+
my $end = "HEAD";
if (defined($patchcheck_end)) {
$end = $patchcheck_end;
+ } elsif ($cherry) {
+ die "PATCHCHECK_END must be defined with PATCHCHECK_CHERRY\n";
}
# Get the true sha1's since we can use things like HEAD~3
@@ -3197,24 +3216,38 @@ sub patchcheck {
$type = "boot";
}
- open (IN, "git log --pretty=oneline $end|") or
- dodie "could not get git list";
+ if ($cherry) {
+ open (IN, "git cherry -v $start $end|") or
+ dodie "could not get git list";
+ } else {
+ open (IN, "git log --pretty=oneline $end|") or
+ dodie "could not get git list";
+ }
my @list;
while (<IN>) {
chomp;
+ # git cherry adds a '+' we want to remove
+ s/^\+ //;
$list[$#list+1] = $_;
last if (/^$start/);
}
close(IN);
- if ($list[$#list] !~ /^$start/) {
- fail "SHA1 $start not found";
+ if (!$cherry) {
+ if ($list[$#list] !~ /^$start/) {
+ fail "SHA1 $start not found";
+ }
+
+ # go backwards in the list
+ @list = reverse @list;
}
- # go backwards in the list
- @list = reverse @list;
+ doprint("Going to test the following commits:\n");
+ foreach my $l (@list) {
+ doprint "$l\n";
+ }
my $save_clean = $noclean;
my %ignored_warnings;
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index 911e45a..6c58cd8 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -906,6 +906,16 @@
#
# PATCHCHECK_END is the last patch to check (default HEAD)
#
+# PATCHCHECK_CHERRY if set to non zero, then git cherry will be
+# performed against PATCHCHECK_START and PATCHCHECK_END. That is
+#
+# git cherry ${PATCHCHECK_START} ${PATCHCHECK_END}
+#
+# Then the changes found will be tested.
+#
+# Note, PATCHCHECK_CHERRY requires PATCHCHECK_END to be defined.
+# (default 0)
+#
# PATCHCHECK_TYPE is required and is the type of test to run:
# build, boot, test.
#
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index e66e710..45f145c 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -2,8 +2,10 @@ TARGETS = breakpoints
TARGETS += cpu-hotplug
TARGETS += efivarfs
TARGETS += kcmp
+TARGETS += memfd
TARGETS += memory-hotplug
TARGETS += mqueue
+TARGETS += mount
TARGETS += net
TARGETS += ptrace
TARGETS += timers
@@ -11,6 +13,11 @@ TARGETS += vm
TARGETS += powerpc
TARGETS += user
TARGETS += sysctl
+TARGETS += firmware
+TARGETS += ftrace
+
+TARGETS_HOTPLUG = cpu-hotplug
+TARGETS_HOTPLUG += memory-hotplug
all:
for TARGET in $(TARGETS); do \
@@ -22,6 +29,21 @@ run_tests: all
make -C $$TARGET run_tests; \
done;
+hotplug:
+ for TARGET in $(TARGETS_HOTPLUG); do \
+ make -C $$TARGET; \
+ done;
+
+run_hotplug: hotplug
+ for TARGET in $(TARGETS_HOTPLUG); do \
+ make -C $$TARGET run_full_test; \
+ done;
+
+clean_hotplug:
+ for TARGET in $(TARGETS_HOTPLUG); do \
+ make -C $$TARGET clean; \
+ done;
+
clean:
for TARGET in $(TARGETS); do \
make -C $$TARGET clean; \
diff --git a/tools/testing/selftests/README.txt b/tools/testing/selftests/README.txt
index 5e2faf9..2660d5f 100644
--- a/tools/testing/selftests/README.txt
+++ b/tools/testing/selftests/README.txt
@@ -4,8 +4,15 @@ The kernel contains a set of "self tests" under the tools/testing/selftests/
directory. These are intended to be small unit tests to exercise individual
code paths in the kernel.
-Running the selftests
-=====================
+On some systems, hot-plug tests could hang forever waiting for cpu and
+memory to be ready to be offlined. A special hot-plug target is created
+to run full range of hot-plug tests. In default mode, hot-plug tests run
+in safe mode with a limited scope. In limited mode, cpu-hotplug test is
+run on a single cpu as opposed to all hotplug capable cpus, and memory
+hotplug test is run on 2% of hotplug capable memory instead of 10%.
+
+Running the selftests (hotplug tests are run in limited mode)
+=============================================================
To build the tests:
@@ -18,14 +25,26 @@ To run the tests:
- note that some tests will require root privileges.
-
-To run only tests targetted for a single subsystem:
+To run only tests targeted for a single subsystem: (including
+hotplug targets in limited mode)
$ make -C tools/testing/selftests TARGETS=cpu-hotplug run_tests
See the top-level tools/testing/selftests/Makefile for the list of all possible
targets.
+Running the full range hotplug selftests
+========================================
+
+To build the tests:
+
+ $ make -C tools/testing/selftests hotplug
+
+To run the tests:
+
+ $ make -C tools/testing/selftests run_hotplug
+
+- note that some tests will require root privileges.
Contributing new tests
======================
diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile
index 790c23a..e9c28d8 100644
--- a/tools/testing/selftests/cpu-hotplug/Makefile
+++ b/tools/testing/selftests/cpu-hotplug/Makefile
@@ -3,4 +3,7 @@ all:
run_tests:
@/bin/bash ./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]"
+run_full_test:
+ @/bin/bash ./on-off-test.sh -a || echo "cpu-hotplug selftests: [FAIL]"
+
clean:
diff --git a/tools/testing/selftests/cpu-hotplug/on-off-test.sh b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
index bdde7cf..98b1d65 100644
--- a/tools/testing/selftests/cpu-hotplug/on-off-test.sh
+++ b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
@@ -11,6 +11,8 @@ prerequisite()
exit 0
fi
+ taskset -p 01 $$
+
SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
if [ ! -d "$SYSFS" ]; then
@@ -22,6 +24,19 @@ prerequisite()
echo $msg cpu hotplug is not supported >&2
exit 0
fi
+
+ echo "CPU online/offline summary:"
+ online_cpus=`cat $SYSFS/devices/system/cpu/online`
+ online_max=${online_cpus##*-}
+ echo -e "\t Cpus in online state: $online_cpus"
+
+ offline_cpus=`cat $SYSFS/devices/system/cpu/offline`
+ if [[ "a$offline_cpus" = "a" ]]; then
+ offline_cpus=0
+ else
+ offline_max=${offline_cpus##*-}
+ fi
+ echo -e "\t Cpus in offline state: $offline_cpus"
}
#
@@ -113,15 +128,25 @@ offline_cpu_expect_fail()
}
error=-12
+allcpus=0
priority=0
+online_cpus=0
+online_max=0
+offline_cpus=0
+offline_max=0
-while getopts e:hp: opt; do
+while getopts e:ahp: opt; do
case $opt in
e)
error=$OPTARG
;;
+ a)
+ allcpus=1
+ ;;
h)
- echo "Usage $0 [ -e errno ] [ -p notifier-priority ]"
+ echo "Usage $0 [ -a ] [ -e errno ] [ -p notifier-priority ]"
+ echo -e "\t default offline one cpu"
+ echo -e "\t run with -a option to offline all cpus"
exit
;;
p)
@@ -138,6 +163,29 @@ fi
prerequisite
#
+# Safe test (default) - offline and online one cpu
+#
+if [ $allcpus -eq 0 ]; then
+ echo "Limited scope test: one hotplug cpu"
+ echo -e "\t (leaves cpu in the original state):"
+ echo -e "\t online to offline to online: cpu $online_max"
+ offline_cpu_expect_success $online_max
+ online_cpu_expect_success $online_max
+
+ if [[ $offline_cpus -gt 0 ]]; then
+ echo -e "\t offline to online to offline: cpu $offline_max"
+ online_cpu_expect_success $offline_max
+ offline_cpu_expect_success $offline_max
+ fi
+ exit 0
+else
+ echo "Full scope test: all hotplug cpus"
+ echo -e "\t online all offline cpus"
+ echo -e "\t offline all online cpus"
+ echo -e "\t online all offline cpus"
+fi
+
+#
# Online all hot-pluggable CPUs
#
for cpu in `hotplaggable_offline_cpus`; do
diff --git a/tools/testing/selftests/firmware/Makefile b/tools/testing/selftests/firmware/Makefile
new file mode 100644
index 0000000..e23cce0
--- /dev/null
+++ b/tools/testing/selftests/firmware/Makefile
@@ -0,0 +1,27 @@
+# Makefile for firmware loading selftests
+
+# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
+all:
+
+fw_filesystem:
+ @if /bin/sh ./fw_filesystem.sh ; then \
+ echo "fw_filesystem: ok"; \
+ else \
+ echo "fw_filesystem: [FAIL]"; \
+ exit 1; \
+ fi
+
+fw_userhelper:
+ @if /bin/sh ./fw_userhelper.sh ; then \
+ echo "fw_userhelper: ok"; \
+ else \
+ echo "fw_userhelper: [FAIL]"; \
+ exit 1; \
+ fi
+
+run_tests: all fw_filesystem fw_userhelper
+
+# Nothing to clean up.
+clean:
+
+.PHONY: all clean run_tests fw_filesystem fw_userhelper
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh
new file mode 100644
index 0000000..3fc6c10
--- /dev/null
+++ b/tools/testing/selftests/firmware/fw_filesystem.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# This validates that the kernel will load firmware out of its list of
+# firmware locations on disk. Since the user helper does similar work,
+# we reset the custom load directory to a location the user helper doesn't
+# know so we can be sure we're not accidentally testing the user helper.
+set -e
+
+modprobe test_firmware
+
+DIR=/sys/devices/virtual/misc/test_firmware
+
+OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
+OLD_FWPATH=$(cat /sys/module/firmware_class/parameters/path)
+
+FWPATH=$(mktemp -d)
+FW="$FWPATH/test-firmware.bin"
+
+test_finish()
+{
+ echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
+ echo -n "$OLD_PATH" >/sys/module/firmware_class/parameters/path
+ rm -f "$FW"
+ rmdir "$FWPATH"
+}
+
+trap "test_finish" EXIT
+
+# Turn down the timeout so failures don't take so long.
+echo 1 >/sys/class/firmware/timeout
+# Set the kernel search path.
+echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path
+
+# This is an unlikely real-world firmware content. :)
+echo "ABCD0123" >"$FW"
+
+NAME=$(basename "$FW")
+
+# Request a firmware that doesn't exist, it should fail.
+echo -n "nope-$NAME" >"$DIR"/trigger_request
+if diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not expected to match" >&2
+ exit 1
+else
+ echo "$0: timeout works"
+fi
+
+# This should succeed via kernel load or will fail after 1 second after
+# being handed over to the user helper, which won't find the fw either.
+if ! echo -n "$NAME" >"$DIR"/trigger_request ; then
+ echo "$0: could not trigger request" >&2
+ exit 1
+fi
+
+# Verify the contents are what we expect.
+if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not loaded" >&2
+ exit 1
+else
+ echo "$0: filesystem loading works"
+fi
+
+exit 0
diff --git a/tools/testing/selftests/firmware/fw_userhelper.sh b/tools/testing/selftests/firmware/fw_userhelper.sh
new file mode 100644
index 0000000..6efbade
--- /dev/null
+++ b/tools/testing/selftests/firmware/fw_userhelper.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+# This validates that the kernel will fall back to using the user helper
+# to load firmware it can't find on disk itself. We must request a firmware
+# that the kernel won't find, and any installed helper (e.g. udev) also
+# won't find so that we can do the load ourself manually.
+set -e
+
+modprobe test_firmware
+
+DIR=/sys/devices/virtual/misc/test_firmware
+
+OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
+
+FWPATH=$(mktemp -d)
+FW="$FWPATH/test-firmware.bin"
+
+test_finish()
+{
+ echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
+ rm -f "$FW"
+ rmdir "$FWPATH"
+}
+
+load_fw()
+{
+ local name="$1"
+ local file="$2"
+
+ # This will block until our load (below) has finished.
+ echo -n "$name" >"$DIR"/trigger_request &
+
+ # Give kernel a chance to react.
+ local timeout=10
+ while [ ! -e "$DIR"/"$name"/loading ]; do
+ sleep 0.1
+ timeout=$(( $timeout - 1 ))
+ if [ "$timeout" -eq 0 ]; then
+ echo "$0: firmware interface never appeared" >&2
+ exit 1
+ fi
+ done
+
+ echo 1 >"$DIR"/"$name"/loading
+ cat "$file" >"$DIR"/"$name"/data
+ echo 0 >"$DIR"/"$name"/loading
+
+ # Wait for request to finish.
+ wait
+}
+
+trap "test_finish" EXIT
+
+# This is an unlikely real-world firmware content. :)
+echo "ABCD0123" >"$FW"
+NAME=$(basename "$FW")
+
+# Test failure when doing nothing (timeout works).
+echo 1 >/sys/class/firmware/timeout
+echo -n "$NAME" >"$DIR"/trigger_request
+if diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not expected to match" >&2
+ exit 1
+else
+ echo "$0: timeout works"
+fi
+
+# Put timeout high enough for us to do work but not so long that failures
+# slow down this test too much.
+echo 4 >/sys/class/firmware/timeout
+
+# Load this script instead of the desired firmware.
+load_fw "$NAME" "$0"
+if diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not expected to match" >&2
+ exit 1
+else
+ echo "$0: firmware comparison works"
+fi
+
+# Do a proper load, which should work correctly.
+load_fw "$NAME" "$FW"
+if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not loaded" >&2
+ exit 1
+else
+ echo "$0: user helper firmware loading works"
+fi
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/Makefile b/tools/testing/selftests/ftrace/Makefile
new file mode 100644
index 0000000..76cc9f1
--- /dev/null
+++ b/tools/testing/selftests/ftrace/Makefile
@@ -0,0 +1,7 @@
+all:
+
+run_tests:
+ @/bin/sh ./ftracetest || echo "ftrace selftests: [FAIL]"
+
+clean:
+ rm -rf logs/*
diff --git a/tools/testing/selftests/ftrace/README b/tools/testing/selftests/ftrace/README
new file mode 100644
index 0000000..182e76f
--- /dev/null
+++ b/tools/testing/selftests/ftrace/README
@@ -0,0 +1,82 @@
+Linux Ftrace Testcases
+
+This is a collection of testcases for ftrace tracing feature in the Linux
+kernel. Since ftrace exports interfaces via the debugfs, we just need
+shell scripts for testing. Feel free to add new test cases.
+
+Running the ftrace testcases
+============================
+
+At first, you need to be the root user to run this script.
+To run all testcases:
+
+ $ sudo ./ftracetest
+
+To run specific testcases:
+
+ # ./ftracetest test.d/basic3.tc
+
+Or you can also run testcases under given directory:
+
+ # ./ftracetest test.d/kprobe/
+
+Contributing new testcases
+==========================
+
+Copy test.d/template to your testcase (whose filename must have *.tc
+extension) and rewrite the test description line.
+
+ * The working directory of the script is <debugfs>/tracing/.
+
+ * Take care with side effects as the tests are run with root privilege.
+
+ * The tests should not run for a long period of time (more than 1 min.)
+ These are to be unit tests.
+
+ * You can add a directory for your testcases under test.d/ if needed.
+
+ * The test cases should run on dash (busybox shell) for testing on
+ minimal cross-build environments.
+
+ * Note that the tests are run with "set -e" (errexit) option. If any
+ command fails, the test will be terminated immediately.
+
+ * The tests can return some result codes instead of pass or fail by
+ using exit_unresolved, exit_untested, exit_unsupported and exit_xfail.
+
+Result code
+===========
+
+Ftracetest supports following result codes.
+
+ * PASS: The test succeeded as expected. The test which exits with 0 is
+ counted as passed test.
+
+ * FAIL: The test failed, but was expected to succeed. The test which exits
+ with !0 is counted as failed test.
+
+ * UNRESOLVED: The test produced unclear or intermidiate results.
+ for example, the test was interrupted
+ or the test depends on a previous test, which failed.
+ or the test was set up incorrectly
+ The test which is in above situation, must call exit_unresolved.
+
+ * UNTESTED: The test was not run, currently just a placeholder.
+ In this case, the test must call exit_untested.
+
+ * UNSUPPORTED: The test failed because of lack of feature.
+ In this case, the test must call exit_unsupported.
+
+ * XFAIL: The test failed, and was expected to fail.
+ To return XFAIL, call exit_xfail from the test.
+
+There are some sample test scripts for result code under samples/.
+You can also run samples as below:
+
+ # ./ftracetest samples/
+
+TODO
+====
+
+ * Fancy colored output :)
+
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest
new file mode 100755
index 0000000..a8f81c7
--- /dev/null
+++ b/tools/testing/selftests/ftrace/ftracetest
@@ -0,0 +1,253 @@
+#!/bin/sh
+
+# ftracetest - Ftrace test shell scripts
+#
+# Copyright (C) Hitachi Ltd., 2014
+# Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+#
+# Released under the terms of the GPL v2.
+
+usage() { # errno [message]
+[ "$2" ] && echo $2
+echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]"
+echo " Options:"
+echo " -h|--help Show help message"
+echo " -k|--keep Keep passed test logs"
+echo " -d|--debug Debug mode (trace all shell commands)"
+exit $1
+}
+
+errexit() { # message
+ echo "Error: $1" 1>&2
+ exit 1
+}
+
+# Ensuring user privilege
+if [ `id -u` -ne 0 ]; then
+ errexit "this must be run by root user"
+fi
+
+# Utilities
+absdir() { # file_path
+ (cd `dirname $1`; pwd)
+}
+
+abspath() {
+ echo `absdir $1`/`basename $1`
+}
+
+find_testcases() { #directory
+ echo `find $1 -name \*.tc`
+}
+
+parse_opts() { # opts
+ local OPT_TEST_CASES=
+ local OPT_TEST_DIR=
+
+ while [ "$1" ]; do
+ case "$1" in
+ --help|-h)
+ usage 0
+ ;;
+ --keep|-k)
+ KEEP_LOG=1
+ shift 1
+ ;;
+ --debug|-d)
+ DEBUG=1
+ shift 1
+ ;;
+ *.tc)
+ if [ -f "$1" ]; then
+ OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`"
+ shift 1
+ else
+ usage 1 "$1 is not a testcase"
+ fi
+ ;;
+ *)
+ if [ -d "$1" ]; then
+ OPT_TEST_DIR=`abspath $1`
+ OPT_TEST_CASES="$OPT_TEST_CASES `find_testcases $OPT_TEST_DIR`"
+ shift 1
+ else
+ usage 1 "Invalid option ($1)"
+ fi
+ ;;
+ esac
+ done
+ if [ "$OPT_TEST_CASES" ]; then
+ TEST_CASES=$OPT_TEST_CASES
+ fi
+}
+
+# Parameters
+DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' '`
+TRACING_DIR=$DEBUGFS_DIR/tracing
+TOP_DIR=`absdir $0`
+TEST_DIR=$TOP_DIR/test.d
+TEST_CASES=`find_testcases $TEST_DIR`
+LOG_DIR=$TOP_DIR/logs/`date +%Y%m%d-%H%M%S`/
+KEEP_LOG=0
+DEBUG=0
+# Parse command-line options
+parse_opts $*
+
+[ $DEBUG -ne 0 ] && set -x
+
+# Verify parameters
+if [ -z "$DEBUGFS_DIR" -o ! -d "$TRACING_DIR" ]; then
+ errexit "No ftrace directory found"
+fi
+
+# Preparing logs
+LOG_FILE=$LOG_DIR/ftracetest.log
+mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR"
+date > $LOG_FILE
+prlog() { # messages
+ echo "$@" | tee -a $LOG_FILE
+}
+catlog() { #file
+ cat $1 | tee -a $LOG_FILE
+}
+prlog "=== Ftrace unit tests ==="
+
+
+# Testcase management
+# Test result codes - Dejagnu extended code
+PASS=0 # The test succeeded.
+FAIL=1 # The test failed, but was expected to succeed.
+UNRESOLVED=2 # The test produced indeterminate results. (e.g. interrupted)
+UNTESTED=3 # The test was not run, currently just a placeholder.
+UNSUPPORTED=4 # The test failed because of lack of feature.
+XFAIL=5 # The test failed, and was expected to fail.
+
+# Accumulations
+PASSED_CASES=
+FAILED_CASES=
+UNRESOLVED_CASES=
+UNTESTED_CASES=
+UNSUPPORTED_CASES=
+XFAILED_CASES=
+UNDEFINED_CASES=
+TOTAL_RESULT=0
+
+CASENO=0
+testcase() { # testfile
+ CASENO=$((CASENO+1))
+ prlog -n "[$CASENO]"`grep "^#[ \t]*description:" $1 | cut -f2 -d:`
+}
+
+eval_result() { # retval sigval
+ local retval=$2
+ if [ $2 -eq 0 ]; then
+ test $1 -ne 0 && retval=$FAIL
+ fi
+ case $retval in
+ $PASS)
+ prlog " [PASS]"
+ PASSED_CASES="$PASSED_CASES $CASENO"
+ return 0
+ ;;
+ $FAIL)
+ prlog " [FAIL]"
+ FAILED_CASES="$FAILED_CASES $CASENO"
+ return 1 # this is a bug.
+ ;;
+ $UNRESOLVED)
+ prlog " [UNRESOLVED]"
+ UNRESOLVED_CASES="$UNRESOLVED_CASES $CASENO"
+ return 1 # this is a kind of bug.. something happened.
+ ;;
+ $UNTESTED)
+ prlog " [UNTESTED]"
+ UNTESTED_CASES="$UNTESTED_CASES $CASENO"
+ return 0
+ ;;
+ $UNSUPPORTED)
+ prlog " [UNSUPPORTED]"
+ UNSUPPORTED_CASES="$UNSUPPORTED_CASES $CASENO"
+ return 1 # this is not a bug, but the result should be reported.
+ ;;
+ $XFAIL)
+ prlog " [XFAIL]"
+ XFAILED_CASES="$XFAILED_CASES $CASENO"
+ return 0
+ ;;
+ *)
+ prlog " [UNDEFINED]"
+ UNDEFINED_CASES="$UNDEFINED_CASES $CASENO"
+ return 1 # this must be a test bug
+ ;;
+ esac
+}
+
+# Signal handling for result codes
+SIG_RESULT=
+SIG_BASE=36 # Use realtime signals
+SIG_PID=$$
+
+SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED))
+exit_unresolved () {
+ kill -s $SIG_UNRESOLVED $SIG_PID
+ exit 0
+}
+trap 'SIG_RESULT=$UNRESOLVED' $SIG_UNRESOLVED
+
+SIG_UNTESTED=$((SIG_BASE + UNTESTED))
+exit_untested () {
+ kill -s $SIG_UNTESTED $SIG_PID
+ exit 0
+}
+trap 'SIG_RESULT=$UNTESTED' $SIG_UNTESTED
+
+SIG_UNSUPPORTED=$((SIG_BASE + UNSUPPORTED))
+exit_unsupported () {
+ kill -s $SIG_UNSUPPORTED $SIG_PID
+ exit 0
+}
+trap 'SIG_RESULT=$UNSUPPORTED' $SIG_UNSUPPORTED
+
+SIG_XFAIL=$((SIG_BASE + XFAIL))
+exit_xfail () {
+ kill -s $SIG_XFAIL $SIG_PID
+ exit 0
+}
+trap 'SIG_RESULT=$XFAIL' $SIG_XFAIL
+
+# Run one test case
+run_test() { # testfile
+ local testname=`basename $1`
+ local testlog=`mktemp --tmpdir=$LOG_DIR ${testname}-XXXXXX.log`
+ testcase $1
+ echo "execute: "$1 > $testlog
+ SIG_RESULT=0
+ # setup PID and PPID, $$ is not updated.
+ (cd $TRACING_DIR; read PID _ < /proc/self/stat ;
+ set -e; set -x; . $1) >> $testlog 2>&1
+ eval_result $? $SIG_RESULT
+ if [ $? -eq 0 ]; then
+ # Remove test log if the test was done as it was expected.
+ [ $KEEP_LOG -eq 0 ] && rm $testlog
+ else
+ catlog $testlog
+ TOTAL_RESULT=1
+ fi
+}
+
+# Main loop
+for t in $TEST_CASES; do
+ run_test $t
+done
+
+prlog ""
+prlog "# of passed: " `echo $PASSED_CASES | wc -w`
+prlog "# of failed: " `echo $FAILED_CASES | wc -w`
+prlog "# of unresolved: " `echo $UNRESOLVED_CASES | wc -w`
+prlog "# of untested: " `echo $UNTESTED_CASES | wc -w`
+prlog "# of unsupported: " `echo $UNSUPPORTED_CASES | wc -w`
+prlog "# of xfailed: " `echo $XFAILED_CASES | wc -w`
+prlog "# of undefined(test bug): " `echo $UNDEFINED_CASES | wc -w`
+
+# if no error, return 0
+exit $TOTAL_RESULT
diff --git a/tools/testing/selftests/ftrace/samples/fail.tc b/tools/testing/selftests/ftrace/samples/fail.tc
new file mode 100644
index 0000000..15e35b9
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/fail.tc
@@ -0,0 +1,4 @@
+#!/bin/sh
+# description: failure-case example
+cat non-exist-file
+echo "this is not executed"
diff --git a/tools/testing/selftests/ftrace/samples/pass.tc b/tools/testing/selftests/ftrace/samples/pass.tc
new file mode 100644
index 0000000..d015493
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/pass.tc
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: pass-case example
+return 0
diff --git a/tools/testing/selftests/ftrace/samples/unresolved.tc b/tools/testing/selftests/ftrace/samples/unresolved.tc
new file mode 100644
index 0000000..41e99d3
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/unresolved.tc
@@ -0,0 +1,4 @@
+#!/bin/sh
+# description: unresolved-case example
+trap exit_unresolved INT
+kill -INT $PID
diff --git a/tools/testing/selftests/ftrace/samples/unsupported.tc b/tools/testing/selftests/ftrace/samples/unsupported.tc
new file mode 100644
index 0000000..45910ff
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/unsupported.tc
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: unsupported-case example
+exit_unsupported
diff --git a/tools/testing/selftests/ftrace/samples/untested.tc b/tools/testing/selftests/ftrace/samples/untested.tc
new file mode 100644
index 0000000..35a4594
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/untested.tc
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: untested-case example
+exit_untested
diff --git a/tools/testing/selftests/ftrace/samples/xfail.tc b/tools/testing/selftests/ftrace/samples/xfail.tc
new file mode 100644
index 0000000..9dd3953
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/xfail.tc
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: xfail-case example
+cat non-exist-file || exit_xfail
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc
new file mode 100644
index 0000000..9980ff1
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: Basic trace file check
+test -f README -a -f trace -a -f tracing_on -a -f trace_pipe
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc
new file mode 100644
index 0000000..bf9a7b0
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc
@@ -0,0 +1,7 @@
+#!/bin/sh
+# description: Basic test for tracers
+test -f available_tracers
+for t in `cat available_tracers`; do
+ echo $t > current_tracer
+done
+echo nop > current_tracer
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc
new file mode 100644
index 0000000..bde6625
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc
@@ -0,0 +1,8 @@
+#!/bin/sh
+# description: Basic trace clock test
+test -f trace_clock
+for c in `cat trace_clock | tr -d \[\]`; do
+ echo $c > trace_clock
+ grep '\['$c'\]' trace_clock
+done
+echo local > trace_clock
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
new file mode 100644
index 0000000..1b8b665
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# description: Kprobe dynamic event - adding and removing
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+echo 0 > events/enable
+echo > kprobe_events
+echo p:myevent do_fork > kprobe_events
+grep myevent kprobe_events
+test -d events/kprobes/myevent
+echo > kprobe_events
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
new file mode 100644
index 0000000..b55c840
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
@@ -0,0 +1,13 @@
+#!/bin/sh
+# description: Kprobe dynamic event - busy event check
+
+[ -f kprobe_events ] || exit_unsupported
+
+echo 0 > events/enable
+echo > kprobe_events
+echo p:myevent do_fork > kprobe_events
+test -d events/kprobes/myevent
+echo 1 > events/kprobes/myevent/enable
+echo > kprobe_events && exit 1 # this must fail
+echo 0 > events/kprobes/myevent/enable
+echo > kprobe_events # this must succeed
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
new file mode 100644
index 0000000..a603d3f
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
@@ -0,0 +1,16 @@
+#!/bin/sh
+# description: Kprobe dynamic event with arguments
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+echo 0 > events/enable
+echo > kprobe_events
+echo 'p:testprobe do_fork $stack $stack0 +0($stack)' > kprobe_events
+grep testprobe kprobe_events
+test -d events/kprobes/testprobe
+echo 1 > events/kprobes/testprobe/enable
+( echo "forked")
+echo 0 > events/kprobes/testprobe/enable
+echo "-:testprobe" >> kprobe_events
+test -d events/kprobes/testprobe && exit 1 || exit 0
+
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
new file mode 100644
index 0000000..283c29e
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
@@ -0,0 +1,15 @@
+#!/bin/sh
+# description: Kretprobe dynamic event with arguments
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+echo 0 > events/enable
+echo > kprobe_events
+echo 'r:testprobe2 do_fork $retval' > kprobe_events
+grep testprobe2 kprobe_events
+test -d events/kprobes/testprobe2
+echo 1 > events/kprobes/testprobe2/enable
+( echo "forked")
+echo 0 > events/kprobes/testprobe2/enable
+echo '-:testprobe2' >> kprobe_events
+test -d events/kprobes/testprobe2 && exit 1 || exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/template b/tools/testing/selftests/ftrace/test.d/template
new file mode 100644
index 0000000..5448f7a
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/template
@@ -0,0 +1,9 @@
+#!/bin/sh
+# description: %HERE DESCRIBE WHAT THIS DOES%
+# you have to add ".tc" extention for your testcase file
+# Note that all tests are run with "errexit" option.
+
+exit 0 # Return 0 if the test is passed, otherwise return !0
+# If the test could not run because of lack of feature, call exit_unsupported
+# If the test returned unclear results, call exit_unresolved
+# If the test is a dummy, or a placeholder, call exit_untested
diff --git a/tools/testing/selftests/ipc/Makefile b/tools/testing/selftests/ipc/Makefile
index 5386fd7..74bbefd 100644
--- a/tools/testing/selftests/ipc/Makefile
+++ b/tools/testing/selftests/ipc/Makefile
@@ -1,18 +1,18 @@
uname_M := $(shell uname -m 2>/dev/null || echo not)
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
ifeq ($(ARCH),i386)
- ARCH := X86
+ ARCH := x86
CFLAGS := -DCONFIG_X86_32 -D__i386__
endif
ifeq ($(ARCH),x86_64)
- ARCH := X86
+ ARCH := x86
CFLAGS := -DCONFIG_X86_64 -D__x86_64__
endif
CFLAGS += -I../../../../usr/include/
all:
-ifeq ($(ARCH),X86)
+ifeq ($(ARCH),x86)
gcc $(CFLAGS) msgque.c -o msgque_test
else
echo "Not an x86 target, can't build msgque selftest"
diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile
index d7d6bbe..8aabd82 100644
--- a/tools/testing/selftests/kcmp/Makefile
+++ b/tools/testing/selftests/kcmp/Makefile
@@ -1,11 +1,11 @@
uname_M := $(shell uname -m 2>/dev/null || echo not)
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
ifeq ($(ARCH),i386)
- ARCH := X86
+ ARCH := x86
CFLAGS := -DCONFIG_X86_32 -D__i386__
endif
ifeq ($(ARCH),x86_64)
- ARCH := X86
+ ARCH := x86
CFLAGS := -DCONFIG_X86_64 -D__x86_64__
endif
@@ -15,7 +15,7 @@ CFLAGS += -I../../../../usr/include/
CFLAGS += -I../../../../arch/x86/include/
all:
-ifeq ($(ARCH),X86)
+ifeq ($(ARCH),x86)
gcc $(CFLAGS) kcmp_test.c -o kcmp_test
else
echo "Not an x86 target, can't build kcmp selftest"
diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c
index fa4f1b3..dbba408 100644
--- a/tools/testing/selftests/kcmp/kcmp_test.c
+++ b/tools/testing/selftests/kcmp/kcmp_test.c
@@ -81,7 +81,7 @@ int main(int argc, char **argv)
/* Compare with self */
ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0);
if (ret) {
- printf("FAIL: 0 expected but %li returned (%s)\n",
+ printf("FAIL: 0 expected but %d returned (%s)\n",
ret, strerror(errno));
ret = -1;
} else
diff --git a/tools/testing/selftests/memfd/.gitignore b/tools/testing/selftests/memfd/.gitignore
new file mode 100644
index 0000000..afe87c4
--- /dev/null
+++ b/tools/testing/selftests/memfd/.gitignore
@@ -0,0 +1,4 @@
+fuse_mnt
+fuse_test
+memfd_test
+memfd-test-file
diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile
new file mode 100644
index 0000000..b80cd10
--- /dev/null
+++ b/tools/testing/selftests/memfd/Makefile
@@ -0,0 +1,20 @@
+CFLAGS += -D_FILE_OFFSET_BITS=64
+CFLAGS += -I../../../../include/uapi/
+CFLAGS += -I../../../../include/
+
+all:
+ gcc $(CFLAGS) memfd_test.c -o memfd_test
+
+run_tests: all
+ gcc $(CFLAGS) memfd_test.c -o memfd_test
+ @./memfd_test || echo "memfd_test: [FAIL]"
+
+build_fuse:
+ gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt
+ gcc $(CFLAGS) fuse_test.c -o fuse_test
+
+run_fuse: build_fuse
+ @./run_fuse_test.sh || echo "fuse_test: [FAIL]"
+
+clean:
+ $(RM) memfd_test fuse_test
diff --git a/tools/testing/selftests/memfd/fuse_mnt.c b/tools/testing/selftests/memfd/fuse_mnt.c
new file mode 100644
index 0000000..feacf12
--- /dev/null
+++ b/tools/testing/selftests/memfd/fuse_mnt.c
@@ -0,0 +1,110 @@
+/*
+ * memfd test file-system
+ * This file uses FUSE to create a dummy file-system with only one file /memfd.
+ * This file is read-only and takes 1s per read.
+ *
+ * This file-system is used by the memfd test-cases to force the kernel to pin
+ * pages during reads(). Due to the 1s delay of this file-system, this is a
+ * nice way to test race-conditions against get_user_pages() in the kernel.
+ *
+ * We use direct_io==1 to force the kernel to use direct-IO for this
+ * file-system.
+ */
+
+#define FUSE_USE_VERSION 26
+
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+static const char memfd_content[] = "memfd-example-content";
+static const char memfd_path[] = "/memfd";
+
+static int memfd_getattr(const char *path, struct stat *st)
+{
+ memset(st, 0, sizeof(*st));
+
+ if (!strcmp(path, "/")) {
+ st->st_mode = S_IFDIR | 0755;
+ st->st_nlink = 2;
+ } else if (!strcmp(path, memfd_path)) {
+ st->st_mode = S_IFREG | 0444;
+ st->st_nlink = 1;
+ st->st_size = strlen(memfd_content);
+ } else {
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int memfd_readdir(const char *path,
+ void *buf,
+ fuse_fill_dir_t filler,
+ off_t offset,
+ struct fuse_file_info *fi)
+{
+ if (strcmp(path, "/"))
+ return -ENOENT;
+
+ filler(buf, ".", NULL, 0);
+ filler(buf, "..", NULL, 0);
+ filler(buf, memfd_path + 1, NULL, 0);
+
+ return 0;
+}
+
+static int memfd_open(const char *path, struct fuse_file_info *fi)
+{
+ if (strcmp(path, memfd_path))
+ return -ENOENT;
+
+ if ((fi->flags & 3) != O_RDONLY)
+ return -EACCES;
+
+ /* force direct-IO */
+ fi->direct_io = 1;
+
+ return 0;
+}
+
+static int memfd_read(const char *path,
+ char *buf,
+ size_t size,
+ off_t offset,
+ struct fuse_file_info *fi)
+{
+ size_t len;
+
+ if (strcmp(path, memfd_path) != 0)
+ return -ENOENT;
+
+ sleep(1);
+
+ len = strlen(memfd_content);
+ if (offset < len) {
+ if (offset + size > len)
+ size = len - offset;
+
+ memcpy(buf, memfd_content + offset, size);
+ } else {
+ size = 0;
+ }
+
+ return size;
+}
+
+static struct fuse_operations memfd_ops = {
+ .getattr = memfd_getattr,
+ .readdir = memfd_readdir,
+ .open = memfd_open,
+ .read = memfd_read,
+};
+
+int main(int argc, char *argv[])
+{
+ return fuse_main(argc, argv, &memfd_ops, NULL);
+}
diff --git a/tools/testing/selftests/memfd/fuse_test.c b/tools/testing/selftests/memfd/fuse_test.c
new file mode 100644
index 0000000..67908b1
--- /dev/null
+++ b/tools/testing/selftests/memfd/fuse_test.c
@@ -0,0 +1,311 @@
+/*
+ * memfd GUP test-case
+ * This tests memfd interactions with get_user_pages(). We require the
+ * fuse_mnt.c program to provide a fake direct-IO FUSE mount-point for us. This
+ * file-system delays _all_ reads by 1s and forces direct-IO. This means, any
+ * read() on files in that file-system will pin the receive-buffer pages for at
+ * least 1s via get_user_pages().
+ *
+ * We use this trick to race ADD_SEALS against a write on a memfd object. The
+ * ADD_SEALS must fail if the memfd pages are still pinned. Note that we use
+ * the read() syscall with our memory-mapped memfd object as receive buffer to
+ * force the kernel to write into our memfd object.
+ */
+
+#define _GNU_SOURCE
+#define __EXPORTED_HEADERS__
+
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <linux/falloc.h>
+#include <linux/fcntl.h>
+#include <linux/memfd.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define MFD_DEF_SIZE 8192
+#define STACK_SIZE 65535
+
+static int sys_memfd_create(const char *name,
+ unsigned int flags)
+{
+ return syscall(__NR_memfd_create, name, flags);
+}
+
+static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
+{
+ int r, fd;
+
+ fd = sys_memfd_create(name, flags);
+ if (fd < 0) {
+ printf("memfd_create(\"%s\", %u) failed: %m\n",
+ name, flags);
+ abort();
+ }
+
+ r = ftruncate(fd, sz);
+ if (r < 0) {
+ printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
+ abort();
+ }
+
+ return fd;
+}
+
+static __u64 mfd_assert_get_seals(int fd)
+{
+ long r;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0) {
+ printf("GET_SEALS(%d) failed: %m\n", fd);
+ abort();
+ }
+
+ return r;
+}
+
+static void mfd_assert_has_seals(int fd, __u64 seals)
+{
+ __u64 s;
+
+ s = mfd_assert_get_seals(fd);
+ if (s != seals) {
+ printf("%llu != %llu = GET_SEALS(%d)\n",
+ (unsigned long long)seals, (unsigned long long)s, fd);
+ abort();
+ }
+}
+
+static void mfd_assert_add_seals(int fd, __u64 seals)
+{
+ long r;
+ __u64 s;
+
+ s = mfd_assert_get_seals(fd);
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r < 0) {
+ printf("ADD_SEALS(%d, %llu -> %llu) failed: %m\n",
+ fd, (unsigned long long)s, (unsigned long long)seals);
+ abort();
+ }
+}
+
+static int mfd_busy_add_seals(int fd, __u64 seals)
+{
+ long r;
+ __u64 s;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0)
+ s = 0;
+ else
+ s = r;
+
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r < 0 && errno != EBUSY) {
+ printf("ADD_SEALS(%d, %llu -> %llu) didn't fail as expected with EBUSY: %m\n",
+ fd, (unsigned long long)s, (unsigned long long)seals);
+ abort();
+ }
+
+ return r;
+}
+
+static void *mfd_assert_mmap_shared(int fd)
+{
+ void *p;
+
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ return p;
+}
+
+static void *mfd_assert_mmap_private(int fd)
+{
+ void *p;
+
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ return p;
+}
+
+static int global_mfd = -1;
+static void *global_p = NULL;
+
+static int sealing_thread_fn(void *arg)
+{
+ int sig, r;
+
+ /*
+ * This thread first waits 200ms so any pending operation in the parent
+ * is correctly started. After that, it tries to seal @global_mfd as
+ * SEAL_WRITE. This _must_ fail as the parent thread has a read() into
+ * that memory mapped object still ongoing.
+ * We then wait one more second and try sealing again. This time it
+ * must succeed as there shouldn't be anyone else pinning the pages.
+ */
+
+ /* wait 200ms for FUSE-request to be active */
+ usleep(200000);
+
+ /* unmount mapping before sealing to avoid i_mmap_writable failures */
+ munmap(global_p, MFD_DEF_SIZE);
+
+ /* Try sealing the global file; expect EBUSY or success. Current
+ * kernels will never succeed, but in the future, kernels might
+ * implement page-replacements or other fancy ways to avoid racing
+ * writes. */
+ r = mfd_busy_add_seals(global_mfd, F_SEAL_WRITE);
+ if (r >= 0) {
+ printf("HURRAY! This kernel fixed GUP races!\n");
+ } else {
+ /* wait 1s more so the FUSE-request is done */
+ sleep(1);
+
+ /* try sealing the global file again */
+ mfd_assert_add_seals(global_mfd, F_SEAL_WRITE);
+ }
+
+ return 0;
+}
+
+static pid_t spawn_sealing_thread(void)
+{
+ uint8_t *stack;
+ pid_t pid;
+
+ stack = malloc(STACK_SIZE);
+ if (!stack) {
+ printf("malloc(STACK_SIZE) failed: %m\n");
+ abort();
+ }
+
+ pid = clone(sealing_thread_fn,
+ stack + STACK_SIZE,
+ SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM,
+ NULL);
+ if (pid < 0) {
+ printf("clone() failed: %m\n");
+ abort();
+ }
+
+ return pid;
+}
+
+static void join_sealing_thread(pid_t pid)
+{
+ waitpid(pid, NULL, 0);
+}
+
+int main(int argc, char **argv)
+{
+ static const char zero[MFD_DEF_SIZE];
+ int fd, mfd, r;
+ void *p;
+ int was_sealed;
+ pid_t pid;
+
+ if (argc < 2) {
+ printf("error: please pass path to file in fuse_mnt mount-point\n");
+ abort();
+ }
+
+ /* open FUSE memfd file for GUP testing */
+ printf("opening: %s\n", argv[1]);
+ fd = open(argv[1], O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ printf("cannot open(\"%s\"): %m\n", argv[1]);
+ abort();
+ }
+
+ /* create new memfd-object */
+ mfd = mfd_assert_new("kern_memfd_fuse",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+
+ /* mmap memfd-object for writing */
+ p = mfd_assert_mmap_shared(mfd);
+
+ /* pass mfd+mapping to a separate sealing-thread which tries to seal
+ * the memfd objects with SEAL_WRITE while we write into it */
+ global_mfd = mfd;
+ global_p = p;
+ pid = spawn_sealing_thread();
+
+ /* Use read() on the FUSE file to read into our memory-mapped memfd
+ * object. This races the other thread which tries to seal the
+ * memfd-object.
+ * If @fd is on the memfd-fake-FUSE-FS, the read() is delayed by 1s.
+ * This guarantees that the receive-buffer is pinned for 1s until the
+ * data is written into it. The racing ADD_SEALS should thus fail as
+ * the pages are still pinned. */
+ r = read(fd, p, MFD_DEF_SIZE);
+ if (r < 0) {
+ printf("read() failed: %m\n");
+ abort();
+ } else if (!r) {
+ printf("unexpected EOF on read()\n");
+ abort();
+ }
+
+ was_sealed = mfd_assert_get_seals(mfd) & F_SEAL_WRITE;
+
+ /* Wait for sealing-thread to finish and verify that it
+ * successfully sealed the file after the second try. */
+ join_sealing_thread(pid);
+ mfd_assert_has_seals(mfd, F_SEAL_WRITE);
+
+ /* *IF* the memfd-object was sealed at the time our read() returned,
+ * then the kernel did a page-replacement or canceled the read() (or
+ * whatever magic it did..). In that case, the memfd object is still
+ * all zero.
+ * In case the memfd-object was *not* sealed, the read() was successfull
+ * and the memfd object must *not* be all zero.
+ * Note that in real scenarios, there might be a mixture of both, but
+ * in this test-cases, we have explicit 200ms delays which should be
+ * enough to avoid any in-flight writes. */
+
+ p = mfd_assert_mmap_private(mfd);
+ if (was_sealed && memcmp(p, zero, MFD_DEF_SIZE)) {
+ printf("memfd sealed during read() but data not discarded\n");
+ abort();
+ } else if (!was_sealed && !memcmp(p, zero, MFD_DEF_SIZE)) {
+ printf("memfd sealed after read() but data discarded\n");
+ abort();
+ }
+
+ close(mfd);
+ close(fd);
+
+ printf("fuse: DONE\n");
+
+ return 0;
+}
diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
new file mode 100644
index 0000000..0b9eafb
--- /dev/null
+++ b/tools/testing/selftests/memfd/memfd_test.c
@@ -0,0 +1,911 @@
+#define _GNU_SOURCE
+#define __EXPORTED_HEADERS__
+
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <linux/falloc.h>
+#include <linux/fcntl.h>
+#include <linux/memfd.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#define MFD_DEF_SIZE 8192
+#define STACK_SIZE 65535
+
+static int sys_memfd_create(const char *name,
+ unsigned int flags)
+{
+ return syscall(__NR_memfd_create, name, flags);
+}
+
+static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
+{
+ int r, fd;
+
+ fd = sys_memfd_create(name, flags);
+ if (fd < 0) {
+ printf("memfd_create(\"%s\", %u) failed: %m\n",
+ name, flags);
+ abort();
+ }
+
+ r = ftruncate(fd, sz);
+ if (r < 0) {
+ printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
+ abort();
+ }
+
+ return fd;
+}
+
+static void mfd_fail_new(const char *name, unsigned int flags)
+{
+ int r;
+
+ r = sys_memfd_create(name, flags);
+ if (r >= 0) {
+ printf("memfd_create(\"%s\", %u) succeeded, but failure expected\n",
+ name, flags);
+ close(r);
+ abort();
+ }
+}
+
+static unsigned int mfd_assert_get_seals(int fd)
+{
+ int r;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0) {
+ printf("GET_SEALS(%d) failed: %m\n", fd);
+ abort();
+ }
+
+ return (unsigned int)r;
+}
+
+static void mfd_assert_has_seals(int fd, unsigned int seals)
+{
+ unsigned int s;
+
+ s = mfd_assert_get_seals(fd);
+ if (s != seals) {
+ printf("%u != %u = GET_SEALS(%d)\n", seals, s, fd);
+ abort();
+ }
+}
+
+static void mfd_assert_add_seals(int fd, unsigned int seals)
+{
+ int r;
+ unsigned int s;
+
+ s = mfd_assert_get_seals(fd);
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r < 0) {
+ printf("ADD_SEALS(%d, %u -> %u) failed: %m\n", fd, s, seals);
+ abort();
+ }
+}
+
+static void mfd_fail_add_seals(int fd, unsigned int seals)
+{
+ int r;
+ unsigned int s;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0)
+ s = 0;
+ else
+ s = (unsigned int)r;
+
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r >= 0) {
+ printf("ADD_SEALS(%d, %u -> %u) didn't fail as expected\n",
+ fd, s, seals);
+ abort();
+ }
+}
+
+static void mfd_assert_size(int fd, size_t size)
+{
+ struct stat st;
+ int r;
+
+ r = fstat(fd, &st);
+ if (r < 0) {
+ printf("fstat(%d) failed: %m\n", fd);
+ abort();
+ } else if (st.st_size != size) {
+ printf("wrong file size %lld, but expected %lld\n",
+ (long long)st.st_size, (long long)size);
+ abort();
+ }
+}
+
+static int mfd_assert_dup(int fd)
+{
+ int r;
+
+ r = dup(fd);
+ if (r < 0) {
+ printf("dup(%d) failed: %m\n", fd);
+ abort();
+ }
+
+ return r;
+}
+
+static void *mfd_assert_mmap_shared(int fd)
+{
+ void *p;
+
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ return p;
+}
+
+static void *mfd_assert_mmap_private(int fd)
+{
+ void *p;
+
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ return p;
+}
+
+static int mfd_assert_open(int fd, int flags, mode_t mode)
+{
+ char buf[512];
+ int r;
+
+ sprintf(buf, "/proc/self/fd/%d", fd);
+ r = open(buf, flags, mode);
+ if (r < 0) {
+ printf("open(%s) failed: %m\n", buf);
+ abort();
+ }
+
+ return r;
+}
+
+static void mfd_fail_open(int fd, int flags, mode_t mode)
+{
+ char buf[512];
+ int r;
+
+ sprintf(buf, "/proc/self/fd/%d", fd);
+ r = open(buf, flags, mode);
+ if (r >= 0) {
+ printf("open(%s) didn't fail as expected\n", buf);
+ abort();
+ }
+}
+
+static void mfd_assert_read(int fd)
+{
+ char buf[16];
+ void *p;
+ ssize_t l;
+
+ l = read(fd, buf, sizeof(buf));
+ if (l != sizeof(buf)) {
+ printf("read() failed: %m\n");
+ abort();
+ }
+
+ /* verify PROT_READ *is* allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+ munmap(p, MFD_DEF_SIZE);
+
+ /* verify MAP_PRIVATE is *always* allowed (even writable) */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+ munmap(p, MFD_DEF_SIZE);
+}
+
+static void mfd_assert_write(int fd)
+{
+ ssize_t l;
+ void *p;
+ int r;
+
+ /* verify write() succeeds */
+ l = write(fd, "\0\0\0\0", 4);
+ if (l != 4) {
+ printf("write() failed: %m\n");
+ abort();
+ }
+
+ /* verify PROT_READ | PROT_WRITE is allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+ *(char *)p = 0;
+ munmap(p, MFD_DEF_SIZE);
+
+ /* verify PROT_WRITE is allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+ *(char *)p = 0;
+ munmap(p, MFD_DEF_SIZE);
+
+ /* verify PROT_READ with MAP_SHARED is allowed and a following
+ * mprotect(PROT_WRITE) allows writing */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE);
+ if (r < 0) {
+ printf("mprotect() failed: %m\n");
+ abort();
+ }
+
+ *(char *)p = 0;
+ munmap(p, MFD_DEF_SIZE);
+
+ /* verify PUNCH_HOLE works */
+ r = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ 0,
+ MFD_DEF_SIZE);
+ if (r < 0) {
+ printf("fallocate(PUNCH_HOLE) failed: %m\n");
+ abort();
+ }
+}
+
+static void mfd_fail_write(int fd)
+{
+ ssize_t l;
+ void *p;
+ int r;
+
+ /* verify write() fails */
+ l = write(fd, "data", 4);
+ if (l != -EPERM) {
+ printf("expected EPERM on write(), but got %d: %m\n", (int)l);
+ abort();
+ }
+
+ /* verify PROT_READ | PROT_WRITE is not allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p != MAP_FAILED) {
+ printf("mmap() didn't fail as expected\n");
+ abort();
+ }
+
+ /* verify PROT_WRITE is not allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p != MAP_FAILED) {
+ printf("mmap() didn't fail as expected\n");
+ abort();
+ }
+
+ /* Verify PROT_READ with MAP_SHARED with a following mprotect is not
+ * allowed. Note that for r/w the kernel already prevents the mmap. */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p != MAP_FAILED) {
+ r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE);
+ if (r >= 0) {
+ printf("mmap()+mprotect() didn't fail as expected\n");
+ abort();
+ }
+ }
+
+ /* verify PUNCH_HOLE fails */
+ r = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ 0,
+ MFD_DEF_SIZE);
+ if (r >= 0) {
+ printf("fallocate(PUNCH_HOLE) didn't fail as expected\n");
+ abort();
+ }
+}
+
+static void mfd_assert_shrink(int fd)
+{
+ int r, fd2;
+
+ r = ftruncate(fd, MFD_DEF_SIZE / 2);
+ if (r < 0) {
+ printf("ftruncate(SHRINK) failed: %m\n");
+ abort();
+ }
+
+ mfd_assert_size(fd, MFD_DEF_SIZE / 2);
+
+ fd2 = mfd_assert_open(fd,
+ O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+ close(fd2);
+
+ mfd_assert_size(fd, 0);
+}
+
+static void mfd_fail_shrink(int fd)
+{
+ int r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE / 2);
+ if (r >= 0) {
+ printf("ftruncate(SHRINK) didn't fail as expected\n");
+ abort();
+ }
+
+ mfd_fail_open(fd,
+ O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+}
+
+static void mfd_assert_grow(int fd)
+{
+ int r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE * 2);
+ if (r < 0) {
+ printf("ftruncate(GROW) failed: %m\n");
+ abort();
+ }
+
+ mfd_assert_size(fd, MFD_DEF_SIZE * 2);
+
+ r = fallocate(fd,
+ 0,
+ 0,
+ MFD_DEF_SIZE * 4);
+ if (r < 0) {
+ printf("fallocate(ALLOC) failed: %m\n");
+ abort();
+ }
+
+ mfd_assert_size(fd, MFD_DEF_SIZE * 4);
+}
+
+static void mfd_fail_grow(int fd)
+{
+ int r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE * 2);
+ if (r >= 0) {
+ printf("ftruncate(GROW) didn't fail as expected\n");
+ abort();
+ }
+
+ r = fallocate(fd,
+ 0,
+ 0,
+ MFD_DEF_SIZE * 4);
+ if (r >= 0) {
+ printf("fallocate(ALLOC) didn't fail as expected\n");
+ abort();
+ }
+}
+
+static void mfd_assert_grow_write(int fd)
+{
+ static char buf[MFD_DEF_SIZE * 8];
+ ssize_t l;
+
+ l = pwrite(fd, buf, sizeof(buf), 0);
+ if (l != sizeof(buf)) {
+ printf("pwrite() failed: %m\n");
+ abort();
+ }
+
+ mfd_assert_size(fd, MFD_DEF_SIZE * 8);
+}
+
+static void mfd_fail_grow_write(int fd)
+{
+ static char buf[MFD_DEF_SIZE * 8];
+ ssize_t l;
+
+ l = pwrite(fd, buf, sizeof(buf), 0);
+ if (l == sizeof(buf)) {
+ printf("pwrite() didn't fail as expected\n");
+ abort();
+ }
+}
+
+static int idle_thread_fn(void *arg)
+{
+ sigset_t set;
+ int sig;
+
+ /* dummy waiter; SIGTERM terminates us anyway */
+ sigemptyset(&set);
+ sigaddset(&set, SIGTERM);
+ sigwait(&set, &sig);
+
+ return 0;
+}
+
+static pid_t spawn_idle_thread(unsigned int flags)
+{
+ uint8_t *stack;
+ pid_t pid;
+
+ stack = malloc(STACK_SIZE);
+ if (!stack) {
+ printf("malloc(STACK_SIZE) failed: %m\n");
+ abort();
+ }
+
+ pid = clone(idle_thread_fn,
+ stack + STACK_SIZE,
+ SIGCHLD | flags,
+ NULL);
+ if (pid < 0) {
+ printf("clone() failed: %m\n");
+ abort();
+ }
+
+ return pid;
+}
+
+static void join_idle_thread(pid_t pid)
+{
+ kill(pid, SIGTERM);
+ waitpid(pid, NULL, 0);
+}
+
+/*
+ * Test memfd_create() syscall
+ * Verify syscall-argument validation, including name checks, flag validation
+ * and more.
+ */
+static void test_create(void)
+{
+ char buf[2048];
+ int fd;
+
+ /* test NULL name */
+ mfd_fail_new(NULL, 0);
+
+ /* test over-long name (not zero-terminated) */
+ memset(buf, 0xff, sizeof(buf));
+ mfd_fail_new(buf, 0);
+
+ /* test over-long zero-terminated name */
+ memset(buf, 0xff, sizeof(buf));
+ buf[sizeof(buf) - 1] = 0;
+ mfd_fail_new(buf, 0);
+
+ /* verify "" is a valid name */
+ fd = mfd_assert_new("", 0, 0);
+ close(fd);
+
+ /* verify invalid O_* open flags */
+ mfd_fail_new("", 0x0100);
+ mfd_fail_new("", ~MFD_CLOEXEC);
+ mfd_fail_new("", ~MFD_ALLOW_SEALING);
+ mfd_fail_new("", ~0);
+ mfd_fail_new("", 0x80000000U);
+
+ /* verify MFD_CLOEXEC is allowed */
+ fd = mfd_assert_new("", 0, MFD_CLOEXEC);
+ close(fd);
+
+ /* verify MFD_ALLOW_SEALING is allowed */
+ fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
+ close(fd);
+
+ /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
+ fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
+ close(fd);
+}
+
+/*
+ * Test basic sealing
+ * A very basic sealing test to see whether setting/retrieving seals works.
+ */
+static void test_basic(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_basic",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+
+ /* add basic seals */
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE);
+
+ /* add them again */
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE);
+
+ /* add more seals and seal against sealing */
+ mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_GROW |
+ F_SEAL_WRITE |
+ F_SEAL_SEAL);
+
+ /* verify that sealing no longer works */
+ mfd_fail_add_seals(fd, F_SEAL_GROW);
+ mfd_fail_add_seals(fd, 0);
+
+ close(fd);
+
+ /* verify sealing does not work without MFD_ALLOW_SEALING */
+ fd = mfd_assert_new("kern_memfd_basic",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+ mfd_fail_add_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_GROW |
+ F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+ close(fd);
+}
+
+/*
+ * Test SEAL_WRITE
+ * Test whether SEAL_WRITE actually prevents modifications.
+ */
+static void test_seal_write(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_seal_write",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE);
+
+ mfd_assert_read(fd);
+ mfd_fail_write(fd);
+ mfd_assert_shrink(fd);
+ mfd_assert_grow(fd);
+ mfd_fail_grow_write(fd);
+
+ close(fd);
+}
+
+/*
+ * Test SEAL_SHRINK
+ * Test whether SEAL_SHRINK actually prevents shrinking
+ */
+static void test_seal_shrink(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_seal_shrink",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK);
+
+ mfd_assert_read(fd);
+ mfd_assert_write(fd);
+ mfd_fail_shrink(fd);
+ mfd_assert_grow(fd);
+ mfd_assert_grow_write(fd);
+
+ close(fd);
+}
+
+/*
+ * Test SEAL_GROW
+ * Test whether SEAL_GROW actually prevents growing
+ */
+static void test_seal_grow(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_seal_grow",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_GROW);
+ mfd_assert_has_seals(fd, F_SEAL_GROW);
+
+ mfd_assert_read(fd);
+ mfd_assert_write(fd);
+ mfd_assert_shrink(fd);
+ mfd_fail_grow(fd);
+ mfd_fail_grow_write(fd);
+
+ close(fd);
+}
+
+/*
+ * Test SEAL_SHRINK | SEAL_GROW
+ * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
+ */
+static void test_seal_resize(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_seal_resize",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
+
+ mfd_assert_read(fd);
+ mfd_assert_write(fd);
+ mfd_fail_shrink(fd);
+ mfd_fail_grow(fd);
+ mfd_fail_grow_write(fd);
+
+ close(fd);
+}
+
+/*
+ * Test sharing via dup()
+ * Test that seals are shared between dupped FDs and they're all equal.
+ */
+static void test_share_dup(void)
+{
+ int fd, fd2;
+
+ fd = mfd_assert_new("kern_memfd_share_dup",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+
+ fd2 = mfd_assert_dup(fd);
+ mfd_assert_has_seals(fd2, 0);
+
+ mfd_assert_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE);
+
+ mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
+
+ mfd_assert_add_seals(fd, F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
+
+ mfd_fail_add_seals(fd, F_SEAL_GROW);
+ mfd_fail_add_seals(fd2, F_SEAL_GROW);
+ mfd_fail_add_seals(fd, F_SEAL_SEAL);
+ mfd_fail_add_seals(fd2, F_SEAL_SEAL);
+
+ close(fd2);
+
+ mfd_fail_add_seals(fd, F_SEAL_GROW);
+ close(fd);
+}
+
+/*
+ * Test sealing with active mmap()s
+ * Modifying seals is only allowed if no other mmap() refs exist.
+ */
+static void test_share_mmap(void)
+{
+ int fd;
+ void *p;
+
+ fd = mfd_assert_new("kern_memfd_share_mmap",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+
+ /* shared/writable ref prevents sealing WRITE, but allows others */
+ p = mfd_assert_mmap_shared(fd);
+ mfd_fail_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK);
+ munmap(p, MFD_DEF_SIZE);
+
+ /* readable ref allows sealing */
+ p = mfd_assert_mmap_private(fd);
+ mfd_assert_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
+ munmap(p, MFD_DEF_SIZE);
+
+ close(fd);
+}
+
+/*
+ * Test sealing with open(/proc/self/fd/%d)
+ * Via /proc we can get access to a separate file-context for the same memfd.
+ * This is *not* like dup(), but like a real separate open(). Make sure the
+ * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
+ */
+static void test_share_open(void)
+{
+ int fd, fd2;
+
+ fd = mfd_assert_new("kern_memfd_share_open",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+
+ fd2 = mfd_assert_open(fd, O_RDWR, 0);
+ mfd_assert_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE);
+
+ mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
+
+ close(fd);
+ fd = mfd_assert_open(fd2, O_RDONLY, 0);
+
+ mfd_fail_add_seals(fd, F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
+
+ close(fd2);
+ fd2 = mfd_assert_open(fd, O_RDWR, 0);
+
+ mfd_assert_add_seals(fd2, F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
+
+ close(fd2);
+ close(fd);
+}
+
+/*
+ * Test sharing via fork()
+ * Test whether seal-modifications work as expected with forked childs.
+ */
+static void test_share_fork(void)
+{
+ int fd;
+ pid_t pid;
+
+ fd = mfd_assert_new("kern_memfd_share_fork",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+
+ pid = spawn_idle_thread(0);
+ mfd_assert_add_seals(fd, F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+
+ mfd_fail_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+
+ join_idle_thread(pid);
+
+ mfd_fail_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ pid_t pid;
+
+ printf("memfd: CREATE\n");
+ test_create();
+ printf("memfd: BASIC\n");
+ test_basic();
+
+ printf("memfd: SEAL-WRITE\n");
+ test_seal_write();
+ printf("memfd: SEAL-SHRINK\n");
+ test_seal_shrink();
+ printf("memfd: SEAL-GROW\n");
+ test_seal_grow();
+ printf("memfd: SEAL-RESIZE\n");
+ test_seal_resize();
+
+ printf("memfd: SHARE-DUP\n");
+ test_share_dup();
+ printf("memfd: SHARE-MMAP\n");
+ test_share_mmap();
+ printf("memfd: SHARE-OPEN\n");
+ test_share_open();
+ printf("memfd: SHARE-FORK\n");
+ test_share_fork();
+
+ /* Run test-suite in a multi-threaded environment with a shared
+ * file-table. */
+ pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM);
+ printf("memfd: SHARE-DUP (shared file-table)\n");
+ test_share_dup();
+ printf("memfd: SHARE-MMAP (shared file-table)\n");
+ test_share_mmap();
+ printf("memfd: SHARE-OPEN (shared file-table)\n");
+ test_share_open();
+ printf("memfd: SHARE-FORK (shared file-table)\n");
+ test_share_fork();
+ join_idle_thread(pid);
+
+ printf("memfd: DONE\n");
+
+ return 0;
+}
diff --git a/tools/testing/selftests/memfd/run_fuse_test.sh b/tools/testing/selftests/memfd/run_fuse_test.sh
new file mode 100644
index 0000000..69b930e
--- /dev/null
+++ b/tools/testing/selftests/memfd/run_fuse_test.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+if test -d "./mnt" ; then
+ fusermount -u ./mnt
+ rmdir ./mnt
+fi
+
+set -e
+
+mkdir mnt
+./fuse_mnt ./mnt
+./fuse_test ./mnt/memfd
+fusermount -u ./mnt
+rmdir ./mnt
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
index 058c76f..d46b8d4 100644
--- a/tools/testing/selftests/memory-hotplug/Makefile
+++ b/tools/testing/selftests/memory-hotplug/Makefile
@@ -1,6 +1,9 @@
all:
run_tests:
+ @/bin/bash ./on-off-test.sh -r 2 || echo "memory-hotplug selftests: [FAIL]"
+
+run_full_test:
@/bin/bash ./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
clean:
diff --git a/tools/testing/selftests/memory-hotplug/on-off-test.sh b/tools/testing/selftests/memory-hotplug/on-off-test.sh
index a2816f6..6cddde0 100644
--- a/tools/testing/selftests/memory-hotplug/on-off-test.sh
+++ b/tools/testing/selftests/memory-hotplug/on-off-test.sh
@@ -142,10 +142,16 @@ fi
prerequisite
+echo "Test scope: $ratio% hotplug memory"
+echo -e "\t online all hotplug memory in offline state"
+echo -e "\t offline $ratio% hotplug memory in online state"
+echo -e "\t online all hotplug memory in offline state"
+
#
# Online all hot-pluggable memory
#
for memory in `hotplaggable_offline_memory`; do
+ echo offline-online $memory
online_memory_expect_success $memory
done
@@ -154,6 +160,7 @@ done
#
for memory in `hotpluggable_online_memory`; do
if [ $((RANDOM % 100)) -lt $ratio ]; then
+ echo online-offline $memory
offline_memory_expect_success $memory
fi
done
@@ -162,6 +169,7 @@ done
# Online all hot-pluggable memory again
#
for memory in `hotplaggable_offline_memory`; do
+ echo offline-online $memory
online_memory_expect_success $memory
done
diff --git a/tools/testing/selftests/mount/Makefile b/tools/testing/selftests/mount/Makefile
new file mode 100644
index 0000000..337d853
--- /dev/null
+++ b/tools/testing/selftests/mount/Makefile
@@ -0,0 +1,17 @@
+# Makefile for mount selftests.
+
+all: unprivileged-remount-test
+
+unprivileged-remount-test: unprivileged-remount-test.c
+ gcc -Wall -O2 unprivileged-remount-test.c -o unprivileged-remount-test
+
+# Allow specific tests to be selected.
+test_unprivileged_remount: unprivileged-remount-test
+ @if [ -f /proc/self/uid_map ] ; then ./unprivileged-remount-test ; fi
+
+run_tests: all test_unprivileged_remount
+
+clean:
+ rm -f unprivileged-remount-test
+
+.PHONY: all test_unprivileged_remount
diff --git a/tools/testing/selftests/mount/unprivileged-remount-test.c b/tools/testing/selftests/mount/unprivileged-remount-test.c
new file mode 100644
index 0000000..1b3ff2f
--- /dev/null
+++ b/tools/testing/selftests/mount/unprivileged-remount-test.c
@@ -0,0 +1,242 @@
+#define _GNU_SOURCE
+#include <sched.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#ifndef CLONE_NEWNS
+# define CLONE_NEWNS 0x00020000
+#endif
+#ifndef CLONE_NEWUTS
+# define CLONE_NEWUTS 0x04000000
+#endif
+#ifndef CLONE_NEWIPC
+# define CLONE_NEWIPC 0x08000000
+#endif
+#ifndef CLONE_NEWNET
+# define CLONE_NEWNET 0x40000000
+#endif
+#ifndef CLONE_NEWUSER
+# define CLONE_NEWUSER 0x10000000
+#endif
+#ifndef CLONE_NEWPID
+# define CLONE_NEWPID 0x20000000
+#endif
+
+#ifndef MS_RELATIME
+#define MS_RELATIME (1 << 21)
+#endif
+#ifndef MS_STRICTATIME
+#define MS_STRICTATIME (1 << 24)
+#endif
+
+static void die(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+static void write_file(char *filename, char *fmt, ...)
+{
+ char buf[4096];
+ int fd;
+ ssize_t written;
+ int buf_len;
+ va_list ap;
+
+ va_start(ap, fmt);
+ buf_len = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ if (buf_len < 0) {
+ die("vsnprintf failed: %s\n",
+ strerror(errno));
+ }
+ if (buf_len >= sizeof(buf)) {
+ die("vsnprintf output truncated\n");
+ }
+
+ fd = open(filename, O_WRONLY);
+ if (fd < 0) {
+ die("open of %s failed: %s\n",
+ filename, strerror(errno));
+ }
+ written = write(fd, buf, buf_len);
+ if (written != buf_len) {
+ if (written >= 0) {
+ die("short write to %s\n", filename);
+ } else {
+ die("write to %s failed: %s\n",
+ filename, strerror(errno));
+ }
+ }
+ if (close(fd) != 0) {
+ die("close of %s failed: %s\n",
+ filename, strerror(errno));
+ }
+}
+
+static void create_and_enter_userns(void)
+{
+ uid_t uid;
+ gid_t gid;
+
+ uid = getuid();
+ gid = getgid();
+
+ if (unshare(CLONE_NEWUSER) !=0) {
+ die("unshare(CLONE_NEWUSER) failed: %s\n",
+ strerror(errno));
+ }
+
+ write_file("/proc/self/uid_map", "0 %d 1", uid);
+ write_file("/proc/self/gid_map", "0 %d 1", gid);
+
+ if (setgroups(0, NULL) != 0) {
+ die("setgroups failed: %s\n",
+ strerror(errno));
+ }
+ if (setgid(0) != 0) {
+ die ("setgid(0) failed %s\n",
+ strerror(errno));
+ }
+ if (setuid(0) != 0) {
+ die("setuid(0) failed %s\n",
+ strerror(errno));
+ }
+}
+
+static
+bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags)
+{
+ pid_t child;
+
+ child = fork();
+ if (child == -1) {
+ die("fork failed: %s\n",
+ strerror(errno));
+ }
+ if (child != 0) { /* parent */
+ pid_t pid;
+ int status;
+ pid = waitpid(child, &status, 0);
+ if (pid == -1) {
+ die("waitpid failed: %s\n",
+ strerror(errno));
+ }
+ if (pid != child) {
+ die("waited for %d got %d\n",
+ child, pid);
+ }
+ if (!WIFEXITED(status)) {
+ die("child did not terminate cleanly\n");
+ }
+ return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false;
+ }
+
+ create_and_enter_userns();
+ if (unshare(CLONE_NEWNS) != 0) {
+ die("unshare(CLONE_NEWNS) failed: %s\n",
+ strerror(errno));
+ }
+
+ if (mount("testing", "/tmp", "ramfs", mount_flags, NULL) != 0) {
+ die("mount of /tmp failed: %s\n",
+ strerror(errno));
+ }
+
+ create_and_enter_userns();
+
+ if (unshare(CLONE_NEWNS) != 0) {
+ die("unshare(CLONE_NEWNS) failed: %s\n",
+ strerror(errno));
+ }
+
+ if (mount("/tmp", "/tmp", "none",
+ MS_REMOUNT | MS_BIND | remount_flags, NULL) != 0) {
+ /* system("cat /proc/self/mounts"); */
+ die("remount of /tmp failed: %s\n",
+ strerror(errno));
+ }
+
+ if (mount("/tmp", "/tmp", "none",
+ MS_REMOUNT | MS_BIND | invalid_flags, NULL) == 0) {
+ /* system("cat /proc/self/mounts"); */
+ die("remount of /tmp with invalid flags "
+ "succeeded unexpectedly\n");
+ }
+ exit(EXIT_SUCCESS);
+}
+
+static bool test_unpriv_remount_simple(int mount_flags)
+{
+ return test_unpriv_remount(mount_flags, mount_flags, 0);
+}
+
+static bool test_unpriv_remount_atime(int mount_flags, int invalid_flags)
+{
+ return test_unpriv_remount(mount_flags, mount_flags, invalid_flags);
+}
+
+int main(int argc, char **argv)
+{
+ if (!test_unpriv_remount_simple(MS_RDONLY|MS_NODEV)) {
+ die("MS_RDONLY malfunctions\n");
+ }
+ if (!test_unpriv_remount_simple(MS_NODEV)) {
+ die("MS_NODEV malfunctions\n");
+ }
+ if (!test_unpriv_remount_simple(MS_NOSUID|MS_NODEV)) {
+ die("MS_NOSUID malfunctions\n");
+ }
+ if (!test_unpriv_remount_simple(MS_NOEXEC|MS_NODEV)) {
+ die("MS_NOEXEC malfunctions\n");
+ }
+ if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODEV,
+ MS_NOATIME|MS_NODEV))
+ {
+ die("MS_RELATIME malfunctions\n");
+ }
+ if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODEV,
+ MS_NOATIME|MS_NODEV))
+ {
+ die("MS_STRICTATIME malfunctions\n");
+ }
+ if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODEV,
+ MS_STRICTATIME|MS_NODEV))
+ {
+ die("MS_RELATIME malfunctions\n");
+ }
+ if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME|MS_NODEV,
+ MS_NOATIME|MS_NODEV))
+ {
+ die("MS_RELATIME malfunctions\n");
+ }
+ if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME|MS_NODEV,
+ MS_NOATIME|MS_NODEV))
+ {
+ die("MS_RELATIME malfunctions\n");
+ }
+ if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME|MS_NODEV,
+ MS_STRICTATIME|MS_NODEV))
+ {
+ die("MS_RELATIME malfunctions\n");
+ }
+ if (!test_unpriv_remount(MS_STRICTATIME|MS_NODEV, MS_NODEV,
+ MS_NOATIME|MS_NODEV))
+ {
+ die("Default atime malfunctions\n");
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile
index 218a122..8056e2e 100644
--- a/tools/testing/selftests/mqueue/Makefile
+++ b/tools/testing/selftests/mqueue/Makefile
@@ -1,6 +1,6 @@
all:
- gcc -O2 -lrt mq_open_tests.c -o mq_open_tests
- gcc -O2 -lrt -lpthread -lpopt -o mq_perf_tests mq_perf_tests.c
+ gcc -O2 mq_open_tests.c -o mq_open_tests -lrt
+ gcc -O2 -o mq_perf_tests mq_perf_tests.c -lrt -lpthread -lpopt
run_tests:
@./mq_open_tests /test1 || echo "mq_open_tests: [FAIL]"
diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c
index 711cc29..9c1a5d35 100644
--- a/tools/testing/selftests/mqueue/mq_open_tests.c
+++ b/tools/testing/selftests/mqueue/mq_open_tests.c
@@ -80,7 +80,8 @@ void shutdown(int exit_val, char *err_cause, int line_no)
if (in_shutdown++)
return;
- seteuid(0);
+ if (seteuid(0) == -1)
+ perror("seteuid() failed");
if (queue != -1)
if (mq_close(queue))
@@ -292,8 +293,10 @@ int main(int argc, char *argv[])
/* Tell the user our initial state */
printf("\nInitial system state:\n");
printf("\tUsing queue path:\t\t%s\n", queue_path);
- printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", saved_limits.rlim_cur);
- printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", saved_limits.rlim_max);
+ printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n",
+ (long) saved_limits.rlim_cur);
+ printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n",
+ (long) saved_limits.rlim_max);
printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
if (default_settings) {
@@ -308,8 +311,8 @@ int main(int argc, char *argv[])
validate_current_settings();
printf("Adjusted system state for testing:\n");
- printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", cur_limits.rlim_cur);
- printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", cur_limits.rlim_max);
+ printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur);
+ printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max);
printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
if (default_settings) {
@@ -454,7 +457,12 @@ int main(int argc, char *argv[])
else
printf("Queue open with total size > 2GB when euid = 0 "
"failed:\t\t\tPASS\n");
- seteuid(99);
+
+ if (seteuid(99) == -1) {
+ perror("seteuid() failed");
+ exit(1);
+ }
+
attr.mq_maxmsg = cur_max_msgs;
attr.mq_msgsize = cur_max_msgsize;
if (test_queue_fail(&attr, &result))
diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c
index 2fadd4b..94dae65 100644
--- a/tools/testing/selftests/mqueue/mq_perf_tests.c
+++ b/tools/testing/selftests/mqueue/mq_perf_tests.c
@@ -296,9 +296,9 @@ static inline void open_queue(struct mq_attr *attr)
printf("\n\tQueue %s created:\n", queue_path);
printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ?
"O_NONBLOCK" : "(null)");
- printf("\t\tmq_maxmsg:\t\t\t%d\n", result.mq_maxmsg);
- printf("\t\tmq_msgsize:\t\t\t%d\n", result.mq_msgsize);
- printf("\t\tmq_curmsgs:\t\t\t%d\n", result.mq_curmsgs);
+ printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg);
+ printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize);
+ printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs);
}
void *fake_cont_thread(void *arg)
@@ -440,7 +440,7 @@ void *perf_test_thread(void *arg)
shutdown(2, "clock_getres()", __LINE__);
printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max);
- printf("\t\tClock resolution:\t\t%d nsec%s\n", res.tv_nsec,
+ printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec,
res.tv_nsec > 1 ? "s" : "");
@@ -454,20 +454,20 @@ void *perf_test_thread(void *arg)
recv_total.tv_nsec = 0;
for (i = 0; i < TEST1_LOOPS; i++)
do_send_recv();
- printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
+ printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
send_total.tv_sec, send_total.tv_nsec);
nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
send_total.tv_nsec) / TEST1_LOOPS;
- printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
- printf("\t\tRecv msg:\t\t\t%d.%ds total time\n",
+ printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
+ printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
recv_total.tv_sec, recv_total.tv_nsec);
nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
recv_total.tv_nsec) / TEST1_LOOPS;
- printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
+ printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
- printf(cur_test->desc);
+ printf("%s:\n", cur_test->desc);
printf("\t\t(%d iterations)\n", TEST2_LOOPS);
prio_out = 0;
send_total.tv_sec = 0;
@@ -493,16 +493,16 @@ void *perf_test_thread(void *arg)
cur_test->func(&prio_out);
}
printf("done.\n");
- printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
+ printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
send_total.tv_sec, send_total.tv_nsec);
nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
send_total.tv_nsec) / TEST2_LOOPS;
- printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
- printf("\t\tRecv msg:\t\t\t%d.%ds total time\n",
+ printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
+ printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
recv_total.tv_sec, recv_total.tv_nsec);
nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
recv_total.tv_nsec) / TEST2_LOOPS;
- printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
+ printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
printf("\t\tDraining queue...");
fflush(stdout);
clock_gettime(clock, &start);
@@ -653,8 +653,10 @@ int main(int argc, char *argv[])
/* Tell the user our initial state */
printf("\nInitial system state:\n");
printf("\tUsing queue path:\t\t\t%s\n", queue_path);
- printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n", saved_limits.rlim_cur);
- printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", saved_limits.rlim_max);
+ printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
+ (long) saved_limits.rlim_cur);
+ printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
+ (long) saved_limits.rlim_max);
printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
printf("\tNice value:\t\t\t\t%d\n", cur_nice);
@@ -667,10 +669,10 @@ int main(int argc, char *argv[])
printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
} else {
- printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n",
- cur_limits.rlim_cur);
- printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n",
- cur_limits.rlim_max);
+ printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
+ (long) cur_limits.rlim_cur);
+ printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
+ (long) cur_limits.rlim_max);
}
printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index 54833a7..f6ff90a 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -13,14 +13,14 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR
export CC CFLAGS
-TARGETS = pmu copyloops mm tm
+TARGETS = pmu copyloops mm tm primitives
endif
-all:
- @for TARGET in $(TARGETS); do \
- $(MAKE) -C $$TARGET all; \
- done;
+all: $(TARGETS)
+
+$(TARGETS):
+ $(MAKE) -k -C $@ all
run_tests: all
@for TARGET in $(TARGETS); do \
@@ -36,4 +36,4 @@ clean:
tags:
find . -name '*.c' -o -name '*.h' | xargs ctags
-.PHONY: all run_tests clean tags
+.PHONY: all run_tests clean tags $(TARGETS)
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile
index b9ff0db..c9f4263 100644
--- a/tools/testing/selftests/powerpc/pmu/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/Makefile
@@ -1,10 +1,12 @@
noarg:
$(MAKE) -C ../
-PROGS := count_instructions
-EXTRA_SOURCES := ../harness.c event.c
+PROGS := count_instructions l3_bank_test per_event_excludes
+EXTRA_SOURCES := ../harness.c event.c lib.c
-all: $(PROGS) sub_all
+SUB_TARGETS = ebb
+
+all: $(PROGS) $(SUB_TARGETS)
$(PROGS): $(EXTRA_SOURCES)
@@ -20,13 +22,8 @@ run_tests: all sub_run_tests
clean: sub_clean
rm -f $(PROGS) loop.o
-
-SUB_TARGETS = ebb
-
-sub_all:
- @for TARGET in $(SUB_TARGETS); do \
- $(MAKE) -C $$TARGET all; \
- done;
+$(SUB_TARGETS):
+ $(MAKE) -k -C $@ all
sub_run_tests: all
@for TARGET in $(SUB_TARGETS); do \
@@ -38,4 +35,4 @@ sub_clean:
$(MAKE) -C $$TARGET clean; \
done;
-.PHONY: all run_tests clean sub_all sub_run_tests sub_clean
+.PHONY: all run_tests clean sub_run_tests sub_clean $(SUB_TARGETS)
diff --git a/tools/testing/selftests/powerpc/pmu/count_instructions.c b/tools/testing/selftests/powerpc/pmu/count_instructions.c
index 312b4f0..4622117 100644
--- a/tools/testing/selftests/powerpc/pmu/count_instructions.c
+++ b/tools/testing/selftests/powerpc/pmu/count_instructions.c
@@ -12,6 +12,7 @@
#include "event.h"
#include "utils.h"
+#include "lib.h"
extern void thirty_two_instruction_loop(u64 loops);
@@ -90,7 +91,7 @@ static u64 determine_overhead(struct event *events)
return overhead;
}
-static int count_instructions(void)
+static int test_body(void)
{
struct event events[2];
u64 overhead;
@@ -111,17 +112,23 @@ static int count_instructions(void)
overhead = determine_overhead(events);
printf("Overhead of null loop: %llu instructions\n", overhead);
- /* Run for 1M instructions */
- FAIL_IF(do_count_loop(events, 0x100000, overhead, true));
+ /* Run for 1Mi instructions */
+ FAIL_IF(do_count_loop(events, 1000000, overhead, true));
+
+ /* Run for 10Mi instructions */
+ FAIL_IF(do_count_loop(events, 10000000, overhead, true));
+
+ /* Run for 100Mi instructions */
+ FAIL_IF(do_count_loop(events, 100000000, overhead, true));
- /* Run for 10M instructions */
- FAIL_IF(do_count_loop(events, 0xa00000, overhead, true));
+ /* Run for 1Bi instructions */
+ FAIL_IF(do_count_loop(events, 1000000000, overhead, true));
- /* Run for 100M instructions */
- FAIL_IF(do_count_loop(events, 0x6400000, overhead, true));
+ /* Run for 16Bi instructions */
+ FAIL_IF(do_count_loop(events, 16000000000, overhead, true));
- /* Run for 1G instructions */
- FAIL_IF(do_count_loop(events, 0x40000000, overhead, true));
+ /* Run for 64Bi instructions */
+ FAIL_IF(do_count_loop(events, 64000000000, overhead, true));
event_close(&events[0]);
event_close(&events[1]);
@@ -129,6 +136,11 @@ static int count_instructions(void)
return 0;
}
+static int count_instructions(void)
+{
+ return eat_cpu(test_body);
+}
+
int main(void)
{
return test_harness(count_instructions, "count_instructions");
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
index edbba2a..3dc4332 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
@@ -13,11 +13,12 @@ PROGS := reg_access_test event_attributes_test cycles_test \
close_clears_pmcc_test instruction_count_test \
fork_cleanup_test ebb_on_child_test \
ebb_on_willing_child_test back_to_back_ebbs_test \
- lost_exception_test no_handler_test
+ lost_exception_test no_handler_test \
+ cycles_with_mmcr2_test
all: $(PROGS)
-$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c
+$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S
instruction_count_test: ../loop.S
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S b/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S
new file mode 100644
index 0000000..c7e4093
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2014, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#include <ppc-asm.h>
+
+ .text
+
+FUNC_START(core_busy_loop)
+ stdu %r1, -168(%r1)
+ std r14, 160(%r1)
+ std r15, 152(%r1)
+ std r16, 144(%r1)
+ std r17, 136(%r1)
+ std r18, 128(%r1)
+ std r19, 120(%r1)
+ std r20, 112(%r1)
+ std r21, 104(%r1)
+ std r22, 96(%r1)
+ std r23, 88(%r1)
+ std r24, 80(%r1)
+ std r25, 72(%r1)
+ std r26, 64(%r1)
+ std r27, 56(%r1)
+ std r28, 48(%r1)
+ std r29, 40(%r1)
+ std r30, 32(%r1)
+ std r31, 24(%r1)
+
+ li r3, 0x3030
+ std r3, -96(%r1)
+ li r4, 0x4040
+ std r4, -104(%r1)
+ li r5, 0x5050
+ std r5, -112(%r1)
+ li r6, 0x6060
+ std r6, -120(%r1)
+ li r7, 0x7070
+ std r7, -128(%r1)
+ li r8, 0x0808
+ std r8, -136(%r1)
+ li r9, 0x0909
+ std r9, -144(%r1)
+ li r10, 0x1010
+ std r10, -152(%r1)
+ li r11, 0x1111
+ std r11, -160(%r1)
+ li r14, 0x1414
+ std r14, -168(%r1)
+ li r15, 0x1515
+ std r15, -176(%r1)
+ li r16, 0x1616
+ std r16, -184(%r1)
+ li r17, 0x1717
+ std r17, -192(%r1)
+ li r18, 0x1818
+ std r18, -200(%r1)
+ li r19, 0x1919
+ std r19, -208(%r1)
+ li r20, 0x2020
+ std r20, -216(%r1)
+ li r21, 0x2121
+ std r21, -224(%r1)
+ li r22, 0x2222
+ std r22, -232(%r1)
+ li r23, 0x2323
+ std r23, -240(%r1)
+ li r24, 0x2424
+ std r24, -248(%r1)
+ li r25, 0x2525
+ std r25, -256(%r1)
+ li r26, 0x2626
+ std r26, -264(%r1)
+ li r27, 0x2727
+ std r27, -272(%r1)
+ li r28, 0x2828
+ std r28, -280(%r1)
+ li r29, 0x2929
+ std r29, -288(%r1)
+ li r30, 0x3030
+ li r31, 0x3131
+
+ li r3, 0
+0: addi r3, r3, 1
+ cmpwi r3, 100
+ blt 0b
+
+ /* Return 1 (fail) unless we get through all the checks */
+ li r3, 1
+
+ /* Check none of our registers have been corrupted */
+ cmpwi r4, 0x4040
+ bne 1f
+ cmpwi r5, 0x5050
+ bne 1f
+ cmpwi r6, 0x6060
+ bne 1f
+ cmpwi r7, 0x7070
+ bne 1f
+ cmpwi r8, 0x0808
+ bne 1f
+ cmpwi r9, 0x0909
+ bne 1f
+ cmpwi r10, 0x1010
+ bne 1f
+ cmpwi r11, 0x1111
+ bne 1f
+ cmpwi r14, 0x1414
+ bne 1f
+ cmpwi r15, 0x1515
+ bne 1f
+ cmpwi r16, 0x1616
+ bne 1f
+ cmpwi r17, 0x1717
+ bne 1f
+ cmpwi r18, 0x1818
+ bne 1f
+ cmpwi r19, 0x1919
+ bne 1f
+ cmpwi r20, 0x2020
+ bne 1f
+ cmpwi r21, 0x2121
+ bne 1f
+ cmpwi r22, 0x2222
+ bne 1f
+ cmpwi r23, 0x2323
+ bne 1f
+ cmpwi r24, 0x2424
+ bne 1f
+ cmpwi r25, 0x2525
+ bne 1f
+ cmpwi r26, 0x2626
+ bne 1f
+ cmpwi r27, 0x2727
+ bne 1f
+ cmpwi r28, 0x2828
+ bne 1f
+ cmpwi r29, 0x2929
+ bne 1f
+ cmpwi r30, 0x3030
+ bne 1f
+ cmpwi r31, 0x3131
+ bne 1f
+
+ /* Load junk into all our registers before we reload them from the stack. */
+ li r3, 0xde
+ li r4, 0xad
+ li r5, 0xbe
+ li r6, 0xef
+ li r7, 0xde
+ li r8, 0xad
+ li r9, 0xbe
+ li r10, 0xef
+ li r11, 0xde
+ li r14, 0xad
+ li r15, 0xbe
+ li r16, 0xef
+ li r17, 0xde
+ li r18, 0xad
+ li r19, 0xbe
+ li r20, 0xef
+ li r21, 0xde
+ li r22, 0xad
+ li r23, 0xbe
+ li r24, 0xef
+ li r25, 0xde
+ li r26, 0xad
+ li r27, 0xbe
+ li r28, 0xef
+ li r29, 0xdd
+
+ ld r3, -96(%r1)
+ cmpwi r3, 0x3030
+ bne 1f
+ ld r4, -104(%r1)
+ cmpwi r4, 0x4040
+ bne 1f
+ ld r5, -112(%r1)
+ cmpwi r5, 0x5050
+ bne 1f
+ ld r6, -120(%r1)
+ cmpwi r6, 0x6060
+ bne 1f
+ ld r7, -128(%r1)
+ cmpwi r7, 0x7070
+ bne 1f
+ ld r8, -136(%r1)
+ cmpwi r8, 0x0808
+ bne 1f
+ ld r9, -144(%r1)
+ cmpwi r9, 0x0909
+ bne 1f
+ ld r10, -152(%r1)
+ cmpwi r10, 0x1010
+ bne 1f
+ ld r11, -160(%r1)
+ cmpwi r11, 0x1111
+ bne 1f
+ ld r14, -168(%r1)
+ cmpwi r14, 0x1414
+ bne 1f
+ ld r15, -176(%r1)
+ cmpwi r15, 0x1515
+ bne 1f
+ ld r16, -184(%r1)
+ cmpwi r16, 0x1616
+ bne 1f
+ ld r17, -192(%r1)
+ cmpwi r17, 0x1717
+ bne 1f
+ ld r18, -200(%r1)
+ cmpwi r18, 0x1818
+ bne 1f
+ ld r19, -208(%r1)
+ cmpwi r19, 0x1919
+ bne 1f
+ ld r20, -216(%r1)
+ cmpwi r20, 0x2020
+ bne 1f
+ ld r21, -224(%r1)
+ cmpwi r21, 0x2121
+ bne 1f
+ ld r22, -232(%r1)
+ cmpwi r22, 0x2222
+ bne 1f
+ ld r23, -240(%r1)
+ cmpwi r23, 0x2323
+ bne 1f
+ ld r24, -248(%r1)
+ cmpwi r24, 0x2424
+ bne 1f
+ ld r25, -256(%r1)
+ cmpwi r25, 0x2525
+ bne 1f
+ ld r26, -264(%r1)
+ cmpwi r26, 0x2626
+ bne 1f
+ ld r27, -272(%r1)
+ cmpwi r27, 0x2727
+ bne 1f
+ ld r28, -280(%r1)
+ cmpwi r28, 0x2828
+ bne 1f
+ ld r29, -288(%r1)
+ cmpwi r29, 0x2929
+ bne 1f
+
+ /* Load 0 (success) to return */
+ li r3, 0
+
+1: ld r14, 160(%r1)
+ ld r15, 152(%r1)
+ ld r16, 144(%r1)
+ ld r17, 136(%r1)
+ ld r18, 128(%r1)
+ ld r19, 120(%r1)
+ ld r20, 112(%r1)
+ ld r21, 104(%r1)
+ ld r22, 96(%r1)
+ ld r23, 88(%r1)
+ ld r24, 80(%r1)
+ ld r25, 72(%r1)
+ ld r26, 64(%r1)
+ ld r27, 56(%r1)
+ ld r28, 48(%r1)
+ ld r29, 40(%r1)
+ ld r30, 32(%r1)
+ ld r31, 24(%r1)
+ addi %r1, %r1, 168
+ blr
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c
new file mode 100644
index 0000000..d43029b
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2014, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "ebb.h"
+
+
+/*
+ * Test of counting cycles while manipulating the user accessible bits in MMCR2.
+ */
+
+/* We use two values because the first freezes PMC1 and so we would get no EBBs */
+#define MMCR2_EXPECTED_1 0x4020100804020000UL /* (FC1P|FC2P|FC3P|FC4P|FC5P|FC6P) */
+#define MMCR2_EXPECTED_2 0x0020100804020000UL /* ( FC2P|FC3P|FC4P|FC5P|FC6P) */
+
+
+int cycles_with_mmcr2(void)
+{
+ struct event event;
+ uint64_t val, expected[2], actual;
+ int i;
+ bool bad_mmcr2;
+
+ event_init_named(&event, 0x1001e, "cycles");
+ event_leader_ebb_init(&event);
+
+ event.attr.exclude_kernel = 1;
+ event.attr.exclude_hv = 1;
+ event.attr.exclude_idle = 1;
+
+ FAIL_IF(event_open(&event));
+
+ ebb_enable_pmc_counting(1);
+ setup_ebb_handler(standard_ebb_callee);
+ ebb_global_enable();
+
+ FAIL_IF(ebb_event_enable(&event));
+
+ mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
+
+ /* XXX Set of MMCR2 must be after enable */
+ expected[0] = MMCR2_EXPECTED_1;
+ expected[1] = MMCR2_EXPECTED_2;
+ i = 0;
+ bad_mmcr2 = false;
+
+ /* Make sure we loop until we take at least one EBB */
+ while ((ebb_state.stats.ebb_count < 20 && !bad_mmcr2) ||
+ ebb_state.stats.ebb_count < 1)
+ {
+ mtspr(SPRN_MMCR2, expected[i % 2]);
+
+ FAIL_IF(core_busy_loop());
+
+ val = mfspr(SPRN_MMCR2);
+ if (val != expected[i % 2]) {
+ bad_mmcr2 = true;
+ actual = val;
+ }
+
+ i++;
+ }
+
+ ebb_global_disable();
+ ebb_freeze_pmcs();
+
+ count_pmc(1, sample_period);
+
+ dump_ebb_state();
+
+ event_close(&event);
+
+ FAIL_IF(ebb_state.stats.ebb_count == 0);
+
+ if (bad_mmcr2)
+ printf("Bad MMCR2 value seen is 0x%lx\n", actual);
+
+ FAIL_IF(bad_mmcr2);
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(cycles_with_mmcr2, "cycles_with_mmcr2");
+}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
index 1b46be9..d7a72ce 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
@@ -224,6 +224,7 @@ void dump_ebb_hw_state(void)
printf("HW state:\n" \
"MMCR0 0x%016x %s\n" \
+ "MMCR2 0x%016lx\n" \
"EBBHR 0x%016lx\n" \
"BESCR 0x%016llx %s\n" \
"PMC1 0x%016lx\n" \
@@ -233,10 +234,11 @@ void dump_ebb_hw_state(void)
"PMC5 0x%016lx\n" \
"PMC6 0x%016lx\n" \
"SIAR 0x%016lx\n",
- mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_EBBHR), bescr,
- decode_bescr(bescr), mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
- mfspr(SPRN_PMC3), mfspr(SPRN_PMC4), mfspr(SPRN_PMC5),
- mfspr(SPRN_PMC6), mfspr(SPRN_SIAR));
+ mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_MMCR2),
+ mfspr(SPRN_EBBHR), bescr, decode_bescr(bescr),
+ mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), mfspr(SPRN_PMC3),
+ mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), mfspr(SPRN_PMC6),
+ mfspr(SPRN_SIAR));
}
void dump_ebb_state(void)
@@ -335,257 +337,6 @@ void event_leader_ebb_init(struct event *e)
e->attr.pinned = 1;
}
-int core_busy_loop(void)
-{
- int rc;
-
- asm volatile (
- "li 3, 0x3030\n"
- "std 3, -96(1)\n"
- "li 4, 0x4040\n"
- "std 4, -104(1)\n"
- "li 5, 0x5050\n"
- "std 5, -112(1)\n"
- "li 6, 0x6060\n"
- "std 6, -120(1)\n"
- "li 7, 0x7070\n"
- "std 7, -128(1)\n"
- "li 8, 0x0808\n"
- "std 8, -136(1)\n"
- "li 9, 0x0909\n"
- "std 9, -144(1)\n"
- "li 10, 0x1010\n"
- "std 10, -152(1)\n"
- "li 11, 0x1111\n"
- "std 11, -160(1)\n"
- "li 14, 0x1414\n"
- "std 14, -168(1)\n"
- "li 15, 0x1515\n"
- "std 15, -176(1)\n"
- "li 16, 0x1616\n"
- "std 16, -184(1)\n"
- "li 17, 0x1717\n"
- "std 17, -192(1)\n"
- "li 18, 0x1818\n"
- "std 18, -200(1)\n"
- "li 19, 0x1919\n"
- "std 19, -208(1)\n"
- "li 20, 0x2020\n"
- "std 20, -216(1)\n"
- "li 21, 0x2121\n"
- "std 21, -224(1)\n"
- "li 22, 0x2222\n"
- "std 22, -232(1)\n"
- "li 23, 0x2323\n"
- "std 23, -240(1)\n"
- "li 24, 0x2424\n"
- "std 24, -248(1)\n"
- "li 25, 0x2525\n"
- "std 25, -256(1)\n"
- "li 26, 0x2626\n"
- "std 26, -264(1)\n"
- "li 27, 0x2727\n"
- "std 27, -272(1)\n"
- "li 28, 0x2828\n"
- "std 28, -280(1)\n"
- "li 29, 0x2929\n"
- "std 29, -288(1)\n"
- "li 30, 0x3030\n"
- "li 31, 0x3131\n"
-
- "li 3, 0\n"
- "0: "
- "addi 3, 3, 1\n"
- "cmpwi 3, 100\n"
- "blt 0b\n"
-
- /* Return 1 (fail) unless we get through all the checks */
- "li 0, 1\n"
-
- /* Check none of our registers have been corrupted */
- "cmpwi 4, 0x4040\n"
- "bne 1f\n"
- "cmpwi 5, 0x5050\n"
- "bne 1f\n"
- "cmpwi 6, 0x6060\n"
- "bne 1f\n"
- "cmpwi 7, 0x7070\n"
- "bne 1f\n"
- "cmpwi 8, 0x0808\n"
- "bne 1f\n"
- "cmpwi 9, 0x0909\n"
- "bne 1f\n"
- "cmpwi 10, 0x1010\n"
- "bne 1f\n"
- "cmpwi 11, 0x1111\n"
- "bne 1f\n"
- "cmpwi 14, 0x1414\n"
- "bne 1f\n"
- "cmpwi 15, 0x1515\n"
- "bne 1f\n"
- "cmpwi 16, 0x1616\n"
- "bne 1f\n"
- "cmpwi 17, 0x1717\n"
- "bne 1f\n"
- "cmpwi 18, 0x1818\n"
- "bne 1f\n"
- "cmpwi 19, 0x1919\n"
- "bne 1f\n"
- "cmpwi 20, 0x2020\n"
- "bne 1f\n"
- "cmpwi 21, 0x2121\n"
- "bne 1f\n"
- "cmpwi 22, 0x2222\n"
- "bne 1f\n"
- "cmpwi 23, 0x2323\n"
- "bne 1f\n"
- "cmpwi 24, 0x2424\n"
- "bne 1f\n"
- "cmpwi 25, 0x2525\n"
- "bne 1f\n"
- "cmpwi 26, 0x2626\n"
- "bne 1f\n"
- "cmpwi 27, 0x2727\n"
- "bne 1f\n"
- "cmpwi 28, 0x2828\n"
- "bne 1f\n"
- "cmpwi 29, 0x2929\n"
- "bne 1f\n"
- "cmpwi 30, 0x3030\n"
- "bne 1f\n"
- "cmpwi 31, 0x3131\n"
- "bne 1f\n"
-
- /* Load junk into all our registers before we reload them from the stack. */
- "li 3, 0xde\n"
- "li 4, 0xad\n"
- "li 5, 0xbe\n"
- "li 6, 0xef\n"
- "li 7, 0xde\n"
- "li 8, 0xad\n"
- "li 9, 0xbe\n"
- "li 10, 0xef\n"
- "li 11, 0xde\n"
- "li 14, 0xad\n"
- "li 15, 0xbe\n"
- "li 16, 0xef\n"
- "li 17, 0xde\n"
- "li 18, 0xad\n"
- "li 19, 0xbe\n"
- "li 20, 0xef\n"
- "li 21, 0xde\n"
- "li 22, 0xad\n"
- "li 23, 0xbe\n"
- "li 24, 0xef\n"
- "li 25, 0xde\n"
- "li 26, 0xad\n"
- "li 27, 0xbe\n"
- "li 28, 0xef\n"
- "li 29, 0xdd\n"
-
- "ld 3, -96(1)\n"
- "cmpwi 3, 0x3030\n"
- "bne 1f\n"
- "ld 4, -104(1)\n"
- "cmpwi 4, 0x4040\n"
- "bne 1f\n"
- "ld 5, -112(1)\n"
- "cmpwi 5, 0x5050\n"
- "bne 1f\n"
- "ld 6, -120(1)\n"
- "cmpwi 6, 0x6060\n"
- "bne 1f\n"
- "ld 7, -128(1)\n"
- "cmpwi 7, 0x7070\n"
- "bne 1f\n"
- "ld 8, -136(1)\n"
- "cmpwi 8, 0x0808\n"
- "bne 1f\n"
- "ld 9, -144(1)\n"
- "cmpwi 9, 0x0909\n"
- "bne 1f\n"
- "ld 10, -152(1)\n"
- "cmpwi 10, 0x1010\n"
- "bne 1f\n"
- "ld 11, -160(1)\n"
- "cmpwi 11, 0x1111\n"
- "bne 1f\n"
- "ld 14, -168(1)\n"
- "cmpwi 14, 0x1414\n"
- "bne 1f\n"
- "ld 15, -176(1)\n"
- "cmpwi 15, 0x1515\n"
- "bne 1f\n"
- "ld 16, -184(1)\n"
- "cmpwi 16, 0x1616\n"
- "bne 1f\n"
- "ld 17, -192(1)\n"
- "cmpwi 17, 0x1717\n"
- "bne 1f\n"
- "ld 18, -200(1)\n"
- "cmpwi 18, 0x1818\n"
- "bne 1f\n"
- "ld 19, -208(1)\n"
- "cmpwi 19, 0x1919\n"
- "bne 1f\n"
- "ld 20, -216(1)\n"
- "cmpwi 20, 0x2020\n"
- "bne 1f\n"
- "ld 21, -224(1)\n"
- "cmpwi 21, 0x2121\n"
- "bne 1f\n"
- "ld 22, -232(1)\n"
- "cmpwi 22, 0x2222\n"
- "bne 1f\n"
- "ld 23, -240(1)\n"
- "cmpwi 23, 0x2323\n"
- "bne 1f\n"
- "ld 24, -248(1)\n"
- "cmpwi 24, 0x2424\n"
- "bne 1f\n"
- "ld 25, -256(1)\n"
- "cmpwi 25, 0x2525\n"
- "bne 1f\n"
- "ld 26, -264(1)\n"
- "cmpwi 26, 0x2626\n"
- "bne 1f\n"
- "ld 27, -272(1)\n"
- "cmpwi 27, 0x2727\n"
- "bne 1f\n"
- "ld 28, -280(1)\n"
- "cmpwi 28, 0x2828\n"
- "bne 1f\n"
- "ld 29, -288(1)\n"
- "cmpwi 29, 0x2929\n"
- "bne 1f\n"
-
- /* Load 0 (success) to return */
- "li 0, 0\n"
-
- "1: mr %0, 0\n"
-
- : "=r" (rc)
- : /* no inputs */
- : "3", "4", "5", "6", "7", "8", "9", "10", "11", "14",
- "15", "16", "17", "18", "19", "20", "21", "22", "23",
- "24", "25", "26", "27", "28", "29", "30", "31",
- "memory"
- );
-
- return rc;
-}
-
-int core_busy_loop_with_freeze(void)
-{
- int rc;
-
- mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
- rc = core_busy_loop();
- mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
-
- return rc;
-}
-
int ebb_child(union pipe read_pipe, union pipe write_pipe)
{
struct event event;
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
index e62bde0..e44eee5 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
@@ -70,7 +70,6 @@ int ebb_check_mmcr0(void);
extern u64 sample_period;
int core_busy_loop(void);
-int core_busy_loop_with_freeze(void);
int ebb_child(union pipe read_pipe, union pipe write_pipe);
int catch_sigill(void (*func)(void));
void write_pmc1(void);
diff --git a/tools/testing/selftests/powerpc/pmu/l3_bank_test.c b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c
new file mode 100644
index 0000000..77472f3
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "event.h"
+#include "utils.h"
+
+#define MALLOC_SIZE (0x10000 * 10) /* Ought to be enough .. */
+
+/*
+ * Tests that the L3 bank handling is correct. We fixed it in commit e9aaac1.
+ */
+static int l3_bank_test(void)
+{
+ struct event event;
+ char *p;
+ int i;
+
+ p = malloc(MALLOC_SIZE);
+ FAIL_IF(!p);
+
+ event_init(&event, 0x84918F);
+
+ FAIL_IF(event_open(&event));
+
+ for (i = 0; i < MALLOC_SIZE; i += 0x10000)
+ p[i] = i;
+
+ event_read(&event);
+ event_report(&event);
+
+ FAIL_IF(event.result.running == 0);
+ FAIL_IF(event.result.enabled == 0);
+
+ event_close(&event);
+ free(p);
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(l3_bank_test, "l3_bank_test");
+}
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
index 0f6a473..9768dea 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.c
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -5,10 +5,15 @@
#define _GNU_SOURCE /* For CPU_ZERO etc. */
+#include <elf.h>
#include <errno.h>
+#include <fcntl.h>
+#include <link.h>
#include <sched.h>
#include <setjmp.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/wait.h>
#include "utils.h"
@@ -177,8 +182,8 @@ struct addr_range libc, vdso;
int parse_proc_maps(void)
{
+ unsigned long start, end;
char execute, name[128];
- uint64_t start, end;
FILE *f;
int rc;
@@ -250,3 +255,46 @@ out_close:
out:
return rc;
}
+
+static char auxv[4096];
+
+void *get_auxv_entry(int type)
+{
+ ElfW(auxv_t) *p;
+ void *result;
+ ssize_t num;
+ int fd;
+
+ fd = open("/proc/self/auxv", O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ return NULL;
+ }
+
+ result = NULL;
+
+ num = read(fd, auxv, sizeof(auxv));
+ if (num < 0) {
+ perror("read");
+ goto out;
+ }
+
+ if (num > sizeof(auxv)) {
+ printf("Overflowed auxv buffer\n");
+ goto out;
+ }
+
+ p = (ElfW(auxv_t) *)auxv;
+
+ while (p->a_type != AT_NULL) {
+ if (p->a_type == type) {
+ result = (void *)p->a_un.a_val;
+ break;
+ }
+
+ p++;
+ }
+out:
+ close(fd);
+ return result;
+}
diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h
index ca5d72a..0f0339c 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.h
+++ b/tools/testing/selftests/powerpc/pmu/lib.h
@@ -29,6 +29,7 @@ extern int notify_parent(union pipe write_pipe);
extern int notify_parent_of_error(union pipe write_pipe);
extern pid_t eat_cpu(int (test_function)(void));
extern bool require_paranoia_below(int level);
+extern void *get_auxv_entry(int type);
struct addr_range {
uint64_t first, last;
diff --git a/tools/testing/selftests/powerpc/pmu/per_event_excludes.c b/tools/testing/selftests/powerpc/pmu/per_event_excludes.c
new file mode 100644
index 0000000..fddbbc9
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/per_event_excludes.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2014, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#define _GNU_SOURCE
+
+#include <elf.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/prctl.h>
+
+#include "event.h"
+#include "lib.h"
+#include "utils.h"
+
+/*
+ * Test that per-event excludes work.
+ */
+
+static int per_event_excludes(void)
+{
+ struct event *e, events[4];
+ char *platform;
+ int i;
+
+ platform = (char *)get_auxv_entry(AT_BASE_PLATFORM);
+ FAIL_IF(!platform);
+ SKIP_IF(strcmp(platform, "power8") != 0);
+
+ /*
+ * We need to create the events disabled, otherwise the running/enabled
+ * counts don't match up.
+ */
+ e = &events[0];
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
+ PERF_TYPE_HARDWARE, "instructions");
+ e->attr.disabled = 1;
+
+ e = &events[1];
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
+ PERF_TYPE_HARDWARE, "instructions(k)");
+ e->attr.disabled = 1;
+ e->attr.exclude_user = 1;
+ e->attr.exclude_hv = 1;
+
+ e = &events[2];
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
+ PERF_TYPE_HARDWARE, "instructions(h)");
+ e->attr.disabled = 1;
+ e->attr.exclude_user = 1;
+ e->attr.exclude_kernel = 1;
+
+ e = &events[3];
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
+ PERF_TYPE_HARDWARE, "instructions(u)");
+ e->attr.disabled = 1;
+ e->attr.exclude_hv = 1;
+ e->attr.exclude_kernel = 1;
+
+ FAIL_IF(event_open(&events[0]));
+
+ /*
+ * The open here will fail if we don't have per event exclude support,
+ * because the second event has an incompatible set of exclude settings
+ * and we're asking for the events to be in a group.
+ */
+ for (i = 1; i < 4; i++)
+ FAIL_IF(event_open_with_group(&events[i], events[0].fd));
+
+ /*
+ * Even though the above will fail without per-event excludes we keep
+ * testing in order to be thorough.
+ */
+ prctl(PR_TASK_PERF_EVENTS_ENABLE);
+
+ /* Spin for a while */
+ for (i = 0; i < INT_MAX; i++)
+ asm volatile("" : : : "memory");
+
+ prctl(PR_TASK_PERF_EVENTS_DISABLE);
+
+ for (i = 0; i < 4; i++) {
+ FAIL_IF(event_read(&events[i]));
+ event_report(&events[i]);
+ }
+
+ /*
+ * We should see that all events have enabled == running. That
+ * shows that they were all on the PMU at once.
+ */
+ for (i = 0; i < 4; i++)
+ FAIL_IF(events[i].result.running != events[i].result.enabled);
+
+ /*
+ * We can also check that the result for instructions is >= all the
+ * other counts. That's because it is counting all instructions while
+ * the others are counting a subset.
+ */
+ for (i = 1; i < 4; i++)
+ FAIL_IF(events[0].result.value < events[i].result.value);
+
+ for (i = 0; i < 4; i++)
+ event_close(&events[i]);
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(per_event_excludes, "per_event_excludes");
+}
diff --git a/tools/testing/selftests/powerpc/primitives/Makefile b/tools/testing/selftests/powerpc/primitives/Makefile
new file mode 100644
index 0000000..ea737ca
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/Makefile
@@ -0,0 +1,17 @@
+CFLAGS += -I$(CURDIR)
+
+PROGS := load_unaligned_zeropad
+
+all: $(PROGS)
+
+$(PROGS): ../harness.c
+
+run_tests: all
+ @-for PROG in $(PROGS); do \
+ ./$$PROG; \
+ done;
+
+clean:
+ rm -f $(PROGS) *.o
+
+.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h b/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h
new file mode 120000
index 0000000..b14255e
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h
@@ -0,0 +1 @@
+../.././../../../../arch/powerpc/include/asm/asm-compat.h \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h b/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h
diff --git a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
new file mode 100644
index 0000000..d1b6475
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
@@ -0,0 +1,147 @@
+/*
+ * Userspace test harness for load_unaligned_zeropad. Creates two
+ * pages and uses mprotect to prevent access to the second page and
+ * a SEGV handler that walks the exception tables and runs the fixup
+ * routine.
+ *
+ * The results are compared against a normal load that is that is
+ * performed while access to the second page is enabled via mprotect.
+ *
+ * Copyright (C) 2014 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#define FIXUP_SECTION ".ex_fixup"
+
+#include "word-at-a-time.h"
+
+#include "utils.h"
+
+
+static int page_size;
+static char *mem_region;
+
+static int protect_region(void)
+{
+ if (mprotect(mem_region + page_size, page_size, PROT_NONE)) {
+ perror("mprotect");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int unprotect_region(void)
+{
+ if (mprotect(mem_region + page_size, page_size, PROT_READ|PROT_WRITE)) {
+ perror("mprotect");
+ return 1;
+ }
+
+ return 0;
+}
+
+extern char __start___ex_table[];
+extern char __stop___ex_table[];
+
+#if defined(__powerpc64__)
+#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP]
+#elif defined(__powerpc__)
+#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP]
+#else
+#error implement UCONTEXT_NIA
+#endif
+
+static int segv_error;
+
+static void segv_handler(int signr, siginfo_t *info, void *ptr)
+{
+ ucontext_t *uc = (ucontext_t *)ptr;
+ unsigned long addr = (unsigned long)info->si_addr;
+ unsigned long *ip = &UCONTEXT_NIA(uc);
+ unsigned long *ex_p = (unsigned long *)__start___ex_table;
+
+ while (ex_p < (unsigned long *)__stop___ex_table) {
+ unsigned long insn, fixup;
+
+ insn = *ex_p++;
+ fixup = *ex_p++;
+
+ if (insn == *ip) {
+ *ip = fixup;
+ return;
+ }
+ }
+
+ printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr);
+ segv_error++;
+}
+
+static void setup_segv_handler(void)
+{
+ struct sigaction action;
+
+ memset(&action, 0, sizeof(action));
+ action.sa_sigaction = segv_handler;
+ action.sa_flags = SA_SIGINFO;
+ sigaction(SIGSEGV, &action, NULL);
+}
+
+static int do_one_test(char *p, int page_offset)
+{
+ unsigned long should;
+ unsigned long got;
+
+ FAIL_IF(unprotect_region());
+ should = *(unsigned long *)p;
+ FAIL_IF(protect_region());
+
+ got = load_unaligned_zeropad(p);
+
+ if (should != got)
+ printf("offset %u load_unaligned_zeropad returned 0x%lx, should be 0x%lx\n", page_offset, got, should);
+
+ return 0;
+}
+
+static int test_body(void)
+{
+ unsigned long i;
+
+ page_size = getpagesize();
+ mem_region = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+
+ FAIL_IF(mem_region == MAP_FAILED);
+
+ for (i = 0; i < page_size; i++)
+ mem_region[i] = i;
+
+ memset(mem_region+page_size, 0, page_size);
+
+ setup_segv_handler();
+
+ for (i = 0; i < page_size; i++)
+ FAIL_IF(do_one_test(mem_region+i, i));
+
+ FAIL_IF(segv_error);
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(test_body, "load_unaligned_zeropad");
+}
diff --git a/tools/testing/selftests/powerpc/primitives/word-at-a-time.h b/tools/testing/selftests/powerpc/primitives/word-at-a-time.h
new file mode 120000
index 0000000..eb74401
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/word-at-a-time.h
@@ -0,0 +1 @@
+../../../../../arch/powerpc/include/asm/word-at-a-time.h \ No newline at end of file
diff --git a/tools/testing/selftests/ptrace/peeksiginfo.c b/tools/testing/selftests/ptrace/peeksiginfo.c
index d46558b..c34cd8a 100644
--- a/tools/testing/selftests/ptrace/peeksiginfo.c
+++ b/tools/testing/selftests/ptrace/peeksiginfo.c
@@ -31,6 +31,10 @@ static int sys_ptrace(int request, pid_t pid, void *addr, void *data)
#define TEST_SICODE_PRIV -1
#define TEST_SICODE_SHARE -2
+#ifndef PAGE_SIZE
+#define PAGE_SIZE sysconf(_SC_PAGESIZE)
+#endif
+
#define err(fmt, ...) \
fprintf(stderr, \
"Error (%s:%d): " fmt, \
diff --git a/tools/testing/selftests/rcutorture/bin/config2frag.sh b/tools/testing/selftests/rcutorture/bin/config2frag.sh
index 9f9ffcd..56f51ae 100644..100755
--- a/tools/testing/selftests/rcutorture/bin/config2frag.sh
+++ b/tools/testing/selftests/rcutorture/bin/config2frag.sh
@@ -1,5 +1,5 @@
-#!/bin/sh
-# Usage: sh config2frag.sh < .config > configfrag
+#!/bin/bash
+# Usage: config2frag.sh < .config > configfrag
#
# Converts the "# CONFIG_XXX is not set" to "CONFIG_XXX=n" so that the
# resulting file becomes a legitimate Kconfig fragment.
diff --git a/tools/testing/selftests/rcutorture/bin/configcheck.sh b/tools/testing/selftests/rcutorture/bin/configcheck.sh
index d686537..eee31e2 100755
--- a/tools/testing/selftests/rcutorture/bin/configcheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/configcheck.sh
@@ -1,5 +1,5 @@
-#!/bin/sh
-# Usage: sh configcheck.sh .config .config-template
+#!/bin/bash
+# Usage: configcheck.sh .config .config-template
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/configinit.sh b/tools/testing/selftests/rcutorture/bin/configinit.sh
index 9c3f3d3..15f1a17 100755
--- a/tools/testing/selftests/rcutorture/bin/configinit.sh
+++ b/tools/testing/selftests/rcutorture/bin/configinit.sh
@@ -1,6 +1,6 @@
-#!/bin/sh
+#!/bin/bash
#
-# sh configinit.sh config-spec-file [ build output dir ]
+# Usage: configinit.sh config-spec-file [ build output dir ]
#
# Create a .config file from the spec file. Run from the kernel source tree.
# Exits with 0 if all went well, with 1 if all went well but the config
diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh
index d01b865..b325470 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -64,6 +64,26 @@ configfrag_boot_params () {
fi
}
+# configfrag_boot_cpus bootparam-string config-fragment-file config-cpus
+#
+# Decreases number of CPUs based on any maxcpus= boot parameters specified.
+configfrag_boot_cpus () {
+ local bootargs="`configfrag_boot_params "$1" "$2"`"
+ local maxcpus
+ if echo "${bootargs}" | grep -q 'maxcpus=[0-9]'
+ then
+ maxcpus="`echo "${bootargs}" | sed -e 's/^.*maxcpus=\([0-9]*\).*$/\1/'`"
+ if test "$3" -gt "$maxcpus"
+ then
+ echo $maxcpus
+ else
+ echo $3
+ fi
+ else
+ echo $3
+ fi
+}
+
# configfrag_hotplug_cpu config-fragment-file
#
# Returns 1 if the config fragment specifies hotplug CPU.
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-build.sh b/tools/testing/selftests/rcutorture/bin/kvm-build.sh
index 7c1e56b..00cb0db 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-build.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-build.sh
@@ -2,7 +2,7 @@
#
# Build a kvm-ready Linux kernel from the tree in the current directory.
#
-# Usage: sh kvm-build.sh config-template build-dir more-configs
+# Usage: kvm-build.sh config-template build-dir more-configs
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
index 7f1ff1a..43f7640 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
@@ -2,7 +2,7 @@
#
# Analyze a given results directory for locktorture progress.
#
-# Usage: sh kvm-recheck-lock.sh resdir
+# Usage: kvm-recheck-lock.sh resdir
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
index 307c4b9..d6cc07f 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
@@ -2,7 +2,7 @@
#
# Analyze a given results directory for rcutorture progress.
#
-# Usage: sh kvm-recheck-rcu.sh resdir
+# Usage: kvm-recheck-rcu.sh resdir
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
index 3f6c9b7..4f5b20f 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
@@ -4,7 +4,7 @@
# check the build and console output for errors. Given a directory
# containing results directories, this recursively checks them all.
#
-# Usage: sh kvm-recheck.sh resdir ...
+# Usage: kvm-recheck.sh resdir ...
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index 0f69dcb..f6b2b47 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -6,7 +6,7 @@
# Execute this in the source tree. Do not run it as a background task
# because qemu does not seem to like that much.
#
-# Usage: sh kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args
+# Usage: kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args
#
# qemu-args defaults to "-nographic", along with arguments specifying the
# number of CPUs and other options generated from
@@ -140,6 +140,7 @@ fi
# Generate -smp qemu argument.
qemu_args="-nographic $qemu_args"
cpu_count=`configNR_CPUS.sh $config_template`
+cpu_count=`configfrag_boot_cpus "$boot_args" "$config_template" "$cpu_count"`
vcpus=`identify_qemu_vcpus`
if test $cpu_count -gt $vcpus
then
@@ -214,7 +215,7 @@ then
fi
if test $kruntime -ge $((seconds + grace))
then
- echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
+ echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
kill -KILL $qemu_pid
break
fi
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index 589e9c3..e527dc9 100644..100755
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -7,7 +7,7 @@
# Edit the definitions below to set the locations of the various directories,
# as well as the test duration.
#
-# Usage: sh kvm.sh [ options ]
+# Usage: kvm.sh [ options ]
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -188,7 +188,9 @@ for CF in $configs
do
if test -f "$CONFIGFRAG/$kversion/$CF"
then
- echo $CF `configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF` >> $T/cfgcpu
+ cpu_count=`configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF`
+ cpu_count=`configfrag_boot_cpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$kversion/$CF" "$cpu_count"`
+ echo $CF $cpu_count >> $T/cfgcpu
else
echo "The --configs file $CF does not exist, terminating."
exit 1
diff --git a/tools/testing/selftests/rcutorture/bin/parse-build.sh b/tools/testing/selftests/rcutorture/bin/parse-build.sh
index 5432309..499d1e5 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-build.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-build.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Check the build output from an rcutorture run for goodness.
# The "file" is a pathname on the local system, and "title" is
@@ -6,8 +6,7 @@
#
# The file must contain kernel build output.
#
-# Usage:
-# sh parse-build.sh file title
+# Usage: parse-build.sh file title
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/parse-console.sh b/tools/testing/selftests/rcutorture/bin/parse-console.sh
index 4185d4c..f962ba4 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-console.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-console.sh
@@ -1,11 +1,10 @@
-#!/bin/sh
+#!/bin/bash
#
# Check the console output from an rcutorture run for oopses.
# The "file" is a pathname on the local system, and "title" is
# a text string for error-message purposes.
#
-# Usage:
-# sh parse-console.sh file title
+# Usage: parse-console.sh file title
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -33,6 +32,10 @@ title="$2"
. functions.sh
+if grep -Pq '\x00' < $file
+then
+ print_warning Console output contains nul bytes, old qemu still running?
+fi
egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T
if test -s $T
then
diff --git a/tools/testing/selftests/rcutorture/bin/parse-torture.sh b/tools/testing/selftests/rcutorture/bin/parse-torture.sh
index 3455560..e3c5f07 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-torture.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-torture.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Check the console output from a torture run for goodness.
# The "file" is a pathname on the local system, and "title" is
@@ -7,8 +7,7 @@
# The file must contain torture output, but can be interspersed
# with other dmesg text, as in console-log output.
#
-# Usage:
-# sh parse-torture.sh file title
+# Usage: parse-torture.sh file title
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFLIST b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
index a061b22..6910b73 100644
--- a/tools/testing/selftests/rcutorture/configs/lock/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
@@ -1 +1,4 @@
LOCK01
+LOCK02
+LOCK03
+LOCK04 \ No newline at end of file
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK02 b/tools/testing/selftests/rcutorture/configs/lock/LOCK02
new file mode 100644
index 0000000..1d1da14
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK02
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot
new file mode 100644
index 0000000..5aa44b4
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot
@@ -0,0 +1 @@
+locktorture.torture_type=mutex_lock
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK03 b/tools/testing/selftests/rcutorture/configs/lock/LOCK03
new file mode 100644
index 0000000..1d1da14
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK03
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot
new file mode 100644
index 0000000..a67bbe0
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot
@@ -0,0 +1 @@
+locktorture.torture_type=rwsem_lock
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK04 b/tools/testing/selftests/rcutorture/configs/lock/LOCK04
new file mode 100644
index 0000000..1d1da14
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK04
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot
new file mode 100644
index 0000000..48c04fe
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot
@@ -0,0 +1 @@
+locktorture.torture_type=rw_lock
diff --git a/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
index 9746ea1..252aae6 100644
--- a/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
+++ b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
@@ -38,6 +38,6 @@ per_version_boot_params () {
echo $1 `locktorture_param_onoff "$1" "$2"` \
locktorture.stat_interval=15 \
locktorture.shutdown_secs=$3 \
- locktorture.locktorture_runnable=1 \
+ locktorture.torture_runnable=1 \
locktorture.verbose=1
}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
index cd3d29c..a3a1a05 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
@@ -11,3 +11,6 @@ SRCU-N
SRCU-P
TINY01
TINY02
+TASKS01
+TASKS02
+TASKS03
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS01 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01
new file mode 100644
index 0000000..97f0a0b
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01
@@ -0,0 +1,9 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_RCU=y
+CONFIG_TASKS_RCU=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot
new file mode 100644
index 0000000..cd2a188
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot
@@ -0,0 +1 @@
+rcutorture.torture_type=tasks
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS02 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02
new file mode 100644
index 0000000..696d2ea
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02
@@ -0,0 +1,5 @@
+CONFIG_SMP=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_TASKS_RCU=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot
new file mode 100644
index 0000000..cd2a188
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot
@@ -0,0 +1 @@
+rcutorture.torture_type=tasks
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03
new file mode 100644
index 0000000..9c60da5
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03
@@ -0,0 +1,13 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_TASKS_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=y
+CONFIG_NO_HZ_FULL_ALL=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot
new file mode 100644
index 0000000..cd2a188
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot
@@ -0,0 +1 @@
+rcutorture.torture_type=tasks
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
index 063b707..38e3895 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
@@ -1,5 +1,4 @@
CONFIG_SMP=y
-CONFIG_NR_CPUS=8
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
@@ -10,8 +9,7 @@ CONFIG_NO_HZ_FULL=n
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_RCU_TRACE=y
CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_FANOUT=8
-CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_MAXSMP=y
CONFIG_RCU_NOCB_CPU=y
CONFIG_RCU_NOCB_CPU_ZERO=y
CONFIG_DEBUG_LOCK_ALLOC=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
index 0fc8a34..adc3abc 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
@@ -1 +1 @@
-rcutorture.torture_type=rcu_bh
+rcutorture.torture_type=rcu_bh maxcpus=8
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
index ab62255..8f10176 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
@@ -1,5 +1,6 @@
CONFIG_SMP=y
CONFIG_NR_CPUS=16
+CONFIG_CPUMASK_OFFSTACK=y
CONFIG_PREEMPT_NONE=y
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
@@ -7,7 +8,7 @@ CONFIG_PREEMPT=n
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=n
CONFIG_NO_HZ_FULL=y
-CONFIG_NO_HZ_FULL_ALL=y
+CONFIG_NO_HZ_FULL_ALL=n
CONFIG_NO_HZ_FULL_SYSIDLE=y
CONFIG_RCU_FAST_NO_HZ=n
CONFIG_RCU_TRACE=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot
new file mode 100644
index 0000000..d446099
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot
@@ -0,0 +1 @@
+nohz_full=2-9
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
index 8977d8d..ffb85ed 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
@@ -51,7 +51,7 @@ per_version_boot_params () {
`rcutorture_param_n_barrier_cbs "$1"` \
rcutorture.stat_interval=15 \
rcutorture.shutdown_secs=$3 \
- rcutorture.rcutorture_runnable=1 \
+ rcutorture.torture_runnable=1 \
rcutorture.test_no_idle_hz=1 \
rcutorture.verbose=1
}
diff --git a/tools/testing/selftests/rcutorture/doc/initrd.txt b/tools/testing/selftests/rcutorture/doc/initrd.txt
index 49d134c..4170e71 100644
--- a/tools/testing/selftests/rcutorture/doc/initrd.txt
+++ b/tools/testing/selftests/rcutorture/doc/initrd.txt
@@ -6,6 +6,7 @@ this case. There are probably much better ways of doing this.
That said, here are the commands:
------------------------------------------------------------------------
+cd tools/testing/selftests/rcutorture
zcat /initrd.img > /tmp/initrd.img.zcat
mkdir initrd
cd initrd
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index 3f94e1a..4c4b1f6 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -3,6 +3,7 @@
CC = $(CROSS_COMPILE)gcc
CFLAGS = -Wall
BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest
+BINARIES += transhuge-stress
all: $(BINARIES)
%: %.c
diff --git a/tools/testing/selftests/vm/transhuge-stress.c b/tools/testing/selftests/vm/transhuge-stress.c
new file mode 100644
index 0000000..fd7f1b4
--- /dev/null
+++ b/tools/testing/selftests/vm/transhuge-stress.c
@@ -0,0 +1,144 @@
+/*
+ * Stress test for transparent huge pages, memory compaction and migration.
+ *
+ * Authors: Konstantin Khlebnikov <koct9i@gmail.com>
+ *
+ * This is free and unencumbered software released into the public domain.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <err.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#define PAGE_SHIFT 12
+#define HPAGE_SHIFT 21
+
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define HPAGE_SIZE (1 << HPAGE_SHIFT)
+
+#define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0)
+#define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1))
+
+int pagemap_fd;
+
+int64_t allocate_transhuge(void *ptr)
+{
+ uint64_t ent[2];
+
+ /* drop pmd */
+ if (mmap(ptr, HPAGE_SIZE, PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_ANONYMOUS |
+ MAP_NORESERVE | MAP_PRIVATE, -1, 0) != ptr)
+ errx(2, "mmap transhuge");
+
+ if (madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE))
+ err(2, "MADV_HUGEPAGE");
+
+ /* allocate transparent huge page */
+ *(volatile void **)ptr = ptr;
+
+ if (pread(pagemap_fd, ent, sizeof(ent),
+ (uintptr_t)ptr >> (PAGE_SHIFT - 3)) != sizeof(ent))
+ err(2, "read pagemap");
+
+ if (PAGEMAP_PRESENT(ent[0]) && PAGEMAP_PRESENT(ent[1]) &&
+ PAGEMAP_PFN(ent[0]) + 1 == PAGEMAP_PFN(ent[1]) &&
+ !(PAGEMAP_PFN(ent[0]) & ((1 << (HPAGE_SHIFT - PAGE_SHIFT)) - 1)))
+ return PAGEMAP_PFN(ent[0]);
+
+ return -1;
+}
+
+int main(int argc, char **argv)
+{
+ size_t ram, len;
+ void *ptr, *p;
+ struct timespec a, b;
+ double s;
+ uint8_t *map;
+ size_t map_len;
+
+ ram = sysconf(_SC_PHYS_PAGES);
+ if (ram > SIZE_MAX / sysconf(_SC_PAGESIZE) / 4)
+ ram = SIZE_MAX / 4;
+ else
+ ram *= sysconf(_SC_PAGESIZE);
+
+ if (argc == 1)
+ len = ram;
+ else if (!strcmp(argv[1], "-h"))
+ errx(1, "usage: %s [size in MiB]", argv[0]);
+ else
+ len = atoll(argv[1]) << 20;
+
+ warnx("allocate %zd transhuge pages, using %zd MiB virtual memory"
+ " and %zd MiB of ram", len >> HPAGE_SHIFT, len >> 20,
+ len >> (20 + HPAGE_SHIFT - PAGE_SHIFT - 1));
+
+ pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
+ if (pagemap_fd < 0)
+ err(2, "open pagemap");
+
+ len -= len % HPAGE_SIZE;
+ ptr = mmap(NULL, len + HPAGE_SIZE, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
+ if (ptr == MAP_FAILED)
+ err(2, "initial mmap");
+ ptr += HPAGE_SIZE - (uintptr_t)ptr % HPAGE_SIZE;
+
+ if (madvise(ptr, len, MADV_HUGEPAGE))
+ err(2, "MADV_HUGEPAGE");
+
+ map_len = ram >> (HPAGE_SHIFT - 1);
+ map = malloc(map_len);
+ if (!map)
+ errx(2, "map malloc");
+
+ while (1) {
+ int nr_succeed = 0, nr_failed = 0, nr_pages = 0;
+
+ memset(map, 0, map_len);
+
+ clock_gettime(CLOCK_MONOTONIC, &a);
+ for (p = ptr; p < ptr + len; p += HPAGE_SIZE) {
+ int64_t pfn;
+
+ pfn = allocate_transhuge(p);
+
+ if (pfn < 0) {
+ nr_failed++;
+ } else {
+ size_t idx = pfn >> (HPAGE_SHIFT - PAGE_SHIFT);
+
+ nr_succeed++;
+ if (idx >= map_len) {
+ map = realloc(map, idx + 1);
+ if (!map)
+ errx(2, "map realloc");
+ memset(map + map_len, 0, idx + 1 - map_len);
+ map_len = idx + 1;
+ }
+ if (!map[idx])
+ nr_pages++;
+ map[idx] = 1;
+ }
+
+ /* split transhuge page, keep last page */
+ if (madvise(p, HPAGE_SIZE - PAGE_SIZE, MADV_DONTNEED))
+ err(2, "MADV_DONTNEED");
+ }
+ clock_gettime(CLOCK_MONOTONIC, &b);
+ s = b.tv_sec - a.tv_sec + (b.tv_nsec - a.tv_nsec) / 1000000000.;
+
+ warnx("%.3f s/loop, %.3f ms/page, %10.3f MiB/s\t"
+ "%4d succeed, %4d failed, %4d different pages",
+ s, s * 1000 / (len >> HPAGE_SHIFT), len / s / (1 << 20),
+ nr_succeed, nr_failed, nr_pages);
+ }
+}
diff --git a/tools/time/udelay_test.sh b/tools/time/udelay_test.sh
new file mode 100755
index 0000000..12d46b9
--- /dev/null
+++ b/tools/time/udelay_test.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# udelay() test script
+#
+# Test is executed by writing and reading to /sys/kernel/debug/udelay_test
+# and exercises a variety of delays to ensure that udelay() is delaying
+# at least as long as requested (as compared to ktime).
+#
+# Copyright (C) 2014 Google, Inc.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+MODULE_NAME=udelay_test
+UDELAY_PATH=/sys/kernel/debug/udelay_test
+
+setup()
+{
+ /sbin/modprobe -q $MODULE_NAME
+ tmp_file=`mktemp`
+}
+
+test_one()
+{
+ delay=$1
+ echo $delay > $UDELAY_PATH
+ tee -a $tmp_file < $UDELAY_PATH
+}
+
+cleanup()
+{
+ if [ -f $tmp_file ]; then
+ rm $tmp_file
+ fi
+ /sbin/modprobe -q -r $MODULE_NAME
+}
+
+trap cleanup EXIT
+setup
+
+# Delay for a variety of times.
+# 1..200, 200..500 (by 10), 500..2000 (by 100)
+for (( delay = 1; delay < 200; delay += 1 )); do
+ test_one $delay
+done
+for (( delay = 200; delay < 500; delay += 10 )); do
+ test_one $delay
+done
+for (( delay = 500; delay <= 2000; delay += 100 )); do
+ test_one $delay
+done
+
+# Search for failures
+count=`grep -c FAIL $tmp_file`
+if [ $? -eq "0" ]; then
+ echo "ERROR: $count delays failed to delay long enough"
+ retcode=1
+fi
+
+exit $retcode
diff --git a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
index 87216a0..af4b050 100644
--- a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
+++ b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
@@ -1,3 +1,30 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org/>
+ */
+
#define _BSD_SOURCE /* for endian.h */
#include <endian.h>
@@ -27,7 +54,9 @@
/******************** Descriptors and Strings *******************************/
static const struct {
- struct usb_functionfs_descs_head header;
+ struct usb_functionfs_descs_head_v2 header;
+ __le32 fs_count;
+ __le32 hs_count;
struct {
struct usb_interface_descriptor intf;
struct usb_endpoint_descriptor_no_audio bulk_sink;
@@ -35,11 +64,12 @@ static const struct {
} __attribute__ ((__packed__)) fs_descs, hs_descs;
} __attribute__ ((__packed__)) descriptors = {
.header = {
- .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
+ FUNCTIONFS_HAS_HS_DESC),
.length = htole32(sizeof(descriptors)),
- .fs_count = 3,
- .hs_count = 3,
},
+ .fs_count = htole32(3),
.fs_descs = {
.intf = {
.bLength = sizeof(descriptors.fs_descs.intf),
@@ -61,6 +91,7 @@ static const struct {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
},
},
+ .hs_count = htole32(3),
.hs_descs = {
.intf = {
.bLength = sizeof(descriptors.hs_descs.intf),
diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/test.c b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
index b0ad874..daa3abe 100644
--- a/tools/usb/ffs-aio-example/multibuff/host_app/test.c
+++ b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
@@ -1,3 +1,30 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org/>
+ */
+
#include <libusb.h>
#include <stdio.h>
#include <string.h>
diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
index f558664..adc310a 100644
--- a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
+++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
@@ -1,3 +1,30 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org/>
+ */
+
#define _BSD_SOURCE /* for endian.h */
#include <endian.h>
@@ -25,7 +52,9 @@
/******************** Descriptors and Strings *******************************/
static const struct {
- struct usb_functionfs_descs_head header;
+ struct usb_functionfs_descs_head_v2 header;
+ __le32 fs_count;
+ __le32 hs_count;
struct {
struct usb_interface_descriptor intf;
struct usb_endpoint_descriptor_no_audio bulk_sink;
@@ -33,11 +62,12 @@ static const struct {
} __attribute__ ((__packed__)) fs_descs, hs_descs;
} __attribute__ ((__packed__)) descriptors = {
.header = {
- .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
+ FUNCTIONFS_HAS_HS_DESC),
.length = htole32(sizeof(descriptors)),
- .fs_count = 3,
- .hs_count = 3,
},
+ .fs_count = htole32(3),
.fs_descs = {
.intf = {
.bLength = sizeof(descriptors.fs_descs.intf),
@@ -59,6 +89,7 @@ static const struct {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
},
},
+ .hs_count = htole32(3),
.hs_descs = {
.intf = {
.bLength = sizeof(descriptors.hs_descs.intf),
diff --git a/tools/usb/ffs-aio-example/simple/host_app/test.c b/tools/usb/ffs-aio-example/simple/host_app/test.c
index 64b6a57..acd6332 100644
--- a/tools/usb/ffs-aio-example/simple/host_app/test.c
+++ b/tools/usb/ffs-aio-example/simple/host_app/test.c
@@ -1,3 +1,30 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org/>
+ */
+
#include <libusb.h>
#include <stdio.h>
#include <string.h>
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index a87e99f..88d5e71 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -1,5 +1,5 @@
/*
- * ffs-test.c.c -- user mode filesystem api for usb composite function
+ * ffs-test.c -- user mode filesystem api for usb composite function
*
* Copyright (C) 2010 Samsung Electronics
* Author: Michal Nazarewicz <mina86@mina86.com>
@@ -29,6 +29,7 @@
#include <fcntl.h>
#include <pthread.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -106,7 +107,9 @@ static void _msg(unsigned level, const char *fmt, ...)
/******************** Descriptors and Strings *******************************/
static const struct {
- struct usb_functionfs_descs_head header;
+ struct usb_functionfs_descs_head_v2 header;
+ __le32 fs_count;
+ __le32 hs_count;
struct {
struct usb_interface_descriptor intf;
struct usb_endpoint_descriptor_no_audio sink;
@@ -114,11 +117,12 @@ static const struct {
} __attribute__((packed)) fs_descs, hs_descs;
} __attribute__((packed)) descriptors = {
.header = {
- .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC |
+ FUNCTIONFS_HAS_HS_DESC),
.length = cpu_to_le32(sizeof descriptors),
- .fs_count = cpu_to_le32(3),
- .hs_count = cpu_to_le32(3),
},
+ .fs_count = cpu_to_le32(3),
.fs_descs = {
.intf = {
.bLength = sizeof descriptors.fs_descs.intf,
@@ -142,6 +146,7 @@ static const struct {
/* .wMaxPacketSize = autoconfiguration (kernel) */
},
},
+ .hs_count = cpu_to_le32(3),
.hs_descs = {
.intf = {
.bLength = sizeof descriptors.fs_descs.intf,
@@ -168,6 +173,89 @@ static const struct {
},
};
+static size_t descs_to_legacy(void **legacy, const void *descriptors_v2)
+{
+ const unsigned char *descs_end, *descs_start;
+ __u32 length, fs_count = 0, hs_count = 0, count;
+
+ /* Read v2 header */
+ {
+ const struct {
+ const struct usb_functionfs_descs_head_v2 header;
+ const __le32 counts[];
+ } __attribute__((packed)) *const in = descriptors_v2;
+ const __le32 *counts = in->counts;
+ __u32 flags;
+
+ if (le32_to_cpu(in->header.magic) !=
+ FUNCTIONFS_DESCRIPTORS_MAGIC_V2)
+ return 0;
+ length = le32_to_cpu(in->header.length);
+ if (length <= sizeof in->header)
+ return 0;
+ length -= sizeof in->header;
+ flags = le32_to_cpu(in->header.flags);
+ if (flags & ~(FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC))
+ return 0;
+
+#define GET_NEXT_COUNT_IF_FLAG(ret, flg) do { \
+ if (!(flags & (flg))) \
+ break; \
+ if (length < 4) \
+ return 0; \
+ ret = le32_to_cpu(*counts); \
+ length -= 4; \
+ ++counts; \
+ } while (0)
+
+ GET_NEXT_COUNT_IF_FLAG(fs_count, FUNCTIONFS_HAS_FS_DESC);
+ GET_NEXT_COUNT_IF_FLAG(hs_count, FUNCTIONFS_HAS_HS_DESC);
+ GET_NEXT_COUNT_IF_FLAG(count, FUNCTIONFS_HAS_SS_DESC);
+
+ count = fs_count + hs_count;
+ if (!count)
+ return 0;
+ descs_start = (const void *)counts;
+
+#undef GET_NEXT_COUNT_IF_FLAG
+ }
+
+ /*
+ * Find the end of FS and HS USB descriptors. SS descriptors
+ * are ignored since legacy format does not support them.
+ */
+ descs_end = descs_start;
+ do {
+ if (length < *descs_end)
+ return 0;
+ length -= *descs_end;
+ descs_end += *descs_end;
+ } while (--count);
+
+ /* Allocate legacy descriptors and copy the data. */
+ {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+ struct {
+ struct usb_functionfs_descs_head header;
+ __u8 descriptors[];
+ } __attribute__((packed)) *out;
+#pragma GCC diagnostic pop
+
+ length = sizeof out->header + (descs_end - descs_start);
+ out = malloc(length);
+ out->header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
+ out->header.length = cpu_to_le32(length);
+ out->header.fs_count = cpu_to_le32(fs_count);
+ out->header.hs_count = cpu_to_le32(hs_count);
+ memcpy(out->descriptors, descs_start, descs_end - descs_start);
+ *legacy = out;
+ }
+
+ return length;
+}
+
#define STR_INTERFACE_ "Source/Sink"
@@ -487,12 +575,29 @@ ep0_consume(struct thread *ignore, const void *buf, size_t nbytes)
return nbytes;
}
-static void ep0_init(struct thread *t)
+static void ep0_init(struct thread *t, bool legacy_descriptors)
{
+ void *legacy;
ssize_t ret;
+ size_t len;
+
+ if (legacy_descriptors) {
+ info("%s: writing descriptors\n", t->filename);
+ goto legacy;
+ }
- info("%s: writing descriptors\n", t->filename);
+ info("%s: writing descriptors (in v2 format)\n", t->filename);
ret = write(t->fd, &descriptors, sizeof descriptors);
+
+ if (ret < 0 && errno == EINVAL) {
+ warn("%s: new format rejected, trying legacy\n", t->filename);
+legacy:
+ len = descs_to_legacy(&legacy, &descriptors);
+ if (len) {
+ ret = write(t->fd, legacy, len);
+ free(legacy);
+ }
+ }
die_on(ret < 0, "%s: write: descriptors", t->filename);
info("%s: writing strings\n", t->filename);
@@ -503,14 +608,15 @@ static void ep0_init(struct thread *t)
/******************** Main **************************************************/
-int main(void)
+int main(int argc, char **argv)
{
+ bool legacy_descriptors;
unsigned i;
- /* XXX TODO: Argument parsing missing */
+ legacy_descriptors = argc > 2 && !strcmp(argv[1], "-l");
init_thread(threads);
- ep0_init(threads);
+ ep0_init(threads, legacy_descriptors);
for (i = 1; i < sizeof threads / sizeof *threads; ++i)
init_thread(threads + i);
diff --git a/tools/usb/usbip/.gitignore b/tools/usb/usbip/.gitignore
new file mode 100644
index 0000000..9aad9e3
--- /dev/null
+++ b/tools/usb/usbip/.gitignore
@@ -0,0 +1,28 @@
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache/
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+install-sh
+libsrc/Makefile
+libsrc/Makefile.in
+libtool
+ltmain.sh
+missing
+src/Makefile
+src/Makefile.in
+stamp-h1
+libsrc/libusbip.la
+libsrc/libusbip_la-names.lo
+libsrc/libusbip_la-usbip_common.lo
+libsrc/libusbip_la-usbip_host_driver.lo
+libsrc/libusbip_la-vhci_driver.lo
+src/usbip
+src/usbipd
diff --git a/tools/usb/usbip/AUTHORS b/tools/usb/usbip/AUTHORS
new file mode 100644
index 0000000..a27ea8d
--- /dev/null
+++ b/tools/usb/usbip/AUTHORS
@@ -0,0 +1,3 @@
+Takahiro Hirofuchi
+Robert Leibl
+matt mooney <mfm@muteddisk.com>
diff --git a/tools/usb/usbip/COPYING b/tools/usb/usbip/COPYING
new file mode 100644
index 0000000..c5611e4
--- /dev/null
+++ b/tools/usb/usbip/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/tools/usb/usbip/INSTALL b/tools/usb/usbip/INSTALL
new file mode 100644
index 0000000..d3c5b40
--- /dev/null
+++ b/tools/usb/usbip/INSTALL
@@ -0,0 +1,237 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007 Free Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 6. Often, you can also type `make uninstall' to remove the installed
+ files again.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about. Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/tools/usb/usbip/Makefile.am b/tools/usb/usbip/Makefile.am
new file mode 100644
index 0000000..66f8bf0
--- /dev/null
+++ b/tools/usb/usbip/Makefile.am
@@ -0,0 +1,6 @@
+SUBDIRS := libsrc src
+includedir = @includedir@/usbip
+include_HEADERS := $(addprefix libsrc/, \
+ usbip_common.h vhci_driver.h usbip_host_driver.h)
+
+dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8)
diff --git a/tools/usb/usbip/README b/tools/usb/usbip/README
new file mode 100644
index 0000000..831f49f
--- /dev/null
+++ b/tools/usb/usbip/README
@@ -0,0 +1,202 @@
+#
+# README for usbip-utils
+#
+# Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+# 2005-2008 Takahiro Hirofuchi
+
+
+[Requirements]
+ - USB/IP device drivers
+ Found in the staging directory of the Linux kernel.
+
+ - libudev >= 2.0
+ libudev library
+
+ - libwrap0-dev
+ tcp wrapper library
+
+ - gcc >= 4.0
+
+ - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config
+
+[Optional]
+ - hwdata
+ Contains USB device identification data.
+
+
+[Install]
+ 0. Generate configuration scripts.
+ $ ./autogen.sh
+
+ 1. Compile & install the userspace utilities.
+ $ ./configure [--with-tcp-wrappers=no] [--with-usbids-dir=<dir>]
+ $ make install
+
+ 2. Compile & install USB/IP drivers.
+
+
+[Usage]
+ server:# (Physically attach your USB device.)
+
+ server:# insmod usbip-core.ko
+ server:# insmod usbip-host.ko
+
+ server:# usbipd -D
+ - Start usbip daemon.
+
+ server:# usbip list -l
+ - List driver assignments for USB devices.
+
+ server:# usbip bind --busid 1-2
+ - Bind usbip-host.ko to the device with busid 1-2.
+ - The USB device 1-2 is now exportable to other hosts!
+ - Use `usbip unbind --busid 1-2' to stop exporting the device.
+
+ client:# insmod usbip-core.ko
+ client:# insmod vhci-hcd.ko
+
+ client:# usbip list --remote <host>
+ - List exported USB devices on the <host>.
+
+ client:# usbip attach --remote <host> --busid 1-2
+ - Connect the remote USB device.
+
+ client:# usbip port
+ - Show virtual port status.
+
+ client:# usbip detach --port <port>
+ - Detach the USB device.
+
+
+[Example]
+---------------------------
+ SERVER SIDE
+---------------------------
+Physically attach your USB devices to this host.
+
+ trois:# insmod path/to/usbip-core.ko
+ trois:# insmod path/to/usbip-host.ko
+ trois:# usbipd -D
+
+In another terminal, let's look up what USB devices are physically
+attached to this host.
+
+ trois:# usbip list -l
+ Local USB devices
+ =================
+ - busid 1-1 (05a9:a511)
+ 1-1:1.0 -> ov511
+
+ - busid 3-2 (0711:0902)
+ 3-2:1.0 -> none
+
+ - busid 3-3.1 (08bb:2702)
+ 3-3.1:1.0 -> snd-usb-audio
+ 3-3.1:1.1 -> snd-usb-audio
+
+ - busid 3-3.2 (04bb:0206)
+ 3-3.2:1.0 -> usb-storage
+
+ - busid 3-3 (0409:0058)
+ 3-3:1.0 -> hub
+
+ - busid 4-1 (046d:08b2)
+ 4-1:1.0 -> none
+ 4-1:1.1 -> none
+ 4-1:1.2 -> none
+
+ - busid 5-2 (058f:9254)
+ 5-2:1.0 -> hub
+
+A USB storage device of busid 3-3.2 is now bound to the usb-storage
+driver. To export this device, we first mark the device as
+"exportable"; the device is bound to the usbip-host driver. Please
+remember you can not export a USB hub.
+
+Mark the device of busid 3-3.2 as exportable:
+
+ trois:# usbip --debug bind --busid 3-3.2
+ ...
+ usbip debug: usbip_bind.c:162:[unbind_other] 3-3.2:1.0 -> usb-storage
+ ...
+ bind device on busid 3-3.2: complete
+
+ trois:# usbip list -l
+ Local USB devices
+ =================
+ ...
+
+ - busid 3-3.2 (04bb:0206)
+ 3-3.2:1.0 -> usbip-host
+ ...
+
+---------------------------
+ CLIENT SIDE
+---------------------------
+First, let's list available remote devices that are marked as
+exportable on the host.
+
+ deux:# insmod path/to/usbip-core.ko
+ deux:# insmod path/to/vhci-hcd.ko
+
+ deux:# usbip list --remote 10.0.0.3
+ Exportable USB devices
+ ======================
+ - 10.0.0.3
+ 1-1: Prolific Technology, Inc. : unknown product (067b:3507)
+ : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-1
+ : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
+ : 0 - Mass Storage / SCSI / Bulk (Zip) (08/06/50)
+
+ 1-2.2.1: Apple Computer, Inc. : unknown product (05ac:0203)
+ : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.1
+ : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
+ : 0 - Human Interface Devices / Boot Interface Subclass / Keyboard (03/01/01)
+
+ 1-2.2.3: OmniVision Technologies, Inc. : OV511+ WebCam (05a9:a511)
+ : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.3
+ : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
+ : 0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00)
+
+ 3-1: Logitech, Inc. : QuickCam Pro 4000 (046d:08b2)
+ : /sys/devices/pci0000:00/0000:00:1e.0/0000:02:0a.0/usb3/3-1
+ : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
+ : 0 - Data / unknown subclass / unknown protocol (0a/ff/00)
+ : 1 - Audio / Control Device / unknown protocol (01/01/00)
+ : 2 - Audio / Streaming / unknown protocol (01/02/00)
+
+Attach a remote USB device:
+
+ deux:# usbip attach --remote 10.0.0.3 --busid 1-1
+ port 0 attached
+
+Show the devices attached to this client:
+
+ deux:# usbip port
+ Port 00: <Port in Use> at Full Speed(12Mbps)
+ Prolific Technology, Inc. : unknown product (067b:3507)
+ 6-1 -> usbip://10.0.0.3:3240/1-1 (remote bus/dev 001/004)
+ 6-1:1.0 used by usb-storage
+ /sys/class/scsi_device/0:0:0:0/device
+ /sys/class/scsi_host/host0/device
+ /sys/block/sda/device
+
+Detach the imported device:
+
+ deux:# usbip detach --port 0
+ port 0 detached
+
+
+[Checklist]
+ - See 'Debug Tips' on the project wiki.
+ - http://usbip.wiki.sourceforge.net/how-to-debug-usbip
+ - usbip-host.ko must be bound to the target device.
+ - See /proc/bus/usb/devices and find "Driver=..." lines of the device.
+ - Shutdown firewall.
+ - usbip now uses TCP port 3240.
+ - Disable SELinux.
+ - Check the kernel and daemon messages.
+
+
+[Contact]
+ Mailing List: linux-usb@vger.kernel.org
diff --git a/tools/usb/usbip/autogen.sh b/tools/usb/usbip/autogen.sh
new file mode 100755
index 0000000..e1112d3
--- /dev/null
+++ b/tools/usb/usbip/autogen.sh
@@ -0,0 +1,9 @@
+#!/bin/sh -x
+
+#aclocal
+#autoheader
+#libtoolize --copy --force
+#automake-1.9 -acf
+#autoconf
+
+autoreconf -i -f -v
diff --git a/tools/usb/usbip/cleanup.sh b/tools/usb/usbip/cleanup.sh
new file mode 100755
index 0000000..955c3cc
--- /dev/null
+++ b/tools/usb/usbip/cleanup.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ -r Makefile ]; then
+ make distclean
+fi
+
+FILES="aclocal.m4 autom4te.cache compile config.guess config.h.in config.log \
+ config.status config.sub configure cscope.out depcomp install-sh \
+ libsrc/Makefile libsrc/Makefile.in libtool ltmain.sh Makefile \
+ Makefile.in missing src/Makefile src/Makefile.in"
+
+rm -vRf $FILES
diff --git a/tools/usb/usbip/configure.ac b/tools/usb/usbip/configure.ac
new file mode 100644
index 0000000..607d05c
--- /dev/null
+++ b/tools/usb/usbip/configure.ac
@@ -0,0 +1,111 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org])
+AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number])
+
+CURRENT=0
+REVISION=1
+AGE=0
+AC_SUBST([LIBUSBIP_VERSION], [$CURRENT:$REVISION:$AGE], [library version])
+
+AC_CONFIG_SRCDIR([src/usbipd.c])
+AC_CONFIG_HEADERS([config.h])
+
+AM_INIT_AUTOMAKE([foreign])
+LT_INIT
+
+# Silent build for automake >= 1.11
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_SUBST([EXTRA_CFLAGS], ["-Wall -Werror -Wextra -std=gnu99"])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+# Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h dnl
+ string.h sys/socket.h syslog.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_INT32_T
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT8_T
+
+# Checks for library functions.
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([memset mkdir regcomp socket strchr strerror strstr dnl
+ strtoul])
+
+AC_CHECK_HEADER([libudev.h],
+ [AC_CHECK_LIB([udev], [udev_new],
+ [LIBS="$LIBS -ludev"],
+ [AC_MSG_ERROR([Missing udev library!])])],
+ [AC_MSG_ERROR([Missing /usr/include/libudev.h])])
+
+# Checks for libwrap library.
+AC_MSG_CHECKING([whether to use the libwrap (TCP wrappers) library])
+AC_ARG_WITH([tcp-wrappers],
+ [AS_HELP_STRING([--with-tcp-wrappers],
+ [use the libwrap (TCP wrappers) library])],
+ dnl [ACTION-IF-GIVEN]
+ [if test "$withval" = "yes"; then
+ AC_MSG_RESULT([yes])
+ AC_MSG_CHECKING([for hosts_access in -lwrap])
+ saved_LIBS="$LIBS"
+ LIBS="-lwrap $saved_LIBS"
+ AC_TRY_LINK(
+ [int hosts_access(); int allow_severity, deny_severity;],
+ [hosts_access()],
+ [AC_MSG_RESULT([yes]);
+ AC_DEFINE([HAVE_LIBWRAP], [1],
+ [use tcp wrapper]) wrap_LIB="-lwrap"],
+ [AC_MSG_RESULT([not found]); exit 1])
+ else
+ AC_MSG_RESULT([no]);
+ fi],
+ dnl [ACTION-IF-NOT-GIVEN]
+ [AC_MSG_RESULT([(default)])
+ AC_MSG_CHECKING([for hosts_access in -lwrap])
+ saved_LIBS="$LIBS"
+ LIBS="-lwrap $saved_LIBS"
+ AC_TRY_LINK(
+ [int hosts_access(); int allow_severity, deny_severity;],
+ [hosts_access()],
+ [AC_MSG_RESULT([yes]);
+ AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])],
+ [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])])
+
+# Sets directory containing usb.ids.
+AC_ARG_WITH([usbids-dir],
+ [AS_HELP_STRING([--with-usbids-dir=DIR],
+ [where usb.ids is found (default /usr/share/hwdata/)])],
+ [USBIDS_DIR=$withval], [USBIDS_DIR="/usr/share/hwdata/"])
+AC_SUBST([USBIDS_DIR])
+
+# use _FORTIFY_SOURCE
+AC_MSG_CHECKING([whether to use fortify])
+AC_ARG_WITH([fortify],
+ [AS_HELP_STRING([--with-fortify],
+ [use _FORTIFY_SROUCE option when compiling)])],
+ dnl [ACTION-IF-GIVEN]
+ [if test "$withval" = "yes"; then
+ AC_MSG_RESULT([yes])
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE -O"
+ else
+ AC_MSG_RESULT([no])
+ CFLAGS="$CFLAGS -U_FORTIFY_SOURCE"
+ fi
+ ],
+ dnl [ACTION-IF-NOT-GIVEN]
+ [AC_MSG_RESULT([default])])
+
+AC_CONFIG_FILES([Makefile libsrc/Makefile src/Makefile])
+AC_OUTPUT
diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8
new file mode 100644
index 0000000..a6097be
--- /dev/null
+++ b/tools/usb/usbip/doc/usbip.8
@@ -0,0 +1,95 @@
+.TH USBIP "8" "February 2009" "usbip" "System Administration Utilities"
+.SH NAME
+usbip \- manage USB/IP devices
+.SH SYNOPSIS
+.B usbip
+[\fIoptions\fR] <\fIcommand\fR> <\fIargs\fR>
+
+.SH DESCRIPTION
+On a USB/IP server, devices can be listed, bound, and unbound using
+this program. On a USB/IP client, devices exported by USB/IP servers
+can be listed, attached and detached.
+
+.SH OPTIONS
+.HP
+\fB\-\-debug\fR
+.IP
+Print debugging information.
+.PP
+
+.HP
+\fB\-\-log\fR
+.IP
+Log to syslog.
+.PP
+
+.HP
+\fB\-\-tcp-port PORT\fR
+.IP
+Connect to PORT on remote host (used for attach and list --remote).
+.PP
+
+.SH COMMANDS
+.HP
+\fBversion\fR
+.IP
+Show version and exit.
+.PP
+
+.HP
+\fBhelp\fR [\fIcommand\fR]
+.IP
+Print the program help message, or help on a specific command, and
+then exit.
+.PP
+
+.HP
+\fBattach\fR \-\-remote=<\fIhost\fR> \-\-busid=<\fIbus_id\fR>
+.IP
+Attach a remote USB device.
+.PP
+
+.HP
+\fBdetach\fR \-\-port=<\fIport\fR>
+.IP
+Detach an imported USB device.
+.PP
+
+.HP
+\fBbind\fR \-\-busid=<\fIbusid\fR>
+.IP
+Make a device exportable.
+.PP
+
+.HP
+\fBunbind\fR \-\-busid=<\fIbusid\fR>
+.IP
+Stop exporting a device so it can be used by a local driver.
+.PP
+
+.HP
+\fBlist\fR \-\-remote=<\fIhost\fR>
+.IP
+List USB devices exported by a remote host.
+.PP
+
+.HP
+\fBlist\fR \-\-local
+.IP
+List local USB devices.
+.PP
+
+
+.SH EXAMPLES
+
+ client:# usbip list --remote=server
+ - List exportable usb devices on the server.
+
+ client:# usbip attach --remote=server --busid=1-2
+ - Connect the remote USB device.
+
+ client:# usbip detach --port=0
+ - Detach the usb device.
+
+.SH "SEE ALSO"
+\fBusbipd\fP\fB(8)\fB\fP
diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8
new file mode 100644
index 0000000..ac4635d
--- /dev/null
+++ b/tools/usb/usbip/doc/usbipd.8
@@ -0,0 +1,91 @@
+.TH USBIP "8" "February 2009" "usbip" "System Administration Utilities"
+.SH NAME
+usbipd \- USB/IP server daemon
+.SH SYNOPSIS
+.B usbipd
+[\fIoptions\fR]
+
+.SH DESCRIPTION
+.B usbipd
+provides USB/IP clients access to exported USB devices.
+
+Devices have to explicitly be exported using
+.B usbip bind
+before usbipd makes them available to other hosts.
+
+The daemon accepts connections from USB/IP clients
+on TCP port 3240 by default.
+
+.SH OPTIONS
+.HP
+\fB\-4\fR, \fB\-\-ipv4\fR
+.IP
+Bind to IPv4. Default is both.
+.PP
+
+.HP
+\fB\-6\fR, \fB\-\-ipv6\fR
+.IP
+Bind to IPv6. Default is both.
+.PP
+
+.HP
+\fB\-D\fR, \fB\-\-daemon\fR
+.IP
+Run as a daemon process.
+.PP
+
+.HP
+\fB\-d\fR, \fB\-\-debug\fR
+.IP
+Print debugging information.
+.PP
+
+.HP
+\fB\-PFILE\fR, \fB\-\-pid FILE\fR
+.IP
+Write process id to FILE.
+.br
+If no FILE specified, use /var/run/usbipd.pid
+.PP
+
+\fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR
+.IP
+Listen on TCP/IP port PORT.
+.PP
+
+\fB\-h\fR, \fB\-\-help\fR
+.IP
+Print the program help message and exit.
+.PP
+
+.HP
+\fB\-v\fR, \fB\-\-version\fR
+.IP
+Show version.
+.PP
+
+.SH LIMITATIONS
+
+.B usbipd
+offers no authentication or authorization for USB/IP. Any
+USB/IP client can connect and use exported devices.
+
+.SH EXAMPLES
+
+ server:# modprobe usbip
+
+ server:# usbipd -D
+ - Start usbip daemon.
+
+ server:# usbip list --local
+ - List driver assignments for usb devices.
+
+ server:# usbip bind --busid=1-2
+ - Bind usbip-host.ko to the device of busid 1-2.
+ - A usb device 1-2 is now exportable to other hosts!
+ - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally.
+
+.SH "SEE ALSO"
+\fBusbip\fP\fB(8)\fB\fP
+
diff --git a/tools/usb/usbip/libsrc/Makefile.am b/tools/usb/usbip/libsrc/Makefile.am
new file mode 100644
index 0000000..7c8f8a4
--- /dev/null
+++ b/tools/usb/usbip/libsrc/Makefile.am
@@ -0,0 +1,8 @@
+libusbip_la_CPPFLAGS = -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
+libusbip_la_CFLAGS = @EXTRA_CFLAGS@
+libusbip_la_LDFLAGS = -version-info @LIBUSBIP_VERSION@
+
+lib_LTLIBRARIES := libusbip.la
+libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \
+ usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \
+ sysfs_utils.c sysfs_utils.h
diff --git a/tools/usb/usbip/libsrc/list.h b/tools/usb/usbip/libsrc/list.h
new file mode 100644
index 0000000..8d0c936
--- /dev/null
+++ b/tools/usb/usbip/libsrc/list.h
@@ -0,0 +1,136 @@
+#ifndef _LIST_H
+#define _LIST_H
+
+/* Stripped down implementation of linked list taken
+ * from the Linux Kernel.
+ */
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+#define POISON_POINTER_DELTA 0
+#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
+#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void __list_del_entry(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#endif
diff --git a/tools/usb/usbip/libsrc/names.c b/tools/usb/usbip/libsrc/names.c
new file mode 100644
index 0000000..81ff852
--- /dev/null
+++ b/tools/usb/usbip/libsrc/names.c
@@ -0,0 +1,504 @@
+/*
+ * names.c -- USB name database manipulation routines
+ *
+ * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ *
+ *
+ * Copyright (C) 2005 Takahiro Hirofuchi
+ * - names_deinit() is added.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "names.h"
+#include "usbip_common.h"
+
+struct vendor {
+ struct vendor *next;
+ u_int16_t vendorid;
+ char name[1];
+};
+
+struct product {
+ struct product *next;
+ u_int16_t vendorid, productid;
+ char name[1];
+};
+
+struct class {
+ struct class *next;
+ u_int8_t classid;
+ char name[1];
+};
+
+struct subclass {
+ struct subclass *next;
+ u_int8_t classid, subclassid;
+ char name[1];
+};
+
+struct protocol {
+ struct protocol *next;
+ u_int8_t classid, subclassid, protocolid;
+ char name[1];
+};
+
+struct genericstrtable {
+ struct genericstrtable *next;
+ unsigned int num;
+ char name[1];
+};
+
+
+#define HASH1 0x10
+#define HASH2 0x02
+#define HASHSZ 16
+
+static unsigned int hashnum(unsigned int num)
+{
+ unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27;
+
+ for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1)
+ if (num & mask1)
+ num ^= mask2;
+ return num & (HASHSZ-1);
+}
+
+
+static struct vendor *vendors[HASHSZ] = { NULL, };
+static struct product *products[HASHSZ] = { NULL, };
+static struct class *classes[HASHSZ] = { NULL, };
+static struct subclass *subclasses[HASHSZ] = { NULL, };
+static struct protocol *protocols[HASHSZ] = { NULL, };
+
+const char *names_vendor(u_int16_t vendorid)
+{
+ struct vendor *v;
+
+ v = vendors[hashnum(vendorid)];
+ for (; v; v = v->next)
+ if (v->vendorid == vendorid)
+ return v->name;
+ return NULL;
+}
+
+const char *names_product(u_int16_t vendorid, u_int16_t productid)
+{
+ struct product *p;
+
+ p = products[hashnum((vendorid << 16) | productid)];
+ for (; p; p = p->next)
+ if (p->vendorid == vendorid && p->productid == productid)
+ return p->name;
+ return NULL;
+}
+
+const char *names_class(u_int8_t classid)
+{
+ struct class *c;
+
+ c = classes[hashnum(classid)];
+ for (; c; c = c->next)
+ if (c->classid == classid)
+ return c->name;
+ return NULL;
+}
+
+const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
+{
+ struct subclass *s;
+
+ s = subclasses[hashnum((classid << 8) | subclassid)];
+ for (; s; s = s->next)
+ if (s->classid == classid && s->subclassid == subclassid)
+ return s->name;
+ return NULL;
+}
+
+const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
+ u_int8_t protocolid)
+{
+ struct protocol *p;
+
+ p = protocols[hashnum((classid << 16) | (subclassid << 8)
+ | protocolid)];
+ for (; p; p = p->next)
+ if (p->classid == classid && p->subclassid == subclassid &&
+ p->protocolid == protocolid)
+ return p->name;
+ return NULL;
+}
+
+/* add a cleanup function by takahiro */
+struct pool {
+ struct pool *next;
+ void *mem;
+};
+
+static struct pool *pool_head;
+
+static void *my_malloc(size_t size)
+{
+ struct pool *p;
+
+ p = calloc(1, sizeof(struct pool));
+ if (!p)
+ return NULL;
+
+ p->mem = calloc(1, size);
+ if (!p->mem) {
+ free(p);
+ return NULL;
+ }
+
+ p->next = pool_head;
+ pool_head = p;
+
+ return p->mem;
+}
+
+void names_free(void)
+{
+ struct pool *pool;
+
+ if (!pool_head)
+ return;
+
+ for (pool = pool_head; pool != NULL; ) {
+ struct pool *tmp;
+
+ if (pool->mem)
+ free(pool->mem);
+
+ tmp = pool;
+ pool = pool->next;
+ free(tmp);
+ }
+}
+
+static int new_vendor(const char *name, u_int16_t vendorid)
+{
+ struct vendor *v;
+ unsigned int h = hashnum(vendorid);
+
+ v = vendors[h];
+ for (; v; v = v->next)
+ if (v->vendorid == vendorid)
+ return -1;
+ v = my_malloc(sizeof(struct vendor) + strlen(name));
+ if (!v)
+ return -1;
+ strcpy(v->name, name);
+ v->vendorid = vendorid;
+ v->next = vendors[h];
+ vendors[h] = v;
+ return 0;
+}
+
+static int new_product(const char *name, u_int16_t vendorid,
+ u_int16_t productid)
+{
+ struct product *p;
+ unsigned int h = hashnum((vendorid << 16) | productid);
+
+ p = products[h];
+ for (; p; p = p->next)
+ if (p->vendorid == vendorid && p->productid == productid)
+ return -1;
+ p = my_malloc(sizeof(struct product) + strlen(name));
+ if (!p)
+ return -1;
+ strcpy(p->name, name);
+ p->vendorid = vendorid;
+ p->productid = productid;
+ p->next = products[h];
+ products[h] = p;
+ return 0;
+}
+
+static int new_class(const char *name, u_int8_t classid)
+{
+ struct class *c;
+ unsigned int h = hashnum(classid);
+
+ c = classes[h];
+ for (; c; c = c->next)
+ if (c->classid == classid)
+ return -1;
+ c = my_malloc(sizeof(struct class) + strlen(name));
+ if (!c)
+ return -1;
+ strcpy(c->name, name);
+ c->classid = classid;
+ c->next = classes[h];
+ classes[h] = c;
+ return 0;
+}
+
+static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
+{
+ struct subclass *s;
+ unsigned int h = hashnum((classid << 8) | subclassid);
+
+ s = subclasses[h];
+ for (; s; s = s->next)
+ if (s->classid == classid && s->subclassid == subclassid)
+ return -1;
+ s = my_malloc(sizeof(struct subclass) + strlen(name));
+ if (!s)
+ return -1;
+ strcpy(s->name, name);
+ s->classid = classid;
+ s->subclassid = subclassid;
+ s->next = subclasses[h];
+ subclasses[h] = s;
+ return 0;
+}
+
+static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
+ u_int8_t protocolid)
+{
+ struct protocol *p;
+ unsigned int h = hashnum((classid << 16) | (subclassid << 8)
+ | protocolid);
+
+ p = protocols[h];
+ for (; p; p = p->next)
+ if (p->classid == classid && p->subclassid == subclassid
+ && p->protocolid == protocolid)
+ return -1;
+ p = my_malloc(sizeof(struct protocol) + strlen(name));
+ if (!p)
+ return -1;
+ strcpy(p->name, name);
+ p->classid = classid;
+ p->subclassid = subclassid;
+ p->protocolid = protocolid;
+ p->next = protocols[h];
+ protocols[h] = p;
+ return 0;
+}
+
+static void parse(FILE *f)
+{
+ char buf[512], *cp;
+ unsigned int linectr = 0;
+ int lastvendor = -1;
+ int lastclass = -1;
+ int lastsubclass = -1;
+ int lasthut = -1;
+ int lastlang = -1;
+ unsigned int u;
+
+ while (fgets(buf, sizeof(buf), f)) {
+ linectr++;
+ /* remove line ends */
+ cp = strchr(buf, '\r');
+ if (cp)
+ *cp = 0;
+ cp = strchr(buf, '\n');
+ if (cp)
+ *cp = 0;
+ if (buf[0] == '#' || !buf[0])
+ continue;
+ cp = buf;
+ if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
+ buf[3] == 'S' && buf[4] == 'D' &&
+ buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
+ buf[7] == ' ') {
+ continue;
+ }
+ if (buf[0] == 'P' && buf[1] == 'H' &&
+ buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
+ continue;
+ }
+ if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
+ buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
+ continue;
+ }
+ if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
+ lasthut = lastclass = lastvendor = lastsubclass = -1;
+ /*
+ * set 1 as pseudo-id to indicate that the parser is
+ * in a `L' section.
+ */
+ lastlang = 1;
+ continue;
+ }
+ if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
+ /* class spec */
+ cp = buf+2;
+ while (isspace(*cp))
+ cp++;
+ if (!isxdigit(*cp)) {
+ err("Invalid class spec at line %u", linectr);
+ continue;
+ }
+ u = strtoul(cp, &cp, 16);
+ while (isspace(*cp))
+ cp++;
+ if (!*cp) {
+ err("Invalid class spec at line %u", linectr);
+ continue;
+ }
+ if (new_class(cp, u))
+ err("Duplicate class spec at line %u class %04x %s",
+ linectr, u, cp);
+ dbg("line %5u class %02x %s", linectr, u, cp);
+ lasthut = lastlang = lastvendor = lastsubclass = -1;
+ lastclass = u;
+ continue;
+ }
+ if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
+ /* audio terminal type spec */
+ continue;
+ }
+ if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
+ && isspace(buf[3])) {
+ /* HID Descriptor bCountryCode */
+ continue;
+ }
+ if (isxdigit(*cp)) {
+ /* vendor */
+ u = strtoul(cp, &cp, 16);
+ while (isspace(*cp))
+ cp++;
+ if (!*cp) {
+ err("Invalid vendor spec at line %u", linectr);
+ continue;
+ }
+ if (new_vendor(cp, u))
+ err("Duplicate vendor spec at line %u vendor %04x %s",
+ linectr, u, cp);
+ dbg("line %5u vendor %04x %s", linectr, u, cp);
+ lastvendor = u;
+ lasthut = lastlang = lastclass = lastsubclass = -1;
+ continue;
+ }
+ if (buf[0] == '\t' && isxdigit(buf[1])) {
+ /* product or subclass spec */
+ u = strtoul(buf+1, &cp, 16);
+ while (isspace(*cp))
+ cp++;
+ if (!*cp) {
+ err("Invalid product/subclass spec at line %u",
+ linectr);
+ continue;
+ }
+ if (lastvendor != -1) {
+ if (new_product(cp, lastvendor, u))
+ err("Duplicate product spec at line %u product %04x:%04x %s",
+ linectr, lastvendor, u, cp);
+ dbg("line %5u product %04x:%04x %s", linectr,
+ lastvendor, u, cp);
+ continue;
+ }
+ if (lastclass != -1) {
+ if (new_subclass(cp, lastclass, u))
+ err("Duplicate subclass spec at line %u class %02x:%02x %s",
+ linectr, lastclass, u, cp);
+ dbg("line %5u subclass %02x:%02x %s", linectr,
+ lastclass, u, cp);
+ lastsubclass = u;
+ continue;
+ }
+ if (lasthut != -1) {
+ /* do not store hut */
+ continue;
+ }
+ if (lastlang != -1) {
+ /* do not store langid */
+ continue;
+ }
+ err("Product/Subclass spec without prior Vendor/Class spec at line %u",
+ linectr);
+ continue;
+ }
+ if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
+ /* protocol spec */
+ u = strtoul(buf+2, &cp, 16);
+ while (isspace(*cp))
+ cp++;
+ if (!*cp) {
+ err("Invalid protocol spec at line %u",
+ linectr);
+ continue;
+ }
+ if (lastclass != -1 && lastsubclass != -1) {
+ if (new_protocol(cp, lastclass, lastsubclass,
+ u))
+ err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
+ linectr, lastclass, lastsubclass,
+ u, cp);
+ dbg("line %5u protocol %02x:%02x:%02x %s",
+ linectr, lastclass, lastsubclass, u, cp);
+ continue;
+ }
+ err("Protocol spec without prior Class and Subclass spec at line %u",
+ linectr);
+ continue;
+ }
+ if (buf[0] == 'H' && buf[1] == 'I' &&
+ buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
+ continue;
+ }
+ if (buf[0] == 'H' && buf[1] == 'U' &&
+ buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
+ lastlang = lastclass = lastvendor = lastsubclass = -1;
+ /*
+ * set 1 as pseudo-id to indicate that the parser is
+ * in a `HUT' section.
+ */
+ lasthut = 1;
+ continue;
+ }
+ if (buf[0] == 'R' && buf[1] == ' ')
+ continue;
+
+ if (buf[0] == 'V' && buf[1] == 'T')
+ continue;
+
+ err("Unknown line at line %u", linectr);
+ }
+}
+
+
+int names_init(char *n)
+{
+ FILE *f;
+
+ f = fopen(n, "r");
+ if (!f)
+ return errno;
+
+ parse(f);
+ fclose(f);
+ return 0;
+}
diff --git a/tools/usb/usbip/libsrc/names.h b/tools/usb/usbip/libsrc/names.h
new file mode 100644
index 0000000..6809265
--- /dev/null
+++ b/tools/usb/usbip/libsrc/names.h
@@ -0,0 +1,41 @@
+/*
+ * names.h -- USB name database manipulation routines
+ *
+ * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ * Copyright (C) 2005 Takahiro Hirofuchi
+ * - names_free() is added.
+ */
+
+#ifndef _NAMES_H
+#define _NAMES_H
+
+#include <sys/types.h>
+
+/* used by usbip_common.c */
+extern const char *names_vendor(u_int16_t vendorid);
+extern const char *names_product(u_int16_t vendorid, u_int16_t productid);
+extern const char *names_class(u_int8_t classid);
+extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid);
+extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
+ u_int8_t protocolid);
+extern int names_init(char *n);
+extern void names_free(void);
+
+#endif /* _NAMES_H */
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.c b/tools/usb/usbip/libsrc/sysfs_utils.c
new file mode 100644
index 0000000..36ac88e
--- /dev/null
+++ b/tools/usb/usbip/libsrc/sysfs_utils.c
@@ -0,0 +1,31 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "sysfs_utils.h"
+#include "usbip_common.h"
+
+int write_sysfs_attribute(const char *attr_path, const char *new_value,
+ size_t len)
+{
+ int fd;
+ int length;
+
+ fd = open(attr_path, O_WRONLY);
+ if (fd < 0) {
+ dbg("error opening attribute %s", attr_path);
+ return -1;
+ }
+
+ length = write(fd, new_value, len);
+ if (length < 0) {
+ dbg("error writing to attribute %s", attr_path);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.h b/tools/usb/usbip/libsrc/sysfs_utils.h
new file mode 100644
index 0000000..32ac1d1
--- /dev/null
+++ b/tools/usb/usbip/libsrc/sysfs_utils.h
@@ -0,0 +1,8 @@
+
+#ifndef __SYSFS_UTILS_H
+#define __SYSFS_UTILS_H
+
+int write_sysfs_attribute(const char *attr_path, const char *new_value,
+ size_t len);
+
+#endif
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
new file mode 100644
index 0000000..ac73710
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_common.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#include <libudev.h>
+#include "usbip_common.h"
+#include "names.h"
+
+#undef PROGNAME
+#define PROGNAME "libusbip"
+
+int usbip_use_syslog;
+int usbip_use_stderr;
+int usbip_use_debug;
+
+extern struct udev *udev_context;
+
+struct speed_string {
+ int num;
+ char *speed;
+ char *desc;
+};
+
+static const struct speed_string speed_strings[] = {
+ { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"},
+ { USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" },
+ { USB_SPEED_FULL, "12", "Full Speed(12Mbps)" },
+ { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" },
+ { USB_SPEED_WIRELESS, "53.3-480", "Wireless"},
+ { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" },
+ { 0, NULL, NULL }
+};
+
+struct portst_string {
+ int num;
+ char *desc;
+};
+
+static struct portst_string portst_strings[] = {
+ { SDEV_ST_AVAILABLE, "Device Available" },
+ { SDEV_ST_USED, "Device in Use" },
+ { SDEV_ST_ERROR, "Device Error"},
+ { VDEV_ST_NULL, "Port Available"},
+ { VDEV_ST_NOTASSIGNED, "Port Initializing"},
+ { VDEV_ST_USED, "Port in Use"},
+ { VDEV_ST_ERROR, "Port Error"},
+ { 0, NULL}
+};
+
+const char *usbip_status_string(int32_t status)
+{
+ for (int i = 0; portst_strings[i].desc != NULL; i++)
+ if (portst_strings[i].num == status)
+ return portst_strings[i].desc;
+
+ return "Unknown Status";
+}
+
+const char *usbip_speed_string(int num)
+{
+ for (int i = 0; speed_strings[i].speed != NULL; i++)
+ if (speed_strings[i].num == num)
+ return speed_strings[i].desc;
+
+ return "Unknown Speed";
+}
+
+
+#define DBG_UDEV_INTEGER(name)\
+ dbg("%-20s = %x", to_string(name), (int) udev->name)
+
+#define DBG_UINF_INTEGER(name)\
+ dbg("%-20s = %x", to_string(name), (int) uinf->name)
+
+void dump_usb_interface(struct usbip_usb_interface *uinf)
+{
+ char buff[100];
+
+ usbip_names_get_class(buff, sizeof(buff),
+ uinf->bInterfaceClass,
+ uinf->bInterfaceSubClass,
+ uinf->bInterfaceProtocol);
+ dbg("%-20s = %s", "Interface(C/SC/P)", buff);
+}
+
+void dump_usb_device(struct usbip_usb_device *udev)
+{
+ char buff[100];
+
+ dbg("%-20s = %s", "path", udev->path);
+ dbg("%-20s = %s", "busid", udev->busid);
+
+ usbip_names_get_class(buff, sizeof(buff),
+ udev->bDeviceClass,
+ udev->bDeviceSubClass,
+ udev->bDeviceProtocol);
+ dbg("%-20s = %s", "Device(C/SC/P)", buff);
+
+ DBG_UDEV_INTEGER(bcdDevice);
+
+ usbip_names_get_product(buff, sizeof(buff),
+ udev->idVendor,
+ udev->idProduct);
+ dbg("%-20s = %s", "Vendor/Product", buff);
+
+ DBG_UDEV_INTEGER(bNumConfigurations);
+ DBG_UDEV_INTEGER(bNumInterfaces);
+
+ dbg("%-20s = %s", "speed",
+ usbip_speed_string(udev->speed));
+
+ DBG_UDEV_INTEGER(busnum);
+ DBG_UDEV_INTEGER(devnum);
+}
+
+
+int read_attr_value(struct udev_device *dev, const char *name,
+ const char *format)
+{
+ const char *attr;
+ int num = 0;
+ int ret;
+
+ attr = udev_device_get_sysattr_value(dev, name);
+ if (!attr) {
+ err("udev_device_get_sysattr_value failed");
+ goto err;
+ }
+
+ /* The client chooses the device configuration
+ * when attaching it so right after being bound
+ * to usbip-host on the server the device will
+ * have no configuration.
+ * Therefore, attributes such as bConfigurationValue
+ * and bNumInterfaces will not exist and sscanf will
+ * fail. Check for these cases and don't treat them
+ * as errors.
+ */
+
+ ret = sscanf(attr, format, &num);
+ if (ret < 1) {
+ if (strcmp(name, "bConfigurationValue") &&
+ strcmp(name, "bNumInterfaces")) {
+ err("sscanf failed for attribute %s", name);
+ goto err;
+ }
+ }
+
+err:
+
+ return num;
+}
+
+
+int read_attr_speed(struct udev_device *dev)
+{
+ const char *speed;
+
+ speed = udev_device_get_sysattr_value(dev, "speed");
+ if (!speed) {
+ err("udev_device_get_sysattr_value failed");
+ goto err;
+ }
+
+ for (int i = 0; speed_strings[i].speed != NULL; i++) {
+ if (!strcmp(speed, speed_strings[i].speed))
+ return speed_strings[i].num;
+ }
+
+err:
+
+ return USB_SPEED_UNKNOWN;
+}
+
+#define READ_ATTR(object, type, dev, name, format) \
+ do { \
+ (object)->name = (type) read_attr_value(dev, to_string(name), \
+ format); \
+ } while (0)
+
+
+int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev)
+{
+ uint32_t busnum, devnum;
+ const char *path, *name;
+
+ READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n");
+ READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n");
+ READ_ATTR(udev, uint8_t, sdev, bDeviceProtocol, "%02x\n");
+
+ READ_ATTR(udev, uint16_t, sdev, idVendor, "%04x\n");
+ READ_ATTR(udev, uint16_t, sdev, idProduct, "%04x\n");
+ READ_ATTR(udev, uint16_t, sdev, bcdDevice, "%04x\n");
+
+ READ_ATTR(udev, uint8_t, sdev, bConfigurationValue, "%02x\n");
+ READ_ATTR(udev, uint8_t, sdev, bNumConfigurations, "%02x\n");
+ READ_ATTR(udev, uint8_t, sdev, bNumInterfaces, "%02x\n");
+
+ READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n");
+ udev->speed = read_attr_speed(sdev);
+
+ path = udev_device_get_syspath(sdev);
+ name = udev_device_get_sysname(sdev);
+
+ strncpy(udev->path, path, SYSFS_PATH_MAX);
+ strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE);
+
+ sscanf(name, "%u-%u", &busnum, &devnum);
+ udev->busnum = busnum;
+
+ return 0;
+}
+
+int read_usb_interface(struct usbip_usb_device *udev, int i,
+ struct usbip_usb_interface *uinf)
+{
+ char busid[SYSFS_BUS_ID_SIZE];
+ struct udev_device *sif;
+
+ sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i);
+
+ sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
+ if (!sif) {
+ err("udev_device_new_from_subsystem_sysname %s failed", busid);
+ return -1;
+ }
+
+ READ_ATTR(uinf, uint8_t, sif, bInterfaceClass, "%02x\n");
+ READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n");
+ READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n");
+
+ return 0;
+}
+
+int usbip_names_init(char *f)
+{
+ return names_init(f);
+}
+
+void usbip_names_free(void)
+{
+ names_free();
+}
+
+void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
+ uint16_t product)
+{
+ const char *prod, *vend;
+
+ prod = names_product(vendor, product);
+ if (!prod)
+ prod = "unknown product";
+
+
+ vend = names_vendor(vendor);
+ if (!vend)
+ vend = "unknown vendor";
+
+ snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product);
+}
+
+void usbip_names_get_class(char *buff, size_t size, uint8_t class,
+ uint8_t subclass, uint8_t protocol)
+{
+ const char *c, *s, *p;
+
+ if (class == 0 && subclass == 0 && protocol == 0) {
+ snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol);
+ return;
+ }
+
+ p = names_protocol(class, subclass, protocol);
+ if (!p)
+ p = "unknown protocol";
+
+ s = names_subclass(class, subclass);
+ if (!s)
+ s = "unknown subclass";
+
+ c = names_class(class);
+ if (!c)
+ c = "unknown class";
+
+ snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol);
+}
diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h
new file mode 100644
index 0000000..15fe792
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_common.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#ifndef __USBIP_COMMON_H
+#define __USBIP_COMMON_H
+
+#include <libudev.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <syslog.h>
+#include <unistd.h>
+#include <linux/usb/ch9.h>
+#include <linux/usbip.h>
+
+#ifndef USBIDS_FILE
+#define USBIDS_FILE "/usr/share/hwdata/usb.ids"
+#endif
+
+#ifndef VHCI_STATE_PATH
+#define VHCI_STATE_PATH "/var/run/vhci_hcd"
+#endif
+
+/* kernel module names */
+#define USBIP_CORE_MOD_NAME "usbip-core"
+#define USBIP_HOST_DRV_NAME "usbip-host"
+#define USBIP_VHCI_DRV_NAME "vhci_hcd"
+
+/* sysfs constants */
+#define SYSFS_MNT_PATH "/sys"
+#define SYSFS_BUS_NAME "bus"
+#define SYSFS_BUS_TYPE "usb"
+#define SYSFS_DRIVERS_NAME "drivers"
+
+#define SYSFS_PATH_MAX 256
+#define SYSFS_BUS_ID_SIZE 32
+
+extern int usbip_use_syslog;
+extern int usbip_use_stderr;
+extern int usbip_use_debug ;
+
+#define PROGNAME "usbip"
+
+#define pr_fmt(fmt) "%s: %s: " fmt "\n", PROGNAME
+#define dbg_fmt(fmt) pr_fmt("%s:%d:[%s] " fmt), "debug", \
+ __FILE__, __LINE__, __func__
+
+#define err(fmt, args...) \
+ do { \
+ if (usbip_use_syslog) { \
+ syslog(LOG_ERR, pr_fmt(fmt), "error", ##args); \
+ } \
+ if (usbip_use_stderr) { \
+ fprintf(stderr, pr_fmt(fmt), "error", ##args); \
+ } \
+ } while (0)
+
+#define info(fmt, args...) \
+ do { \
+ if (usbip_use_syslog) { \
+ syslog(LOG_INFO, pr_fmt(fmt), "info", ##args); \
+ } \
+ if (usbip_use_stderr) { \
+ fprintf(stderr, pr_fmt(fmt), "info", ##args); \
+ } \
+ } while (0)
+
+#define dbg(fmt, args...) \
+ do { \
+ if (usbip_use_debug) { \
+ if (usbip_use_syslog) { \
+ syslog(LOG_DEBUG, dbg_fmt(fmt), ##args); \
+ } \
+ if (usbip_use_stderr) { \
+ fprintf(stderr, dbg_fmt(fmt), ##args); \
+ } \
+ } \
+ } while (0)
+
+#define BUG() \
+ do { \
+ err("sorry, it's a bug!"); \
+ abort(); \
+ } while (0)
+
+struct usbip_usb_interface {
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t padding; /* alignment */
+} __attribute__((packed));
+
+struct usbip_usb_device {
+ char path[SYSFS_PATH_MAX];
+ char busid[SYSFS_BUS_ID_SIZE];
+
+ uint32_t busnum;
+ uint32_t devnum;
+ uint32_t speed;
+
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bConfigurationValue;
+ uint8_t bNumConfigurations;
+ uint8_t bNumInterfaces;
+} __attribute__((packed));
+
+#define to_string(s) #s
+
+void dump_usb_interface(struct usbip_usb_interface *);
+void dump_usb_device(struct usbip_usb_device *);
+int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev);
+int read_attr_value(struct udev_device *dev, const char *name,
+ const char *format);
+int read_usb_interface(struct usbip_usb_device *udev, int i,
+ struct usbip_usb_interface *uinf);
+
+const char *usbip_speed_string(int num);
+const char *usbip_status_string(int32_t status);
+
+int usbip_names_init(char *);
+void usbip_names_free(void);
+void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
+ uint16_t product);
+void usbip_names_get_class(char *buff, size_t size, uint8_t class,
+ uint8_t subclass, uint8_t protocol);
+
+#endif /* __USBIP_COMMON_H */
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.c b/tools/usb/usbip/libsrc/usbip_host_driver.c
new file mode 100644
index 0000000..bef08d5
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_host_driver.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <libudev.h>
+
+#include "usbip_common.h"
+#include "usbip_host_driver.h"
+#include "list.h"
+#include "sysfs_utils.h"
+
+#undef PROGNAME
+#define PROGNAME "libusbip"
+
+struct usbip_host_driver *host_driver;
+struct udev *udev_context;
+
+static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
+{
+ char status_attr_path[SYSFS_PATH_MAX];
+ int fd;
+ int length;
+ char status;
+ int value = 0;
+
+ snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status",
+ udev->path);
+
+ fd = open(status_attr_path, O_RDONLY);
+ if (fd < 0) {
+ err("error opening attribute %s", status_attr_path);
+ return -1;
+ }
+
+ length = read(fd, &status, 1);
+ if (length < 0) {
+ err("error reading attribute %s", status_attr_path);
+ close(fd);
+ return -1;
+ }
+
+ value = atoi(&status);
+
+ return value;
+}
+
+static
+struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath)
+{
+ struct usbip_exported_device *edev = NULL;
+ struct usbip_exported_device *edev_old;
+ size_t size;
+ int i;
+
+ edev = calloc(1, sizeof(struct usbip_exported_device));
+
+ edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath);
+ if (!edev->sudev) {
+ err("udev_device_new_from_syspath: %s", sdevpath);
+ goto err;
+ }
+
+ read_usb_device(edev->sudev, &edev->udev);
+
+ edev->status = read_attr_usbip_status(&edev->udev);
+ if (edev->status < 0)
+ goto err;
+
+ /* reallocate buffer to include usb interface data */
+ size = sizeof(struct usbip_exported_device) +
+ edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface);
+
+ edev_old = edev;
+ edev = realloc(edev, size);
+ if (!edev) {
+ edev = edev_old;
+ dbg("realloc failed");
+ goto err;
+ }
+
+ for (i = 0; i < edev->udev.bNumInterfaces; i++)
+ read_usb_interface(&edev->udev, i, &edev->uinf[i]);
+
+ return edev;
+err:
+ if (edev->sudev)
+ udev_device_unref(edev->sudev);
+ if (edev)
+ free(edev);
+
+ return NULL;
+}
+
+static int refresh_exported_devices(void)
+{
+ struct usbip_exported_device *edev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *dev;
+ const char *path;
+ const char *driver;
+
+ enumerate = udev_enumerate_new(udev_context);
+ udev_enumerate_add_match_subsystem(enumerate, "usb");
+ udev_enumerate_scan_devices(enumerate);
+
+ devices = udev_enumerate_get_list_entry(enumerate);
+
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(udev_context, path);
+ if (dev == NULL)
+ continue;
+
+ /* Check whether device uses usbip-host driver. */
+ driver = udev_device_get_driver(dev);
+ if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) {
+ edev = usbip_exported_device_new(path);
+ if (!edev) {
+ dbg("usbip_exported_device_new failed");
+ continue;
+ }
+
+ list_add(&edev->node, &host_driver->edev_list);
+ host_driver->ndevs++;
+ }
+ }
+
+ return 0;
+}
+
+static void usbip_exported_device_destroy(void)
+{
+ struct list_head *i, *tmp;
+ struct usbip_exported_device *edev;
+
+ list_for_each_safe(i, tmp, &host_driver->edev_list) {
+ edev = list_entry(i, struct usbip_exported_device, node);
+ list_del(i);
+ free(edev);
+ }
+}
+
+int usbip_host_driver_open(void)
+{
+ int rc;
+
+ udev_context = udev_new();
+ if (!udev_context) {
+ err("udev_new failed");
+ return -1;
+ }
+
+ host_driver = calloc(1, sizeof(*host_driver));
+
+ host_driver->ndevs = 0;
+ INIT_LIST_HEAD(&host_driver->edev_list);
+
+ rc = refresh_exported_devices();
+ if (rc < 0)
+ goto err_free_host_driver;
+
+ return 0;
+
+err_free_host_driver:
+ free(host_driver);
+ host_driver = NULL;
+
+ udev_unref(udev_context);
+
+ return -1;
+}
+
+void usbip_host_driver_close(void)
+{
+ if (!host_driver)
+ return;
+
+ usbip_exported_device_destroy();
+
+ free(host_driver);
+ host_driver = NULL;
+
+ udev_unref(udev_context);
+}
+
+int usbip_host_refresh_device_list(void)
+{
+ int rc;
+
+ usbip_exported_device_destroy();
+
+ host_driver->ndevs = 0;
+ INIT_LIST_HEAD(&host_driver->edev_list);
+
+ rc = refresh_exported_devices();
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
+{
+ char attr_name[] = "usbip_sockfd";
+ char sockfd_attr_path[SYSFS_PATH_MAX];
+ char sockfd_buff[30];
+ int ret;
+
+ if (edev->status != SDEV_ST_AVAILABLE) {
+ dbg("device not available: %s", edev->udev.busid);
+ switch (edev->status) {
+ case SDEV_ST_ERROR:
+ dbg("status SDEV_ST_ERROR");
+ break;
+ case SDEV_ST_USED:
+ dbg("status SDEV_ST_USED");
+ break;
+ default:
+ dbg("status unknown: 0x%x", edev->status);
+ }
+ return -1;
+ }
+
+ /* only the first interface is true */
+ snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
+ edev->udev.path, attr_name);
+
+ snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
+
+ ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
+ strlen(sockfd_buff));
+ if (ret < 0) {
+ err("write_sysfs_attribute failed: sockfd %s to %s",
+ sockfd_buff, sockfd_attr_path);
+ return ret;
+ }
+
+ info("connect: %s", edev->udev.busid);
+
+ return ret;
+}
+
+struct usbip_exported_device *usbip_host_get_device(int num)
+{
+ struct list_head *i;
+ struct usbip_exported_device *edev;
+ int cnt = 0;
+
+ list_for_each(i, &host_driver->edev_list) {
+ edev = list_entry(i, struct usbip_exported_device, node);
+ if (num == cnt)
+ return edev;
+ else
+ cnt++;
+ }
+
+ return NULL;
+}
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.h b/tools/usb/usbip/libsrc/usbip_host_driver.h
new file mode 100644
index 0000000..2a31f85
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_host_driver.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __USBIP_HOST_DRIVER_H
+#define __USBIP_HOST_DRIVER_H
+
+#include <stdint.h>
+#include "usbip_common.h"
+#include "list.h"
+
+struct usbip_host_driver {
+ int ndevs;
+ /* list of exported device */
+ struct list_head edev_list;
+};
+
+struct usbip_exported_device {
+ struct udev_device *sudev;
+ int32_t status;
+ struct usbip_usb_device udev;
+ struct list_head node;
+ struct usbip_usb_interface uinf[];
+};
+
+extern struct usbip_host_driver *host_driver;
+
+int usbip_host_driver_open(void);
+void usbip_host_driver_close(void);
+
+int usbip_host_refresh_device_list(void);
+int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd);
+struct usbip_exported_device *usbip_host_get_device(int num);
+
+#endif /* __USBIP_HOST_DRIVER_H */
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
new file mode 100644
index 0000000..ad92047
--- /dev/null
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#include "usbip_common.h"
+#include "vhci_driver.h"
+#include <limits.h>
+#include <netdb.h>
+#include <libudev.h>
+#include "sysfs_utils.h"
+
+#undef PROGNAME
+#define PROGNAME "libusbip"
+
+struct usbip_vhci_driver *vhci_driver;
+struct udev *udev_context;
+
+static struct usbip_imported_device *
+imported_device_init(struct usbip_imported_device *idev, char *busid)
+{
+ struct udev_device *sudev;
+
+ sudev = udev_device_new_from_subsystem_sysname(udev_context,
+ "usb", busid);
+ if (!sudev) {
+ dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
+ goto err;
+ }
+ read_usb_device(sudev, &idev->udev);
+ udev_device_unref(sudev);
+
+ return idev;
+
+err:
+ return NULL;
+}
+
+
+
+static int parse_status(const char *value)
+{
+ int ret = 0;
+ char *c;
+
+
+ for (int i = 0; i < vhci_driver->nports; i++)
+ memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
+
+
+ /* skip a header line */
+ c = strchr(value, '\n');
+ if (!c)
+ return -1;
+ c++;
+
+ while (*c != '\0') {
+ int port, status, speed, devid;
+ unsigned long socket;
+ char lbusid[SYSFS_BUS_ID_SIZE];
+
+ ret = sscanf(c, "%d %d %d %x %lx %31s\n",
+ &port, &status, &speed,
+ &devid, &socket, lbusid);
+
+ if (ret < 5) {
+ dbg("sscanf failed: %d", ret);
+ BUG();
+ }
+
+ dbg("port %d status %d speed %d devid %x",
+ port, status, speed, devid);
+ dbg("socket %lx lbusid %s", socket, lbusid);
+
+
+ /* if a device is connected, look at it */
+ {
+ struct usbip_imported_device *idev = &vhci_driver->idev[port];
+
+ idev->port = port;
+ idev->status = status;
+
+ idev->devid = devid;
+
+ idev->busnum = (devid >> 16);
+ idev->devnum = (devid & 0x0000ffff);
+
+ if (idev->status != VDEV_ST_NULL
+ && idev->status != VDEV_ST_NOTASSIGNED) {
+ idev = imported_device_init(idev, lbusid);
+ if (!idev) {
+ dbg("imported_device_init failed");
+ return -1;
+ }
+ }
+ }
+
+
+ /* go to the next line */
+ c = strchr(c, '\n');
+ if (!c)
+ break;
+ c++;
+ }
+
+ dbg("exit");
+
+ return 0;
+}
+
+static int refresh_imported_device_list(void)
+{
+ const char *attr_status;
+
+ attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
+ "status");
+ if (!attr_status) {
+ err("udev_device_get_sysattr_value failed");
+ return -1;
+ }
+
+ return parse_status(attr_status);
+}
+
+static int get_nports(void)
+{
+ char *c;
+ int nports = 0;
+ const char *attr_status;
+
+ attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
+ "status");
+ if (!attr_status) {
+ err("udev_device_get_sysattr_value failed");
+ return -1;
+ }
+
+ /* skip a header line */
+ c = strchr(attr_status, '\n');
+ if (!c)
+ return 0;
+ c++;
+
+ while (*c != '\0') {
+ /* go to the next line */
+ c = strchr(c, '\n');
+ if (!c)
+ return nports;
+ c++;
+ nports += 1;
+ }
+
+ return nports;
+}
+
+/*
+ * Read the given port's record.
+ *
+ * To avoid buffer overflow we will read the entire line and
+ * validate each part's size. The initial buffer is padded by 4 to
+ * accommodate the 2 spaces, 1 newline and an additional character
+ * which is needed to properly validate the 3rd part without it being
+ * truncated to an acceptable length.
+ */
+static int read_record(int rhport, char *host, unsigned long host_len,
+ char *port, unsigned long port_len, char *busid)
+{
+ int part;
+ FILE *file;
+ char path[PATH_MAX+1];
+ char *buffer, *start, *end;
+ char delim[] = {' ', ' ', '\n'};
+ int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
+ size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
+
+ buffer = malloc(buffer_len);
+ if (!buffer)
+ return -1;
+
+ snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
+
+ file = fopen(path, "r");
+ if (!file) {
+ err("fopen");
+ free(buffer);
+ return -1;
+ }
+
+ if (fgets(buffer, buffer_len, file) == NULL) {
+ err("fgets");
+ free(buffer);
+ fclose(file);
+ return -1;
+ }
+ fclose(file);
+
+ /* validate the length of each of the 3 parts */
+ start = buffer;
+ for (part = 0; part < 3; part++) {
+ end = strchr(start, delim[part]);
+ if (end == NULL || (end - start) > max_len[part]) {
+ free(buffer);
+ return -1;
+ }
+ start = end + 1;
+ }
+
+ if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
+ err("sscanf");
+ free(buffer);
+ return -1;
+ }
+
+ free(buffer);
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int usbip_vhci_driver_open(void)
+{
+ udev_context = udev_new();
+ if (!udev_context) {
+ err("udev_new failed");
+ return -1;
+ }
+
+ vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver));
+
+ /* will be freed in usbip_driver_close() */
+ vhci_driver->hc_device =
+ udev_device_new_from_subsystem_sysname(udev_context,
+ USBIP_VHCI_BUS_TYPE,
+ USBIP_VHCI_DRV_NAME);
+ if (!vhci_driver->hc_device) {
+ err("udev_device_new_from_subsystem_sysname failed");
+ goto err;
+ }
+
+ vhci_driver->nports = get_nports();
+
+ dbg("available ports: %d", vhci_driver->nports);
+
+ if (refresh_imported_device_list())
+ goto err;
+
+ return 0;
+
+err:
+ udev_device_unref(vhci_driver->hc_device);
+
+ if (vhci_driver)
+ free(vhci_driver);
+
+ vhci_driver = NULL;
+
+ udev_unref(udev_context);
+
+ return -1;
+}
+
+
+void usbip_vhci_driver_close(void)
+{
+ if (!vhci_driver)
+ return;
+
+ udev_device_unref(vhci_driver->hc_device);
+
+ free(vhci_driver);
+
+ vhci_driver = NULL;
+
+ udev_unref(udev_context);
+}
+
+
+int usbip_vhci_refresh_device_list(void)
+{
+
+ if (refresh_imported_device_list())
+ goto err;
+
+ return 0;
+err:
+ dbg("failed to refresh device list");
+ return -1;
+}
+
+
+int usbip_vhci_get_free_port(void)
+{
+ for (int i = 0; i < vhci_driver->nports; i++) {
+ if (vhci_driver->idev[i].status == VDEV_ST_NULL)
+ return i;
+ }
+
+ return -1;
+}
+
+int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
+ uint32_t speed) {
+ char buff[200]; /* what size should be ? */
+ char attach_attr_path[SYSFS_PATH_MAX];
+ char attr_attach[] = "attach";
+ const char *path;
+ int ret;
+
+ snprintf(buff, sizeof(buff), "%u %d %u %u",
+ port, sockfd, devid, speed);
+ dbg("writing: %s", buff);
+
+ path = udev_device_get_syspath(vhci_driver->hc_device);
+ snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
+ path, attr_attach);
+ dbg("attach attribute path: %s", attach_attr_path);
+
+ ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff));
+ if (ret < 0) {
+ dbg("write_sysfs_attribute failed");
+ return -1;
+ }
+
+ dbg("attached port: %d", port);
+
+ return 0;
+}
+
+static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
+{
+ return (busnum << 16) | devnum;
+}
+
+/* will be removed */
+int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
+ uint8_t devnum, uint32_t speed)
+{
+ int devid = get_devid(busnum, devnum);
+
+ return usbip_vhci_attach_device2(port, sockfd, devid, speed);
+}
+
+int usbip_vhci_detach_device(uint8_t port)
+{
+ char detach_attr_path[SYSFS_PATH_MAX];
+ char attr_detach[] = "detach";
+ char buff[200]; /* what size should be ? */
+ const char *path;
+ int ret;
+
+ snprintf(buff, sizeof(buff), "%u", port);
+ dbg("writing: %s", buff);
+
+ path = udev_device_get_syspath(vhci_driver->hc_device);
+ snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
+ path, attr_detach);
+ dbg("detach attribute path: %s", detach_attr_path);
+
+ ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff));
+ if (ret < 0) {
+ dbg("write_sysfs_attribute failed");
+ return -1;
+ }
+
+ dbg("detached port: %d", port);
+
+ return 0;
+}
+
+int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
+{
+ char product_name[100];
+ char host[NI_MAXHOST] = "unknown host";
+ char serv[NI_MAXSERV] = "unknown port";
+ char remote_busid[SYSFS_BUS_ID_SIZE];
+ int ret;
+ int read_record_error = 0;
+
+ if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
+ return 0;
+
+ ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
+ remote_busid);
+ if (ret) {
+ err("read_record");
+ read_record_error = 1;
+ }
+
+ printf("Port %02d: <%s> at %s\n", idev->port,
+ usbip_status_string(idev->status),
+ usbip_speed_string(idev->udev.speed));
+
+ usbip_names_get_product(product_name, sizeof(product_name),
+ idev->udev.idVendor, idev->udev.idProduct);
+
+ printf(" %s\n", product_name);
+
+ if (!read_record_error) {
+ printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid,
+ host, serv, remote_busid);
+ printf("%10s -> remote bus/dev %03d/%03d\n", " ",
+ idev->busnum, idev->devnum);
+ } else {
+ printf("%10s -> unknown host, remote port and remote busid\n",
+ idev->udev.busid);
+ printf("%10s -> remote bus/dev %03d/%03d\n", " ",
+ idev->busnum, idev->devnum);
+ }
+
+ return 0;
+}
diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h
new file mode 100644
index 0000000..fa2316c
--- /dev/null
+++ b/tools/usb/usbip/libsrc/vhci_driver.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#ifndef __VHCI_DRIVER_H
+#define __VHCI_DRIVER_H
+
+#include <libudev.h>
+#include <stdint.h>
+
+#include "usbip_common.h"
+
+#define USBIP_VHCI_BUS_TYPE "platform"
+#define MAXNPORT 128
+
+struct usbip_imported_device {
+ uint8_t port;
+ uint32_t status;
+
+ uint32_t devid;
+
+ uint8_t busnum;
+ uint8_t devnum;
+
+ /* usbip_class_device list */
+ struct usbip_usb_device udev;
+};
+
+struct usbip_vhci_driver {
+
+ /* /sys/devices/platform/vhci_hcd */
+ struct udev_device *hc_device;
+
+ int nports;
+ struct usbip_imported_device idev[MAXNPORT];
+};
+
+
+extern struct usbip_vhci_driver *vhci_driver;
+
+int usbip_vhci_driver_open(void);
+void usbip_vhci_driver_close(void);
+
+int usbip_vhci_refresh_device_list(void);
+
+
+int usbip_vhci_get_free_port(void);
+int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
+ uint32_t speed);
+
+/* will be removed */
+int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
+ uint8_t devnum, uint32_t speed);
+
+int usbip_vhci_detach_device(uint8_t port);
+
+int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev);
+
+#endif /* __VHCI_DRIVER_H */
diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am
new file mode 100644
index 0000000..e81a4eb
--- /dev/null
+++ b/tools/usb/usbip/src/Makefile.am
@@ -0,0 +1,11 @@
+AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
+AM_CFLAGS = @EXTRA_CFLAGS@
+LDADD = $(top_builddir)/libsrc/libusbip.la
+
+sbin_PROGRAMS := usbip usbipd
+
+usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
+ usbip_attach.c usbip_detach.c usbip_list.c \
+ usbip_bind.c usbip_unbind.c usbip_port.c
+
+usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
new file mode 100644
index 0000000..d7599d9
--- /dev/null
+++ b/tools/usb/usbip/src/usbip.c
@@ -0,0 +1,201 @@
+/*
+ * command structure borrowed from udev
+ * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
+ *
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <getopt.h>
+#include <syslog.h>
+
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static int usbip_help(int argc, char *argv[]);
+static int usbip_version(int argc, char *argv[]);
+
+static const char usbip_version_string[] = PACKAGE_STRING;
+
+static const char usbip_usage_string[] =
+ "usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
+ " [help] <command> <args>\n";
+
+static void usbip_usage(void)
+{
+ printf("usage: %s", usbip_usage_string);
+}
+
+struct command {
+ const char *name;
+ int (*fn)(int argc, char *argv[]);
+ const char *help;
+ void (*usage)(void);
+};
+
+static const struct command cmds[] = {
+ {
+ .name = "help",
+ .fn = usbip_help,
+ .help = NULL,
+ .usage = NULL
+ },
+ {
+ .name = "version",
+ .fn = usbip_version,
+ .help = NULL,
+ .usage = NULL
+ },
+ {
+ .name = "attach",
+ .fn = usbip_attach,
+ .help = "Attach a remote USB device",
+ .usage = usbip_attach_usage
+ },
+ {
+ .name = "detach",
+ .fn = usbip_detach,
+ .help = "Detach a remote USB device",
+ .usage = usbip_detach_usage
+ },
+ {
+ .name = "list",
+ .fn = usbip_list,
+ .help = "List exportable or local USB devices",
+ .usage = usbip_list_usage
+ },
+ {
+ .name = "bind",
+ .fn = usbip_bind,
+ .help = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
+ .usage = usbip_bind_usage
+ },
+ {
+ .name = "unbind",
+ .fn = usbip_unbind,
+ .help = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
+ .usage = usbip_unbind_usage
+ },
+ {
+ .name = "port",
+ .fn = usbip_port_show,
+ .help = "Show imported USB devices",
+ .usage = NULL
+ },
+ { NULL, NULL, NULL, NULL }
+};
+
+static int usbip_help(int argc, char *argv[])
+{
+ const struct command *cmd;
+ int i;
+ int ret = 0;
+
+ if (argc > 1 && argv++) {
+ for (i = 0; cmds[i].name != NULL; i++)
+ if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
+ cmds[i].usage();
+ goto done;
+ }
+ ret = -1;
+ }
+
+ usbip_usage();
+ printf("\n");
+ for (cmd = cmds; cmd->name != NULL; cmd++)
+ if (cmd->help != NULL)
+ printf(" %-10s %s\n", cmd->name, cmd->help);
+ printf("\n");
+done:
+ return ret;
+}
+
+static int usbip_version(int argc, char *argv[])
+{
+ (void) argc;
+ (void) argv;
+
+ printf(PROGNAME " (%s)\n", usbip_version_string);
+ return 0;
+}
+
+static int run_command(const struct command *cmd, int argc, char *argv[])
+{
+ dbg("running command: `%s'", cmd->name);
+ return cmd->fn(argc, argv);
+}
+
+int main(int argc, char *argv[])
+{
+ static const struct option opts[] = {
+ { "debug", no_argument, NULL, 'd' },
+ { "log", no_argument, NULL, 'l' },
+ { "tcp-port", required_argument, NULL, 't' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ char *cmd;
+ int opt;
+ int i, rc = -1;
+
+ usbip_use_stderr = 1;
+ opterr = 0;
+ for (;;) {
+ opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'd':
+ usbip_use_debug = 1;
+ break;
+ case 'l':
+ usbip_use_syslog = 1;
+ openlog("", LOG_PID, LOG_USER);
+ break;
+ case 't':
+ usbip_setup_port_number(optarg);
+ break;
+ case '?':
+ printf("usbip: invalid option\n");
+ default:
+ usbip_usage();
+ goto out;
+ }
+ }
+
+ cmd = argv[optind];
+ if (cmd) {
+ for (i = 0; cmds[i].name != NULL; i++)
+ if (!strcmp(cmds[i].name, cmd)) {
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+ rc = run_command(&cmds[i], argc, argv);
+ goto out;
+ }
+ }
+
+ /* invalid command */
+ usbip_help(0, NULL);
+out:
+ return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/tools/usb/usbip/src/usbip.h b/tools/usb/usbip/src/usbip.h
new file mode 100644
index 0000000..84fe66a
--- /dev/null
+++ b/tools/usb/usbip/src/usbip.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __USBIP_H
+#define __USBIP_H
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+/* usbip commands */
+int usbip_attach(int argc, char *argv[]);
+int usbip_detach(int argc, char *argv[]);
+int usbip_list(int argc, char *argv[]);
+int usbip_bind(int argc, char *argv[]);
+int usbip_unbind(int argc, char *argv[]);
+int usbip_port_show(int argc, char *argv[]);
+
+void usbip_attach_usage(void);
+void usbip_detach_usage(void);
+void usbip_list_usage(void);
+void usbip_bind_usage(void);
+void usbip_unbind_usage(void);
+
+#endif /* __USBIP_H */
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
new file mode 100644
index 0000000..d58a14d
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/stat.h>
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "vhci_driver.h"
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static const char usbip_attach_usage_string[] =
+ "usbip attach <args>\n"
+ " -r, --remote=<host> The machine with exported USB devices\n"
+ " -b, --busid=<busid> Busid of the device on <host>\n";
+
+void usbip_attach_usage(void)
+{
+ printf("usage: %s", usbip_attach_usage_string);
+}
+
+#define MAX_BUFF 100
+static int record_connection(char *host, char *port, char *busid, int rhport)
+{
+ int fd;
+ char path[PATH_MAX+1];
+ char buff[MAX_BUFF+1];
+ int ret;
+
+ ret = mkdir(VHCI_STATE_PATH, 0700);
+ if (ret < 0) {
+ /* if VHCI_STATE_PATH exists, then it better be a directory */
+ if (errno == EEXIST) {
+ struct stat s;
+
+ ret = stat(VHCI_STATE_PATH, &s);
+ if (ret < 0)
+ return -1;
+ if (!(s.st_mode & S_IFDIR))
+ return -1;
+ } else
+ return -1;
+ }
+
+ snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
+
+ fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
+ if (fd < 0)
+ return -1;
+
+ snprintf(buff, MAX_BUFF, "%s %s %s\n",
+ host, port, busid);
+
+ ret = write(fd, buff, strlen(buff));
+ if (ret != (ssize_t) strlen(buff)) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+static int import_device(int sockfd, struct usbip_usb_device *udev)
+{
+ int rc;
+ int port;
+
+ rc = usbip_vhci_driver_open();
+ if (rc < 0) {
+ err("open vhci_driver");
+ return -1;
+ }
+
+ port = usbip_vhci_get_free_port();
+ if (port < 0) {
+ err("no free port");
+ usbip_vhci_driver_close();
+ return -1;
+ }
+
+ rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
+ udev->devnum, udev->speed);
+ if (rc < 0) {
+ err("import device");
+ usbip_vhci_driver_close();
+ return -1;
+ }
+
+ usbip_vhci_driver_close();
+
+ return port;
+}
+
+static int query_import_device(int sockfd, char *busid)
+{
+ int rc;
+ struct op_import_request request;
+ struct op_import_reply reply;
+ uint16_t code = OP_REP_IMPORT;
+
+ memset(&request, 0, sizeof(request));
+ memset(&reply, 0, sizeof(reply));
+
+ /* send a request */
+ rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
+ if (rc < 0) {
+ err("send op_common");
+ return -1;
+ }
+
+ strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
+
+ PACK_OP_IMPORT_REQUEST(0, &request);
+
+ rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
+ if (rc < 0) {
+ err("send op_import_request");
+ return -1;
+ }
+
+ /* receive a reply */
+ rc = usbip_net_recv_op_common(sockfd, &code);
+ if (rc < 0) {
+ err("recv op_common");
+ return -1;
+ }
+
+ rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
+ if (rc < 0) {
+ err("recv op_import_reply");
+ return -1;
+ }
+
+ PACK_OP_IMPORT_REPLY(0, &reply);
+
+ /* check the reply */
+ if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
+ err("recv different busid %s", reply.udev.busid);
+ return -1;
+ }
+
+ /* import a device */
+ return import_device(sockfd, &reply.udev);
+}
+
+static int attach_device(char *host, char *busid)
+{
+ int sockfd;
+ int rc;
+ int rhport;
+
+ sockfd = usbip_net_tcp_connect(host, usbip_port_string);
+ if (sockfd < 0) {
+ err("tcp connect");
+ return -1;
+ }
+
+ rhport = query_import_device(sockfd, busid);
+ if (rhport < 0) {
+ err("query");
+ return -1;
+ }
+
+ close(sockfd);
+
+ rc = record_connection(host, usbip_port_string, busid, rhport);
+ if (rc < 0) {
+ err("record connection");
+ return -1;
+ }
+
+ return 0;
+}
+
+int usbip_attach(int argc, char *argv[])
+{
+ static const struct option opts[] = {
+ { "remote", required_argument, NULL, 'r' },
+ { "busid", required_argument, NULL, 'b' },
+ { NULL, 0, NULL, 0 }
+ };
+ char *host = NULL;
+ char *busid = NULL;
+ int opt;
+ int ret = -1;
+
+ for (;;) {
+ opt = getopt_long(argc, argv, "r:b:", opts, NULL);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'r':
+ host = optarg;
+ break;
+ case 'b':
+ busid = optarg;
+ break;
+ default:
+ goto err_out;
+ }
+ }
+
+ if (!host || !busid)
+ goto err_out;
+
+ ret = attach_device(host, busid);
+ goto out;
+
+err_out:
+ usbip_attach_usage();
+out:
+ return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c
new file mode 100644
index 0000000..fa46141
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_bind.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libudev.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#include "usbip_common.h"
+#include "utils.h"
+#include "usbip.h"
+#include "sysfs_utils.h"
+
+enum unbind_status {
+ UNBIND_ST_OK,
+ UNBIND_ST_USBIP_HOST,
+ UNBIND_ST_FAILED
+};
+
+static const char usbip_bind_usage_string[] =
+ "usbip bind <args>\n"
+ " -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device "
+ "on <busid>\n";
+
+void usbip_bind_usage(void)
+{
+ printf("usage: %s", usbip_bind_usage_string);
+}
+
+/* call at unbound state */
+static int bind_usbip(char *busid)
+{
+ char attr_name[] = "bind";
+ char bind_attr_path[SYSFS_PATH_MAX];
+ int rc = -1;
+
+ snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
+ SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
+ SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
+
+ rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
+ if (rc < 0) {
+ err("error binding device %s to driver: %s", busid,
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* buggy driver may cause dead lock */
+static int unbind_other(char *busid)
+{
+ enum unbind_status status = UNBIND_ST_OK;
+
+ char attr_name[] = "unbind";
+ char unbind_attr_path[SYSFS_PATH_MAX];
+ int rc = -1;
+
+ struct udev *udev;
+ struct udev_device *dev;
+ const char *driver;
+ const char *bDevClass;
+
+ /* Create libudev context. */
+ udev = udev_new();
+
+ /* Get the device. */
+ dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
+ if (!dev) {
+ dbg("unable to find device with bus ID %s", busid);
+ goto err_close_busid_dev;
+ }
+
+ /* Check what kind of device it is. */
+ bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass");
+ if (!bDevClass) {
+ dbg("unable to get bDevClass device attribute");
+ goto err_close_busid_dev;
+ }
+
+ if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
+ dbg("skip unbinding of hub");
+ goto err_close_busid_dev;
+ }
+
+ /* Get the device driver. */
+ driver = udev_device_get_driver(dev);
+ if (!driver) {
+ /* No driver bound to this device. */
+ goto out;
+ }
+
+ if (!strncmp(USBIP_HOST_DRV_NAME, driver,
+ strlen(USBIP_HOST_DRV_NAME))) {
+ /* Already bound to usbip-host. */
+ status = UNBIND_ST_USBIP_HOST;
+ goto out;
+ }
+
+ /* Unbind device from driver. */
+ snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
+ SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
+ SYSFS_DRIVERS_NAME, driver, attr_name);
+
+ rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
+ if (rc < 0) {
+ err("error unbinding device %s from driver", busid);
+ goto err_close_busid_dev;
+ }
+
+ goto out;
+
+err_close_busid_dev:
+ status = UNBIND_ST_FAILED;
+out:
+ udev_device_unref(dev);
+ udev_unref(udev);
+
+ return status;
+}
+
+static int bind_device(char *busid)
+{
+ int rc;
+ struct udev *udev;
+ struct udev_device *dev;
+
+ /* Check whether the device with this bus ID exists. */
+ udev = udev_new();
+ dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
+ if (!dev) {
+ err("device with the specified bus ID does not exist");
+ return -1;
+ }
+ udev_unref(udev);
+
+ rc = unbind_other(busid);
+ if (rc == UNBIND_ST_FAILED) {
+ err("could not unbind driver from device on busid %s", busid);
+ return -1;
+ } else if (rc == UNBIND_ST_USBIP_HOST) {
+ err("device on busid %s is already bound to %s", busid,
+ USBIP_HOST_DRV_NAME);
+ return -1;
+ }
+
+ rc = modify_match_busid(busid, 1);
+ if (rc < 0) {
+ err("unable to bind device on %s", busid);
+ return -1;
+ }
+
+ rc = bind_usbip(busid);
+ if (rc < 0) {
+ err("could not bind device to %s", USBIP_HOST_DRV_NAME);
+ modify_match_busid(busid, 0);
+ return -1;
+ }
+
+ info("bind device on busid %s: complete", busid);
+
+ return 0;
+}
+
+int usbip_bind(int argc, char *argv[])
+{
+ static const struct option opts[] = {
+ { "busid", required_argument, NULL, 'b' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int opt;
+ int ret = -1;
+
+ for (;;) {
+ opt = getopt_long(argc, argv, "b:", opts, NULL);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'b':
+ ret = bind_device(optarg);
+ goto out;
+ default:
+ goto err_out;
+ }
+ }
+
+err_out:
+ usbip_bind_usage();
+out:
+ return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c
new file mode 100644
index 0000000..05c6d15
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_detach.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <unistd.h>
+
+#include "vhci_driver.h"
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static const char usbip_detach_usage_string[] =
+ "usbip detach <args>\n"
+ " -p, --port=<port> " USBIP_VHCI_DRV_NAME
+ " port the device is on\n";
+
+void usbip_detach_usage(void)
+{
+ printf("usage: %s", usbip_detach_usage_string);
+}
+
+static int detach_port(char *port)
+{
+ int ret;
+ uint8_t portnum;
+ char path[PATH_MAX+1];
+
+ for (unsigned int i = 0; i < strlen(port); i++)
+ if (!isdigit(port[i])) {
+ err("invalid port %s", port);
+ return -1;
+ }
+
+ /* check max port */
+
+ portnum = atoi(port);
+
+ /* remove the port state file */
+
+ snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum);
+
+ remove(path);
+ rmdir(VHCI_STATE_PATH);
+
+ ret = usbip_vhci_driver_open();
+ if (ret < 0) {
+ err("open vhci_driver");
+ return -1;
+ }
+
+ ret = usbip_vhci_detach_device(portnum);
+ if (ret < 0)
+ return -1;
+
+ usbip_vhci_driver_close();
+
+ return ret;
+}
+
+int usbip_detach(int argc, char *argv[])
+{
+ static const struct option opts[] = {
+ { "port", required_argument, NULL, 'p' },
+ { NULL, 0, NULL, 0 }
+ };
+ int opt;
+ int ret = -1;
+
+ for (;;) {
+ opt = getopt_long(argc, argv, "p:", opts, NULL);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'p':
+ ret = detach_port(optarg);
+ goto out;
+ default:
+ goto err_out;
+ }
+ }
+
+err_out:
+ usbip_detach_usage();
+out:
+ return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
new file mode 100644
index 0000000..d5ce34a
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <libudev.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static const char usbip_list_usage_string[] =
+ "usbip list [-p|--parsable] <args>\n"
+ " -p, --parsable Parsable list format\n"
+ " -r, --remote=<host> List the exportable USB devices on <host>\n"
+ " -l, --local List the local USB devices\n";
+
+void usbip_list_usage(void)
+{
+ printf("usage: %s", usbip_list_usage_string);
+}
+
+static int get_exported_devices(char *host, int sockfd)
+{
+ char product_name[100];
+ char class_name[100];
+ struct op_devlist_reply reply;
+ uint16_t code = OP_REP_DEVLIST;
+ struct usbip_usb_device udev;
+ struct usbip_usb_interface uintf;
+ unsigned int i;
+ int rc, j;
+
+ rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
+ if (rc < 0) {
+ dbg("usbip_net_send_op_common failed");
+ return -1;
+ }
+
+ rc = usbip_net_recv_op_common(sockfd, &code);
+ if (rc < 0) {
+ dbg("usbip_net_recv_op_common failed");
+ return -1;
+ }
+
+ memset(&reply, 0, sizeof(reply));
+ rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
+ if (rc < 0) {
+ dbg("usbip_net_recv_op_devlist failed");
+ return -1;
+ }
+ PACK_OP_DEVLIST_REPLY(0, &reply);
+ dbg("exportable devices: %d\n", reply.ndev);
+
+ if (reply.ndev == 0) {
+ info("no exportable devices found on %s", host);
+ return 0;
+ }
+
+ printf("Exportable USB devices\n");
+ printf("======================\n");
+ printf(" - %s\n", host);
+
+ for (i = 0; i < reply.ndev; i++) {
+ memset(&udev, 0, sizeof(udev));
+ rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
+ if (rc < 0) {
+ dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
+ return -1;
+ }
+ usbip_net_pack_usb_device(0, &udev);
+
+ usbip_names_get_product(product_name, sizeof(product_name),
+ udev.idVendor, udev.idProduct);
+ usbip_names_get_class(class_name, sizeof(class_name),
+ udev.bDeviceClass, udev.bDeviceSubClass,
+ udev.bDeviceProtocol);
+ printf("%11s: %s\n", udev.busid, product_name);
+ printf("%11s: %s\n", "", udev.path);
+ printf("%11s: %s\n", "", class_name);
+
+ for (j = 0; j < udev.bNumInterfaces; j++) {
+ rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
+ if (rc < 0) {
+ err("usbip_net_recv failed: usbip_usb_intf[%d]",
+ j);
+
+ return -1;
+ }
+ usbip_net_pack_usb_interface(0, &uintf);
+
+ usbip_names_get_class(class_name, sizeof(class_name),
+ uintf.bInterfaceClass,
+ uintf.bInterfaceSubClass,
+ uintf.bInterfaceProtocol);
+ printf("%11s: %2d - %s\n", "", j, class_name);
+ }
+
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static int list_exported_devices(char *host)
+{
+ int rc;
+ int sockfd;
+
+ sockfd = usbip_net_tcp_connect(host, usbip_port_string);
+ if (sockfd < 0) {
+ err("could not connect to %s:%s: %s", host,
+ usbip_port_string, gai_strerror(sockfd));
+ return -1;
+ }
+ dbg("connected to %s:%s", host, usbip_port_string);
+
+ rc = get_exported_devices(host, sockfd);
+ if (rc < 0) {
+ err("failed to get device list from %s", host);
+ return -1;
+ }
+
+ close(sockfd);
+
+ return 0;
+}
+
+static void print_device(const char *busid, const char *vendor,
+ const char *product, bool parsable)
+{
+ if (parsable)
+ printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
+ else
+ printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
+}
+
+static void print_product_name(char *product_name, bool parsable)
+{
+ if (!parsable)
+ printf(" %s\n", product_name);
+}
+
+static int list_devices(bool parsable)
+{
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *dev;
+ const char *path;
+ const char *idVendor;
+ const char *idProduct;
+ const char *bConfValue;
+ const char *bNumIntfs;
+ const char *busid;
+ char product_name[128];
+ int ret = -1;
+
+ /* Create libudev context. */
+ udev = udev_new();
+
+ /* Create libudev device enumeration. */
+ enumerate = udev_enumerate_new(udev);
+
+ /* Take only USB devices that are not hubs and do not have
+ * the bInterfaceNumber attribute, i.e. are not interfaces.
+ */
+ udev_enumerate_add_match_subsystem(enumerate, "usb");
+ udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
+ udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
+ udev_enumerate_scan_devices(enumerate);
+
+ devices = udev_enumerate_get_list_entry(enumerate);
+
+ /* Show information about each device. */
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(udev, path);
+
+ /* Get device information. */
+ idVendor = udev_device_get_sysattr_value(dev, "idVendor");
+ idProduct = udev_device_get_sysattr_value(dev, "idProduct");
+ bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue");
+ bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces");
+ busid = udev_device_get_sysname(dev);
+ if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
+ err("problem getting device attributes: %s",
+ strerror(errno));
+ goto err_out;
+ }
+
+ /* Get product name. */
+ usbip_names_get_product(product_name, sizeof(product_name),
+ strtol(idVendor, NULL, 16),
+ strtol(idProduct, NULL, 16));
+
+ /* Print information. */
+ print_device(busid, idVendor, idProduct, parsable);
+ print_product_name(product_name, parsable);
+
+ printf("\n");
+
+ udev_device_unref(dev);
+ }
+
+ ret = 0;
+
+err_out:
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
+
+ return ret;
+}
+
+int usbip_list(int argc, char *argv[])
+{
+ static const struct option opts[] = {
+ { "parsable", no_argument, NULL, 'p' },
+ { "remote", required_argument, NULL, 'r' },
+ { "local", no_argument, NULL, 'l' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ bool parsable = false;
+ int opt;
+ int ret = -1;
+
+ if (usbip_names_init(USBIDS_FILE))
+ err("failed to open %s", USBIDS_FILE);
+
+ for (;;) {
+ opt = getopt_long(argc, argv, "pr:l", opts, NULL);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'p':
+ parsable = true;
+ break;
+ case 'r':
+ ret = list_exported_devices(optarg);
+ goto out;
+ case 'l':
+ ret = list_devices(parsable);
+ goto out;
+ default:
+ goto err_out;
+ }
+ }
+
+err_out:
+ usbip_list_usage();
+out:
+ usbip_names_free();
+
+ return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
new file mode 100644
index 0000000..b4c37e7
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_network.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/socket.h>
+
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <unistd.h>
+
+#ifdef HAVE_LIBWRAP
+#include <tcpd.h>
+#endif
+
+#include "usbip_common.h"
+#include "usbip_network.h"
+
+int usbip_port = 3240;
+char *usbip_port_string = "3240";
+
+void usbip_setup_port_number(char *arg)
+{
+ dbg("parsing port arg '%s'", arg);
+ char *end;
+ unsigned long int port = strtoul(arg, &end, 10);
+
+ if (end == arg) {
+ err("port: could not parse '%s' as a decimal integer", arg);
+ return;
+ }
+
+ if (*end != '\0') {
+ err("port: garbage at end of '%s'", arg);
+ return;
+ }
+
+ if (port > UINT16_MAX) {
+ err("port: %s too high (max=%d)",
+ arg, UINT16_MAX);
+ return;
+ }
+
+ usbip_port = port;
+ usbip_port_string = arg;
+ info("using port %d (\"%s\")", usbip_port, usbip_port_string);
+}
+
+void usbip_net_pack_uint32_t(int pack, uint32_t *num)
+{
+ uint32_t i;
+
+ if (pack)
+ i = htonl(*num);
+ else
+ i = ntohl(*num);
+
+ *num = i;
+}
+
+void usbip_net_pack_uint16_t(int pack, uint16_t *num)
+{
+ uint16_t i;
+
+ if (pack)
+ i = htons(*num);
+ else
+ i = ntohs(*num);
+
+ *num = i;
+}
+
+void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
+{
+ usbip_net_pack_uint32_t(pack, &udev->busnum);
+ usbip_net_pack_uint32_t(pack, &udev->devnum);
+ usbip_net_pack_uint32_t(pack, &udev->speed);
+
+ usbip_net_pack_uint16_t(pack, &udev->idVendor);
+ usbip_net_pack_uint16_t(pack, &udev->idProduct);
+ usbip_net_pack_uint16_t(pack, &udev->bcdDevice);
+}
+
+void usbip_net_pack_usb_interface(int pack __attribute__((unused)),
+ struct usbip_usb_interface *udev
+ __attribute__((unused)))
+{
+ /* uint8_t members need nothing */
+}
+
+static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
+ int sending)
+{
+ ssize_t nbytes;
+ ssize_t total = 0;
+
+ if (!bufflen)
+ return 0;
+
+ do {
+ if (sending)
+ nbytes = send(sockfd, buff, bufflen, 0);
+ else
+ nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
+
+ if (nbytes <= 0)
+ return -1;
+
+ buff = (void *)((intptr_t) buff + nbytes);
+ bufflen -= nbytes;
+ total += nbytes;
+
+ } while (bufflen > 0);
+
+ return total;
+}
+
+ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
+{
+ return usbip_net_xmit(sockfd, buff, bufflen, 0);
+}
+
+ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
+{
+ return usbip_net_xmit(sockfd, buff, bufflen, 1);
+}
+
+int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
+{
+ struct op_common op_common;
+ int rc;
+
+ memset(&op_common, 0, sizeof(op_common));
+
+ op_common.version = USBIP_VERSION;
+ op_common.code = code;
+ op_common.status = status;
+
+ PACK_OP_COMMON(1, &op_common);
+
+ rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));
+ if (rc < 0) {
+ dbg("usbip_net_send failed: %d", rc);
+ return -1;
+ }
+
+ return 0;
+}
+
+int usbip_net_recv_op_common(int sockfd, uint16_t *code)
+{
+ struct op_common op_common;
+ int rc;
+
+ memset(&op_common, 0, sizeof(op_common));
+
+ rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
+ if (rc < 0) {
+ dbg("usbip_net_recv failed: %d", rc);
+ goto err;
+ }
+
+ PACK_OP_COMMON(0, &op_common);
+
+ if (op_common.version != USBIP_VERSION) {
+ dbg("version mismatch: %d %d", op_common.version,
+ USBIP_VERSION);
+ goto err;
+ }
+
+ switch (*code) {
+ case OP_UNSPEC:
+ break;
+ default:
+ if (op_common.code != *code) {
+ dbg("unexpected pdu %#0x for %#0x", op_common.code,
+ *code);
+ goto err;
+ }
+ }
+
+ if (op_common.status != ST_OK) {
+ dbg("request failed at peer: %d", op_common.status);
+ goto err;
+ }
+
+ *code = op_common.code;
+
+ return 0;
+err:
+ return -1;
+}
+
+int usbip_net_set_reuseaddr(int sockfd)
+{
+ const int val = 1;
+ int ret;
+
+ ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+ if (ret < 0)
+ dbg("setsockopt: SO_REUSEADDR");
+
+ return ret;
+}
+
+int usbip_net_set_nodelay(int sockfd)
+{
+ const int val = 1;
+ int ret;
+
+ ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+ if (ret < 0)
+ dbg("setsockopt: TCP_NODELAY");
+
+ return ret;
+}
+
+int usbip_net_set_keepalive(int sockfd)
+{
+ const int val = 1;
+ int ret;
+
+ ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
+ if (ret < 0)
+ dbg("setsockopt: SO_KEEPALIVE");
+
+ return ret;
+}
+
+int usbip_net_set_v6only(int sockfd)
+{
+ const int val = 1;
+ int ret;
+
+ ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
+ if (ret < 0)
+ dbg("setsockopt: IPV6_V6ONLY");
+
+ return ret;
+}
+
+/*
+ * IPv6 Ready
+ */
+int usbip_net_tcp_connect(char *hostname, char *service)
+{
+ struct addrinfo hints, *res, *rp;
+ int sockfd;
+ int ret;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ /* get all possible addresses */
+ ret = getaddrinfo(hostname, service, &hints, &res);
+ if (ret < 0) {
+ dbg("getaddrinfo: %s service %s: %s", hostname, service,
+ gai_strerror(ret));
+ return ret;
+ }
+
+ /* try the addresses */
+ for (rp = res; rp; rp = rp->ai_next) {
+ sockfd = socket(rp->ai_family, rp->ai_socktype,
+ rp->ai_protocol);
+ if (sockfd < 0)
+ continue;
+
+ /* should set TCP_NODELAY for usbip */
+ usbip_net_set_nodelay(sockfd);
+ /* TODO: write code for heartbeat */
+ usbip_net_set_keepalive(sockfd);
+
+ if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
+ break;
+
+ close(sockfd);
+ }
+
+ freeaddrinfo(res);
+
+ if (!rp)
+ return EAI_SYSTEM;
+
+ return sockfd;
+}
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
new file mode 100644
index 0000000..c1e875c
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_network.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#ifndef __USBIP_NETWORK_H
+#define __USBIP_NETWORK_H
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+extern int usbip_port;
+extern char *usbip_port_string;
+void usbip_setup_port_number(char *arg);
+
+/* ---------------------------------------------------------------------- */
+/* Common header for all the kinds of PDUs. */
+struct op_common {
+ uint16_t version;
+
+#define OP_REQUEST (0x80 << 8)
+#define OP_REPLY (0x00 << 8)
+ uint16_t code;
+
+ /* add more error code */
+#define ST_OK 0x00
+#define ST_NA 0x01
+ uint32_t status; /* op_code status (for reply) */
+
+} __attribute__((packed));
+
+#define PACK_OP_COMMON(pack, op_common) do {\
+ usbip_net_pack_uint16_t(pack, &(op_common)->version);\
+ usbip_net_pack_uint16_t(pack, &(op_common)->code);\
+ usbip_net_pack_uint32_t(pack, &(op_common)->status);\
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+/* Dummy Code */
+#define OP_UNSPEC 0x00
+#define OP_REQ_UNSPEC OP_UNSPEC
+#define OP_REP_UNSPEC OP_UNSPEC
+
+/* ---------------------------------------------------------------------- */
+/* Retrieve USB device information. (still not used) */
+#define OP_DEVINFO 0x02
+#define OP_REQ_DEVINFO (OP_REQUEST | OP_DEVINFO)
+#define OP_REP_DEVINFO (OP_REPLY | OP_DEVINFO)
+
+struct op_devinfo_request {
+ char busid[SYSFS_BUS_ID_SIZE];
+} __attribute__((packed));
+
+struct op_devinfo_reply {
+ struct usbip_usb_device udev;
+ struct usbip_usb_interface uinf[];
+} __attribute__((packed));
+
+/* ---------------------------------------------------------------------- */
+/* Import a remote USB device. */
+#define OP_IMPORT 0x03
+#define OP_REQ_IMPORT (OP_REQUEST | OP_IMPORT)
+#define OP_REP_IMPORT (OP_REPLY | OP_IMPORT)
+
+struct op_import_request {
+ char busid[SYSFS_BUS_ID_SIZE];
+} __attribute__((packed));
+
+struct op_import_reply {
+ struct usbip_usb_device udev;
+// struct usbip_usb_interface uinf[];
+} __attribute__((packed));
+
+#define PACK_OP_IMPORT_REQUEST(pack, request) do {\
+} while (0)
+
+#define PACK_OP_IMPORT_REPLY(pack, reply) do {\
+ usbip_net_pack_usb_device(pack, &(reply)->udev);\
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+/* Export a USB device to a remote host. */
+#define OP_EXPORT 0x06
+#define OP_REQ_EXPORT (OP_REQUEST | OP_EXPORT)
+#define OP_REP_EXPORT (OP_REPLY | OP_EXPORT)
+
+struct op_export_request {
+ struct usbip_usb_device udev;
+} __attribute__((packed));
+
+struct op_export_reply {
+ int returncode;
+} __attribute__((packed));
+
+
+#define PACK_OP_EXPORT_REQUEST(pack, request) do {\
+ usbip_net_pack_usb_device(pack, &(request)->udev);\
+} while (0)
+
+#define PACK_OP_EXPORT_REPLY(pack, reply) do {\
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+/* un-Export a USB device from a remote host. */
+#define OP_UNEXPORT 0x07
+#define OP_REQ_UNEXPORT (OP_REQUEST | OP_UNEXPORT)
+#define OP_REP_UNEXPORT (OP_REPLY | OP_UNEXPORT)
+
+struct op_unexport_request {
+ struct usbip_usb_device udev;
+} __attribute__((packed));
+
+struct op_unexport_reply {
+ int returncode;
+} __attribute__((packed));
+
+#define PACK_OP_UNEXPORT_REQUEST(pack, request) do {\
+ usbip_net_pack_usb_device(pack, &(request)->udev);\
+} while (0)
+
+#define PACK_OP_UNEXPORT_REPLY(pack, reply) do {\
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+/* Negotiate IPSec encryption key. (still not used) */
+#define OP_CRYPKEY 0x04
+#define OP_REQ_CRYPKEY (OP_REQUEST | OP_CRYPKEY)
+#define OP_REP_CRYPKEY (OP_REPLY | OP_CRYPKEY)
+
+struct op_crypkey_request {
+ /* 128bit key */
+ uint32_t key[4];
+} __attribute__((packed));
+
+struct op_crypkey_reply {
+ uint32_t __reserved;
+} __attribute__((packed));
+
+
+/* ---------------------------------------------------------------------- */
+/* Retrieve the list of exported USB devices. */
+#define OP_DEVLIST 0x05
+#define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST)
+#define OP_REP_DEVLIST (OP_REPLY | OP_DEVLIST)
+
+struct op_devlist_request {
+} __attribute__((packed));
+
+struct op_devlist_reply {
+ uint32_t ndev;
+ /* followed by reply_extra[] */
+} __attribute__((packed));
+
+struct op_devlist_reply_extra {
+ struct usbip_usb_device udev;
+ struct usbip_usb_interface uinf[];
+} __attribute__((packed));
+
+#define PACK_OP_DEVLIST_REQUEST(pack, request) do {\
+} while (0)
+
+#define PACK_OP_DEVLIST_REPLY(pack, reply) do {\
+ usbip_net_pack_uint32_t(pack, &(reply)->ndev);\
+} while (0)
+
+void usbip_net_pack_uint32_t(int pack, uint32_t *num);
+void usbip_net_pack_uint16_t(int pack, uint16_t *num);
+void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
+void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf);
+
+ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen);
+ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen);
+int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status);
+int usbip_net_recv_op_common(int sockfd, uint16_t *code);
+int usbip_net_set_reuseaddr(int sockfd);
+int usbip_net_set_nodelay(int sockfd);
+int usbip_net_set_keepalive(int sockfd);
+int usbip_net_set_v6only(int sockfd);
+int usbip_net_tcp_connect(char *hostname, char *port);
+
+#endif /* __USBIP_NETWORK_H */
diff --git a/tools/usb/usbip/src/usbip_port.c b/tools/usb/usbip/src/usbip_port.c
new file mode 100644
index 0000000..a2e884fd
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_port.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "vhci_driver.h"
+#include "usbip_common.h"
+
+static int list_imported_devices(void)
+{
+ int i;
+ struct usbip_imported_device *idev;
+ int ret;
+
+ ret = usbip_vhci_driver_open();
+ if (ret < 0) {
+ err("open vhci_driver");
+ return -1;
+ }
+
+ printf("Imported USB devices\n");
+ printf("====================\n");
+
+ for (i = 0; i < vhci_driver->nports; i++) {
+ idev = &vhci_driver->idev[i];
+
+ if (usbip_vhci_imported_device_dump(idev) < 0)
+ ret = -1;
+ }
+
+ usbip_vhci_driver_close();
+
+ return ret;
+
+}
+
+int usbip_port_show(__attribute__((unused)) int argc,
+ __attribute__((unused)) char *argv[])
+{
+ int ret;
+
+ ret = list_imported_devices();
+ if (ret < 0)
+ err("list imported devices");
+
+ return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_unbind.c b/tools/usb/usbip/src/usbip_unbind.c
new file mode 100644
index 0000000..a4a496c
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_unbind.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libudev.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#include "usbip_common.h"
+#include "utils.h"
+#include "usbip.h"
+#include "sysfs_utils.h"
+
+static const char usbip_unbind_usage_string[] =
+ "usbip unbind <args>\n"
+ " -b, --busid=<busid> Unbind " USBIP_HOST_DRV_NAME ".ko from "
+ "device on <busid>\n";
+
+void usbip_unbind_usage(void)
+{
+ printf("usage: %s", usbip_unbind_usage_string);
+}
+
+static int unbind_device(char *busid)
+{
+ char bus_type[] = "usb";
+ int rc, ret = -1;
+
+ char unbind_attr_name[] = "unbind";
+ char unbind_attr_path[SYSFS_PATH_MAX];
+ char rebind_attr_name[] = "rebind";
+ char rebind_attr_path[SYSFS_PATH_MAX];
+
+ struct udev *udev;
+ struct udev_device *dev;
+ const char *driver;
+
+ /* Create libudev context. */
+ udev = udev_new();
+
+ /* Check whether the device with this bus ID exists. */
+ dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
+ if (!dev) {
+ err("device with the specified bus ID does not exist");
+ goto err_close_udev;
+ }
+
+ /* Check whether the device is using usbip-host driver. */
+ driver = udev_device_get_driver(dev);
+ if (!driver || strcmp(driver, "usbip-host")) {
+ err("device is not bound to usbip-host driver");
+ goto err_close_udev;
+ }
+
+ /* Unbind device from driver. */
+ snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
+ SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
+ USBIP_HOST_DRV_NAME, unbind_attr_name);
+
+ rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
+ if (rc < 0) {
+ err("error unbinding device %s from driver", busid);
+ goto err_close_udev;
+ }
+
+ /* Notify driver of unbind. */
+ rc = modify_match_busid(busid, 0);
+ if (rc < 0) {
+ err("unable to unbind device on %s", busid);
+ goto err_close_udev;
+ }
+
+ /* Trigger new probing. */
+ snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
+ SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
+ USBIP_HOST_DRV_NAME, rebind_attr_name);
+
+ rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid));
+ if (rc < 0) {
+ err("error rebinding");
+ goto err_close_udev;
+ }
+
+ ret = 0;
+ info("unbind device on busid %s: complete", busid);
+
+err_close_udev:
+ udev_device_unref(dev);
+ udev_unref(udev);
+
+ return ret;
+}
+
+int usbip_unbind(int argc, char *argv[])
+{
+ static const struct option opts[] = {
+ { "busid", required_argument, NULL, 'b' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int opt;
+ int ret = -1;
+
+ for (;;) {
+ opt = getopt_long(argc, argv, "b:", opts, NULL);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'b':
+ ret = unbind_device(optarg);
+ goto out;
+ default:
+ goto err_out;
+ }
+ }
+
+err_out:
+ usbip_unbind_usage();
+out:
+ return ret;
+}
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
new file mode 100644
index 0000000..2f87f2d
--- /dev/null
+++ b/tools/usb/usbip/src/usbipd.c
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#ifdef HAVE_LIBWRAP
+#include <tcpd.h>
+#endif
+
+#include <getopt.h>
+#include <signal.h>
+#include <poll.h>
+
+#include "usbip_host_driver.h"
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "list.h"
+
+#undef PROGNAME
+#define PROGNAME "usbipd"
+#define MAXSOCKFD 20
+
+#define MAIN_LOOP_TIMEOUT 10
+
+#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
+
+static const char usbip_version_string[] = PACKAGE_STRING;
+
+static const char usbipd_help_string[] =
+ "usage: usbipd [options]\n"
+ "\n"
+ " -4, --ipv4\n"
+ " Bind to IPv4. Default is both.\n"
+ "\n"
+ " -6, --ipv6\n"
+ " Bind to IPv6. Default is both.\n"
+ "\n"
+ " -D, --daemon\n"
+ " Run as a daemon process.\n"
+ "\n"
+ " -d, --debug\n"
+ " Print debugging information.\n"
+ "\n"
+ " -PFILE, --pid FILE\n"
+ " Write process id to FILE.\n"
+ " If no FILE specified, use " DEFAULT_PID_FILE "\n"
+ "\n"
+ " -tPORT, --tcp-port PORT\n"
+ " Listen on TCP/IP port PORT.\n"
+ "\n"
+ " -h, --help\n"
+ " Print this help.\n"
+ "\n"
+ " -v, --version\n"
+ " Show version.\n";
+
+static void usbipd_help(void)
+{
+ printf("%s\n", usbipd_help_string);
+}
+
+static int recv_request_import(int sockfd)
+{
+ struct op_import_request req;
+ struct op_common reply;
+ struct usbip_exported_device *edev;
+ struct usbip_usb_device pdu_udev;
+ struct list_head *i;
+ int found = 0;
+ int error = 0;
+ int rc;
+
+ memset(&req, 0, sizeof(req));
+ memset(&reply, 0, sizeof(reply));
+
+ rc = usbip_net_recv(sockfd, &req, sizeof(req));
+ if (rc < 0) {
+ dbg("usbip_net_recv failed: import request");
+ return -1;
+ }
+ PACK_OP_IMPORT_REQUEST(0, &req);
+
+ list_for_each(i, &host_driver->edev_list) {
+ edev = list_entry(i, struct usbip_exported_device, node);
+ if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) {
+ info("found requested device: %s", req.busid);
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ /* should set TCP_NODELAY for usbip */
+ usbip_net_set_nodelay(sockfd);
+
+ /* export device needs a TCP/IP socket descriptor */
+ rc = usbip_host_export_device(edev, sockfd);
+ if (rc < 0)
+ error = 1;
+ } else {
+ info("requested device not found: %s", req.busid);
+ error = 1;
+ }
+
+ rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
+ (!error ? ST_OK : ST_NA));
+ if (rc < 0) {
+ dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
+ return -1;
+ }
+
+ if (error) {
+ dbg("import request busid %s: failed", req.busid);
+ return -1;
+ }
+
+ memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
+ usbip_net_pack_usb_device(1, &pdu_udev);
+
+ rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
+ if (rc < 0) {
+ dbg("usbip_net_send failed: devinfo");
+ return -1;
+ }
+
+ dbg("import request busid %s: complete", req.busid);
+
+ return 0;
+}
+
+static int send_reply_devlist(int connfd)
+{
+ struct usbip_exported_device *edev;
+ struct usbip_usb_device pdu_udev;
+ struct usbip_usb_interface pdu_uinf;
+ struct op_devlist_reply reply;
+ struct list_head *j;
+ int rc, i;
+
+ reply.ndev = 0;
+ /* number of exported devices */
+ list_for_each(j, &host_driver->edev_list) {
+ reply.ndev += 1;
+ }
+ info("exportable devices: %d", reply.ndev);
+
+ rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
+ if (rc < 0) {
+ dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
+ return -1;
+ }
+ PACK_OP_DEVLIST_REPLY(1, &reply);
+
+ rc = usbip_net_send(connfd, &reply, sizeof(reply));
+ if (rc < 0) {
+ dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
+ return -1;
+ }
+
+ list_for_each(j, &host_driver->edev_list) {
+ edev = list_entry(j, struct usbip_exported_device, node);
+ dump_usb_device(&edev->udev);
+ memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
+ usbip_net_pack_usb_device(1, &pdu_udev);
+
+ rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
+ if (rc < 0) {
+ dbg("usbip_net_send failed: pdu_udev");
+ return -1;
+ }
+
+ for (i = 0; i < edev->udev.bNumInterfaces; i++) {
+ dump_usb_interface(&edev->uinf[i]);
+ memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
+ usbip_net_pack_usb_interface(1, &pdu_uinf);
+
+ rc = usbip_net_send(connfd, &pdu_uinf,
+ sizeof(pdu_uinf));
+ if (rc < 0) {
+ err("usbip_net_send failed: pdu_uinf");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int recv_request_devlist(int connfd)
+{
+ struct op_devlist_request req;
+ int rc;
+
+ memset(&req, 0, sizeof(req));
+
+ rc = usbip_net_recv(connfd, &req, sizeof(req));
+ if (rc < 0) {
+ dbg("usbip_net_recv failed: devlist request");
+ return -1;
+ }
+
+ rc = send_reply_devlist(connfd);
+ if (rc < 0) {
+ dbg("send_reply_devlist failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int recv_pdu(int connfd)
+{
+ uint16_t code = OP_UNSPEC;
+ int ret;
+
+ ret = usbip_net_recv_op_common(connfd, &code);
+ if (ret < 0) {
+ dbg("could not receive opcode: %#0x", code);
+ return -1;
+ }
+
+ ret = usbip_host_refresh_device_list();
+ if (ret < 0) {
+ dbg("could not refresh device list: %d", ret);
+ return -1;
+ }
+
+ info("received request: %#0x(%d)", code, connfd);
+ switch (code) {
+ case OP_REQ_DEVLIST:
+ ret = recv_request_devlist(connfd);
+ break;
+ case OP_REQ_IMPORT:
+ ret = recv_request_import(connfd);
+ break;
+ case OP_REQ_DEVINFO:
+ case OP_REQ_CRYPKEY:
+ default:
+ err("received an unknown opcode: %#0x", code);
+ ret = -1;
+ }
+
+ if (ret == 0)
+ info("request %#0x(%d): complete", code, connfd);
+ else
+ info("request %#0x(%d): failed", code, connfd);
+
+ return ret;
+}
+
+#ifdef HAVE_LIBWRAP
+static int tcpd_auth(int connfd)
+{
+ struct request_info request;
+ int rc;
+
+ request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
+ fromhost(&request);
+ rc = hosts_access(&request);
+ if (rc == 0)
+ return -1;
+
+ return 0;
+}
+#endif
+
+static int do_accept(int listenfd)
+{
+ int connfd;
+ struct sockaddr_storage ss;
+ socklen_t len = sizeof(ss);
+ char host[NI_MAXHOST], port[NI_MAXSERV];
+ int rc;
+
+ memset(&ss, 0, sizeof(ss));
+
+ connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
+ if (connfd < 0) {
+ err("failed to accept connection");
+ return -1;
+ }
+
+ rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
+ if (rc)
+ err("getnameinfo: %s", gai_strerror(rc));
+
+#ifdef HAVE_LIBWRAP
+ rc = tcpd_auth(connfd);
+ if (rc < 0) {
+ info("denied access from %s", host);
+ close(connfd);
+ return -1;
+ }
+#endif
+ info("connection from %s:%s", host, port);
+
+ return connfd;
+}
+
+int process_request(int listenfd)
+{
+ pid_t childpid;
+ int connfd;
+
+ connfd = do_accept(listenfd);
+ if (connfd < 0)
+ return -1;
+ childpid = fork();
+ if (childpid == 0) {
+ close(listenfd);
+ recv_pdu(connfd);
+ exit(0);
+ }
+ close(connfd);
+ return 0;
+}
+
+static void addrinfo_to_text(struct addrinfo *ai, char buf[],
+ const size_t buf_size)
+{
+ char hbuf[NI_MAXHOST];
+ char sbuf[NI_MAXSERV];
+ int rc;
+
+ buf[0] = '\0';
+
+ rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
+ sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
+ if (rc)
+ err("getnameinfo: %s", gai_strerror(rc));
+
+ snprintf(buf, buf_size, "%s:%s", hbuf, sbuf);
+}
+
+static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[],
+ int maxsockfd)
+{
+ struct addrinfo *ai;
+ int ret, nsockfd = 0;
+ const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2;
+ char ai_buf[ai_buf_size];
+
+ for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) {
+ int sock;
+
+ addrinfo_to_text(ai, ai_buf, ai_buf_size);
+ dbg("opening %s", ai_buf);
+ sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sock < 0) {
+ err("socket: %s: %d (%s)",
+ ai_buf, errno, strerror(errno));
+ continue;
+ }
+
+ usbip_net_set_reuseaddr(sock);
+ usbip_net_set_nodelay(sock);
+ /* We use seperate sockets for IPv4 and IPv6
+ * (see do_standalone_mode()) */
+ usbip_net_set_v6only(sock);
+
+ if (sock >= FD_SETSIZE) {
+ err("FD_SETSIZE: %s: sock=%d, max=%d",
+ ai_buf, sock, FD_SETSIZE);
+ close(sock);
+ continue;
+ }
+
+ ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
+ if (ret < 0) {
+ err("bind: %s: %d (%s)",
+ ai_buf, errno, strerror(errno));
+ close(sock);
+ continue;
+ }
+
+ ret = listen(sock, SOMAXCONN);
+ if (ret < 0) {
+ err("listen: %s: %d (%s)",
+ ai_buf, errno, strerror(errno));
+ close(sock);
+ continue;
+ }
+
+ info("listening on %s", ai_buf);
+ sockfdlist[nsockfd++] = sock;
+ }
+
+ return nsockfd;
+}
+
+static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
+{
+ struct addrinfo hints, *ai_head;
+ int rc;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = ai_family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+
+ rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head);
+ if (rc) {
+ err("failed to get a network address %s: %s", usbip_port_string,
+ gai_strerror(rc));
+ return NULL;
+ }
+
+ return ai_head;
+}
+
+static void signal_handler(int i)
+{
+ dbg("received '%s' signal", strsignal(i));
+}
+
+static void set_signal(void)
+{
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = signal_handler;
+ sigemptyset(&act.sa_mask);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGINT, &act, NULL);
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGCLD, &act, NULL);
+}
+
+static const char *pid_file;
+
+static void write_pid_file(void)
+{
+ if (pid_file) {
+ dbg("creating pid file %s", pid_file);
+ FILE *fp;
+
+ fp = fopen(pid_file, "w");
+ if (!fp) {
+ err("pid_file: %s: %d (%s)",
+ pid_file, errno, strerror(errno));
+ return;
+ }
+ fprintf(fp, "%d\n", getpid());
+ fclose(fp);
+ }
+}
+
+static void remove_pid_file(void)
+{
+ if (pid_file) {
+ dbg("removing pid file %s", pid_file);
+ unlink(pid_file);
+ }
+}
+
+static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
+{
+ struct addrinfo *ai_head;
+ int sockfdlist[MAXSOCKFD];
+ int nsockfd, family;
+ int i, terminate;
+ struct pollfd *fds;
+ struct timespec timeout;
+ sigset_t sigmask;
+
+ if (usbip_host_driver_open()) {
+ err("please load " USBIP_CORE_MOD_NAME ".ko and "
+ USBIP_HOST_DRV_NAME ".ko!");
+ return -1;
+ }
+
+ if (daemonize) {
+ if (daemon(0, 0) < 0) {
+ err("daemonizing failed: %s", strerror(errno));
+ usbip_host_driver_close();
+ return -1;
+ }
+ umask(0);
+ usbip_use_syslog = 1;
+ }
+ set_signal();
+ write_pid_file();
+
+ info("starting " PROGNAME " (%s)", usbip_version_string);
+
+ /*
+ * To suppress warnings on systems with bindv6only disabled
+ * (default), we use seperate sockets for IPv6 and IPv4 and set
+ * IPV6_V6ONLY on the IPv6 sockets.
+ */
+ if (ipv4 && ipv6)
+ family = AF_UNSPEC;
+ else if (ipv4)
+ family = AF_INET;
+ else
+ family = AF_INET6;
+
+ ai_head = do_getaddrinfo(NULL, family);
+ if (!ai_head) {
+ usbip_host_driver_close();
+ return -1;
+ }
+ nsockfd = listen_all_addrinfo(ai_head, sockfdlist,
+ sizeof(sockfdlist) / sizeof(*sockfdlist));
+ freeaddrinfo(ai_head);
+ if (nsockfd <= 0) {
+ err("failed to open a listening socket");
+ usbip_host_driver_close();
+ return -1;
+ }
+
+ dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es");
+
+ fds = calloc(nsockfd, sizeof(struct pollfd));
+ for (i = 0; i < nsockfd; i++) {
+ fds[i].fd = sockfdlist[i];
+ fds[i].events = POLLIN;
+ }
+ timeout.tv_sec = MAIN_LOOP_TIMEOUT;
+ timeout.tv_nsec = 0;
+
+ sigfillset(&sigmask);
+ sigdelset(&sigmask, SIGTERM);
+ sigdelset(&sigmask, SIGINT);
+
+ terminate = 0;
+ while (!terminate) {
+ int r;
+
+ r = ppoll(fds, nsockfd, &timeout, &sigmask);
+ if (r < 0) {
+ dbg("%s", strerror(errno));
+ terminate = 1;
+ } else if (r) {
+ for (i = 0; i < nsockfd; i++) {
+ if (fds[i].revents & POLLIN) {
+ dbg("read event on fd[%d]=%d",
+ i, sockfdlist[i]);
+ process_request(sockfdlist[i]);
+ }
+ }
+ } else {
+ dbg("heartbeat timeout on ppoll()");
+ }
+ }
+
+ info("shutting down " PROGNAME);
+ free(fds);
+ usbip_host_driver_close();
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ static const struct option longopts[] = {
+ { "ipv4", no_argument, NULL, '4' },
+ { "ipv6", no_argument, NULL, '6' },
+ { "daemon", no_argument, NULL, 'D' },
+ { "daemon", no_argument, NULL, 'D' },
+ { "debug", no_argument, NULL, 'd' },
+ { "pid", optional_argument, NULL, 'P' },
+ { "tcp-port", required_argument, NULL, 't' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ enum {
+ cmd_standalone_mode = 1,
+ cmd_help,
+ cmd_version
+ } cmd;
+
+ int daemonize = 0;
+ int ipv4 = 0, ipv6 = 0;
+ int opt, rc = -1;
+
+ pid_file = NULL;
+
+ usbip_use_stderr = 1;
+ usbip_use_syslog = 0;
+
+ if (geteuid() != 0)
+ err("not running as root?");
+
+ cmd = cmd_standalone_mode;
+ for (;;) {
+ opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case '4':
+ ipv4 = 1;
+ break;
+ case '6':
+ ipv6 = 1;
+ break;
+ case 'D':
+ daemonize = 1;
+ break;
+ case 'd':
+ usbip_use_debug = 1;
+ break;
+ case 'h':
+ cmd = cmd_help;
+ break;
+ case 'P':
+ pid_file = optarg ? optarg : DEFAULT_PID_FILE;
+ break;
+ case 't':
+ usbip_setup_port_number(optarg);
+ break;
+ case 'v':
+ cmd = cmd_version;
+ break;
+ case '?':
+ usbipd_help();
+ default:
+ goto err_out;
+ }
+ }
+
+ if (!ipv4 && !ipv6)
+ ipv4 = ipv6 = 1;
+
+ switch (cmd) {
+ case cmd_standalone_mode:
+ rc = do_standalone_mode(daemonize, ipv4, ipv6);
+ remove_pid_file();
+ break;
+ case cmd_version:
+ printf(PROGNAME " (%s)\n", usbip_version_string);
+ rc = 0;
+ break;
+ case cmd_help:
+ usbipd_help();
+ rc = 0;
+ break;
+ default:
+ usbipd_help();
+ goto err_out;
+ }
+
+err_out:
+ return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c
new file mode 100644
index 0000000..2b3d6d2
--- /dev/null
+++ b/tools/usb/usbip/src/utils.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "usbip_common.h"
+#include "utils.h"
+#include "sysfs_utils.h"
+
+int modify_match_busid(char *busid, int add)
+{
+ char attr_name[] = "match_busid";
+ char command[SYSFS_BUS_ID_SIZE + 4];
+ char match_busid_attr_path[SYSFS_PATH_MAX];
+ int rc;
+
+ snprintf(match_busid_attr_path, sizeof(match_busid_attr_path),
+ "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME,
+ SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME,
+ attr_name);
+
+ if (add)
+ snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid);
+ else
+ snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid);
+
+ rc = write_sysfs_attribute(match_busid_attr_path, command,
+ sizeof(command));
+ if (rc < 0) {
+ dbg("failed to write match_busid: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/tools/usb/usbip/src/utils.h b/tools/usb/usbip/src/utils.h
new file mode 100644
index 0000000..5916fd3
--- /dev/null
+++ b/tools/usb/usbip/src/utils.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UTILS_H
+#define __UTILS_H
+
+int modify_match_busid(char *busid, int add);
+
+#endif /* __UTILS_H */
+
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index c4d6d2e..264fbc2 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -132,6 +132,7 @@ static const char * const page_flag_names[] = {
[KPF_NOPAGE] = "n:nopage",
[KPF_KSM] = "x:ksm",
[KPF_THP] = "t:thp",
+ [KPF_BALLOON] = "o:balloon",
[KPF_RESERVED] = "r:reserved",
[KPF_MLOCKED] = "m:mlocked",