diff options
Diffstat (limited to 'tools')
166 files changed, 3989 insertions, 3398 deletions
diff --git a/tools/arch/x86/include/uapi/asm/unistd_32.h b/tools/arch/x86/include/uapi/asm/unistd_32.h index bc48a4dabe5d..4798f9d18fe8 100644 --- a/tools/arch/x86/include/uapi/asm/unistd_32.h +++ b/tools/arch/x86/include/uapi/asm/unistd_32.h @@ -26,3 +26,6 @@ #ifndef __NR_setns #define __NR_setns 346 #endif +#ifdef __NR_seccomp +#define __NR_seccomp 354 +#endif diff --git a/tools/arch/x86/include/uapi/asm/unistd_64.h b/tools/arch/x86/include/uapi/asm/unistd_64.h index f70d2cada256..d0f2043d7132 100644 --- a/tools/arch/x86/include/uapi/asm/unistd_64.h +++ b/tools/arch/x86/include/uapi/asm/unistd_64.h @@ -26,3 +26,6 @@ #ifndef __NR_getcpu #define __NR_getcpu 309 #endif +#ifndef __NR_seccomp +#define __NR_seccomp 317 +#endif diff --git a/tools/crypto/ccp/.gitignore b/tools/crypto/ccp/.gitignore new file mode 100644 index 000000000000..bee8a64b79a9 --- /dev/null +++ b/tools/crypto/ccp/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/tools/crypto/ccp/Makefile b/tools/crypto/ccp/Makefile new file mode 100644 index 000000000000..ae4a66d1558a --- /dev/null +++ b/tools/crypto/ccp/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +CFLAGS += -D__EXPORTED_HEADERS__ -I../../../include/uapi -I../../../include + +TARGET = dbc_library.so + +all: $(TARGET) + +dbc_library.so: dbc.c + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< + chmod -x $@ + +clean: + $(RM) $(TARGET) diff --git a/tools/crypto/ccp/dbc.c b/tools/crypto/ccp/dbc.c new file mode 100644 index 000000000000..37e813175642 --- /dev/null +++ b/tools/crypto/ccp/dbc.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AMD Secure Processor Dynamic Boost Control sample library + * + * Copyright (C) 2023 Advanced Micro Devices, Inc. + * + * Author: Mario Limonciello <mario.limonciello@amd.com> + */ + +#include <assert.h> +#include <string.h> +#include <sys/ioctl.h> + +/* if uapi header isn't installed, this might not yet exist */ +#ifndef __packed +#define __packed __attribute__((packed)) +#endif +#include <linux/psp-dbc.h> + +int get_nonce(int fd, void *nonce_out, void *signature) +{ + struct dbc_user_nonce tmp = { + .auth_needed = !!signature, + }; + int ret; + + assert(nonce_out); + + if (signature) + memcpy(tmp.signature, signature, sizeof(tmp.signature)); + + ret = ioctl(fd, DBCIOCNONCE, &tmp); + if (ret) + return ret; + memcpy(nonce_out, tmp.nonce, sizeof(tmp.nonce)); + + return 0; +} + +int set_uid(int fd, __u8 *uid, __u8 *signature) +{ + struct dbc_user_setuid tmp; + + assert(uid); + assert(signature); + + memcpy(tmp.uid, uid, sizeof(tmp.uid)); + memcpy(tmp.signature, signature, sizeof(tmp.signature)); + + return ioctl(fd, DBCIOCUID, &tmp); +} + +int process_param(int fd, int msg_index, __u8 *signature, int *data) +{ + struct dbc_user_param tmp = { + .msg_index = msg_index, + .param = *data, + }; + int ret; + + assert(signature); + assert(data); + + memcpy(tmp.signature, signature, sizeof(tmp.signature)); + + ret = ioctl(fd, DBCIOCPARAM, &tmp); + if (ret) + return ret; + + *data = tmp.param; + return 0; +} diff --git a/tools/crypto/ccp/dbc.py b/tools/crypto/ccp/dbc.py new file mode 100644 index 000000000000..3f6a825ffc9e --- /dev/null +++ b/tools/crypto/ccp/dbc.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0 + +import ctypes +import os + +DBC_UID_SIZE = 16 +DBC_NONCE_SIZE = 16 +DBC_SIG_SIZE = 32 + +PARAM_GET_FMAX_CAP = (0x3,) +PARAM_SET_FMAX_CAP = (0x4,) +PARAM_GET_PWR_CAP = (0x5,) +PARAM_SET_PWR_CAP = (0x6,) +PARAM_GET_GFX_MODE = (0x7,) +PARAM_SET_GFX_MODE = (0x8,) +PARAM_GET_CURR_TEMP = (0x9,) +PARAM_GET_FMAX_MAX = (0xA,) +PARAM_GET_FMAX_MIN = (0xB,) +PARAM_GET_SOC_PWR_MAX = (0xC,) +PARAM_GET_SOC_PWR_MIN = (0xD,) +PARAM_GET_SOC_PWR_CUR = (0xE,) + +DEVICE_NODE = "/dev/dbc" + +lib = ctypes.CDLL("./dbc_library.so", mode=ctypes.RTLD_GLOBAL) + + +def handle_error(code): + val = code * -1 + raise OSError(val, os.strerror(val)) + + +def get_nonce(device, signature): + if not device: + raise ValueError("Device required") + buf = ctypes.create_string_buffer(DBC_NONCE_SIZE) + ret = lib.get_nonce(device.fileno(), ctypes.byref(buf), signature) + if ret: + handle_error(ret) + return buf.value + + +def set_uid(device, new_uid, signature): + if not signature: + raise ValueError("Signature required") + if not new_uid: + raise ValueError("UID required") + ret = lib.set_uid(device.fileno(), new_uid, signature) + if ret: + handle_error(ret) + return True + + +def process_param(device, message, signature, data=None): + if not signature: + raise ValueError("Signature required") + if type(message) != tuple: + raise ValueError("Expected message tuple") + arg = ctypes.c_int(data if data else 0) + ret = lib.process_param(device.fileno(), message[0], signature, ctypes.pointer(arg)) + if ret: + handle_error(ret) + return arg, signature diff --git a/tools/crypto/ccp/dbc_cli.py b/tools/crypto/ccp/dbc_cli.py new file mode 100755 index 000000000000..bf52233fd038 --- /dev/null +++ b/tools/crypto/ccp/dbc_cli.py @@ -0,0 +1,134 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0 +import argparse +import binascii +import os +import errno +from dbc import * + +ERRORS = { + errno.EACCES: "Access is denied", + errno.E2BIG: "Excess data provided", + errno.EINVAL: "Bad parameters", + errno.EAGAIN: "Bad state", + errno.ENOENT: "Not implemented or message failure", + errno.EBUSY: "Busy", + errno.ENFILE: "Overflow", + errno.EPERM: "Signature invalid", +} + +messages = { + "get-fmax-cap": PARAM_GET_FMAX_CAP, + "set-fmax-cap": PARAM_SET_FMAX_CAP, + "get-power-cap": PARAM_GET_PWR_CAP, + "set-power-cap": PARAM_SET_PWR_CAP, + "get-graphics-mode": PARAM_GET_GFX_MODE, + "set-graphics-mode": PARAM_SET_GFX_MODE, + "get-current-temp": PARAM_GET_CURR_TEMP, + "get-fmax-max": PARAM_GET_FMAX_MAX, + "get-fmax-min": PARAM_GET_FMAX_MIN, + "get-soc-power-max": PARAM_GET_SOC_PWR_MAX, + "get-soc-power-min": PARAM_GET_SOC_PWR_MIN, + "get-soc-power-cur": PARAM_GET_SOC_PWR_CUR, +} + + +def _pretty_buffer(ba): + return str(binascii.hexlify(ba, " ")) + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Dynamic Boost control command line interface" + ) + parser.add_argument( + "command", + choices=["get-nonce", "get-param", "set-param", "set-uid"], + help="Command to send", + ) + parser.add_argument("--device", default="/dev/dbc", help="Device to operate") + parser.add_argument("--signature", help="File containing signature for command") + parser.add_argument("--message", choices=messages.keys(), help="Message index") + parser.add_argument("--data", help="Argument to pass to message") + parser.add_argument("--uid", help="File containing UID to pass") + return parser.parse_args() + + +def pretty_error(code): + if code in ERRORS: + print(ERRORS[code]) + else: + print("failed with return code %d" % code) + + +if __name__ == "__main__": + args = parse_args() + data = 0 + sig = None + uid = None + if not os.path.exists(args.device): + raise IOError("Missing device {device}".format(device=args.device)) + if args.signature: + if not os.path.exists(args.signature): + raise ValueError("Invalid signature file %s" % args.signature) + with open(args.signature, "rb") as f: + sig = f.read() + if len(sig) != DBC_SIG_SIZE: + raise ValueError( + "Invalid signature length %d (expected %d)" % (len(sig), DBC_SIG_SIZE) + ) + if args.uid: + if not os.path.exists(args.uid): + raise ValueError("Invalid uid file %s" % args.uid) + with open(args.uid, "rb") as f: + uid = f.read() + if len(uid) != DBC_UID_SIZE: + raise ValueError( + "Invalid UID length %d (expected %d)" % (len(uid), DBC_UID_SIZE) + ) + if args.data: + try: + data = int(args.data, 10) + except ValueError: + data = int(args.data, 16) + + with open(args.device) as d: + if args.command == "get-nonce": + try: + nonce = get_nonce(d, sig) + print("Nonce: %s" % _pretty_buffer(bytes(nonce))) + except OSError as e: + pretty_error(e.errno) + elif args.command == "set-uid": + try: + result = set_uid(d, uid, sig) + if result: + print("Set UID") + except OSError as e: + pretty_error(e.errno) + elif args.command == "get-param": + if not args.message or args.message.startswith("set"): + raise ValueError("Invalid message %s" % args.message) + try: + param, signature = process_param(d, messages[args.message], sig) + print( + "Parameter: {par}, response signature {sig}".format( + par=param, + sig=_pretty_buffer(bytes(signature)), + ) + ) + except OSError as e: + pretty_error(e.errno) + elif args.command == "set-param": + if not args.message or args.message.startswith("get"): + raise ValueError("Invalid message %s" % args.message) + try: + param, signature = process_param(d, messages[args.message], sig, data) + print( + "Parameter: {par}, response signature {sig}".format( + par=param, + sig=_pretty_buffer(bytes(signature)), + ) + ) + except OSError as e: + pretty_error(e.errno) diff --git a/tools/crypto/ccp/test_dbc.py b/tools/crypto/ccp/test_dbc.py new file mode 100755 index 000000000000..998bb3e3cd04 --- /dev/null +++ b/tools/crypto/ccp/test_dbc.py @@ -0,0 +1,266 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0 +import unittest +import os +import time +import glob +from dbc import * + +# Artificial delay between set commands +SET_DELAY = 0.5 + + +class invalid_param(ctypes.Structure): + _fields_ = [ + ("data", ctypes.c_uint8), + ] + + +def system_is_secured() -> bool: + fused_part = glob.glob("/sys/bus/pci/drivers/ccp/**/fused_part")[0] + if os.path.exists(fused_part): + with open(fused_part, "r") as r: + return int(r.read()) == 1 + return True + + +class DynamicBoostControlTest(unittest.TestCase): + def __init__(self, data) -> None: + self.d = None + self.signature = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + self.uid = "1111111111111111" + super().__init__(data) + + def setUp(self) -> None: + self.d = open(DEVICE_NODE) + return super().setUp() + + def tearDown(self) -> None: + if self.d: + self.d.close() + return super().tearDown() + + +class TestUnsupportedSystem(DynamicBoostControlTest): + def setUp(self) -> None: + if os.path.exists(DEVICE_NODE): + self.skipTest("system is supported") + with self.assertRaises(FileNotFoundError) as error: + super().setUp() + self.assertEqual(error.exception.errno, 2) + + def test_unauthenticated_nonce(self) -> None: + """fetch unauthenticated nonce""" + with self.assertRaises(ValueError) as error: + get_nonce(self.d, None) + + +class TestInvalidIoctls(DynamicBoostControlTest): + def __init__(self, data) -> None: + self.data = invalid_param() + self.data.data = 1 + super().__init__(data) + + def setUp(self) -> None: + if not os.path.exists(DEVICE_NODE): + self.skipTest("system is unsupported") + return super().setUp() + + def test_invalid_nonce_ioctl(self) -> None: + """tries to call get_nonce ioctl with invalid data structures""" + + # 0x1 (get nonce), and invalid data + INVALID1 = IOWR(ord("D"), 0x01, invalid_param) + with self.assertRaises(OSError) as error: + fcntl.ioctl(self.d, INVALID1, self.data, True) + self.assertEqual(error.exception.errno, 22) + + def test_invalid_setuid_ioctl(self) -> None: + """tries to call set_uid ioctl with invalid data structures""" + + # 0x2 (set uid), and invalid data + INVALID2 = IOW(ord("D"), 0x02, invalid_param) + with self.assertRaises(OSError) as error: + fcntl.ioctl(self.d, INVALID2, self.data, True) + self.assertEqual(error.exception.errno, 22) + + def test_invalid_setuid_rw_ioctl(self) -> None: + """tries to call set_uid ioctl with invalid data structures""" + + # 0x2 as RW (set uid), and invalid data + INVALID3 = IOWR(ord("D"), 0x02, invalid_param) + with self.assertRaises(OSError) as error: + fcntl.ioctl(self.d, INVALID3, self.data, True) + self.assertEqual(error.exception.errno, 22) + + def test_invalid_param_ioctl(self) -> None: + """tries to call param ioctl with invalid data structures""" + # 0x3 (param), and invalid data + INVALID4 = IOWR(ord("D"), 0x03, invalid_param) + with self.assertRaises(OSError) as error: + fcntl.ioctl(self.d, INVALID4, self.data, True) + self.assertEqual(error.exception.errno, 22) + + def test_invalid_call_ioctl(self) -> None: + """tries to call the DBC ioctl with invalid data structures""" + # 0x4, and invalid data + INVALID5 = IOWR(ord("D"), 0x04, invalid_param) + with self.assertRaises(OSError) as error: + fcntl.ioctl(self.d, INVALID5, self.data, True) + self.assertEqual(error.exception.errno, 22) + + +class TestInvalidSignature(DynamicBoostControlTest): + def setUp(self) -> None: + if not os.path.exists(DEVICE_NODE): + self.skipTest("system is unsupported") + if not system_is_secured(): + self.skipTest("system is unfused") + return super().setUp() + + def test_unauthenticated_nonce(self) -> None: + """fetch unauthenticated nonce""" + get_nonce(self.d, None) + + def test_multiple_unauthenticated_nonce(self) -> None: + """ensure state machine always returns nonce""" + for count in range(0, 2): + get_nonce(self.d, None) + + def test_authenticated_nonce(self) -> None: + """fetch authenticated nonce""" + with self.assertRaises(OSError) as error: + get_nonce(self.d, self.signature) + self.assertEqual(error.exception.errno, 1) + + def test_set_uid(self) -> None: + """set uid""" + with self.assertRaises(OSError) as error: + set_uid(self.d, self.uid, self.signature) + self.assertEqual(error.exception.errno, 1) + + def test_get_param(self) -> None: + """fetch a parameter""" + with self.assertRaises(OSError) as error: + process_param(self.d, PARAM_GET_SOC_PWR_CUR, self.signature) + self.assertEqual(error.exception.errno, 1) + + def test_set_param(self) -> None: + """set a parameter""" + with self.assertRaises(OSError) as error: + process_param(self.d, PARAM_SET_PWR_CAP, self.signature, 1000) + self.assertEqual(error.exception.errno, 1) + + +class TestUnFusedSystem(DynamicBoostControlTest): + def setup_identity(self) -> None: + """sets up the identity of the caller""" + # if already authenticated these may fail + try: + get_nonce(self.d, None) + except PermissionError: + pass + try: + set_uid(self.d, self.uid, self.signature) + except BlockingIOError: + pass + try: + get_nonce(self.d, self.signature) + except PermissionError: + pass + + def setUp(self) -> None: + if not os.path.exists(DEVICE_NODE): + self.skipTest("system is unsupported") + if system_is_secured(): + self.skipTest("system is fused") + super().setUp() + self.setup_identity() + time.sleep(SET_DELAY) + + def test_get_valid_param(self) -> None: + """fetch all possible parameters""" + # SOC power + soc_power_max = process_param(self.d, PARAM_GET_SOC_PWR_MAX, self.signature) + soc_power_min = process_param(self.d, PARAM_GET_SOC_PWR_MIN, self.signature) + self.assertGreater(soc_power_max.parameter, soc_power_min.parameter) + + # fmax + fmax_max = process_param(self.d, PARAM_GET_FMAX_MAX, self.signature) + fmax_min = process_param(self.d, PARAM_GET_FMAX_MIN, self.signature) + self.assertGreater(fmax_max.parameter, fmax_min.parameter) + + # cap values + keys = { + "fmax-cap": PARAM_GET_FMAX_CAP, + "power-cap": PARAM_GET_PWR_CAP, + "current-temp": PARAM_GET_CURR_TEMP, + "soc-power-cur": PARAM_GET_SOC_PWR_CUR, + } + for k in keys: + result = process_param(self.d, keys[k], self.signature) + self.assertGreater(result.parameter, 0) + + def test_get_invalid_param(self) -> None: + """fetch an invalid parameter""" + try: + set_uid(self.d, self.uid, self.signature) + except OSError: + pass + with self.assertRaises(OSError) as error: + process_param(self.d, (0xF,), self.signature) + self.assertEqual(error.exception.errno, 22) + + def test_set_fmax(self) -> None: + """get/set fmax limit""" + # fetch current + original = process_param(self.d, PARAM_GET_FMAX_CAP, self.signature) + + # set the fmax + target = original.parameter - 100 + process_param(self.d, PARAM_SET_FMAX_CAP, self.signature, target) + time.sleep(SET_DELAY) + new = process_param(self.d, PARAM_GET_FMAX_CAP, self.signature) + self.assertEqual(new.parameter, target) + + # revert back to current + process_param(self.d, PARAM_SET_FMAX_CAP, self.signature, original.parameter) + time.sleep(SET_DELAY) + cur = process_param(self.d, PARAM_GET_FMAX_CAP, self.signature) + self.assertEqual(cur.parameter, original.parameter) + + def test_set_power_cap(self) -> None: + """get/set power cap limit""" + # fetch current + original = process_param(self.d, PARAM_GET_PWR_CAP, self.signature) + + # set the fmax + target = original.parameter - 10 + process_param(self.d, PARAM_SET_PWR_CAP, self.signature, target) + time.sleep(SET_DELAY) + new = process_param(self.d, PARAM_GET_PWR_CAP, self.signature) + self.assertEqual(new.parameter, target) + + # revert back to current + process_param(self.d, PARAM_SET_PWR_CAP, self.signature, original.parameter) + time.sleep(SET_DELAY) + cur = process_param(self.d, PARAM_GET_PWR_CAP, self.signature) + self.assertEqual(cur.parameter, original.parameter) + + def test_set_3d_graphics_mode(self) -> None: + """set/get 3d graphics mode""" + # these aren't currently implemented but may be some day + # they are *expected* to fail + with self.assertRaises(OSError) as error: + process_param(self.d, PARAM_GET_GFX_MODE, self.signature) + self.assertEqual(error.exception.errno, 2) + + time.sleep(SET_DELAY) + + with self.assertRaises(OSError) as error: + process_param(self.d, PARAM_SET_GFX_MODE, self.signature, 1) + self.assertEqual(error.exception.errno, 2) + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index 9d36c8ce1fe7..1684216e826a 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -42,6 +42,18 @@ # define __always_inline inline __attribute__((always_inline)) #endif +#ifndef __always_unused +#define __always_unused __attribute__((__unused__)) +#endif + +#ifndef __noreturn +#define __noreturn __attribute__((__noreturn__)) +#endif + +#ifndef unreachable +#define unreachable() __builtin_unreachable() +#endif + #ifndef noinline #define noinline #endif @@ -190,4 +202,10 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s #define ___PASTE(a, b) a##b #define __PASTE(a, b) ___PASTE(a, b) +#ifndef OPTIMIZER_HIDE_VAR +/* Make the optimizer believe the variable can be manipulated arbitrarily. */ +#define OPTIMIZER_HIDE_VAR(var) \ + __asm__ ("" : "=r" (var) : "0" (var)) +#endif + #endif /* _TOOLS_LINUX_COMPILER_H */ diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 64d67b080744..909b6eb500fe 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -27,6 +27,7 @@ nolibc_arch := $(patsubst arm64,aarch64,$(ARCH)) arch_file := arch-$(nolibc_arch).h all_files := \ compiler.h \ + crt.h \ ctype.h \ errno.h \ nolibc.h \ diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index 11f294a406b7..6c33c46848e3 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -8,34 +8,7 @@ #define _NOLIBC_ARCH_AARCH64_H #include "compiler.h" - -/* The struct returned by the newfstatat() syscall. Differs slightly from the - * x86_64's stat one by field ordering, so be careful. - */ -struct sys_stat_struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - - unsigned long st_rdev; - unsigned long __pad1; - long st_size; - int st_blksize; - int __pad2; - - long st_blocks; - long st_atime; - unsigned long st_atime_nsec; - long st_mtime; - - unsigned long st_mtime_nsec; - long st_ctime; - unsigned long st_ctime_nsec; - unsigned int __unused[2]; -}; +#include "crt.h" /* Syscalls for AARCH64 : * - registers are 64-bit @@ -56,8 +29,8 @@ struct sys_stat_struct { ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -70,8 +43,8 @@ struct sys_stat_struct { ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), \ @@ -86,8 +59,8 @@ struct sys_stat_struct { register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ register long _arg2 __asm__ ("x1") = (long)(arg2); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), \ @@ -103,8 +76,8 @@ struct sys_stat_struct { register long _arg1 __asm__ ("x0") = (long)(arg1); \ register long _arg2 __asm__ ("x1") = (long)(arg2); \ register long _arg3 __asm__ ("x2") = (long)(arg3); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -121,8 +94,8 @@ struct sys_stat_struct { register long _arg2 __asm__ ("x1") = (long)(arg2); \ register long _arg3 __asm__ ("x2") = (long)(arg3); \ register long _arg4 __asm__ ("x3") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -140,8 +113,8 @@ struct sys_stat_struct { register long _arg3 __asm__ ("x2") = (long)(arg3); \ register long _arg4 __asm__ ("x3") = (long)(arg4); \ register long _arg5 __asm__ ("x4") = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r" (_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -160,8 +133,8 @@ struct sys_stat_struct { register long _arg4 __asm__ ("x3") = (long)(arg4); \ register long _arg5 __asm__ ("x4") = (long)(arg5); \ register long _arg6 __asm__ ("x5") = (long)(arg6); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r" (_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -171,33 +144,13 @@ struct sys_stat_struct { _arg1; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "bl __stack_chk_init\n" /* initialize stack protector */ -#endif - "ldr x0, [sp]\n" /* argc (x0) was in the stack */ - "add x1, sp, 8\n" /* argv (x1) = sp */ - "lsl x2, x0, 3\n" /* envp (x2) = 8*argc ... */ - "add x2, x2, 8\n" /* + 8 (skip null) */ - "add x2, x2, x1\n" /* + argv */ - "adrp x3, environ\n" /* x3 = &environ (high bits) */ - "str x2, [x3, #:lo12:environ]\n" /* store envp into environ */ - "mov x4, x2\n" /* search for auxv (follows NULL after last env) */ - "0:\n" - "ldr x5, [x4], 8\n" /* x5 = *x4; x4 += 8 */ - "cbnz x5, 0b\n" /* and stop at NULL after last env */ - "adrp x3, _auxv\n" /* x3 = &_auxv (high bits) */ - "str x4, [x3, #:lo12:_auxv]\n" /* store x4 into _auxv */ - "and sp, x1, -16\n" /* sp must be 16-byte aligned in the callee */ - "bl main\n" /* main() returns the status code, we'll exit with it. */ - "mov x8, 93\n" /* NR_exit == 93 */ - "svc #0\n" + "mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */ + "and sp, x0, -16\n" /* sp must be 16-byte aligned in the callee */ + "bl _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index ca4c66987497..cae4afa7c1c7 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -8,43 +8,7 @@ #define _NOLIBC_ARCH_ARM_H #include "compiler.h" - -/* The struct returned by the stat() syscall, 32-bit only, the syscall returns - * exactly 56 bytes (stops before the unused array). In big endian, the format - * differs as devices are returned as short only. - */ -struct sys_stat_struct { -#if defined(__ARMEB__) - unsigned short st_dev; - unsigned short __pad1; -#else - unsigned long st_dev; -#endif - unsigned long st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - -#if defined(__ARMEB__) - unsigned short st_rdev; - unsigned short __pad2; -#else - unsigned long st_rdev; -#endif - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned long st_mtime_nsec; - - unsigned long st_ctime; - unsigned long st_ctime_nsec; - unsigned long __unused[2]; -}; +#include "crt.h" /* Syscalls for ARM in ARM or Thumb modes : * - registers are 32-bit @@ -90,8 +54,8 @@ struct sys_stat_struct { ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -107,8 +71,8 @@ struct sys_stat_struct { ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -125,8 +89,8 @@ struct sys_stat_struct { register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ register long _arg2 __asm__ ("r1") = (long)(arg2); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -144,8 +108,8 @@ struct sys_stat_struct { register long _arg1 __asm__ ("r0") = (long)(arg1); \ register long _arg2 __asm__ ("r1") = (long)(arg2); \ register long _arg3 __asm__ ("r2") = (long)(arg3); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -164,8 +128,8 @@ struct sys_stat_struct { register long _arg2 __asm__ ("r1") = (long)(arg2); \ register long _arg3 __asm__ ("r2") = (long)(arg3); \ register long _arg4 __asm__ ("r3") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -185,8 +149,8 @@ struct sys_stat_struct { register long _arg3 __asm__ ("r2") = (long)(arg3); \ register long _arg4 __asm__ ("r3") = (long)(arg4); \ register long _arg5 __asm__ ("r4") = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -207,8 +171,8 @@ struct sys_stat_struct { register long _arg4 __asm__ ("r3") = (long)(arg4); \ register long _arg5 __asm__ ("r4") = (long)(arg5); \ register long _arg6 __asm__ ("r5") = (long)(arg6); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -220,49 +184,14 @@ struct sys_stat_struct { _arg1; \ }) - -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "bl __stack_chk_init\n" /* initialize stack protector */ -#endif - "pop {%r0}\n" /* argc was in the stack */ - "mov %r1, %sp\n" /* argv = sp */ - - "add %r2, %r0, $1\n" /* envp = (argc + 1) ... */ - "lsl %r2, %r2, $2\n" /* * 4 ... */ - "add %r2, %r2, %r1\n" /* + argv */ - "ldr %r3, 1f\n" /* r3 = &environ (see below) */ - "str %r2, [r3]\n" /* store envp into environ */ - - "mov r4, r2\n" /* search for auxv (follows NULL after last env) */ - "0:\n" - "mov r5, r4\n" /* r5 = r4 */ - "add r4, r4, #4\n" /* r4 += 4 */ - "ldr r5,[r5]\n" /* r5 = *r5 = *(r4-4) */ - "cmp r5, #0\n" /* and stop at NULL after last env */ - "bne 0b\n" - "ldr %r3, 2f\n" /* r3 = &_auxv (low bits) */ - "str r4, [r3]\n" /* store r4 into _auxv */ - - "mov %r3, $8\n" /* AAPCS : sp must be 8-byte aligned in the */ - "neg %r3, %r3\n" /* callee, and bl doesn't push (lr=pc) */ - "and %r3, %r3, %r1\n" /* so we do sp = r1(=sp) & r3(=-8); */ - "mov %sp, %r3\n" - - "bl main\n" /* main() returns the status code, we'll exit with it. */ - "movs r7, $1\n" /* NR_exit == 1 */ - "svc $0x00\n" - ".align 2\n" /* below are the pointers to a few variables */ - "1:\n" - ".word environ\n" - "2:\n" - ".word _auxv\n" + "mov %r0, sp\n" /* save stack pointer to %r0, as arg1 of _start_c */ + "and ip, %r0, #-8\n" /* sp must be 8-byte aligned in the callee */ + "mov sp, ip\n" + "bl _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index 3d672d925e9e..64415b9fac77 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -8,32 +8,7 @@ #define _NOLIBC_ARCH_I386_H #include "compiler.h" - -/* The struct returned by the stat() syscall, 32-bit only, the syscall returns - * exactly 56 bytes (stops before the unused array). - */ -struct sys_stat_struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - - unsigned long st_rdev; - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned long st_mtime_nsec; - - unsigned long st_ctime; - unsigned long st_ctime_nsec; - unsigned long __unused[2]; -}; +#include "crt.h" /* Syscalls for i386 : * - mostly similar to x86_64 @@ -57,8 +32,8 @@ struct sys_stat_struct { ({ \ long _ret; \ register long _num __asm__ ("eax") = (num); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "0"(_num) \ @@ -72,8 +47,8 @@ struct sys_stat_struct { long _ret; \ register long _num __asm__ ("eax") = (num); \ register long _arg1 __asm__ ("ebx") = (long)(arg1); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), \ @@ -89,8 +64,8 @@ struct sys_stat_struct { register long _num __asm__ ("eax") = (num); \ register long _arg1 __asm__ ("ebx") = (long)(arg1); \ register long _arg2 __asm__ ("ecx") = (long)(arg2); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), \ @@ -107,8 +82,8 @@ struct sys_stat_struct { register long _arg1 __asm__ ("ebx") = (long)(arg1); \ register long _arg2 __asm__ ("ecx") = (long)(arg2); \ register long _arg3 __asm__ ("edx") = (long)(arg3); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -126,8 +101,8 @@ struct sys_stat_struct { register long _arg2 __asm__ ("ecx") = (long)(arg2); \ register long _arg3 __asm__ ("edx") = (long)(arg3); \ register long _arg4 __asm__ ("esi") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -146,8 +121,8 @@ struct sys_stat_struct { register long _arg3 __asm__ ("edx") = (long)(arg3); \ register long _arg4 __asm__ ("esi") = (long)(arg4); \ register long _arg5 __asm__ ("edi") = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -180,9 +155,6 @@ struct sys_stat_struct { _eax; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ /* * i386 System V ABI mandates: @@ -190,33 +162,15 @@ const unsigned long *_auxv __attribute__((weak)); * 2) The deepest stack frame should be set to zero * */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "call __stack_chk_init\n" /* initialize stack protector */ -#endif - "pop %eax\n" /* argc (first arg, %eax) */ - "mov %esp, %ebx\n" /* argv[] (second arg, %ebx) */ - "lea 4(%ebx,%eax,4),%ecx\n" /* then a NULL then envp (third arg, %ecx) */ - "mov %ecx, environ\n" /* save environ */ - "xor %ebp, %ebp\n" /* zero the stack frame */ - "mov %ecx, %edx\n" /* search for auxv (follows NULL after last env) */ - "0:\n" - "add $4, %edx\n" /* search for auxv using edx, it follows the */ - "cmp -4(%edx), %ebp\n" /* ... NULL after last env (ebp is zero here) */ - "jnz 0b\n" - "mov %edx, _auxv\n" /* save it into _auxv */ - "and $-16, %esp\n" /* x86 ABI : esp must be 16-byte aligned before */ - "sub $4, %esp\n" /* the call instruction (args are aligned) */ - "push %ecx\n" /* push all registers on the stack so that we */ - "push %ebx\n" /* support both regparm and plain stack modes */ - "push %eax\n" - "call main\n" /* main() returns the status code in %eax */ - "mov %eax, %ebx\n" /* retrieve exit code (32-bit int) */ - "movl $1, %eax\n" /* NR_exit == 1 */ - "int $0x80\n" /* exit now */ - "hlt\n" /* ensure it does not */ + "xor %ebp, %ebp\n" /* zero the stack frame */ + "mov %esp, %eax\n" /* save stack pointer to %eax, as arg1 of _start_c */ + "and $-16, %esp\n" /* last pushed argument must be 16-byte aligned */ + "push %eax\n" /* push arg1 on stack to support plain stack modes too */ + "call _start_c\n" /* transfer to c runtime */ + "hlt\n" /* ensure it does not return */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index ad3f266e7093..bf98f6220195 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -8,6 +8,7 @@ #define _NOLIBC_ARCH_LOONGARCH_H #include "compiler.h" +#include "crt.h" /* Syscalls for LoongArch : * - stack is 16-byte aligned @@ -22,18 +23,19 @@ * On LoongArch, select() is not implemented so we have to use pselect6(). */ #define __ARCH_WANT_SYS_PSELECT6 +#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8" #define my_syscall0(num) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "=r"(_arg1) \ : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -43,12 +45,11 @@ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -59,13 +60,12 @@ register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg2 __asm__ ("a1") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -77,13 +77,12 @@ register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -96,13 +95,12 @@ register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -116,13 +114,12 @@ register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 __asm__ ("a4") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -137,67 +134,29 @@ register long _arg5 __asm__ ("a4") = (long)(arg5); \ register long _arg6 __asm__ ("a5") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - #if __loongarch_grlen == 32 -#define LONGLOG "2" -#define SZREG "4" -#define REG_L "ld.w" -#define LONG_S "st.w" -#define LONG_ADD "add.w" -#define LONG_ADDI "addi.w" -#define LONG_SLL "slli.w" #define LONG_BSTRINS "bstrins.w" #else /* __loongarch_grlen == 64 */ -#define LONGLOG "3" -#define SZREG "8" -#define REG_L "ld.d" -#define LONG_S "st.d" -#define LONG_ADD "add.d" -#define LONG_ADDI "addi.d" -#define LONG_SLL "slli.d" #define LONG_BSTRINS "bstrins.d" #endif /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "bl __stack_chk_init\n" /* initialize stack protector */ -#endif - REG_L " $a0, $sp, 0\n" /* argc (a0) was in the stack */ - LONG_ADDI " $a1, $sp, "SZREG"\n" /* argv (a1) = sp + SZREG */ - LONG_SLL " $a2, $a0, "LONGLOG"\n" /* envp (a2) = SZREG*argc ... */ - LONG_ADDI " $a2, $a2, "SZREG"\n" /* + SZREG (skip null) */ - LONG_ADD " $a2, $a2, $a1\n" /* + argv */ - - "move $a3, $a2\n" /* iterate a3 over envp to find auxv (after NULL) */ - "0:\n" /* do { */ - REG_L " $a4, $a3, 0\n" /* a4 = *a3; */ - LONG_ADDI " $a3, $a3, "SZREG"\n" /* a3 += sizeof(void*); */ - "bne $a4, $zero, 0b\n" /* } while (a4); */ - "la.pcrel $a4, _auxv\n" /* a4 = &_auxv */ - LONG_S " $a3, $a4, 0\n" /* store a3 into _auxv */ - - "la.pcrel $a3, environ\n" /* a3 = &environ */ - LONG_S " $a2, $a3, 0\n" /* store envp(a2) into environ */ - LONG_BSTRINS " $sp, $zero, 3, 0\n" /* sp must be 16-byte aligned */ - "bl main\n" /* main() returns the status code, we'll exit with it. */ - "li.w $a7, 93\n" /* NR_exit == 93 */ - "syscall 0\n" + "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ + LONG_BSTRINS " $sp, $zero, 3, 0\n" /* $sp must be 16-byte aligned */ + "bl _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index db24e0837a39..4ab6fa54beee 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -8,34 +8,7 @@ #define _NOLIBC_ARCH_MIPS_H #include "compiler.h" - -/* The struct returned by the stat() syscall. 88 bytes are returned by the - * syscall. - */ -struct sys_stat_struct { - unsigned int st_dev; - long st_pad1[3]; - unsigned long st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - unsigned int st_rdev; - long st_pad2[2]; - long st_size; - long st_pad3; - - long st_atime; - long st_atime_nsec; - long st_mtime; - long st_mtime_nsec; - - long st_ctime; - long st_ctime_nsec; - long st_blksize; - long st_blocks; - long st_pad4[14]; -}; +#include "crt.h" /* Syscalls for MIPS ABI O32 : * - WARNING! there's always a delayed slot! @@ -57,19 +30,22 @@ struct sys_stat_struct { * don't have to experience issues with register constraints. */ +#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "cc", "at", "v1", "hi", "lo", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" + #define my_syscall0(num) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg4 __asm__ ("a3"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r"(_num), "=r"(_arg4) \ : "r"(_num) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -79,16 +55,15 @@ struct sys_stat_struct { register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg4 __asm__ ("a3"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r"(_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -99,16 +74,15 @@ struct sys_stat_struct { register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg4 __asm__ ("a3"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r"(_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -120,16 +94,15 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r"(_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -141,16 +114,15 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r" (_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -163,65 +135,58 @@ struct sys_stat_struct { register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "sw %7, 16($sp)\n" \ - "syscall\n " \ + "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r" (_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("v0") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ + register long _arg3 __asm__ ("a2") = (long)(arg3); \ + register long _arg4 __asm__ ("a3") = (long)(arg4); \ + register long _arg5 = (long)(arg5); \ + register long _arg6 = (long)(arg6); \ + \ + __asm__ volatile ( \ + "addiu $sp, $sp, -32\n" \ + "sw %7, 16($sp)\n" \ + "sw %8, 20($sp)\n" \ + "syscall\n" \ + "addiu $sp, $sp, 32\n" \ + : "=r" (_num), "=r"(_arg4) \ + : "0"(_num), \ + "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_arg6) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _arg4 ? -_num : _num; \ +}) /* startup code, note that it's called __start on MIPS */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector __start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector __start(void) { __asm__ volatile ( - /*".set nomips16\n"*/ ".set push\n" - ".set noreorder\n" + ".set noreorder\n" ".option pic0\n" -#ifdef _NOLIBC_STACKPROTECTOR - "jal __stack_chk_init\n" /* initialize stack protector */ - "nop\n" /* delayed slot */ -#endif - /*".ent __start\n"*/ - /*"__start:\n"*/ - "lw $a0,($sp)\n" /* argc was in the stack */ - "addiu $a1, $sp, 4\n" /* argv = sp + 4 */ - "sll $a2, $a0, 2\n" /* a2 = argc * 4 */ - "add $a2, $a2, $a1\n" /* envp = argv + 4*argc ... */ - "addiu $a2, $a2, 4\n" /* ... + 4 */ - "lui $a3, %hi(environ)\n" /* load environ into a3 (hi) */ - "addiu $a3, %lo(environ)\n" /* load environ into a3 (lo) */ - "sw $a2,($a3)\n" /* store envp(a2) into environ */ - - "move $t0, $a2\n" /* iterate t0 over envp, look for NULL */ - "0:" /* do { */ - "lw $a3, ($t0)\n" /* a3=*(t0); */ - "bne $a3, $0, 0b\n" /* } while (a3); */ - "addiu $t0, $t0, 4\n" /* delayed slot: t0+=4; */ - "lui $a3, %hi(_auxv)\n" /* load _auxv into a3 (hi) */ - "addiu $a3, %lo(_auxv)\n" /* load _auxv into a3 (lo) */ - "sw $t0, ($a3)\n" /* store t0 into _auxv */ - - "li $t0, -8\n" - "and $sp, $sp, $t0\n" /* sp must be 8-byte aligned */ - "addiu $sp,$sp,-16\n" /* the callee expects to save a0..a3 there! */ - "jal main\n" /* main() returns the status code, we'll exit with it. */ - "nop\n" /* delayed slot */ - "move $a0, $v0\n" /* retrieve 32-bit exit code from v0 */ - "li $v0, 4001\n" /* NR_exit == 4001 */ - "syscall\n" - /*".end __start\n"*/ + "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ + "li $t0, -8\n" + "and $sp, $sp, $t0\n" /* $sp must be 8-byte aligned */ + "addiu $sp, $sp, -16\n" /* the callee expects to save a0..a3 there */ + "jal _start_c\n" /* transfer to c runtime */ + " nop\n" /* delayed slot */ ".set pop\n" ); __builtin_unreachable(); diff --git a/tools/include/nolibc/arch-powerpc.h b/tools/include/nolibc/arch-powerpc.h new file mode 100644 index 000000000000..ac212e6185b2 --- /dev/null +++ b/tools/include/nolibc/arch-powerpc.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * PowerPC specific definitions for NOLIBC + * Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org> + */ + +#ifndef _NOLIBC_ARCH_POWERPC_H +#define _NOLIBC_ARCH_POWERPC_H + +#include "compiler.h" +#include "crt.h" + +/* Syscalls for PowerPC : + * - stack is 16-byte aligned + * - syscall number is passed in r0 + * - arguments are in r3, r4, r5, r6, r7, r8, r9 + * - the system call is performed by calling "sc" + * - syscall return comes in r3, and the summary overflow bit is checked + * to know if an error occurred, in which case errno is in r3. + * - the arguments are cast to long and assigned into the target + * registers which are then simply passed as registers to the asm code, + * so that we don't have to experience issues with register constraints. + */ + +#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "cr0", "r12", "r11", "r10", "r9" + +#define my_syscall0(num) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num) \ + : \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4" \ + ); \ + _ret; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4" \ + ); \ + _ret; \ +}) + + +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5" \ + ); \ + _ret; \ +}) + + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6" \ + ); \ + _ret; \ +}) + + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + register long _arg4 __asm__ ("r6") = (long)(arg4); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \ + "+r"(_arg4) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7" \ + ); \ + _ret; \ +}) + + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + register long _arg4 __asm__ ("r6") = (long)(arg4); \ + register long _arg5 __asm__ ("r7") = (long)(arg5); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \ + "+r"(_arg4), "+r"(_arg5) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8" \ + ); \ + _ret; \ +}) + +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + register long _arg4 __asm__ ("r6") = (long)(arg4); \ + register long _arg5 __asm__ ("r7") = (long)(arg5); \ + register long _arg6 __asm__ ("r8") = (long)(arg6); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \ + "+r"(_arg4), "+r"(_arg5), "+r"(_arg6) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#ifndef __powerpc64__ +/* FIXME: For 32-bit PowerPC, with newer gcc compilers (e.g. gcc 13.1.0), + * "omit-frame-pointer" fails with __attribute__((no_stack_protector)) but + * works with __attribute__((__optimize__("-fno-stack-protector"))) + */ +#ifdef __no_stack_protector +#undef __no_stack_protector +#define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector"))) +#endif +#endif /* !__powerpc64__ */ + +/* startup code */ +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) +{ +#ifdef __powerpc64__ +#if _CALL_ELF == 2 + /* with -mabi=elfv2, save TOC/GOT pointer to r2 + * r12 is global entry pointer, we use it to compute TOC from r12 + * https://www.llvm.org/devmtg/2014-04/PDFs/Talks/Euro-LLVM-2014-Weigand.pdf + * https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.pdf + */ + __asm__ volatile ( + "addis 2, 12, .TOC. - _start@ha\n" + "addi 2, 2, .TOC. - _start@l\n" + ); +#endif /* _CALL_ELF == 2 */ + + __asm__ volatile ( + "mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */ + "clrrdi 1, 1, 4\n" /* align the stack to 16 bytes */ + "li 0, 0\n" /* zero the frame pointer */ + "stdu 1, -32(1)\n" /* the initial stack frame */ + "bl _start_c\n" /* transfer to c runtime */ + ); +#else + __asm__ volatile ( + "mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */ + "clrrwi 1, 1, 4\n" /* align the stack to 16 bytes */ + "li 0, 0\n" /* zero the frame pointer */ + "stwu 1, -16(1)\n" /* the initial stack frame */ + "bl _start_c\n" /* transfer to c runtime */ + ); +#endif + __builtin_unreachable(); +} + +#endif /* _NOLIBC_ARCH_POWERPC_H */ diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index a2e8564e66d6..950cc2283fd7 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -8,41 +8,7 @@ #define _NOLIBC_ARCH_RISCV_H #include "compiler.h" - -struct sys_stat_struct { - unsigned long st_dev; /* Device. */ - unsigned long st_ino; /* File serial number. */ - unsigned int st_mode; /* File mode. */ - unsigned int st_nlink; /* Link count. */ - unsigned int st_uid; /* User ID of the file's owner. */ - unsigned int st_gid; /* Group ID of the file's group. */ - unsigned long st_rdev; /* Device number, if device. */ - unsigned long __pad1; - long st_size; /* Size of file, in bytes. */ - int st_blksize; /* Optimal block size for I/O. */ - int __pad2; - long st_blocks; /* Number 512-byte blocks allocated. */ - long st_atime; /* Time of last access. */ - unsigned long st_atime_nsec; - long st_mtime; /* Time of last modification. */ - unsigned long st_mtime_nsec; - long st_ctime; /* Time of last status change. */ - unsigned long st_ctime_nsec; - unsigned int __unused4; - unsigned int __unused5; -}; - -#if __riscv_xlen == 64 -#define PTRLOG "3" -#define SZREG "8" -#define REG_L "ld" -#define REG_S "sd" -#elif __riscv_xlen == 32 -#define PTRLOG "2" -#define SZREG "4" -#define REG_L "lw" -#define REG_S "sw" -#endif +#include "crt.h" /* Syscalls for RISCV : * - stack is 16-byte aligned @@ -63,7 +29,7 @@ struct sys_stat_struct { register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n\t" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -77,7 +43,7 @@ struct sys_stat_struct { register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_num) \ @@ -92,7 +58,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg2 __asm__ ("a1") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), \ @@ -109,7 +75,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n\t" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), \ @@ -127,7 +93,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -146,7 +112,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 __asm__ ("a4") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -166,7 +132,7 @@ struct sys_stat_struct { register long _arg5 __asm__ ("a4") = (long)(arg5); \ register long _arg6 __asm__ ("a5") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ @@ -176,40 +142,17 @@ struct sys_stat_struct { _arg1; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( ".option push\n" ".option norelax\n" - "lla gp, __global_pointer$\n" + "lla gp, __global_pointer$\n" ".option pop\n" -#ifdef _NOLIBC_STACKPROTECTOR - "call __stack_chk_init\n" /* initialize stack protector */ -#endif - REG_L" a0, 0(sp)\n" /* argc (a0) was in the stack */ - "add a1, sp, "SZREG"\n" /* argv (a1) = sp */ - "slli a2, a0, "PTRLOG"\n" /* envp (a2) = SZREG*argc ... */ - "add a2, a2, "SZREG"\n" /* + SZREG (skip null) */ - "add a2,a2,a1\n" /* + argv */ - - "add a3, a2, zero\n" /* iterate a3 over envp to find auxv (after NULL) */ - "0:\n" /* do { */ - REG_L" a4, 0(a3)\n" /* a4 = *a3; */ - "add a3, a3, "SZREG"\n" /* a3 += sizeof(void*); */ - "bne a4, zero, 0b\n" /* } while (a4); */ - "lui a4, %hi(_auxv)\n" /* a4 = &_auxv (high bits) */ - REG_S" a3, %lo(_auxv)(a4)\n" /* store a3 into _auxv */ - - "lui a3, %hi(environ)\n" /* a3 = &environ (high bits) */ - REG_S" a2,%lo(environ)(a3)\n"/* store envp(a2) into environ */ - "andi sp,a1,-16\n" /* sp must be 16-byte aligned */ - "call main\n" /* main() returns the status code, we'll exit with it. */ - "li a7, 93\n" /* NR_exit == 93 */ - "ecall\n" + "mv a0, sp\n" /* save stack pointer to a0, as arg1 of _start_c */ + "andi sp, a0, -16\n" /* sp must be 16-byte aligned */ + "call _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h index 516dff5bff8b..5d60fd43f883 100644 --- a/tools/include/nolibc/arch-s390.h +++ b/tools/include/nolibc/arch-s390.h @@ -9,31 +9,7 @@ #include <asm/unistd.h> #include "compiler.h" - -/* The struct returned by the stat() syscall, equivalent to stat64(). The - * syscall returns 116 bytes and stops in the middle of __unused. - */ - -struct sys_stat_struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned long st_nlink; - unsigned int st_mode; - unsigned int st_uid; - unsigned int st_gid; - unsigned int __pad1; - unsigned long st_rdev; - unsigned long st_size; - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned long st_mtime_nsec; - unsigned long st_ctime; - unsigned long st_ctime_nsec; - unsigned long st_blksize; - long st_blocks; - unsigned long __unused[3]; -}; +#include "crt.h" /* Syscalls for s390: * - registers are 64-bit @@ -52,7 +28,7 @@ struct sys_stat_struct { register long _num __asm__ ("1") = (num); \ register long _rc __asm__ ("2"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "=d"(_rc) \ : "d"(_num) \ @@ -66,7 +42,7 @@ struct sys_stat_struct { register long _num __asm__ ("1") = (num); \ register long _arg1 __asm__ ("2") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_num) \ @@ -81,7 +57,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("2") = (long)(arg1); \ register long _arg2 __asm__ ("3") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_num) \ @@ -97,7 +73,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("3") = (long)(arg2); \ register long _arg3 __asm__ ("4") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_num) \ @@ -114,7 +90,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("4") = (long)(arg3); \ register long _arg4 __asm__ ("5") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \ @@ -132,7 +108,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("5") = (long)(arg4); \ register long _arg5 __asm__ ("6") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ @@ -152,7 +128,7 @@ struct sys_stat_struct { register long _arg5 __asm__ ("6") = (long)(arg5); \ register long _arg6 __asm__ ("7") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ @@ -162,41 +138,14 @@ struct sys_stat_struct { _arg1; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( - "lg %r2,0(%r15)\n" /* argument count */ - "la %r3,8(%r15)\n" /* argument pointers */ - - "xgr %r0,%r0\n" /* r0 will be our NULL value */ - /* search for envp */ - "lgr %r4,%r3\n" /* start at argv */ - "0:\n" - "clg %r0,0(%r4)\n" /* entry zero? */ - "la %r4,8(%r4)\n" /* advance pointer */ - "jnz 0b\n" /* no -> test next pointer */ - /* yes -> r4 now contains start of envp */ - "larl %r1,environ\n" - "stg %r4,0(%r1)\n" - - /* search for auxv */ - "lgr %r5,%r4\n" /* start at envp */ - "1:\n" - "clg %r0,0(%r5)\n" /* entry zero? */ - "la %r5,8(%r5)\n" /* advance pointer */ - "jnz 1b\n" /* no -> test next pointer */ - "larl %r1,_auxv\n" /* yes -> store value in _auxv */ - "stg %r5,0(%r1)\n" - - "aghi %r15,-160\n" /* allocate new stackframe */ - "xc 0(8,%r15),0(%r15)\n" /* clear backchain */ - "brasl %r14,main\n" /* ret value of main is arg to exit */ - "lghi %r1,1\n" /* __NR_exit */ - "svc 0\n" + "lgr %r2, %r15\n" /* save stack pointer to %r2, as arg1 of _start_c */ + "aghi %r15, -160\n" /* allocate new stackframe */ + "xc 0(8,%r15), 0(%r15)\n" /* clear backchain */ + "brasl %r14, _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index 6fc4d8392742..e5ccb926c903 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -8,33 +8,7 @@ #define _NOLIBC_ARCH_X86_64_H #include "compiler.h" - -/* The struct returned by the stat() syscall, equivalent to stat64(). The - * syscall returns 116 bytes and stops in the middle of __unused. - */ -struct sys_stat_struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned long st_nlink; - unsigned int st_mode; - unsigned int st_uid; - - unsigned int st_gid; - unsigned int __pad0; - unsigned long st_rdev; - long st_size; - long st_blksize; - - long st_blocks; - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - - unsigned long st_mtime_nsec; - unsigned long st_ctime; - unsigned long st_ctime_nsec; - long __unused[3]; -}; +#include "crt.h" /* Syscalls for x86_64 : * - registers are 64-bit @@ -59,8 +33,8 @@ struct sys_stat_struct { ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "0"(_num) \ @@ -74,8 +48,8 @@ struct sys_stat_struct { long _ret; \ register long _num __asm__ ("rax") = (num); \ register long _arg1 __asm__ ("rdi") = (long)(arg1); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), \ @@ -91,8 +65,8 @@ struct sys_stat_struct { register long _num __asm__ ("rax") = (num); \ register long _arg1 __asm__ ("rdi") = (long)(arg1); \ register long _arg2 __asm__ ("rsi") = (long)(arg2); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), \ @@ -109,8 +83,8 @@ struct sys_stat_struct { register long _arg1 __asm__ ("rdi") = (long)(arg1); \ register long _arg2 __asm__ ("rsi") = (long)(arg2); \ register long _arg3 __asm__ ("rdx") = (long)(arg3); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -128,8 +102,8 @@ struct sys_stat_struct { register long _arg2 __asm__ ("rsi") = (long)(arg2); \ register long _arg3 __asm__ ("rdx") = (long)(arg3); \ register long _arg4 __asm__ ("r10") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -148,8 +122,8 @@ struct sys_stat_struct { register long _arg3 __asm__ ("rdx") = (long)(arg3); \ register long _arg4 __asm__ ("r10") = (long)(arg4); \ register long _arg5 __asm__ ("r8") = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -169,8 +143,8 @@ struct sys_stat_struct { register long _arg4 __asm__ ("r10") = (long)(arg4); \ register long _arg5 __asm__ ("r8") = (long)(arg5); \ register long _arg6 __asm__ ("r9") = (long)(arg6); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -180,9 +154,6 @@ struct sys_stat_struct { _ret; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ /* * x86-64 System V ABI mandates: @@ -190,29 +161,14 @@ const unsigned long *_auxv __attribute__((weak)); * 2) The deepest stack frame should be zero (the %rbp). * */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "call __stack_chk_init\n" /* initialize stack protector */ -#endif - "pop %rdi\n" /* argc (first arg, %rdi) */ - "mov %rsp, %rsi\n" /* argv[] (second arg, %rsi) */ - "lea 8(%rsi,%rdi,8),%rdx\n" /* then a NULL then envp (third arg, %rdx) */ - "mov %rdx, environ\n" /* save environ */ - "xor %ebp, %ebp\n" /* zero the stack frame */ - "mov %rdx, %rax\n" /* search for auxv (follows NULL after last env) */ - "0:\n" - "add $8, %rax\n" /* search for auxv using rax, it follows the */ - "cmp -8(%rax), %rbp\n" /* ... NULL after last env (rbp is zero here) */ - "jnz 0b\n" - "mov %rax, _auxv\n" /* save it into _auxv */ - "and $-16, %rsp\n" /* x86 ABI : esp must be 16-byte aligned before call */ - "call main\n" /* main() returns the status code, we'll exit with it. */ - "mov %eax, %edi\n" /* retrieve exit code (32 bit) */ - "mov $60, %eax\n" /* NR_exit == 60 */ - "syscall\n" /* really exit */ - "hlt\n" /* ensure it does not return */ + "xor %ebp, %ebp\n" /* zero the stack frame */ + "mov %rsp, %rdi\n" /* save stack pointer to %rdi, as arg1 of _start_c */ + "and $-16, %rsp\n" /* %rsp must be 16-byte aligned before call */ + "call _start_c\n" /* transfer to c runtime */ + "hlt\n" /* ensure it does not return */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h index 82b43935650f..e276fb0680af 100644 --- a/tools/include/nolibc/arch.h +++ b/tools/include/nolibc/arch.h @@ -25,6 +25,8 @@ #include "arch-aarch64.h" #elif defined(__mips__) && defined(_ABIO32) #include "arch-mips.h" +#elif defined(__powerpc__) +#include "arch-powerpc.h" #elif defined(__riscv) #include "arch-riscv.h" #elif defined(__s390x__) diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h new file mode 100644 index 000000000000..a5f33fef1672 --- /dev/null +++ b/tools/include/nolibc/crt.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * C Run Time support for NOLIBC + * Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org> + */ + +#ifndef _NOLIBC_CRT_H +#define _NOLIBC_CRT_H + +char **environ __attribute__((weak)); +const unsigned long *_auxv __attribute__((weak)); + +static void __stack_chk_init(void); +static void exit(int); + +void _start_c(long *sp) +{ + long argc; + char **argv; + char **envp; + const unsigned long *auxv; + /* silence potential warning: conflicting types for 'main' */ + int _nolibc_main(int, char **, char **) __asm__ ("main"); + + /* initialize stack protector */ + __stack_chk_init(); + + /* + * sp : argc <-- argument count, required by main() + * argv: argv[0] <-- argument vector, required by main() + * argv[1] + * ... + * argv[argc-1] + * null + * environ: environ[0] <-- environment variables, required by main() and getenv() + * environ[1] + * ... + * null + * _auxv: _auxv[0] <-- auxiliary vector, required by getauxval() + * _auxv[1] + * ... + * null + */ + + /* assign argc and argv */ + argc = *sp; + argv = (void *)(sp + 1); + + /* find environ */ + environ = envp = argv + argc + 1; + + /* find _auxv */ + for (auxv = (void *)envp; *auxv++;) + ; + _auxv = auxv; + + /* go to application */ + exit(_nolibc_main(argc, argv, envp)); +} + +#endif /* _NOLIBC_CRT_H */ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 05a228a6ee78..1f8d821000ac 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -13,11 +13,10 @@ * Syscalls are split into 3 levels: * - The lower level is the arch-specific syscall() definition, consisting in * assembly code in compound expressions. These are called my_syscall0() to - * my_syscall6() depending on the number of arguments. The MIPS - * implementation is limited to 5 arguments. All input arguments are cast - * to a long stored in a register. These expressions always return the - * syscall's return value as a signed long value which is often either a - * pointer or the negated errno value. + * my_syscall6() depending on the number of arguments. All input arguments + * are castto a long stored in a register. These expressions always return + * the syscall's return value as a signed long value which is often either + * a pointer or the negated errno value. * * - The second level is mostly architecture-independent. It is made of * static functions called sys_<name>() which rely on my_syscallN() diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h index 88f7b2d098ff..13f1d0e60387 100644 --- a/tools/include/nolibc/stackprotector.h +++ b/tools/include/nolibc/stackprotector.h @@ -37,14 +37,15 @@ void __stack_chk_fail_local(void) __attribute__((weak,section(".data.nolibc_stack_chk"))) uintptr_t __stack_chk_guard; -__attribute__((weak,section(".text.nolibc_stack_chk"))) __no_stack_protector -void __stack_chk_init(void) +static __no_stack_protector void __stack_chk_init(void) { my_syscall3(__NR_getrandom, &__stack_chk_guard, sizeof(__stack_chk_guard), 0); /* a bit more randomness in case getrandom() fails, ensure the guard is never 0 */ if (__stack_chk_guard != (uintptr_t) &__stack_chk_guard) __stack_chk_guard ^= (uintptr_t) &__stack_chk_guard; } +#else /* !defined(_NOLIBC_STACKPROTECTOR) */ +static void __stack_chk_init(void) {} #endif /* defined(_NOLIBC_STACKPROTECTOR) */ #endif /* _NOLIBC_STACKPROTECTOR_H */ diff --git a/tools/include/nolibc/stdint.h b/tools/include/nolibc/stdint.h index 4b282435a59a..6665e272e213 100644 --- a/tools/include/nolibc/stdint.h +++ b/tools/include/nolibc/stdint.h @@ -15,7 +15,7 @@ typedef unsigned int uint32_t; typedef signed int int32_t; typedef unsigned long long uint64_t; typedef signed long long int64_t; -typedef unsigned long size_t; +typedef __SIZE_TYPE__ size_t; typedef signed long ssize_t; typedef unsigned long uintptr_t; typedef signed long intptr_t; diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 0eef91daf289..cae402c11e57 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -21,6 +21,11 @@ #define EOF (-1) #endif +/* Buffering mode used by setvbuf. */ +#define _IOFBF 0 /* Fully buffered. */ +#define _IOLBF 1 /* Line buffered. */ +#define _IONBF 2 /* No buffering. */ + /* just define FILE as a non-empty type. The value of the pointer gives * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE * are immediately identified as abnormal entries (i.e. possible copies @@ -350,6 +355,28 @@ void perror(const char *msg) fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); } +static __attribute__((unused)) +int setvbuf(FILE *stream __attribute__((unused)), + char *buf __attribute__((unused)), + int mode, + size_t size __attribute__((unused))) +{ + /* + * nolibc does not support buffering so this is a nop. Just check mode + * is valid as required by the spec. + */ + switch (mode) { + case _IOFBF: + case _IOLBF: + case _IONBF: + break; + default: + return EOF; + } + + return 0; +} + /* make sure to include all global symbols */ #include "nolibc.h" diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 902162f80337..bacfd35c5156 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -83,11 +83,10 @@ void free(void *ptr) * declared as a char **, and must be terminated by a NULL (it is recommended * to set this variable to the "envp" argument of main()). If the requested * environment variable exists its value is returned otherwise NULL is - * returned. getenv() is forcefully inlined so that the reference to "environ" - * will be dropped if unused, even at -O0. + * returned. */ static __attribute__((unused)) -char *_getenv(const char *name, char **environ) +char *getenv(const char *name) { int idx, i; @@ -102,13 +101,6 @@ char *_getenv(const char *name, char **environ) return NULL; } -static __inline__ __attribute__((unused,always_inline)) -char *getenv(const char *name) -{ - extern char **environ; - return _getenv(name, environ); -} - static __attribute__((unused)) unsigned long getauxval(unsigned long type) { diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 856249a11890..fdb6bd6c0e2f 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -21,7 +21,6 @@ #include <linux/auxvec.h> #include <linux/fcntl.h> /* for O_* and AT_* */ #include <linux/stat.h> /* for statx() */ -#include <linux/reboot.h> /* for LINUX_REBOOT_* */ #include <linux/prctl.h> #include "arch.h" @@ -29,6 +28,22 @@ #include "types.h" +/* Syscall return helper: takes the syscall value in argument and checks for an + * error in it. This may only be used with signed returns (int or long), but + * not with pointers. An error is any value < 0. When an error is encountered, + * -ret is set into errno and -1 is returned. Otherwise the returned value is + * passed as-is with its type preserved. + */ + +#define __sysret(arg) \ +({ \ + __typeof__(arg) __sysret_arg = (arg); \ + (__sysret_arg < 0) /* error ? */ \ + ? (({ SET_ERRNO(-__sysret_arg); }), -1) /* ret -1 with errno = -arg */ \ + : __sysret_arg; /* return original value */ \ +}) + + /* Functions in this file only describe syscalls. They're declared static so * that the compiler usually decides to inline them while still being allowed * to pass a pointer to one of their instances. Each syscall exists in two @@ -78,10 +93,10 @@ int brk(void *addr) static __attribute__((unused)) void *sbrk(intptr_t inc) { - void *ret; - /* first call to find current end */ - if ((ret = sys_brk(0)) && (sys_brk(ret + inc) == ret + inc)) + void *ret = sys_brk(0); + + if (ret && sys_brk(ret + inc) == ret + inc) return ret + inc; SET_ERRNO(ENOMEM); @@ -102,13 +117,7 @@ int sys_chdir(const char *path) static __attribute__((unused)) int chdir(const char *path) { - int ret = sys_chdir(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chdir(path)); } @@ -124,20 +133,14 @@ int sys_chmod(const char *path, mode_t mode) #elif defined(__NR_chmod) return my_syscall2(__NR_chmod, path, mode); #else -#error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod() + return -ENOSYS; #endif } static __attribute__((unused)) int chmod(const char *path, mode_t mode) { - int ret = sys_chmod(path, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chmod(path, mode)); } @@ -153,20 +156,14 @@ int sys_chown(const char *path, uid_t owner, gid_t group) #elif defined(__NR_chown) return my_syscall3(__NR_chown, path, owner, group); #else -#error Neither __NR_fchownat nor __NR_chown defined, cannot implement sys_chown() + return -ENOSYS; #endif } static __attribute__((unused)) int chown(const char *path, uid_t owner, gid_t group) { - int ret = sys_chown(path, owner, group); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chown(path, owner, group)); } @@ -183,13 +180,7 @@ int sys_chroot(const char *path) static __attribute__((unused)) int chroot(const char *path) { - int ret = sys_chroot(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chroot(path)); } @@ -206,13 +197,7 @@ int sys_close(int fd) static __attribute__((unused)) int close(int fd) { - int ret = sys_close(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_close(fd)); } @@ -229,13 +214,7 @@ int sys_dup(int fd) static __attribute__((unused)) int dup(int fd) { - int ret = sys_dup(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup(fd)); } @@ -251,20 +230,14 @@ int sys_dup2(int old, int new) #elif defined(__NR_dup2) return my_syscall2(__NR_dup2, old, new); #else -#error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2() + return -ENOSYS; #endif } static __attribute__((unused)) int dup2(int old, int new) { - int ret = sys_dup2(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup2(old, new)); } @@ -282,13 +255,7 @@ int sys_dup3(int old, int new, int flags) static __attribute__((unused)) int dup3(int old, int new, int flags) { - int ret = sys_dup3(old, new, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup3(old, new, flags)); } #endif @@ -306,13 +273,7 @@ int sys_execve(const char *filename, char *const argv[], char *const envp[]) static __attribute__((unused)) int execve(const char *filename, char *const argv[], char *const envp[]) { - int ret = sys_execve(filename, argv, envp); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_execve(filename, argv, envp)); } @@ -351,7 +312,7 @@ pid_t sys_fork(void) #elif defined(__NR_fork) return my_syscall0(__NR_fork); #else -#error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork() + return -ENOSYS; #endif } #endif @@ -359,13 +320,7 @@ pid_t sys_fork(void) static __attribute__((unused)) pid_t fork(void) { - pid_t ret = sys_fork(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_fork()); } @@ -382,13 +337,7 @@ int sys_fsync(int fd) static __attribute__((unused)) int fsync(int fd) { - int ret = sys_fsync(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_fsync(fd)); } @@ -405,13 +354,7 @@ int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) static __attribute__((unused)) int getdents64(int fd, struct linux_dirent64 *dirp, int count) { - int ret = sys_getdents64(fd, dirp, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_getdents64(fd, dirp, count)); } @@ -449,13 +392,7 @@ pid_t sys_getpgid(pid_t pid) static __attribute__((unused)) pid_t getpgid(pid_t pid) { - pid_t ret = sys_getpgid(pid); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_getpgid(pid)); } @@ -529,21 +466,13 @@ pid_t gettid(void) static unsigned long getauxval(unsigned long key); /* - * long getpagesize(void); + * int getpagesize(void); */ static __attribute__((unused)) -long getpagesize(void) +int getpagesize(void) { - long ret; - - ret = getauxval(AT_PAGESZ); - if (!ret) { - SET_ERRNO(ENOENT); - return -1; - } - - return ret; + return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT); } @@ -554,19 +483,17 @@ long getpagesize(void) static __attribute__((unused)) int sys_gettimeofday(struct timeval *tv, struct timezone *tz) { +#ifdef __NR_gettimeofday return my_syscall2(__NR_gettimeofday, tv, tz); +#else + return -ENOSYS; +#endif } static __attribute__((unused)) int gettimeofday(struct timeval *tv, struct timezone *tz) { - int ret = sys_gettimeofday(tv, tz); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_gettimeofday(tv, tz)); } @@ -604,13 +531,7 @@ int sys_ioctl(int fd, unsigned long req, void *value) static __attribute__((unused)) int ioctl(int fd, unsigned long req, void *value) { - int ret = sys_ioctl(fd, req, value); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_ioctl(fd, req, value)); } /* @@ -626,13 +547,7 @@ int sys_kill(pid_t pid, int signal) static __attribute__((unused)) int kill(pid_t pid, int signal) { - int ret = sys_kill(pid, signal); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_kill(pid, signal)); } @@ -648,20 +563,14 @@ int sys_link(const char *old, const char *new) #elif defined(__NR_link) return my_syscall2(__NR_link, old, new); #else -#error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link() + return -ENOSYS; #endif } static __attribute__((unused)) int link(const char *old, const char *new) { - int ret = sys_link(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_link(old, new)); } @@ -672,19 +581,17 @@ int link(const char *old, const char *new) static __attribute__((unused)) off_t sys_lseek(int fd, off_t offset, int whence) { +#ifdef __NR_lseek return my_syscall3(__NR_lseek, fd, offset, whence); +#else + return -ENOSYS; +#endif } static __attribute__((unused)) off_t lseek(int fd, off_t offset, int whence) { - off_t ret = sys_lseek(fd, offset, whence); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_lseek(fd, offset, whence)); } @@ -700,20 +607,36 @@ int sys_mkdir(const char *path, mode_t mode) #elif defined(__NR_mkdir) return my_syscall2(__NR_mkdir, path, mode); #else -#error Neither __NR_mkdirat nor __NR_mkdir defined, cannot implement sys_mkdir() + return -ENOSYS; #endif } static __attribute__((unused)) int mkdir(const char *path, mode_t mode) { - int ret = sys_mkdir(path, mode); + return __sysret(sys_mkdir(path, mode)); +} - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; +/* + * int rmdir(const char *path); + */ + +static __attribute__((unused)) +int sys_rmdir(const char *path) +{ +#ifdef __NR_rmdir + return my_syscall1(__NR_rmdir, path); +#elif defined(__NR_unlinkat) + return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); +#else + return -ENOSYS; +#endif +} + +static __attribute__((unused)) +int rmdir(const char *path) +{ + return __sysret(sys_rmdir(path)); } @@ -729,42 +652,21 @@ long sys_mknod(const char *path, mode_t mode, dev_t dev) #elif defined(__NR_mknod) return my_syscall3(__NR_mknod, path, mode, dev); #else -#error Neither __NR_mknodat nor __NR_mknod defined, cannot implement sys_mknod() + return -ENOSYS; #endif } static __attribute__((unused)) int mknod(const char *path, mode_t mode, dev_t dev) { - int ret = sys_mknod(path, mode, dev); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mknod(path, mode, dev)); } -#ifndef MAP_SHARED -#define MAP_SHARED 0x01 /* Share changes */ -#define MAP_PRIVATE 0x02 /* Changes are private */ -#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */ -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - #ifndef sys_mmap static __attribute__((unused)) void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { -#ifndef my_syscall6 - /* Function not implemented. */ - return (void *)-ENOSYS; -#else - int n; #if defined(__NR_mmap2) @@ -775,10 +677,14 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, #endif return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); -#endif } #endif +/* Note that on Linux, MAP_FAILED is -1 so we can use the generic __sysret() + * which returns -1 upon error and still satisfy user land that checks for + * MAP_FAILED. + */ + static __attribute__((unused)) void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { @@ -800,13 +706,7 @@ int sys_munmap(void *addr, size_t length) static __attribute__((unused)) int munmap(void *addr, size_t length) { - int ret = sys_munmap(addr, length); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_munmap(addr, length)); } /* @@ -826,13 +726,7 @@ int mount(const char *src, const char *tgt, const char *fst, unsigned long flags, const void *data) { - int ret = sys_mount(src, tgt, fst, flags, data); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mount(src, tgt, fst, flags, data)); } @@ -848,7 +742,7 @@ int sys_open(const char *path, int flags, mode_t mode) #elif defined(__NR_open) return my_syscall3(__NR_open, path, flags, mode); #else -#error Neither __NR_openat nor __NR_open defined, cannot implement sys_open() + return -ENOSYS; #endif } @@ -856,7 +750,6 @@ static __attribute__((unused)) int open(const char *path, int flags, ...) { mode_t mode = 0; - int ret; if (flags & O_CREAT) { va_list args; @@ -866,13 +759,31 @@ int open(const char *path, int flags, ...) va_end(args); } - ret = sys_open(path, flags, mode); + return __sysret(sys_open(path, flags, mode)); +} - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + +/* + * int pipe2(int pipefd[2], int flags); + * int pipe(int pipefd[2]); + */ + +static __attribute__((unused)) +int sys_pipe2(int pipefd[2], int flags) +{ + return my_syscall2(__NR_pipe2, pipefd, flags); +} + +static __attribute__((unused)) +int pipe2(int pipefd[2], int flags) +{ + return __sysret(sys_pipe2(pipefd, flags)); +} + +static __attribute__((unused)) +int pipe(int pipefd[2]) +{ + return pipe2(pipefd, 0); } @@ -892,13 +803,7 @@ static __attribute__((unused)) int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - int ret = sys_prctl(option, arg2, arg3, arg4, arg5); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_prctl(option, arg2, arg3, arg4, arg5)); } @@ -915,13 +820,7 @@ int sys_pivot_root(const char *new, const char *old) static __attribute__((unused)) int pivot_root(const char *new, const char *old) { - int ret = sys_pivot_root(new, old); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_pivot_root(new, old)); } @@ -943,20 +842,14 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout) #elif defined(__NR_poll) return my_syscall3(__NR_poll, fds, nfds, timeout); #else -#error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll() + return -ENOSYS; #endif } static __attribute__((unused)) int poll(struct pollfd *fds, int nfds, int timeout) { - int ret = sys_poll(fds, nfds, timeout); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_poll(fds, nfds, timeout)); } @@ -973,13 +866,7 @@ ssize_t sys_read(int fd, void *buf, size_t count) static __attribute__((unused)) ssize_t read(int fd, void *buf, size_t count) { - ssize_t ret = sys_read(fd, buf, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_read(fd, buf, count)); } @@ -997,13 +884,7 @@ ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) static __attribute__((unused)) int reboot(int cmd) { - int ret = sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0)); } @@ -1020,13 +901,7 @@ int sys_sched_yield(void) static __attribute__((unused)) int sched_yield(void) { - int ret = sys_sched_yield(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_sched_yield()); } @@ -1059,20 +934,14 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva #endif return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout); #else -#error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select() + return -ENOSYS; #endif } static __attribute__((unused)) int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) { - int ret = sys_select(nfds, rfds, wfds, efds, timeout); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_select(nfds, rfds, wfds, efds, timeout)); } @@ -1089,13 +958,7 @@ int sys_setpgid(pid_t pid, pid_t pgid) static __attribute__((unused)) int setpgid(pid_t pid, pid_t pgid) { - int ret = sys_setpgid(pid, pgid); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_setpgid(pid, pgid)); } @@ -1112,55 +975,41 @@ pid_t sys_setsid(void) static __attribute__((unused)) pid_t setsid(void) { - pid_t ret = sys_setsid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_setsid()); } -#if defined(__NR_statx) /* * int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf); + * int stat(const char *path, struct stat *buf); */ static __attribute__((unused)) int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) { +#ifdef __NR_statx return my_syscall5(__NR_statx, fd, path, flags, mask, buf); +#else + return -ENOSYS; +#endif } static __attribute__((unused)) int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) { - int ret = sys_statx(fd, path, flags, mask, buf); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_statx(fd, path, flags, mask, buf)); } -#endif -/* - * int stat(const char *path, struct stat *buf); - * Warning: the struct stat's layout is arch-dependent. - */ -#if defined(__NR_statx) && !defined(__NR_newfstatat) && !defined(__NR_stat) -/* - * Maybe we can just use statx() when available for all architectures? - */ static __attribute__((unused)) -int sys_stat(const char *path, struct stat *buf) +int stat(const char *path, struct stat *buf) { struct statx statx; long ret; - ret = sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx); + ret = __sysret(sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx)); + if (ret == -1) + return ret; + buf->st_dev = ((statx.stx_dev_minor & 0xff) | (statx.stx_dev_major << 8) | ((statx.stx_dev_minor & ~0xff) << 12)); @@ -1181,53 +1030,8 @@ int sys_stat(const char *path, struct stat *buf) buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec; buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec; buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec; - return ret; -} -#else -static __attribute__((unused)) -int sys_stat(const char *path, struct stat *buf) -{ - struct sys_stat_struct stat; - long ret; - -#ifdef __NR_newfstatat - /* only solution for arm64 */ - ret = my_syscall4(__NR_newfstatat, AT_FDCWD, path, &stat, 0); -#elif defined(__NR_stat) - ret = my_syscall2(__NR_stat, path, &stat); -#else -#error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat() -#endif - buf->st_dev = stat.st_dev; - buf->st_ino = stat.st_ino; - buf->st_mode = stat.st_mode; - buf->st_nlink = stat.st_nlink; - buf->st_uid = stat.st_uid; - buf->st_gid = stat.st_gid; - buf->st_rdev = stat.st_rdev; - buf->st_size = stat.st_size; - buf->st_blksize = stat.st_blksize; - buf->st_blocks = stat.st_blocks; - buf->st_atim.tv_sec = stat.st_atime; - buf->st_atim.tv_nsec = stat.st_atime_nsec; - buf->st_mtim.tv_sec = stat.st_mtime; - buf->st_mtim.tv_nsec = stat.st_mtime_nsec; - buf->st_ctim.tv_sec = stat.st_ctime; - buf->st_ctim.tv_nsec = stat.st_ctime_nsec; - return ret; -} -#endif -static __attribute__((unused)) -int stat(const char *path, struct stat *buf) -{ - int ret = sys_stat(path, buf); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return 0; } @@ -1243,20 +1047,14 @@ int sys_symlink(const char *old, const char *new) #elif defined(__NR_symlink) return my_syscall2(__NR_symlink, old, new); #else -#error Neither __NR_symlinkat nor __NR_symlink defined, cannot implement sys_symlink() + return -ENOSYS; #endif } static __attribute__((unused)) int symlink(const char *old, const char *new) { - int ret = sys_symlink(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_symlink(old, new)); } @@ -1290,13 +1088,7 @@ int sys_umount2(const char *path, int flags) static __attribute__((unused)) int umount2(const char *path, int flags) { - int ret = sys_umount2(path, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_umount2(path, flags)); } @@ -1312,20 +1104,14 @@ int sys_unlink(const char *path) #elif defined(__NR_unlink) return my_syscall1(__NR_unlink, path); #else -#error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink() + return -ENOSYS; #endif } static __attribute__((unused)) int unlink(const char *path) { - int ret = sys_unlink(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_unlink(path)); } @@ -1338,44 +1124,30 @@ int unlink(const char *path) static __attribute__((unused)) pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) { +#ifdef __NR_wait4 return my_syscall4(__NR_wait4, pid, status, options, rusage); +#else + return -ENOSYS; +#endif } static __attribute__((unused)) pid_t wait(int *status) { - pid_t ret = sys_wait4(-1, status, 0, NULL); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(-1, status, 0, NULL)); } static __attribute__((unused)) pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) { - pid_t ret = sys_wait4(pid, status, options, rusage); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(pid, status, options, rusage)); } static __attribute__((unused)) pid_t waitpid(pid_t pid, int *status, int options) { - pid_t ret = sys_wait4(pid, status, options, NULL); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(pid, status, options, NULL)); } @@ -1392,13 +1164,7 @@ ssize_t sys_write(int fd, const void *buf, size_t count) static __attribute__((unused)) ssize_t write(int fd, const void *buf, size_t count) { - ssize_t ret = sys_write(fd, buf, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_write(fd, buf, count)); } @@ -1415,13 +1181,7 @@ int sys_memfd_create(const char *name, unsigned int flags) static __attribute__((unused)) int memfd_create(const char *name, unsigned int flags) { - ssize_t ret = sys_memfd_create(name, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_memfd_create(name, flags)); } /* make sure to include all global symbols */ diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index f96e28bff4ba..8cfc4c860fa4 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -8,13 +8,15 @@ #define _NOLIBC_TYPES_H #include "std.h" -#include <linux/time.h> +#include <linux/mman.h> +#include <linux/reboot.h> /* for LINUX_REBOOT_* */ #include <linux/stat.h> +#include <linux/time.h> /* Only the generic macros and types may be defined here. The arch-specific - * ones such as the O_RDONLY and related macros used by fcntl() and open(), or - * the layout of sys_stat_struct must not be defined here. + * ones such as the O_RDONLY and related macros used by fcntl() and open() + * must not be defined here. */ /* stat flags (WARNING, octal here). We need to check for an existing @@ -81,11 +83,25 @@ #define MAXPATHLEN (PATH_MAX) #endif +/* flags for mmap */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + /* whence values for lseek() */ #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 +/* flags for reboot */ +#define RB_AUTOBOOT LINUX_REBOOT_CMD_RESTART +#define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT +#define RB_ENABLE_CAD LINUX_REBOOT_CMD_CAD_ON +#define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF +#define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF +#define RB_SW_SUSPEND LINUX_REBOOT_CMD_SW_SUSPEND +#define RB_KEXEC LINUX_REBOOT_CMD_KEXEC + /* Macros used on waitpid()'s return status */ #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define WIFEXITED(status) (((status) & 0x7f) == 0) diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index 0e832e10a0b2..e38f3660c051 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -56,18 +56,9 @@ int tcsetpgrp(int fd, pid_t pid) return ioctl(fd, TIOCSPGRP, &pid); } -#define _syscall(N, ...) \ -({ \ - long _ret = my_syscall##N(__VA_ARGS__); \ - if (_ret < 0) { \ - SET_ERRNO(-_ret); \ - _ret = -1; \ - } \ - _ret; \ -}) - -#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N +#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) +#define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) #define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py index ffaa8038aa8c..564ecf07cd2c 100755 --- a/tools/net/ynl/cli.py +++ b/tools/net/ynl/cli.py @@ -6,7 +6,7 @@ import json import pprint import time -from lib import YnlFamily +from lib import YnlFamily, Netlink def main(): @@ -19,6 +19,14 @@ def main(): parser.add_argument('--dump', dest='dump', type=str) parser.add_argument('--sleep', dest='sleep', type=int) parser.add_argument('--subscribe', dest='ntf', type=str) + parser.add_argument('--replace', dest='flags', action='append_const', + const=Netlink.NLM_F_REPLACE) + parser.add_argument('--excl', dest='flags', action='append_const', + const=Netlink.NLM_F_EXCL) + parser.add_argument('--create', dest='flags', action='append_const', + const=Netlink.NLM_F_CREATE) + parser.add_argument('--append', dest='flags', action='append_const', + const=Netlink.NLM_F_APPEND) args = parser.parse_args() if args.no_schema: @@ -37,7 +45,7 @@ def main(): time.sleep(args.sleep) if args.do: - reply = ynl.do(args.do, attrs) + reply = ynl.do(args.do, attrs, args.flags) pprint.PrettyPrinter().pprint(reply) if args.dump: reply = ynl.dump(args.dump, attrs) diff --git a/tools/net/ynl/lib/__init__.py b/tools/net/ynl/lib/__init__.py index 4b3797fe784b..f7eaa07783e7 100644 --- a/tools/net/ynl/lib/__init__.py +++ b/tools/net/ynl/lib/__init__.py @@ -2,7 +2,7 @@ from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \ SpecFamily, SpecOperation -from .ynl import YnlFamily +from .ynl import YnlFamily, Netlink __all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet", - "SpecFamily", "SpecOperation", "YnlFamily"] + "SpecFamily", "SpecOperation", "YnlFamily", "Netlink"] diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 0ff0d18666b2..37bcb4d8b37b 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -322,6 +322,26 @@ class SpecOperation(SpecElement): self.attr_set = self.family.attr_sets[attr_set_name] +class SpecMcastGroup(SpecElement): + """Netlink Multicast Group + + Information about a multicast group. + + Value is only used for classic netlink families that use the + netlink-raw schema. Genetlink families use dynamic ID allocation + where the ids of multicast groups get resolved at runtime. Value + will be None for genetlink families. + + Attributes: + name name of the mulitcast group + value integer id of this multicast group for netlink-raw or None + yaml raw spec as loaded from the spec file + """ + def __init__(self, family, yaml): + super().__init__(family, yaml) + self.value = self.yaml.get('value') + + class SpecFamily(SpecElement): """ Netlink Family Spec class. @@ -343,6 +363,7 @@ class SpecFamily(SpecElement): ntfs dict of all async events consts dict of all constants/enums fixed_header string, optional name of family default fixed header struct + mcast_groups dict of all multicast groups (index by name) """ def __init__(self, spec_path, schema_path=None, exclude_ops=None): with open(spec_path, "r") as stream: @@ -384,6 +405,7 @@ class SpecFamily(SpecElement): self.ops = collections.OrderedDict() self.ntfs = collections.OrderedDict() self.consts = collections.OrderedDict() + self.mcast_groups = collections.OrderedDict() last_exception = None while len(self._resolution_list) > 0: @@ -416,6 +438,9 @@ class SpecFamily(SpecElement): def new_operation(self, elem, req_val, rsp_val): return SpecOperation(self, elem, req_val, rsp_val) + def new_mcast_group(self, elem): + return SpecMcastGroup(self, elem) + def add_unresolved(self, elem): self._resolution_list.append(elem) @@ -512,3 +537,9 @@ class SpecFamily(SpecElement): self.ops[op.name] = op elif op.is_async: self.ntfs[op.name] = op + + mcgs = self.yaml.get('mcast-groups') + if mcgs: + for elem in mcgs['list']: + mcg = self.new_mcast_group(elem) + self.mcast_groups[elem['name']] = mcg diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index fa4f1c28efc5..13c4b019a881 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -25,6 +25,7 @@ class Netlink: NETLINK_ADD_MEMBERSHIP = 1 NETLINK_CAP_ACK = 10 NETLINK_EXT_ACK = 11 + NETLINK_GET_STRICT_CHK = 12 # Netlink message NLMSG_ERROR = 2 @@ -34,6 +35,10 @@ class Netlink: NLM_F_ACK = 4 NLM_F_ROOT = 0x100 NLM_F_MATCH = 0x200 + + NLM_F_REPLACE = 0x100 + NLM_F_EXCL = 0x200 + NLM_F_CREATE = 0x400 NLM_F_APPEND = 0x800 NLM_F_CAPPED = 0x100 @@ -228,6 +233,9 @@ class NlMsg: desc += f" ({spec['doc']})" self.extack['miss-type'] = desc + def cmd(self): + return self.nl_type + def __repr__(self): msg = f"nl_len = {self.nl_len} ({len(self.raw)}) nl_flags = 0x{self.nl_flags:x} nl_type = {self.nl_type}\n" if self.error: @@ -293,7 +301,7 @@ def _genl_load_families(): gm = GenlMsg(nl_msg) fam = dict() - for attr in gm.raw_attrs: + for attr in NlAttrs(gm.raw): if attr.type == Netlink.CTRL_ATTR_FAMILY_ID: fam['id'] = attr.as_scalar('u16') elif attr.type == Netlink.CTRL_ATTR_FAMILY_NAME: @@ -317,23 +325,13 @@ def _genl_load_families(): class GenlMsg: - def __init__(self, nl_msg, fixed_header_members=[]): + def __init__(self, nl_msg): self.nl = nl_msg + self.genl_cmd, self.genl_version, _ = struct.unpack_from("BBH", nl_msg.raw, 0) + self.raw = nl_msg.raw[4:] - self.hdr = nl_msg.raw[0:4] - offset = 4 - - self.genl_cmd, self.genl_version, _ = struct.unpack("BBH", self.hdr) - - self.fixed_header_attrs = dict() - for m in fixed_header_members: - format = NlAttr.get_format(m.type, m.byte_order) - decoded = format.unpack_from(nl_msg.raw, offset) - offset += format.size - self.fixed_header_attrs[m.name] = decoded[0] - - self.raw = nl_msg.raw[offset:] - self.raw_attrs = NlAttrs(self.raw) + def cmd(self): + return self.genl_cmd def __repr__(self): msg = repr(self.nl) @@ -343,9 +341,41 @@ class GenlMsg: return msg -class GenlFamily: - def __init__(self, family_name): +class NetlinkProtocol: + def __init__(self, family_name, proto_num): self.family_name = family_name + self.proto_num = proto_num + + def _message(self, nl_type, nl_flags, seq=None): + if seq is None: + seq = random.randint(1, 1024) + nlmsg = struct.pack("HHII", nl_type, nl_flags, seq, 0) + return nlmsg + + def message(self, flags, command, version, seq=None): + return self._message(command, flags, seq) + + def _decode(self, nl_msg): + return nl_msg + + def decode(self, ynl, nl_msg): + msg = self._decode(nl_msg) + fixed_header_size = 0 + if ynl: + op = ynl.rsp_by_value[msg.cmd()] + fixed_header_size = ynl._fixed_header_size(op) + msg.raw_attrs = NlAttrs(msg.raw[fixed_header_size:]) + return msg + + def get_mcast_id(self, mcast_name, mcast_groups): + if mcast_name not in mcast_groups: + raise Exception(f'Multicast group "{mcast_name}" not present in the spec') + return mcast_groups[mcast_name].value + + +class GenlProtocol(NetlinkProtocol): + def __init__(self, family_name): + super().__init__(family_name, Netlink.NETLINK_GENERIC) global genl_family_name_to_id if genl_family_name_to_id is None: @@ -354,6 +384,19 @@ class GenlFamily: self.genl_family = genl_family_name_to_id[family_name] self.family_id = genl_family_name_to_id[family_name]['id'] + def message(self, flags, command, version, seq=None): + nlmsg = self._message(self.family_id, flags, seq) + genlmsg = struct.pack("BBH", command, version, 0) + return nlmsg + genlmsg + + def _decode(self, nl_msg): + return GenlMsg(nl_msg) + + def get_mcast_id(self, mcast_name, mcast_groups): + if mcast_name not in self.genl_family['mcast']: + raise Exception(f'Multicast group "{mcast_name}" not present in the family') + return self.genl_family['mcast'][mcast_name] + # # YNL implementation details. @@ -366,9 +409,19 @@ class YnlFamily(SpecFamily): self.include_raw = False - self.sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, Netlink.NETLINK_GENERIC) + try: + if self.proto == "netlink-raw": + self.nlproto = NetlinkProtocol(self.yaml['name'], + self.yaml['protonum']) + else: + self.nlproto = GenlProtocol(self.yaml['name']) + except KeyError: + raise Exception(f"Family '{self.yaml['name']}' not supported by the kernel") + + self.sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, self.nlproto.proto_num) self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_CAP_ACK, 1) self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_EXT_ACK, 1) + self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_GET_STRICT_CHK, 1) self.async_msg_ids = set() self.async_msg_queue = [] @@ -381,18 +434,12 @@ class YnlFamily(SpecFamily): bound_f = functools.partial(self._op, op_name) setattr(self, op.ident_name, bound_f) - try: - self.family = GenlFamily(self.yaml['name']) - except KeyError: - raise Exception(f"Family '{self.yaml['name']}' not supported by the kernel") def ntf_subscribe(self, mcast_name): - if mcast_name not in self.family.genl_family['mcast']: - raise Exception(f'Multicast group "{mcast_name}" not present in the family') - + mcast_id = self.nlproto.get_mcast_id(mcast_name, self.mcast_groups) self.sock.bind((0, 0)) self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_ADD_MEMBERSHIP, - self.family.genl_family['mcast'][mcast_name]) + mcast_id) def _add_attr(self, space, name, value): try: @@ -454,6 +501,17 @@ class YnlFamily(SpecFamily): decoded = NlAttr.formatted_string(decoded, attr_spec.display_hint) return decoded + def _decode_array_nest(self, attr, attr_spec): + decoded = [] + offset = 0 + while offset < len(attr.raw): + item = NlAttr(attr.raw, offset) + offset += item.full_len + + subattrs = self._decode(NlAttrs(item.raw), attr_spec['nested-attributes']) + decoded.append({ item.type: subattrs }) + return decoded + def _decode(self, attrs, space): attr_space = self.attr_sets[space] rsp = dict() @@ -473,6 +531,8 @@ class YnlFamily(SpecFamily): decoded = True elif attr_spec["type"] in NlAttr.type_formats: decoded = attr.as_scalar(attr_spec['type'], attr_spec.byte_order) + elif attr_spec["type"] == 'array-nest': + decoded = self._decode_array_nest(attr, attr_spec) else: raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}') @@ -514,25 +574,53 @@ class YnlFamily(SpecFamily): return None - def _decode_extack(self, request, attr_space, extack): + def _decode_extack(self, request, op, extack): if 'bad-attr-offs' not in extack: return - genl_req = GenlMsg(NlMsg(request, 0, attr_space=attr_space)) - path = self._decode_extack_path(genl_req.raw_attrs, attr_space, - 20, extack['bad-attr-offs']) + msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set)) + offset = 20 + self._fixed_header_size(op) + path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset, + extack['bad-attr-offs']) if path: del extack['bad-attr-offs'] extack['bad-attr'] = path - def handle_ntf(self, nl_msg, genl_msg): + def _fixed_header_size(self, op): + if op.fixed_header: + fixed_header_members = self.consts[op.fixed_header].members + size = 0 + for m in fixed_header_members: + format = NlAttr.get_format(m.type, m.byte_order) + size += format.size + return size + else: + return 0 + + def _decode_fixed_header(self, msg, name): + fixed_header_members = self.consts[name].members + fixed_header_attrs = dict() + offset = 0 + for m in fixed_header_members: + format = NlAttr.get_format(m.type, m.byte_order) + [ value ] = format.unpack_from(msg.raw, offset) + offset += format.size + if m.enum: + value = self._decode_enum(value, m) + fixed_header_attrs[m.name] = value + return fixed_header_attrs + + def handle_ntf(self, decoded): msg = dict() if self.include_raw: - msg['nlmsg'] = nl_msg - msg['genlmsg'] = genl_msg - op = self.rsp_by_value[genl_msg.genl_cmd] + msg['raw'] = decoded + op = self.rsp_by_value[decoded.cmd()] + attrs = self._decode(decoded.raw_attrs, op.attr_set.name) + if op.fixed_header: + attrs.update(self._decode_fixed_header(decoded, op.fixed_header)) + msg['name'] = op['name'] - msg['msg'] = self._decode(genl_msg.raw_attrs, op.attr_set.name) + msg['msg'] = attrs self.async_msg_queue.append(msg) def check_ntf(self): @@ -552,12 +640,12 @@ class YnlFamily(SpecFamily): print("Netlink done while checking for ntf!?") continue - gm = GenlMsg(nl_msg) - if gm.genl_cmd not in self.async_msg_ids: - print("Unexpected msg id done while checking for ntf", gm) + decoded = self.nlproto.decode(self, nl_msg) + if decoded.cmd() not in self.async_msg_ids: + print("Unexpected msg id done while checking for ntf", decoded) continue - self.handle_ntf(nl_msg, gm) + self.handle_ntf(decoded) def operation_do_attributes(self, name): """ @@ -570,15 +658,17 @@ class YnlFamily(SpecFamily): return op['do']['request']['attributes'].copy() - def _op(self, method, vals, dump=False): + def _op(self, method, vals, flags, dump=False): op = self.ops[method] nl_flags = Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK + for flag in flags or []: + nl_flags |= flag if dump: nl_flags |= Netlink.NLM_F_DUMP req_seq = random.randint(1024, 65535) - msg = _genl_msg(self.family.family_id, nl_flags, op.req_value, 1, req_seq) + msg = self.nlproto.message(nl_flags, op.req_value, 1, req_seq) fixed_header_members = [] if op.fixed_header: fixed_header_members = self.consts[op.fixed_header].members @@ -599,7 +689,7 @@ class YnlFamily(SpecFamily): nms = NlMsgs(reply, attr_space=op.attr_set) for nl_msg in nms: if nl_msg.extack: - self._decode_extack(msg, op.attr_set, nl_msg.extack) + self._decode_extack(msg, op, nl_msg.extack) if nl_msg.error: raise NlError(nl_msg) @@ -610,18 +700,20 @@ class YnlFamily(SpecFamily): done = True break - gm = GenlMsg(nl_msg, fixed_header_members) + decoded = self.nlproto.decode(self, nl_msg) + # Check if this is a reply to our request - if nl_msg.nl_seq != req_seq or gm.genl_cmd != op.rsp_value: - if gm.genl_cmd in self.async_msg_ids: - self.handle_ntf(nl_msg, gm) + if nl_msg.nl_seq != req_seq or decoded.cmd() != op.rsp_value: + if decoded.cmd() in self.async_msg_ids: + self.handle_ntf(decoded) continue else: - print('Unexpected message: ' + repr(gm)) + print('Unexpected message: ' + repr(decoded)) continue - rsp_msg = self._decode(gm.raw_attrs, op.attr_set.name) - rsp_msg.update(gm.fixed_header_attrs) + rsp_msg = self._decode(decoded.raw_attrs, op.attr_set.name) + if op.fixed_header: + rsp_msg.update(self._decode_fixed_header(decoded, op.fixed_header)) rsp.append(rsp_msg) if not rsp: @@ -630,8 +722,8 @@ class YnlFamily(SpecFamily): return rsp[0] return rsp - def do(self, method, vals): - return self._op(method, vals) + def do(self, method, vals, flags): + return self._op(method, vals, flags) def dump(self, method, vals): - return self._op(method, vals, dump=True) + return self._op(method, vals, [], dump=True) diff --git a/tools/perf/bench/Build b/tools/perf/bench/Build index 0f158dc8139b..07bbc449329e 100644 --- a/tools/perf/bench/Build +++ b/tools/perf/bench/Build @@ -1,5 +1,6 @@ perf-y += sched-messaging.o perf-y += sched-pipe.o +perf-y += sched-seccomp-notify.o perf-y += syscall.o perf-y += mem-functions.o perf-y += futex-hash.o diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h index 0d2b65976212..a0625c77bea3 100644 --- a/tools/perf/bench/bench.h +++ b/tools/perf/bench/bench.h @@ -21,6 +21,7 @@ extern struct timeval bench__start, bench__end, bench__runtime; int bench_numa(int argc, const char **argv); int bench_sched_messaging(int argc, const char **argv); int bench_sched_pipe(int argc, const char **argv); +int bench_sched_seccomp_notify(int argc, const char **argv); int bench_syscall_basic(int argc, const char **argv); int bench_syscall_getpgid(int argc, const char **argv); int bench_syscall_fork(int argc, const char **argv); diff --git a/tools/perf/bench/sched-seccomp-notify.c b/tools/perf/bench/sched-seccomp-notify.c new file mode 100644 index 000000000000..b04ebcde4036 --- /dev/null +++ b/tools/perf/bench/sched-seccomp-notify.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <subcmd/parse-options.h> +#include "bench.h" + +#include <uapi/linux/filter.h> +#include <sys/types.h> +#include <sys/time.h> +#include <linux/unistd.h> +#include <sys/syscall.h> +#include <sys/ioctl.h> +#include <linux/time64.h> +#include <linux/seccomp.h> +#include <sys/prctl.h> + +#include <unistd.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/wait.h> +#include <string.h> +#include <errno.h> +#include <err.h> +#include <inttypes.h> + +#define LOOPS_DEFAULT 1000000UL +static uint64_t loops = LOOPS_DEFAULT; +static bool sync_mode; + +static const struct option options[] = { + OPT_U64('l', "loop", &loops, "Specify number of loops"), + OPT_BOOLEAN('s', "sync-mode", &sync_mode, + "Enable the synchronious mode for seccomp notifications"), + OPT_END() +}; + +static const char * const bench_seccomp_usage[] = { + "perf bench sched secccomp-notify <options>", + NULL +}; + +static int seccomp(unsigned int op, unsigned int flags, void *args) +{ + return syscall(__NR_seccomp, op, flags, args); +} + +static int user_notif_syscall(int nr, unsigned int flags) +{ + struct sock_filter filter[] = { + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, + offsetof(struct seccomp_data, nr)), + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, nr, 0, 1), + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_USER_NOTIF), + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), + }; + + struct sock_fprog prog = { + .len = (unsigned short)ARRAY_SIZE(filter), + .filter = filter, + }; + + return seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog); +} + +#define USER_NOTIF_MAGIC INT_MAX +static void user_notification_sync_loop(int listener) +{ + struct seccomp_notif_resp resp; + struct seccomp_notif req; + uint64_t nr; + + for (nr = 0; nr < loops; nr++) { + memset(&req, 0, sizeof(req)); + if (ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req)) + err(EXIT_FAILURE, "SECCOMP_IOCTL_NOTIF_RECV failed"); + + if (req.data.nr != __NR_gettid) + errx(EXIT_FAILURE, "unexpected syscall: %d", req.data.nr); + + resp.id = req.id; + resp.error = 0; + resp.val = USER_NOTIF_MAGIC; + resp.flags = 0; + if (ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp)) + err(EXIT_FAILURE, "SECCOMP_IOCTL_NOTIF_SEND failed"); + } +} + +#ifndef SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP +#define SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP (1UL << 0) +#define SECCOMP_IOCTL_NOTIF_SET_FLAGS SECCOMP_IOW(4, __u64) +#endif +int bench_sched_seccomp_notify(int argc, const char **argv) +{ + struct timeval start, stop, diff; + unsigned long long result_usec = 0; + int status, listener; + pid_t pid; + long ret; + + argc = parse_options(argc, argv, options, bench_seccomp_usage, 0); + + gettimeofday(&start, NULL); + + prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + listener = user_notif_syscall(__NR_gettid, + SECCOMP_FILTER_FLAG_NEW_LISTENER); + if (listener < 0) + err(EXIT_FAILURE, "can't create a notification descriptor"); + + pid = fork(); + if (pid < 0) + err(EXIT_FAILURE, "fork"); + if (pid == 0) { + if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) + err(EXIT_FAILURE, "can't set the parent death signal"); + while (1) { + ret = syscall(__NR_gettid); + if (ret == USER_NOTIF_MAGIC) + continue; + break; + } + _exit(1); + } + + if (sync_mode) { + if (ioctl(listener, SECCOMP_IOCTL_NOTIF_SET_FLAGS, + SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP, 0)) + err(EXIT_FAILURE, + "can't set SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP"); + } + user_notification_sync_loop(listener); + + kill(pid, SIGKILL); + if (waitpid(pid, &status, 0) != pid) + err(EXIT_FAILURE, "waitpid(%d) failed", pid); + if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) + errx(EXIT_FAILURE, "unexpected exit code: %d", status); + + gettimeofday(&stop, NULL); + timersub(&stop, &start, &diff); + + switch (bench_format) { + case BENCH_FORMAT_DEFAULT: + printf("# Executed %" PRIu64 " system calls\n\n", + loops); + + result_usec = diff.tv_sec * USEC_PER_SEC; + result_usec += diff.tv_usec; + + printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", + (unsigned long) diff.tv_sec, + (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); + + printf(" %14lf usecs/op\n", + (double)result_usec / (double)loops); + printf(" %14d ops/sec\n", + (int)((double)loops / + ((double)result_usec / (double)USEC_PER_SEC))); + break; + + case BENCH_FORMAT_SIMPLE: + printf("%lu.%03lu\n", + (unsigned long) diff.tv_sec, + (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); + break; + + default: + /* reaching here is something disaster */ + fprintf(stderr, "Unknown format:%d\n", bench_format); + exit(1); + break; + } + + return 0; +} diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index db435b791a09..5033e8bab276 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -47,6 +47,7 @@ static struct bench numa_benchmarks[] = { static struct bench sched_benchmarks[] = { { "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging }, { "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe }, + { "seccomp-notify", "Benchmark for seccomp user notify", bench_sched_seccomp_notify}, { "all", "Run all scheduler benchmarks", NULL }, { NULL, NULL, NULL } }; diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index 59bfa05dec5d..dc531805a570 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile @@ -53,7 +53,7 @@ DESTDIR ?= VERSION:= $(shell ./utils/version-gen.sh) LIB_MAJ= 0.0.1 -LIB_MIN= 0 +LIB_MIN= 1 PACKAGE = cpupower PACKAGE_BUGREPORT = linux-pm@vger.kernel.org diff --git a/tools/power/cpupower/lib/cpupower.c b/tools/power/cpupower/lib/cpupower.c index 3f7d0c0c5067..7a2ef691b20e 100644 --- a/tools/power/cpupower/lib/cpupower.c +++ b/tools/power/cpupower/lib/cpupower.c @@ -14,6 +14,13 @@ #include "cpupower.h" #include "cpupower_intern.h" +int is_valid_path(const char *path) +{ + if (access(path, F_OK) == -1) + return 0; + return 1; +} + unsigned int cpupower_read_sysfs(const char *path, char *buf, size_t buflen) { ssize_t numread; diff --git a/tools/power/cpupower/lib/cpupower_intern.h b/tools/power/cpupower/lib/cpupower_intern.h index ac1112b956ec..5fdb8620d41b 100644 --- a/tools/power/cpupower/lib/cpupower_intern.h +++ b/tools/power/cpupower/lib/cpupower_intern.h @@ -7,5 +7,6 @@ #define SYSFS_PATH_MAX 255 +int is_valid_path(const char *path); unsigned int cpupower_read_sysfs(const char *path, char *buf, size_t buflen); unsigned int cpupower_write_sysfs(const char *path, char *buf, size_t buflen); diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c index 46158928f9ad..a551d1d4ac51 100644 --- a/tools/power/cpupower/utils/cpuidle-set.c +++ b/tools/power/cpupower/utils/cpuidle-set.c @@ -41,14 +41,6 @@ int cmd_idle_set(int argc, char **argv) cont = 0; break; case 'd': - if (param) { - param = -1; - cont = 0; - break; - } - param = ret; - idlestate = atoi(optarg); - break; case 'e': if (param) { param = -1; @@ -56,7 +48,13 @@ int cmd_idle_set(int argc, char **argv) break; } param = ret; - idlestate = atoi(optarg); + strtol(optarg, &endptr, 10); + if (*endptr != '\0') { + printf(_("Bad value: %s, Integer expected\n"), optarg); + exit(EXIT_FAILURE); + } else { + idlestate = atoi(optarg); + } break; case 'D': if (param) { diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c index 180d5ba877e6..0677b58374ab 100644 --- a/tools/power/cpupower/utils/cpupower-set.c +++ b/tools/power/cpupower/utils/cpupower-set.c @@ -18,6 +18,9 @@ static struct option set_opts[] = { {"perf-bias", required_argument, NULL, 'b'}, + {"epp", required_argument, NULL, 'e'}, + {"amd-pstate-mode", required_argument, NULL, 'm'}, + {"turbo-boost", required_argument, NULL, 't'}, { }, }; @@ -37,11 +40,15 @@ int cmd_set(int argc, char **argv) union { struct { int perf_bias:1; + int epp:1; + int mode:1; + int turbo_boost:1; }; int params; } params; - int perf_bias = 0; + int perf_bias = 0, turbo_boost = 1; int ret = 0; + char epp[30], mode[20]; ret = uname(&uts); if (!ret && (!strcmp(uts.machine, "ppc64le") || @@ -55,7 +62,7 @@ int cmd_set(int argc, char **argv) params.params = 0; /* parameter parsing */ - while ((ret = getopt_long(argc, argv, "b:", + while ((ret = getopt_long(argc, argv, "b:e:m:", set_opts, NULL)) != -1) { switch (ret) { case 'b': @@ -69,6 +76,38 @@ int cmd_set(int argc, char **argv) } params.perf_bias = 1; break; + case 'e': + if (params.epp) + print_wrong_arg_exit(); + if (sscanf(optarg, "%29s", epp) != 1) { + print_wrong_arg_exit(); + return -EINVAL; + } + params.epp = 1; + break; + case 'm': + if (cpupower_cpu_info.vendor != X86_VENDOR_AMD) + print_wrong_arg_exit(); + if (params.mode) + print_wrong_arg_exit(); + if (sscanf(optarg, "%19s", mode) != 1) { + print_wrong_arg_exit(); + return -EINVAL; + } + params.mode = 1; + break; + case 't': + if (params.turbo_boost) + print_wrong_arg_exit(); + turbo_boost = atoi(optarg); + if (turbo_boost < 0 || turbo_boost > 1) { + printf("--turbo-boost param out of range [0-1]\n"); + print_wrong_arg_exit(); + } + params.turbo_boost = 1; + break; + + default: print_wrong_arg_exit(); } @@ -77,6 +116,18 @@ int cmd_set(int argc, char **argv) if (!params.params) print_wrong_arg_exit(); + if (params.mode) { + ret = cpupower_set_amd_pstate_mode(mode); + if (ret) + fprintf(stderr, "Error setting mode\n"); + } + + if (params.turbo_boost) { + ret = cpupower_set_turbo_boost(turbo_boost); + if (ret) + fprintf(stderr, "Error setting turbo-boost\n"); + } + /* Default is: set all CPUs */ if (bitmask_isallclear(cpus_chosen)) bitmask_setall(cpus_chosen); @@ -102,6 +153,16 @@ int cmd_set(int argc, char **argv) break; } } + + if (params.epp) { + ret = cpupower_set_epp(cpu, epp); + if (ret) { + fprintf(stderr, + "Error setting epp value on CPU %d\n", cpu); + break; + } + } + } return ret; } diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index 96e4bede078b..95749b8ee475 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h @@ -116,6 +116,10 @@ extern int cpupower_intel_set_perf_bias(unsigned int cpu, unsigned int val); extern int cpupower_intel_get_perf_bias(unsigned int cpu); extern unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu); +extern int cpupower_set_epp(unsigned int cpu, char *epp); +extern int cpupower_set_amd_pstate_mode(char *mode); +extern int cpupower_set_turbo_boost(int turbo_boost); + /* Read/Write msr ****************************/ /* PCI stuff ****************************/ @@ -173,6 +177,13 @@ static inline int cpupower_intel_get_perf_bias(unsigned int cpu) static inline unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu) { return 0; }; +static inline int cpupower_set_epp(unsigned int cpu, char *epp) +{ return -1; }; +static inline int cpupower_set_amd_pstate_mode(char *mode) +{ return -1; }; +static inline int cpupower_set_turbo_boost(int turbo_boost) +{ return -1; }; + /* Read/Write msr ****************************/ static inline int cpufreq_has_boost_support(unsigned int cpu, int *support, diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c index 9547b29254a7..76e461ff4f74 100644 --- a/tools/power/cpupower/utils/helpers/misc.c +++ b/tools/power/cpupower/utils/helpers/misc.c @@ -87,6 +87,61 @@ int cpupower_intel_set_perf_bias(unsigned int cpu, unsigned int val) return 0; } +int cpupower_set_epp(unsigned int cpu, char *epp) +{ + char path[SYSFS_PATH_MAX]; + char linebuf[30] = {}; + + snprintf(path, sizeof(path), + PATH_TO_CPU "cpu%u/cpufreq/energy_performance_preference", cpu); + + if (!is_valid_path(path)) + return -1; + + snprintf(linebuf, sizeof(linebuf), "%s", epp); + + if (cpupower_write_sysfs(path, linebuf, 30) <= 0) + return -1; + + return 0; +} + +int cpupower_set_amd_pstate_mode(char *mode) +{ + char path[SYSFS_PATH_MAX]; + char linebuf[20] = {}; + + snprintf(path, sizeof(path), PATH_TO_CPU "amd_pstate/status"); + + if (!is_valid_path(path)) + return -1; + + snprintf(linebuf, sizeof(linebuf), "%s\n", mode); + + if (cpupower_write_sysfs(path, linebuf, 20) <= 0) + return -1; + + return 0; +} + +int cpupower_set_turbo_boost(int turbo_boost) +{ + char path[SYSFS_PATH_MAX]; + char linebuf[2] = {}; + + snprintf(path, sizeof(path), PATH_TO_CPU "cpufreq/boost"); + + if (!is_valid_path(path)) + return -1; + + snprintf(linebuf, sizeof(linebuf), "%d", turbo_boost); + + if (cpupower_write_sysfs(path, linebuf, 2) <= 0) + return -1; + + return 0; +} + bool cpupower_amd_pstate_enabled(void) { char *driver = cpufreq_get_driver(0); @@ -95,7 +150,7 @@ bool cpupower_amd_pstate_enabled(void) if (!driver) return ret; - if (!strcmp(driver, "amd-pstate")) + if (!strncmp(driver, "amd", 3)) ret = true; cpufreq_put_driver(driver); diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 8a36ba5df9f9..9a10512e3407 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -5447,7 +5447,7 @@ unsigned int intel_model_duplicates(unsigned int model) case INTEL_FAM6_LAKEFIELD: case INTEL_FAM6_ALDERLAKE: case INTEL_FAM6_ALDERLAKE_L: - case INTEL_FAM6_ALDERLAKE_N: + case INTEL_FAM6_ATOM_GRACEMONT: case INTEL_FAM6_RAPTORLAKE: case INTEL_FAM6_RAPTORLAKE_P: case INTEL_FAM6_RAPTORLAKE_S: diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config index 0393940c706a..873f3e06ccad 100644 --- a/tools/testing/kunit/configs/all_tests.config +++ b/tools/testing/kunit/configs/all_tests.config @@ -33,5 +33,7 @@ CONFIG_DAMON_PADDR=y CONFIG_DEBUG_FS=y CONFIG_DAMON_DBGFS=y +CONFIG_REGMAP_BUILD=y + CONFIG_SECURITY=y CONFIG_SECURITY_APPARMOR=y diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py index 3905c43369c3..bc74088c458a 100755 --- a/tools/testing/kunit/kunit.py +++ b/tools/testing/kunit/kunit.py @@ -55,8 +55,12 @@ class KunitExecRequest(KunitParseRequest): build_dir: str timeout: int filter_glob: str + filter: str + filter_action: Optional[str] kernel_args: Optional[List[str]] run_isolated: Optional[str] + list_tests: bool + list_tests_attr: bool @dataclass class KunitRequest(KunitExecRequest, KunitBuildRequest): @@ -102,19 +106,41 @@ def config_and_build_tests(linux: kunit_kernel.LinuxSourceTree, def _list_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> List[str]: args = ['kunit.action=list'] + + if request.kernel_args: + args.extend(request.kernel_args) + + output = linux.run_kernel(args=args, + timeout=request.timeout, + filter_glob=request.filter_glob, + filter=request.filter, + filter_action=request.filter_action, + build_dir=request.build_dir) + lines = kunit_parser.extract_tap_lines(output) + # Hack! Drop the dummy TAP version header that the executor prints out. + lines.pop() + + # Filter out any extraneous non-test output that might have gotten mixed in. + return [l for l in output if re.match(r'^[^\s.]+\.[^\s.]+$', l)] + +def _list_tests_attr(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> Iterable[str]: + args = ['kunit.action=list_attr'] + if request.kernel_args: args.extend(request.kernel_args) output = linux.run_kernel(args=args, timeout=request.timeout, filter_glob=request.filter_glob, + filter=request.filter, + filter_action=request.filter_action, build_dir=request.build_dir) lines = kunit_parser.extract_tap_lines(output) # Hack! Drop the dummy TAP version header that the executor prints out. lines.pop() # Filter out any extraneous non-test output that might have gotten mixed in. - return [l for l in lines if re.match(r'^[^\s.]+\.[^\s.]+$', l)] + return lines def _suites_from_test_list(tests: List[str]) -> List[str]: """Extracts all the suites from an ordered list of tests.""" @@ -128,10 +154,18 @@ def _suites_from_test_list(tests: List[str]) -> List[str]: suites.append(suite) return suites - - def exec_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> KunitResult: filter_globs = [request.filter_glob] + if request.list_tests: + output = _list_tests(linux, request) + for line in output: + print(line.rstrip()) + return KunitResult(status=KunitStatus.SUCCESS, elapsed_time=0.0) + if request.list_tests_attr: + attr_output = _list_tests_attr(linux, request) + for line in attr_output: + print(line.rstrip()) + return KunitResult(status=KunitStatus.SUCCESS, elapsed_time=0.0) if request.run_isolated: tests = _list_tests(linux, request) if request.run_isolated == 'test': @@ -155,6 +189,8 @@ def exec_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) - args=request.kernel_args, timeout=request.timeout, filter_glob=filter_glob, + filter=request.filter, + filter_action=request.filter_action, build_dir=request.build_dir) _, test_result = parse_tests(request, metadata, run_result) @@ -341,6 +377,16 @@ def add_exec_opts(parser: argparse.ArgumentParser) -> None: nargs='?', default='', metavar='filter_glob') + parser.add_argument('--filter', + help='Filter KUnit tests with attributes, ' + 'e.g. module=example or speed>slow', + type=str, + default='') + parser.add_argument('--filter_action', + help='If set to skip, filtered tests will be skipped, ' + 'e.g. --filter_action=skip. Otherwise they will not run.', + type=str, + choices=['skip']) parser.add_argument('--kernel_args', help='Kernel command-line parameters. Maybe be repeated', action='append', metavar='') @@ -350,6 +396,12 @@ def add_exec_opts(parser: argparse.ArgumentParser) -> None: 'what ran before it.', type=str, choices=['suite', 'test']) + parser.add_argument('--list_tests', help='If set, list all tests that will be ' + 'run.', + action='store_true') + parser.add_argument('--list_tests_attr', help='If set, list all tests and test ' + 'attributes.', + action='store_true') def add_parse_opts(parser: argparse.ArgumentParser) -> None: parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. ' @@ -398,8 +450,12 @@ def run_handler(cli_args: argparse.Namespace) -> None: json=cli_args.json, timeout=cli_args.timeout, filter_glob=cli_args.filter_glob, + filter=cli_args.filter, + filter_action=cli_args.filter_action, kernel_args=cli_args.kernel_args, - run_isolated=cli_args.run_isolated) + run_isolated=cli_args.run_isolated, + list_tests=cli_args.list_tests, + list_tests_attr=cli_args.list_tests_attr) result = run_tests(linux, request) if result.status != KunitStatus.SUCCESS: sys.exit(1) @@ -441,8 +497,12 @@ def exec_handler(cli_args: argparse.Namespace) -> None: json=cli_args.json, timeout=cli_args.timeout, filter_glob=cli_args.filter_glob, + filter=cli_args.filter, + filter_action=cli_args.filter_action, kernel_args=cli_args.kernel_args, - run_isolated=cli_args.run_isolated) + run_isolated=cli_args.run_isolated, + list_tests=cli_args.list_tests, + list_tests_attr=cli_args.list_tests_attr) result = exec_tests(linux, exec_request) stdout.print_with_timestamp(( 'Elapsed time: %.3fs\n') % (result.elapsed_time)) diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py index 7f648802caf6..0b6488efed47 100644 --- a/tools/testing/kunit/kunit_kernel.py +++ b/tools/testing/kunit/kunit_kernel.py @@ -330,11 +330,15 @@ class LinuxSourceTree: return False return self.validate_config(build_dir) - def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', timeout: Optional[int]=None) -> Iterator[str]: + def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', filter: str='', filter_action: Optional[str]=None, timeout: Optional[int]=None) -> Iterator[str]: if not args: args = [] if filter_glob: - args.append('kunit.filter_glob='+filter_glob) + args.append('kunit.filter_glob=' + filter_glob) + if filter: + args.append('kunit.filter="' + filter + '"') + if filter_action: + args.append('kunit.filter_action=' + filter_action) args.append('kunit.enable=1') process = self._ops.start(args, build_dir) diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py index fbc094f0567e..79d8832c862a 100644 --- a/tools/testing/kunit/kunit_parser.py +++ b/tools/testing/kunit/kunit_parser.py @@ -212,6 +212,7 @@ KTAP_START = re.compile(r'\s*KTAP version ([0-9]+)$') TAP_START = re.compile(r'\s*TAP version ([0-9]+)$') KTAP_END = re.compile(r'\s*(List of all partitions:|' 'Kernel panic - not syncing: VFS:|reboot: System halted)') +EXECUTOR_ERROR = re.compile(r'\s*kunit executor: (.*)$') def extract_tap_lines(kernel_output: Iterable[str]) -> LineStream: """Extracts KTAP lines from the kernel output.""" @@ -242,6 +243,8 @@ def extract_tap_lines(kernel_output: Iterable[str]) -> LineStream: # remove the prefix, if any. line = line[prefix_len:] yield line_num, line + elif EXECUTOR_ERROR.search(line): + yield line_num, line return LineStream(lines=isolate_ktap_output(kernel_output)) KTAP_VERSIONS = [1] @@ -447,7 +450,7 @@ def parse_diagnostic(lines: LineStream) -> List[str]: Log of diagnostic lines """ log = [] # type: List[str] - non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START] + non_diagnostic_lines = [TEST_RESULT, TEST_HEADER, KTAP_START, TAP_START] while lines and not any(re.match(lines.peek()) for re in non_diagnostic_lines): log.append(lines.pop()) @@ -713,6 +716,11 @@ def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest: """ test = Test() test.log.extend(log) + + # Parse any errors prior to parsing tests + err_log = parse_diagnostic(lines) + test.log.extend(err_log) + if not is_subtest: # If parsing the main/top-level test, parse KTAP version line and # test plan @@ -774,6 +782,7 @@ def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest: # Don't override a bad status if this test had one reported. # Assumption: no subtests means CRASHED is from Test.__init__() if test.status in (TestStatus.TEST_CRASHED, TestStatus.SUCCESS): + print_log(test.log) test.status = TestStatus.NO_TESTS test.add_error('0 tests run!') diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py index be35999bb84f..b28c1510be2e 100755 --- a/tools/testing/kunit/kunit_tool_test.py +++ b/tools/testing/kunit/kunit_tool_test.py @@ -597,7 +597,7 @@ class KUnitMainTest(unittest.TestCase): self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 0) self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1) self.linux_source_mock.run_kernel.assert_called_once_with( - args=None, build_dir='.kunit', filter_glob='', timeout=300) + args=None, build_dir='.kunit', filter_glob='', filter='', filter_action=None, timeout=300) self.print_mock.assert_any_call(StrContains('Testing complete.')) def test_run_passes_args_pass(self): @@ -605,7 +605,7 @@ class KUnitMainTest(unittest.TestCase): self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1) self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1) self.linux_source_mock.run_kernel.assert_called_once_with( - args=None, build_dir='.kunit', filter_glob='', timeout=300) + args=None, build_dir='.kunit', filter_glob='', filter='', filter_action=None, timeout=300) self.print_mock.assert_any_call(StrContains('Testing complete.')) def test_exec_passes_args_fail(self): @@ -629,7 +629,7 @@ class KUnitMainTest(unittest.TestCase): kunit.main(['run']) self.assertEqual(e.exception.code, 1) self.linux_source_mock.run_kernel.assert_called_once_with( - args=None, build_dir='.kunit', filter_glob='', timeout=300) + args=None, build_dir='.kunit', filter_glob='', filter='', filter_action=None, timeout=300) self.print_mock.assert_any_call(StrContains(' 0 tests run!')) def test_exec_raw_output(self): @@ -670,13 +670,13 @@ class KUnitMainTest(unittest.TestCase): self.linux_source_mock.run_kernel = mock.Mock(return_value=[]) kunit.main(['run', '--raw_output', 'filter_glob']) self.linux_source_mock.run_kernel.assert_called_once_with( - args=None, build_dir='.kunit', filter_glob='filter_glob', timeout=300) + args=None, build_dir='.kunit', filter_glob='filter_glob', filter='', filter_action=None, timeout=300) def test_exec_timeout(self): timeout = 3453 kunit.main(['exec', '--timeout', str(timeout)]) self.linux_source_mock.run_kernel.assert_called_once_with( - args=None, build_dir='.kunit', filter_glob='', timeout=timeout) + args=None, build_dir='.kunit', filter_glob='', filter='', filter_action=None, timeout=timeout) self.print_mock.assert_any_call(StrContains('Testing complete.')) def test_run_timeout(self): @@ -684,7 +684,7 @@ class KUnitMainTest(unittest.TestCase): kunit.main(['run', '--timeout', str(timeout)]) self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1) self.linux_source_mock.run_kernel.assert_called_once_with( - args=None, build_dir='.kunit', filter_glob='', timeout=timeout) + args=None, build_dir='.kunit', filter_glob='', filter='', filter_action=None, timeout=timeout) self.print_mock.assert_any_call(StrContains('Testing complete.')) def test_run_builddir(self): @@ -692,7 +692,7 @@ class KUnitMainTest(unittest.TestCase): kunit.main(['run', '--build_dir=.kunit']) self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1) self.linux_source_mock.run_kernel.assert_called_once_with( - args=None, build_dir=build_dir, filter_glob='', timeout=300) + args=None, build_dir=build_dir, filter_glob='', filter='', filter_action=None, timeout=300) self.print_mock.assert_any_call(StrContains('Testing complete.')) def test_config_builddir(self): @@ -710,7 +710,7 @@ class KUnitMainTest(unittest.TestCase): build_dir = '.kunit' kunit.main(['exec', '--build_dir', build_dir]) self.linux_source_mock.run_kernel.assert_called_once_with( - args=None, build_dir=build_dir, filter_glob='', timeout=300) + args=None, build_dir=build_dir, filter_glob='', filter='', filter_action=None, timeout=300) self.print_mock.assert_any_call(StrContains('Testing complete.')) def test_run_kunitconfig(self): @@ -786,7 +786,7 @@ class KUnitMainTest(unittest.TestCase): kunit.main(['run', '--kernel_args=a=1', '--kernel_args=b=2']) self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1) self.linux_source_mock.run_kernel.assert_called_once_with( - args=['a=1','b=2'], build_dir='.kunit', filter_glob='', timeout=300) + args=['a=1','b=2'], build_dir='.kunit', filter_glob='', filter='', filter_action=None, timeout=300) self.print_mock.assert_any_call(StrContains('Testing complete.')) def test_list_tests(self): @@ -794,13 +794,11 @@ class KUnitMainTest(unittest.TestCase): self.linux_source_mock.run_kernel.return_value = ['TAP version 14', 'init: random output'] + want got = kunit._list_tests(self.linux_source_mock, - kunit.KunitExecRequest(None, None, '.kunit', 300, 'suite*', None, 'suite')) - + kunit.KunitExecRequest(None, None, '.kunit', 300, 'suite*', '', None, None, 'suite', False, False)) self.assertEqual(got, want) # Should respect the user's filter glob when listing tests. self.linux_source_mock.run_kernel.assert_called_once_with( - args=['kunit.action=list'], build_dir='.kunit', filter_glob='suite*', timeout=300) - + args=['kunit.action=list'], build_dir='.kunit', filter_glob='suite*', filter='', filter_action=None, timeout=300) @mock.patch.object(kunit, '_list_tests') def test_run_isolated_by_suite(self, mock_tests): @@ -809,10 +807,10 @@ class KUnitMainTest(unittest.TestCase): # Should respect the user's filter glob when listing tests. mock_tests.assert_called_once_with(mock.ANY, - kunit.KunitExecRequest(None, None, '.kunit', 300, 'suite*.test*', None, 'suite')) + kunit.KunitExecRequest(None, None, '.kunit', 300, 'suite*.test*', '', None, None, 'suite', False, False)) self.linux_source_mock.run_kernel.assert_has_calls([ - mock.call(args=None, build_dir='.kunit', filter_glob='suite.test*', timeout=300), - mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test*', timeout=300), + mock.call(args=None, build_dir='.kunit', filter_glob='suite.test*', filter='', filter_action=None, timeout=300), + mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test*', filter='', filter_action=None, timeout=300), ]) @mock.patch.object(kunit, '_list_tests') @@ -822,13 +820,12 @@ class KUnitMainTest(unittest.TestCase): # Should respect the user's filter glob when listing tests. mock_tests.assert_called_once_with(mock.ANY, - kunit.KunitExecRequest(None, None, '.kunit', 300, 'suite*', None, 'test')) + kunit.KunitExecRequest(None, None, '.kunit', 300, 'suite*', '', None, None, 'test', False, False)) self.linux_source_mock.run_kernel.assert_has_calls([ - mock.call(args=None, build_dir='.kunit', filter_glob='suite.test1', timeout=300), - mock.call(args=None, build_dir='.kunit', filter_glob='suite.test2', timeout=300), - mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', timeout=300), + mock.call(args=None, build_dir='.kunit', filter_glob='suite.test1', filter='', filter_action=None, timeout=300), + mock.call(args=None, build_dir='.kunit', filter_glob='suite.test2', filter='', filter_action=None, timeout=300), + mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', filter='', filter_action=None, timeout=300), ]) - if __name__ == '__main__': unittest.main() diff --git a/tools/testing/kunit/qemu_configs/arm64.py b/tools/testing/kunit/qemu_configs/arm64.py index 67d04064f785..d3ff27024755 100644 --- a/tools/testing/kunit/qemu_configs/arm64.py +++ b/tools/testing/kunit/qemu_configs/arm64.py @@ -9,4 +9,4 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y''', qemu_arch='aarch64', kernel_path='arch/arm64/boot/Image.gz', kernel_command_line='console=ttyAMA0', - extra_qemu_params=['-machine', 'virt', '-cpu', 'cortex-a57']) + extra_qemu_params=['-machine', 'virt', '-cpu', 'max,pauth-impdef=on']) diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 5c60a7cea732..42806add0114 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -13,12 +13,14 @@ TARGETS += core TARGETS += cpufreq TARGETS += cpu-hotplug TARGETS += damon +TARGETS += dmabuf-heaps TARGETS += drivers/dma-buf TARGETS += drivers/s390x/uvdevice TARGETS += drivers/net/bonding TARGETS += drivers/net/team TARGETS += efivarfs TARGETS += exec +TARGETS += fchmodat2 TARGETS += filesystems TARGETS += filesystems/binderfs TARGETS += filesystems/epoll @@ -57,6 +59,7 @@ TARGETS += net/mptcp TARGETS += net/openvswitch TARGETS += netfilter TARGETS += nsfs +TARGETS += perf_events TARGETS += pidfd TARGETS += pid_namespace TARGETS += powerpc @@ -89,7 +92,9 @@ endif TARGETS += tmpfs TARGETS += tpm2 TARGETS += tty +TARGETS += uevents TARGETS += user +TARGETS += user_events TARGETS += vDSO TARGETS += mm TARGETS += x86 diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile index ace8b67fb22d..28b93cab8c0d 100644 --- a/tools/testing/selftests/arm64/Makefile +++ b/tools/testing/selftests/arm64/Makefile @@ -19,6 +19,8 @@ CFLAGS += -I$(top_srcdir)/tools/testing/selftests/ CFLAGS += $(KHDR_INCLUDES) +CFLAGS += -I$(top_srcdir)/tools/include + export CFLAGS export top_srcdir diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c index d4ad813fed10..e3d262831d91 100644 --- a/tools/testing/selftests/arm64/abi/hwcap.c +++ b/tools/testing/selftests/arm64/abi/hwcap.c @@ -19,19 +19,38 @@ #include "../../kselftest.h" -#define TESTS_PER_HWCAP 2 +#define TESTS_PER_HWCAP 3 /* - * Function expected to generate SIGILL when the feature is not - * supported and return when it is supported. If SIGILL is generated - * then the handler must be able to skip over the instruction safely. + * Function expected to generate exception when the feature is not + * supported and return when it is supported. If the specific exception + * is generated then the handler must be able to skip over the + * instruction safely. * * Note that it is expected that for many architecture extensions * there are no specific traps due to no architecture state being * added so we may not fault if running on a kernel which doesn't know * to add the hwcap. */ -typedef void (*sigill_fn)(void); +typedef void (*sig_fn)(void); + +static void aes_sigill(void) +{ + /* AESE V0.16B, V0.16B */ + asm volatile(".inst 0x4e284800" : : : ); +} + +static void atomics_sigill(void) +{ + /* STADD W0, [SP] */ + asm volatile(".inst 0xb82003ff" : : : ); +} + +static void crc32_sigill(void) +{ + /* CRC32W W0, W0, W1 */ + asm volatile(".inst 0x1ac14800" : : : ); +} static void cssc_sigill(void) { @@ -39,6 +58,29 @@ static void cssc_sigill(void) asm volatile(".inst 0xdac01c00" : : : "x0"); } +static void fp_sigill(void) +{ + asm volatile("fmov s0, #1"); +} + +static void ilrcpc_sigill(void) +{ + /* LDAPUR W0, [SP, #8] */ + asm volatile(".inst 0x994083e0" : : : ); +} + +static void jscvt_sigill(void) +{ + /* FJCVTZS W0, D0 */ + asm volatile(".inst 0x1e7e0000" : : : ); +} + +static void lrcpc_sigill(void) +{ + /* LDAPR W0, [SP, #0] */ + asm volatile(".inst 0xb8bfc3e0" : : : ); +} + static void mops_sigill(void) { char dst[1], src[1]; @@ -53,11 +95,35 @@ static void mops_sigill(void) : "cc", "memory"); } +static void pmull_sigill(void) +{ + /* PMULL V0.1Q, V0.1D, V0.1D */ + asm volatile(".inst 0x0ee0e000" : : : ); +} + static void rng_sigill(void) { asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0"); } +static void sha1_sigill(void) +{ + /* SHA1H S0, S0 */ + asm volatile(".inst 0x5e280800" : : : ); +} + +static void sha2_sigill(void) +{ + /* SHA256H Q0, Q0, V0.4S */ + asm volatile(".inst 0x5e004000" : : : ); +} + +static void sha512_sigill(void) +{ + /* SHA512H Q0, Q0, V0.2D */ + asm volatile(".inst 0xce608000" : : : ); +} + static void sme_sigill(void) { /* RDSVL x0, #0 */ @@ -208,15 +274,46 @@ static void svebf16_sigill(void) asm volatile(".inst 0x658aa000" : : : "z0"); } +static void hbc_sigill(void) +{ + /* BC.EQ +4 */ + asm volatile("cmp xzr, xzr\n" + ".inst 0x54000030" : : : "cc"); +} + +static void uscat_sigbus(void) +{ + /* unaligned atomic access */ + asm volatile("ADD x1, sp, #2" : : : ); + /* STADD W0, [X1] */ + asm volatile(".inst 0xb820003f" : : : ); +} + static const struct hwcap_data { const char *name; unsigned long at_hwcap; unsigned long hwcap_bit; const char *cpuinfo; - sigill_fn sigill_fn; + sig_fn sigill_fn; bool sigill_reliable; + sig_fn sigbus_fn; + bool sigbus_reliable; } hwcaps[] = { { + .name = "AES", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_AES, + .cpuinfo = "aes", + .sigill_fn = aes_sigill, + }, + { + .name = "CRC32", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_CRC32, + .cpuinfo = "crc32", + .sigill_fn = crc32_sigill, + }, + { .name = "CSSC", .at_hwcap = AT_HWCAP2, .hwcap_bit = HWCAP2_CSSC, @@ -224,6 +321,50 @@ static const struct hwcap_data { .sigill_fn = cssc_sigill, }, { + .name = "FP", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_FP, + .cpuinfo = "fp", + .sigill_fn = fp_sigill, + }, + { + .name = "JSCVT", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_JSCVT, + .cpuinfo = "jscvt", + .sigill_fn = jscvt_sigill, + }, + { + .name = "LRCPC", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_LRCPC, + .cpuinfo = "lrcpc", + .sigill_fn = lrcpc_sigill, + }, + { + .name = "LRCPC2", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_ILRCPC, + .cpuinfo = "ilrcpc", + .sigill_fn = ilrcpc_sigill, + }, + { + .name = "LSE", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_ATOMICS, + .cpuinfo = "atomics", + .sigill_fn = atomics_sigill, + }, + { + .name = "LSE2", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_USCAT, + .cpuinfo = "uscat", + .sigill_fn = atomics_sigill, + .sigbus_fn = uscat_sigbus, + .sigbus_reliable = true, + }, + { .name = "MOPS", .at_hwcap = AT_HWCAP2, .hwcap_bit = HWCAP2_MOPS, @@ -232,6 +373,13 @@ static const struct hwcap_data { .sigill_reliable = true, }, { + .name = "PMULL", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_PMULL, + .cpuinfo = "pmull", + .sigill_fn = pmull_sigill, + }, + { .name = "RNG", .at_hwcap = AT_HWCAP2, .hwcap_bit = HWCAP2_RNG, @@ -245,6 +393,27 @@ static const struct hwcap_data { .cpuinfo = "rprfm", }, { + .name = "SHA1", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_SHA1, + .cpuinfo = "sha1", + .sigill_fn = sha1_sigill, + }, + { + .name = "SHA2", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_SHA2, + .cpuinfo = "sha2", + .sigill_fn = sha2_sigill, + }, + { + .name = "SHA512", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_SHA512, + .cpuinfo = "sha512", + .sigill_fn = sha512_sigill, + }, + { .name = "SME", .at_hwcap = AT_HWCAP2, .hwcap_bit = HWCAP2_SME, @@ -386,20 +555,32 @@ static const struct hwcap_data { .hwcap_bit = HWCAP2_SVE_EBF16, .cpuinfo = "sveebf16", }, + { + .name = "HBC", + .at_hwcap = AT_HWCAP2, + .hwcap_bit = HWCAP2_HBC, + .cpuinfo = "hbc", + .sigill_fn = hbc_sigill, + .sigill_reliable = true, + }, }; -static bool seen_sigill; - -static void handle_sigill(int sig, siginfo_t *info, void *context) -{ - ucontext_t *uc = context; - - seen_sigill = true; - - /* Skip over the offending instruction */ - uc->uc_mcontext.pc += 4; +typedef void (*sighandler_fn)(int, siginfo_t *, void *); + +#define DEF_SIGHANDLER_FUNC(SIG, NUM) \ +static bool seen_##SIG; \ +static void handle_##SIG(int sig, siginfo_t *info, void *context) \ +{ \ + ucontext_t *uc = context; \ + \ + seen_##SIG = true; \ + /* Skip over the offending instruction */ \ + uc->uc_mcontext.pc += 4; \ } +DEF_SIGHANDLER_FUNC(sigill, SIGILL); +DEF_SIGHANDLER_FUNC(sigbus, SIGBUS); + bool cpuinfo_present(const char *name) { FILE *f; @@ -442,24 +623,77 @@ bool cpuinfo_present(const char *name) return false; } -int main(void) +static int install_sigaction(int signum, sighandler_fn handler) { - const struct hwcap_data *hwcap; - int i, ret; - bool have_cpuinfo, have_hwcap; + int ret; struct sigaction sa; - ksft_print_header(); - ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP); - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handle_sigill; + sa.sa_sigaction = handler; sa.sa_flags = SA_RESTART | SA_SIGINFO; sigemptyset(&sa.sa_mask); - ret = sigaction(SIGILL, &sa, NULL); + ret = sigaction(signum, &sa, NULL); if (ret < 0) - ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n", + ksft_exit_fail_msg("Failed to install SIGNAL handler: %s (%d)\n", + strerror(errno), errno); + + return ret; +} + +static void uninstall_sigaction(int signum) +{ + if (sigaction(signum, NULL, NULL) < 0) + ksft_exit_fail_msg("Failed to uninstall SIGNAL handler: %s (%d)\n", strerror(errno), errno); +} + +#define DEF_INST_RAISE_SIG(SIG, NUM) \ +static bool inst_raise_##SIG(const struct hwcap_data *hwcap, \ + bool have_hwcap) \ +{ \ + if (!hwcap->SIG##_fn) { \ + ksft_test_result_skip(#SIG"_%s\n", hwcap->name); \ + /* assume that it would raise exception in default */ \ + return true; \ + } \ + \ + install_sigaction(NUM, handle_##SIG); \ + \ + seen_##SIG = false; \ + hwcap->SIG##_fn(); \ + \ + if (have_hwcap) { \ + /* Should be able to use the extension */ \ + ksft_test_result(!seen_##SIG, \ + #SIG"_%s\n", hwcap->name); \ + } else if (hwcap->SIG##_reliable) { \ + /* Guaranteed a SIGNAL */ \ + ksft_test_result(seen_##SIG, \ + #SIG"_%s\n", hwcap->name); \ + } else { \ + /* Missing SIGNAL might be fine */ \ + ksft_print_msg(#SIG"_%sreported for %s\n", \ + seen_##SIG ? "" : "not ", \ + hwcap->name); \ + ksft_test_result_skip(#SIG"_%s\n", \ + hwcap->name); \ + } \ + \ + uninstall_sigaction(NUM); \ + return seen_##SIG; \ +} + +DEF_INST_RAISE_SIG(sigill, SIGILL); +DEF_INST_RAISE_SIG(sigbus, SIGBUS); + +int main(void) +{ + int i; + const struct hwcap_data *hwcap; + bool have_cpuinfo, have_hwcap, raise_sigill; + + ksft_print_header(); + ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP); for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { hwcap = &hwcaps[i]; @@ -473,30 +707,15 @@ int main(void) ksft_test_result(have_hwcap == have_cpuinfo, "cpuinfo_match_%s\n", hwcap->name); - if (hwcap->sigill_fn) { - seen_sigill = false; - hwcap->sigill_fn(); - - if (have_hwcap) { - /* Should be able to use the extension */ - ksft_test_result(!seen_sigill, "sigill_%s\n", - hwcap->name); - } else if (hwcap->sigill_reliable) { - /* Guaranteed a SIGILL */ - ksft_test_result(seen_sigill, "sigill_%s\n", - hwcap->name); - } else { - /* Missing SIGILL might be fine */ - ksft_print_msg("SIGILL %sreported for %s\n", - seen_sigill ? "" : "not ", - hwcap->name); - ksft_test_result_skip("sigill_%s\n", - hwcap->name); - } - } else { - ksft_test_result_skip("sigill_%s\n", - hwcap->name); - } + /* + * Testing for SIGBUS only makes sense after make sure + * that the instruction does not cause a SIGILL signal. + */ + raise_sigill = inst_raise_sigill(hwcap, have_hwcap); + if (!raise_sigill) + inst_raise_sigbus(hwcap, have_hwcap); + else + ksft_test_result_skip("sigbus_%s\n", hwcap->name); } ksft_print_cnts(); diff --git a/tools/testing/selftests/arm64/abi/syscall-abi.c b/tools/testing/selftests/arm64/abi/syscall-abi.c index 18cc123e2347..d704511a0955 100644 --- a/tools/testing/selftests/arm64/abi/syscall-abi.c +++ b/tools/testing/selftests/arm64/abi/syscall-abi.c @@ -20,12 +20,20 @@ #include "syscall-abi.h" +/* + * The kernel defines a much larger SVE_VQ_MAX than is expressable in + * the architecture, this creates a *lot* of overhead filling the + * buffers (especially ZA) on emulated platforms so use the actual + * architectural maximum instead. + */ +#define ARCH_SVE_VQ_MAX 16 + static int default_sme_vl; static int sve_vl_count; -static unsigned int sve_vls[SVE_VQ_MAX]; +static unsigned int sve_vls[ARCH_SVE_VQ_MAX]; static int sme_vl_count; -static unsigned int sme_vls[SVE_VQ_MAX]; +static unsigned int sme_vls[ARCH_SVE_VQ_MAX]; extern void do_syscall(int sve_vl, int sme_vl); @@ -130,9 +138,9 @@ static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, #define SVE_Z_SHARED_BYTES (128 / 8) -static uint8_t z_zero[__SVE_ZREG_SIZE(SVE_VQ_MAX)]; -uint8_t z_in[SVE_NUM_ZREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)]; -uint8_t z_out[SVE_NUM_ZREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)]; +static uint8_t z_zero[__SVE_ZREG_SIZE(ARCH_SVE_VQ_MAX)]; +uint8_t z_in[SVE_NUM_ZREGS * __SVE_ZREG_SIZE(ARCH_SVE_VQ_MAX)]; +uint8_t z_out[SVE_NUM_ZREGS * __SVE_ZREG_SIZE(ARCH_SVE_VQ_MAX)]; static void setup_z(struct syscall_cfg *cfg, int sve_vl, int sme_vl, uint64_t svcr) @@ -190,8 +198,8 @@ static int check_z(struct syscall_cfg *cfg, int sve_vl, int sme_vl, return errors; } -uint8_t p_in[SVE_NUM_PREGS * __SVE_PREG_SIZE(SVE_VQ_MAX)]; -uint8_t p_out[SVE_NUM_PREGS * __SVE_PREG_SIZE(SVE_VQ_MAX)]; +uint8_t p_in[SVE_NUM_PREGS * __SVE_PREG_SIZE(ARCH_SVE_VQ_MAX)]; +uint8_t p_out[SVE_NUM_PREGS * __SVE_PREG_SIZE(ARCH_SVE_VQ_MAX)]; static void setup_p(struct syscall_cfg *cfg, int sve_vl, int sme_vl, uint64_t svcr) @@ -222,8 +230,8 @@ static int check_p(struct syscall_cfg *cfg, int sve_vl, int sme_vl, return errors; } -uint8_t ffr_in[__SVE_PREG_SIZE(SVE_VQ_MAX)]; -uint8_t ffr_out[__SVE_PREG_SIZE(SVE_VQ_MAX)]; +uint8_t ffr_in[__SVE_PREG_SIZE(ARCH_SVE_VQ_MAX)]; +uint8_t ffr_out[__SVE_PREG_SIZE(ARCH_SVE_VQ_MAX)]; static void setup_ffr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, uint64_t svcr) @@ -300,8 +308,8 @@ static int check_svcr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, return errors; } -uint8_t za_in[ZA_SIG_REGS_SIZE(SVE_VQ_MAX)]; -uint8_t za_out[ZA_SIG_REGS_SIZE(SVE_VQ_MAX)]; +uint8_t za_in[ZA_SIG_REGS_SIZE(ARCH_SVE_VQ_MAX)]; +uint8_t za_out[ZA_SIG_REGS_SIZE(ARCH_SVE_VQ_MAX)]; static void setup_za(struct syscall_cfg *cfg, int sve_vl, int sme_vl, uint64_t svcr) @@ -470,9 +478,9 @@ void sve_count_vls(void) return; /* - * Enumerate up to SVE_VQ_MAX vector lengths + * Enumerate up to ARCH_SVE_VQ_MAX vector lengths */ - for (vq = SVE_VQ_MAX; vq > 0; vq /= 2) { + for (vq = ARCH_SVE_VQ_MAX; vq > 0; vq /= 2) { vl = prctl(PR_SVE_SET_VL, vq * 16); if (vl == -1) ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n", @@ -496,9 +504,9 @@ void sme_count_vls(void) return; /* - * Enumerate up to SVE_VQ_MAX vector lengths + * Enumerate up to ARCH_SVE_VQ_MAX vector lengths */ - for (vq = SVE_VQ_MAX; vq > 0; vq /= 2) { + for (vq = ARCH_SVE_VQ_MAX; vq > 0; vq /= 2) { vl = prctl(PR_SME_SET_VL, vq * 16); if (vl == -1) ksft_exit_fail_msg("PR_SME_SET_VL failed: %s (%d)\n", diff --git a/tools/testing/selftests/arm64/bti/Makefile b/tools/testing/selftests/arm64/bti/Makefile index ccdac414ad94..05e4ee523a53 100644 --- a/tools/testing/selftests/arm64/bti/Makefile +++ b/tools/testing/selftests/arm64/bti/Makefile @@ -2,8 +2,6 @@ TEST_GEN_PROGS := btitest nobtitest -PROGS := $(patsubst %,gen/%,$(TEST_GEN_PROGS)) - # These tests are built as freestanding binaries since otherwise BTI # support in ld.so is required which is not currently widespread; when # it is available it will still be useful to test this separately as the @@ -18,44 +16,41 @@ CFLAGS_COMMON = -ffreestanding -Wall -Wextra $(CFLAGS) BTI_CC_COMMAND = $(CC) $(CFLAGS_BTI) $(CFLAGS_COMMON) -c -o $@ $< NOBTI_CC_COMMAND = $(CC) $(CFLAGS_NOBTI) $(CFLAGS_COMMON) -c -o $@ $< -%-bti.o: %.c +$(OUTPUT)/%-bti.o: %.c $(BTI_CC_COMMAND) -%-bti.o: %.S +$(OUTPUT)/%-bti.o: %.S $(BTI_CC_COMMAND) -%-nobti.o: %.c +$(OUTPUT)/%-nobti.o: %.c $(NOBTI_CC_COMMAND) -%-nobti.o: %.S +$(OUTPUT)/%-nobti.o: %.S $(NOBTI_CC_COMMAND) BTI_OBJS = \ - test-bti.o \ - signal-bti.o \ - start-bti.o \ - syscall-bti.o \ - system-bti.o \ - teststubs-bti.o \ - trampoline-bti.o -gen/btitest: $(BTI_OBJS) + $(OUTPUT)/test-bti.o \ + $(OUTPUT)/signal-bti.o \ + $(OUTPUT)/start-bti.o \ + $(OUTPUT)/syscall-bti.o \ + $(OUTPUT)/system-bti.o \ + $(OUTPUT)/teststubs-bti.o \ + $(OUTPUT)/trampoline-bti.o +$(OUTPUT)/btitest: $(BTI_OBJS) $(CC) $(CFLAGS_BTI) $(CFLAGS_COMMON) -nostdlib -static -o $@ $^ NOBTI_OBJS = \ - test-nobti.o \ - signal-nobti.o \ - start-nobti.o \ - syscall-nobti.o \ - system-nobti.o \ - teststubs-nobti.o \ - trampoline-nobti.o -gen/nobtitest: $(NOBTI_OBJS) + $(OUTPUT)/test-nobti.o \ + $(OUTPUT)/signal-nobti.o \ + $(OUTPUT)/start-nobti.o \ + $(OUTPUT)/syscall-nobti.o \ + $(OUTPUT)/system-nobti.o \ + $(OUTPUT)/teststubs-nobti.o \ + $(OUTPUT)/trampoline-nobti.o +$(OUTPUT)/nobtitest: $(NOBTI_OBJS) $(CC) $(CFLAGS_BTI) $(CFLAGS_COMMON) -nostdlib -static -o $@ $^ # Including KSFT lib.mk here will also mangle the TEST_GEN_PROGS list # to account for any OUTPUT target-dirs optionally provided by # the toplevel makefile include ../../lib.mk - -$(TEST_GEN_PROGS): $(PROGS) - cp $(PROGS) $(OUTPUT)/ diff --git a/tools/testing/selftests/arm64/bti/compiler.h b/tools/testing/selftests/arm64/bti/compiler.h deleted file mode 100644 index ebb6204f447a..000000000000 --- a/tools/testing/selftests/arm64/bti/compiler.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2019 Arm Limited - * Original author: Dave Martin <Dave.Martin@arm.com> - */ - -#ifndef COMPILER_H -#define COMPILER_H - -#define __always_unused __attribute__((__unused__)) -#define __noreturn __attribute__((__noreturn__)) -#define __unreachable() __builtin_unreachable() - -/* curse(e) has value e, but the compiler cannot assume so */ -#define curse(e) ({ \ - __typeof__(e) __curse_e = (e); \ - asm ("" : "+r" (__curse_e)); \ - __curse_e; \ -}) - -#endif /* ! COMPILER_H */ diff --git a/tools/testing/selftests/arm64/bti/gen/.gitignore b/tools/testing/selftests/arm64/bti/gen/.gitignore deleted file mode 100644 index 73869fabada4..000000000000 --- a/tools/testing/selftests/arm64/bti/gen/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -btitest -nobtitest diff --git a/tools/testing/selftests/arm64/bti/system.c b/tools/testing/selftests/arm64/bti/system.c index 6385d8d4973b..93d772b00bfe 100644 --- a/tools/testing/selftests/arm64/bti/system.c +++ b/tools/testing/selftests/arm64/bti/system.c @@ -8,12 +8,10 @@ #include <asm/unistd.h> -#include "compiler.h" - void __noreturn exit(int n) { syscall(__NR_exit, n); - __unreachable(); + unreachable(); } ssize_t write(int fd, const void *buf, size_t size) diff --git a/tools/testing/selftests/arm64/bti/system.h b/tools/testing/selftests/arm64/bti/system.h index aca118589705..2e9ee1284a0c 100644 --- a/tools/testing/selftests/arm64/bti/system.h +++ b/tools/testing/selftests/arm64/bti/system.h @@ -14,12 +14,12 @@ typedef __kernel_size_t size_t; typedef __kernel_ssize_t ssize_t; #include <linux/errno.h> +#include <linux/compiler.h> + #include <asm/hwcap.h> #include <asm/ptrace.h> #include <asm/unistd.h> -#include "compiler.h" - long syscall(int nr, ...); void __noreturn exit(int n); diff --git a/tools/testing/selftests/arm64/bti/test.c b/tools/testing/selftests/arm64/bti/test.c index 2cd8dcee5aec..28a8e8a28a84 100644 --- a/tools/testing/selftests/arm64/bti/test.c +++ b/tools/testing/selftests/arm64/bti/test.c @@ -17,7 +17,6 @@ typedef struct ucontext ucontext_t; #include "btitest.h" -#include "compiler.h" #include "signal.h" #define EXPECTED_TESTS 18 diff --git a/tools/testing/selftests/arm64/fp/vec-syscfg.c b/tools/testing/selftests/arm64/fp/vec-syscfg.c index 9bcfcdc34ee9..5f648b97a06f 100644 --- a/tools/testing/selftests/arm64/fp/vec-syscfg.c +++ b/tools/testing/selftests/arm64/fp/vec-syscfg.c @@ -6,6 +6,7 @@ #include <assert.h> #include <errno.h> #include <fcntl.h> +#include <stdbool.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> @@ -39,9 +40,11 @@ struct vec_data { int max_vl; }; +#define VEC_SVE 0 +#define VEC_SME 1 static struct vec_data vec_data[] = { - { + [VEC_SVE] = { .name = "SVE", .hwcap_type = AT_HWCAP, .hwcap = HWCAP_SVE, @@ -51,7 +54,7 @@ static struct vec_data vec_data[] = { .prctl_set = PR_SVE_SET_VL, .default_vl_file = "/proc/sys/abi/sve_default_vector_length", }, - { + [VEC_SME] = { .name = "SME", .hwcap_type = AT_HWCAP2, .hwcap = HWCAP2_SME, @@ -551,7 +554,8 @@ static void prctl_set_onexec(struct vec_data *data) /* For each VQ verify that setting via prctl() does the right thing */ static void prctl_set_all_vqs(struct vec_data *data) { - int ret, vq, vl, new_vl; + int ret, vq, vl, new_vl, i; + int orig_vls[ARRAY_SIZE(vec_data)]; int errors = 0; if (!data->min_vl || !data->max_vl) { @@ -560,6 +564,9 @@ static void prctl_set_all_vqs(struct vec_data *data) return; } + for (i = 0; i < ARRAY_SIZE(vec_data); i++) + orig_vls[i] = vec_data[i].rdvl(); + for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) { vl = sve_vl_from_vq(vq); @@ -582,6 +589,22 @@ static void prctl_set_all_vqs(struct vec_data *data) errors++; } + /* Did any other VLs change? */ + for (i = 0; i < ARRAY_SIZE(vec_data); i++) { + if (&vec_data[i] == data) + continue; + + if (!(getauxval(vec_data[i].hwcap_type) & vec_data[i].hwcap)) + continue; + + if (vec_data[i].rdvl() != orig_vls[i]) { + ksft_print_msg("%s VL changed from %d to %d\n", + vec_data[i].name, orig_vls[i], + vec_data[i].rdvl()); + errors++; + } + } + /* Was that the VL we asked for? */ if (new_vl == vl) continue; @@ -644,18 +667,107 @@ static const test_type tests[] = { prctl_set_all_vqs, }; +static inline void smstart(void) +{ + asm volatile("msr S0_3_C4_C7_3, xzr"); +} + +static inline void smstart_sm(void) +{ + asm volatile("msr S0_3_C4_C3_3, xzr"); +} + +static inline void smstop(void) +{ + asm volatile("msr S0_3_C4_C6_3, xzr"); +} + + +/* + * Verify we can change the SVE vector length while SME is active and + * continue to use SME afterwards. + */ +static void change_sve_with_za(void) +{ + struct vec_data *sve_data = &vec_data[VEC_SVE]; + bool pass = true; + int ret, i; + + if (sve_data->min_vl == sve_data->max_vl) { + ksft_print_msg("Only one SVE VL supported, can't change\n"); + ksft_test_result_skip("change_sve_while_sme\n"); + return; + } + + /* Ensure we will trigger a change when we set the maximum */ + ret = prctl(sve_data->prctl_set, sve_data->min_vl); + if (ret != sve_data->min_vl) { + ksft_print_msg("Failed to set SVE VL %d: %d\n", + sve_data->min_vl, ret); + pass = false; + } + + /* Enable SM and ZA */ + smstart(); + + /* Trigger another VL change */ + ret = prctl(sve_data->prctl_set, sve_data->max_vl); + if (ret != sve_data->max_vl) { + ksft_print_msg("Failed to set SVE VL %d: %d\n", + sve_data->max_vl, ret); + pass = false; + } + + /* + * Spin for a bit with SM enabled to try to trigger another + * save/restore. We can't use syscalls without exiting + * streaming mode. + */ + for (i = 0; i < 100000000; i++) + smstart_sm(); + + /* + * TODO: Verify that ZA was preserved over the VL change and + * spin. + */ + + /* Clean up after ourselves */ + smstop(); + ret = prctl(sve_data->prctl_set, sve_data->default_vl); + if (ret != sve_data->default_vl) { + ksft_print_msg("Failed to restore SVE VL %d: %d\n", + sve_data->default_vl, ret); + pass = false; + } + + ksft_test_result(pass, "change_sve_with_za\n"); +} + +typedef void (*test_all_type)(void); + +static const struct { + const char *name; + test_all_type test; +} all_types_tests[] = { + { "change_sve_with_za", change_sve_with_za }, +}; + int main(void) { + bool all_supported = true; int i, j; ksft_print_header(); - ksft_set_plan(ARRAY_SIZE(tests) * ARRAY_SIZE(vec_data)); + ksft_set_plan(ARRAY_SIZE(tests) * ARRAY_SIZE(vec_data) + + ARRAY_SIZE(all_types_tests)); for (i = 0; i < ARRAY_SIZE(vec_data); i++) { struct vec_data *data = &vec_data[i]; unsigned long supported; supported = getauxval(data->hwcap_type) & data->hwcap; + if (!supported) + all_supported = false; for (j = 0; j < ARRAY_SIZE(tests); j++) { if (supported) @@ -666,5 +778,12 @@ int main(void) } } + for (i = 0; i < ARRAY_SIZE(all_types_tests); i++) { + if (all_supported) + all_types_tests[i].test(); + else + ksft_test_result_skip("%s\n", all_types_tests[i].name); + } + ksft_exit_pass(); } diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h index 222093f51b67..762c8fe9c54a 100644 --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h @@ -8,6 +8,8 @@ #include <stdio.h> #include <string.h> +#include <linux/compiler.h> + #include "test_signals.h" int test_init(struct tdescr *td); @@ -60,13 +62,25 @@ static __always_inline bool get_current_context(struct tdescr *td, size_t dest_sz) { static volatile bool seen_already; + int i; + char *uc = (char *)dest_uc; assert(td && dest_uc); /* it's a genuine invocation..reinit */ seen_already = 0; td->live_uc_valid = 0; td->live_sz = dest_sz; - memset(dest_uc, 0x00, td->live_sz); + + /* + * This is a memset() but we don't want the compiler to + * optimise it into either instructions or a library call + * which might be incompatible with streaming mode. + */ + for (i = 0; i < td->live_sz; i++) { + uc[i] = 0; + OPTIMIZER_HIDE_VAR(uc[0]); + } + td->live_uc = dest_uc; /* * Grab ucontext_t triggering a SIGTRAP. @@ -104,6 +118,17 @@ static __always_inline bool get_current_context(struct tdescr *td, : "memory"); /* + * If we were grabbing a streaming mode context then we may + * have entered streaming mode behind the system's back and + * libc or compiler generated code might decide to do + * something invalid in streaming mode, or potentially even + * the state of ZA. Issue a SMSTOP to exit both now we have + * grabbed the state. + */ + if (td->feats_supported & FEAT_SME) + asm volatile("msr S0_3_C4_C6_3, xzr"); + + /* * If we get here with seen_already==1 it implies the td->live_uc * context has been used to get back here....this probably means * a test has failed to cause a SEGV...anyway live_uc does not diff --git a/tools/testing/selftests/arm64/signal/testcases/zt_regs.c b/tools/testing/selftests/arm64/signal/testcases/zt_regs.c index e1eb4d5c027a..2e384d731618 100644 --- a/tools/testing/selftests/arm64/signal/testcases/zt_regs.c +++ b/tools/testing/selftests/arm64/signal/testcases/zt_regs.c @@ -65,6 +65,7 @@ int zt_regs_run(struct tdescr *td, siginfo_t *si, ucontext_t *uc) if (memcmp(zeros, (char *)zt + ZT_SIG_REGS_OFFSET, ZT_SIG_REGS_SIZE(zt->nregs)) != 0) { fprintf(stderr, "ZT data invalid\n"); + free(zeros); return 1; } diff --git a/tools/testing/selftests/cachestat/Makefile b/tools/testing/selftests/cachestat/Makefile index fca73aaa7d14..778b54ebb036 100644 --- a/tools/testing/selftests/cachestat/Makefile +++ b/tools/testing/selftests/cachestat/Makefile @@ -3,6 +3,6 @@ TEST_GEN_PROGS := test_cachestat CFLAGS += $(KHDR_INCLUDES) CFLAGS += -Wall -CFLAGS += -lrt +LDLIBS += -lrt include ../lib.mk diff --git a/tools/testing/selftests/cachestat/test_cachestat.c b/tools/testing/selftests/cachestat/test_cachestat.c index 54d09b820ed4..4804c7dc7b31 100644 --- a/tools/testing/selftests/cachestat/test_cachestat.c +++ b/tools/testing/selftests/cachestat/test_cachestat.c @@ -4,10 +4,12 @@ #include <stdio.h> #include <stdbool.h> #include <linux/kernel.h> +#include <linux/magic.h> #include <linux/mman.h> #include <sys/mman.h> #include <sys/shm.h> #include <sys/syscall.h> +#include <sys/vfs.h> #include <unistd.h> #include <string.h> #include <fcntl.h> @@ -15,11 +17,12 @@ #include "../kselftest.h" +#define NR_TESTS 9 + static const char * const dev_files[] = { "/dev/zero", "/dev/null", "/dev/urandom", "/proc/version", "/proc" }; -static const int cachestat_nr = 451; void print_cachestat(struct cachestat *cs) { @@ -91,19 +94,33 @@ out: } /* + * fsync() is implemented via noop_fsync() on tmpfs. This makes the fsync() + * test fail below, so we need to check for test file living on a tmpfs. + */ +static bool is_on_tmpfs(int fd) +{ + struct statfs statfs_buf; + + if (fstatfs(fd, &statfs_buf)) + return false; + + return statfs_buf.f_type == TMPFS_MAGIC; +} + +/* * Open/create the file at filename, (optionally) write random data to it * (exactly num_pages), then test the cachestat syscall on this file. * * If test_fsync == true, fsync the file, then check the number of dirty * pages. */ -bool test_cachestat(const char *filename, bool write_random, bool create, - bool test_fsync, unsigned long num_pages, int open_flags, - mode_t open_mode) +static int test_cachestat(const char *filename, bool write_random, bool create, + bool test_fsync, unsigned long num_pages, + int open_flags, mode_t open_mode) { size_t PS = sysconf(_SC_PAGESIZE); int filesize = num_pages * PS; - bool ret = true; + int ret = KSFT_PASS; long syscall_ret; struct cachestat cs; struct cachestat_range cs_range = { 0, filesize }; @@ -112,7 +129,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create, if (fd == -1) { ksft_print_msg("Unable to create/open file.\n"); - ret = false; + ret = KSFT_FAIL; goto out; } else { ksft_print_msg("Create/open %s\n", filename); @@ -121,18 +138,18 @@ bool test_cachestat(const char *filename, bool write_random, bool create, if (write_random) { if (!write_exactly(fd, filesize)) { ksft_print_msg("Unable to access urandom.\n"); - ret = false; + ret = KSFT_FAIL; goto out1; } } - syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); + syscall_ret = syscall(__NR_cachestat, fd, &cs_range, &cs, 0); ksft_print_msg("Cachestat call returned %ld\n", syscall_ret); if (syscall_ret) { ksft_print_msg("Cachestat returned non-zero.\n"); - ret = false; + ret = KSFT_FAIL; goto out1; } else { @@ -142,17 +159,19 @@ bool test_cachestat(const char *filename, bool write_random, bool create, if (cs.nr_cache + cs.nr_evicted != num_pages) { ksft_print_msg( "Total number of cached and evicted pages is off.\n"); - ret = false; + ret = KSFT_FAIL; } } } if (test_fsync) { - if (fsync(fd)) { + if (is_on_tmpfs(fd)) { + ret = KSFT_SKIP; + } else if (fsync(fd)) { ksft_print_msg("fsync fails.\n"); - ret = false; + ret = KSFT_FAIL; } else { - syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); + syscall_ret = syscall(__NR_cachestat, fd, &cs_range, &cs, 0); ksft_print_msg("Cachestat call (after fsync) returned %ld\n", syscall_ret); @@ -161,13 +180,13 @@ bool test_cachestat(const char *filename, bool write_random, bool create, print_cachestat(&cs); if (cs.nr_dirty) { - ret = false; + ret = KSFT_FAIL; ksft_print_msg( "Number of dirty should be zero after fsync.\n"); } } else { ksft_print_msg("Cachestat (after fsync) returned non-zero.\n"); - ret = false; + ret = KSFT_FAIL; goto out1; } } @@ -213,7 +232,7 @@ bool test_cachestat_shmem(void) goto close_fd; } - syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); + syscall_ret = syscall(__NR_cachestat, fd, &cs_range, &cs, 0); if (syscall_ret) { ksft_print_msg("Cachestat returned non-zero.\n"); @@ -236,13 +255,29 @@ out: int main(void) { - int ret = 0; + int ret; + + ksft_print_header(); + + ret = syscall(__NR_cachestat, -1, NULL, NULL, 0); + if (ret == -1 && errno == ENOSYS) + ksft_exit_skip("cachestat syscall not available\n"); + + ksft_set_plan(NR_TESTS); + + if (ret == -1 && errno == EBADF) { + ksft_test_result_pass("bad file descriptor recognized\n"); + ret = 0; + } else { + ksft_test_result_fail("bad file descriptor ignored\n"); + ret = 1; + } for (int i = 0; i < 5; i++) { const char *dev_filename = dev_files[i]; if (test_cachestat(dev_filename, false, false, false, - 4, O_RDONLY, 0400)) + 4, O_RDONLY, 0400) == KSFT_PASS) ksft_test_result_pass("cachestat works with %s\n", dev_filename); else { ksft_test_result_fail("cachestat fails with %s\n", dev_filename); @@ -251,13 +286,27 @@ int main(void) } if (test_cachestat("tmpfilecachestat", true, true, - true, 4, O_CREAT | O_RDWR, 0400 | 0600)) + false, 4, O_CREAT | O_RDWR, 0600) == KSFT_PASS) ksft_test_result_pass("cachestat works with a normal file\n"); else { ksft_test_result_fail("cachestat fails with normal file\n"); ret = 1; } + switch (test_cachestat("tmpfilecachestat", true, true, + true, 4, O_CREAT | O_RDWR, 0600)) { + case KSFT_FAIL: + ksft_test_result_fail("cachestat fsync fails with normal file\n"); + ret = KSFT_FAIL; + break; + case KSFT_PASS: + ksft_test_result_pass("cachestat fsync works with a normal file\n"); + break; + case KSFT_SKIP: + ksft_test_result_skip("tmpfilecachestat is on tmpfs\n"); + break; + } + if (test_cachestat_shmem()) ksft_test_result_pass("cachestat works with a shmem file\n"); else { diff --git a/tools/testing/selftests/cgroup/test_kmem.c b/tools/testing/selftests/cgroup/test_kmem.c index 1b2cec9d18a4..ed2e50bb1e76 100644 --- a/tools/testing/selftests/cgroup/test_kmem.c +++ b/tools/testing/selftests/cgroup/test_kmem.c @@ -75,11 +75,11 @@ static int test_kmem_basic(const char *root) sleep(1); slab1 = cg_read_key_long(cg, "memory.stat", "slab "); - if (slab1 <= 0) + if (slab1 < 0) goto cleanup; current = cg_read_long(cg, "memory.current"); - if (current <= 0) + if (current < 0) goto cleanup; if (slab1 < slab0 / 2 && current < slab0 / 2) diff --git a/tools/testing/selftests/drivers/net/bonding/bond-arp-interval-causes-panic.sh b/tools/testing/selftests/drivers/net/bonding/bond-arp-interval-causes-panic.sh index 7b2d421f09cf..4917dbb35a44 100755 --- a/tools/testing/selftests/drivers/net/bonding/bond-arp-interval-causes-panic.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond-arp-interval-causes-panic.sh @@ -22,14 +22,12 @@ server_ip4=192.168.1.254 echo 180 >/proc/sys/kernel/panic # build namespaces -ip link add dev link1_1 type veth peer name link1_2 - ip netns add "server" -ip link set dev link1_2 netns server up name eth0 +ip netns add "client" +ip -n client link add eth0 type veth peer name eth0 netns server +ip netns exec server ip link set dev eth0 up ip netns exec server ip addr add ${server_ip4}/24 dev eth0 -ip netns add "client" -ip link set dev link1_1 netns client down name eth0 ip netns exec client ip link add dev bond0 down type bond mode 1 \ miimon 100 all_slaves_active 1 ip netns exec client ip link set dev eth0 down master bond0 diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/.gitignore b/tools/testing/selftests/fchmodat2/.gitignore index 57d296341304..82a4846cbc4b 100644 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/.gitignore +++ b/tools/testing/selftests/fchmodat2/.gitignore @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -srcu.h +/*_test diff --git a/tools/testing/selftests/fchmodat2/Makefile b/tools/testing/selftests/fchmodat2/Makefile new file mode 100644 index 000000000000..20839f8e43f2 --- /dev/null +++ b/tools/testing/selftests/fchmodat2/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined $(KHDR_INCLUDES) +TEST_GEN_PROGS := fchmodat2_test + +include ../lib.mk diff --git a/tools/testing/selftests/fchmodat2/fchmodat2_test.c b/tools/testing/selftests/fchmodat2/fchmodat2_test.c new file mode 100644 index 000000000000..e0319417124d --- /dev/null +++ b/tools/testing/selftests/fchmodat2/fchmodat2_test.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#define _GNU_SOURCE +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <syscall.h> +#include <unistd.h> + +#include "../kselftest.h" + +int sys_fchmodat2(int dfd, const char *filename, mode_t mode, int flags) +{ + int ret = syscall(__NR_fchmodat2, dfd, filename, mode, flags); + + return ret >= 0 ? ret : -errno; +} + +int setup_testdir(void) +{ + int dfd, ret; + char dirname[] = "/tmp/ksft-fchmodat2.XXXXXX"; + + /* Make the top-level directory. */ + if (!mkdtemp(dirname)) + ksft_exit_fail_msg("%s: failed to create tmpdir\n", __func__); + + dfd = open(dirname, O_PATH | O_DIRECTORY); + if (dfd < 0) + ksft_exit_fail_msg("%s: failed to open tmpdir\n", __func__); + + ret = openat(dfd, "regfile", O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (ret < 0) + ksft_exit_fail_msg("%s: failed to create file in tmpdir\n", + __func__); + close(ret); + + ret = symlinkat("regfile", dfd, "symlink"); + if (ret < 0) + ksft_exit_fail_msg("%s: failed to create symlink in tmpdir\n", + __func__); + + return dfd; +} + +int expect_mode(int dfd, const char *filename, mode_t expect_mode) +{ + struct stat st; + int ret = fstatat(dfd, filename, &st, AT_SYMLINK_NOFOLLOW); + + if (ret) + ksft_exit_fail_msg("%s: %s: fstatat failed\n", + __func__, filename); + + return (st.st_mode == expect_mode); +} + +void test_regfile(void) +{ + int dfd, ret; + + dfd = setup_testdir(); + + ret = sys_fchmodat2(dfd, "regfile", 0640, 0); + + if (ret < 0) + ksft_exit_fail_msg("%s: fchmodat2(noflag) failed\n", __func__); + + if (!expect_mode(dfd, "regfile", 0100640)) + ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2\n", + __func__); + + ret = sys_fchmodat2(dfd, "regfile", 0600, AT_SYMLINK_NOFOLLOW); + + if (ret < 0) + ksft_exit_fail_msg("%s: fchmodat2(AT_SYMLINK_NOFOLLOW) failed\n", + __func__); + + if (!expect_mode(dfd, "regfile", 0100600)) + ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2 with nofollow\n", + __func__); + + ksft_test_result_pass("fchmodat2(regfile)\n"); +} + +void test_symlink(void) +{ + int dfd, ret; + + dfd = setup_testdir(); + + ret = sys_fchmodat2(dfd, "symlink", 0640, 0); + + if (ret < 0) + ksft_exit_fail_msg("%s: fchmodat2(noflag) failed\n", __func__); + + if (!expect_mode(dfd, "regfile", 0100640)) + ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2\n", + __func__); + + if (!expect_mode(dfd, "symlink", 0120777)) + ksft_exit_fail_msg("%s: wrong symlink mode bits after fchmodat2\n", + __func__); + + ret = sys_fchmodat2(dfd, "symlink", 0600, AT_SYMLINK_NOFOLLOW); + + /* + * On certain filesystems (xfs or btrfs), chmod operation fails. So we + * first check the symlink target but if the operation fails we mark the + * test as skipped. + * + * https://sourceware.org/legacy-ml/libc-alpha/2020-02/msg00467.html + */ + if (ret == 0 && !expect_mode(dfd, "symlink", 0120600)) + ksft_exit_fail_msg("%s: wrong symlink mode bits after fchmodat2 with nofollow\n", + __func__); + + if (!expect_mode(dfd, "regfile", 0100640)) + ksft_exit_fail_msg("%s: wrong file mode bits after fchmodat2 with nofollow\n", + __func__); + + if (ret != 0) + ksft_test_result_skip("fchmodat2(symlink)\n"); + else + ksft_test_result_pass("fchmodat2(symlink)\n"); +} + +#define NUM_TESTS 2 + +int main(int argc, char **argv) +{ + ksft_print_header(); + ksft_set_plan(NUM_TESTS); + + test_regfile(); + test_symlink(); + + if (ksft_get_fail_cnt() + ksft_get_error_cnt() > 0) + ksft_exit_fail(); + else + ksft_exit_pass(); +} diff --git a/tools/testing/selftests/filelock/Makefile b/tools/testing/selftests/filelock/Makefile new file mode 100644 index 000000000000..478e82f8b464 --- /dev/null +++ b/tools/testing/selftests/filelock/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +TEST_GEN_PROGS := ofdlocks + +include ../lib.mk diff --git a/tools/testing/selftests/filelock/ofdlocks.c b/tools/testing/selftests/filelock/ofdlocks.c new file mode 100644 index 000000000000..a55b79810ab2 --- /dev/null +++ b/tools/testing/selftests/filelock/ofdlocks.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include <fcntl.h> +#include <assert.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include "../kselftest.h" + +static int lock_set(int fd, struct flock *fl) +{ + int ret; + + fl->l_pid = 0; // needed for OFD locks + fl->l_whence = SEEK_SET; + ret = fcntl(fd, F_OFD_SETLK, fl); + if (ret) + perror("fcntl()"); + return ret; +} + +static int lock_get(int fd, struct flock *fl) +{ + int ret; + + fl->l_pid = 0; // needed for OFD locks + fl->l_whence = SEEK_SET; + ret = fcntl(fd, F_OFD_GETLK, fl); + if (ret) + perror("fcntl()"); + return ret; +} + +int main(void) +{ + int rc; + struct flock fl, fl2; + int fd = open("/tmp/aa", O_RDWR | O_CREAT | O_EXCL, 0600); + int fd2 = open("/tmp/aa", O_RDONLY); + + unlink("/tmp/aa"); + assert(fd != -1); + assert(fd2 != -1); + ksft_print_msg("[INFO] opened fds %i %i\n", fd, fd2); + + /* Set some read lock */ + fl.l_type = F_RDLCK; + fl.l_start = 5; + fl.l_len = 3; + rc = lock_set(fd, &fl); + if (rc == 0) { + ksft_print_msg + ("[SUCCESS] set OFD read lock on first fd\n"); + } else { + ksft_print_msg("[FAIL] to set OFD read lock on first fd\n"); + return -1; + } + /* Make sure read locks do not conflict on different fds. */ + fl.l_type = F_RDLCK; + fl.l_start = 5; + fl.l_len = 1; + rc = lock_get(fd2, &fl); + if (rc != 0) + return -1; + if (fl.l_type != F_UNLCK) { + ksft_print_msg("[FAIL] read locks conflicted\n"); + return -1; + } + /* Make sure read/write locks do conflict on different fds. */ + fl.l_type = F_WRLCK; + fl.l_start = 5; + fl.l_len = 1; + rc = lock_get(fd2, &fl); + if (rc != 0) + return -1; + if (fl.l_type != F_UNLCK) { + ksft_print_msg + ("[SUCCESS] read and write locks conflicted\n"); + } else { + ksft_print_msg + ("[SUCCESS] read and write locks not conflicted\n"); + return -1; + } + /* Get info about the lock on first fd. */ + fl.l_type = F_UNLCK; + fl.l_start = 5; + fl.l_len = 1; + rc = lock_get(fd, &fl); + if (rc != 0) { + ksft_print_msg + ("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n"); + return -1; + } + if (fl.l_type != F_UNLCK) { + ksft_print_msg + ("[SUCCESS] F_UNLCK test returns: locked, type %i pid %i len %zi\n", + fl.l_type, fl.l_pid, fl.l_len); + } else { + ksft_print_msg + ("[FAIL] F_OFD_GETLK with F_UNLCK did not return lock info\n"); + return -1; + } + /* Try the same but by locking everything by len==0. */ + fl2.l_type = F_UNLCK; + fl2.l_start = 0; + fl2.l_len = 0; + rc = lock_get(fd, &fl2); + if (rc != 0) { + ksft_print_msg + ("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n"); + return -1; + } + if (memcmp(&fl, &fl2, sizeof(fl))) { + ksft_print_msg + ("[FAIL] F_UNLCK test returns: locked, type %i pid %i len %zi\n", + fl.l_type, fl.l_pid, fl.l_len); + return -1; + } + ksft_print_msg("[SUCCESS] F_UNLCK with len==0 returned the same\n"); + /* Get info about the lock on second fd - no locks on it. */ + fl.l_type = F_UNLCK; + fl.l_start = 0; + fl.l_len = 0; + lock_get(fd2, &fl); + if (fl.l_type != F_UNLCK) { + ksft_print_msg + ("[FAIL] F_OFD_GETLK with F_UNLCK return lock info from another fd\n"); + return -1; + } + return 0; +} diff --git a/tools/testing/selftests/filesystems/fat/run_fat_tests.sh b/tools/testing/selftests/filesystems/fat/run_fat_tests.sh index 7f35dc3d15df..d61264d4795d 100755 --- a/tools/testing/selftests/filesystems/fat/run_fat_tests.sh +++ b/tools/testing/selftests/filesystems/fat/run_fat_tests.sh @@ -12,7 +12,7 @@ set -u set -o pipefail BASE_DIR="$(dirname $0)" -TMP_DIR="$(mktemp -d /tmp/fat_tests_tmp.XXXX)" +TMP_DIR="$(mktemp -d /tmp/fat_tests_tmp.XXXXXX)" IMG_PATH="${TMP_DIR}/fat.img" MNT_PATH="${TMP_DIR}/mnt" diff --git a/tools/testing/selftests/ftrace/test.d/00basic/snapshot1.tc b/tools/testing/selftests/ftrace/test.d/00basic/snapshot1.tc new file mode 100644 index 000000000000..63b76cf2a360 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/00basic/snapshot1.tc @@ -0,0 +1,31 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Snapshot and tracing_cpumask +# requires: trace_marker tracing_cpumask snapshot +# flags: instance + +# This testcase is constrived to reproduce a problem that the cpu buffers +# become unavailable which is due to 'record_disabled' of array_buffer and +# max_buffer being messed up. + +# Store origin cpumask +ORIG_CPUMASK=`cat tracing_cpumask` + +# Stop tracing all cpu +echo 0 > tracing_cpumask + +# Take a snapshot of the main buffer +echo 1 > snapshot + +# Restore origin cpumask, note that there should be some cpus being traced +echo ${ORIG_CPUMASK} > tracing_cpumask + +# Set tracing on +echo 1 > tracing_on + +# Write a log into buffer +echo "test input 1" > trace_marker + +# Ensure the log writed so that cpu buffers are still available +grep -q "test input 1" trace +exit 0 diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c index 3651ce17beeb..d183f878360b 100644 --- a/tools/testing/selftests/futex/functional/futex_wait_timeout.c +++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c @@ -24,6 +24,7 @@ static long timeout_ns = 100000; /* 100us default timeout */ static futex_t futex_pi; +static pthread_barrier_t barrier; void usage(char *prog) { @@ -48,6 +49,8 @@ void *get_pi_lock(void *arg) if (ret != 0) error("futex_lock_pi failed\n", ret); + pthread_barrier_wait(&barrier); + /* Blocks forever */ ret = futex_wait(&lock, 0, NULL, 0); error("futex_wait failed\n", ret); @@ -130,6 +133,7 @@ int main(int argc, char *argv[]) basename(argv[0])); ksft_print_msg("\tArguments: timeout=%ldns\n", timeout_ns); + pthread_barrier_init(&barrier, NULL, 2); pthread_create(&thread, NULL, get_pi_lock, NULL); /* initialize relative timeout */ @@ -163,6 +167,9 @@ int main(int argc, char *argv[]) res = futex_wait_requeue_pi(&f1, f1, &futex_pi, &to, 0); test_timeout(res, &ret, "futex_wait_requeue_pi monotonic", ETIMEDOUT); + /* Wait until the other thread calls futex_lock_pi() */ + pthread_barrier_wait(&barrier); + pthread_barrier_destroy(&barrier); /* * FUTEX_LOCK_PI with CLOCK_REALTIME * Due to historical reasons, FUTEX_LOCK_PI supports only realtime diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 5fd49ad0c696..e05ac8261046 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -938,7 +938,11 @@ void __wait_for_test(struct __test_metadata *t) fprintf(TH_LOG_STREAM, "# %s: Test terminated by timeout\n", t->name); } else if (WIFEXITED(status)) { - if (t->termsig != -1) { + if (WEXITSTATUS(status) == 255) { + /* SKIP */ + t->passed = 1; + t->skip = 1; + } else if (t->termsig != -1) { t->passed = 0; fprintf(TH_LOG_STREAM, "# %s: Test exited normally instead of by signal (code: %d)\n", @@ -950,11 +954,6 @@ void __wait_for_test(struct __test_metadata *t) case 0: t->passed = 1; break; - /* SKIP */ - case 255: - t->passed = 1; - t->skip = 1; - break; /* Other failure, assume step report. */ default: t->passed = 0; diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c index 4adaad1b822f..20294553a5dd 100644 --- a/tools/testing/selftests/mm/hmm-tests.c +++ b/tools/testing/selftests/mm/hmm-tests.c @@ -57,9 +57,14 @@ enum { #define ALIGN(x, a) (((x) + (a - 1)) & (~((a) - 1))) /* Just the flags we need, copied from mm.h: */ + +#ifndef FOLL_WRITE #define FOLL_WRITE 0x01 /* check pte is writable */ -#define FOLL_LONGTERM 0x10000 /* mapping lifetime is indefinite */ +#endif +#ifndef FOLL_LONGTERM +#define FOLL_LONGTERM 0x100 /* mapping lifetime is indefinite */ +#endif FIXTURE(hmm) { int fd; diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index cd3cc52c59b4..8da562a9ae87 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config @@ -51,3 +51,4 @@ CONFIG_AMT=m CONFIG_VXLAN=m CONFIG_IP_SCTP=m CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_CRYPTO_ARIA=y diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index 4b63708c6a81..297d972558fb 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -30,12 +30,15 @@ static int fips_enabled; struct tls_crypto_info_keys { union { + struct tls_crypto_info crypto_info; struct tls12_crypto_info_aes_gcm_128 aes128; struct tls12_crypto_info_chacha20_poly1305 chacha20; struct tls12_crypto_info_sm4_gcm sm4gcm; struct tls12_crypto_info_sm4_ccm sm4ccm; struct tls12_crypto_info_aes_ccm_128 aesccm128; struct tls12_crypto_info_aes_gcm_256 aesgcm256; + struct tls12_crypto_info_aria_gcm_128 ariagcm128; + struct tls12_crypto_info_aria_gcm_256 ariagcm256; }; size_t len; }; @@ -76,6 +79,16 @@ static void tls_crypto_info_init(uint16_t tls_version, uint16_t cipher_type, tls12->aesgcm256.info.version = tls_version; tls12->aesgcm256.info.cipher_type = cipher_type; break; + case TLS_CIPHER_ARIA_GCM_128: + tls12->len = sizeof(struct tls12_crypto_info_aria_gcm_128); + tls12->ariagcm128.info.version = tls_version; + tls12->ariagcm128.info.cipher_type = cipher_type; + break; + case TLS_CIPHER_ARIA_GCM_256: + tls12->len = sizeof(struct tls12_crypto_info_aria_gcm_256); + tls12->ariagcm256.info.version = tls_version; + tls12->ariagcm256.info.cipher_type = cipher_type; + break; default: break; } @@ -228,6 +241,31 @@ TEST_F(tls_basic, base_base) EXPECT_EQ(memcmp(buf, test_str, send_len), 0); }; +TEST_F(tls_basic, bad_cipher) +{ + struct tls_crypto_info_keys tls12; + + tls12.crypto_info.version = 200; + tls12.crypto_info.cipher_type = TLS_CIPHER_AES_GCM_128; + EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1); + + tls12.crypto_info.version = TLS_1_2_VERSION; + tls12.crypto_info.cipher_type = 50; + EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1); + + tls12.crypto_info.version = TLS_1_2_VERSION; + tls12.crypto_info.cipher_type = 59; + EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1); + + tls12.crypto_info.version = TLS_1_2_VERSION; + tls12.crypto_info.cipher_type = 10; + EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1); + + tls12.crypto_info.version = TLS_1_2_VERSION; + tls12.crypto_info.cipher_type = 70; + EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1); +} + FIXTURE(tls) { int fd, cfd; @@ -312,6 +350,18 @@ FIXTURE_VARIANT_ADD(tls, 13_nopad) .nopad = true, }; +FIXTURE_VARIANT_ADD(tls, 12_aria_gcm) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_ARIA_GCM_128, +}; + +FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_ARIA_GCM_256, +}; + FIXTURE_SETUP(tls) { struct tls_crypto_info_keys tls12; @@ -1472,6 +1522,40 @@ TEST_F(tls, shutdown_reuse) EXPECT_EQ(errno, EISCONN); } +TEST_F(tls, getsockopt) +{ + struct tls_crypto_info_keys expect, get; + socklen_t len; + + /* get only the version/cipher */ + len = sizeof(struct tls_crypto_info); + memrnd(&get, sizeof(get)); + EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &get, &len), 0); + EXPECT_EQ(len, sizeof(struct tls_crypto_info)); + EXPECT_EQ(get.crypto_info.version, variant->tls_version); + EXPECT_EQ(get.crypto_info.cipher_type, variant->cipher_type); + + /* get the full crypto_info */ + tls_crypto_info_init(variant->tls_version, variant->cipher_type, &expect); + len = expect.len; + memrnd(&get, sizeof(get)); + EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &get, &len), 0); + EXPECT_EQ(len, expect.len); + EXPECT_EQ(get.crypto_info.version, variant->tls_version); + EXPECT_EQ(get.crypto_info.cipher_type, variant->cipher_type); + EXPECT_EQ(memcmp(&get, &expect, expect.len), 0); + + /* short get should fail */ + len = sizeof(struct tls_crypto_info) - 1; + EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &get, &len), -1); + EXPECT_EQ(errno, EINVAL); + + /* partial get of the cipher data should fail */ + len = expect.len - 1; + EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &get, &len), -1); + EXPECT_EQ(errno, EINVAL); +} + FIXTURE(tls_err) { int fd, cfd; diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 1b7b3c82f8ad..dfe66776a331 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -14,6 +14,31 @@ include $(srctree)/scripts/subarch.include ARCH = $(SUBARCH) endif +# XARCH extends the kernel's ARCH with a few variants of the same +# architecture that only differ by the configuration, the toolchain +# and the Qemu program used. It is copied as-is into ARCH except for +# a few specific values which are mapped like this: +# +# XARCH | ARCH | config +# -------------|-----------|------------------------- +# ppc | powerpc | 32 bits +# ppc64 | powerpc | 64 bits big endian +# ppc64le | powerpc | 64 bits little endian +# +# It is recommended to only use XARCH, though it does not harm if +# ARCH is already set. For simplicity, ARCH is sufficient for all +# architectures where both are equal. + +# configure default variants for target kernel supported architectures +XARCH_powerpc = ppc +XARCH = $(or $(XARCH_$(ARCH)),$(ARCH)) + +# map from user input variants to their kernel supported architectures +ARCH_ppc = powerpc +ARCH_ppc64 = powerpc +ARCH_ppc64le = powerpc +ARCH := $(or $(ARCH_$(XARCH)),$(XARCH)) + # kernel image names by architecture IMAGE_i386 = arch/x86/boot/bzImage IMAGE_x86_64 = arch/x86/boot/bzImage @@ -21,10 +46,13 @@ IMAGE_x86 = arch/x86/boot/bzImage IMAGE_arm64 = arch/arm64/boot/Image IMAGE_arm = arch/arm/boot/zImage IMAGE_mips = vmlinuz +IMAGE_ppc = vmlinux +IMAGE_ppc64 = vmlinux +IMAGE_ppc64le = arch/powerpc/boot/zImage IMAGE_riscv = arch/riscv/boot/Image IMAGE_s390 = arch/s390/boot/bzImage IMAGE_loongarch = arch/loongarch/boot/vmlinuz.efi -IMAGE = $(IMAGE_$(ARCH)) +IMAGE = $(IMAGE_$(XARCH)) IMAGE_NAME = $(notdir $(IMAGE)) # default kernel configurations that appear to be usable @@ -34,10 +62,13 @@ DEFCONFIG_x86 = defconfig DEFCONFIG_arm64 = defconfig DEFCONFIG_arm = multi_v7_defconfig DEFCONFIG_mips = malta_defconfig +DEFCONFIG_ppc = pmac32_defconfig +DEFCONFIG_ppc64 = powernv_be_defconfig +DEFCONFIG_ppc64le = powernv_defconfig DEFCONFIG_riscv = defconfig DEFCONFIG_s390 = defconfig DEFCONFIG_loongarch = defconfig -DEFCONFIG = $(DEFCONFIG_$(ARCH)) +DEFCONFIG = $(DEFCONFIG_$(XARCH)) # optional tests to run (default = all) TEST = @@ -49,10 +80,13 @@ QEMU_ARCH_x86 = x86_64 QEMU_ARCH_arm64 = aarch64 QEMU_ARCH_arm = arm QEMU_ARCH_mips = mipsel # works with malta_defconfig +QEMU_ARCH_ppc = ppc +QEMU_ARCH_ppc64 = ppc64 +QEMU_ARCH_ppc64le = ppc64le QEMU_ARCH_riscv = riscv64 QEMU_ARCH_s390 = s390x QEMU_ARCH_loongarch = loongarch64 -QEMU_ARCH = $(QEMU_ARCH_$(ARCH)) +QEMU_ARCH = $(QEMU_ARCH_$(XARCH)) # QEMU_ARGS : some arch-specific args to pass to qemu QEMU_ARGS_i386 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)" @@ -61,10 +95,13 @@ QEMU_ARGS_x86 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $( QEMU_ARGS_arm64 = -M virt -cpu cortex-a53 -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_arm = -M virt -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_mips = -M malta -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" +QEMU_ARGS_ppc = -M g3beige -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" +QEMU_ARGS_ppc64 = -M powernv -append "console=hvc0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" +QEMU_ARGS_ppc64le = -M powernv -append "console=hvc0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_riscv = -M virt -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_s390 = -M s390-ccw-virtio -m 1G -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" -QEMU_ARGS = $(QEMU_ARGS_$(ARCH)) $(QEMU_ARGS_EXTRA) +QEMU_ARGS = $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_EXTRA) # OUTPUT is only set when run from the main makefile, otherwise # it defaults to this nolibc directory. @@ -76,13 +113,21 @@ else Q=@ endif +CFLAGS_ppc = -m32 -mbig-endian -mno-vsx $(call cc-option,-mmultiple) +CFLAGS_ppc64 = -m64 -mbig-endian -mno-vsx $(call cc-option,-mmultiple) +CFLAGS_ppc64le = -m64 -mlittle-endian -mno-vsx $(call cc-option,-mabi=elfv2) CFLAGS_s390 = -m64 CFLAGS_mips = -EL CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all)) -CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ +CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 -W -Wall -Wextra \ $(call cc-option,-fno-stack-protector) \ - $(CFLAGS_$(ARCH)) $(CFLAGS_STACKPROTECTOR) -LDFLAGS := -s + $(CFLAGS_$(XARCH)) $(CFLAGS_STACKPROTECTOR) +LDFLAGS := + +REPORT ?= awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{if (!f) printf("\n"); f++; print;} /\[SKIPPED\][\r]*$$/{s++} \ + END{ printf("\n%3d test(s): %3d passed, %3d skipped, %3d failed => status: ", p+s+f, p, s, f); \ + if (f) printf("failure\n"); else if (s) printf("warning\n"); else printf("success\n");; \ + printf("\nSee all results in %s\n", ARGV[1]); }' help: @echo "Supported targets under selftests/nolibc:" @@ -91,24 +136,25 @@ help: @echo " sysroot create the nolibc sysroot here (uses \$$ARCH)" @echo " nolibc-test build the executable (uses \$$CC and \$$CROSS_COMPILE)" @echo " libc-test build an executable using the compiler's default libc instead" - @echo " run-user runs the executable under QEMU (uses \$$ARCH, \$$TEST)" + @echo " run-user runs the executable under QEMU (uses \$$XARCH, \$$TEST)" @echo " initramfs prepare the initramfs with nolibc-test" - @echo " defconfig create a fresh new default config (uses \$$ARCH)" - @echo " kernel (re)build the kernel with the initramfs (uses \$$ARCH)" - @echo " run runs the kernel in QEMU after building it (uses \$$ARCH, \$$TEST)" - @echo " rerun runs a previously prebuilt kernel in QEMU (uses \$$ARCH, \$$TEST)" + @echo " defconfig create a fresh new default config (uses \$$XARCH)" + @echo " kernel (re)build the kernel with the initramfs (uses \$$XARCH)" + @echo " run runs the kernel in QEMU after building it (uses \$$XARCH, \$$TEST)" + @echo " rerun runs a previously prebuilt kernel in QEMU (uses \$$XARCH, \$$TEST)" @echo " clean clean the sysroot, initramfs, build and output files" @echo "" @echo "The output file is \"run.out\". Test ranges may be passed using \$$TEST." @echo "" @echo "Currently using the following variables:" @echo " ARCH = $(ARCH)" + @echo " XARCH = $(XARCH)" @echo " CROSS_COMPILE = $(CROSS_COMPILE)" @echo " CC = $(CC)" @echo " OUTPUT = $(OUTPUT)" @echo " TEST = $(TEST)" - @echo " QEMU_ARCH = $(if $(QEMU_ARCH),$(QEMU_ARCH),UNKNOWN_ARCH) [determined from \$$ARCH]" - @echo " IMAGE_NAME = $(if $(IMAGE_NAME),$(IMAGE_NAME),UNKNOWN_ARCH) [determined from \$$ARCH]" + @echo " QEMU_ARCH = $(if $(QEMU_ARCH),$(QEMU_ARCH),UNKNOWN_ARCH) [determined from \$$XARCH]" + @echo " IMAGE_NAME = $(if $(IMAGE_NAME),$(IMAGE_NAME),UNKNOWN_ARCH) [determined from \$$XARCH]" @echo "" all: run @@ -121,20 +167,33 @@ sysroot/$(ARCH)/include: $(Q)$(MAKE) -C ../../../include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone $(Q)mv sysroot/sysroot sysroot/$(ARCH) +ifneq ($(NOLIBC_SYSROOT),0) nolibc-test: nolibc-test.c sysroot/$(ARCH)/include $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ -nostdlib -static -Isysroot/$(ARCH)/include $< -lgcc +else +nolibc-test: nolibc-test.c + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ + -nostdlib -static -include ../../../include/nolibc/nolibc.h $< -lgcc +endif libc-test: nolibc-test.c - $(QUIET_CC)$(CC) -o $@ $< + $(QUIET_CC)$(HOSTCC) -o $@ $< + +# local libc-test +run-libc-test: libc-test + $(Q)./libc-test > "$(CURDIR)/run.out" || : + $(Q)$(REPORT) $(CURDIR)/run.out + +# local nolibc-test +run-nolibc-test: nolibc-test + $(Q)./nolibc-test > "$(CURDIR)/run.out" || : + $(Q)$(REPORT) $(CURDIR)/run.out # qemu user-land test run-user: nolibc-test $(Q)qemu-$(QEMU_ARCH) ./nolibc-test > "$(CURDIR)/run.out" || : - $(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \ - END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \ - if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \ - $(CURDIR)/run.out + $(Q)$(REPORT) $(CURDIR)/run.out initramfs: nolibc-test $(QUIET_MKDIR)mkdir -p initramfs @@ -150,18 +209,16 @@ kernel: initramfs # run the tests after building the kernel run: kernel $(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out" - $(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \ - END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \ - if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \ - $(CURDIR)/run.out + $(Q)$(REPORT) $(CURDIR)/run.out # re-run the tests from an existing kernel rerun: $(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out" - $(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \ - END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \ - if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \ - $(CURDIR)/run.out + $(Q)$(REPORT) $(CURDIR)/run.out + +# report with existing test log +report: + $(Q)$(REPORT) $(CURDIR)/run.out clean: $(call QUIET_CLEAN, sysroot) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 486334981e60..fb3bf91462e2 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ #define _GNU_SOURCE +#define _LARGEFILE64_SOURCE /* libc-specific include files * The program may be built in 3 ways: @@ -14,7 +15,7 @@ #include <string.h> #ifndef _NOLIBC_STDIO_H /* standard libcs need more includes */ -#include <linux/reboot.h> +#include <sys/auxv.h> #include <sys/io.h> #include <sys/ioctl.h> #include <sys/mman.h> @@ -40,8 +41,21 @@ #endif #endif -/* will be used by nolibc by getenv() */ -char **environ; +/* for the type of int_fast16_t and int_fast32_t, musl differs from glibc and nolibc */ +#define SINT_MAX_OF_TYPE(type) (((type)1 << (sizeof(type) * 8 - 2)) - (type)1 + ((type)1 << (sizeof(type) * 8 - 2))) +#define SINT_MIN_OF_TYPE(type) (-SINT_MAX_OF_TYPE(type) - 1) + +/* will be used to test initialization of environ */ +static char **test_envp; + +/* will be used to test initialization of argv */ +static char **test_argv; + +/* will be used to test initialization of argc */ +static int test_argc; + +/* will be used by some test cases as readable file, please don't write it */ +static const char *argv0; /* definition of a series of tests */ struct test { @@ -66,7 +80,7 @@ char *itoa(int i) /* returns the error name (e.g. "ENOENT") for common errors, "SUCCESS" for 0, * or the decimal value for less common ones. */ -const char *errorname(int err) +static const char *errorname(int err) { switch (err) { case 0: return "SUCCESS"; @@ -120,17 +134,26 @@ static void putcharn(char c, size_t n) fputs(buf, stdout); } -static int pad_spc(int llen, int cnt, const char *fmt, ...) -{ - va_list args; - int ret; - - putcharn(' ', cnt - llen); +enum RESULT { + OK, + FAIL, + SKIPPED, +}; - va_start(args, fmt); - ret = vfprintf(stdout, fmt, args); - va_end(args); - return ret < 0 ? ret : ret + cnt - llen; +static void result(int llen, enum RESULT r) +{ + const char *msg; + + if (r == OK) + msg = " [OK]"; + else if (r == SKIPPED) + msg = "[SKIPPED]"; + else + msg = "[FAIL]"; + + if (llen < 64) + putcharn(' ', 64 - llen); + puts(msg); } /* The tests below are intended to be used by the macroes, which evaluate @@ -140,173 +163,185 @@ static int pad_spc(int llen, int cnt, const char *fmt, ...) */ #define EXPECT_ZR(cond, expr) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_zr(expr, llen); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_zr(expr, llen); } while (0) -static int expect_zr(int expr, int llen) +static __attribute__((unused)) +int expect_zr(int expr, int llen) { int ret = !(expr == 0); llen += printf(" = %d ", expr); - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + result(llen, ret ? FAIL : OK); return ret; } #define EXPECT_NZ(cond, expr, val) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_nz(expr, llen; } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_nz(expr, llen; } while (0) -static int expect_nz(int expr, int llen) +static __attribute__((unused)) +int expect_nz(int expr, int llen) { int ret = !(expr != 0); llen += printf(" = %d ", expr); - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + result(llen, ret ? FAIL : OK); return ret; } #define EXPECT_EQ(cond, expr, val) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_eq(expr, llen, val); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_eq(expr, llen, val); } while (0) -static int expect_eq(uint64_t expr, int llen, uint64_t val) +static __attribute__((unused)) +int expect_eq(uint64_t expr, int llen, uint64_t val) { int ret = !(expr == val); llen += printf(" = %lld ", (long long)expr); - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + result(llen, ret ? FAIL : OK); return ret; } #define EXPECT_NE(cond, expr, val) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ne(expr, llen, val); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ne(expr, llen, val); } while (0) -static int expect_ne(int expr, int llen, int val) +static __attribute__((unused)) +int expect_ne(int expr, int llen, int val) { int ret = !(expr != val); llen += printf(" = %d ", expr); - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + result(llen, ret ? FAIL : OK); return ret; } #define EXPECT_GE(cond, expr, val) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ge(expr, llen, val); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ge(expr, llen, val); } while (0) -static int expect_ge(int expr, int llen, int val) +static __attribute__((unused)) +int expect_ge(int expr, int llen, int val) { int ret = !(expr >= val); llen += printf(" = %d ", expr); - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + result(llen, ret ? FAIL : OK); return ret; } #define EXPECT_GT(cond, expr, val) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_gt(expr, llen, val); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_gt(expr, llen, val); } while (0) -static int expect_gt(int expr, int llen, int val) +static __attribute__((unused)) +int expect_gt(int expr, int llen, int val) { int ret = !(expr > val); llen += printf(" = %d ", expr); - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + result(llen, ret ? FAIL : OK); return ret; } #define EXPECT_LE(cond, expr, val) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_le(expr, llen, val); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_le(expr, llen, val); } while (0) -static int expect_le(int expr, int llen, int val) +static __attribute__((unused)) +int expect_le(int expr, int llen, int val) { int ret = !(expr <= val); llen += printf(" = %d ", expr); - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + result(llen, ret ? FAIL : OK); return ret; } #define EXPECT_LT(cond, expr, val) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_lt(expr, llen, val); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_lt(expr, llen, val); } while (0) -static int expect_lt(int expr, int llen, int val) +static __attribute__((unused)) +int expect_lt(int expr, int llen, int val) { int ret = !(expr < val); llen += printf(" = %d ", expr); - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + result(llen, ret ? FAIL : OK); return ret; } #define EXPECT_SYSZR(cond, expr) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syszr(expr, llen); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_syszr(expr, llen); } while (0) -static int expect_syszr(int expr, int llen) +static __attribute__((unused)) +int expect_syszr(int expr, int llen) { int ret = 0; if (expr) { ret = 1; llen += printf(" = %d %s ", expr, errorname(errno)); - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); } else { llen += printf(" = %d ", expr); - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } #define EXPECT_SYSEQ(cond, expr, val) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syseq(expr, llen, val); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_syseq(expr, llen, val); } while (0) -static int expect_syseq(int expr, int llen, int val) +static __attribute__((unused)) +int expect_syseq(int expr, int llen, int val) { int ret = 0; if (expr != val) { ret = 1; llen += printf(" = %d %s ", expr, errorname(errno)); - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); } else { llen += printf(" = %d ", expr); - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } #define EXPECT_SYSNE(cond, expr, val) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_sysne(expr, llen, val); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_sysne(expr, llen, val); } while (0) -static int expect_sysne(int expr, int llen, int val) +static __attribute__((unused)) +int expect_sysne(int expr, int llen, int val) { int ret = 0; if (expr == val) { ret = 1; llen += printf(" = %d %s ", expr, errorname(errno)); - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); } else { llen += printf(" = %d ", expr); - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } #define EXPECT_SYSER2(cond, expr, expret, experr1, experr2) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syserr2(expr, expret, experr1, experr2, llen); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_syserr2(expr, expret, experr1, experr2, llen); } while (0) #define EXPECT_SYSER(cond, expr, expret, experr) \ EXPECT_SYSER2(cond, expr, expret, experr, 0) -static int expect_syserr2(int expr, int expret, int experr1, int experr2, int llen) +static __attribute__((unused)) +int expect_syserr2(int expr, int expret, int experr1, int experr2, int llen) { int ret = 0; int _errno = errno; @@ -318,117 +353,238 @@ static int expect_syserr2(int expr, int expret, int experr1, int experr2, int ll llen += printf(" != (%d %s) ", expret, errorname(experr1)); else llen += printf(" != (%d %s %s) ", expret, errorname(experr1), errorname(experr2)); - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); } else { - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } #define EXPECT_PTRZR(cond, expr) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrzr(expr, llen); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrzr(expr, llen); } while (0) -static int expect_ptrzr(const void *expr, int llen) +static __attribute__((unused)) +int expect_ptrzr(const void *expr, int llen) { int ret = 0; llen += printf(" = <%p> ", expr); if (expr) { ret = 1; - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); } else { - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } #define EXPECT_PTRNZ(cond, expr) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrnz(expr, llen); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrnz(expr, llen); } while (0) -static int expect_ptrnz(const void *expr, int llen) +static __attribute__((unused)) +int expect_ptrnz(const void *expr, int llen) { int ret = 0; llen += printf(" = <%p> ", expr); if (!expr) { ret = 1; - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); + } else { + result(llen, OK); + } + return ret; +} + +#define EXPECT_PTREQ(cond, expr, cmp) \ + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptreq(expr, llen, cmp); } while (0) + +static __attribute__((unused)) +int expect_ptreq(const void *expr, int llen, const void *cmp) +{ + int ret = 0; + + llen += printf(" = <%p> ", expr); + if (expr != cmp) { + ret = 1; + result(llen, FAIL); + } else { + result(llen, OK); + } + return ret; +} + +#define EXPECT_PTRNE(cond, expr, cmp) \ + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrne(expr, llen, cmp); } while (0) + +static __attribute__((unused)) +int expect_ptrne(const void *expr, int llen, const void *cmp) +{ + int ret = 0; + + llen += printf(" = <%p> ", expr); + if (expr == cmp) { + ret = 1; + result(llen, FAIL); } else { - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } +#define EXPECT_PTRGE(cond, expr, cmp) \ + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrge(expr, llen, cmp); } while (0) + +static __attribute__((unused)) +int expect_ptrge(const void *expr, int llen, const void *cmp) +{ + int ret = !(expr >= cmp); + + llen += printf(" = <%p> ", expr); + result(llen, ret ? FAIL : OK); + return ret; +} + +#define EXPECT_PTRGT(cond, expr, cmp) \ + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrgt(expr, llen, cmp); } while (0) + +static __attribute__((unused)) +int expect_ptrgt(const void *expr, int llen, const void *cmp) +{ + int ret = !(expr > cmp); + + llen += printf(" = <%p> ", expr); + result(llen, ret ? FAIL : OK); + return ret; +} + + +#define EXPECT_PTRLE(cond, expr, cmp) \ + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrle(expr, llen, cmp); } while (0) + +static __attribute__((unused)) +int expect_ptrle(const void *expr, int llen, const void *cmp) +{ + int ret = !(expr <= cmp); + + llen += printf(" = <%p> ", expr); + result(llen, ret ? FAIL : OK); + return ret; +} + + +#define EXPECT_PTRLT(cond, expr, cmp) \ + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrlt(expr, llen, cmp); } while (0) + +static __attribute__((unused)) +int expect_ptrlt(const void *expr, int llen, const void *cmp) +{ + int ret = !(expr < cmp); + + llen += printf(" = <%p> ", expr); + result(llen, ret ? FAIL : OK); + return ret; +} + +#define EXPECT_PTRER2(cond, expr, expret, experr1, experr2) \ + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrerr2(expr, expret, experr1, experr2, llen); } while (0) + +#define EXPECT_PTRER(cond, expr, expret, experr) \ + EXPECT_PTRER2(cond, expr, expret, experr, 0) + +static __attribute__((unused)) +int expect_ptrerr2(const void *expr, const void *expret, int experr1, int experr2, int llen) +{ + int ret = 0; + int _errno = errno; + + llen += printf(" = <%p> %s ", expr, errorname(_errno)); + if (expr != expret || (_errno != experr1 && _errno != experr2)) { + ret = 1; + if (experr2 == 0) + llen += printf(" != (<%p> %s) ", expret, errorname(experr1)); + else + llen += printf(" != (<%p> %s %s) ", expret, errorname(experr1), errorname(experr2)); + result(llen, FAIL); + } else { + result(llen, OK); + } + return ret; +} #define EXPECT_STRZR(cond, expr) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strzr(expr, llen); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_strzr(expr, llen); } while (0) -static int expect_strzr(const char *expr, int llen) +static __attribute__((unused)) +int expect_strzr(const char *expr, int llen) { int ret = 0; llen += printf(" = <%s> ", expr); if (expr) { ret = 1; - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); } else { - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } #define EXPECT_STRNZ(cond, expr) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strnz(expr, llen); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_strnz(expr, llen); } while (0) -static int expect_strnz(const char *expr, int llen) +static __attribute__((unused)) +int expect_strnz(const char *expr, int llen) { int ret = 0; llen += printf(" = <%s> ", expr); if (!expr) { ret = 1; - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); } else { - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } #define EXPECT_STREQ(cond, expr, cmp) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_streq(expr, llen, cmp); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_streq(expr, llen, cmp); } while (0) -static int expect_streq(const char *expr, int llen, const char *cmp) +static __attribute__((unused)) +int expect_streq(const char *expr, int llen, const char *cmp) { int ret = 0; llen += printf(" = <%s> ", expr); if (strcmp(expr, cmp) != 0) { ret = 1; - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); } else { - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } #define EXPECT_STRNE(cond, expr, cmp) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strne(expr, llen, cmp); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_strne(expr, llen, cmp); } while (0) -static int expect_strne(const char *expr, int llen, const char *cmp) +static __attribute__((unused)) +int expect_strne(const char *expr, int llen, const char *cmp) { int ret = 0; llen += printf(" = <%s> ", expr); if (strcmp(expr, cmp) == 0) { ret = 1; - llen += pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); } else { - llen += pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); } return ret; } @@ -438,6 +594,51 @@ static int expect_strne(const char *expr, int llen, const char *cmp) #define CASE_TEST(name) \ case __LINE__: llen += printf("%d %s", test, #name); +int run_startup(int min, int max) +{ + int test; + int ret = 0; + /* kernel at least passes HOME and TERM, shell passes more */ + int env_total = 2; + /* checking NULL for argv/argv0, environ and _auxv is not enough, let's compare with sbrk(0) or &end */ + extern char end; + char *brk = sbrk(0) != (void *)-1 ? sbrk(0) : &end; + /* differ from nolibc, both glibc and musl have no global _auxv */ + const unsigned long *test_auxv = (void *)-1; +#ifdef NOLIBC + test_auxv = _auxv; +#endif + + for (test = min; test >= 0 && test <= max; test++) { + int llen = 0; /* line length */ + + /* avoid leaving empty lines below, this will insert holes into + * test numbers. + */ + switch (test + __LINE__ + 1) { + CASE_TEST(argc); EXPECT_GE(1, test_argc, 1); break; + CASE_TEST(argv_addr); EXPECT_PTRGT(1, test_argv, brk); break; + CASE_TEST(argv_environ); EXPECT_PTRLT(1, test_argv, environ); break; + CASE_TEST(argv_total); EXPECT_EQ(1, environ - test_argv - 1, test_argc ?: 1); break; + CASE_TEST(argv0_addr); EXPECT_PTRGT(1, argv0, brk); break; + CASE_TEST(argv0_str); EXPECT_STRNZ(1, argv0 > brk ? argv0 : NULL); break; + CASE_TEST(argv0_len); EXPECT_GE(1, argv0 > brk ? strlen(argv0) : 0, 1); break; + CASE_TEST(environ_addr); EXPECT_PTRGT(1, environ, brk); break; + CASE_TEST(environ_envp); EXPECT_PTREQ(1, environ, test_envp); break; + CASE_TEST(environ_auxv); EXPECT_PTRLT(test_auxv != (void *)-1, environ, test_auxv); break; + CASE_TEST(environ_total); EXPECT_GE(test_auxv != (void *)-1, (void *)test_auxv - (void *)environ - 1, env_total); break; + CASE_TEST(environ_HOME); EXPECT_PTRNZ(1, getenv("HOME")); break; + CASE_TEST(auxv_addr); EXPECT_PTRGT(test_auxv != (void *)-1, test_auxv, brk); break; + CASE_TEST(auxv_AT_UID); EXPECT_EQ(1, getauxval(AT_UID), getuid()); break; + CASE_TEST(auxv_AT_PAGESZ); EXPECT_GE(1, getauxval(AT_PAGESZ), 4096); break; + case __LINE__: + return ret; /* must be last */ + /* note: do not set any defaults so as to permit holes above */ + } + } + return ret; +} + /* used by some syscall tests below */ int test_getdents64(const char *dir) @@ -458,9 +659,9 @@ int test_getdents64(const char *dir) return ret; } -static int test_getpagesize(void) +int test_getpagesize(void) { - long x = getpagesize(); + int x = getpagesize(); int c; if (x < 0) @@ -487,7 +688,7 @@ static int test_getpagesize(void) return !c; } -static int test_fork(void) +int test_fork(void) { int status; pid_t pid; @@ -512,14 +713,14 @@ static int test_fork(void) } } -static int test_stat_timestamps(void) +int test_stat_timestamps(void) { struct stat st; if (sizeof(st.st_atim.tv_sec) != sizeof(st.st_atime)) return 1; - if (stat("/proc/self/", &st)) + if (stat("/proc/self/", &st) && stat(argv0, &st) && stat("/", &st)) return 1; if (st.st_atim.tv_sec != st.st_atime || st.st_atim.tv_nsec > 1000000000) @@ -534,6 +735,86 @@ static int test_stat_timestamps(void) return 0; } +int test_mmap_munmap(void) +{ + int ret, fd, i, page_size; + void *mem; + size_t file_size, length; + off_t offset, pa_offset; + struct stat stat_buf; + const char * const files[] = { + "/dev/zero", + "/proc/1/exe", "/proc/self/exe", + argv0, + NULL + }; + + page_size = getpagesize(); + if (page_size < 0) + return 1; + + /* find a right file to mmap, existed and accessible */ + for (i = 0; files[i] != NULL; i++) { + ret = fd = open(files[i], O_RDONLY); + if (ret == -1) + continue; + else + break; + } + if (ret == -1) + return 1; + + ret = stat(files[i], &stat_buf); + if (ret == -1) + goto end; + + /* file size of the special /dev/zero is 0, let's assign one manually */ + if (i == 0) + file_size = 3*page_size; + else + file_size = stat_buf.st_size; + + offset = file_size - 1; + if (offset < 0) + offset = 0; + length = file_size - offset; + pa_offset = offset & ~(page_size - 1); + + mem = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_SHARED, fd, pa_offset); + if (mem == MAP_FAILED) { + ret = 1; + goto end; + } + + ret = munmap(mem, length + offset - pa_offset); + +end: + close(fd); + return !!ret; +} + +int test_pipe(void) +{ + const char *const msg = "hello, nolibc"; + int pipefd[2]; + char buf[32]; + size_t len; + + if (pipe(pipefd) == -1) + return 1; + + write(pipefd[1], msg, strlen(msg)); + close(pipefd[1]); + len = read(pipefd[0], buf, sizeof(buf)); + close(pipefd[0]); + + if (len != strlen(msg)) + return 1; + + return !!memcmp(buf, msg, len); +} + + /* Run syscall tests between IDs <min> and <max>. * Return 0 on success, non-zero on failure. */ @@ -548,6 +829,7 @@ int run_syscall(int min, int max) int tmp; int ret = 0; void *p1, *p2; + int has_gettid = 1; /* <proc> indicates whether or not /proc is mounted */ proc = stat("/proc", &stat_buf) == 0; @@ -555,6 +837,11 @@ int run_syscall(int min, int max) /* this will be used to skip certain tests that can't be run unprivileged */ euid0 = geteuid() == 0; + /* from 2.30, glibc provides gettid() */ +#if defined(__GLIBC_MINOR__) && defined(__GLIBC__) + has_gettid = __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 30); +#endif + for (test = min; test >= 0 && test <= max; test++) { int llen = 0; /* line length */ @@ -564,25 +851,24 @@ int run_syscall(int min, int max) switch (test + __LINE__ + 1) { CASE_TEST(getpid); EXPECT_SYSNE(1, getpid(), -1); break; CASE_TEST(getppid); EXPECT_SYSNE(1, getppid(), -1); break; -#ifdef NOLIBC - CASE_TEST(gettid); EXPECT_SYSNE(1, gettid(), -1); break; -#endif + CASE_TEST(gettid); EXPECT_SYSNE(has_gettid, gettid(), -1); break; CASE_TEST(getpgid_self); EXPECT_SYSNE(1, getpgid(0), -1); break; CASE_TEST(getpgid_bad); EXPECT_SYSER(1, getpgid(-1), -1, ESRCH); break; CASE_TEST(kill_0); EXPECT_SYSZR(1, kill(getpid(), 0)); break; CASE_TEST(kill_CONT); EXPECT_SYSZR(1, kill(getpid(), 0)); break; CASE_TEST(kill_BADPID); EXPECT_SYSER(1, kill(INT_MAX, 0), -1, ESRCH); break; + CASE_TEST(sbrk_0); EXPECT_PTRNE(1, sbrk(0), (void *)-1); break; CASE_TEST(sbrk); if ((p1 = p2 = sbrk(4096)) != (void *)-1) p2 = sbrk(-4096); EXPECT_SYSZR(1, (p2 == (void *)-1) || p2 == p1); break; CASE_TEST(brk); EXPECT_SYSZR(1, brk(sbrk(0))); break; - CASE_TEST(chdir_root); EXPECT_SYSZR(1, chdir("/")); break; + CASE_TEST(chdir_root); EXPECT_SYSZR(1, chdir("/")); chdir(getenv("PWD")); break; CASE_TEST(chdir_dot); EXPECT_SYSZR(1, chdir(".")); break; CASE_TEST(chdir_blah); EXPECT_SYSER(1, chdir("/blah"), -1, ENOENT); break; - CASE_TEST(chmod_net); EXPECT_SYSZR(proc, chmod("/proc/self/net", 0555)); break; + CASE_TEST(chmod_argv0); EXPECT_SYSZR(1, chmod(argv0, 0555)); break; CASE_TEST(chmod_self); EXPECT_SYSER(proc, chmod("/proc/self", 0555), -1, EPERM); break; CASE_TEST(chown_self); EXPECT_SYSER(proc, chown("/proc/self", 0, 0), -1, EPERM); break; CASE_TEST(chroot_root); EXPECT_SYSZR(euid0, chroot("/")); break; CASE_TEST(chroot_blah); EXPECT_SYSER(1, chroot("/proc/self/blah"), -1, ENOENT); break; - CASE_TEST(chroot_exe); EXPECT_SYSER(proc, chroot("/proc/self/exe"), -1, ENOTDIR); break; + CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(argv0), -1, ENOTDIR); break; CASE_TEST(close_m1); EXPECT_SYSER(1, close(-1), -1, EBADF); break; CASE_TEST(close_dup); EXPECT_SYSZR(1, close(dup(0))); break; CASE_TEST(dup_0); tmp = dup(0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break; @@ -603,23 +889,28 @@ int run_syscall(int min, int max) CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break; CASE_TEST(link_blah); EXPECT_SYSER(1, link("/proc/self/blah", "/blah"), -1, ENOENT); break; CASE_TEST(link_dir); EXPECT_SYSER(euid0, link("/", "/blah"), -1, EPERM); break; - CASE_TEST(link_cross); EXPECT_SYSER(proc, link("/proc/self/net", "/blah"), -1, EXDEV); break; + CASE_TEST(link_cross); EXPECT_SYSER(proc, link("/proc/self/cmdline", "/blah"), -1, EXDEV); break; CASE_TEST(lseek_m1); EXPECT_SYSER(1, lseek(-1, 0, SEEK_SET), -1, EBADF); break; CASE_TEST(lseek_0); EXPECT_SYSER(1, lseek(0, 0, SEEK_SET), -1, ESPIPE); break; CASE_TEST(mkdir_root); EXPECT_SYSER(1, mkdir("/", 0755), -1, EEXIST); break; + CASE_TEST(mmap_bad); EXPECT_PTRER(1, mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL); break; + CASE_TEST(munmap_bad); EXPECT_SYSER(1, munmap((void *)1, 0), -1, EINVAL); break; + CASE_TEST(mmap_munmap_good); EXPECT_SYSZR(1, test_mmap_munmap()); break; CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", 0), -1); if (tmp != -1) close(tmp); break; CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", 0), -1, ENOENT); if (tmp != -1) close(tmp); break; + CASE_TEST(pipe); EXPECT_SYSZR(1, test_pipe()); break; CASE_TEST(poll_null); EXPECT_SYSZR(1, poll(NULL, 0, 0)); break; CASE_TEST(poll_stdout); EXPECT_SYSNE(1, ({ struct pollfd fds = { 1, POLLOUT, 0}; poll(&fds, 1, 0); }), -1); break; CASE_TEST(poll_fault); EXPECT_SYSER(1, poll((void *)1, 1, 0), -1, EFAULT); break; CASE_TEST(prctl); EXPECT_SYSER(1, prctl(PR_SET_NAME, (unsigned long)NULL, 0, 0, 0), -1, EFAULT); break; CASE_TEST(read_badf); EXPECT_SYSER(1, read(-1, &tmp, 1), -1, EBADF); break; + CASE_TEST(rmdir_blah); EXPECT_SYSER(1, rmdir("/blah"), -1, ENOENT); break; CASE_TEST(sched_yield); EXPECT_SYSZR(1, sched_yield()); break; CASE_TEST(select_null); EXPECT_SYSZR(1, ({ struct timeval tv = { 0 }; select(0, NULL, NULL, NULL, &tv); })); break; CASE_TEST(select_stdout); EXPECT_SYSNE(1, ({ fd_set fds; FD_ZERO(&fds); FD_SET(1, &fds); select(2, NULL, &fds, NULL, NULL); }), -1); break; CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break; CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break; - CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break; + CASE_TEST(stat_fault); EXPECT_SYSER(1, stat((void *)1, &stat_buf), -1, EFAULT); break; CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break; CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break; CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break; @@ -642,9 +933,7 @@ int run_syscall(int min, int max) int run_stdlib(int min, int max) { int test; - int tmp; int ret = 0; - void *p1, *p2; for (test = min; test >= 0 && test <= max; test++) { int llen = 0; /* line length */ @@ -699,32 +988,23 @@ int run_stdlib(int min, int max) CASE_TEST(limit_int_fast8_max); EXPECT_EQ(1, INT_FAST8_MAX, (int_fast8_t) 0x7f); break; CASE_TEST(limit_int_fast8_min); EXPECT_EQ(1, INT_FAST8_MIN, (int_fast8_t) 0x80); break; CASE_TEST(limit_uint_fast8_max); EXPECT_EQ(1, UINT_FAST8_MAX, (uint_fast8_t) 0xff); break; - CASE_TEST(limit_int_fast16_min); EXPECT_EQ(1, INT_FAST16_MIN, (int_fast16_t) INTPTR_MIN); break; - CASE_TEST(limit_int_fast16_max); EXPECT_EQ(1, INT_FAST16_MAX, (int_fast16_t) INTPTR_MAX); break; + CASE_TEST(limit_int_fast16_min); EXPECT_EQ(1, INT_FAST16_MIN, (int_fast16_t) SINT_MIN_OF_TYPE(int_fast16_t)); break; + CASE_TEST(limit_int_fast16_max); EXPECT_EQ(1, INT_FAST16_MAX, (int_fast16_t) SINT_MAX_OF_TYPE(int_fast16_t)); break; CASE_TEST(limit_uint_fast16_max); EXPECT_EQ(1, UINT_FAST16_MAX, (uint_fast16_t) UINTPTR_MAX); break; - CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) INTPTR_MIN); break; - CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) INTPTR_MAX); break; + CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) SINT_MIN_OF_TYPE(int_fast32_t)); break; + CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) SINT_MAX_OF_TYPE(int_fast32_t)); break; CASE_TEST(limit_uint_fast32_max); EXPECT_EQ(1, UINT_FAST32_MAX, (uint_fast32_t) UINTPTR_MAX); break; CASE_TEST(limit_int_fast64_min); EXPECT_EQ(1, INT_FAST64_MIN, (int_fast64_t) INT64_MIN); break; CASE_TEST(limit_int_fast64_max); EXPECT_EQ(1, INT_FAST64_MAX, (int_fast64_t) INT64_MAX); break; CASE_TEST(limit_uint_fast64_max); EXPECT_EQ(1, UINT_FAST64_MAX, (uint_fast64_t) UINT64_MAX); break; -#if __SIZEOF_LONG__ == 8 - CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x8000000000000000LL); break; - CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffffffffffffLL); break; - CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, (uintptr_t) 0xffffffffffffffffULL); break; - CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, (ptrdiff_t) 0x8000000000000000LL); break; - CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, (ptrdiff_t) 0x7fffffffffffffffLL); break; - CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, (size_t) 0xffffffffffffffffULL); break; -#elif __SIZEOF_LONG__ == 4 - CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x80000000); break; - CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffff); break; - CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, (uintptr_t) 0xffffffffU); break; - CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, (ptrdiff_t) 0x80000000); break; - CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, (ptrdiff_t) 0x7fffffff); break; - CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, (size_t) 0xffffffffU); break; -#else -# warning "__SIZEOF_LONG__ is undefined" -#endif /* __SIZEOF_LONG__ */ + CASE_TEST(sizeof_long_sane); EXPECT_EQ(1, sizeof(long) == 8 || sizeof(long) == 4, 1); break; + CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, sizeof(long) == 8 ? (intptr_t) 0x8000000000000000LL : (intptr_t) 0x80000000); break; + CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, sizeof(long) == 8 ? (intptr_t) 0x7fffffffffffffffLL : (intptr_t) 0x7fffffff); break; + CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, sizeof(long) == 8 ? (uintptr_t) 0xffffffffffffffffULL : (uintptr_t) 0xffffffffU); break; + CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, sizeof(long) == 8 ? (ptrdiff_t) 0x8000000000000000LL : (ptrdiff_t) 0x80000000); break; + CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, sizeof(long) == 8 ? (ptrdiff_t) 0x7fffffffffffffffLL : (ptrdiff_t) 0x7fffffff); break; + CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, sizeof(long) == 8 ? (size_t) 0xffffffffffffffffULL : (size_t) 0xffffffffU); break; + case __LINE__: return ret; /* must be last */ /* note: do not set any defaults so as to permit holes above */ @@ -736,22 +1016,23 @@ int run_stdlib(int min, int max) #define EXPECT_VFPRINTF(c, expected, fmt, ...) \ ret += expect_vfprintf(llen, c, expected, fmt, ##__VA_ARGS__) -static int expect_vfprintf(int llen, size_t c, const char *expected, const char *fmt, ...) +static int expect_vfprintf(int llen, int c, const char *expected, const char *fmt, ...) { - int ret, fd, w, r; + int ret, fd; + ssize_t w, r; char buf[100]; FILE *memfile; va_list args; - fd = memfd_create("vfprintf", 0); + fd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR, 0600); if (fd == -1) { - pad_spc(llen, 64, "[FAIL]\n"); - return 1; + result(llen, SKIPPED); + return 0; } memfile = fdopen(fd, "w+"); if (!memfile) { - pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); return 1; } @@ -760,8 +1041,8 @@ static int expect_vfprintf(int llen, size_t c, const char *expected, const char va_end(args); if (w != c) { - llen += printf(" written(%d) != %d", w, (int) c); - pad_spc(llen, 64, "[FAIL]\n"); + llen += printf(" written(%d) != %d", (int)w, c); + result(llen, FAIL); return 1; } @@ -769,29 +1050,27 @@ static int expect_vfprintf(int llen, size_t c, const char *expected, const char lseek(fd, 0, SEEK_SET); r = read(fd, buf, sizeof(buf) - 1); - buf[r] = '\0'; fclose(memfile); if (r != w) { - llen += printf(" written(%d) != read(%d)", w, r); - pad_spc(llen, 64, "[FAIL]\n"); + llen += printf(" written(%d) != read(%d)", (int)w, (int)r); + result(llen, FAIL); return 1; } + buf[r] = '\0'; llen += printf(" \"%s\" = \"%s\"", expected, buf); ret = strncmp(expected, buf, c); - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + result(llen, ret ? FAIL : OK); return ret; } static int run_vfprintf(int min, int max) { int test; - int tmp; int ret = 0; - void *p1, *p2; for (test = min; test >= 0 && test <= max; test++) { int llen = 0; /* line length */ @@ -829,7 +1108,8 @@ static int smash_stack(void) return 1; } -static int run_protection(int min, int max) +static int run_protection(int min __attribute__((unused)), + int max __attribute__((unused))) { pid_t pid; int llen = 0, status; @@ -838,14 +1118,14 @@ static int run_protection(int min, int max) #if !defined(_NOLIBC_STACKPROTECTOR) llen += printf("not supported"); - pad_spc(llen, 64, "[SKIPPED]\n"); + result(llen, SKIPPED); return 0; #endif #if defined(_NOLIBC_STACKPROTECTOR) if (!__stack_chk_guard) { llen += printf("__stack_chk_guard not initialized"); - pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); return 1; } #endif @@ -856,7 +1136,7 @@ static int run_protection(int min, int max) switch (pid) { case -1: llen += printf("fork()"); - pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); return 1; case 0: @@ -872,10 +1152,10 @@ static int run_protection(int min, int max) if (pid == -1 || !WIFSIGNALED(status) || WTERMSIG(status) != SIGABRT) { llen += printf("waitpid()"); - pad_spc(llen, 64, "[FAIL]\n"); + result(llen, FAIL); return 1; } - pad_spc(llen, 64, " [OK]\n"); + result(llen, OK); return 0; } } @@ -891,11 +1171,13 @@ int prepare(void) */ if (stat("/dev/.", &stat_buf) == 0 || mkdir("/dev", 0755) == 0) { if (stat("/dev/console", &stat_buf) != 0 || - stat("/dev/null", &stat_buf) != 0) { + stat("/dev/null", &stat_buf) != 0 || + stat("/dev/zero", &stat_buf) != 0) { /* try devtmpfs first, otherwise fall back to manual creation */ if (mount("/dev", "/dev", "devtmpfs", 0, 0) != 0) { mknod("/dev/console", 0600 | S_IFCHR, makedev(5, 1)); mknod("/dev/null", 0666 | S_IFCHR, makedev(1, 3)); + mknod("/dev/zero", 0666 | S_IFCHR, makedev(1, 5)); } } } @@ -922,16 +1204,23 @@ int prepare(void) /* try to mount /proc if not mounted. Silently fail otherwise */ if (stat("/proc/.", &stat_buf) == 0 || mkdir("/proc", 0755) == 0) { - if (stat("/proc/self", &stat_buf) != 0) - mount("/proc", "/proc", "proc", 0, 0); + if (stat("/proc/self", &stat_buf) != 0) { + /* If not mountable, remove /proc completely to avoid misuse */ + if (mount("none", "/proc", "proc", 0, 0) != 0) + rmdir("/proc"); + } } + /* some tests rely on a writable /tmp */ + mkdir("/tmp", 0755); + return 0; } /* This is the definition of known test names, with their functions */ static const struct test test_names[] = { /* add new tests here */ + { .name = "startup", .func = run_startup }, { .name = "syscall", .func = run_syscall }, { .name = "stdlib", .func = run_stdlib }, { .name = "vfprintf", .func = run_vfprintf }, @@ -939,6 +1228,35 @@ static const struct test test_names[] = { { 0 } }; +static int is_setting_valid(char *test) +{ + int idx, len, test_len, valid = 0; + char delimiter; + + if (!test) + return valid; + + test_len = strlen(test); + + for (idx = 0; test_names[idx].name; idx++) { + len = strlen(test_names[idx].name); + if (test_len < len) + continue; + + if (strncmp(test, test_names[idx].name, len) != 0) + continue; + + delimiter = test[len]; + if (delimiter != ':' && delimiter != ',' && delimiter != '\0') + continue; + + valid = 1; + break; + } + + return valid; +} + int main(int argc, char **argv, char **envp) { int min = 0; @@ -948,7 +1266,10 @@ int main(int argc, char **argv, char **envp) int idx; char *test; - environ = envp; + argv0 = argv[0]; + test_argc = argc; + test_argv = argv; + test_envp = envp; /* when called as init, it's possible that no console was opened, for * example if no /dev file system was provided. We'll check that fd#1 @@ -964,10 +1285,10 @@ int main(int argc, char **argv, char **envp) * syscall:5-15[:.*],stdlib:8-10 */ test = argv[1]; - if (!test) + if (!is_setting_valid(test)) test = getenv("NOLIBC_TEST"); - if (test) { + if (is_setting_valid(test)) { char *comma, *colon, *dash, *value; do { @@ -1045,17 +1366,13 @@ int main(int argc, char **argv, char **envp) */ printf("Leaving init with final status: %d\n", !!ret); if (ret == 0) - reboot(LINUX_REBOOT_CMD_POWER_OFF); + reboot(RB_POWER_OFF); #if defined(__x86_64__) /* QEMU started with "-device isa-debug-exit -no-reboot" will * exit with status code 2N+1 when N is written to 0x501. We * hard-code the syscall here as it's arch-dependent. */ -#if defined(_NOLIBC_SYS_H) - else if (my_syscall3(__NR_ioperm, 0x501, 1, 1) == 0) -#else - else if (ioperm(0x501, 1, 1) == 0) -#endif + else if (syscall(__NR_ioperm, 0x501, 1, 1) == 0) __asm__ volatile ("outb %%al, %%dx" :: "d"(0x501), "a"(0)); /* if it does nothing, fall back to the regular panic */ #endif diff --git a/tools/testing/selftests/prctl/.gitignore b/tools/testing/selftests/prctl/.gitignore index 7a657b25f686..05d5e31661df 100644 --- a/tools/testing/selftests/prctl/.gitignore +++ b/tools/testing/selftests/prctl/.gitignore @@ -3,3 +3,4 @@ disable-tsc-ctxt-sw-stress-test disable-tsc-on-off-stress-test disable-tsc-test set-anon-vma-name-test +set-process-name diff --git a/tools/testing/selftests/prctl/Makefile b/tools/testing/selftests/prctl/Makefile index c058b81eeb41..01dc90fbb509 100644 --- a/tools/testing/selftests/prctl/Makefile +++ b/tools/testing/selftests/prctl/Makefile @@ -5,12 +5,10 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) ifeq ($(ARCH),x86) TEST_PROGS := disable-tsc-ctxt-sw-stress-test disable-tsc-on-off-stress-test \ - disable-tsc-test set-anon-vma-name-test + disable-tsc-test set-anon-vma-name-test set-process-name all: $(TEST_PROGS) include ../lib.mk -clean: - rm -fr $(TEST_PROGS) endif endif diff --git a/tools/testing/selftests/prctl/set-process-name.c b/tools/testing/selftests/prctl/set-process-name.c new file mode 100644 index 000000000000..3bc5e0e09eb9 --- /dev/null +++ b/tools/testing/selftests/prctl/set-process-name.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This test covers the PR_SET_NAME functionality of prctl calls + */ + +#include <errno.h> +#include <sys/prctl.h> +#include <string.h> + +#include "../kselftest_harness.h" + +#define CHANGE_NAME "changename" +#define EMPTY_NAME "" +#define TASK_COMM_LEN 16 + +int set_name(char *name) +{ + int res; + + res = prctl(PR_SET_NAME, name, NULL, NULL, NULL); + + if (res < 0) + return -errno; + return res; +} + +int check_is_name_correct(char *check_name) +{ + char name[TASK_COMM_LEN]; + int res; + + res = prctl(PR_GET_NAME, name, NULL, NULL, NULL); + + if (res < 0) + return -errno; + + return !strcmp(name, check_name); +} + +int check_null_pointer(char *check_name) +{ + char *name = NULL; + int res; + + res = prctl(PR_GET_NAME, name, NULL, NULL, NULL); + + return res; +} + +TEST(rename_process) { + + EXPECT_GE(set_name(CHANGE_NAME), 0); + EXPECT_TRUE(check_is_name_correct(CHANGE_NAME)); + + EXPECT_GE(set_name(EMPTY_NAME), 0); + EXPECT_TRUE(check_is_name_correct(EMPTY_NAME)); + + EXPECT_GE(set_name(CHANGE_NAME), 0); + EXPECT_LT(check_null_pointer(CHANGE_NAME), 0); +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/rcutorture/bin/configcheck.sh b/tools/testing/selftests/rcutorture/bin/configcheck.sh index b92dfeb7fbbf..99162d18bad3 100755 --- a/tools/testing/selftests/rcutorture/bin/configcheck.sh +++ b/tools/testing/selftests/rcutorture/bin/configcheck.sh @@ -3,6 +3,8 @@ # # Usage: configcheck.sh .config .config-template # +# Non-empty output if errors detected. +# # Copyright (C) IBM Corporation, 2011 # # Authors: Paul E. McKenney <paulmck@linux.ibm.com> @@ -10,32 +12,35 @@ T="`mktemp -d ${TMPDIR-/tmp}/configcheck.sh.XXXXXX`" trap 'rm -rf $T' 0 -sed -e 's/"//g' < $1 > $T/.config +# function test_kconfig_enabled ( Kconfig-var=val ) +function test_kconfig_enabled () { + if ! grep -q "^$1$" $T/.config + then + echo :$1: improperly set + return 1 + fi + return 0 +} -sed -e 's/"//g' -e 's/\(.*\)=n/# \1 is not set/' -e 's/^#CHECK#//' < $2 | -awk ' -{ - print "if grep -q \"" $0 "\" < '"$T/.config"'"; - print "then"; - print "\t:"; - print "else"; - if ($1 == "#") { - print "\tif grep -q \"" $2 "\" < '"$T/.config"'"; - print "\tthen"; - print "\t\tif test \"$firsttime\" = \"\"" - print "\t\tthen" - print "\t\t\tfirsttime=1" - print "\t\tfi" - print "\t\techo \":" $2 ": improperly set\""; - print "\telse"; - print "\t\t:"; - print "\tfi"; - } else { - print "\tif test \"$firsttime\" = \"\"" - print "\tthen" - print "\t\tfirsttime=1" - print "\tfi" - print "\techo \":" $0 ": improperly set\""; - } - print "fi"; - }' | sh +# function test_kconfig_disabled ( Kconfig-var ) +function test_kconfig_disabled () { + if grep -q "^$1=n$" $T/.config + then + return 0 + fi + if grep -q "^$1=" $T/.config + then + echo :$1=n: improperly set + return 1 + fi + return 0 +} + +sed -e 's/"//g' < $1 > $T/.config +sed -e 's/^#CHECK#//' < $2 > $T/ConfigFragment +grep '^CONFIG_.*=n$' $T/ConfigFragment | + sed -e 's/^/test_kconfig_disabled /' -e 's/=n$//' > $T/kconfig-n.sh +. $T/kconfig-n.sh +grep -v '^CONFIG_.*=n$' $T/ConfigFragment | grep '^CONFIG_' | + sed -e 's/^/test_kconfig_enabled /' > $T/kconfig-not-n.sh +. $T/kconfig-not-n.sh diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh index 48b9147e8c91..b8e2ea23cb3f 100644 --- a/tools/testing/selftests/rcutorture/bin/functions.sh +++ b/tools/testing/selftests/rcutorture/bin/functions.sh @@ -45,7 +45,7 @@ checkarg () { configfrag_boot_params () { if test -r "$2.boot" then - echo $1 `grep -v '^#' "$2.boot" | tr '\012' ' '` + echo `grep -v '^#' "$2.boot" | tr '\012' ' '` $1 else echo $1 fi diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuscale.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuscale.sh index b582113178ac..f683e424ddd5 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuscale.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuscale.sh @@ -40,6 +40,10 @@ awk ' sum += $5 / 1000.; } +/rcu_scale: Grace-period kthread CPU time/ { + cputime = $6; +} + END { newNR = asort(gptimes); if (newNR <= 0) { @@ -78,6 +82,8 @@ END { print "90th percentile grace-period duration: " gptimes[pct90]; print "99th percentile grace-period duration: " gptimes[pct99]; print "Maximum grace-period duration: " gptimes[newNR]; - print "Grace periods: " ngps + 0 " Batches: " nbatches + 0 " Ratio: " ngps / nbatches; + if (cputime != "") + cpustr = " CPU: " cputime; + print "Grace periods: " ngps + 0 " Batches: " nbatches + 0 " Ratio: " ngps / nbatches cpustr; print "Computed from rcuscale printk output."; }' diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh index 1df7e695edf7..5be670dd4009 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh @@ -16,6 +16,8 @@ T=/tmp/kvm-recheck.sh.$$ trap 'rm -f $T' 0 2 +configerrors=0 + PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH . functions.sh for rd in "$@" @@ -32,7 +34,7 @@ do fi TORTURE_SUITE="`cat $i/../torture_suite`" ; export TORTURE_SUITE configfile=`echo $i | sed -e 's,^.*/,,'` - rm -f $i/console.log.*.diags + rm -f $i/console.log.*.diags $i/ConfigFragment.diags case "${TORTURE_SUITE}" in X*) ;; @@ -49,8 +51,21 @@ do then echo QEMU killed fi - configcheck.sh $i/.config $i/ConfigFragment > $T 2>&1 - cat $T + configcheck.sh $i/.config $i/ConfigFragment > $i/ConfigFragment.diags 2>&1 + if grep -q '^CONFIG_KCSAN=y$' $i/ConfigFragment.input + then + # KCSAN forces a number of Kconfig options, so remove + # complaints about those Kconfig options in KCSAN runs. + mv $i/ConfigFragment.diags $i/ConfigFragment.diags.kcsan + grep -v -E 'CONFIG_PROVE_RCU|CONFIG_PREEMPT_COUNT' $i/ConfigFragment.diags.kcsan > $i/ConfigFragment.diags + fi + if test -s $i/ConfigFragment.diags + then + cat $i/ConfigFragment.diags + configerrors=$((configerrors+1)) + else + rm $i/ConfigFragment.diags + fi if test -r $i/Make.oldconfig.err then cat $i/Make.oldconfig.err @@ -65,7 +80,14 @@ do if test -f "$i/buildonly" then echo Build-only run, no boot/test - configcheck.sh $i/.config $i/ConfigFragment + configcheck.sh $i/.config $i/ConfigFragment > $i/ConfigFragment.diags 2>&1 + if test -s $i/ConfigFragment.diags + then + cat $i/ConfigFragment.diags + configerrors=$((configerrors+1)) + else + rm $i/ConfigFragment.diags + fi parse-build.sh $i/Make.out $configfile elif test -f "$i/qemu-cmd" then @@ -79,10 +101,10 @@ do done if test -f "$rd/kcsan.sum" then - if ! test -f $T + if ! test -f $i/ConfigFragment.diags then : - elif grep -q CONFIG_KCSAN=y $T + elif grep -q CONFIG_KCSAN=y $i/ConfigFragment.diags then echo "Compiler or architecture does not support KCSAN!" echo Did you forget to switch your compiler with '--kmake-arg CC=<cc-that-supports-kcsan>'? @@ -94,17 +116,23 @@ do fi fi done + +if test "$configerrors" -gt 0 +then + echo $configerrors runs with .config errors. + ret=1 +fi EDITOR=echo kvm-find-errors.sh "${@: -1}" > $T 2>&1 builderrors="`tr ' ' '\012' < $T | grep -c '/Make.out.diags'`" if test "$builderrors" -gt 0 then echo $builderrors runs with build errors. - ret=1 + ret=2 fi runerrors="`tr ' ' '\012' < $T | grep -c '/console.log.diags'`" if test "$runerrors" -gt 0 then echo $runerrors runs with runtime errors. - ret=2 + ret=3 fi exit $ret diff --git a/tools/testing/selftests/rcutorture/bin/kvm-remote.sh b/tools/testing/selftests/rcutorture/bin/kvm-remote.sh index a2328163eba1..134cdef5a6e0 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-remote.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-remote.sh @@ -137,14 +137,20 @@ chmod +x $T/bin/kvm-remote-*.sh # Check first to avoid the need for cleanup for system-name typos for i in $systems do - ncpus="`ssh -o BatchMode=yes $i getconf _NPROCESSORS_ONLN 2> /dev/null`" + ssh -o BatchMode=yes $i getconf _NPROCESSORS_ONLN > $T/ssh.stdout 2> $T/ssh.stderr ret=$? if test "$ret" -ne 0 then - echo System $i unreachable, giving up. | tee -a "$oldrun/remote-log" + echo "System $i unreachable ($ret), giving up." | tee -a "$oldrun/remote-log" + echo ' --- ssh stdout: vvv' | tee -a "$oldrun/remote-log" + cat $T/ssh.stdout | tee -a "$oldrun/remote-log" + echo ' --- ssh stdout: ^^^' | tee -a "$oldrun/remote-log" + echo ' --- ssh stderr: vvv' | tee -a "$oldrun/remote-log" + cat $T/ssh.stderr | tee -a "$oldrun/remote-log" + echo ' --- ssh stderr: ^^^' | tee -a "$oldrun/remote-log" exit 4 fi - echo $i: $ncpus CPUs " " `date` | tee -a "$oldrun/remote-log" + echo $i: `cat $T/ssh.stdout` CPUs " " `date` | tee -a "$oldrun/remote-log" done # Download and expand the tarball on all systems. 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 d2a3710a5f2a..b33cd8753689 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -9,9 +9,10 @@ # # Usage: kvm-test-1-run.sh config resdir seconds qemu-args boot_args_in # -# qemu-args defaults to "-enable-kvm -nographic", along with arguments -# specifying the number of CPUs and other options -# generated from the underlying CPU architecture. +# qemu-args defaults to "-enable-kvm -display none -no-reboot", along +# with arguments specifying the number of CPUs +# and other options generated from the underlying +# CPU architecture. # boot_args_in defaults to value returned by the per_version_boot_params # shell function. # @@ -57,7 +58,6 @@ config_override_param () { cat $T/Kconfig_args >> $resdir/ConfigFragment.input config_override.sh $T/$2 $T/Kconfig_args > $T/$2.tmp mv $T/$2.tmp $T/$2 - # Note that "#CHECK#" is not permitted on commandline. fi } @@ -140,7 +140,7 @@ then fi # Generate -smp qemu argument. -qemu_args="-enable-kvm -nographic $qemu_args" +qemu_args="-enable-kvm -display none -no-reboot $qemu_args" cpu_count=`configNR_CPUS.sh $resdir/ConfigFragment` cpu_count=`configfrag_boot_cpus "$boot_args_in" "$config_template" "$cpu_count"` if test "$cpu_count" -gt "$TORTURE_ALLOTED_CPUS" @@ -163,7 +163,7 @@ boot_args="`configfrag_boot_params "$boot_args_in" "$config_template"`" boot_args="`per_version_boot_params "$boot_args" $resdir/.config $seconds`" if test -n "$TORTURE_BOOT_GDB_ARG" then - boot_args="$boot_args $TORTURE_BOOT_GDB_ARG" + boot_args="$TORTURE_BOOT_GDB_ARG $boot_args" fi # Give bare-metal advice diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index d3cdc2d33d4b..b0f36a638a69 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -186,7 +186,7 @@ do fi ;; --kconfig|--kconfigs) - checkarg --kconfig "(Kconfig options)" $# "$2" '^CONFIG_[A-Z0-9_]\+=\([ynm]\|[0-9]\+\|"[^"]*"\)\( CONFIG_[A-Z0-9_]\+=\([ynm]\|[0-9]\+\|"[^"]*"\)\)*$' '^error$' + checkarg --kconfig "(Kconfig options)" $# "$2" '^\(#CHECK#\)\?CONFIG_[A-Z0-9_]\+=\([ynm]\|[0-9]\+\|"[^"]*"\)\( \(#CHECK#\)\?CONFIG_[A-Z0-9_]\+=\([ynm]\|[0-9]\+\|"[^"]*"\)\)*$' '^error$' TORTURE_KCONFIG_ARG="`echo "$TORTURE_KCONFIG_ARG $2" | sed -e 's/^ *//' -e 's/ *$//'`" shift ;; diff --git a/tools/testing/selftests/rcutorture/bin/mkinitrd.sh b/tools/testing/selftests/rcutorture/bin/mkinitrd.sh index 71f0dfbb2a6d..212c52ca90b5 100755 --- a/tools/testing/selftests/rcutorture/bin/mkinitrd.sh +++ b/tools/testing/selftests/rcutorture/bin/mkinitrd.sh @@ -10,7 +10,6 @@ D=tools/testing/selftests/rcutorture # Prerequisite checks -[ -z "$D" ] && echo >&2 "No argument supplied" && exit 1 if [ ! -d "$D" ]; then echo >&2 "$D does not exist: Malformed kernel source tree?" exit 1 @@ -34,12 +33,16 @@ cat > init.c << '___EOF___' volatile unsigned long delaycount; -int main(int argc, int argv[]) +int main(int argc, char *argv[]) { int i; struct timeval tv; struct timeval tvb; + printf("Torture-test rudimentary init program started, command line:\n"); + for (i = 0; i < argc; i++) + printf(" %s", argv[i]); + printf("\n"); for (;;) { sleep(1); /* Need some userspace time. */ @@ -64,15 +67,23 @@ ___EOF___ # build using nolibc on supported archs (smaller executable) and fall # back to regular glibc on other ones. if echo -e "#if __x86_64__||__i386__||__i486__||__i586__||__i686__" \ - "||__ARM_EABI__||__aarch64__||__s390x__\nyes\n#endif" \ + "||__ARM_EABI__||__aarch64__||__s390x__||__loongarch__\nyes\n#endif" \ | ${CROSS_COMPILE}gcc -E -nostdlib -xc - \ | grep -q '^yes'; then # architecture supported by nolibc ${CROSS_COMPILE}gcc -fno-asynchronous-unwind-tables -fno-ident \ -nostdlib -include ../../../../include/nolibc/nolibc.h \ -s -static -Os -o init init.c -lgcc + ret=$? else ${CROSS_COMPILE}gcc -s -static -Os -o init init.c + ret=$? +fi + +if [ "$ret" -ne 0 ] +then + echo "Failed to create a statically linked C-language initrd" + exit "$ret" fi rm init.c diff --git a/tools/testing/selftests/rcutorture/bin/torture.sh b/tools/testing/selftests/rcutorture/bin/torture.sh index 5a2ae2264403..12b50a4a881a 100755 --- a/tools/testing/selftests/rcutorture/bin/torture.sh +++ b/tools/testing/selftests/rcutorture/bin/torture.sh @@ -55,6 +55,8 @@ do_kasan=yes do_kcsan=no do_clocksourcewd=yes do_rt=yes +do_rcutasksflavors=yes +do_srcu_lockdep=yes # doyesno - Helper function for yes/no arguments function doyesno () { @@ -73,18 +75,20 @@ usage () { echo " --configs-locktorture \"config-file list w/ repeat factor (10*LOCK01)\"" echo " --configs-scftorture \"config-file list w/ repeat factor (2*CFLIST)\"" echo " --do-all" - echo " --do-allmodconfig / --do-no-allmodconfig" - echo " --do-clocksourcewd / --do-no-clocksourcewd" - echo " --do-kasan / --do-no-kasan" - echo " --do-kcsan / --do-no-kcsan" - echo " --do-kvfree / --do-no-kvfree" - echo " --do-locktorture / --do-no-locktorture" + echo " --do-allmodconfig / --do-no-allmodconfig / --no-allmodconfig" + echo " --do-clocksourcewd / --do-no-clocksourcewd / --no-clocksourcewd" + echo " --do-kasan / --do-no-kasan / --no-kasan" + echo " --do-kcsan / --do-no-kcsan / --no-kcsan" + echo " --do-kvfree / --do-no-kvfree / --no-kvfree" + echo " --do-locktorture / --do-no-locktorture / --no-locktorture" echo " --do-none" - echo " --do-rcuscale / --do-no-rcuscale" - echo " --do-rcutorture / --do-no-rcutorture" - echo " --do-refscale / --do-no-refscale" - echo " --do-rt / --do-no-rt" - echo " --do-scftorture / --do-no-scftorture" + echo " --do-rcuscale / --do-no-rcuscale / --no-rcuscale" + echo " --do-rcutasksflavors / --do-no-rcutasksflavors / --no-rcutasksflavors" + echo " --do-rcutorture / --do-no-rcutorture / --no-rcutorture" + echo " --do-refscale / --do-no-refscale / --no-refscale" + echo " --do-rt / --do-no-rt / --no-rt" + echo " --do-scftorture / --do-no-scftorture / --no-scftorture" + echo " --do-srcu-lockdep / --do-no-srcu-lockdep / --no-srcu-lockdep" echo " --duration [ <minutes> | <hours>h | <days>d ]" echo " --kcsan-kmake-arg kernel-make-arguments" exit 1 @@ -115,6 +119,7 @@ do ;; --do-all|--doall) do_allmodconfig=yes + do_rcutasksflavor=yes do_rcutorture=yes do_locktorture=yes do_scftorture=yes @@ -125,27 +130,29 @@ do do_kasan=yes do_kcsan=yes do_clocksourcewd=yes + do_srcu_lockdep=yes ;; - --do-allmodconfig|--do-no-allmodconfig) + --do-allmodconfig|--do-no-allmodconfig|--no-allmodconfig) do_allmodconfig=`doyesno "$1" --do-allmodconfig` ;; - --do-clocksourcewd|--do-no-clocksourcewd) + --do-clocksourcewd|--do-no-clocksourcewd|--no-clocksourcewd) do_clocksourcewd=`doyesno "$1" --do-clocksourcewd` ;; - --do-kasan|--do-no-kasan) + --do-kasan|--do-no-kasan|--no-kasan) do_kasan=`doyesno "$1" --do-kasan` ;; - --do-kcsan|--do-no-kcsan) + --do-kcsan|--do-no-kcsan|--no-kcsan) do_kcsan=`doyesno "$1" --do-kcsan` ;; - --do-kvfree|--do-no-kvfree) + --do-kvfree|--do-no-kvfree|--no-kvfree) do_kvfree=`doyesno "$1" --do-kvfree` ;; - --do-locktorture|--do-no-locktorture) + --do-locktorture|--do-no-locktorture|--no-locktorture) do_locktorture=`doyesno "$1" --do-locktorture` ;; --do-none|--donone) do_allmodconfig=no + do_rcutasksflavors=no do_rcutorture=no do_locktorture=no do_scftorture=no @@ -156,22 +163,29 @@ do do_kasan=no do_kcsan=no do_clocksourcewd=no + do_srcu_lockdep=no ;; - --do-rcuscale|--do-no-rcuscale) + --do-rcuscale|--do-no-rcuscale|--no-rcuscale) do_rcuscale=`doyesno "$1" --do-rcuscale` ;; - --do-rcutorture|--do-no-rcutorture) + --do-rcutasksflavors|--do-no-rcutasksflavors|--no-rcutasksflavors) + do_rcutasksflavors=`doyesno "$1" --do-rcutasksflavors` + ;; + --do-rcutorture|--do-no-rcutorture|--no-rcutorture) do_rcutorture=`doyesno "$1" --do-rcutorture` ;; - --do-refscale|--do-no-refscale) + --do-refscale|--do-no-refscale|--no-refscale) do_refscale=`doyesno "$1" --do-refscale` ;; - --do-rt|--do-no-rt) + --do-rt|--do-no-rt|--no-rt) do_rt=`doyesno "$1" --do-rt` ;; - --do-scftorture|--do-no-scftorture) + --do-scftorture|--do-no-scftorture|--no-scftorture) do_scftorture=`doyesno "$1" --do-scftorture` ;; + --do-srcu-lockdep|--do-no-srcu-lockdep|--no-srcu-lockdep) + do_srcu_lockdep=`doyesno "$1" --do-srcu-lockdep` + ;; --duration) checkarg --duration "(minutes)" $# "$2" '^[0-9][0-9]*\(m\|h\|d\|\)$' '^error' mult=1 @@ -361,6 +375,40 @@ then fi fi +# Test building RCU Tasks flavors in isolation, both SMP and !SMP +if test "$do_rcutasksflavors" = "yes" +then + echo " --- rcutasksflavors:" Start `date` | tee -a $T/log + rtfdir="tools/testing/selftests/rcutorture/res/$ds/results-rcutasksflavors" + mkdir -p "$rtfdir" + cat > $T/rcutasksflavors << __EOF__ +#CHECK#CONFIG_TASKS_RCU=n +#CHECK#CONFIG_TASKS_RUDE_RCU=n +#CHECK#CONFIG_TASKS_TRACE_RCU=n +__EOF__ + for flavor in CONFIG_TASKS_RCU CONFIG_TASKS_RUDE_RCU CONFIG_TASKS_TRACE_RCU + do + forceflavor="`echo $flavor | sed -e 's/^CONFIG/CONFIG_FORCE/'`" + deselectedflavors="`grep -v $flavor $T/rcutasksflavors | tr '\012' ' ' | tr -s ' ' | sed -e 's/ *$//'`" + echo " --- Running RCU Tasks Trace flavor $flavor `date`" >> $rtfdir/log + tools/testing/selftests/rcutorture/bin/kvm.sh --datestamp "$ds/results-rcutasksflavors/$flavor" --buildonly --configs "TINY01 TREE04" --kconfig "CONFIG_RCU_EXPERT=y CONFIG_RCU_SCALE_TEST=y $forceflavor=y $deselectedflavors" --trust-make > $T/$flavor.out 2>&1 + retcode=$? + if test "$retcode" -ne 0 + then + break + fi + done + if test "$retcode" -eq 0 + then + echo "rcutasksflavors($retcode)" $rtfdir >> $T/successes + echo Success >> $rtfdir/log + else + echo "rcutasksflavors($retcode)" $rtfdir >> $T/failures + echo " --- rcutasksflavors Test summary:" >> $rtfdir/log + echo " --- Summary: Exit code $retcode from $flavor, see Make.out" >> $rtfdir/log + fi +fi + # --torture rcu if test "$do_rcutorture" = "yes" then @@ -376,8 +424,10 @@ fi if test "$do_scftorture" = "yes" then + # Scale memory based on the number of CPUs. + scfmem=$((2+HALF_ALLOTED_CPUS/16)) torture_bootargs="scftorture.nthreads=$HALF_ALLOTED_CPUS torture.disable_onoff_at_boot csdlock_debug=1" - torture_set "scftorture" tools/testing/selftests/rcutorture/bin/kvm.sh --torture scf --allcpus --duration "$duration_scftorture" --configs "$configs_scftorture" --kconfig "CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --memory 2G --trust-make + torture_set "scftorture" tools/testing/selftests/rcutorture/bin/kvm.sh --torture scf --allcpus --duration "$duration_scftorture" --configs "$configs_scftorture" --kconfig "CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --memory ${scfmem}G --trust-make fi if test "$do_rt" = "yes" @@ -391,6 +441,23 @@ then torture_set "rcurttorture-exp" tools/testing/selftests/rcutorture/bin/kvm.sh --allcpus --duration "$duration_rcutorture" --configs "TREE03" --trust-make fi +if test "$do_srcu_lockdep" = "yes" +then + echo " --- do-srcu-lockdep:" Start `date` | tee -a $T/log + tools/testing/selftests/rcutorture/bin/srcu_lockdep.sh --datestamp "$ds/results-srcu-lockdep" > $T/srcu_lockdep.sh.out 2>&1 + retcode=$? + cp $T/srcu_lockdep.sh.out "tools/testing/selftests/rcutorture/res/$ds/results-srcu-lockdep/log" + if test "$retcode" -eq 0 + then + echo "srcu_lockdep($retcode)" "tools/testing/selftests/rcutorture/res/$ds/results-srcu-lockdep" >> $T/successes + echo Success >> "tools/testing/selftests/rcutorture/res/$ds/results-srcu-lockdep/log" + else + echo "srcu_lockdep($retcode)" "tools/testing/selftests/rcutorture/res/$ds/results-srcu-lockdep" >> $T/failures + echo " --- srcu_lockdep Test Summary:" >> "tools/testing/selftests/rcutorture/res/$ds/results-srcu-lockdep/log" + echo " --- Summary: Exit code $retcode from srcu_lockdep.sh, see ds/results-srcu-lockdep" >> "tools/testing/selftests/rcutorture/res/$ds/results-srcu-lockdep/log" + fi +fi + if test "$do_refscale" = yes then primlist="`grep '\.name[ ]*=' kernel/rcu/refscale.c | sed -e 's/^[^"]*"//' -e 's/".*$//'`" @@ -541,11 +608,23 @@ then fi echo Started at $startdate, ended at `date`, duration `get_starttime_duration $starttime`. | tee -a $T/log echo Summary: Successes: $nsuccesses Failures: $nfailures. | tee -a $T/log +tdir="`cat $T/successes $T/failures | head -1 | awk '{ print $NF }' | sed -e 's,/[^/]\+/*$,,'`" +find "$tdir" -name 'ConfigFragment.diags' -print > $T/configerrors +find "$tdir" -name 'Make.out.diags' -print > $T/builderrors +if test -s "$T/configerrors" +then + echo " Scenarios with .config errors: `wc -l "$T/configerrors" | awk '{ print $1 }'`" + nonkcsanbug="yes" +fi +if test -s "$T/builderrors" +then + echo " Scenarios with build errors: `wc -l "$T/builderrors" | awk '{ print $1 }'`" + nonkcsanbug="yes" +fi if test -z "$nonkcsanbug" && test -s "$T/failuresum" then echo " All bugs were KCSAN failures." fi -tdir="`cat $T/successes $T/failures | head -1 | awk '{ print $NF }' | sed -e 's,/[^/]\+/*$,,'`" if test -n "$tdir" && test $compress_concurrency -gt 0 then # KASAN vmlinux files can approach 1GB in size, so compress them. diff --git a/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh index d3e4b2971f92..e7bb32709d78 100644 --- a/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh @@ -22,8 +22,9 @@ locktorture_param_onoff () { # # Adds per-version torture-module parameters to kernels supporting them. per_version_boot_params () { - echo $1 `locktorture_param_onoff "$1" "$2"` \ + echo `locktorture_param_onoff "$1" "$2"` \ locktorture.stat_interval=15 \ locktorture.shutdown_secs=$3 \ - locktorture.verbose=1 + locktorture.verbose=1 \ + $1 } diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 index dea26c568678..2ef2fb69c360 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 @@ -6,6 +6,5 @@ CONFIG_PREEMPT=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=n CONFIG_NO_HZ_FULL=y -#CHECK#CONFIG_RCU_EXPERT=n CONFIG_TASKS_RCU=y CONFIG_RCU_EXPERT=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 index 04831ef1f9b5..8ae41d5f81a3 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 @@ -15,4 +15,3 @@ CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_RCU_EXPERT=y -CONFIG_BOOTPARAM_HOTPLUG_CPU0=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh index e2bc99c785e7..c044df386876 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh @@ -46,10 +46,11 @@ rcutorture_param_stat_interval () { # # Adds per-version torture-module parameters to kernels supporting them. per_version_boot_params () { - echo $1 `rcutorture_param_onoff "$1" "$2"` \ + echo `rcutorture_param_onoff "$1" "$2"` \ `rcutorture_param_n_barrier_cbs "$1"` \ `rcutorture_param_stat_interval "$1"` \ rcutorture.shutdown_secs=$3 \ rcutorture.test_no_idle_hz=1 \ - rcutorture.verbose=1 + rcutorture.verbose=1 \ + $1 } diff --git a/tools/testing/selftests/rcutorture/configs/rcuscale/CFcommon b/tools/testing/selftests/rcutorture/configs/rcuscale/CFcommon index 6a00157bee5b..b1ffd7c67604 100644 --- a/tools/testing/selftests/rcutorture/configs/rcuscale/CFcommon +++ b/tools/testing/selftests/rcutorture/configs/rcuscale/CFcommon @@ -2,5 +2,7 @@ CONFIG_RCU_SCALE_TEST=y CONFIG_PRINTK_TIME=y CONFIG_FORCE_TASKS_RCU=y #CHECK#CONFIG_TASKS_RCU=y +CONFIG_FORCE_TASKS_RUDE_RCU=y +#CHECK#CONFIG_TASKS_RUDE_RCU=y CONFIG_FORCE_TASKS_TRACE_RCU=y #CHECK#CONFIG_TASKS_TRACE_RCU=y diff --git a/tools/testing/selftests/rcutorture/configs/rcuscale/TRACE01 b/tools/testing/selftests/rcutorture/configs/rcuscale/TRACE01 index 227aba7783af..0059592c7408 100644 --- a/tools/testing/selftests/rcutorture/configs/rcuscale/TRACE01 +++ b/tools/testing/selftests/rcutorture/configs/rcuscale/TRACE01 @@ -2,6 +2,8 @@ CONFIG_SMP=y CONFIG_PREEMPT_NONE=y CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=n +CONFIG_PREEMPT_DYNAMIC=n +#CHECK#CONFIG_TREE_RCU=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_FULL=n diff --git a/tools/testing/selftests/rcutorture/configs/rcuscale/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcuscale/ver_functions.sh index ffbe15109f0d..28070b43f017 100644 --- a/tools/testing/selftests/rcutorture/configs/rcuscale/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/rcuscale/ver_functions.sh @@ -11,6 +11,7 @@ # # Adds per-version torture-module parameters to kernels supporting them. per_version_boot_params () { - echo $1 rcuscale.shutdown=1 \ - rcuscale.verbose=0 + echo rcuscale.shutdown=1 \ + rcuscale.verbose=0 \ + $1 } diff --git a/tools/testing/selftests/rcutorture/configs/refscale/NOPREEMPT b/tools/testing/selftests/rcutorture/configs/refscale/NOPREEMPT index ef2b501a6971..67f9d2998afd 100644 --- a/tools/testing/selftests/rcutorture/configs/refscale/NOPREEMPT +++ b/tools/testing/selftests/rcutorture/configs/refscale/NOPREEMPT @@ -2,6 +2,7 @@ CONFIG_SMP=y CONFIG_PREEMPT_NONE=y CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=n +CONFIG_PREEMPT_DYNAMIC=n #CHECK#CONFIG_PREEMPT_RCU=n CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=y diff --git a/tools/testing/selftests/rcutorture/configs/refscale/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/refscale/ver_functions.sh index f81fa2c541a6..748465627601 100644 --- a/tools/testing/selftests/rcutorture/configs/refscale/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/refscale/ver_functions.sh @@ -11,6 +11,7 @@ # # Adds per-version torture-module parameters to kernels supporting them. per_version_boot_params () { - echo $1 refscale.shutdown=1 \ - refscale.verbose=0 + echo refscale.shutdown=1 \ + refscale.verbose=0 \ + $1 } diff --git a/tools/testing/selftests/rcutorture/configs/scf/NOPREEMPT b/tools/testing/selftests/rcutorture/configs/scf/NOPREEMPT index 3a59346b3de7..6133f54ce2a7 100644 --- a/tools/testing/selftests/rcutorture/configs/scf/NOPREEMPT +++ b/tools/testing/selftests/rcutorture/configs/scf/NOPREEMPT @@ -2,6 +2,8 @@ CONFIG_SMP=y CONFIG_PREEMPT_NONE=y CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=n +CONFIG_PREEMPT_DYNAMIC=n +#CHECK#CONFIG_PREEMPT_RCU=n CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=n CONFIG_NO_HZ_FULL=y diff --git a/tools/testing/selftests/rcutorture/configs/scf/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/scf/ver_functions.sh index 2d949e58f5a5..7637f68ef0ce 100644 --- a/tools/testing/selftests/rcutorture/configs/scf/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/scf/ver_functions.sh @@ -22,8 +22,9 @@ scftorture_param_onoff () { # # Adds per-version torture-module parameters to kernels supporting them. per_version_boot_params () { - echo $1 `scftorture_param_onoff "$1" "$2"` \ + echo `scftorture_param_onoff "$1" "$2"` \ scftorture.stat_interval=15 \ scftorture.shutdown_secs=$3 \ - scftorture.verbose=1 + scftorture.verbose=1 \ + $1 } diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/.gitignore b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/.gitignore deleted file mode 100644 index 24e27957efcc..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -srcu.c diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/Makefile b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/Makefile deleted file mode 100644 index 4bed0b678f8b..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -all: srcu.c store_buffering - -LINUX_SOURCE = ../../../../../.. - -modified_srcu_input = $(LINUX_SOURCE)/include/linux/srcu.h \ - $(LINUX_SOURCE)/kernel/rcu/srcu.c - -modified_srcu_output = include/linux/srcu.h srcu.c - -include/linux/srcu.h: srcu.c - -srcu.c: modify_srcu.awk Makefile $(modified_srcu_input) - awk -f modify_srcu.awk $(modified_srcu_input) $(modified_srcu_output) - -store_buffering: - @cd tests/store_buffering; make diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/delay.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/delay.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/delay.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/export.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/export.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/export.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/mutex.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/mutex.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/mutex.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/percpu.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/percpu.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/percpu.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/preempt.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/preempt.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/preempt.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/rcupdate.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/rcupdate.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/rcupdate.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/sched.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/sched.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/sched.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/smp.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/smp.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/smp.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/workqueue.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/workqueue.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/workqueue.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/uapi/linux/types.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/uapi/linux/types.h deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/uapi/linux/types.h +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/kconfig.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/kconfig.h deleted file mode 100644 index f2860dd1b407..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/kconfig.h +++ /dev/null @@ -1 +0,0 @@ -#include <LINUX_SOURCE/linux/kconfig.h> diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/types.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/types.h deleted file mode 100644 index 8bc960e5e713..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/types.h +++ /dev/null @@ -1,152 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * This header has been modifies to remove definitions of types that - * are defined in standard userspace headers or are problematic for some - * other reason. - */ - -#ifndef _LINUX_TYPES_H -#define _LINUX_TYPES_H - -#define __EXPORTED_HEADERS__ -#include <uapi/linux/types.h> - -#ifndef __ASSEMBLY__ - -#define DECLARE_BITMAP(name, bits) \ - unsigned long name[BITS_TO_LONGS(bits)] - -typedef __u32 __kernel_dev_t; - -/* bsd */ -typedef unsigned char u_char; -typedef unsigned short u_short; -typedef unsigned int u_int; -typedef unsigned long u_long; - -/* sysv */ -typedef unsigned char unchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ulong; - -#ifndef __BIT_TYPES_DEFINED__ -#define __BIT_TYPES_DEFINED__ - -typedef __u8 u_int8_t; -typedef __s8 int8_t; -typedef __u16 u_int16_t; -typedef __s16 int16_t; -typedef __u32 u_int32_t; -typedef __s32 int32_t; - -#endif /* !(__BIT_TYPES_DEFINED__) */ - -typedef __u8 uint8_t; -typedef __u16 uint16_t; -typedef __u32 uint32_t; - -/* this is a special 64bit data type that is 8-byte aligned */ -#define aligned_u64 __u64 __attribute__((aligned(8))) -#define aligned_be64 __be64 __attribute__((aligned(8))) -#define aligned_le64 __le64 __attribute__((aligned(8))) - -/** - * The type used for indexing onto a disc or disc partition. - * - * Linux always considers sectors to be 512 bytes long independently - * of the devices real block size. - * - * blkcnt_t is the type of the inode's block count. - */ -typedef u64 sector_t; - -/* - * The type of an index into the pagecache. - */ -#define pgoff_t unsigned long - -/* - * A dma_addr_t can hold any valid DMA address, i.e., any address returned - * by the DMA API. - * - * If the DMA API only uses 32-bit addresses, dma_addr_t need only be 32 - * bits wide. Bus addresses, e.g., PCI BARs, may be wider than 32 bits, - * but drivers do memory-mapped I/O to ioremapped kernel virtual addresses, - * so they don't care about the size of the actual bus addresses. - */ -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -typedef u64 dma_addr_t; -#else -typedef u32 dma_addr_t; -#endif - -#ifdef CONFIG_PHYS_ADDR_T_64BIT -typedef u64 phys_addr_t; -#else -typedef u32 phys_addr_t; -#endif - -typedef phys_addr_t resource_size_t; - -/* - * This type is the placeholder for a hardware interrupt number. It has to be - * big enough to enclose whatever representation is used by a given platform. - */ -typedef unsigned long irq_hw_number_t; - -typedef struct { - int counter; -} atomic_t; - -#ifdef CONFIG_64BIT -typedef struct { - long counter; -} atomic64_t; -#endif - -struct list_head { - struct list_head *next, *prev; -}; - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -/** - * struct callback_head - callback structure for use with RCU and task_work - * @next: next update requests in a list - * @func: actual update function to call after the grace period. - * - * The struct is aligned to size of pointer. On most architectures it happens - * naturally due ABI requirements, but some architectures (like CRIS) have - * weird ABI and we need to ask it explicitly. - * - * The alignment is required to guarantee that bits 0 and 1 of @next will be - * clear under normal conditions -- as long as we use call_rcu() or - * call_srcu() to queue callback. - * - * This guarantee is important for few reasons: - * - future call_rcu_lazy() will make use of lower bits in the pointer; - * - the structure shares storage spacer in struct page with @compound_head, - * which encode PageTail() in bit 0. The guarantee is needed to avoid - * false-positive PageTail(). - */ -struct callback_head { - struct callback_head *next; - void (*func)(struct callback_head *head); -} __attribute__((aligned(sizeof(void *)))); -#define rcu_head callback_head - -typedef void (*rcu_callback_t)(struct rcu_head *head); -typedef void (*call_rcu_func_t)(struct rcu_head *head, rcu_callback_t func); - -/* clocksource cycle base type */ -typedef u64 cycle_t; - -#endif /* __ASSEMBLY__ */ -#endif /* _LINUX_TYPES_H */ diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk deleted file mode 100755 index e05182d3e47d..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk +++ /dev/null @@ -1,376 +0,0 @@ -#!/usr/bin/awk -f -# SPDX-License-Identifier: GPL-2.0 - -# Modify SRCU for formal verification. The first argument should be srcu.h and -# the second should be srcu.c. Outputs modified srcu.h and srcu.c into the -# current directory. - -BEGIN { - if (ARGC != 5) { - print "Usange: input.h input.c output.h output.c" > "/dev/stderr"; - exit 1; - } - h_output = ARGV[3]; - c_output = ARGV[4]; - ARGC = 3; - - # Tokenize using FS and not RS as FS supports regular expressions. Each - # record is one line of source, except that backslashed lines are - # combined. Comments are treated as field separators, as are quotes. - quote_regexp="\"([^\\\\\"]|\\\\.)*\""; - comment_regexp="\\/\\*([^*]|\\*+[^*/])*\\*\\/|\\/\\/.*(\n|$)"; - FS="([ \\\\\t\n\v\f;,.=(){}+*/<>&|^-]|\\[|\\]|" comment_regexp "|" quote_regexp ")+"; - - inside_srcu_struct = 0; - inside_srcu_init_def = 0; - srcu_init_param_name = ""; - in_macro = 0; - brace_nesting = 0; - paren_nesting = 0; - - # Allow the manipulation of the last field separator after has been - # seen. - last_fs = ""; - # Whether the last field separator was intended to be output. - last_fs_print = 0; - - # rcu_batches stores the initialization for each instance of struct - # rcu_batch - - in_comment = 0; - - outputfile = ""; -} - -{ - prev_outputfile = outputfile; - if (FILENAME ~ /\.h$/) { - outputfile = h_output; - if (FNR != NR) { - print "Incorrect file order" > "/dev/stderr"; - exit 1; - } - } - else - outputfile = c_output; - - if (prev_outputfile && outputfile != prev_outputfile) { - new_outputfile = outputfile; - outputfile = prev_outputfile; - update_fieldsep("", 0); - outputfile = new_outputfile; - } -} - -# Combine the next line into $0. -function combine_line() { - ret = getline next_line; - if (ret == 0) { - # Don't allow two consecutive getlines at the end of the file - if (eof_found) { - print "Error: expected more input." > "/dev/stderr"; - exit 1; - } else { - eof_found = 1; - } - } else if (ret == -1) { - print "Error reading next line of file" FILENAME > "/dev/stderr"; - exit 1; - } - $0 = $0 "\n" next_line; -} - -# Combine backslashed lines and multiline comments. -function combine_backslashes() { - while (/\\$|\/\*([^*]|\*+[^*\/])*\**$/) { - combine_line(); - } -} - -function read_line() { - combine_line(); - combine_backslashes(); -} - -# Print out field separators and update variables that depend on them. Only -# print if p is true. Call with sep="" and p=0 to print out the last field -# separator. -function update_fieldsep(sep, p) { - # Count braces - sep_tmp = sep; - gsub(quote_regexp "|" comment_regexp, "", sep_tmp); - while (1) - { - if (sub("[^{}()]*\\{", "", sep_tmp)) { - brace_nesting++; - continue; - } - if (sub("[^{}()]*\\}", "", sep_tmp)) { - brace_nesting--; - if (brace_nesting < 0) { - print "Unbalanced braces!" > "/dev/stderr"; - exit 1; - } - continue; - } - if (sub("[^{}()]*\\(", "", sep_tmp)) { - paren_nesting++; - continue; - } - if (sub("[^{}()]*\\)", "", sep_tmp)) { - paren_nesting--; - if (paren_nesting < 0) { - print "Unbalanced parenthesis!" > "/dev/stderr"; - exit 1; - } - continue; - } - - break; - } - - if (last_fs_print) - printf("%s", last_fs) > outputfile; - last_fs = sep; - last_fs_print = p; -} - -# Shifts the fields down by n positions. Calls next if there are no more. If p -# is true then print out field separators. -function shift_fields(n, p) { - do { - if (match($0, FS) > 0) { - update_fieldsep(substr($0, RSTART, RLENGTH), p); - if (RSTART + RLENGTH <= length()) - $0 = substr($0, RSTART + RLENGTH); - else - $0 = ""; - } else { - update_fieldsep("", 0); - print "" > outputfile; - next; - } - } while (--n > 0); -} - -# Shifts and prints the first n fields. -function print_fields(n) { - do { - update_fieldsep("", 0); - printf("%s", $1) > outputfile; - shift_fields(1, 1); - } while (--n > 0); -} - -{ - combine_backslashes(); -} - -# Print leading FS -{ - if (match($0, "^(" FS ")+") > 0) { - update_fieldsep(substr($0, RSTART, RLENGTH), 1); - if (RSTART + RLENGTH <= length()) - $0 = substr($0, RSTART + RLENGTH); - else - $0 = ""; - } -} - -# Parse the line. -{ - while (NF > 0) { - if ($1 == "struct" && NF < 3) { - read_line(); - continue; - } - - if (FILENAME ~ /\.h$/ && !inside_srcu_struct && - brace_nesting == 0 && paren_nesting == 0 && - $1 == "struct" && $2 == "srcu_struct" && - $0 ~ "^struct(" FS ")+srcu_struct(" FS ")+\\{") { - inside_srcu_struct = 1; - print_fields(2); - continue; - } - if (inside_srcu_struct && brace_nesting == 0 && - paren_nesting == 0) { - inside_srcu_struct = 0; - update_fieldsep("", 0); - for (name in rcu_batches) - print "extern struct rcu_batch " name ";" > outputfile; - } - - if (inside_srcu_struct && $1 == "struct" && $2 == "rcu_batch") { - # Move rcu_batches outside of the struct. - rcu_batches[$3] = ""; - shift_fields(3, 1); - sub(/;[[:space:]]*$/, "", last_fs); - continue; - } - - if (FILENAME ~ /\.h$/ && !inside_srcu_init_def && - $1 == "#define" && $2 == "__SRCU_STRUCT_INIT") { - inside_srcu_init_def = 1; - srcu_init_param_name = $3; - in_macro = 1; - print_fields(3); - continue; - } - if (inside_srcu_init_def && brace_nesting == 0 && - paren_nesting == 0) { - inside_srcu_init_def = 0; - in_macro = 0; - continue; - } - - if (inside_srcu_init_def && brace_nesting == 1 && - paren_nesting == 0 && last_fs ~ /\.[[:space:]]*$/ && - $1 ~ /^[[:alnum:]_]+$/) { - name = $1; - if (name in rcu_batches) { - # Remove the dot. - sub(/\.[[:space:]]*$/, "", last_fs); - - old_record = $0; - do - shift_fields(1, 0); - while (last_fs !~ /,/ || paren_nesting > 0); - end_loc = length(old_record) - length($0); - end_loc += index(last_fs, ",") - length(last_fs); - - last_fs = substr(last_fs, index(last_fs, ",") + 1); - last_fs_print = 1; - - match(old_record, "^"name"("FS")+="); - start_loc = RSTART + RLENGTH; - - len = end_loc - start_loc; - initializer = substr(old_record, start_loc, len); - gsub(srcu_init_param_name "\\.", "", initializer); - rcu_batches[name] = initializer; - continue; - } - } - - # Don't include a nonexistent file - if (!in_macro && $1 == "#include" && /^#include[[:space:]]+"rcu\.h"/) { - update_fieldsep("", 0); - next; - } - - # Ignore most preprocessor stuff. - if (!in_macro && $1 ~ /#/) { - break; - } - - if (brace_nesting > 0 && $1 ~ "^[[:alnum:]_]+$" && NF < 2) { - read_line(); - continue; - } - if (brace_nesting > 0 && - $0 ~ "^[[:alnum:]_]+[[:space:]]*(\\.|->)[[:space:]]*[[:alnum:]_]+" && - $2 in rcu_batches) { - # Make uses of rcu_batches global. Somewhat unreliable. - shift_fields(1, 0); - print_fields(1); - continue; - } - - if ($1 == "static" && NF < 3) { - read_line(); - continue; - } - if ($1 == "static" && ($2 == "bool" && $3 == "try_check_zero" || - $2 == "void" && $3 == "srcu_flip")) { - shift_fields(1, 1); - print_fields(2); - continue; - } - - # Distinguish between read-side and write-side memory barriers. - if ($1 == "smp_mb" && NF < 2) { - read_line(); - continue; - } - if (match($0, /^smp_mb[[:space:]();\/*]*[[:alnum:]]/)) { - barrier_letter = substr($0, RLENGTH, 1); - if (barrier_letter ~ /A|D/) - new_barrier_name = "sync_smp_mb"; - else if (barrier_letter ~ /B|C/) - new_barrier_name = "rs_smp_mb"; - else { - print "Unrecognized memory barrier." > "/dev/null"; - exit 1; - } - - shift_fields(1, 1); - printf("%s", new_barrier_name) > outputfile; - continue; - } - - # Skip definition of rcu_synchronize, since it is already - # defined in misc.h. Only present in old versions of srcu. - if (brace_nesting == 0 && paren_nesting == 0 && - $1 == "struct" && $2 == "rcu_synchronize" && - $0 ~ "^struct(" FS ")+rcu_synchronize(" FS ")+\\{") { - shift_fields(2, 0); - while (brace_nesting) { - if (NF < 2) - read_line(); - shift_fields(1, 0); - } - } - - # Skip definition of wakeme_after_rcu for the same reason - if (brace_nesting == 0 && $1 == "static" && $2 == "void" && - $3 == "wakeme_after_rcu") { - while (NF < 5) - read_line(); - shift_fields(3, 0); - do { - while (NF < 3) - read_line(); - shift_fields(1, 0); - } while (paren_nesting || brace_nesting); - } - - if ($1 ~ /^(unsigned|long)$/ && NF < 3) { - read_line(); - continue; - } - - # Give srcu_batches_completed the correct type for old SRCU. - if (brace_nesting == 0 && $1 == "long" && - $2 == "srcu_batches_completed") { - update_fieldsep("", 0); - printf("unsigned ") > outputfile; - print_fields(2); - continue; - } - if (brace_nesting == 0 && $1 == "unsigned" && $2 == "long" && - $3 == "srcu_batches_completed") { - print_fields(3); - continue; - } - - # Just print out the input code by default. - print_fields(1); - } - update_fieldsep("", 0); - print > outputfile; - next; -} - -END { - update_fieldsep("", 0); - - if (brace_nesting != 0) { - print "Unbalanced braces!" > "/dev/stderr"; - exit 1; - } - - # Define the rcu_batches - for (name in rcu_batches) - print "struct rcu_batch " name " = " rcu_batches[name] ";" > c_output; -} diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/assume.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/assume.h deleted file mode 100644 index 570a49d9da7e..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/assume.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef ASSUME_H -#define ASSUME_H - -/* Provide an assumption macro that can be disabled for gcc. */ -#ifdef RUN -#define assume(x) \ - do { \ - /* Evaluate x to suppress warnings. */ \ - (void) (x); \ - } while (0) - -#else -#define assume(x) __CPROVER_assume(x) -#endif - -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/barriers.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/barriers.h deleted file mode 100644 index 3f95a768a03b..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/barriers.h +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef BARRIERS_H -#define BARRIERS_H - -#define barrier() __asm__ __volatile__("" : : : "memory") - -#ifdef RUN -#define smp_mb() __sync_synchronize() -#define smp_mb__after_unlock_lock() __sync_synchronize() -#else -/* - * Copied from CBMC's implementation of __sync_synchronize(), which - * seems to be disabled by default. - */ -#define smp_mb() __CPROVER_fence("WWfence", "RRfence", "RWfence", "WRfence", \ - "WWcumul", "RRcumul", "RWcumul", "WRcumul") -#define smp_mb__after_unlock_lock() __CPROVER_fence("WWfence", "RRfence", "RWfence", "WRfence", \ - "WWcumul", "RRcumul", "RWcumul", "WRcumul") -#endif - -/* - * Allow memory barriers to be disabled in either the read or write side - * of SRCU individually. - */ - -#ifndef NO_SYNC_SMP_MB -#define sync_smp_mb() smp_mb() -#else -#define sync_smp_mb() do {} while (0) -#endif - -#ifndef NO_READ_SIDE_SMP_MB -#define rs_smp_mb() smp_mb() -#else -#define rs_smp_mb() do {} while (0) -#endif - -#define READ_ONCE(x) (*(volatile typeof(x) *) &(x)) -#define WRITE_ONCE(x) ((*(volatile typeof(x) *) &(x)) = (val)) - -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/bug_on.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/bug_on.h deleted file mode 100644 index 5e7912c6a521..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/bug_on.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef BUG_ON_H -#define BUG_ON_H - -#include <assert.h> - -#define BUG() assert(0) -#define BUG_ON(x) assert(!(x)) - -/* Does it make sense to treat warnings as errors? */ -#define WARN() BUG() -#define WARN_ON(x) (BUG_ON(x), false) - -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/combined_source.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/combined_source.c deleted file mode 100644 index e67ee5b3dd7c..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/combined_source.c +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <config.h> - -/* Include all source files. */ - -#include "include_srcu.c" - -#include "preempt.c" -#include "misc.c" - -/* Used by test.c files */ -#include <pthread.h> -#include <stdlib.h> -#include <linux/srcu.h> diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/config.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/config.h deleted file mode 100644 index 283d7103334f..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/config.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* "Cheater" definitions based on restricted Kconfig choices. */ - -#undef CONFIG_TINY_RCU -#undef __CHECKER__ -#undef CONFIG_DEBUG_LOCK_ALLOC -#undef CONFIG_DEBUG_OBJECTS_RCU_HEAD -#undef CONFIG_HOTPLUG_CPU -#undef CONFIG_MODULES -#undef CONFIG_NO_HZ_FULL_SYSIDLE -#undef CONFIG_PREEMPT_COUNT -#undef CONFIG_PREEMPT_RCU -#undef CONFIG_PROVE_RCU -#undef CONFIG_RCU_NOCB_CPU -#undef CONFIG_RCU_NOCB_CPU_ALL -#undef CONFIG_RCU_STALL_COMMON -#undef CONFIG_RCU_TRACE -#undef CONFIG_RCU_USER_QS -#undef CONFIG_TASKS_RCU -#define CONFIG_TREE_RCU - -#define CONFIG_GENERIC_ATOMIC64 - -#if NR_CPUS > 1 -#define CONFIG_SMP -#else -#undef CONFIG_SMP -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/include_srcu.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/include_srcu.c deleted file mode 100644 index e5202d4cff30..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/include_srcu.c +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <config.h> - -#include <assert.h> -#include <errno.h> -#include <inttypes.h> -#include <pthread.h> -#include <stddef.h> -#include <string.h> -#include <sys/types.h> - -#include "int_typedefs.h" - -#include "barriers.h" -#include "bug_on.h" -#include "locks.h" -#include "misc.h" -#include "preempt.h" -#include "percpu.h" -#include "workqueues.h" - -#ifdef USE_SIMPLE_SYNC_SRCU -#define synchronize_srcu(sp) synchronize_srcu_original(sp) -#endif - -#include <srcu.c> - -#ifdef USE_SIMPLE_SYNC_SRCU -#undef synchronize_srcu - -#include "simple_sync_srcu.c" -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/int_typedefs.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/int_typedefs.h deleted file mode 100644 index 0dd27aa517a7..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/int_typedefs.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef INT_TYPEDEFS_H -#define INT_TYPEDEFS_H - -#include <inttypes.h> - -typedef int8_t s8; -typedef uint8_t u8; -typedef int16_t s16; -typedef uint16_t u16; -typedef int32_t s32; -typedef uint32_t u32; -typedef int64_t s64; -typedef uint64_t u64; - -typedef int8_t __s8; -typedef uint8_t __u8; -typedef int16_t __s16; -typedef uint16_t __u16; -typedef int32_t __s32; -typedef uint32_t __u32; -typedef int64_t __s64; -typedef uint64_t __u64; - -#define S8_C(x) INT8_C(x) -#define U8_C(x) UINT8_C(x) -#define S16_C(x) INT16_C(x) -#define U16_C(x) UINT16_C(x) -#define S32_C(x) INT32_C(x) -#define U32_C(x) UINT32_C(x) -#define S64_C(x) INT64_C(x) -#define U64_C(x) UINT64_C(x) - -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/locks.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/locks.h deleted file mode 100644 index 1e24827f96f1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/locks.h +++ /dev/null @@ -1,221 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef LOCKS_H -#define LOCKS_H - -#include <limits.h> -#include <pthread.h> -#include <stdbool.h> - -#include "assume.h" -#include "bug_on.h" -#include "preempt.h" - -int nondet_int(void); - -#define __acquire(x) -#define __acquires(x) -#define __release(x) -#define __releases(x) - -/* Only use one lock mechanism. Select which one. */ -#ifdef PTHREAD_LOCK -struct lock_impl { - pthread_mutex_t mutex; -}; - -static inline void lock_impl_lock(struct lock_impl *lock) -{ - BUG_ON(pthread_mutex_lock(&lock->mutex)); -} - -static inline void lock_impl_unlock(struct lock_impl *lock) -{ - BUG_ON(pthread_mutex_unlock(&lock->mutex)); -} - -static inline bool lock_impl_trylock(struct lock_impl *lock) -{ - int err = pthread_mutex_trylock(&lock->mutex); - - if (!err) - return true; - else if (err == EBUSY) - return false; - BUG(); -} - -static inline void lock_impl_init(struct lock_impl *lock) -{ - pthread_mutex_init(&lock->mutex, NULL); -} - -#define LOCK_IMPL_INITIALIZER {.mutex = PTHREAD_MUTEX_INITIALIZER} - -#else /* !defined(PTHREAD_LOCK) */ -/* Spinlock that assumes that it always gets the lock immediately. */ - -struct lock_impl { - bool locked; -}; - -static inline bool lock_impl_trylock(struct lock_impl *lock) -{ -#ifdef RUN - /* TODO: Should this be a test and set? */ - return __sync_bool_compare_and_swap(&lock->locked, false, true); -#else - __CPROVER_atomic_begin(); - bool old_locked = lock->locked; - lock->locked = true; - __CPROVER_atomic_end(); - - /* Minimal barrier to prevent accesses leaking out of lock. */ - __CPROVER_fence("RRfence", "RWfence"); - - return !old_locked; -#endif -} - -static inline void lock_impl_lock(struct lock_impl *lock) -{ - /* - * CBMC doesn't support busy waiting, so just assume that the - * lock is available. - */ - assume(lock_impl_trylock(lock)); - - /* - * If the lock was already held by this thread then the assumption - * is unsatisfiable (deadlock). - */ -} - -static inline void lock_impl_unlock(struct lock_impl *lock) -{ -#ifdef RUN - BUG_ON(!__sync_bool_compare_and_swap(&lock->locked, true, false)); -#else - /* Minimal barrier to prevent accesses leaking out of lock. */ - __CPROVER_fence("RWfence", "WWfence"); - - __CPROVER_atomic_begin(); - bool old_locked = lock->locked; - lock->locked = false; - __CPROVER_atomic_end(); - - BUG_ON(!old_locked); -#endif -} - -static inline void lock_impl_init(struct lock_impl *lock) -{ - lock->locked = false; -} - -#define LOCK_IMPL_INITIALIZER {.locked = false} - -#endif /* !defined(PTHREAD_LOCK) */ - -/* - * Implement spinlocks using the lock mechanism. Wrap the lock to prevent mixing - * locks of different types. - */ -typedef struct { - struct lock_impl internal_lock; -} spinlock_t; - -#define SPIN_LOCK_UNLOCKED {.internal_lock = LOCK_IMPL_INITIALIZER} -#define __SPIN_LOCK_UNLOCKED(x) SPIN_LOCK_UNLOCKED -#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED - -static inline void spin_lock_init(spinlock_t *lock) -{ - lock_impl_init(&lock->internal_lock); -} - -static inline void spin_lock(spinlock_t *lock) -{ - /* - * Spin locks also need to be removed in order to eliminate all - * memory barriers. They are only used by the write side anyway. - */ -#ifndef NO_SYNC_SMP_MB - preempt_disable(); - lock_impl_lock(&lock->internal_lock); -#endif -} - -static inline void spin_unlock(spinlock_t *lock) -{ -#ifndef NO_SYNC_SMP_MB - lock_impl_unlock(&lock->internal_lock); - preempt_enable(); -#endif -} - -/* Don't bother with interrupts */ -#define spin_lock_irq(lock) spin_lock(lock) -#define spin_unlock_irq(lock) spin_unlock(lock) -#define spin_lock_irqsave(lock, flags) spin_lock(lock) -#define spin_unlock_irqrestore(lock, flags) spin_unlock(lock) - -/* - * This is supposed to return an int, but I think that a bool should work as - * well. - */ -static inline bool spin_trylock(spinlock_t *lock) -{ -#ifndef NO_SYNC_SMP_MB - preempt_disable(); - return lock_impl_trylock(&lock->internal_lock); -#else - return true; -#endif -} - -struct completion { - /* Hopefully this won't overflow. */ - unsigned int count; -}; - -#define COMPLETION_INITIALIZER(x) {.count = 0} -#define DECLARE_COMPLETION(x) struct completion x = COMPLETION_INITIALIZER(x) -#define DECLARE_COMPLETION_ONSTACK(x) DECLARE_COMPLETION(x) - -static inline void init_completion(struct completion *c) -{ - c->count = 0; -} - -static inline void wait_for_completion(struct completion *c) -{ - unsigned int prev_count = __sync_fetch_and_sub(&c->count, 1); - - assume(prev_count); -} - -static inline void complete(struct completion *c) -{ - unsigned int prev_count = __sync_fetch_and_add(&c->count, 1); - - BUG_ON(prev_count == UINT_MAX); -} - -/* This function probably isn't very useful for CBMC. */ -static inline bool try_wait_for_completion(struct completion *c) -{ - BUG(); -} - -static inline bool completion_done(struct completion *c) -{ - return c->count; -} - -/* TODO: Implement complete_all */ -static inline void complete_all(struct completion *c) -{ - BUG(); -} - -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.c deleted file mode 100644 index 9440cc39e3c6..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.c +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <config.h> - -#include "misc.h" -#include "bug_on.h" - -struct rcu_head; - -void wakeme_after_rcu(struct rcu_head *head) -{ - BUG(); -} diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.h deleted file mode 100644 index aca50030f954..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef MISC_H -#define MISC_H - -#include "assume.h" -#include "int_typedefs.h" -#include "locks.h" - -#include <linux/types.h> - -/* Probably won't need to deal with bottom halves. */ -static inline void local_bh_disable(void) {} -static inline void local_bh_enable(void) {} - -#define MODULE_ALIAS(X) -#define module_param(...) -#define EXPORT_SYMBOL_GPL(x) - -#define container_of(ptr, type, member) ({ \ - const typeof(((type *)0)->member) *__mptr = (ptr); \ - (type *)((char *)__mptr - offsetof(type, member)); \ -}) - -#ifndef USE_SIMPLE_SYNC_SRCU -/* Abuse udelay to make sure that busy loops terminate. */ -#define udelay(x) assume(0) - -#else - -/* The simple custom synchronize_srcu is ok with try_check_zero failing. */ -#define udelay(x) do { } while (0) -#endif - -#define trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ - do { } while (0) - -#define notrace - -/* Avoid including rcupdate.h */ -struct rcu_synchronize { - struct rcu_head head; - struct completion completion; -}; - -void wakeme_after_rcu(struct rcu_head *head); - -#define rcu_lock_acquire(a) do { } while (0) -#define rcu_lock_release(a) do { } while (0) -#define rcu_lockdep_assert(c, s) do { } while (0) -#define RCU_LOCKDEP_WARN(c, s) do { } while (0) - -/* Let CBMC non-deterministically choose switch between normal and expedited. */ -bool rcu_gp_is_normal(void); -bool rcu_gp_is_expedited(void); - -/* Do the same for old versions of rcu. */ -#define rcu_expedited (rcu_gp_is_expedited()) - -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/percpu.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/percpu.h deleted file mode 100644 index 27e67a3f291f..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/percpu.h +++ /dev/null @@ -1,93 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef PERCPU_H -#define PERCPU_H - -#include <stddef.h> -#include "bug_on.h" -#include "preempt.h" - -#define __percpu - -/* Maximum size of any percpu data. */ -#define PERCPU_OFFSET (4 * sizeof(long)) - -/* Ignore alignment, as CBMC doesn't care about false sharing. */ -#define alloc_percpu(type) __alloc_percpu(sizeof(type), 1) - -static inline void *__alloc_percpu(size_t size, size_t align) -{ - BUG(); - return NULL; -} - -static inline void free_percpu(void *ptr) -{ - BUG(); -} - -#define per_cpu_ptr(ptr, cpu) \ - ((typeof(ptr)) ((char *) (ptr) + PERCPU_OFFSET * cpu)) - -#define __this_cpu_inc(pcp) __this_cpu_add(pcp, 1) -#define __this_cpu_dec(pcp) __this_cpu_sub(pcp, 1) -#define __this_cpu_sub(pcp, n) __this_cpu_add(pcp, -(typeof(pcp)) (n)) - -#define this_cpu_inc(pcp) this_cpu_add(pcp, 1) -#define this_cpu_dec(pcp) this_cpu_sub(pcp, 1) -#define this_cpu_sub(pcp, n) this_cpu_add(pcp, -(typeof(pcp)) (n)) - -/* Make CBMC use atomics to work around bug. */ -#ifdef RUN -#define THIS_CPU_ADD_HELPER(ptr, x) (*(ptr) += (x)) -#else -/* - * Split the atomic into a read and a write so that it has the least - * possible ordering. - */ -#define THIS_CPU_ADD_HELPER(ptr, x) \ - do { \ - typeof(ptr) this_cpu_add_helper_ptr = (ptr); \ - typeof(ptr) this_cpu_add_helper_x = (x); \ - typeof(*ptr) this_cpu_add_helper_temp; \ - __CPROVER_atomic_begin(); \ - this_cpu_add_helper_temp = *(this_cpu_add_helper_ptr); \ - __CPROVER_atomic_end(); \ - this_cpu_add_helper_temp += this_cpu_add_helper_x; \ - __CPROVER_atomic_begin(); \ - *(this_cpu_add_helper_ptr) = this_cpu_add_helper_temp; \ - __CPROVER_atomic_end(); \ - } while (0) -#endif - -/* - * For some reason CBMC needs an atomic operation even though this is percpu - * data. - */ -#define __this_cpu_add(pcp, n) \ - do { \ - BUG_ON(preemptible()); \ - THIS_CPU_ADD_HELPER(per_cpu_ptr(&(pcp), thread_cpu_id), \ - (typeof(pcp)) (n)); \ - } while (0) - -#define this_cpu_add(pcp, n) \ - do { \ - int this_cpu_add_impl_cpu = get_cpu(); \ - THIS_CPU_ADD_HELPER(per_cpu_ptr(&(pcp), this_cpu_add_impl_cpu), \ - (typeof(pcp)) (n)); \ - put_cpu(); \ - } while (0) - -/* - * This will cause a compiler warning because of the cast from char[][] to - * type*. This will cause a compile time error if type is too big. - */ -#define DEFINE_PER_CPU(type, name) \ - char name[NR_CPUS][PERCPU_OFFSET]; \ - typedef char percpu_too_big_##name \ - [sizeof(type) > PERCPU_OFFSET ? -1 : 1] - -#define for_each_possible_cpu(cpu) \ - for ((cpu) = 0; (cpu) < NR_CPUS; ++(cpu)) - -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.c deleted file mode 100644 index b4083ae348fb..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.c +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <config.h> - -#include "preempt.h" - -#include "assume.h" -#include "locks.h" - -/* Support NR_CPUS of at most 64 */ -#define CPU_PREEMPTION_LOCKS_INIT0 LOCK_IMPL_INITIALIZER -#define CPU_PREEMPTION_LOCKS_INIT1 \ - CPU_PREEMPTION_LOCKS_INIT0, CPU_PREEMPTION_LOCKS_INIT0 -#define CPU_PREEMPTION_LOCKS_INIT2 \ - CPU_PREEMPTION_LOCKS_INIT1, CPU_PREEMPTION_LOCKS_INIT1 -#define CPU_PREEMPTION_LOCKS_INIT3 \ - CPU_PREEMPTION_LOCKS_INIT2, CPU_PREEMPTION_LOCKS_INIT2 -#define CPU_PREEMPTION_LOCKS_INIT4 \ - CPU_PREEMPTION_LOCKS_INIT3, CPU_PREEMPTION_LOCKS_INIT3 -#define CPU_PREEMPTION_LOCKS_INIT5 \ - CPU_PREEMPTION_LOCKS_INIT4, CPU_PREEMPTION_LOCKS_INIT4 - -/* - * Simulate disabling preemption by locking a particular cpu. NR_CPUS - * should be the actual number of cpus, not just the maximum. - */ -struct lock_impl cpu_preemption_locks[NR_CPUS] = { - CPU_PREEMPTION_LOCKS_INIT0 -#if (NR_CPUS - 1) & 1 - , CPU_PREEMPTION_LOCKS_INIT0 -#endif -#if (NR_CPUS - 1) & 2 - , CPU_PREEMPTION_LOCKS_INIT1 -#endif -#if (NR_CPUS - 1) & 4 - , CPU_PREEMPTION_LOCKS_INIT2 -#endif -#if (NR_CPUS - 1) & 8 - , CPU_PREEMPTION_LOCKS_INIT3 -#endif -#if (NR_CPUS - 1) & 16 - , CPU_PREEMPTION_LOCKS_INIT4 -#endif -#if (NR_CPUS - 1) & 32 - , CPU_PREEMPTION_LOCKS_INIT5 -#endif -}; - -#undef CPU_PREEMPTION_LOCKS_INIT0 -#undef CPU_PREEMPTION_LOCKS_INIT1 -#undef CPU_PREEMPTION_LOCKS_INIT2 -#undef CPU_PREEMPTION_LOCKS_INIT3 -#undef CPU_PREEMPTION_LOCKS_INIT4 -#undef CPU_PREEMPTION_LOCKS_INIT5 - -__thread int thread_cpu_id; -__thread int preempt_disable_count; - -void preempt_disable(void) -{ - BUG_ON(preempt_disable_count < 0 || preempt_disable_count == INT_MAX); - - if (preempt_disable_count++) - return; - - thread_cpu_id = nondet_int(); - assume(thread_cpu_id >= 0); - assume(thread_cpu_id < NR_CPUS); - lock_impl_lock(&cpu_preemption_locks[thread_cpu_id]); -} - -void preempt_enable(void) -{ - BUG_ON(preempt_disable_count < 1); - - if (--preempt_disable_count) - return; - - lock_impl_unlock(&cpu_preemption_locks[thread_cpu_id]); -} diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.h deleted file mode 100644 index f8b762cd214c..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef PREEMPT_H -#define PREEMPT_H - -#include <stdbool.h> - -#include "bug_on.h" - -/* This flag contains garbage if preempt_disable_count is 0. */ -extern __thread int thread_cpu_id; - -/* Support recursive preemption disabling. */ -extern __thread int preempt_disable_count; - -void preempt_disable(void); -void preempt_enable(void); - -static inline void preempt_disable_notrace(void) -{ - preempt_disable(); -} - -static inline void preempt_enable_no_resched(void) -{ - preempt_enable(); -} - -static inline void preempt_enable_notrace(void) -{ - preempt_enable(); -} - -static inline int preempt_count(void) -{ - return preempt_disable_count; -} - -static inline bool preemptible(void) -{ - return !preempt_count(); -} - -static inline int get_cpu(void) -{ - preempt_disable(); - return thread_cpu_id; -} - -static inline void put_cpu(void) -{ - preempt_enable(); -} - -static inline void might_sleep(void) -{ - BUG_ON(preempt_disable_count); -} - -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/simple_sync_srcu.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/simple_sync_srcu.c deleted file mode 100644 index 97f592048e0b..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/simple_sync_srcu.c +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <config.h> - -#include <assert.h> -#include <errno.h> -#include <inttypes.h> -#include <pthread.h> -#include <stddef.h> -#include <string.h> -#include <sys/types.h> - -#include "int_typedefs.h" - -#include "barriers.h" -#include "bug_on.h" -#include "locks.h" -#include "misc.h" -#include "preempt.h" -#include "percpu.h" -#include "workqueues.h" - -#include <linux/srcu.h> - -/* Functions needed from modify_srcu.c */ -bool try_check_zero(struct srcu_struct *sp, int idx, int trycount); -void srcu_flip(struct srcu_struct *sp); - -/* Simpler implementation of synchronize_srcu that ignores batching. */ -void synchronize_srcu(struct srcu_struct *sp) -{ - int idx; - /* - * This code assumes that try_check_zero will succeed anyway, - * so there is no point in multiple tries. - */ - const int trycount = 1; - - might_sleep(); - - /* Ignore the lock, as multiple writers aren't working yet anyway. */ - - idx = 1 ^ (sp->completed & 1); - - /* For comments see srcu_advance_batches. */ - - assume(try_check_zero(sp, idx, trycount)); - - srcu_flip(sp); - - assume(try_check_zero(sp, idx^1, trycount)); -} diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/workqueues.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/workqueues.h deleted file mode 100644 index 28b960300971..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/workqueues.h +++ /dev/null @@ -1,103 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef WORKQUEUES_H -#define WORKQUEUES_H - -#include <stdbool.h> - -#include "barriers.h" -#include "bug_on.h" -#include "int_typedefs.h" - -#include <linux/types.h> - -/* Stub workqueue implementation. */ - -struct work_struct; -typedef void (*work_func_t)(struct work_struct *work); -void delayed_work_timer_fn(unsigned long __data); - -struct work_struct { -/* atomic_long_t data; */ - unsigned long data; - - struct list_head entry; - work_func_t func; -#ifdef CONFIG_LOCKDEP - struct lockdep_map lockdep_map; -#endif -}; - -struct timer_list { - struct hlist_node entry; - unsigned long expires; - void (*function)(unsigned long); - unsigned long data; - u32 flags; - int slack; -}; - -struct delayed_work { - struct work_struct work; - struct timer_list timer; - - /* target workqueue and CPU ->timer uses to queue ->work */ - struct workqueue_struct *wq; - int cpu; -}; - - -static inline bool schedule_work(struct work_struct *work) -{ - BUG(); - return true; -} - -static inline bool schedule_work_on(int cpu, struct work_struct *work) -{ - BUG(); - return true; -} - -static inline bool queue_work(struct workqueue_struct *wq, - struct work_struct *work) -{ - BUG(); - return true; -} - -static inline bool queue_delayed_work(struct workqueue_struct *wq, - struct delayed_work *dwork, - unsigned long delay) -{ - BUG(); - return true; -} - -#define INIT_WORK(w, f) \ - do { \ - (w)->data = 0; \ - (w)->func = (f); \ - } while (0) - -#define INIT_DELAYED_WORK(w, f) INIT_WORK(&(w)->work, (f)) - -#define __WORK_INITIALIZER(n, f) { \ - .data = 0, \ - .entry = { &(n).entry, &(n).entry }, \ - .func = f \ - } - -/* Don't bother initializing timer. */ -#define __DELAYED_WORK_INITIALIZER(n, f, tflags) { \ - .work = __WORK_INITIALIZER((n).work, (f)), \ - } - -#define DECLARE_WORK(n, f) \ - struct workqueue_struct n = __WORK_INITIALIZER - -#define DECLARE_DELAYED_WORK(n, f) \ - struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, 0) - -#define system_power_efficient_wq ((struct workqueue_struct *) NULL) - -#endif diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/.gitignore b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/.gitignore deleted file mode 100644 index d65462d64816..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -*.out diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/Makefile b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/Makefile deleted file mode 100644 index ad21b925fbb4..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -CBMC_FLAGS = -I../.. -I../../src -I../../include -I../../empty_includes -32 -pointer-check -mm pso - -all: - for i in ./*.pass; do \ - echo $$i ; \ - CBMC_FLAGS="$(CBMC_FLAGS)" sh ../test_script.sh --should-pass $$i > $$i.out 2>&1 ; \ - done - for i in ./*.fail; do \ - echo $$i ; \ - CBMC_FLAGS="$(CBMC_FLAGS)" sh ../test_script.sh --should-fail $$i > $$i.out 2>&1 ; \ - done diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/assert_end.fail b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/assert_end.fail deleted file mode 100644 index 40c8075919d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/assert_end.fail +++ /dev/null @@ -1 +0,0 @@ -test_cbmc_options="-DASSERT_END" diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force.fail b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force.fail deleted file mode 100644 index ada5baf0b60d..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force.fail +++ /dev/null @@ -1 +0,0 @@ -test_cbmc_options="-DFORCE_FAILURE" diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force2.fail b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force2.fail deleted file mode 100644 index 8fe00c8db466..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force2.fail +++ /dev/null @@ -1 +0,0 @@ -test_cbmc_options="-DFORCE_FAILURE_2" diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force3.fail b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force3.fail deleted file mode 100644 index 612ed6772844..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force3.fail +++ /dev/null @@ -1 +0,0 @@ -test_cbmc_options="-DFORCE_FAILURE_3" diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/main.pass b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/main.pass deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/main.pass +++ /dev/null diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/test.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/test.c deleted file mode 100644 index 2ce2016f7871..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/test.c +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <src/combined_source.c> - -int x; -int y; - -int __unbuffered_tpr_x; -int __unbuffered_tpr_y; - -DEFINE_SRCU(ss); - -void rcu_reader(void) -{ - int idx; - -#ifndef FORCE_FAILURE_3 - idx = srcu_read_lock(&ss); -#endif - might_sleep(); - - __unbuffered_tpr_y = READ_ONCE(y); -#ifdef FORCE_FAILURE - srcu_read_unlock(&ss, idx); - idx = srcu_read_lock(&ss); -#endif - WRITE_ONCE(x, 1); - -#ifndef FORCE_FAILURE_3 - srcu_read_unlock(&ss, idx); -#endif - might_sleep(); -} - -void *thread_update(void *arg) -{ - WRITE_ONCE(y, 1); -#ifndef FORCE_FAILURE_2 - synchronize_srcu(&ss); -#endif - might_sleep(); - __unbuffered_tpr_x = READ_ONCE(x); - - return NULL; -} - -void *thread_process_reader(void *arg) -{ - rcu_reader(); - - return NULL; -} - -int main(int argc, char *argv[]) -{ - pthread_t tu; - pthread_t tpr; - - if (pthread_create(&tu, NULL, thread_update, NULL)) - abort(); - if (pthread_create(&tpr, NULL, thread_process_reader, NULL)) - abort(); - if (pthread_join(tu, NULL)) - abort(); - if (pthread_join(tpr, NULL)) - abort(); - assert(__unbuffered_tpr_y != 0 || __unbuffered_tpr_x != 0); - -#ifdef ASSERT_END - assert(0); -#endif - - return 0; -} diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/test_script.sh b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/test_script.sh deleted file mode 100755 index 2fe1f0339b4f..000000000000 --- a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/test_script.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 - -# This script expects a mode (either --should-pass or --should-fail) followed by -# an input file. The script uses the following environment variables. The test C -# source file is expected to be named test.c in the directory containing the -# input file. -# -# CBMC: The command to run CBMC. Default: cbmc -# CBMC_FLAGS: Additional flags to pass to CBMC -# NR_CPUS: Number of cpus to run tests with. Default specified by the test -# SYNC_SRCU_MODE: Choose implementation of synchronize_srcu. Defaults to simple. -# kernel: Version included in the linux kernel source. -# simple: Use try_check_zero directly. -# -# The input file is a script that is sourced by this file. It can define any of -# the following variables to configure the test. -# -# test_cbmc_options: Extra options to pass to CBMC. -# min_cpus_fail: Minimum number of CPUs (NR_CPUS) for verification to fail. -# The test is expected to pass if it is run with fewer. (Only -# useful for .fail files) -# default_cpus: Quantity of CPUs to use for the test, if not specified on the -# command line. Default: Larger of 2 and MIN_CPUS_FAIL. - -set -e - -if test "$#" -ne 2; then - echo "Expected one option followed by an input file" 1>&2 - exit 99 -fi - -if test "x$1" = "x--should-pass"; then - should_pass="yes" -elif test "x$1" = "x--should-fail"; then - should_pass="no" -else - echo "Unrecognized argument '$1'" 1>&2 - - # Exit code 99 indicates a hard error. - exit 99 -fi - -CBMC=${CBMC:-cbmc} - -SYNC_SRCU_MODE=${SYNC_SRCU_MODE:-simple} - -case ${SYNC_SRCU_MODE} in -kernel) sync_srcu_mode_flags="" ;; -simple) sync_srcu_mode_flags="-DUSE_SIMPLE_SYNC_SRCU" ;; - -*) - echo "Unrecognized argument '${SYNC_SRCU_MODE}'" 1>&2 - exit 99 - ;; -esac - -min_cpus_fail=1 - -c_file=`dirname "$2"`/test.c - -# Source the input file. -. $2 - -if test ${min_cpus_fail} -gt 2; then - default_default_cpus=${min_cpus_fail} -else - default_default_cpus=2 -fi -default_cpus=${default_cpus:-${default_default_cpus}} -cpus=${NR_CPUS:-${default_cpus}} - -# Check if there are two few cpus to make the test fail. -if test $cpus -lt ${min_cpus_fail:-0}; then - should_pass="yes" -fi - -cbmc_opts="-DNR_CPUS=${cpus} ${sync_srcu_mode_flags} ${test_cbmc_options} ${CBMC_FLAGS}" - -echo "Running CBMC: ${CBMC} ${cbmc_opts} ${c_file}" -if ${CBMC} ${cbmc_opts} "${c_file}"; then - # Verification successful. Make sure that it was supposed to verify. - test "x${should_pass}" = xyes -else - cbmc_exit_status=$? - - # An exit status of 10 indicates a failed verification. - # (see cbmc_parse_optionst::do_bmc in the CBMC source code) - if test ${cbmc_exit_status} -eq 10 && test "x${should_pass}" = xno; then - : - else - echo "CBMC returned ${cbmc_exit_status} exit status" 1>&2 - - # Parse errors have exit status 6. Any other type of error - # should be considered a hard error. - if test ${cbmc_exit_status} -ne 6 && \ - test ${cbmc_exit_status} -ne 10; then - exit 99 - else - exit 1 - fi - fi -fi diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile index 73d53257df42..5073dbc96125 100644 --- a/tools/testing/selftests/resctrl/Makefile +++ b/tools/testing/selftests/resctrl/Makefile @@ -7,4 +7,4 @@ TEST_GEN_PROGS := resctrl_tests include ../lib.mk -$(OUTPUT)/resctrl_tests: $(wildcard *.c) +$(OUTPUT)/resctrl_tests: $(wildcard *.[ch]) diff --git a/tools/testing/selftests/resctrl/cache.c b/tools/testing/selftests/resctrl/cache.c index 8a4fe8693be6..d3cbb829ff6a 100644 --- a/tools/testing/selftests/resctrl/cache.c +++ b/tools/testing/selftests/resctrl/cache.c @@ -87,21 +87,19 @@ static int reset_enable_llc_perf(pid_t pid, int cpu_no) static int get_llc_perf(unsigned long *llc_perf_miss) { __u64 total_misses; + int ret; /* Stop counters after one span to get miss rate */ ioctl(fd_lm, PERF_EVENT_IOC_DISABLE, 0); - if (read(fd_lm, &rf_cqm, sizeof(struct read_format)) == -1) { + ret = read(fd_lm, &rf_cqm, sizeof(struct read_format)); + if (ret == -1) { perror("Could not get llc misses through perf"); - return -1; } total_misses = rf_cqm.values[0].value; - - close(fd_lm); - *llc_perf_miss = total_misses; return 0; @@ -212,7 +210,7 @@ int measure_cache_vals(struct resctrl_val_param *param, int bm_pid) */ int cat_val(struct resctrl_val_param *param) { - int malloc_and_init_memory = 1, memflush = 1, operation = 0, ret = 0; + int memflush = 1, operation = 0, ret = 0; char *resctrl_val = param->resctrl_val; pid_t bm_pid; @@ -232,40 +230,38 @@ int cat_val(struct resctrl_val_param *param) if (ret) return ret; - if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR))) - initialize_llc_perf(); + initialize_llc_perf(); /* Test runs until the callback setup() tells the test to stop. */ while (1) { - if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR))) { - ret = param->setup(1, param); - if (ret == END_OF_TESTS) { - ret = 0; - break; - } - if (ret < 0) - break; - ret = reset_enable_llc_perf(bm_pid, param->cpu_no); - if (ret) - break; - - if (run_fill_buf(param->span, malloc_and_init_memory, - memflush, operation, resctrl_val)) { - fprintf(stderr, "Error-running fill buffer\n"); - ret = -1; - break; - } - - sleep(1); - ret = measure_cache_vals(param, bm_pid); - if (ret) - break; - } else { + ret = param->setup(param); + if (ret == END_OF_TESTS) { + ret = 0; + break; + } + if (ret < 0) + break; + ret = reset_enable_llc_perf(bm_pid, param->cpu_no); + if (ret) break; + + if (run_fill_buf(param->span, memflush, operation, true)) { + fprintf(stderr, "Error-running fill buffer\n"); + ret = -1; + goto pe_close; } + + sleep(1); + ret = measure_cache_vals(param, bm_pid); + if (ret) + goto pe_close; } return ret; + +pe_close: + close(fd_lm); + return ret; } /* @@ -282,7 +278,7 @@ int cat_val(struct resctrl_val_param *param) * Return: 0 on success. non-zero on failure. */ int show_cache_info(unsigned long sum_llc_val, int no_of_bits, - unsigned long cache_span, unsigned long max_diff, + size_t cache_span, unsigned long max_diff, unsigned long max_diff_percent, unsigned long num_of_runs, bool platform, bool cmt) { @@ -291,7 +287,7 @@ int show_cache_info(unsigned long sum_llc_val, int no_of_bits, long avg_diff = 0; int ret; - avg_llc_val = sum_llc_val / (num_of_runs - 1); + avg_llc_val = sum_llc_val / num_of_runs; avg_diff = (long)abs(cache_span - avg_llc_val); diff_percent = ((float)cache_span - avg_llc_val) / cache_span * 100; @@ -304,7 +300,7 @@ int show_cache_info(unsigned long sum_llc_val, int no_of_bits, ksft_print_msg("Percent diff=%d\n", abs((int)diff_percent)); ksft_print_msg("Number of bits: %d\n", no_of_bits); ksft_print_msg("Average LLC val: %lu\n", avg_llc_val); - ksft_print_msg("Cache span (%s): %lu\n", cmt ? "bytes" : "lines", + ksft_print_msg("Cache span (%s): %zu\n", cmt ? "bytes" : "lines", cache_span); return ret; diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c index fb1443f888c4..3848dfb46aba 100644 --- a/tools/testing/selftests/resctrl/cat_test.c +++ b/tools/testing/selftests/resctrl/cat_test.c @@ -17,27 +17,16 @@ #define MAX_DIFF_PERCENT 4 #define MAX_DIFF 1000000 -static int count_of_bits; -static char cbm_mask[256]; -static unsigned long long_mask; -static unsigned long cache_size; - /* * Change schemata. Write schemata to specified * con_mon grp, mon_grp in resctrl FS. * Run 5 times in order to get average values. */ -static int cat_setup(int num, ...) +static int cat_setup(struct resctrl_val_param *p) { - struct resctrl_val_param *p; char schemata[64]; - va_list param; int ret = 0; - va_start(param, num); - p = va_arg(param, struct resctrl_val_param *); - va_end(param); - /* Run NUM_OF_RUNS times */ if (p->num_of_runs >= NUM_OF_RUNS) return END_OF_TESTS; @@ -88,7 +77,7 @@ static int check_results(struct resctrl_val_param *param) no_of_bits = count_bits(param->mask); return show_cache_info(sum_llc_perf_miss, no_of_bits, param->span / 64, - MAX_DIFF, MAX_DIFF_PERCENT, NUM_OF_RUNS, + MAX_DIFF, MAX_DIFF_PERCENT, runs - 1, get_vendor() == ARCH_INTEL, false); } @@ -102,14 +91,12 @@ int cat_perf_miss_val(int cpu_no, int n, char *cache_type) { unsigned long l_mask, l_mask_1; int ret, pipefd[2], sibling_cpu_no; + unsigned long cache_size = 0; + unsigned long long_mask; + char cbm_mask[256]; + int count_of_bits; char pipe_message; - cache_size = 0; - - ret = remount_resctrlfs(true); - if (ret) - return ret; - /* Get default cbm mask for L3/L2 cache */ ret = get_cbm_mask(cache_type, cbm_mask); if (ret) @@ -144,7 +131,6 @@ int cat_perf_miss_val(int cpu_no, int n, char *cache_type) struct resctrl_val_param param = { .resctrl_val = CAT_STR, .cpu_no = cpu_no, - .mum_resctrlfs = false, .setup = cat_setup, }; @@ -227,8 +213,6 @@ int cat_perf_miss_val(int cpu_no, int n, char *cache_type) out: cat_test_cleanup(); - if (bm_pid) - umount_resctrlfs(); return ret; } diff --git a/tools/testing/selftests/resctrl/cmt_test.c b/tools/testing/selftests/resctrl/cmt_test.c index af71b2141271..cb2197647c6c 100644 --- a/tools/testing/selftests/resctrl/cmt_test.c +++ b/tools/testing/selftests/resctrl/cmt_test.c @@ -16,20 +16,8 @@ #define MAX_DIFF 2000000 #define MAX_DIFF_PERCENT 15 -static int count_of_bits; -static char cbm_mask[256]; -static unsigned long long_mask; -static unsigned long cache_size; - -static int cmt_setup(int num, ...) +static int cmt_setup(struct resctrl_val_param *p) { - struct resctrl_val_param *p; - va_list param; - - va_start(param, num); - p = va_arg(param, struct resctrl_val_param *); - va_end(param); - /* Run NUM_OF_RUNS times */ if (p->num_of_runs >= NUM_OF_RUNS) return END_OF_TESTS; @@ -71,7 +59,7 @@ static int check_results(struct resctrl_val_param *param, int no_of_bits) fclose(fp); return show_cache_info(sum_llc_occu_resc, no_of_bits, param->span, - MAX_DIFF, MAX_DIFF_PERCENT, NUM_OF_RUNS, + MAX_DIFF, MAX_DIFF_PERCENT, runs - 1, true, true); } @@ -82,14 +70,12 @@ void cmt_test_cleanup(void) int cmt_resctrl_val(int cpu_no, int n, char **benchmark_cmd) { + unsigned long cache_size = 0; + unsigned long long_mask; + char cbm_mask[256]; + int count_of_bits; int ret; - cache_size = 0; - - ret = remount_resctrlfs(true); - if (ret) - return ret; - if (!validate_resctrl_feature_request(CMT_STR)) return -1; @@ -117,7 +103,6 @@ int cmt_resctrl_val(int cpu_no, int n, char **benchmark_cmd) .ctrlgrp = "c1", .mongrp = "m1", .cpu_no = cpu_no, - .mum_resctrlfs = false, .filename = RESULT_FILE_NAME, .mask = ~(long_mask << n) & long_mask, .span = cache_size * n / count_of_bits, @@ -126,7 +111,7 @@ int cmt_resctrl_val(int cpu_no, int n, char **benchmark_cmd) }; if (strcmp(benchmark_cmd[0], "fill_buf") == 0) - sprintf(benchmark_cmd[1], "%lu", param.span); + sprintf(benchmark_cmd[1], "%zu", param.span); remove(RESULT_FILE_NAME); diff --git a/tools/testing/selftests/resctrl/fill_buf.c b/tools/testing/selftests/resctrl/fill_buf.c index 341cc93ca84c..0d425f26583a 100644 --- a/tools/testing/selftests/resctrl/fill_buf.c +++ b/tools/testing/selftests/resctrl/fill_buf.c @@ -22,8 +22,6 @@ #define PAGE_SIZE (4 * 1024) #define MB (1024 * 1024) -static unsigned char *startptr; - static void sb(void) { #if defined(__i386) || defined(__x86_64) @@ -40,32 +38,32 @@ static void cl_flush(void *p) #endif } -static void mem_flush(void *p, size_t s) +static void mem_flush(unsigned char *buf, size_t buf_size) { - char *cp = (char *)p; + unsigned char *cp = buf; size_t i = 0; - s = s / CL_SIZE; /* mem size in cache llines */ + buf_size = buf_size / CL_SIZE; /* mem size in cache lines */ - for (i = 0; i < s; i++) + for (i = 0; i < buf_size; i++) cl_flush(&cp[i * CL_SIZE]); sb(); } -static void *malloc_and_init_memory(size_t s) +static void *malloc_and_init_memory(size_t buf_size) { void *p = NULL; uint64_t *p64; size_t s64; int ret; - ret = posix_memalign(&p, PAGE_SIZE, s); + ret = posix_memalign(&p, PAGE_SIZE, buf_size); if (ret < 0) return NULL; p64 = (uint64_t *)p; - s64 = s / sizeof(uint64_t); + s64 = buf_size / sizeof(uint64_t); while (s64 > 0) { *p64 = (uint64_t)rand(); @@ -76,12 +74,13 @@ static void *malloc_and_init_memory(size_t s) return p; } -static int fill_one_span_read(unsigned char *start_ptr, unsigned char *end_ptr) +static int fill_one_span_read(unsigned char *buf, size_t buf_size) { + unsigned char *end_ptr = buf + buf_size; unsigned char sum, *p; sum = 0; - p = start_ptr; + p = buf; while (p < end_ptr) { sum += *p; p += (CL_SIZE / 2); @@ -90,27 +89,26 @@ static int fill_one_span_read(unsigned char *start_ptr, unsigned char *end_ptr) return sum; } -static -void fill_one_span_write(unsigned char *start_ptr, unsigned char *end_ptr) +static void fill_one_span_write(unsigned char *buf, size_t buf_size) { + unsigned char *end_ptr = buf + buf_size; unsigned char *p; - p = start_ptr; + p = buf; while (p < end_ptr) { *p = '1'; p += (CL_SIZE / 2); } } -static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr, - char *resctrl_val) +static int fill_cache_read(unsigned char *buf, size_t buf_size, bool once) { int ret = 0; FILE *fp; while (1) { - ret = fill_one_span_read(start_ptr, end_ptr); - if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR))) + ret = fill_one_span_read(buf, buf_size); + if (once) break; } @@ -126,75 +124,52 @@ static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr, return 0; } -static int fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr, - char *resctrl_val) +static int fill_cache_write(unsigned char *buf, size_t buf_size, bool once) { while (1) { - fill_one_span_write(start_ptr, end_ptr); - if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR))) + fill_one_span_write(buf, buf_size); + if (once) break; } return 0; } -static int -fill_cache(unsigned long long buf_size, int malloc_and_init, int memflush, - int op, char *resctrl_val) +static int fill_cache(size_t buf_size, int memflush, int op, bool once) { - unsigned char *start_ptr, *end_ptr; - unsigned long long i; + unsigned char *buf; int ret; - if (malloc_and_init) - start_ptr = malloc_and_init_memory(buf_size); - else - start_ptr = malloc(buf_size); - - if (!start_ptr) + buf = malloc_and_init_memory(buf_size); + if (!buf) return -1; - startptr = start_ptr; - end_ptr = start_ptr + buf_size; - - /* - * It's better to touch the memory once to avoid any compiler - * optimizations - */ - if (!malloc_and_init) { - for (i = 0; i < buf_size; i++) - *start_ptr++ = (unsigned char)rand(); - } - - start_ptr = startptr; - /* Flush the memory before using to avoid "cache hot pages" effect */ if (memflush) - mem_flush(start_ptr, buf_size); + mem_flush(buf, buf_size); if (op == 0) - ret = fill_cache_read(start_ptr, end_ptr, resctrl_val); + ret = fill_cache_read(buf, buf_size, once); else - ret = fill_cache_write(start_ptr, end_ptr, resctrl_val); + ret = fill_cache_write(buf, buf_size, once); + + free(buf); if (ret) { printf("\n Error in fill cache read/write...\n"); return -1; } - free(startptr); return 0; } -int run_fill_buf(unsigned long span, int malloc_and_init_memory, - int memflush, int op, char *resctrl_val) +int run_fill_buf(size_t span, int memflush, int op, bool once) { - unsigned long long cache_size = span; + size_t cache_size = span; int ret; - ret = fill_cache(cache_size, malloc_and_init_memory, memflush, op, - resctrl_val); + ret = fill_cache(cache_size, memflush, op, once); if (ret) { printf("\n Error in fill cache\n"); return -1; diff --git a/tools/testing/selftests/resctrl/mba_test.c b/tools/testing/selftests/resctrl/mba_test.c index cde3781a9ab0..4d2f145804b8 100644 --- a/tools/testing/selftests/resctrl/mba_test.c +++ b/tools/testing/selftests/resctrl/mba_test.c @@ -22,18 +22,12 @@ * con_mon grp, mon_grp in resctrl FS. * For each allocation, run 5 times in order to get average values. */ -static int mba_setup(int num, ...) +static int mba_setup(struct resctrl_val_param *p) { static int runs_per_allocation, allocation = 100; - struct resctrl_val_param *p; char allocation_str[64]; - va_list param; int ret; - va_start(param, num); - p = va_arg(param, struct resctrl_val_param *); - va_end(param); - if (runs_per_allocation >= NUM_OF_RUNS) runs_per_allocation = 0; @@ -154,7 +148,6 @@ int mba_schemata_change(int cpu_no, char *bw_report, char **benchmark_cmd) .ctrlgrp = "c1", .mongrp = "m1", .cpu_no = cpu_no, - .mum_resctrlfs = true, .filename = RESULT_FILE_NAME, .bw_report = bw_report, .setup = mba_setup diff --git a/tools/testing/selftests/resctrl/mbm_test.c b/tools/testing/selftests/resctrl/mbm_test.c index 538d35a6485a..c7de6f5977f6 100644 --- a/tools/testing/selftests/resctrl/mbm_test.c +++ b/tools/testing/selftests/resctrl/mbm_test.c @@ -15,7 +15,7 @@ #define NUM_OF_RUNS 5 static int -show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, int span) +show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, size_t span) { unsigned long avg_bw_imc = 0, avg_bw_resc = 0; unsigned long sum_bw_imc = 0, sum_bw_resc = 0; @@ -40,14 +40,14 @@ show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, int span) ksft_print_msg("%s Check MBM diff within %d%%\n", ret ? "Fail:" : "Pass:", MAX_DIFF_PERCENT); ksft_print_msg("avg_diff_per: %d%%\n", avg_diff_per); - ksft_print_msg("Span (MB): %d\n", span); + ksft_print_msg("Span (MB): %zu\n", span / MB); ksft_print_msg("avg_bw_imc: %lu\n", avg_bw_imc); ksft_print_msg("avg_bw_resc: %lu\n", avg_bw_resc); return ret; } -static int check_results(int span) +static int check_results(size_t span) { unsigned long bw_imc[NUM_OF_RUNS], bw_resc[NUM_OF_RUNS]; char temp[1024], *token_array[8]; @@ -86,16 +86,10 @@ static int check_results(int span) return ret; } -static int mbm_setup(int num, ...) +static int mbm_setup(struct resctrl_val_param *p) { - struct resctrl_val_param *p; - va_list param; int ret = 0; - va_start(param, num); - p = va_arg(param, struct resctrl_val_param *); - va_end(param); - /* Run NUM_OF_RUNS times */ if (p->num_of_runs >= NUM_OF_RUNS) return END_OF_TESTS; @@ -115,7 +109,7 @@ void mbm_test_cleanup(void) remove(RESULT_FILE_NAME); } -int mbm_bw_change(int span, int cpu_no, char *bw_report, char **benchmark_cmd) +int mbm_bw_change(size_t span, int cpu_no, char *bw_report, char **benchmark_cmd) { struct resctrl_val_param param = { .resctrl_val = MBM_STR, @@ -123,7 +117,6 @@ int mbm_bw_change(int span, int cpu_no, char *bw_report, char **benchmark_cmd) .mongrp = "m1", .span = span, .cpu_no = cpu_no, - .mum_resctrlfs = true, .filename = RESULT_FILE_NAME, .bw_report = bw_report, .setup = mbm_setup diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h index 87e39456dee0..838d1a438f33 100644 --- a/tools/testing/selftests/resctrl/resctrl.h +++ b/tools/testing/selftests/resctrl/resctrl.h @@ -3,7 +3,6 @@ #ifndef RESCTRL_H #define RESCTRL_H #include <stdio.h> -#include <stdarg.h> #include <math.h> #include <errno.h> #include <sched.h> @@ -43,6 +42,7 @@ do { \ perror(err_msg); \ kill(ppid, SIGKILL); \ + umount_resctrlfs(); \ exit(EXIT_FAILURE); \ } while (0) @@ -53,7 +53,6 @@ * @mongrp: Name of the monitor group (mon grp) * @cpu_no: CPU number to which the benchmark would be binded * @span: Memory bytes accessed in each benchmark iteration - * @mum_resctrlfs: Should the resctrl FS be remounted? * @filename: Name of file to which the o/p should be written * @bw_report: Bandwidth report type (reads vs writes) * @setup: Call back function to setup test environment @@ -63,13 +62,12 @@ struct resctrl_val_param { char ctrlgrp[64]; char mongrp[64]; int cpu_no; - unsigned long span; - bool mum_resctrlfs; + size_t span; char filename[64]; char *bw_report; unsigned long mask; int num_of_runs; - int (*setup)(int num, ...); + int (*setup)(struct resctrl_val_param *param); }; #define MBM_STR "mbm" @@ -84,8 +82,8 @@ extern char llc_occup_path[1024]; int get_vendor(void); bool check_resctrlfs_support(void); int filter_dmesg(void); -int remount_resctrlfs(bool mum_resctrlfs); int get_resource_id(int cpu_no, int *resource_id); +int mount_resctrlfs(void); int umount_resctrlfs(void); int validate_bw_report_request(char *bw_report); bool validate_resctrl_feature_request(const char *resctrl_val); @@ -98,10 +96,9 @@ int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp, char *resctrl_val); int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags); -int run_fill_buf(unsigned long span, int malloc_and_init_memory, int memflush, - int op, char *resctrl_va); +int run_fill_buf(size_t span, int memflush, int op, bool once); int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param); -int mbm_bw_change(int span, int cpu_no, char *bw_report, char **benchmark_cmd); +int mbm_bw_change(size_t span, int cpu_no, char *bw_report, char **benchmark_cmd); void tests_cleanup(void); void mbm_test_cleanup(void); int mba_schemata_change(int cpu_no, char *bw_report, char **benchmark_cmd); @@ -120,7 +117,7 @@ void cmt_test_cleanup(void); int get_core_sibling(int cpu_no); int measure_cache_vals(struct resctrl_val_param *param, int bm_pid); int show_cache_info(unsigned long sum_llc_val, int no_of_bits, - unsigned long cache_span, unsigned long max_diff, + size_t cache_span, unsigned long max_diff, unsigned long max_diff_percent, unsigned long num_of_runs, bool platform, bool cmt); diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c index 9b9751206e1c..d511daeb6851 100644 --- a/tools/testing/selftests/resctrl/resctrl_tests.c +++ b/tools/testing/selftests/resctrl/resctrl_tests.c @@ -70,60 +70,81 @@ void tests_cleanup(void) cat_test_cleanup(); } -static void run_mbm_test(bool has_ben, char **benchmark_cmd, int span, +static void run_mbm_test(char **benchmark_cmd, size_t span, int cpu_no, char *bw_report) { int res; ksft_print_msg("Starting MBM BW change ...\n"); + res = mount_resctrlfs(); + if (res) { + ksft_exit_fail_msg("Failed to mount resctrl FS\n"); + return; + } + if (!validate_resctrl_feature_request(MBM_STR) || (get_vendor() != ARCH_INTEL)) { ksft_test_result_skip("Hardware does not support MBM or MBM is disabled\n"); - return; + goto umount; } - if (!has_ben) - sprintf(benchmark_cmd[5], "%s", MBA_STR); res = mbm_bw_change(span, cpu_no, bw_report, benchmark_cmd); ksft_test_result(!res, "MBM: bw change\n"); if ((get_vendor() == ARCH_INTEL) && res) ksft_print_msg("Intel MBM may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n"); + +umount: + umount_resctrlfs(); } -static void run_mba_test(bool has_ben, char **benchmark_cmd, int span, - int cpu_no, char *bw_report) +static void run_mba_test(char **benchmark_cmd, int cpu_no, char *bw_report) { int res; ksft_print_msg("Starting MBA Schemata change ...\n"); + res = mount_resctrlfs(); + if (res) { + ksft_exit_fail_msg("Failed to mount resctrl FS\n"); + return; + } + if (!validate_resctrl_feature_request(MBA_STR) || (get_vendor() != ARCH_INTEL)) { ksft_test_result_skip("Hardware does not support MBA or MBA is disabled\n"); - return; + goto umount; } - if (!has_ben) - sprintf(benchmark_cmd[1], "%d", span); res = mba_schemata_change(cpu_no, bw_report, benchmark_cmd); ksft_test_result(!res, "MBA: schemata change\n"); + +umount: + umount_resctrlfs(); } -static void run_cmt_test(bool has_ben, char **benchmark_cmd, int cpu_no) +static void run_cmt_test(char **benchmark_cmd, int cpu_no) { int res; ksft_print_msg("Starting CMT test ...\n"); + + res = mount_resctrlfs(); + if (res) { + ksft_exit_fail_msg("Failed to mount resctrl FS\n"); + return; + } + if (!validate_resctrl_feature_request(CMT_STR)) { ksft_test_result_skip("Hardware does not support CMT or CMT is disabled\n"); - return; + goto umount; } - if (!has_ben) - sprintf(benchmark_cmd[5], "%s", CMT_STR); res = cmt_resctrl_val(cpu_no, 5, benchmark_cmd); ksft_test_result(!res, "CMT: test\n"); if ((get_vendor() == ARCH_INTEL) && res) ksft_print_msg("Intel CMT may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n"); + +umount: + umount_resctrlfs(); } static void run_cat_test(int cpu_no, int no_of_bits) @@ -132,22 +153,32 @@ static void run_cat_test(int cpu_no, int no_of_bits) ksft_print_msg("Starting CAT test ...\n"); + res = mount_resctrlfs(); + if (res) { + ksft_exit_fail_msg("Failed to mount resctrl FS\n"); + return; + } + if (!validate_resctrl_feature_request(CAT_STR)) { ksft_test_result_skip("Hardware does not support CAT or CAT is disabled\n"); - return; + goto umount; } res = cat_perf_miss_val(cpu_no, no_of_bits, "L3"); ksft_test_result(!res, "CAT: test\n"); + +umount: + umount_resctrlfs(); } int main(int argc, char **argv) { bool has_ben = false, mbm_test = true, mba_test = true, cmt_test = true; - int c, cpu_no = 1, span = 250, argc_new = argc, i, no_of_bits = 0; char *benchmark_cmd[BENCHMARK_ARGS], bw_report[64], bm_type[64]; char benchmark_cmd_area[BENCHMARK_ARGS][BENCHMARK_ARG_SIZE]; + int c, cpu_no = 1, argc_new = argc, i, no_of_bits = 0; int ben_ind, ben_count, tests = 0; + size_t span = 250 * MB; bool cat_test = true; for (i = 0; i < argc; i++) { @@ -232,16 +263,15 @@ int main(int argc, char **argv) benchmark_cmd[ben_count] = NULL; } else { /* If no benchmark is given by "-b" argument, use fill_buf. */ - for (i = 0; i < 6; i++) + for (i = 0; i < 5; i++) benchmark_cmd[i] = benchmark_cmd_area[i]; strcpy(benchmark_cmd[0], "fill_buf"); - sprintf(benchmark_cmd[1], "%d", span); + sprintf(benchmark_cmd[1], "%zu", span); strcpy(benchmark_cmd[2], "1"); - strcpy(benchmark_cmd[3], "1"); - strcpy(benchmark_cmd[4], "0"); - strcpy(benchmark_cmd[5], ""); - benchmark_cmd[6] = NULL; + strcpy(benchmark_cmd[3], "0"); + strcpy(benchmark_cmd[4], "false"); + benchmark_cmd[5] = NULL; } sprintf(bw_report, "reads"); @@ -250,23 +280,24 @@ int main(int argc, char **argv) if (!check_resctrlfs_support()) return ksft_exit_skip("resctrl FS does not exist. Enable X86_CPU_RESCTRL config option.\n"); + if (umount_resctrlfs()) + return ksft_exit_skip("resctrl FS unmount failed.\n"); + filter_dmesg(); ksft_set_plan(tests ? : 4); if (mbm_test) - run_mbm_test(has_ben, benchmark_cmd, span, cpu_no, bw_report); + run_mbm_test(benchmark_cmd, span, cpu_no, bw_report); if (mba_test) - run_mba_test(has_ben, benchmark_cmd, span, cpu_no, bw_report); + run_mba_test(benchmark_cmd, cpu_no, bw_report); if (cmt_test) - run_cmt_test(has_ben, benchmark_cmd, cpu_no); + run_cmt_test(benchmark_cmd, cpu_no); if (cat_test) run_cat_test(cpu_no, no_of_bits); - umount_resctrlfs(); - ksft_finished(); } diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c index ab1eab1e7ff6..f0f6c5f6e98b 100644 --- a/tools/testing/selftests/resctrl/resctrl_val.c +++ b/tools/testing/selftests/resctrl/resctrl_val.c @@ -648,10 +648,6 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param) return ret; } - ret = remount_resctrlfs(param->mum_resctrlfs); - if (ret) - return ret; - /* * If benchmark wasn't successfully started by child, then child should * kill parent, so save parent's pid @@ -763,7 +759,7 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param) /* Test runs until the callback setup() tells the test to stop. */ while (1) { - ret = param->setup(1, param); + ret = param->setup(param); if (ret == END_OF_TESTS) { ret = 0; break; @@ -788,7 +784,6 @@ unregister: signal_handler_unregister(); out: kill(bm_pid, SIGKILL); - umount_resctrlfs(); return ret; } diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c index fb00245dee92..bd36ee206602 100644 --- a/tools/testing/selftests/resctrl/resctrlfs.c +++ b/tools/testing/selftests/resctrl/resctrlfs.c @@ -48,29 +48,20 @@ static int find_resctrl_mount(char *buffer) } /* - * remount_resctrlfs - Remount resctrl FS at /sys/fs/resctrl - * @mum_resctrlfs: Should the resctrl FS be remounted? + * mount_resctrlfs - Mount resctrl FS at /sys/fs/resctrl * - * If not mounted, mount it. - * If mounted and mum_resctrlfs then remount resctrl FS. - * If mounted and !mum_resctrlfs then noop + * Mounts resctrl FS. Fails if resctrl FS is already mounted to avoid + * pre-existing settings interfering with the test results. * * Return: 0 on success, non-zero on failure */ -int remount_resctrlfs(bool mum_resctrlfs) +int mount_resctrlfs(void) { - char mountpoint[256]; int ret; - ret = find_resctrl_mount(mountpoint); - if (ret) - strcpy(mountpoint, RESCTRL_PATH); - - if (!ret && mum_resctrlfs && umount(mountpoint)) - ksft_print_msg("Fail: unmounting \"%s\"\n", mountpoint); - - if (!ret && !mum_resctrlfs) - return 0; + ret = find_resctrl_mount(NULL); + if (ret != -ENOENT) + return -1; ksft_print_msg("Mounting resctrl to \"%s\"\n", RESCTRL_PATH); ret = mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL); @@ -82,10 +73,16 @@ int remount_resctrlfs(bool mum_resctrlfs) int umount_resctrlfs(void) { - if (find_resctrl_mount(NULL)) + char mountpoint[256]; + int ret; + + ret = find_resctrl_mount(mountpoint); + if (ret == -ENOENT) return 0; + if (ret) + return ret; - if (umount(RESCTRL_PATH)) { + if (umount(mountpoint)) { perror("# Unable to umount resctrl"); return errno; @@ -305,10 +302,10 @@ int taskset_benchmark(pid_t bm_pid, int cpu_no) */ void run_benchmark(int signum, siginfo_t *info, void *ucontext) { - int operation, ret, malloc_and_init_memory, memflush; - unsigned long span, buffer_span; + int operation, ret, memflush; char **benchmark_cmd; - char resctrl_val[64]; + size_t span; + bool once; FILE *fp; benchmark_cmd = info->si_ptr; @@ -324,18 +321,16 @@ void run_benchmark(int signum, siginfo_t *info, void *ucontext) if (strcmp(benchmark_cmd[0], "fill_buf") == 0) { /* Execute default fill_buf benchmark */ span = strtoul(benchmark_cmd[1], NULL, 10); - malloc_and_init_memory = atoi(benchmark_cmd[2]); - memflush = atoi(benchmark_cmd[3]); - operation = atoi(benchmark_cmd[4]); - sprintf(resctrl_val, "%s", benchmark_cmd[5]); - - if (strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) - buffer_span = span * MB; + memflush = atoi(benchmark_cmd[2]); + operation = atoi(benchmark_cmd[3]); + if (!strcmp(benchmark_cmd[4], "true")) + once = true; + else if (!strcmp(benchmark_cmd[4], "false")) + once = false; else - buffer_span = span; + PARENT_EXIT("Invalid once parameter"); - if (run_fill_buf(buffer_span, malloc_and_init_memory, memflush, - operation, resctrl_val)) + if (run_fill_buf(span, memflush, operation, once)) fprintf(stderr, "Error in running fill buffer\n"); } else { /* Execute specified benchmark */ @@ -611,7 +606,8 @@ char *fgrep(FILE *inf, const char *str) * validate_resctrl_feature_request - Check if requested feature is valid. * @resctrl_val: Requested feature * - * Return: True if the feature is supported, else false + * Return: True if the feature is supported, else false. False is also + * returned if resctrl FS is not mounted. */ bool validate_resctrl_feature_request(const char *resctrl_val) { @@ -619,11 +615,13 @@ bool validate_resctrl_feature_request(const char *resctrl_val) bool found = false; char *res; FILE *inf; + int ret; if (!resctrl_val) return false; - if (remount_resctrlfs(false)) + ret = find_resctrl_mount(NULL); + if (ret) return false; if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR))) { diff --git a/tools/testing/selftests/rseq/Makefile b/tools/testing/selftests/rseq/Makefile index 7a957c7d459a..5a3432fceb58 100644 --- a/tools/testing/selftests/rseq/Makefile +++ b/tools/testing/selftests/rseq/Makefile @@ -33,7 +33,7 @@ $(OUTPUT)/%: %.c $(TEST_GEN_PROGS_EXTENDED) rseq.h rseq-*.h $(CC) $(CFLAGS) $< $(LDLIBS) -lrseq -o $@ $(OUTPUT)/basic_percpu_ops_mm_cid_test: basic_percpu_ops_test.c $(TEST_GEN_PROGS_EXTENDED) rseq.h rseq-*.h - $(CC) $(CFLAGS) -DBUILDOPT_RSEQ_PERCPU_MM_CID_ID $< $(LDLIBS) -lrseq -o $@ + $(CC) $(CFLAGS) -DBUILDOPT_RSEQ_PERCPU_MM_CID $< $(LDLIBS) -lrseq -o $@ $(OUTPUT)/param_test_benchmark: param_test.c $(TEST_GEN_PROGS_EXTENDED) \ rseq.h rseq-*.h diff --git a/tools/testing/selftests/rseq/compiler.h b/tools/testing/selftests/rseq/compiler.h index f47092bddeba..49d62fbd6dda 100644 --- a/tools/testing/selftests/rseq/compiler.h +++ b/tools/testing/selftests/rseq/compiler.h @@ -33,4 +33,30 @@ #define RSEQ_COMBINE_TOKENS(_tokena, _tokenb) \ RSEQ__COMBINE_TOKENS(_tokena, _tokenb) +#ifdef __cplusplus +#define rseq_unqual_scalar_typeof(x) \ + std::remove_cv<std::remove_reference<decltype(x)>::type>::type +#else +#define rseq_scalar_type_to_expr(type) \ + unsigned type: (unsigned type)0, \ + signed type: (signed type)0 + +/* + * Use C11 _Generic to express unqualified type from expression. This removes + * volatile qualifier from expression type. + */ +#define rseq_unqual_scalar_typeof(x) \ + __typeof__( \ + _Generic((x), \ + char: (char)0, \ + rseq_scalar_type_to_expr(char), \ + rseq_scalar_type_to_expr(short), \ + rseq_scalar_type_to_expr(int), \ + rseq_scalar_type_to_expr(long), \ + rseq_scalar_type_to_expr(long long), \ + default: (x) \ + ) \ + ) +#endif + #endif /* RSEQ_COMPILER_H_ */ diff --git a/tools/testing/selftests/rseq/rseq-arm.h b/tools/testing/selftests/rseq/rseq-arm.h index 8414fc3eac15..d887b3bbe257 100644 --- a/tools/testing/selftests/rseq/rseq-arm.h +++ b/tools/testing/selftests/rseq/rseq-arm.h @@ -66,7 +66,7 @@ #define rseq_smp_load_acquire(p) \ __extension__ ({ \ - __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \ rseq_smp_mb(); \ ____p1; \ }) @@ -76,7 +76,7 @@ __extension__ ({ \ #define rseq_smp_store_release(p, v) \ do { \ rseq_smp_mb(); \ - RSEQ_WRITE_ONCE(*p, v); \ + RSEQ_WRITE_ONCE(*(p), v); \ } while (0) #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \ diff --git a/tools/testing/selftests/rseq/rseq-arm64.h b/tools/testing/selftests/rseq/rseq-arm64.h index 85b90977e7e6..21e1626a7235 100644 --- a/tools/testing/selftests/rseq/rseq-arm64.h +++ b/tools/testing/selftests/rseq/rseq-arm64.h @@ -27,59 +27,61 @@ #define rseq_smp_load_acquire(p) \ __extension__ ({ \ - __typeof(*p) ____p1; \ - switch (sizeof(*p)) { \ + union { rseq_unqual_scalar_typeof(*(p)) __val; char __c[sizeof(*(p))]; } __u; \ + switch (sizeof(*(p))) { \ case 1: \ - asm volatile ("ldarb %w0, %1" \ - : "=r" (*(__u8 *)p) \ - : "Q" (*p) : "memory"); \ + __asm__ __volatile__ ("ldarb %w0, %1" \ + : "=r" (*(__u8 *)__u.__c) \ + : "Q" (*(p)) : "memory"); \ break; \ case 2: \ - asm volatile ("ldarh %w0, %1" \ - : "=r" (*(__u16 *)p) \ - : "Q" (*p) : "memory"); \ + __asm__ __volatile__ ("ldarh %w0, %1" \ + : "=r" (*(__u16 *)__u.__c) \ + : "Q" (*(p)) : "memory"); \ break; \ case 4: \ - asm volatile ("ldar %w0, %1" \ - : "=r" (*(__u32 *)p) \ - : "Q" (*p) : "memory"); \ + __asm__ __volatile__ ("ldar %w0, %1" \ + : "=r" (*(__u32 *)__u.__c) \ + : "Q" (*(p)) : "memory"); \ break; \ case 8: \ - asm volatile ("ldar %0, %1" \ - : "=r" (*(__u64 *)p) \ - : "Q" (*p) : "memory"); \ + __asm__ __volatile__ ("ldar %0, %1" \ + : "=r" (*(__u64 *)__u.__c) \ + : "Q" (*(p)) : "memory"); \ break; \ } \ - ____p1; \ + (rseq_unqual_scalar_typeof(*(p)))__u.__val; \ }) #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb() #define rseq_smp_store_release(p, v) \ do { \ - switch (sizeof(*p)) { \ + union { rseq_unqual_scalar_typeof(*(p)) __val; char __c[sizeof(*(p))]; } __u = \ + { .__val = (rseq_unqual_scalar_typeof(*(p))) (v) }; \ + switch (sizeof(*(p))) { \ case 1: \ - asm volatile ("stlrb %w1, %0" \ - : "=Q" (*p) \ - : "r" ((__u8)v) \ + __asm__ __volatile__ ("stlrb %w1, %0" \ + : "=Q" (*(p)) \ + : "r" (*(__u8 *)__u.__c) \ : "memory"); \ break; \ case 2: \ - asm volatile ("stlrh %w1, %0" \ - : "=Q" (*p) \ - : "r" ((__u16)v) \ + __asm__ __volatile__ ("stlrh %w1, %0" \ + : "=Q" (*(p)) \ + : "r" (*(__u16 *)__u.__c) \ : "memory"); \ break; \ case 4: \ - asm volatile ("stlr %w1, %0" \ - : "=Q" (*p) \ - : "r" ((__u32)v) \ + __asm__ __volatile__ ("stlr %w1, %0" \ + : "=Q" (*(p)) \ + : "r" (*(__u32 *)__u.__c) \ : "memory"); \ break; \ case 8: \ - asm volatile ("stlr %1, %0" \ - : "=Q" (*p) \ - : "r" ((__u64)v) \ + __asm__ __volatile__ ("stlr %1, %0" \ + : "=Q" (*(p)) \ + : "r" (*(__u64 *)__u.__c) \ : "memory"); \ break; \ } \ diff --git a/tools/testing/selftests/rseq/rseq-mips.h b/tools/testing/selftests/rseq/rseq-mips.h index 50b950cf9585..42ef8e946693 100644 --- a/tools/testing/selftests/rseq/rseq-mips.h +++ b/tools/testing/selftests/rseq/rseq-mips.h @@ -45,7 +45,7 @@ #define rseq_smp_load_acquire(p) \ __extension__ ({ \ - __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \ rseq_smp_mb(); \ ____p1; \ }) @@ -55,7 +55,7 @@ __extension__ ({ \ #define rseq_smp_store_release(p, v) \ do { \ rseq_smp_mb(); \ - RSEQ_WRITE_ONCE(*p, v); \ + RSEQ_WRITE_ONCE(*(p), v); \ } while (0) #if _MIPS_SZLONG == 64 diff --git a/tools/testing/selftests/rseq/rseq-ppc.h b/tools/testing/selftests/rseq/rseq-ppc.h index dc9190facee9..57b160597189 100644 --- a/tools/testing/selftests/rseq/rseq-ppc.h +++ b/tools/testing/selftests/rseq/rseq-ppc.h @@ -23,7 +23,7 @@ #define rseq_smp_load_acquire(p) \ __extension__ ({ \ - __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \ rseq_smp_lwsync(); \ ____p1; \ }) @@ -33,7 +33,7 @@ __extension__ ({ \ #define rseq_smp_store_release(p, v) \ do { \ rseq_smp_lwsync(); \ - RSEQ_WRITE_ONCE(*p, v); \ + RSEQ_WRITE_ONCE(*(p), v); \ } while (0) /* diff --git a/tools/testing/selftests/rseq/rseq-riscv.h b/tools/testing/selftests/rseq/rseq-riscv.h index 17932a79e066..37e598d0a365 100644 --- a/tools/testing/selftests/rseq/rseq-riscv.h +++ b/tools/testing/selftests/rseq/rseq-riscv.h @@ -36,8 +36,8 @@ #define rseq_smp_load_acquire(p) \ __extension__ ({ \ - __typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \ - RISCV_FENCE(r, rw) \ + rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \ + RISCV_FENCE(r, rw); \ ____p1; \ }) @@ -46,7 +46,7 @@ __extension__ ({ \ #define rseq_smp_store_release(p, v) \ do { \ RISCV_FENCE(rw, w); \ - RSEQ_WRITE_ONCE(*(p), v); \ + RSEQ_WRITE_ONCE(*(p), v); \ } while (0) #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \ diff --git a/tools/testing/selftests/rseq/rseq-s390.h b/tools/testing/selftests/rseq/rseq-s390.h index 46c92598acc7..33baaa9f9997 100644 --- a/tools/testing/selftests/rseq/rseq-s390.h +++ b/tools/testing/selftests/rseq/rseq-s390.h @@ -15,7 +15,7 @@ #define rseq_smp_load_acquire(p) \ __extension__ ({ \ - __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \ rseq_barrier(); \ ____p1; \ }) @@ -25,7 +25,7 @@ __extension__ ({ \ #define rseq_smp_store_release(p, v) \ do { \ rseq_barrier(); \ - RSEQ_WRITE_ONCE(*p, v); \ + RSEQ_WRITE_ONCE(*(p), v); \ } while (0) #ifdef __s390x__ diff --git a/tools/testing/selftests/rseq/rseq-x86.h b/tools/testing/selftests/rseq/rseq-x86.h index fb65ef54b0fb..a2aa428ba151 100644 --- a/tools/testing/selftests/rseq/rseq-x86.h +++ b/tools/testing/selftests/rseq/rseq-x86.h @@ -42,7 +42,7 @@ #define rseq_smp_load_acquire(p) \ __extension__ ({ \ - __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \ rseq_barrier(); \ ____p1; \ }) @@ -52,7 +52,7 @@ __extension__ ({ \ #define rseq_smp_store_release(p, v) \ do { \ rseq_barrier(); \ - RSEQ_WRITE_ONCE(*p, v); \ + RSEQ_WRITE_ONCE(*(p), v); \ } while (0) #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 43ec36b179dc..38f651469968 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -2184,6 +2184,9 @@ FIXTURE_TEARDOWN(TRACE_syscall) TEST(negative_ENOSYS) { +#if defined(__arm__) + SKIP(return, "arm32 does not support calling syscall -1"); +#endif /* * There should be no difference between an "internal" skip * and userspace asking for syscall "-1". @@ -3072,7 +3075,8 @@ TEST(syscall_restart) timeout.tv_sec = 1; errno = 0; EXPECT_EQ(0, nanosleep(&timeout, NULL)) { - TH_LOG("Call to nanosleep() failed (errno %d)", errno); + TH_LOG("Call to nanosleep() failed (errno %d: %s)", + errno, strerror(errno)); } /* Read final sync from parent. */ @@ -3908,6 +3912,9 @@ TEST(user_notification_filter_empty) TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); } + if (__NR_clone3 < 0) + SKIP(return, "Test not built with clone3 support"); + pid = sys_clone3(&args, sizeof(args)); ASSERT_GE(pid, 0); @@ -3962,6 +3969,9 @@ TEST(user_notification_filter_empty_threaded) TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); } + if (__NR_clone3 < 0) + SKIP(return, "Test not built with clone3 support"); + pid = sys_clone3(&args, sizeof(args)); ASSERT_GE(pid, 0); @@ -4255,6 +4265,61 @@ TEST(user_notification_addfd_rlimit) close(memfd); } +#ifndef SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP +#define SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP (1UL << 0) +#define SECCOMP_IOCTL_NOTIF_SET_FLAGS SECCOMP_IOW(4, __u64) +#endif + +TEST(user_notification_sync) +{ + struct seccomp_notif req = {}; + struct seccomp_notif_resp resp = {}; + int status, listener; + pid_t pid; + long ret; + + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + ASSERT_EQ(0, ret) { + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); + } + + listener = user_notif_syscall(__NR_getppid, + SECCOMP_FILTER_FLAG_NEW_LISTENER); + ASSERT_GE(listener, 0); + + /* Try to set invalid flags. */ + EXPECT_SYSCALL_RETURN(-EINVAL, + ioctl(listener, SECCOMP_IOCTL_NOTIF_SET_FLAGS, 0xffffffff, 0)); + + ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SET_FLAGS, + SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP, 0), 0); + + pid = fork(); + ASSERT_GE(pid, 0); + if (pid == 0) { + ret = syscall(__NR_getppid); + ASSERT_EQ(ret, USER_NOTIF_MAGIC) { + _exit(1); + } + _exit(0); + } + + req.pid = 0; + ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0); + + ASSERT_EQ(req.data.nr, __NR_getppid); + + resp.id = req.id; + resp.error = 0; + resp.val = USER_NOTIF_MAGIC; + resp.flags = 0; + ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0); + + ASSERT_EQ(waitpid(pid, &status, 0), pid); + ASSERT_EQ(status, 0); +} + + /* Make sure PTRACE_O_SUSPEND_SECCOMP requires CAP_SYS_ADMIN. */ FIXTURE(O_SUSPEND_SECCOMP) { pid_t pid; diff --git a/tools/testing/selftests/user_events/Makefile b/tools/testing/selftests/user_events/Makefile index 9e95bd41b0b4..10fcd0066203 100644 --- a/tools/testing/selftests/user_events/Makefile +++ b/tools/testing/selftests/user_events/Makefile @@ -2,14 +2,6 @@ CFLAGS += -Wl,-no-as-needed -Wall $(KHDR_INCLUDES) LDLIBS += -lrt -lpthread -lm -# Note: -# This test depends on <linux/user_events.h> exported in uapi -# The following commit removed user_events.h out of uapi: -# commit 5cfff569cab8bf544bab62c911c5d6efd5af5e05 -# tracing: Move user_events.h temporarily out of include/uapi -# This test will not compile until user_events.h is added -# back to uapi. - TEST_GEN_PROGS = ftrace_test dyn_test perf_test abi_test TEST_FILES := settings |