From e40fbbf0572c5e41dc87ad79001748ed399ce32d Mon Sep 17 00:00:00 2001 From: Usama Arif Date: Wed, 19 Jan 2022 11:44:40 +0000 Subject: uapi/bpf: Add missing description and returns for helper documentation Both description and returns section will become mandatory for helpers and syscalls in a later commit to generate man pages. This commit also adds in the documentation that BPF_PROG_RUN is an alias for BPF_PROG_TEST_RUN for anyone searching for the syscall in the generated man pages. Signed-off-by: Usama Arif Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20220119114442.1452088-1-usama.arif@bytedance.com --- tools/include/uapi/linux/bpf.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index b0383d371b9a..a9c96c21330a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -330,6 +330,8 @@ union bpf_iter_link_info { * *ctx_out*, *data_in* and *data_out* must be NULL. * *repeat* must be zero. * + * BPF_PROG_RUN is an alias for BPF_PROG_TEST_RUN. + * * Return * Returns zero on success. On error, -1 is returned and *errno* * is set appropriately. @@ -1775,6 +1777,8 @@ union bpf_attr { * 0 on success, or a negative error in case of failure. * * u64 bpf_get_current_pid_tgid(void) + * Description + * Get the current pid and tgid. * Return * A 64-bit integer containing the current tgid and pid, and * created as such: @@ -1782,6 +1786,8 @@ union bpf_attr { * *current_task*\ **->pid**. * * u64 bpf_get_current_uid_gid(void) + * Description + * Get the current uid and gid. * Return * A 64-bit integer containing the current GID and UID, and * created as such: *current_gid* **<< 32 \|** *current_uid*. @@ -2256,6 +2262,8 @@ union bpf_attr { * The 32-bit hash. * * u64 bpf_get_current_task(void) + * Description + * Get the current task. * Return * A pointer to the current task struct. * @@ -2369,6 +2377,8 @@ union bpf_attr { * indicate that the hash is outdated and to trigger a * recalculation the next time the kernel tries to access this * hash or when the **bpf_get_hash_recalc**\ () helper is called. + * Return + * void. * * long bpf_get_numa_node_id(void) * Description @@ -2466,6 +2476,8 @@ union bpf_attr { * A 8-byte long unique number or 0 if *sk* is NULL. * * u32 bpf_get_socket_uid(struct sk_buff *skb) + * Description + * Get the owner UID of the socked associated to *skb*. * Return * The owner UID of the socket associated to *skb*. If the socket * is **NULL**, or if it is not a full socket (i.e. if it is a @@ -3240,6 +3252,9 @@ union bpf_attr { * The id is returned or 0 in case the id could not be retrieved. * * u64 bpf_get_current_cgroup_id(void) + * Description + * Get the current cgroup id based on the cgroup within which + * the current task is running. * Return * A 64-bit integer containing the current cgroup id based * on the cgroup within which the current task is running. -- cgit From b44123b4a3dcad4664d3a0f72c011ffd4c9c4d93 Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Thu, 16 Dec 2021 02:04:27 +0000 Subject: bpf: Add cgroup helpers bpf_{get,set}_retval to get/set syscall return value The helpers continue to use int for retval because all the hooks are int-returning rather than long-returning. The return value of bpf_set_retval is int for future-proofing, in case in the future there may be errors trying to set the retval. After the previous patch, if a program rejects a syscall by returning 0, an -EPERM will be generated no matter if the retval is already set to -err. This patch change it being forced only if retval is not -err. This is because we want to support, for example, invoking bpf_set_retval(-EINVAL) and return 0, and have the syscall return value be -EINVAL not -EPERM. For BPF_PROG_CGROUP_INET_EGRESS_RUN_ARRAY, the prior behavior is that, if the return value is NET_XMIT_DROP, the packet is silently dropped. We preserve this behavior for backward compatibility reasons, so even if an errno is set, the errno does not return to caller. However, setting a non-err to retval cannot propagate so this is not allowed and we return a -EFAULT in that case. Signed-off-by: YiFei Zhu Reviewed-by: Stanislav Fomichev Link: https://lore.kernel.org/r/b4013fd5d16bed0b01977c1fafdeae12e1de61fb.1639619851.git.zhuyifei@google.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 10 ++++++---- include/uapi/linux/bpf.h | 18 ++++++++++++++++++ kernel/bpf/cgroup.c | 38 +++++++++++++++++++++++++++++++++++++- tools/include/uapi/linux/bpf.h | 18 ++++++++++++++++++ 4 files changed, 79 insertions(+), 5 deletions(-) (limited to 'tools/include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 7b0c11f414d0..dce54eb0aae8 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1299,7 +1299,7 @@ BPF_PROG_RUN_ARRAY_CG_FLAGS(const struct bpf_prog_array __rcu *array_rcu, while ((prog = READ_ONCE(item->prog))) { run_ctx.prog_item = item; func_ret = run_prog(prog, ctx); - if (!(func_ret & 1)) + if (!(func_ret & 1) && !IS_ERR_VALUE((long)run_ctx.retval)) run_ctx.retval = -EPERM; *(ret_flags) |= (func_ret >> 1); item++; @@ -1329,7 +1329,7 @@ BPF_PROG_RUN_ARRAY_CG(const struct bpf_prog_array __rcu *array_rcu, old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx); while ((prog = READ_ONCE(item->prog))) { run_ctx.prog_item = item; - if (!run_prog(prog, ctx)) + if (!run_prog(prog, ctx) && !IS_ERR_VALUE((long)run_ctx.retval)) run_ctx.retval = -EPERM; item++; } @@ -1389,7 +1389,7 @@ out: * 0: NET_XMIT_SUCCESS skb should be transmitted * 1: NET_XMIT_DROP skb should be dropped and cn * 2: NET_XMIT_CN skb should be transmitted and cn - * 3: -EPERM skb should be dropped + * 3: -err skb should be dropped */ #define BPF_PROG_CGROUP_INET_EGRESS_RUN_ARRAY(array, ctx, func) \ ({ \ @@ -1398,10 +1398,12 @@ out: u32 _ret; \ _ret = BPF_PROG_RUN_ARRAY_CG_FLAGS(array, ctx, func, 0, &_flags); \ _cn = _flags & BPF_RET_SET_CN; \ + if (_ret && !IS_ERR_VALUE((long)_ret)) \ + _ret = -EFAULT; \ if (!_ret) \ _ret = (_cn ? NET_XMIT_CN : NET_XMIT_SUCCESS); \ else \ - _ret = (_cn ? NET_XMIT_DROP : -EPERM); \ + _ret = (_cn ? NET_XMIT_DROP : _ret); \ _ret; \ }) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index a9c96c21330a..fe2272defcd9 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5033,6 +5033,22 @@ union bpf_attr { * * Return * The number of arguments of the traced function. + * + * int bpf_get_retval(void) + * Description + * Get the syscall's return value that will be returned to userspace. + * + * This helper is currently supported by cgroup programs only. + * Return + * The syscall's return value. + * + * int bpf_set_retval(int retval) + * Description + * Set the syscall's return value that will be returned to userspace. + * + * This helper is currently supported by cgroup programs only. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5221,6 +5237,8 @@ union bpf_attr { FN(get_func_arg), \ FN(get_func_ret), \ FN(get_func_arg_cnt), \ + FN(get_retval), \ + FN(set_retval), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index b6fad0bbf5a7..279ebbed75a5 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -1044,7 +1044,7 @@ int cgroup_bpf_prog_query(const union bpf_attr *attr, * NET_XMIT_DROP (1) - drop packet and notify TCP to call cwr * NET_XMIT_CN (2) - continue with packet output and notify TCP * to call cwr - * -EPERM - drop packet + * -err - drop packet * * For ingress packets, this function will return -EPERM if any * attached program was found and if it returned != 1 during execution. @@ -1080,6 +1080,8 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk, } else { ret = BPF_PROG_RUN_ARRAY_CG(cgrp->bpf.effective[atype], skb, __bpf_prog_run_save_cb, 0); + if (ret && !IS_ERR_VALUE((long)ret)) + ret = -EFAULT; } bpf_restore_data_end(skb, saved_data_end); __skb_pull(skb, offset); @@ -1205,6 +1207,36 @@ int __cgroup_bpf_check_dev_permission(short dev_type, u32 major, u32 minor, return ret; } +BPF_CALL_0(bpf_get_retval) +{ + struct bpf_cg_run_ctx *ctx = + container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx); + + return ctx->retval; +} + +static const struct bpf_func_proto bpf_get_retval_proto = { + .func = bpf_get_retval, + .gpl_only = false, + .ret_type = RET_INTEGER, +}; + +BPF_CALL_1(bpf_set_retval, int, retval) +{ + struct bpf_cg_run_ctx *ctx = + container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx); + + ctx->retval = retval; + return 0; +} + +static const struct bpf_func_proto bpf_set_retval_proto = { + .func = bpf_set_retval, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_ANYTHING, +}; + static const struct bpf_func_proto * cgroup_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -1217,6 +1249,10 @@ cgroup_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_get_current_cgroup_id_proto; case BPF_FUNC_perf_event_output: return &bpf_event_output_data_proto; + case BPF_FUNC_get_retval: + return &bpf_get_retval_proto; + case BPF_FUNC_set_retval: + return &bpf_set_retval_proto; default: return bpf_base_func_proto(func_id); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index a9c96c21330a..fe2272defcd9 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5033,6 +5033,22 @@ union bpf_attr { * * Return * The number of arguments of the traced function. + * + * int bpf_get_retval(void) + * Description + * Get the syscall's return value that will be returned to userspace. + * + * This helper is currently supported by cgroup programs only. + * Return + * The syscall's return value. + * + * int bpf_set_retval(int retval) + * Description + * Set the syscall's return value that will be returned to userspace. + * + * This helper is currently supported by cgroup programs only. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5221,6 +5237,8 @@ union bpf_attr { FN(get_func_arg), \ FN(get_func_ret), \ FN(get_func_arg_cnt), \ + FN(get_retval), \ + FN(set_retval), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From c2f2cdbeffda7b153c19e0f3d73149c41026c0db Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 21 Jan 2022 11:09:52 +0100 Subject: bpf: introduce BPF_F_XDP_HAS_FRAGS flag in prog_flags loading the ebpf program Introduce BPF_F_XDP_HAS_FRAGS and the related field in bpf_prog_aux in order to notify the driver the loaded program support xdp frags. Acked-by: Toke Hoiland-Jorgensen Acked-by: John Fastabend Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/db2e8075b7032a356003f407d1b0deb99adaa0ed.1642758637.git.lorenzo@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 1 + include/uapi/linux/bpf.h | 5 +++++ kernel/bpf/syscall.c | 4 +++- tools/include/uapi/linux/bpf.h | 5 +++++ 4 files changed, 14 insertions(+), 1 deletion(-) (limited to 'tools/include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 80e3387ea3af..e93ed028a030 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -933,6 +933,7 @@ struct bpf_prog_aux { bool func_proto_unreliable; bool sleepable; bool tail_call_reachable; + bool xdp_has_frags; struct hlist_node tramp_hlist; /* BTF_KIND_FUNC_PROTO for valid attach_btf_id */ const struct btf_type *attach_func_proto; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index fe2272defcd9..945649c67e03 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1113,6 +1113,11 @@ enum bpf_link_type { */ #define BPF_F_SLEEPABLE (1U << 4) +/* If BPF_F_XDP_HAS_FRAGS is used in BPF_PROG_LOAD command, the loaded program + * fully support xdp frags. + */ +#define BPF_F_XDP_HAS_FRAGS (1U << 5) + /* When BPF ldimm64's insn[0].src_reg != 0 then this can have * the following extensions: * diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 9e0631f091a6..f29090643c6e 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2217,7 +2217,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) BPF_F_ANY_ALIGNMENT | BPF_F_TEST_STATE_FREQ | BPF_F_SLEEPABLE | - BPF_F_TEST_RND_HI32)) + BPF_F_TEST_RND_HI32 | + BPF_F_XDP_HAS_FRAGS)) return -EINVAL; if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && @@ -2303,6 +2304,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) prog->aux->dst_prog = dst_prog; prog->aux->offload_requested = !!attr->prog_ifindex; prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; + prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS; err = security_bpf_prog_alloc(prog->aux); if (err) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index fe2272defcd9..945649c67e03 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1113,6 +1113,11 @@ enum bpf_link_type { */ #define BPF_F_SLEEPABLE (1U << 4) +/* If BPF_F_XDP_HAS_FRAGS is used in BPF_PROG_LOAD command, the loaded program + * fully support xdp frags. + */ +#define BPF_F_XDP_HAS_FRAGS (1U << 5) + /* When BPF ldimm64's insn[0].src_reg != 0 then this can have * the following extensions: * -- cgit From 0165cc817075cf701e4289838f1d925ff1911b3e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 21 Jan 2022 11:09:54 +0100 Subject: bpf: introduce bpf_xdp_get_buff_len helper Introduce bpf_xdp_get_buff_len helper in order to return the xdp buffer total size (linear and paged area) Acked-by: Toke Hoiland-Jorgensen Acked-by: John Fastabend Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/aac9ac3504c84026cf66a3c71b7c5ae89bc991be.1642758637.git.lorenzo@kernel.org Signed-off-by: Alexei Starovoitov --- include/net/xdp.h | 14 ++++++++++++++ include/uapi/linux/bpf.h | 7 +++++++ net/core/filter.c | 15 +++++++++++++++ tools/include/uapi/linux/bpf.h | 7 +++++++ 4 files changed, 43 insertions(+) (limited to 'tools/include') diff --git a/include/net/xdp.h b/include/net/xdp.h index 8463dea8b4db..52b593321956 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -145,6 +145,20 @@ xdp_get_shared_info_from_buff(struct xdp_buff *xdp) return (struct skb_shared_info *)xdp_data_hard_end(xdp); } +static __always_inline unsigned int xdp_get_buff_len(struct xdp_buff *xdp) +{ + unsigned int len = xdp->data_end - xdp->data; + struct skb_shared_info *sinfo; + + if (likely(!xdp_buff_has_frags(xdp))) + goto out; + + sinfo = xdp_get_shared_info_from_buff(xdp); + len += sinfo->xdp_frags_size; +out: + return len; +} + struct xdp_frame { void *data; u16 len; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 945649c67e03..5a28772063f6 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5054,6 +5054,12 @@ union bpf_attr { * This helper is currently supported by cgroup programs only. * Return * 0 on success, or a negative error in case of failure. + * + * u64 bpf_xdp_get_buff_len(struct xdp_buff *xdp_md) + * Description + * Get the total size of a given xdp buff (linear and paged area) + * Return + * The total size of a given xdp buffer. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5244,6 +5250,7 @@ union bpf_attr { FN(get_func_arg_cnt), \ FN(get_retval), \ FN(set_retval), \ + FN(xdp_get_buff_len), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/net/core/filter.c b/net/core/filter.c index f73a84c75970..a7f03bbca465 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3783,6 +3783,19 @@ static const struct bpf_func_proto sk_skb_change_head_proto = { .arg2_type = ARG_ANYTHING, .arg3_type = ARG_ANYTHING, }; + +BPF_CALL_1(bpf_xdp_get_buff_len, struct xdp_buff*, xdp) +{ + return xdp_get_buff_len(xdp); +} + +static const struct bpf_func_proto bpf_xdp_get_buff_len_proto = { + .func = bpf_xdp_get_buff_len, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +}; + static unsigned long xdp_get_metalen(const struct xdp_buff *xdp) { return xdp_data_meta_unsupported(xdp) ? 0 : @@ -7533,6 +7546,8 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_xdp_redirect_map_proto; case BPF_FUNC_xdp_adjust_tail: return &bpf_xdp_adjust_tail_proto; + case BPF_FUNC_xdp_get_buff_len: + return &bpf_xdp_get_buff_len_proto; case BPF_FUNC_fib_lookup: return &bpf_xdp_fib_lookup_proto; case BPF_FUNC_check_mtu: diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 945649c67e03..5a28772063f6 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5054,6 +5054,12 @@ union bpf_attr { * This helper is currently supported by cgroup programs only. * Return * 0 on success, or a negative error in case of failure. + * + * u64 bpf_xdp_get_buff_len(struct xdp_buff *xdp_md) + * Description + * Get the total size of a given xdp buff (linear and paged area) + * Return + * The total size of a given xdp buffer. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5244,6 +5250,7 @@ union bpf_attr { FN(get_func_arg_cnt), \ FN(get_retval), \ FN(set_retval), \ + FN(xdp_get_buff_len), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From 3f364222d032eea6b245780e845ad213dab28cdd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 21 Jan 2022 11:10:03 +0100 Subject: net: xdp: introduce bpf_xdp_pointer utility routine Similar to skb_header_pointer, introduce bpf_xdp_pointer utility routine to return a pointer to a given position in the xdp_buff if the requested area (offset + len) is contained in a contiguous memory area otherwise it will be copied in a bounce buffer provided by the caller. Similar to the tc counterpart, introduce the two following xdp helpers: - bpf_xdp_load_bytes - bpf_xdp_store_bytes Reviewed-by: Eelco Chaudron Acked-by: Toke Hoiland-Jorgensen Acked-by: John Fastabend Acked-by: Jakub Kicinski Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/ab285c1efdd5b7a9d361348b1e7d3ef49f6382b3.1642758637.git.lorenzo@kernel.org Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 18 +++++ net/core/filter.c | 176 ++++++++++++++++++++++++++++++++--------- tools/include/uapi/linux/bpf.h | 18 +++++ 3 files changed, 174 insertions(+), 38 deletions(-) (limited to 'tools/include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 5a28772063f6..16a7574292a5 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5060,6 +5060,22 @@ union bpf_attr { * Get the total size of a given xdp buff (linear and paged area) * Return * The total size of a given xdp buffer. + * + * long bpf_xdp_load_bytes(struct xdp_buff *xdp_md, u32 offset, void *buf, u32 len) + * Description + * This helper is provided as an easy way to load data from a + * xdp buffer. It can be used to load *len* bytes from *offset* from + * the frame associated to *xdp_md*, into the buffer pointed by + * *buf*. + * Return + * 0 on success, or a negative error in case of failure. + * + * long bpf_xdp_store_bytes(struct xdp_buff *xdp_md, u32 offset, void *buf, u32 len) + * Description + * Store *len* bytes from buffer *buf* into the frame + * associated to *xdp_md*, at *offset*. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5251,6 +5267,8 @@ union bpf_attr { FN(get_retval), \ FN(set_retval), \ FN(xdp_get_buff_len), \ + FN(xdp_load_bytes), \ + FN(xdp_store_bytes), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/net/core/filter.c b/net/core/filter.c index e4ce138bf925..945ccaaab3cb 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3839,6 +3839,138 @@ static const struct bpf_func_proto bpf_xdp_adjust_head_proto = { .arg2_type = ARG_ANYTHING, }; +static void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, + void *buf, unsigned long len, bool flush) +{ + unsigned long ptr_len, ptr_off = 0; + skb_frag_t *next_frag, *end_frag; + struct skb_shared_info *sinfo; + void *src, *dst; + u8 *ptr_buf; + + if (likely(xdp->data_end - xdp->data >= off + len)) { + src = flush ? buf : xdp->data + off; + dst = flush ? xdp->data + off : buf; + memcpy(dst, src, len); + return; + } + + sinfo = xdp_get_shared_info_from_buff(xdp); + end_frag = &sinfo->frags[sinfo->nr_frags]; + next_frag = &sinfo->frags[0]; + + ptr_len = xdp->data_end - xdp->data; + ptr_buf = xdp->data; + + while (true) { + if (off < ptr_off + ptr_len) { + unsigned long copy_off = off - ptr_off; + unsigned long copy_len = min(len, ptr_len - copy_off); + + src = flush ? buf : ptr_buf + copy_off; + dst = flush ? ptr_buf + copy_off : buf; + memcpy(dst, src, copy_len); + + off += copy_len; + len -= copy_len; + buf += copy_len; + } + + if (!len || next_frag == end_frag) + break; + + ptr_off += ptr_len; + ptr_buf = skb_frag_address(next_frag); + ptr_len = skb_frag_size(next_frag); + next_frag++; + } +} + +static void *bpf_xdp_pointer(struct xdp_buff *xdp, u32 offset, u32 len) +{ + struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); + u32 size = xdp->data_end - xdp->data; + void *addr = xdp->data; + int i; + + if (unlikely(offset > 0xffff || len > 0xffff)) + return ERR_PTR(-EFAULT); + + if (offset + len > xdp_get_buff_len(xdp)) + return ERR_PTR(-EINVAL); + + if (offset < size) /* linear area */ + goto out; + + offset -= size; + for (i = 0; i < sinfo->nr_frags; i++) { /* paged area */ + u32 frag_size = skb_frag_size(&sinfo->frags[i]); + + if (offset < frag_size) { + addr = skb_frag_address(&sinfo->frags[i]); + size = frag_size; + break; + } + offset -= frag_size; + } +out: + return offset + len < size ? addr + offset : NULL; +} + +BPF_CALL_4(bpf_xdp_load_bytes, struct xdp_buff *, xdp, u32, offset, + void *, buf, u32, len) +{ + void *ptr; + + ptr = bpf_xdp_pointer(xdp, offset, len); + if (IS_ERR(ptr)) + return PTR_ERR(ptr); + + if (!ptr) + bpf_xdp_copy_buf(xdp, offset, buf, len, false); + else + memcpy(buf, ptr, len); + + return 0; +} + +static const struct bpf_func_proto bpf_xdp_load_bytes_proto = { + .func = bpf_xdp_load_bytes, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_PTR_TO_UNINIT_MEM, + .arg4_type = ARG_CONST_SIZE, +}; + +BPF_CALL_4(bpf_xdp_store_bytes, struct xdp_buff *, xdp, u32, offset, + void *, buf, u32, len) +{ + void *ptr; + + ptr = bpf_xdp_pointer(xdp, offset, len); + if (IS_ERR(ptr)) + return PTR_ERR(ptr); + + if (!ptr) + bpf_xdp_copy_buf(xdp, offset, buf, len, true); + else + memcpy(ptr, buf, len); + + return 0; +} + +static const struct bpf_func_proto bpf_xdp_store_bytes_proto = { + .func = bpf_xdp_store_bytes, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_PTR_TO_UNINIT_MEM, + .arg4_type = ARG_CONST_SIZE, +}; + static int bpf_xdp_frags_increase_tail(struct xdp_buff *xdp, int offset) { struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); @@ -4677,48 +4809,12 @@ static const struct bpf_func_proto bpf_sk_ancestor_cgroup_id_proto = { }; #endif -static unsigned long bpf_xdp_copy(void *dst_buff, const void *ctx, +static unsigned long bpf_xdp_copy(void *dst, const void *ctx, unsigned long off, unsigned long len) { struct xdp_buff *xdp = (struct xdp_buff *)ctx; - unsigned long ptr_len, ptr_off = 0; - skb_frag_t *next_frag, *end_frag; - struct skb_shared_info *sinfo; - u8 *ptr_buf; - - if (likely(xdp->data_end - xdp->data >= off + len)) { - memcpy(dst_buff, xdp->data + off, len); - return 0; - } - - sinfo = xdp_get_shared_info_from_buff(xdp); - end_frag = &sinfo->frags[sinfo->nr_frags]; - next_frag = &sinfo->frags[0]; - - ptr_len = xdp->data_end - xdp->data; - ptr_buf = xdp->data; - - while (true) { - if (off < ptr_off + ptr_len) { - unsigned long copy_off = off - ptr_off; - unsigned long copy_len = min(len, ptr_len - copy_off); - - memcpy(dst_buff, ptr_buf + copy_off, copy_len); - - off += copy_len; - len -= copy_len; - dst_buff += copy_len; - } - - if (!len || next_frag == end_frag) - break; - - ptr_off += ptr_len; - ptr_buf = skb_frag_address(next_frag); - ptr_len = skb_frag_size(next_frag); - next_frag++; - } + bpf_xdp_copy_buf(xdp, off, dst, len, false); return 0; } @@ -7660,6 +7756,10 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_xdp_adjust_tail_proto; case BPF_FUNC_xdp_get_buff_len: return &bpf_xdp_get_buff_len_proto; + case BPF_FUNC_xdp_load_bytes: + return &bpf_xdp_load_bytes_proto; + case BPF_FUNC_xdp_store_bytes: + return &bpf_xdp_store_bytes_proto; case BPF_FUNC_fib_lookup: return &bpf_xdp_fib_lookup_proto; case BPF_FUNC_check_mtu: diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 5a28772063f6..16a7574292a5 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5060,6 +5060,22 @@ union bpf_attr { * Get the total size of a given xdp buff (linear and paged area) * Return * The total size of a given xdp buffer. + * + * long bpf_xdp_load_bytes(struct xdp_buff *xdp_md, u32 offset, void *buf, u32 len) + * Description + * This helper is provided as an easy way to load data from a + * xdp buffer. It can be used to load *len* bytes from *offset* from + * the frame associated to *xdp_md*, into the buffer pointed by + * *buf*. + * Return + * 0 on success, or a negative error in case of failure. + * + * long bpf_xdp_store_bytes(struct xdp_buff *xdp_md, u32 offset, void *buf, u32 len) + * Description + * Store *len* bytes from buffer *buf* into the frame + * associated to *xdp_md*, at *offset*. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5251,6 +5267,8 @@ union bpf_attr { FN(get_retval), \ FN(set_retval), \ FN(xdp_get_buff_len), \ + FN(xdp_load_bytes), \ + FN(xdp_store_bytes), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From 376040e47334c6dc6a939a32197acceb00fe4acf Mon Sep 17 00:00:00 2001 From: Kenny Yu Date: Mon, 24 Jan 2022 10:54:01 -0800 Subject: bpf: Add bpf_copy_from_user_task() helper This adds a helper for bpf programs to read the memory of other tasks. As an example use case at Meta, we are using a bpf task iterator program and this new helper to print C++ async stack traces for all threads of a given process. Signed-off-by: Kenny Yu Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20220124185403.468466-3-kennyyu@fb.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 1 + include/uapi/linux/bpf.h | 11 +++++++++++ kernel/bpf/helpers.c | 34 ++++++++++++++++++++++++++++++++++ kernel/trace/bpf_trace.c | 2 ++ tools/include/uapi/linux/bpf.h | 11 +++++++++++ 5 files changed, 59 insertions(+) (limited to 'tools/include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8c92c974bd12..394305a5e02f 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2243,6 +2243,7 @@ extern const struct bpf_func_proto bpf_kallsyms_lookup_name_proto; extern const struct bpf_func_proto bpf_find_vma_proto; extern const struct bpf_func_proto bpf_loop_proto; extern const struct bpf_func_proto bpf_strncmp_proto; +extern const struct bpf_func_proto bpf_copy_from_user_task_proto; const struct bpf_func_proto *tracing_prog_func_proto( enum bpf_func_id func_id, const struct bpf_prog *prog); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 16a7574292a5..4a2f7041ebae 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5076,6 +5076,16 @@ union bpf_attr { * associated to *xdp_md*, at *offset*. * Return * 0 on success, or a negative error in case of failure. + * + * long bpf_copy_from_user_task(void *dst, u32 size, const void *user_ptr, struct task_struct *tsk, u64 flags) + * Description + * Read *size* bytes from user space address *user_ptr* in *tsk*'s + * address space, and stores the data in *dst*. *flags* is not + * used yet and is provided for future extensibility. This helper + * can only be used by sleepable programs. + * Return + * 0 on success, or a negative error in case of failure. On error + * *dst* buffer is zeroed out. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5269,6 +5279,7 @@ union bpf_attr { FN(xdp_get_buff_len), \ FN(xdp_load_bytes), \ FN(xdp_store_bytes), \ + FN(copy_from_user_task), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 01cfdf40c838..ed2780b76cc1 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "../../lib/kstrtox.h" @@ -671,6 +672,39 @@ const struct bpf_func_proto bpf_copy_from_user_proto = { .arg3_type = ARG_ANYTHING, }; +BPF_CALL_5(bpf_copy_from_user_task, void *, dst, u32, size, + const void __user *, user_ptr, struct task_struct *, tsk, u64, flags) +{ + int ret; + + /* flags is not used yet */ + if (unlikely(flags)) + return -EINVAL; + + if (unlikely(!size)) + return 0; + + ret = access_process_vm(tsk, (unsigned long)user_ptr, dst, size, 0); + if (ret == size) + return 0; + + memset(dst, 0, size); + /* Return -EFAULT for partial read */ + return ret < 0 ? ret : -EFAULT; +} + +const struct bpf_func_proto bpf_copy_from_user_task_proto = { + .func = bpf_copy_from_user_task, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_UNINIT_MEM, + .arg2_type = ARG_CONST_SIZE_OR_ZERO, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_PTR_TO_BTF_ID, + .arg4_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK], + .arg5_type = ARG_ANYTHING +}; + BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu) { if (cpu >= nr_cpu_ids) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 06a9e220069e..a2024ba32a20 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1235,6 +1235,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_get_task_stack_proto; case BPF_FUNC_copy_from_user: return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL; + case BPF_FUNC_copy_from_user_task: + return prog->aux->sleepable ? &bpf_copy_from_user_task_proto : NULL; case BPF_FUNC_snprintf_btf: return &bpf_snprintf_btf_proto; case BPF_FUNC_per_cpu_ptr: diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 16a7574292a5..4a2f7041ebae 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5076,6 +5076,16 @@ union bpf_attr { * associated to *xdp_md*, at *offset*. * Return * 0 on success, or a negative error in case of failure. + * + * long bpf_copy_from_user_task(void *dst, u32 size, const void *user_ptr, struct task_struct *tsk, u64 flags) + * Description + * Read *size* bytes from user space address *user_ptr* in *tsk*'s + * address space, and stores the data in *dst*. *flags* is not + * used yet and is provided for future extensibility. This helper + * can only be used by sleepable programs. + * Return + * 0 on success, or a negative error in case of failure. On error + * *dst* buffer is zeroed out. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5269,6 +5279,7 @@ union bpf_attr { FN(xdp_get_buff_len), \ FN(xdp_load_bytes), \ FN(xdp_store_bytes), \ + FN(copy_from_user_task), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From 8f50f16ff39dd4e2d43d1548ca66925652f8aff7 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Sun, 30 Jan 2022 12:55:18 +0100 Subject: selftests/bpf: Extend verifier and bpf_sock tests for dst_port loads Add coverage to the verifier tests and tests for reading bpf_sock fields to ensure that 32-bit, 16-bit, and 8-bit loads from dst_port field are allowed only at intended offsets and produce expected values. While 16-bit and 8-bit access to dst_port field is straight-forward, 32-bit wide loads need be allowed and produce a zero-padded 16-bit value for backward compatibility. Signed-off-by: Jakub Sitnicki Link: https://lore.kernel.org/r/20220130115518.213259-3-jakub@cloudflare.com Signed-off-by: Alexei Starovoitov --- tools/include/uapi/linux/bpf.h | 3 +- .../testing/selftests/bpf/prog_tests/sock_fields.c | 58 +++++++++++----- .../testing/selftests/bpf/progs/test_sock_fields.c | 41 +++++++++++ tools/testing/selftests/bpf/verifier/sock.c | 81 +++++++++++++++++++++- 4 files changed, 162 insertions(+), 21 deletions(-) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 4a2f7041ebae..a7f0ddedac1f 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5574,7 +5574,8 @@ struct bpf_sock { __u32 src_ip4; __u32 src_ip6[4]; __u32 src_port; /* host byte order */ - __u32 dst_port; /* network byte order */ + __be16 dst_port; /* network byte order */ + __u16 :16; /* zero padding */ __u32 dst_ip4; __u32 dst_ip6[4]; __u32 state; diff --git a/tools/testing/selftests/bpf/prog_tests/sock_fields.c b/tools/testing/selftests/bpf/prog_tests/sock_fields.c index 9fc040eaa482..9d211b5c22c4 100644 --- a/tools/testing/selftests/bpf/prog_tests/sock_fields.c +++ b/tools/testing/selftests/bpf/prog_tests/sock_fields.c @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2019 Facebook */ +#define _GNU_SOURCE #include #include #include +#include #include #include #include @@ -20,6 +22,7 @@ enum bpf_linum_array_idx { EGRESS_LINUM_IDX, INGRESS_LINUM_IDX, + READ_SK_DST_PORT_LINUM_IDX, __NR_BPF_LINUM_ARRAY_IDX, }; @@ -42,8 +45,16 @@ static __u64 child_cg_id; static int linum_map_fd; static __u32 duration; -static __u32 egress_linum_idx = EGRESS_LINUM_IDX; -static __u32 ingress_linum_idx = INGRESS_LINUM_IDX; +static bool create_netns(void) +{ + if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) + return false; + + if (!ASSERT_OK(system("ip link set dev lo up"), "bring up lo")) + return false; + + return true; +} static void print_sk(const struct bpf_sock *sk, const char *prefix) { @@ -91,19 +102,24 @@ static void check_result(void) { struct bpf_tcp_sock srv_tp, cli_tp, listen_tp; struct bpf_sock srv_sk, cli_sk, listen_sk; - __u32 ingress_linum, egress_linum; + __u32 idx, ingress_linum, egress_linum, linum; int err; - err = bpf_map_lookup_elem(linum_map_fd, &egress_linum_idx, - &egress_linum); + idx = EGRESS_LINUM_IDX; + err = bpf_map_lookup_elem(linum_map_fd, &idx, &egress_linum); CHECK(err < 0, "bpf_map_lookup_elem(linum_map_fd)", "err:%d errno:%d\n", err, errno); - err = bpf_map_lookup_elem(linum_map_fd, &ingress_linum_idx, - &ingress_linum); + idx = INGRESS_LINUM_IDX; + err = bpf_map_lookup_elem(linum_map_fd, &idx, &ingress_linum); CHECK(err < 0, "bpf_map_lookup_elem(linum_map_fd)", "err:%d errno:%d\n", err, errno); + idx = READ_SK_DST_PORT_LINUM_IDX; + err = bpf_map_lookup_elem(linum_map_fd, &idx, &linum); + ASSERT_OK(err, "bpf_map_lookup_elem(linum_map_fd, READ_SK_DST_PORT_IDX)"); + ASSERT_EQ(linum, 0, "failure in read_sk_dst_port on line"); + memcpy(&srv_sk, &skel->bss->srv_sk, sizeof(srv_sk)); memcpy(&srv_tp, &skel->bss->srv_tp, sizeof(srv_tp)); memcpy(&cli_sk, &skel->bss->cli_sk, sizeof(cli_sk)); @@ -262,7 +278,7 @@ static void test(void) char buf[DATA_LEN]; /* Prepare listen_fd */ - listen_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0); + listen_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0xcafe, 0); /* start_server() has logged the error details */ if (CHECK_FAIL(listen_fd == -1)) goto done; @@ -330,8 +346,12 @@ done: void serial_test_sock_fields(void) { - struct bpf_link *egress_link = NULL, *ingress_link = NULL; int parent_cg_fd = -1, child_cg_fd = -1; + struct bpf_link *link; + + /* Use a dedicated netns to have a fixed listen port */ + if (!create_netns()) + return; /* Create a cgroup, get fd, and join it */ parent_cg_fd = test__join_cgroup(PARENT_CGROUP); @@ -352,15 +372,20 @@ void serial_test_sock_fields(void) if (CHECK(!skel, "test_sock_fields__open_and_load", "failed\n")) goto done; - egress_link = bpf_program__attach_cgroup(skel->progs.egress_read_sock_fields, - child_cg_fd); - if (!ASSERT_OK_PTR(egress_link, "attach_cgroup(egress)")) + link = bpf_program__attach_cgroup(skel->progs.egress_read_sock_fields, child_cg_fd); + if (!ASSERT_OK_PTR(link, "attach_cgroup(egress_read_sock_fields)")) + goto done; + skel->links.egress_read_sock_fields = link; + + link = bpf_program__attach_cgroup(skel->progs.ingress_read_sock_fields, child_cg_fd); + if (!ASSERT_OK_PTR(link, "attach_cgroup(ingress_read_sock_fields)")) goto done; + skel->links.ingress_read_sock_fields = link; - ingress_link = bpf_program__attach_cgroup(skel->progs.ingress_read_sock_fields, - child_cg_fd); - if (!ASSERT_OK_PTR(ingress_link, "attach_cgroup(ingress)")) + link = bpf_program__attach_cgroup(skel->progs.read_sk_dst_port, child_cg_fd); + if (!ASSERT_OK_PTR(link, "attach_cgroup(read_sk_dst_port")) goto done; + skel->links.read_sk_dst_port = link; linum_map_fd = bpf_map__fd(skel->maps.linum_map); sk_pkt_out_cnt_fd = bpf_map__fd(skel->maps.sk_pkt_out_cnt); @@ -369,8 +394,7 @@ void serial_test_sock_fields(void) test(); done: - bpf_link__destroy(egress_link); - bpf_link__destroy(ingress_link); + test_sock_fields__detach(skel); test_sock_fields__destroy(skel); if (child_cg_fd >= 0) close(child_cg_fd); diff --git a/tools/testing/selftests/bpf/progs/test_sock_fields.c b/tools/testing/selftests/bpf/progs/test_sock_fields.c index 81b57b9aaaea..246f1f001813 100644 --- a/tools/testing/selftests/bpf/progs/test_sock_fields.c +++ b/tools/testing/selftests/bpf/progs/test_sock_fields.c @@ -12,6 +12,7 @@ enum bpf_linum_array_idx { EGRESS_LINUM_IDX, INGRESS_LINUM_IDX, + READ_SK_DST_PORT_LINUM_IDX, __NR_BPF_LINUM_ARRAY_IDX, }; @@ -250,4 +251,44 @@ int ingress_read_sock_fields(struct __sk_buff *skb) return CG_OK; } +static __noinline bool sk_dst_port__load_word(struct bpf_sock *sk) +{ + __u32 *word = (__u32 *)&sk->dst_port; + return word[0] == bpf_htonl(0xcafe0000); +} + +static __noinline bool sk_dst_port__load_half(struct bpf_sock *sk) +{ + __u16 *half = (__u16 *)&sk->dst_port; + return half[0] == bpf_htons(0xcafe); +} + +static __noinline bool sk_dst_port__load_byte(struct bpf_sock *sk) +{ + __u8 *byte = (__u8 *)&sk->dst_port; + return byte[0] == 0xca && byte[1] == 0xfe; +} + +SEC("cgroup_skb/egress") +int read_sk_dst_port(struct __sk_buff *skb) +{ + __u32 linum, linum_idx; + struct bpf_sock *sk; + + linum_idx = READ_SK_DST_PORT_LINUM_IDX; + + sk = skb->sk; + if (!sk) + RET_LOG(); + + if (!sk_dst_port__load_word(sk)) + RET_LOG(); + if (!sk_dst_port__load_half(sk)) + RET_LOG(); + if (!sk_dst_port__load_byte(sk)) + RET_LOG(); + + return CG_OK; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/verifier/sock.c b/tools/testing/selftests/bpf/verifier/sock.c index ce13ece08d51..8c224eac93df 100644 --- a/tools/testing/selftests/bpf/verifier/sock.c +++ b/tools/testing/selftests/bpf/verifier/sock.c @@ -121,7 +121,25 @@ .result = ACCEPT, }, { - "sk_fullsock(skb->sk): sk->dst_port [narrow load]", + "sk_fullsock(skb->sk): sk->dst_port [word load] (backward compatibility)", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offsetof(struct __sk_buff, sk)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_EMIT_CALL(BPF_FUNC_sk_fullsock), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, offsetof(struct bpf_sock, dst_port)), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + .result = ACCEPT, +}, +{ + "sk_fullsock(skb->sk): sk->dst_port [half load]", .insns = { BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offsetof(struct __sk_buff, sk)), BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), @@ -139,7 +157,64 @@ .result = ACCEPT, }, { - "sk_fullsock(skb->sk): sk->dst_port [load 2nd byte]", + "sk_fullsock(skb->sk): sk->dst_port [half load] (invalid)", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offsetof(struct __sk_buff, sk)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_EMIT_CALL(BPF_FUNC_sk_fullsock), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_0, offsetof(struct bpf_sock, dst_port) + 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + .result = REJECT, + .errstr = "invalid sock access", +}, +{ + "sk_fullsock(skb->sk): sk->dst_port [byte load]", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offsetof(struct __sk_buff, sk)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_EMIT_CALL(BPF_FUNC_sk_fullsock), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_LDX_MEM(BPF_B, BPF_REG_2, BPF_REG_0, offsetof(struct bpf_sock, dst_port)), + BPF_LDX_MEM(BPF_B, BPF_REG_2, BPF_REG_0, offsetof(struct bpf_sock, dst_port) + 1), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + .result = ACCEPT, +}, +{ + "sk_fullsock(skb->sk): sk->dst_port [byte load] (invalid)", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offsetof(struct __sk_buff, sk)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_EMIT_CALL(BPF_FUNC_sk_fullsock), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, offsetof(struct bpf_sock, dst_port) + 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + .result = REJECT, + .errstr = "invalid sock access", +}, +{ + "sk_fullsock(skb->sk): past sk->dst_port [half load] (invalid)", .insns = { BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offsetof(struct __sk_buff, sk)), BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), @@ -149,7 +224,7 @@ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), - BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, offsetof(struct bpf_sock, dst_port) + 1), + BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_0, offsetofend(struct bpf_sock, dst_port)), BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, -- cgit From 2ed0dc5937d38f282841d22c5a5354ec264c7b8d Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Wed, 9 Feb 2022 19:43:33 +0100 Subject: selftests/bpf: Cover 4-byte load from remote_port in bpf_sk_lookup Extend the context access tests for sk_lookup prog to cover the surprising case of a 4-byte load from the remote_port field, where the expected value is actually shifted by 16 bits. Signed-off-by: Jakub Sitnicki Signed-off-by: Alexei Starovoitov Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20220209184333.654927-3-jakub@cloudflare.com --- tools/include/uapi/linux/bpf.h | 3 ++- tools/testing/selftests/bpf/progs/test_sk_lookup.c | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index a7f0ddedac1f..afe3d0d7f5f2 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -6453,7 +6453,8 @@ struct bpf_sk_lookup { __u32 protocol; /* IP protocol (IPPROTO_TCP, IPPROTO_UDP) */ __u32 remote_ip4; /* Network byte order */ __u32 remote_ip6[4]; /* Network byte order */ - __u32 remote_port; /* Network byte order */ + __be16 remote_port; /* Network byte order */ + __u16 :16; /* Zero padding */ __u32 local_ip4; /* Network byte order */ __u32 local_ip6[4]; /* Network byte order */ __u32 local_port; /* Host byte order */ diff --git a/tools/testing/selftests/bpf/progs/test_sk_lookup.c b/tools/testing/selftests/bpf/progs/test_sk_lookup.c index 83b0aaa52ef7..bf5b7caefdd0 100644 --- a/tools/testing/selftests/bpf/progs/test_sk_lookup.c +++ b/tools/testing/selftests/bpf/progs/test_sk_lookup.c @@ -392,6 +392,7 @@ int ctx_narrow_access(struct bpf_sk_lookup *ctx) { struct bpf_sock *sk; int err, family; + __u32 val_u32; bool v4; v4 = (ctx->family == AF_INET); @@ -418,6 +419,11 @@ int ctx_narrow_access(struct bpf_sk_lookup *ctx) if (LSW(ctx->remote_port, 0) != SRC_PORT) return SK_DROP; + /* Load from remote_port field with zero padding (backward compatibility) */ + val_u32 = *(__u32 *)&ctx->remote_port; + if (val_u32 != bpf_htonl(bpf_ntohs(SRC_PORT) << 16)) + return SK_DROP; + /* Narrow loads from local_port field. Expect DST_PORT. */ if (LSB(ctx->local_port, 0) != ((DST_PORT >> 0) & 0xff) || LSB(ctx->local_port, 1) != ((DST_PORT >> 8) & 0xff) || -- cgit From aca8af3c2e8cb57662e6035c0ccb3c111a11d97a Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 13 Jan 2022 09:10:52 +0000 Subject: perf cs-etm: Update deduction of TRCCONFIGR register for branch broadcast Now that a config flag for branch broadcast has been added, take it into account when trying to deduce what the driver would have programmed the TRCCONFIGR register to. Reviewed-by: Leo Yan Reviewed-by: Mike Leach Reviewed-by: Suzuki Poulouse Signed-off-by: James Clark Cc: Alexander Shishkin Cc: Jiri Olsa Cc: John Garry Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Will Deacon Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-doc@vger.kernel.org Link: https://lore.kernel.org/r/20220113091056.1297982-4-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/coresight-pmu.h | 2 ++ tools/perf/arch/arm/util/cs-etm.c | 3 +++ 2 files changed, 5 insertions(+) (limited to 'tools/include') diff --git a/tools/include/linux/coresight-pmu.h b/tools/include/linux/coresight-pmu.h index 4ac5c081af93..6c2fd6cc5a98 100644 --- a/tools/include/linux/coresight-pmu.h +++ b/tools/include/linux/coresight-pmu.h @@ -18,6 +18,7 @@ * ETMv3.5/PTM doesn't define ETMCR config bits with prefix "ETM3_" and * directly use below macros as config bits. */ +#define ETM_OPT_BRANCH_BROADCAST 8 #define ETM_OPT_CYCACC 12 #define ETM_OPT_CTXTID 14 #define ETM_OPT_CTXTID2 15 @@ -25,6 +26,7 @@ #define ETM_OPT_RETSTK 29 /* ETMv4 CONFIGR programming bits for the ETM OPTs */ +#define ETM4_CFG_BIT_BB 3 #define ETM4_CFG_BIT_CYCACC 4 #define ETM4_CFG_BIT_CTXTID 6 #define ETM4_CFG_BIT_VMID 7 diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 2e8b2c4365a0..cbc555245959 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -510,6 +510,9 @@ static u64 cs_etmv4_get_config(struct auxtrace_record *itr) if (config_opts & BIT(ETM_OPT_CTXTID2)) config |= BIT(ETM4_CFG_BIT_VMID) | BIT(ETM4_CFG_BIT_VMID_OPT); + if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST)) + config |= BIT(ETM4_CFG_BIT_BB); + return config; } -- cgit From aa0eab8639ff0fb1edf18b8616e6ae2c38ca5854 Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:00 +0100 Subject: tools: Move gfp.h and slab.h from radix-tree to lib Merge radix-tree definitions from gfp.h and slab.h with these in tools/lib, so they can be used in other test suites. Fix style issues in slab.h. Update radix-tree test files. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/b76ddb8a12fdf9870b55c1401213e44f5e0d0da3.1643796665.git.karolinadrobnik@gmail.com --- tools/include/linux/gfp.h | 28 ++++++++++++++++++++++++++ tools/include/linux/slab.h | 28 ++++++++++++++++++++++++++ tools/lib/slab.c | 38 +++++++++++++++++++++++++++++++++++ tools/testing/radix-tree/Makefile | 3 ++- tools/testing/radix-tree/linux.c | 27 ------------------------- tools/testing/radix-tree/linux/gfp.h | 33 ------------------------------ tools/testing/radix-tree/linux/slab.h | 27 ------------------------- 7 files changed, 96 insertions(+), 88 deletions(-) create mode 100644 tools/include/linux/slab.h create mode 100644 tools/lib/slab.c delete mode 100644 tools/testing/radix-tree/linux/gfp.h delete mode 100644 tools/testing/radix-tree/linux/slab.h (limited to 'tools/include') diff --git a/tools/include/linux/gfp.h b/tools/include/linux/gfp.h index 22030756fbc0..b238dbc9eb85 100644 --- a/tools/include/linux/gfp.h +++ b/tools/include/linux/gfp.h @@ -1,4 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _TOOLS_INCLUDE_LINUX_GFP_H #define _TOOLS_INCLUDE_LINUX_GFP_H +#include + +#define __GFP_BITS_SHIFT 26 +#define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) + +#define __GFP_HIGH 0x20u +#define __GFP_IO 0x40u +#define __GFP_FS 0x80u +#define __GFP_NOWARN 0x200u +#define __GFP_ZERO 0x8000u +#define __GFP_ATOMIC 0x80000u +#define __GFP_ACCOUNT 0x100000u +#define __GFP_DIRECT_RECLAIM 0x400000u +#define __GFP_KSWAPD_RECLAIM 0x2000000u + +#define __GFP_RECLAIM (__GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM) + +#define GFP_ZONEMASK 0x0fu +#define GFP_ATOMIC (__GFP_HIGH | __GFP_ATOMIC | __GFP_KSWAPD_RECLAIM) +#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) +#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) + +static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags) +{ + return !!(gfp_flags & __GFP_DIRECT_RECLAIM); +} + #endif /* _TOOLS_INCLUDE_LINUX_GFP_H */ diff --git a/tools/include/linux/slab.h b/tools/include/linux/slab.h new file mode 100644 index 000000000000..07d7930d4003 --- /dev/null +++ b/tools/include/linux/slab.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_SLAB_H +#define _TOOLS_SLAB_H + +#include +#include + +#define SLAB_PANIC 2 +#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ + +#define kzalloc_node(size, flags, node) kmalloc(size, flags) + +void *kmalloc(size_t size, gfp_t gfp); +void kfree(void *p); + +static inline void *kzalloc(size_t size, gfp_t gfp) +{ + return kmalloc(size, gfp | __GFP_ZERO); +} + +void *kmem_cache_alloc(struct kmem_cache *cachep, int flags); +void kmem_cache_free(struct kmem_cache *cachep, void *objp); + +struct kmem_cache *kmem_cache_create(const char *name, unsigned int size, + unsigned int align, unsigned int flags, + void (*ctor)(void *)); + +#endif /* _TOOLS_SLAB_H */ diff --git a/tools/lib/slab.c b/tools/lib/slab.c new file mode 100644 index 000000000000..959997fb0652 --- /dev/null +++ b/tools/lib/slab.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include +#include +#include +#include + +int kmalloc_nr_allocated; +int kmalloc_verbose; + +void *kmalloc(size_t size, gfp_t gfp) +{ + void *ret; + + if (!(gfp & __GFP_DIRECT_RECLAIM)) + return NULL; + + ret = malloc(size); + uatomic_inc(&kmalloc_nr_allocated); + if (kmalloc_verbose) + printf("Allocating %p from malloc\n", ret); + if (gfp & __GFP_ZERO) + memset(ret, 0, size); + return ret; +} + +void kfree(void *p) +{ + if (!p) + return; + uatomic_dec(&kmalloc_nr_allocated); + if (kmalloc_verbose) + printf("Freeing %p to malloc\n", p); + free(p); +} diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile index aa6abfe0749c..c4ea4fbb0bfc 100644 --- a/tools/testing/radix-tree/Makefile +++ b/tools/testing/radix-tree/Makefile @@ -5,7 +5,8 @@ CFLAGS += -I. -I../../include -g -Og -Wall -D_LGPL_SOURCE -fsanitize=address \ LDFLAGS += -fsanitize=address -fsanitize=undefined LDLIBS+= -lpthread -lurcu TARGETS = main idr-test multiorder xarray -CORE_OFILES := xarray.o radix-tree.o idr.o linux.o test.o find_bit.o bitmap.o +CORE_OFILES := xarray.o radix-tree.o idr.o linux.o test.o find_bit.o bitmap.o \ + slab.o OFILES = main.o $(CORE_OFILES) regression1.o regression2.o regression3.o \ regression4.o tag_check.o multiorder.o idr-test.o iteration_check.o \ iteration_check_2.o benchmark.o diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c index 2d9c59df60de..81539f543954 100644 --- a/tools/testing/radix-tree/linux.c +++ b/tools/testing/radix-tree/linux.c @@ -14,7 +14,6 @@ int nr_allocated; int preempt_count; -int kmalloc_verbose; int test_verbose; struct kmem_cache { @@ -78,32 +77,6 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp) pthread_mutex_unlock(&cachep->lock); } -void *kmalloc(size_t size, gfp_t gfp) -{ - void *ret; - - if (!(gfp & __GFP_DIRECT_RECLAIM)) - return NULL; - - ret = malloc(size); - uatomic_inc(&nr_allocated); - if (kmalloc_verbose) - printf("Allocating %p from malloc\n", ret); - if (gfp & __GFP_ZERO) - memset(ret, 0, size); - return ret; -} - -void kfree(void *p) -{ - if (!p) - return; - uatomic_dec(&nr_allocated); - if (kmalloc_verbose) - printf("Freeing %p to malloc\n", p); - free(p); -} - struct kmem_cache * kmem_cache_create(const char *name, unsigned int size, unsigned int align, unsigned int flags, void (*ctor)(void *)) diff --git a/tools/testing/radix-tree/linux/gfp.h b/tools/testing/radix-tree/linux/gfp.h deleted file mode 100644 index 32159c08a52e..000000000000 --- a/tools/testing/radix-tree/linux/gfp.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _GFP_H -#define _GFP_H - -#include - -#define __GFP_BITS_SHIFT 26 -#define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) - -#define __GFP_HIGH 0x20u -#define __GFP_IO 0x40u -#define __GFP_FS 0x80u -#define __GFP_NOWARN 0x200u -#define __GFP_ZERO 0x8000u -#define __GFP_ATOMIC 0x80000u -#define __GFP_ACCOUNT 0x100000u -#define __GFP_DIRECT_RECLAIM 0x400000u -#define __GFP_KSWAPD_RECLAIM 0x2000000u - -#define __GFP_RECLAIM (__GFP_DIRECT_RECLAIM|__GFP_KSWAPD_RECLAIM) - -#define GFP_ZONEMASK 0x0fu -#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) -#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) -#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) - - -static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags) -{ - return !!(gfp_flags & __GFP_DIRECT_RECLAIM); -} - -#endif diff --git a/tools/testing/radix-tree/linux/slab.h b/tools/testing/radix-tree/linux/slab.h deleted file mode 100644 index 2958830ce4d7..000000000000 --- a/tools/testing/radix-tree/linux/slab.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef SLAB_H -#define SLAB_H - -#include -#include - -#define SLAB_HWCACHE_ALIGN 1 -#define SLAB_PANIC 2 -#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ - -void *kmalloc(size_t size, gfp_t); -void kfree(void *); - -static inline void *kzalloc(size_t size, gfp_t gfp) -{ - return kmalloc(size, gfp | __GFP_ZERO); -} - -void *kmem_cache_alloc(struct kmem_cache *cachep, int flags); -void kmem_cache_free(struct kmem_cache *cachep, void *objp); - -struct kmem_cache *kmem_cache_create(const char *name, unsigned int size, - unsigned int align, unsigned int flags, - void (*ctor)(void *)); - -#endif /* SLAB_H */ -- cgit From 884ee1e585ca01b47f66c7e5b6902c62d1af77a3 Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:01 +0100 Subject: tools/include: Add phys_addr_t to types.h Update types.h file to include phys_addr_t typedef so it can be used in testing. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/f0b42be7d1fe2eb9cd299532676d9df2df9ef089.1643796665.git.karolinadrobnik@gmail.com --- tools/include/linux/types.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/include') diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h index 6e14a533ab4e..35cedaf191e8 100644 --- a/tools/include/linux/types.h +++ b/tools/include/linux/types.h @@ -64,6 +64,12 @@ typedef __u64 __bitwise __be64; typedef __u16 __bitwise __sum16; typedef __u32 __bitwise __wsum; +#ifdef CONFIG_PHYS_ADDR_T_64BIT +typedef u64 phys_addr_t; +#else +typedef u32 phys_addr_t; +#endif + typedef struct { int counter; } atomic_t; -- cgit From 5cf67a6051ea2558fd7c3d39c5a808db73073e9d Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:02 +0100 Subject: tools/include: Add _RET_IP_ and math definitions to kernel.h Add max_t, min_t and clamp functions, together with _RET_IP_ definition, so they can be used in testing. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/230fea382cb1e1659cdd52a55201854d38a0a149.1643796665.git.karolinadrobnik@gmail.com --- tools/include/linux/kernel.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/include') diff --git a/tools/include/linux/kernel.h b/tools/include/linux/kernel.h index 9701e8307db0..4b0673bf52c2 100644 --- a/tools/include/linux/kernel.h +++ b/tools/include/linux/kernel.h @@ -15,6 +15,8 @@ #define UINT_MAX (~0U) #endif +#define _RET_IP_ ((unsigned long)__builtin_return_address(0)) + #define PERF_ALIGN(x, a) __PERF_ALIGN_MASK(x, (typeof(x))(a)-1) #define __PERF_ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) @@ -51,6 +53,10 @@ _min1 < _min2 ? _min1 : _min2; }) #endif +#define max_t(type, x, y) max((type)x, (type)y) +#define min_t(type, x, y) min((type)x, (type)y) +#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi) + #ifndef BUG_ON #ifdef NDEBUG #define BUG_ON(cond) do { if (cond) {} } while (0) -- cgit From 9c07af207c65e6fa8063d1105356568d8b03c536 Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:03 +0100 Subject: tools/include: Update atomic definitions Add atomic_long_set function to atomic.h and atomic_long_t type to types.h so they can be used in testing. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/082fde69debc36bfc56cdb413d847dcd6b1e36dd.1643796665.git.karolinadrobnik@gmail.com --- tools/include/linux/atomic.h | 2 ++ tools/include/linux/types.h | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'tools/include') diff --git a/tools/include/linux/atomic.h b/tools/include/linux/atomic.h index 00a6c4ca562b..01907b33537e 100644 --- a/tools/include/linux/atomic.h +++ b/tools/include/linux/atomic.h @@ -4,6 +4,8 @@ #include +void atomic_long_set(atomic_long_t *v, long i); + /* atomic_cmpxchg_relaxed */ #ifndef atomic_cmpxchg_relaxed #define atomic_cmpxchg_relaxed atomic_cmpxchg diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h index 35cedaf191e8..5908e58c3598 100644 --- a/tools/include/linux/types.h +++ b/tools/include/linux/types.h @@ -74,6 +74,10 @@ typedef struct { int counter; } atomic_t; +typedef struct { + long counter; +} atomic_long_t; + #ifndef __aligned_u64 # define __aligned_u64 __u64 __attribute__((aligned(8))) #endif -- cgit From 2473bc35ba554003cdda8a3a0124f35433590fe7 Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:04 +0100 Subject: tools/include: Add mm.h file Add a stubbed mm.h file with dummy page-related definitions, memory alignment and physical to virtual address conversions, so they can be used in testing. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/e8b83d96fec95f3556e80f001d9d5cbe18b8ad5f.1643796665.git.karolinadrobnik@gmail.com --- tools/include/linux/mm.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tools/include/linux/mm.h (limited to 'tools/include') diff --git a/tools/include/linux/mm.h b/tools/include/linux/mm.h new file mode 100644 index 000000000000..a03d9bba5151 --- /dev/null +++ b/tools/include/linux/mm.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_LINUX_MM_H +#define _TOOLS_LINUX_MM_H + +#include +#include + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) + +#define PHYS_ADDR_MAX (~(phys_addr_t)0) + +#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) +#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) +#define ALIGN_DOWN(x, a) __ALIGN_KERNEL((x) - ((a) - 1), (a)) + +#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) + +#define __va(x) ((void *)((unsigned long)(x))) +#define __pa(x) ((unsigned long)(x)) + +#define pfn_to_page(pfn) ((void *)((pfn) * PAGE_SIZE)) + +#define phys_to_virt phys_to_virt +static inline void *phys_to_virt(unsigned long address) +{ + return __va(address); +} + +void reserve_bootmem_region(phys_addr_t start, phys_addr_t end); + +static inline void totalram_pages_inc(void) +{ +} + +static inline void totalram_pages_add(long count) +{ +} + +#endif -- cgit From 1fef073b71c3f22e2328872324fdb187f4fb7d7d Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:05 +0100 Subject: tools/include: Add cache.h stub Add a dummy version of the cache header. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/5e02865094aaf56dd30772722799e53f4130ebc8.1643796665.git.karolinadrobnik@gmail.com --- tools/include/linux/cache.h | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tools/include/linux/cache.h (limited to 'tools/include') diff --git a/tools/include/linux/cache.h b/tools/include/linux/cache.h new file mode 100644 index 000000000000..9e9d585f0b9d --- /dev/null +++ b/tools/include/linux/cache.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_LINUX_CACHE_H +#define _TOOLS_LINUX_CACHE_H + +#define L1_CACHE_SHIFT 5 +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#define SMP_CACHE_BYTES L1_CACHE_BYTES + +#endif -- cgit From 93f4e871e7e0fd0269e27f5122a70a39d8105924 Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:06 +0100 Subject: tools/include: Add io.h stub Add a dummy io.h header. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/3e8d42cbd01382d956d393cf3bb2a6d639dfdd97.1643796665.git.karolinadrobnik@gmail.com --- tools/include/linux/io.h | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tools/include/linux/io.h (limited to 'tools/include') diff --git a/tools/include/linux/io.h b/tools/include/linux/io.h new file mode 100644 index 000000000000..e129871fe661 --- /dev/null +++ b/tools/include/linux/io.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_IO_H +#define _TOOLS_IO_H + +#endif -- cgit From a2e3fe5f24f90e2bd98fa8bfabbf55962080b7b4 Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:07 +0100 Subject: tools/include: Add pfn.h stub Add a stubbed pfn header with definitions used in testing. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/1bdc02125963f945bf90dd8cb37c404cc0688af2.1643796665.git.karolinadrobnik@gmail.com --- tools/include/linux/pfn.h | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tools/include/linux/pfn.h (limited to 'tools/include') diff --git a/tools/include/linux/pfn.h b/tools/include/linux/pfn.h new file mode 100644 index 000000000000..7512a58189eb --- /dev/null +++ b/tools/include/linux/pfn.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_LINUX_PFN_H_ +#define _TOOLS_LINUX_PFN_H_ + +#include + +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT) +#endif -- cgit From 62183279ad2f52d36b40365eb3a27c7a4a2284f8 Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:08 +0100 Subject: tools/include: Add debugfs.h stub Add a dummy debugfs.h header. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/80fceff27934094873cc3f0656d22e802dfcce78.1643796665.git.karolinadrobnik@gmail.com --- tools/include/linux/debugfs.h | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tools/include/linux/debugfs.h (limited to 'tools/include') diff --git a/tools/include/linux/debugfs.h b/tools/include/linux/debugfs.h new file mode 100644 index 000000000000..4ba06140b1be --- /dev/null +++ b/tools/include/linux/debugfs.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_DEBUGFS_H +#define _TOOLS_DEBUGFS_H + +#endif -- cgit From 16802e55dea9534c18a30bd8eeefea8a06337916 Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Wed, 2 Feb 2022 12:03:09 +0100 Subject: memblock tests: Add skeleton of the memblock simulator Add basic project files, together with local stubs of required headers. Update tools/include/slab.h to include definitions used by memblock. Signed-off-by: Karolina Drobnik Signed-off-by: Mike Rapoport Link: https://lore.kernel.org/r/d296fceb023a04b316a31fbff9acf1e76ac684e4.1643796665.git.karolinadrobnik@gmail.com --- MAINTAINERS | 1 + tools/include/linux/slab.h | 10 +++++ tools/testing/memblock/.gitignore | 4 ++ tools/testing/memblock/Makefile | 52 +++++++++++++++++++++++++ tools/testing/memblock/asm/dma.h | 5 +++ tools/testing/memblock/internal.h | 12 ++++++ tools/testing/memblock/lib/slab.c | 9 +++++ tools/testing/memblock/linux/init.h | 34 ++++++++++++++++ tools/testing/memblock/linux/kernel.h | 12 ++++++ tools/testing/memblock/linux/kmemleak.h | 18 +++++++++ tools/testing/memblock/linux/memory_hotplug.h | 19 +++++++++ tools/testing/memblock/linux/mmzone.h | 35 +++++++++++++++++ tools/testing/memblock/linux/printk.h | 25 ++++++++++++ tools/testing/memblock/main.c | 6 +++ tools/testing/memblock/mmzone.c | 20 ++++++++++ tools/testing/memblock/scripts/Makefile.include | 17 ++++++++ 16 files changed, 279 insertions(+) create mode 100644 tools/testing/memblock/.gitignore create mode 100644 tools/testing/memblock/Makefile create mode 100644 tools/testing/memblock/asm/dma.h create mode 100644 tools/testing/memblock/internal.h create mode 100644 tools/testing/memblock/lib/slab.c create mode 100644 tools/testing/memblock/linux/init.h create mode 100644 tools/testing/memblock/linux/kernel.h create mode 100644 tools/testing/memblock/linux/kmemleak.h create mode 100644 tools/testing/memblock/linux/memory_hotplug.h create mode 100644 tools/testing/memblock/linux/mmzone.h create mode 100644 tools/testing/memblock/linux/printk.h create mode 100644 tools/testing/memblock/main.c create mode 100644 tools/testing/memblock/mmzone.c create mode 100644 tools/testing/memblock/scripts/Makefile.include (limited to 'tools/include') diff --git a/MAINTAINERS b/MAINTAINERS index fca970a46e77..38502bf0231a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12423,6 +12423,7 @@ S: Maintained F: Documentation/core-api/boot-time-mm.rst F: include/linux/memblock.h F: mm/memblock.c +F: tools/testing/memblock/ MEMORY CONTROLLER DRIVERS M: Krzysztof Kozlowski diff --git a/tools/include/linux/slab.h b/tools/include/linux/slab.h index 07d7930d4003..f41d8a0eb1a4 100644 --- a/tools/include/linux/slab.h +++ b/tools/include/linux/slab.h @@ -13,6 +13,16 @@ void *kmalloc(size_t size, gfp_t gfp); void kfree(void *p); +bool slab_is_available(void); + +enum slab_state { + DOWN, + PARTIAL, + PARTIAL_NODE, + UP, + FULL +}; + static inline void *kzalloc(size_t size, gfp_t gfp) { return kmalloc(size, gfp | __GFP_ZERO); diff --git a/tools/testing/memblock/.gitignore b/tools/testing/memblock/.gitignore new file mode 100644 index 000000000000..654338e0be52 --- /dev/null +++ b/tools/testing/memblock/.gitignore @@ -0,0 +1,4 @@ +main +memblock.c +linux/memblock.h +asm/cmpxchg.h diff --git a/tools/testing/memblock/Makefile b/tools/testing/memblock/Makefile new file mode 100644 index 000000000000..e43ed9de9bcf --- /dev/null +++ b/tools/testing/memblock/Makefile @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Memblock simulator requires AddressSanitizer (libasan) and liburcu development +# packages installed +CFLAGS += -I. -I../../include -Wall -O2 -fsanitize=address \ + -fsanitize=undefined -D CONFIG_PHYS_ADDR_T_64BIT +LDFLAGS += -fsanitize=address -fsanitize=undefined +TARGETS = main +OFILES = main.o memblock.o lib/slab.o mmzone.o slab.o +EXTR_SRC = ../../../mm/memblock.c + +ifeq ($(BUILD), 32) + CFLAGS += -m32 + LDFLAGS += -m32 +endif + +# Process user parameters +include scripts/Makefile.include + +main: $(OFILES) + +$(OFILES): include + +include: ../../../include/linux/memblock.h ../../include/linux/*.h \ + ../../include/asm/*.h + + @mkdir -p linux + test -L linux/memblock.h || ln -s ../../../../include/linux/memblock.h linux/memblock.h + test -L asm/cmpxchg.h || ln -s ../../../arch/x86/include/asm/cmpxchg.h asm/cmpxchg.h + +memblock.c: $(EXTR_SRC) + test -L memblock.c || ln -s $(EXTR_SRC) memblock.c + +clean: + $(RM) $(TARGETS) $(OFILES) linux/memblock.h memblock.c asm/cmpxchg.h + +help: + @echo 'Memblock simulator' + @echo '' + @echo 'Available targets:' + @echo ' main - Build the memblock simulator' + @echo ' clean - Remove generated files and symlinks in the directory' + @echo '' + @echo 'Configuration:' + @echo ' make NUMA=1 - simulate enabled NUMA' + @echo ' make MOVABLE_NODE=1 - override `movable_node_is_enabled`' + @echo ' definition to simulate movable NUMA nodes' + @echo ' make 32BIT_PHYS_ADDR_T=1 - Use 32 bit physical addresses' + +vpath %.c ../../lib + +.PHONY: clean include help diff --git a/tools/testing/memblock/asm/dma.h b/tools/testing/memblock/asm/dma.h new file mode 100644 index 000000000000..13ff8e5d22ef --- /dev/null +++ b/tools/testing/memblock/asm/dma.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_DMA_H +#define _TOOLS_DMA_H + +#endif diff --git a/tools/testing/memblock/internal.h b/tools/testing/memblock/internal.h new file mode 100644 index 000000000000..94b52a8718b5 --- /dev/null +++ b/tools/testing/memblock/internal.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _MM_INTERNAL_H +#define _MM_INTERNAL_H + +struct page {}; + +void memblock_free_pages(struct page *page, unsigned long pfn, + unsigned int order) +{ +} + +#endif diff --git a/tools/testing/memblock/lib/slab.c b/tools/testing/memblock/lib/slab.c new file mode 100644 index 000000000000..6be6020328fb --- /dev/null +++ b/tools/testing/memblock/lib/slab.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +enum slab_state slab_state; + +bool slab_is_available(void) +{ + return slab_state >= UP; +} diff --git a/tools/testing/memblock/linux/init.h b/tools/testing/memblock/linux/init.h new file mode 100644 index 000000000000..828e0ee0bc6c --- /dev/null +++ b/tools/testing/memblock/linux/init.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_INIT_H +#define _LINUX_INIT_H + +#include +#include +#include + +#define __section(section) __attribute__((__section__(section))) + +#define __initconst +#define __meminit +#define __meminitdata +#define __refdata +#define __initdata + +struct obs_kernel_param { + const char *str; + int (*setup_func)(char *st); + int early; +}; + +#define __setup_param(str, unique_id, fn, early) \ + static const char __setup_str_##unique_id[] __initconst \ + __aligned(1) = str; \ + static struct obs_kernel_param __setup_##unique_id \ + __used __section(".init.setup") \ + __aligned(__alignof__(struct obs_kernel_param)) = \ + { __setup_str_##unique_id, fn, early } + +#define early_param(str, fn) \ + __setup_param(str, fn, fn, 1) + +#endif diff --git a/tools/testing/memblock/linux/kernel.h b/tools/testing/memblock/linux/kernel.h new file mode 100644 index 000000000000..d2f148bd8902 --- /dev/null +++ b/tools/testing/memblock/linux/kernel.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _MEMBLOCK_LINUX_KERNEL_H +#define _MEMBLOCK_LINUX_KERNEL_H + +#include <../../include/linux/kernel.h> +#include +#include +#include +#include +#include + +#endif diff --git a/tools/testing/memblock/linux/kmemleak.h b/tools/testing/memblock/linux/kmemleak.h new file mode 100644 index 000000000000..462f8c5e8aa0 --- /dev/null +++ b/tools/testing/memblock/linux/kmemleak.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _KMEMLEAK_H +#define _KMEMLEAK_H + +static inline void kmemleak_free_part_phys(phys_addr_t phys, size_t size) +{ +} + +static inline void kmemleak_alloc_phys(phys_addr_t phys, size_t size, + int min_count, gfp_t gfp) +{ +} + +static inline void dump_stack(void) +{ +} + +#endif diff --git a/tools/testing/memblock/linux/memory_hotplug.h b/tools/testing/memblock/linux/memory_hotplug.h new file mode 100644 index 000000000000..47988765a219 --- /dev/null +++ b/tools/testing/memblock/linux/memory_hotplug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_MEMORY_HOTPLUG_H +#define _LINUX_MEMORY_HOTPLUG_H + +#include +#include +#include +#include + +static inline bool movable_node_is_enabled(void) +{ +#ifdef MOVABLE_NODE + return true; +#else + return false; +#endif +} + +#endif diff --git a/tools/testing/memblock/linux/mmzone.h b/tools/testing/memblock/linux/mmzone.h new file mode 100644 index 000000000000..7c2eb5c9bb54 --- /dev/null +++ b/tools/testing/memblock/linux/mmzone.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_MMZONE_H +#define _TOOLS_MMZONE_H + +#include + +struct pglist_data *first_online_pgdat(void); +struct pglist_data *next_online_pgdat(struct pglist_data *pgdat); + +#define for_each_online_pgdat(pgdat) \ + for (pgdat = first_online_pgdat(); \ + pgdat; \ + pgdat = next_online_pgdat(pgdat)) + +enum zone_type { + __MAX_NR_ZONES +}; + +#define MAX_NR_ZONES __MAX_NR_ZONES +#define MAX_ORDER 11 +#define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1)) + +#define pageblock_order (MAX_ORDER - 1) +#define pageblock_nr_pages BIT(pageblock_order) + +struct zone { + atomic_long_t managed_pages; +}; + +typedef struct pglist_data { + struct zone node_zones[MAX_NR_ZONES]; + +} pg_data_t; + +#endif diff --git a/tools/testing/memblock/linux/printk.h b/tools/testing/memblock/linux/printk.h new file mode 100644 index 000000000000..61af424d8c6c --- /dev/null +++ b/tools/testing/memblock/linux/printk.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _PRINTK_H +#define _PRINTK_H + +#include +#include + +/* + * memblock_dbg is called with u64 arguments that don't match the "%llu" + * specifier in printf. This results in warnings that cannot be fixed without + * modifying memblock.c, which we wish to avoid. As these messaged are not used + * in testing anyway, the mismatch can be ignored. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#define printk printf +#pragma GCC diagnostic push + +#define pr_info printk +#define pr_debug printk +#define pr_cont printk +#define pr_err printk +#define pr_warn printk + +#endif diff --git a/tools/testing/memblock/main.c b/tools/testing/memblock/main.c new file mode 100644 index 000000000000..62958da35d0f --- /dev/null +++ b/tools/testing/memblock/main.c @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +int main(int argc, char **argv) +{ + return 0; +} diff --git a/tools/testing/memblock/mmzone.c b/tools/testing/memblock/mmzone.c new file mode 100644 index 000000000000..7b0909e8b759 --- /dev/null +++ b/tools/testing/memblock/mmzone.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include + +struct pglist_data *first_online_pgdat(void) +{ + return NULL; +} + +struct pglist_data *next_online_pgdat(struct pglist_data *pgdat) +{ + return NULL; +} + +void reserve_bootmem_region(phys_addr_t start, phys_addr_t end) +{ +} + +void atomic_long_set(atomic_long_t *v, long i) +{ +} diff --git a/tools/testing/memblock/scripts/Makefile.include b/tools/testing/memblock/scripts/Makefile.include new file mode 100644 index 000000000000..699b0d6cda07 --- /dev/null +++ b/tools/testing/memblock/scripts/Makefile.include @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0 +# Definitions for user-provided arguments + +# Simulate CONFIG_NUMA=y +ifeq ($(NUMA), 1) + CFLAGS += -D CONFIG_NUMA +endif + +# Simulate movable NUMA memory regions +ifeq ($(MOVABLE_NODE), 1) + CFLAGS += -D MOVABLE_NODE +endif + +# Use 32 bit physical addresses +ifeq ($(32BIT_PHYS_ADDR_T), 1) + CFLAGS += -U CONFIG_PHYS_ADDR_T_64BIT +endif -- cgit From 129e3c1bab24d27d0fa6e505a472345a92d7a2b0 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Mon, 21 Feb 2022 13:54:57 +0800 Subject: bonding: add new option ns_ip6_target This patch add a new bonding option ns_ip6_target, which correspond to the arp_ip_target. With this we set IPv6 targets and send IPv6 NS request to determine the health of the link. For other related options like the validation, we still use arp_validate, and will change to ns_validate later. Note: the sysfs configuration support was removed based on https://lore.kernel.org/netdev/8863.1645071997@famine Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller --- Documentation/networking/bonding.rst | 11 ++++++ drivers/net/bonding/bond_netlink.c | 59 +++++++++++++++++++++++++++++ drivers/net/bonding/bond_options.c | 72 ++++++++++++++++++++++++++++++++++++ include/net/bond_options.h | 4 ++ include/net/bonding.h | 7 ++++ include/uapi/linux/if_link.h | 1 + tools/include/uapi/linux/if_link.h | 1 + 7 files changed, 155 insertions(+) (limited to 'tools/include') diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst index ab98373535ea..525e6842dd33 100644 --- a/Documentation/networking/bonding.rst +++ b/Documentation/networking/bonding.rst @@ -313,6 +313,17 @@ arp_ip_target maximum number of targets that can be specified is 16. The default value is no IP addresses. +ns_ip6_target + + Specifies the IPv6 addresses to use as IPv6 monitoring peers when + arp_interval is > 0. These are the targets of the NS request + sent to determine the health of the link to the targets. + Specify these values in ffff:ffff::ffff:ffff format. Multiple IPv6 + addresses must be separated by a comma. At least one IPv6 + address must be given for NS/NA monitoring to function. The + maximum number of targets that can be specified is 16. The + default value is no IPv6 addresses. + arp_validate Specifies whether or not ARP probes and replies should be diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 1007bf6d385d..f427fa1737c7 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -14,6 +14,7 @@ #include #include #include +#include static size_t bond_get_slave_size(const struct net_device *bond_dev, const struct net_device *slave_dev) @@ -111,6 +112,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_TLB_DYNAMIC_LB] = { .type = NLA_U8 }, [IFLA_BOND_PEER_NOTIF_DELAY] = { .type = NLA_U32 }, [IFLA_BOND_MISSED_MAX] = { .type = NLA_U8 }, + [IFLA_BOND_NS_IP6_TARGET] = { .type = NLA_NESTED }, }; static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { @@ -272,6 +274,40 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], if (err) return err; } +#if IS_ENABLED(CONFIG_IPV6) + if (data[IFLA_BOND_NS_IP6_TARGET]) { + struct nlattr *attr; + int i = 0, rem; + + bond_option_ns_ip6_targets_clear(bond); + nla_for_each_nested(attr, data[IFLA_BOND_NS_IP6_TARGET], rem) { + struct in6_addr addr6; + + if (nla_len(attr) < sizeof(addr6)) { + NL_SET_ERR_MSG(extack, "Invalid IPv6 address"); + return -EINVAL; + } + + addr6 = nla_get_in6_addr(attr); + + if (ipv6_addr_type(&addr6) & IPV6_ADDR_LINKLOCAL) { + NL_SET_ERR_MSG(extack, "Invalid IPv6 addr6"); + return -EINVAL; + } + + bond_opt_initextra(&newval, &addr6, sizeof(addr6)); + err = __bond_opt_set(bond, BOND_OPT_NS_TARGETS, + &newval); + if (err) + break; + i++; + } + if (i == 0 && bond->params.arp_interval) + netdev_warn(bond->dev, "Removing last ns target with arp_interval on\n"); + if (err) + return err; + } +#endif if (data[IFLA_BOND_ARP_VALIDATE]) { int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]); @@ -526,6 +562,9 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u8)) + /* IFLA_BOND_TLB_DYNAMIC_LB */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_PEER_NOTIF_DELAY */ nla_total_size(sizeof(u8)) + /* IFLA_BOND_MISSED_MAX */ + /* IFLA_BOND_NS_IP6_TARGET */ + nla_total_size(sizeof(struct nlattr)) + + nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS + 0; } @@ -603,6 +642,26 @@ static int bond_fill_info(struct sk_buff *skb, bond->params.arp_all_targets)) goto nla_put_failure; +#if IS_ENABLED(CONFIG_IPV6) + targets = nla_nest_start(skb, IFLA_BOND_NS_IP6_TARGET); + if (!targets) + goto nla_put_failure; + + targets_added = 0; + for (i = 0; i < BOND_MAX_NS_TARGETS; i++) { + if (!ipv6_addr_any(&bond->params.ns_targets[i])) { + if (nla_put_in6_addr(skb, i, &bond->params.ns_targets[i])) + goto nla_put_failure; + targets_added = 1; + } + } + + if (targets_added) + nla_nest_end(skb, targets); + else + nla_nest_cancel(skb, targets); +#endif + primary = rtnl_dereference(bond->primary_slave); if (primary && nla_put_u32(skb, IFLA_BOND_PRIMARY, primary->dev->ifindex)) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index ab575135b626..64f7db2627ce 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -34,6 +34,10 @@ static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); static int bond_option_arp_ip_targets_set(struct bonding *bond, const struct bond_opt_value *newval); +#if IS_ENABLED(CONFIG_IPV6) +static int bond_option_ns_ip6_targets_set(struct bonding *bond, + const struct bond_opt_value *newval); +#endif static int bond_option_arp_validate_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_arp_all_targets_set(struct bonding *bond, @@ -295,6 +299,15 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .flags = BOND_OPTFLAG_RAWVAL, .set = bond_option_arp_ip_targets_set }, +#if IS_ENABLED(CONFIG_IPV6) + [BOND_OPT_NS_TARGETS] = { + .id = BOND_OPT_NS_TARGETS, + .name = "ns_ip6_target", + .desc = "NS targets in ffff:ffff::ffff:ffff form", + .flags = BOND_OPTFLAG_RAWVAL, + .set = bond_option_ns_ip6_targets_set + }, +#endif [BOND_OPT_DOWNDELAY] = { .id = BOND_OPT_DOWNDELAY, .name = "downdelay", @@ -1184,6 +1197,65 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond, return ret; } +#if IS_ENABLED(CONFIG_IPV6) +static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot, + struct in6_addr *target, + unsigned long last_rx) +{ + struct in6_addr *targets = bond->params.ns_targets; + struct list_head *iter; + struct slave *slave; + + if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) { + bond_for_each_slave(bond, slave, iter) + slave->target_last_arp_rx[slot] = last_rx; + targets[slot] = *target; + } +} + +void bond_option_ns_ip6_targets_clear(struct bonding *bond) +{ + struct in6_addr addr_any = in6addr_any; + int i; + + for (i = 0; i < BOND_MAX_NS_TARGETS; i++) + _bond_options_ns_ip6_target_set(bond, i, &addr_any, 0); +} + +static int bond_option_ns_ip6_targets_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + struct in6_addr *target = (struct in6_addr *)newval->extra; + struct in6_addr *targets = bond->params.ns_targets; + struct in6_addr addr_any = in6addr_any; + int index; + + if (!bond_is_ip6_target_ok(target)) { + netdev_err(bond->dev, "invalid NS target %pI6c specified for addition\n", + target); + return -EINVAL; + } + + if (bond_get_targets_ip6(targets, target) != -1) { /* dup */ + netdev_err(bond->dev, "NS target %pI6c is already present\n", + target); + return -EINVAL; + } + + index = bond_get_targets_ip6(targets, &addr_any); /* first free slot */ + if (index == -1) { + netdev_err(bond->dev, "NS target table is full!\n"); + return -EINVAL; + } + + netdev_dbg(bond->dev, "Adding NS target %pI6c\n", target); + + _bond_options_ns_ip6_target_set(bond, index, target, jiffies); + + return 0; +} +#endif + static int bond_option_arp_validate_set(struct bonding *bond, const struct bond_opt_value *newval) { diff --git a/include/net/bond_options.h b/include/net/bond_options.h index 286b29c6c451..61b49063791c 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -66,6 +66,7 @@ enum { BOND_OPT_PEER_NOTIF_DELAY, BOND_OPT_LACP_ACTIVE, BOND_OPT_MISSED_MAX, + BOND_OPT_NS_TARGETS, BOND_OPT_LAST }; @@ -140,5 +141,8 @@ static inline void __bond_opt_init(struct bond_opt_value *optval, __bond_opt_init(optval, NULL, ULLONG_MAX, extra, extra_len) void bond_option_arp_ip_targets_clear(struct bonding *bond); +#if IS_ENABLED(CONFIG_IPV6) +void bond_option_ns_ip6_targets_clear(struct bonding *bond); +#endif #endif /* _NET_BOND_OPTIONS_H */ diff --git a/include/net/bonding.h b/include/net/bonding.h index f3b986f6b6e4..d0dfe727e0b1 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -503,6 +503,13 @@ static inline int bond_is_ip_target_ok(__be32 addr) return !ipv4_is_lbcast(addr) && !ipv4_is_zeronet(addr); } +static inline int bond_is_ip6_target_ok(struct in6_addr *addr) +{ + return !ipv6_addr_any(addr) && + !ipv6_addr_loopback(addr) && + !ipv6_addr_is_multicast(addr); +} + /* Get the oldest arp which we've received on this slave for bond's * arp_targets. */ diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 6218f93f5c1a..e1ba2d51b717 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -860,6 +860,7 @@ enum { IFLA_BOND_PEER_NOTIF_DELAY, IFLA_BOND_AD_LACP_ACTIVE, IFLA_BOND_MISSED_MAX, + IFLA_BOND_NS_IP6_TARGET, __IFLA_BOND_MAX, }; diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index 6218f93f5c1a..e1ba2d51b717 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -860,6 +860,7 @@ enum { IFLA_BOND_PEER_NOTIF_DELAY, IFLA_BOND_AD_LACP_ACTIVE, IFLA_BOND_MISSED_MAX, + IFLA_BOND_NS_IP6_TARGET, __IFLA_BOND_MAX, }; -- cgit From ba7bb663f5547ef474c98df99a97bb4a13c5715f Mon Sep 17 00:00:00 2001 From: David Dunn Date: Wed, 23 Feb 2022 22:57:41 +0000 Subject: KVM: x86: Provide per VM capability for disabling PMU virtualization Add a new capability, KVM_CAP_PMU_CAPABILITY, that takes a bitmask of settings/features to allow userspace to configure PMU virtualization on a per-VM basis. For now, support a single flag, KVM_PMU_CAP_DISABLE, to allow disabling PMU virtualization for a VM even when KVM is configured with enable_pmu=true a module level. To keep KVM simple, disallow changing VM's PMU configuration after vCPUs have been created. Signed-off-by: David Dunn Message-Id: <20220223225743.2703915-2-daviddunn@google.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 22 ++++++++++++++++++++++ arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/svm/pmu.c | 2 +- arch/x86/kvm/vmx/pmu_intel.c | 2 +- arch/x86/kvm/x86.c | 18 ++++++++++++++++++ include/uapi/linux/kvm.h | 3 +++ tools/include/uapi/linux/kvm.h | 4 ++++ 7 files changed, 50 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index c3e68c1531f0..f5d011351016 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -7643,3 +7643,25 @@ The argument to KVM_ENABLE_CAP is also a bitmask, and must be a subset of the result of KVM_CHECK_EXTENSION. KVM will forward to userspace the hypercalls whose corresponding bit is in the argument, and return ENOSYS for the others. + +8.35 KVM_CAP_PMU_CAPABILITY +--------------------------- + +:Capability KVM_CAP_PMU_CAPABILITY +:Architectures: x86 +:Type: vm +:Parameters: arg[0] is bitmask of PMU virtualization capabilities. +:Returns 0 on success, -EINVAL when arg[0] contains invalid bits + +This capability alters PMU virtualization in KVM. + +Calling KVM_CHECK_EXTENSION for this capability returns a bitmask of +PMU virtualization capabilities that can be adjusted on a VM. + +The argument to KVM_ENABLE_CAP is also a bitmask and selects specific +PMU virtualization capabilities to be applied to the VM. This can +only be invoked on a VM prior to the creation of VCPUs. + +At this time, KVM_PMU_CAP_DISABLE is the only capability. Setting +this capability will disable PMU virtualization for that VM. Usermode +should adjust CPUID leaf 0xA to reflect that the PMU is disabled. diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 463171e3b613..dafb5a6220cd 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1147,6 +1147,7 @@ struct kvm_arch { bool exception_payload_enabled; bool bus_lock_detection_enabled; + bool enable_pmu; /* * If exit_on_emulation_error is set, and the in-kernel instruction * emulator fails to emulate an instruction, allow userspace diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 5aa45f13b16d..d4de52409335 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -101,7 +101,7 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr, { struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu); - if (!enable_pmu) + if (!vcpu->kvm->arch.enable_pmu) return NULL; switch (msr) { diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 03fab48b149c..4e5b1eeeb77c 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -487,7 +487,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->reserved_bits = 0xffffffff00200000ull; entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); - if (!entry || !enable_pmu) + if (!entry || !vcpu->kvm->arch.enable_pmu) return; eax.full = entry->eax; edx.full = entry->edx; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 16d29d41908f..0b95c379e234 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -110,6 +110,8 @@ static u64 __read_mostly cr4_reserved_bits = CR4_RESERVED_BITS; #define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) +#define KVM_CAP_PMU_VALID_MASK KVM_PMU_CAP_DISABLE + #define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \ KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK) @@ -4330,6 +4332,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) if (r < sizeof(struct kvm_xsave)) r = sizeof(struct kvm_xsave); break; + case KVM_CAP_PMU_CAPABILITY: + r = enable_pmu ? KVM_CAP_PMU_VALID_MASK : 0; + break; } default: break; @@ -6004,6 +6009,18 @@ split_irqchip_unlock: kvm->arch.exit_on_emulation_error = cap->args[0]; r = 0; break; + case KVM_CAP_PMU_CAPABILITY: + r = -EINVAL; + if (!enable_pmu || (cap->args[0] & ~KVM_CAP_PMU_VALID_MASK)) + break; + + mutex_lock(&kvm->lock); + if (!kvm->created_vcpus) { + kvm->arch.enable_pmu = !(cap->args[0] & KVM_PMU_CAP_DISABLE); + r = 0; + } + mutex_unlock(&kvm->lock); + break; default: r = -EINVAL; break; @@ -11586,6 +11603,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); kvm->arch.guest_can_read_msr_platform_info = true; + kvm->arch.enable_pmu = enable_pmu; #if IS_ENABLED(CONFIG_HYPERV) spin_lock_init(&kvm->arch.hv_root_tdp_lock); diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a02bbf8fd0f6..d2f1efc3aa35 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1142,6 +1142,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_SYS_ATTRIBUTES 209 #define KVM_CAP_PPC_AIL_MODE_3 210 #define KVM_CAP_S390_MEM_OP_EXTENSION 211 +#define KVM_CAP_PMU_CAPABILITY 212 #ifdef KVM_CAP_IRQ_ROUTING @@ -1978,6 +1979,8 @@ struct kvm_dirty_gfn { #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) +#define KVM_PMU_CAP_DISABLE (1 << 0) + /** * struct kvm_stats_header - Header of per vm/vcpu binary statistics data. * @flags: Some extra information for header, always 0 for now. diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 507ee1f2aa96..bbc6b7c2dc1b 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -1135,6 +1135,8 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_XSAVE2 208 #define KVM_CAP_SYS_ATTRIBUTES 209 #define KVM_CAP_PPC_AIL_MODE_3 210 +#define KVM_CAP_S390_MEM_OP_EXTENSION 211 +#define KVM_CAP_PMU_CAPABILITY 212 #ifdef KVM_CAP_IRQ_ROUTING @@ -1971,6 +1973,8 @@ struct kvm_dirty_gfn { #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) +#define KVM_PMU_CAP_DISABLE (1 << 0) + /** * struct kvm_stats_header - Header of per vm/vcpu binary statistics data. * @flags: Some extra information for header, always 0 for now. -- cgit From cedd3614e5d9c80908099c19f8716714ce0610b1 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 24 Feb 2022 11:06:54 +0530 Subject: perf: Add irq and exception return branch types This expands generic branch type classification by adding two more entries there in i.e irq and exception return. Also updates the x86 implementation to process X86_BR_IRET and X86_BR_IRQ records as appropriate. This changes branch types reported to user space on x86 platform but it should not be a problem. The possible scenarios and impacts are enumerated here. Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/1645681014-3346-1-git-send-email-anshuman.khandual@arm.com --- arch/x86/events/intel/lbr.c | 4 ++-- include/uapi/linux/perf_event.h | 2 ++ tools/include/uapi/linux/perf_event.h | 2 ++ tools/perf/util/branch.c | 4 +++- 4 files changed, 9 insertions(+), 3 deletions(-) (limited to 'tools/include') diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 669c2be14784..fe1742c4ca49 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -1329,10 +1329,10 @@ static int branch_map[X86_BR_TYPE_MAP_MAX] = { PERF_BR_SYSCALL, /* X86_BR_SYSCALL */ PERF_BR_SYSRET, /* X86_BR_SYSRET */ PERF_BR_UNKNOWN, /* X86_BR_INT */ - PERF_BR_UNKNOWN, /* X86_BR_IRET */ + PERF_BR_ERET, /* X86_BR_IRET */ PERF_BR_COND, /* X86_BR_JCC */ PERF_BR_UNCOND, /* X86_BR_JMP */ - PERF_BR_UNKNOWN, /* X86_BR_IRQ */ + PERF_BR_IRQ, /* X86_BR_IRQ */ PERF_BR_IND_CALL, /* X86_BR_IND_CALL */ PERF_BR_UNKNOWN, /* X86_BR_ABORT */ PERF_BR_UNKNOWN, /* X86_BR_IN_TX */ diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 1b65042ab1db..7dc71768749d 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -251,6 +251,8 @@ enum { PERF_BR_SYSRET = 8, /* syscall return */ PERF_BR_COND_CALL = 9, /* conditional function call */ PERF_BR_COND_RET = 10, /* conditional function return */ + PERF_BR_ERET = 11, /* exception return */ + PERF_BR_IRQ = 12, /* irq */ PERF_BR_MAX, }; diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h index 4cd39aaccbe7..d1324c427e8b 100644 --- a/tools/include/uapi/linux/perf_event.h +++ b/tools/include/uapi/linux/perf_event.h @@ -251,6 +251,8 @@ enum { PERF_BR_SYSRET = 8, /* syscall return */ PERF_BR_COND_CALL = 9, /* conditional function call */ PERF_BR_COND_RET = 10, /* conditional function return */ + PERF_BR_ERET = 11, /* exception return */ + PERF_BR_IRQ = 12, /* irq */ PERF_BR_MAX, }; diff --git a/tools/perf/util/branch.c b/tools/perf/util/branch.c index 2285b1eb3128..a9a909db8cc7 100644 --- a/tools/perf/util/branch.c +++ b/tools/perf/util/branch.c @@ -49,7 +49,9 @@ const char *branch_type_name(int type) "SYSCALL", "SYSRET", "COND_CALL", - "COND_RET" + "COND_RET", + "ERET", + "IRQ" }; if (type >= 0 && type < PERF_BR_MAX) -- cgit From 8d21ec0e46ed6e39994accff8eb4f2be3d2e76b5 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Wed, 2 Mar 2022 11:56:34 -0800 Subject: bpf: Add __sk_buff->delivery_time_type and bpf_skb_set_skb_delivery_time() * __sk_buff->delivery_time_type: This patch adds __sk_buff->delivery_time_type. It tells if the delivery_time is stored in __sk_buff->tstamp or not. It will be most useful for ingress to tell if the __sk_buff->tstamp has the (rcv) timestamp or delivery_time. If delivery_time_type is 0 (BPF_SKB_DELIVERY_TIME_NONE), it has the (rcv) timestamp. Two non-zero types are defined for the delivery_time_type, BPF_SKB_DELIVERY_TIME_MONO and BPF_SKB_DELIVERY_TIME_UNSPEC. For UNSPEC, it can only happen in egress because only mono delivery_time can be forwarded to ingress now. The clock of UNSPEC delivery_time can be deduced from the skb->sk->sk_clockid which is how the sch_etf doing it also. * Provide forwarded delivery_time to tc-bpf@ingress: With the help of the new delivery_time_type, the tc-bpf has a way to tell if the __sk_buff->tstamp has the (rcv) timestamp or the delivery_time. During bpf load time, the verifier will learn if the bpf prog has accessed the new __sk_buff->delivery_time_type. If it does, it means the tc-bpf@ingress is expecting the skb->tstamp could have the delivery_time. The kernel will then read the skb->tstamp as-is during bpf insn rewrite without checking the skb->mono_delivery_time. This is done by adding a new prog->delivery_time_access bit. The same goes for writing skb->tstamp. * bpf_skb_set_delivery_time(): The bpf_skb_set_delivery_time() helper is added to allow setting both delivery_time and the delivery_time_type at the same time. If the tc-bpf does not need to change the delivery_time_type, it can directly write to the __sk_buff->tstamp as the existing tc-bpf has already been doing. It will be most useful at ingress to change the __sk_buff->tstamp from the (rcv) timestamp to a mono delivery_time and then bpf_redirect_*(). bpf only has mono clock helper (bpf_ktime_get_ns), and the current known use case is the mono EDT for fq, and only mono delivery time can be kept during forward now, so bpf_skb_set_delivery_time() only supports setting BPF_SKB_DELIVERY_TIME_MONO. It can be extended later when use cases come up and the forwarding path also supports other clock bases. Signed-off-by: Martin KaFai Lau Signed-off-by: David S. Miller --- include/linux/filter.h | 3 +- include/uapi/linux/bpf.h | 41 +++++++++- net/core/filter.c | 169 ++++++++++++++++++++++++++++++++--------- tools/include/uapi/linux/bpf.h | 41 +++++++++- 4 files changed, 216 insertions(+), 38 deletions(-) (limited to 'tools/include') diff --git a/include/linux/filter.h b/include/linux/filter.h index 1cb1af917617..9bf26307247f 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -572,7 +572,8 @@ struct bpf_prog { has_callchain_buf:1, /* callchain buffer allocated? */ enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */ call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */ - call_get_func_ip:1; /* Do we call get_func_ip() */ + call_get_func_ip:1, /* Do we call get_func_ip() */ + delivery_time_access:1; /* Accessed __sk_buff->delivery_time_type */ enum bpf_prog_type type; /* Type of BPF program */ enum bpf_attach_type expected_attach_type; /* For some prog types */ u32 len; /* Number of filter blocks */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index afe3d0d7f5f2..4eebea830613 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5086,6 +5086,37 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. On error * *dst* buffer is zeroed out. + * + * long bpf_skb_set_delivery_time(struct sk_buff *skb, u64 dtime, u32 dtime_type) + * Description + * Set a *dtime* (delivery time) to the __sk_buff->tstamp and also + * change the __sk_buff->delivery_time_type to *dtime_type*. + * + * When setting a delivery time (non zero *dtime*) to + * __sk_buff->tstamp, only BPF_SKB_DELIVERY_TIME_MONO *dtime_type* + * is supported. It is the only delivery_time_type that will be + * kept after bpf_redirect_*(). + * + * If there is no need to change the __sk_buff->delivery_time_type, + * the delivery time can be directly written to __sk_buff->tstamp + * instead. + * + * *dtime* 0 and *dtime_type* BPF_SKB_DELIVERY_TIME_NONE + * can be used to clear any delivery time stored in + * __sk_buff->tstamp. + * + * Only IPv4 and IPv6 skb->protocol are supported. + * + * This function is most useful when it needs to set a + * mono delivery time to __sk_buff->tstamp and then + * bpf_redirect_*() to the egress of an iface. For example, + * changing the (rcv) timestamp in __sk_buff->tstamp at + * ingress to a mono delivery time and then bpf_redirect_*() + * to sch_fq@phy-dev. + * Return + * 0 on success. + * **-EINVAL** for invalid input + * **-EOPNOTSUPP** for unsupported delivery_time_type and protocol */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5280,6 +5311,7 @@ union bpf_attr { FN(xdp_load_bytes), \ FN(xdp_store_bytes), \ FN(copy_from_user_task), \ + FN(skb_set_delivery_time), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper @@ -5469,6 +5501,12 @@ union { \ __u64 :64; \ } __attribute__((aligned(8))) +enum { + BPF_SKB_DELIVERY_TIME_NONE, + BPF_SKB_DELIVERY_TIME_UNSPEC, + BPF_SKB_DELIVERY_TIME_MONO, +}; + /* user accessible mirror of in-kernel sk_buff. * new fields can only be added to the end of this structure */ @@ -5509,7 +5547,8 @@ struct __sk_buff { __u32 gso_segs; __bpf_md_ptr(struct bpf_sock *, sk); __u32 gso_size; - __u32 :32; /* Padding, future use. */ + __u8 delivery_time_type; + __u32 :24; /* Padding, future use. */ __u64 hwtstamp; }; diff --git a/net/core/filter.c b/net/core/filter.c index 5072733743e9..88767f7da150 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -7388,6 +7388,43 @@ static const struct bpf_func_proto bpf_sock_ops_reserve_hdr_opt_proto = { .arg3_type = ARG_ANYTHING, }; +BPF_CALL_3(bpf_skb_set_delivery_time, struct sk_buff *, skb, + u64, dtime, u32, dtime_type) +{ + /* skb_clear_delivery_time() is done for inet protocol */ + if (skb->protocol != htons(ETH_P_IP) && + skb->protocol != htons(ETH_P_IPV6)) + return -EOPNOTSUPP; + + switch (dtime_type) { + case BPF_SKB_DELIVERY_TIME_MONO: + if (!dtime) + return -EINVAL; + skb->tstamp = dtime; + skb->mono_delivery_time = 1; + break; + case BPF_SKB_DELIVERY_TIME_NONE: + if (dtime) + return -EINVAL; + skb->tstamp = 0; + skb->mono_delivery_time = 0; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static const struct bpf_func_proto bpf_skb_set_delivery_time_proto = { + .func = bpf_skb_set_delivery_time, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, +}; + #endif /* CONFIG_INET */ bool bpf_helper_changes_pkt_data(void *func) @@ -7749,6 +7786,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_tcp_gen_syncookie_proto; case BPF_FUNC_sk_assign: return &bpf_sk_assign_proto; + case BPF_FUNC_skb_set_delivery_time: + return &bpf_skb_set_delivery_time_proto; #endif default: return bpf_sk_base_func_proto(func_id); @@ -8088,7 +8127,9 @@ static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type return false; info->reg_type = PTR_TO_SOCK_COMMON_OR_NULL; break; - case offsetofend(struct __sk_buff, gso_size) ... offsetof(struct __sk_buff, hwtstamp) - 1: + case offsetof(struct __sk_buff, delivery_time_type): + return false; + case offsetofend(struct __sk_buff, delivery_time_type) ... offsetof(struct __sk_buff, hwtstamp) - 1: /* Explicitly prohibit access to padding in __sk_buff. */ return false; default: @@ -8443,6 +8484,15 @@ static bool tc_cls_act_is_valid_access(int off, int size, break; case bpf_ctx_range_till(struct __sk_buff, family, local_port): return false; + case offsetof(struct __sk_buff, delivery_time_type): + /* The convert_ctx_access() on reading and writing + * __sk_buff->tstamp depends on whether the bpf prog + * has used __sk_buff->delivery_time_type or not. + * Thus, we need to set prog->delivery_time_access + * earlier during is_valid_access() here. + */ + ((struct bpf_prog *)prog)->delivery_time_access = 1; + return size == sizeof(__u8); } return bpf_skb_is_valid_access(off, size, type, prog, info); @@ -8838,6 +8888,45 @@ static u32 flow_dissector_convert_ctx_access(enum bpf_access_type type, return insn - insn_buf; } +static struct bpf_insn *bpf_convert_dtime_type_read(const struct bpf_insn *si, + struct bpf_insn *insn) +{ + __u8 value_reg = si->dst_reg; + __u8 skb_reg = si->src_reg; + __u8 tmp_reg = BPF_REG_AX; + + *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, + SKB_MONO_DELIVERY_TIME_OFFSET); + *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, + SKB_MONO_DELIVERY_TIME_MASK); + *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 2); + /* value_reg = BPF_SKB_DELIVERY_TIME_MONO */ + *insn++ = BPF_MOV32_IMM(value_reg, BPF_SKB_DELIVERY_TIME_MONO); + *insn++ = BPF_JMP_A(IS_ENABLED(CONFIG_NET_CLS_ACT) ? 10 : 5); + + *insn++ = BPF_LDX_MEM(BPF_DW, tmp_reg, skb_reg, + offsetof(struct sk_buff, tstamp)); + *insn++ = BPF_JMP_IMM(BPF_JNE, tmp_reg, 0, 2); + /* value_reg = BPF_SKB_DELIVERY_TIME_NONE */ + *insn++ = BPF_MOV32_IMM(value_reg, BPF_SKB_DELIVERY_TIME_NONE); + *insn++ = BPF_JMP_A(IS_ENABLED(CONFIG_NET_CLS_ACT) ? 6 : 1); + +#ifdef CONFIG_NET_CLS_ACT + *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, TC_AT_INGRESS_OFFSET); + *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, TC_AT_INGRESS_MASK); + *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 2); + /* At ingress, value_reg = 0 */ + *insn++ = BPF_MOV32_IMM(value_reg, 0); + *insn++ = BPF_JMP_A(1); +#endif + + /* value_reg = BPF_SKB_DELIVERYT_TIME_UNSPEC */ + *insn++ = BPF_MOV32_IMM(value_reg, BPF_SKB_DELIVERY_TIME_UNSPEC); + + /* 15 insns with CONFIG_NET_CLS_ACT */ + return insn; +} + static struct bpf_insn *bpf_convert_shinfo_access(const struct bpf_insn *si, struct bpf_insn *insn) { @@ -8859,29 +8948,32 @@ static struct bpf_insn *bpf_convert_shinfo_access(const struct bpf_insn *si, return insn; } -static struct bpf_insn *bpf_convert_tstamp_read(const struct bpf_insn *si, +static struct bpf_insn *bpf_convert_tstamp_read(const struct bpf_prog *prog, + const struct bpf_insn *si, struct bpf_insn *insn) { __u8 value_reg = si->dst_reg; __u8 skb_reg = si->src_reg; #ifdef CONFIG_NET_CLS_ACT - __u8 tmp_reg = BPF_REG_AX; - - *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, TC_AT_INGRESS_OFFSET); - *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, TC_AT_INGRESS_MASK); - *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 5); - /* @ingress, read __sk_buff->tstamp as the (rcv) timestamp, - * so check the skb->mono_delivery_time. - */ - *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, - SKB_MONO_DELIVERY_TIME_OFFSET); - *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, - SKB_MONO_DELIVERY_TIME_MASK); - *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 2); - /* skb->mono_delivery_time is set, read 0 as the (rcv) timestamp. */ - *insn++ = BPF_MOV64_IMM(value_reg, 0); - *insn++ = BPF_JMP_A(1); + if (!prog->delivery_time_access) { + __u8 tmp_reg = BPF_REG_AX; + + *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, TC_AT_INGRESS_OFFSET); + *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, TC_AT_INGRESS_MASK); + *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 5); + /* @ingress, read __sk_buff->tstamp as the (rcv) timestamp, + * so check the skb->mono_delivery_time. + */ + *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, + SKB_MONO_DELIVERY_TIME_OFFSET); + *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, + SKB_MONO_DELIVERY_TIME_MASK); + *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 2); + /* skb->mono_delivery_time is set, read 0 as the (rcv) timestamp. */ + *insn++ = BPF_MOV64_IMM(value_reg, 0); + *insn++ = BPF_JMP_A(1); + } #endif *insn++ = BPF_LDX_MEM(BPF_DW, value_reg, skb_reg, @@ -8889,27 +8981,30 @@ static struct bpf_insn *bpf_convert_tstamp_read(const struct bpf_insn *si, return insn; } -static struct bpf_insn *bpf_convert_tstamp_write(const struct bpf_insn *si, +static struct bpf_insn *bpf_convert_tstamp_write(const struct bpf_prog *prog, + const struct bpf_insn *si, struct bpf_insn *insn) { __u8 value_reg = si->src_reg; __u8 skb_reg = si->dst_reg; #ifdef CONFIG_NET_CLS_ACT - __u8 tmp_reg = BPF_REG_AX; - - *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, TC_AT_INGRESS_OFFSET); - *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, TC_AT_INGRESS_MASK); - *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 3); - /* Writing __sk_buff->tstamp at ingress as the (rcv) timestamp. - * Clear the skb->mono_delivery_time. - */ - *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, - SKB_MONO_DELIVERY_TIME_OFFSET); - *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, - ~SKB_MONO_DELIVERY_TIME_MASK); - *insn++ = BPF_STX_MEM(BPF_B, skb_reg, tmp_reg, - SKB_MONO_DELIVERY_TIME_OFFSET); + if (!prog->delivery_time_access) { + __u8 tmp_reg = BPF_REG_AX; + + *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, TC_AT_INGRESS_OFFSET); + *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, TC_AT_INGRESS_MASK); + *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 3); + /* Writing __sk_buff->tstamp at ingress as the (rcv) timestamp. + * Clear the skb->mono_delivery_time. + */ + *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, + SKB_MONO_DELIVERY_TIME_OFFSET); + *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, + ~SKB_MONO_DELIVERY_TIME_MASK); + *insn++ = BPF_STX_MEM(BPF_B, skb_reg, tmp_reg, + SKB_MONO_DELIVERY_TIME_OFFSET); + } #endif /* skb->tstamp = tstamp */ @@ -9226,9 +9321,13 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type, BUILD_BUG_ON(sizeof_field(struct sk_buff, tstamp) != 8); if (type == BPF_WRITE) - insn = bpf_convert_tstamp_write(si, insn); + insn = bpf_convert_tstamp_write(prog, si, insn); else - insn = bpf_convert_tstamp_read(si, insn); + insn = bpf_convert_tstamp_read(prog, si, insn); + break; + + case offsetof(struct __sk_buff, delivery_time_type): + insn = bpf_convert_dtime_type_read(si, insn); break; case offsetof(struct __sk_buff, gso_segs): diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index afe3d0d7f5f2..4eebea830613 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5086,6 +5086,37 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. On error * *dst* buffer is zeroed out. + * + * long bpf_skb_set_delivery_time(struct sk_buff *skb, u64 dtime, u32 dtime_type) + * Description + * Set a *dtime* (delivery time) to the __sk_buff->tstamp and also + * change the __sk_buff->delivery_time_type to *dtime_type*. + * + * When setting a delivery time (non zero *dtime*) to + * __sk_buff->tstamp, only BPF_SKB_DELIVERY_TIME_MONO *dtime_type* + * is supported. It is the only delivery_time_type that will be + * kept after bpf_redirect_*(). + * + * If there is no need to change the __sk_buff->delivery_time_type, + * the delivery time can be directly written to __sk_buff->tstamp + * instead. + * + * *dtime* 0 and *dtime_type* BPF_SKB_DELIVERY_TIME_NONE + * can be used to clear any delivery time stored in + * __sk_buff->tstamp. + * + * Only IPv4 and IPv6 skb->protocol are supported. + * + * This function is most useful when it needs to set a + * mono delivery time to __sk_buff->tstamp and then + * bpf_redirect_*() to the egress of an iface. For example, + * changing the (rcv) timestamp in __sk_buff->tstamp at + * ingress to a mono delivery time and then bpf_redirect_*() + * to sch_fq@phy-dev. + * Return + * 0 on success. + * **-EINVAL** for invalid input + * **-EOPNOTSUPP** for unsupported delivery_time_type and protocol */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5280,6 +5311,7 @@ union bpf_attr { FN(xdp_load_bytes), \ FN(xdp_store_bytes), \ FN(copy_from_user_task), \ + FN(skb_set_delivery_time), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper @@ -5469,6 +5501,12 @@ union { \ __u64 :64; \ } __attribute__((aligned(8))) +enum { + BPF_SKB_DELIVERY_TIME_NONE, + BPF_SKB_DELIVERY_TIME_UNSPEC, + BPF_SKB_DELIVERY_TIME_MONO, +}; + /* user accessible mirror of in-kernel sk_buff. * new fields can only be added to the end of this structure */ @@ -5509,7 +5547,8 @@ struct __sk_buff { __u32 gso_segs; __bpf_md_ptr(struct bpf_sock *, sk); __u32 gso_size; - __u32 :32; /* Padding, future use. */ + __u8 delivery_time_type; + __u32 :24; /* Padding, future use. */ __u64 hwtstamp; }; -- cgit From aec499c75cf8e0b599be4d559e6922b613085f8f Mon Sep 17 00:00:00 2001 From: Alan Kao Date: Wed, 2 Mar 2022 15:42:45 +0800 Subject: nds32: Remove the architecture The nds32 architecture, also known as AndeStar V3, is a custom 32-bit RISC target designed by Andes Technologies. Support was added to the kernel in 2016 as the replacement RISC-V based V5 processors were already announced, and maintained by (current or former) Andes employees. As explained by Alan Kao, new customers are now all using RISC-V, and all known nds32 users are already on longterm stable kernels provided by Andes, with no development work going into mainline support any more. While the port is still in a reasonably good shape, it only gets worse over time without active maintainers, so it seems best to remove it before it becomes unusable. As always, if it turns out that there are mainline users after all, and they volunteer to maintain the port in the future, the removal can be reverted. Link: https://lore.kernel.org/linux-mm/YhdWNLUhk+x9RAzU@yamatobi.andestech.com/ Link: https://lore.kernel.org/lkml/20220302065213.82702-1-alankao@andestech.com/ Link: https://www.andestech.com/en/products-solutions/andestar-architecture/ Signed-off-by: Alan Kao [arnd: rewrite changelog to provide more background] Signed-off-by: Arnd Bergmann --- .../interrupt-controller/andestech,ativic32.txt | 19 - .../devicetree/bindings/nds32/andestech-boards | 40 - Documentation/devicetree/bindings/nds32/atl2c.txt | 28 - Documentation/devicetree/bindings/nds32/cpus.txt | 38 - .../devicetree/bindings/perf/nds32v3-pmu.txt | 17 - .../bindings/timer/andestech,atcpit100-timer.txt | 33 - .../features/core/cBPF-JIT/arch-support.txt | 1 - .../features/core/eBPF-JIT/arch-support.txt | 1 - .../core/generic-idle-thread/arch-support.txt | 1 - .../features/core/jump-labels/arch-support.txt | 1 - .../core/thread-info-in-task/arch-support.txt | 1 - .../features/core/tracehook/arch-support.txt | 1 - .../features/debug/KASAN/arch-support.txt | 1 - .../debug/debug-vm-pgtable/arch-support.txt | 1 - .../debug/gcov-profile-all/arch-support.txt | 1 - Documentation/features/debug/kcov/arch-support.txt | 1 - Documentation/features/debug/kgdb/arch-support.txt | 1 - .../features/debug/kmemleak/arch-support.txt | 1 - .../debug/kprobes-on-ftrace/arch-support.txt | 1 - .../features/debug/kprobes/arch-support.txt | 1 - .../features/debug/kretprobes/arch-support.txt | 1 - .../features/debug/optprobes/arch-support.txt | 1 - .../features/debug/stackprotector/arch-support.txt | 1 - .../features/debug/uprobes/arch-support.txt | 1 - .../debug/user-ret-profiler/arch-support.txt | 1 - .../features/io/dma-contiguous/arch-support.txt | 1 - .../locking/cmpxchg-local/arch-support.txt | 1 - .../features/locking/lockdep/arch-support.txt | 1 - .../locking/queued-rwlocks/arch-support.txt | 1 - .../locking/queued-spinlocks/arch-support.txt | 1 - .../features/perf/kprobes-event/arch-support.txt | 1 - .../features/perf/perf-regs/arch-support.txt | 1 - .../features/perf/perf-stackdump/arch-support.txt | 1 - .../sched/membarrier-sync-core/arch-support.txt | 1 - .../features/sched/numa-balancing/arch-support.txt | 1 - .../seccomp/seccomp-filter/arch-support.txt | 1 - .../time/arch-tick-broadcast/arch-support.txt | 1 - .../features/time/clockevents/arch-support.txt | 1 - .../time/context-tracking/arch-support.txt | 1 - .../features/time/irq-time-acct/arch-support.txt | 1 - .../features/time/virt-cpuacct/arch-support.txt | 1 - .../features/vm/ELF-ASLR/arch-support.txt | 1 - .../features/vm/PG_uncached/arch-support.txt | 1 - Documentation/features/vm/THP/arch-support.txt | 1 - Documentation/features/vm/TLB/arch-support.txt | 1 - .../features/vm/huge-vmap/arch-support.txt | 1 - .../features/vm/ioremap_prot/arch-support.txt | 1 - .../features/vm/pte_special/arch-support.txt | 1 - MAINTAINERS | 12 - arch/nds32/Kbuild | 4 - arch/nds32/Kconfig | 101 -- arch/nds32/Kconfig.cpu | 218 --- arch/nds32/Kconfig.debug | 2 - arch/nds32/Makefile | 63 - arch/nds32/boot/.gitignore | 2 - arch/nds32/boot/Makefile | 16 - arch/nds32/boot/dts/Makefile | 2 - arch/nds32/boot/dts/ae3xx.dts | 90 -- arch/nds32/configs/defconfig | 104 -- arch/nds32/include/asm/Kbuild | 8 - arch/nds32/include/asm/assembler.h | 39 - arch/nds32/include/asm/barrier.h | 15 - arch/nds32/include/asm/bitfield.h | 985 ------------- arch/nds32/include/asm/cache.h | 12 - arch/nds32/include/asm/cache_info.h | 13 - arch/nds32/include/asm/cacheflush.h | 53 - arch/nds32/include/asm/current.h | 12 - arch/nds32/include/asm/delay.h | 39 - arch/nds32/include/asm/elf.h | 180 --- arch/nds32/include/asm/fixmap.h | 29 - arch/nds32/include/asm/fpu.h | 126 -- arch/nds32/include/asm/fpuemu.h | 44 - arch/nds32/include/asm/ftrace.h | 46 - arch/nds32/include/asm/futex.h | 101 -- arch/nds32/include/asm/highmem.h | 65 - arch/nds32/include/asm/io.h | 84 -- arch/nds32/include/asm/irqflags.h | 41 - arch/nds32/include/asm/l2_cache.h | 137 -- arch/nds32/include/asm/linkage.h | 11 - arch/nds32/include/asm/memory.h | 91 -- arch/nds32/include/asm/mmu.h | 12 - arch/nds32/include/asm/mmu_context.h | 62 - arch/nds32/include/asm/nds32.h | 82 -- arch/nds32/include/asm/nds32_fpu_inst.h | 109 -- arch/nds32/include/asm/page.h | 64 - arch/nds32/include/asm/perf_event.h | 16 - arch/nds32/include/asm/pgalloc.h | 62 - arch/nds32/include/asm/pgtable.h | 377 ----- arch/nds32/include/asm/pmu.h | 386 ----- arch/nds32/include/asm/proc-fns.h | 44 - arch/nds32/include/asm/processor.h | 104 -- arch/nds32/include/asm/ptrace.h | 77 - arch/nds32/include/asm/sfp-machine.h | 158 --- arch/nds32/include/asm/shmparam.h | 19 - arch/nds32/include/asm/stacktrace.h | 39 - arch/nds32/include/asm/string.h | 17 - arch/nds32/include/asm/suspend.h | 11 - arch/nds32/include/asm/swab.h | 35 - arch/nds32/include/asm/syscall.h | 142 -- arch/nds32/include/asm/syscalls.h | 14 - arch/nds32/include/asm/thread_info.h | 72 - arch/nds32/include/asm/tlb.h | 11 - arch/nds32/include/asm/tlbflush.h | 46 - arch/nds32/include/asm/uaccess.h | 282 ---- arch/nds32/include/asm/unistd.h | 6 - arch/nds32/include/asm/vdso.h | 24 - arch/nds32/include/asm/vdso_datapage.h | 37 - arch/nds32/include/asm/vdso_timer_info.h | 14 - arch/nds32/include/asm/vermagic.h | 9 - arch/nds32/include/asm/vmalloc.h | 4 - arch/nds32/include/uapi/asm/Kbuild | 2 - arch/nds32/include/uapi/asm/auxvec.h | 19 - arch/nds32/include/uapi/asm/byteorder.h | 13 - arch/nds32/include/uapi/asm/cachectl.h | 14 - arch/nds32/include/uapi/asm/fp_udfiex_crtl.h | 16 - arch/nds32/include/uapi/asm/param.h | 11 - arch/nds32/include/uapi/asm/ptrace.h | 25 - arch/nds32/include/uapi/asm/sigcontext.h | 84 -- arch/nds32/include/uapi/asm/unistd.h | 16 - arch/nds32/kernel/.gitignore | 2 - arch/nds32/kernel/Makefile | 33 - arch/nds32/kernel/asm-offsets.c | 28 - arch/nds32/kernel/atl2c.c | 65 - arch/nds32/kernel/cacheinfo.c | 49 - arch/nds32/kernel/devtree.c | 19 - arch/nds32/kernel/dma.c | 82 -- arch/nds32/kernel/ex-entry.S | 177 --- arch/nds32/kernel/ex-exit.S | 193 --- arch/nds32/kernel/ex-scall.S | 100 -- arch/nds32/kernel/fpu.c | 266 ---- arch/nds32/kernel/ftrace.c | 278 ---- arch/nds32/kernel/head.S | 197 --- arch/nds32/kernel/irq.c | 9 - arch/nds32/kernel/module.c | 278 ---- arch/nds32/kernel/nds32_ksyms.c | 25 - arch/nds32/kernel/perf_event_cpu.c | 1500 -------------------- arch/nds32/kernel/pm.c | 80 -- arch/nds32/kernel/process.c | 256 ---- arch/nds32/kernel/ptrace.c | 118 -- arch/nds32/kernel/setup.c | 369 ----- arch/nds32/kernel/signal.c | 384 ----- arch/nds32/kernel/sleep.S | 131 -- arch/nds32/kernel/stacktrace.c | 53 - arch/nds32/kernel/sys_nds32.c | 84 -- arch/nds32/kernel/syscall_table.c | 17 - arch/nds32/kernel/time.c | 11 - arch/nds32/kernel/traps.c | 354 ----- arch/nds32/kernel/vdso.c | 231 --- arch/nds32/kernel/vdso/.gitignore | 2 - arch/nds32/kernel/vdso/Makefile | 79 -- arch/nds32/kernel/vdso/datapage.S | 21 - arch/nds32/kernel/vdso/gen_vdso_offsets.sh | 15 - arch/nds32/kernel/vdso/gettimeofday.c | 269 ---- arch/nds32/kernel/vdso/note.S | 11 - arch/nds32/kernel/vdso/sigreturn.S | 19 - arch/nds32/kernel/vdso/vdso.S | 18 - arch/nds32/kernel/vdso/vdso.lds.S | 75 - arch/nds32/kernel/vmlinux.lds.S | 70 - arch/nds32/lib/Makefile | 4 - arch/nds32/lib/clear_user.S | 42 - arch/nds32/lib/copy_from_user.S | 45 - arch/nds32/lib/copy_page.S | 40 - arch/nds32/lib/copy_template.S | 69 - arch/nds32/lib/copy_to_user.S | 45 - arch/nds32/lib/memcpy.S | 30 - arch/nds32/lib/memmove.S | 70 - arch/nds32/lib/memset.S | 33 - arch/nds32/lib/memzero.S | 18 - arch/nds32/math-emu/Makefile | 10 - arch/nds32/math-emu/faddd.c | 24 - arch/nds32/math-emu/fadds.c | 24 - arch/nds32/math-emu/fcmpd.c | 24 - arch/nds32/math-emu/fcmps.c | 24 - arch/nds32/math-emu/fd2s.c | 22 - arch/nds32/math-emu/fd2si.c | 30 - arch/nds32/math-emu/fd2siz.c | 30 - arch/nds32/math-emu/fd2ui.c | 30 - arch/nds32/math-emu/fd2uiz.c | 30 - arch/nds32/math-emu/fdivd.c | 27 - arch/nds32/math-emu/fdivs.c | 26 - arch/nds32/math-emu/fmuld.c | 23 - arch/nds32/math-emu/fmuls.c | 23 - arch/nds32/math-emu/fnegd.c | 21 - arch/nds32/math-emu/fnegs.c | 21 - arch/nds32/math-emu/fpuemu.c | 406 ------ arch/nds32/math-emu/fs2d.c | 23 - arch/nds32/math-emu/fs2si.c | 29 - arch/nds32/math-emu/fs2siz.c | 29 - arch/nds32/math-emu/fs2ui.c | 29 - arch/nds32/math-emu/fs2uiz.c | 30 - arch/nds32/math-emu/fsi2d.c | 22 - arch/nds32/math-emu/fsi2s.c | 22 - arch/nds32/math-emu/fsqrtd.c | 21 - arch/nds32/math-emu/fsqrts.c | 21 - arch/nds32/math-emu/fsubd.c | 27 - arch/nds32/math-emu/fsubs.c | 27 - arch/nds32/math-emu/fui2d.c | 22 - arch/nds32/math-emu/fui2s.c | 22 - arch/nds32/mm/Makefile | 10 - arch/nds32/mm/alignment.c | 575 -------- arch/nds32/mm/cacheflush.c | 338 ----- arch/nds32/mm/extable.c | 16 - arch/nds32/mm/fault.c | 396 ------ arch/nds32/mm/init.c | 263 ---- arch/nds32/mm/mm-nds32.c | 96 -- arch/nds32/mm/mmap.c | 73 - arch/nds32/mm/proc.c | 536 ------- arch/nds32/mm/tlb.c | 50 - drivers/clocksource/Kconfig | 9 - drivers/clocksource/Makefile | 1 - drivers/clocksource/timer-atcpit100.c | 266 ---- drivers/irqchip/Makefile | 1 - drivers/irqchip/irq-ativic32.c | 156 -- drivers/net/ethernet/faraday/Kconfig | 12 +- drivers/video/console/Kconfig | 2 +- scripts/recordmcount.pl | 3 - tools/include/asm/barrier.h | 2 - tools/perf/arch/nds32/Build | 1 - tools/perf/arch/nds32/util/Build | 1 - tools/perf/arch/nds32/util/header.c | 29 - tools/testing/selftests/vDSO/vdso_config.h | 4 - 221 files changed, 6 insertions(+), 15814 deletions(-) delete mode 100644 Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt delete mode 100644 Documentation/devicetree/bindings/nds32/andestech-boards delete mode 100644 Documentation/devicetree/bindings/nds32/atl2c.txt delete mode 100644 Documentation/devicetree/bindings/nds32/cpus.txt delete mode 100644 Documentation/devicetree/bindings/perf/nds32v3-pmu.txt delete mode 100644 Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt delete mode 100644 arch/nds32/Kbuild delete mode 100644 arch/nds32/Kconfig delete mode 100644 arch/nds32/Kconfig.cpu delete mode 100644 arch/nds32/Kconfig.debug delete mode 100644 arch/nds32/Makefile delete mode 100644 arch/nds32/boot/.gitignore delete mode 100644 arch/nds32/boot/Makefile delete mode 100644 arch/nds32/boot/dts/Makefile delete mode 100644 arch/nds32/boot/dts/ae3xx.dts delete mode 100644 arch/nds32/configs/defconfig delete mode 100644 arch/nds32/include/asm/Kbuild delete mode 100644 arch/nds32/include/asm/assembler.h delete mode 100644 arch/nds32/include/asm/barrier.h delete mode 100644 arch/nds32/include/asm/bitfield.h delete mode 100644 arch/nds32/include/asm/cache.h delete mode 100644 arch/nds32/include/asm/cache_info.h delete mode 100644 arch/nds32/include/asm/cacheflush.h delete mode 100644 arch/nds32/include/asm/current.h delete mode 100644 arch/nds32/include/asm/delay.h delete mode 100644 arch/nds32/include/asm/elf.h delete mode 100644 arch/nds32/include/asm/fixmap.h delete mode 100644 arch/nds32/include/asm/fpu.h delete mode 100644 arch/nds32/include/asm/fpuemu.h delete mode 100644 arch/nds32/include/asm/ftrace.h delete mode 100644 arch/nds32/include/asm/futex.h delete mode 100644 arch/nds32/include/asm/highmem.h delete mode 100644 arch/nds32/include/asm/io.h delete mode 100644 arch/nds32/include/asm/irqflags.h delete mode 100644 arch/nds32/include/asm/l2_cache.h delete mode 100644 arch/nds32/include/asm/linkage.h delete mode 100644 arch/nds32/include/asm/memory.h delete mode 100644 arch/nds32/include/asm/mmu.h delete mode 100644 arch/nds32/include/asm/mmu_context.h delete mode 100644 arch/nds32/include/asm/nds32.h delete mode 100644 arch/nds32/include/asm/nds32_fpu_inst.h delete mode 100644 arch/nds32/include/asm/page.h delete mode 100644 arch/nds32/include/asm/perf_event.h delete mode 100644 arch/nds32/include/asm/pgalloc.h delete mode 100644 arch/nds32/include/asm/pgtable.h delete mode 100644 arch/nds32/include/asm/pmu.h delete mode 100644 arch/nds32/include/asm/proc-fns.h delete mode 100644 arch/nds32/include/asm/processor.h delete mode 100644 arch/nds32/include/asm/ptrace.h delete mode 100644 arch/nds32/include/asm/sfp-machine.h delete mode 100644 arch/nds32/include/asm/shmparam.h delete mode 100644 arch/nds32/include/asm/stacktrace.h delete mode 100644 arch/nds32/include/asm/string.h delete mode 100644 arch/nds32/include/asm/suspend.h delete mode 100644 arch/nds32/include/asm/swab.h delete mode 100644 arch/nds32/include/asm/syscall.h delete mode 100644 arch/nds32/include/asm/syscalls.h delete mode 100644 arch/nds32/include/asm/thread_info.h delete mode 100644 arch/nds32/include/asm/tlb.h delete mode 100644 arch/nds32/include/asm/tlbflush.h delete mode 100644 arch/nds32/include/asm/uaccess.h delete mode 100644 arch/nds32/include/asm/unistd.h delete mode 100644 arch/nds32/include/asm/vdso.h delete mode 100644 arch/nds32/include/asm/vdso_datapage.h delete mode 100644 arch/nds32/include/asm/vdso_timer_info.h delete mode 100644 arch/nds32/include/asm/vermagic.h delete mode 100644 arch/nds32/include/asm/vmalloc.h delete mode 100644 arch/nds32/include/uapi/asm/Kbuild delete mode 100644 arch/nds32/include/uapi/asm/auxvec.h delete mode 100644 arch/nds32/include/uapi/asm/byteorder.h delete mode 100644 arch/nds32/include/uapi/asm/cachectl.h delete mode 100644 arch/nds32/include/uapi/asm/fp_udfiex_crtl.h delete mode 100644 arch/nds32/include/uapi/asm/param.h delete mode 100644 arch/nds32/include/uapi/asm/ptrace.h delete mode 100644 arch/nds32/include/uapi/asm/sigcontext.h delete mode 100644 arch/nds32/include/uapi/asm/unistd.h delete mode 100644 arch/nds32/kernel/.gitignore delete mode 100644 arch/nds32/kernel/Makefile delete mode 100644 arch/nds32/kernel/asm-offsets.c delete mode 100644 arch/nds32/kernel/atl2c.c delete mode 100644 arch/nds32/kernel/cacheinfo.c delete mode 100644 arch/nds32/kernel/devtree.c delete mode 100644 arch/nds32/kernel/dma.c delete mode 100644 arch/nds32/kernel/ex-entry.S delete mode 100644 arch/nds32/kernel/ex-exit.S delete mode 100644 arch/nds32/kernel/ex-scall.S delete mode 100644 arch/nds32/kernel/fpu.c delete mode 100644 arch/nds32/kernel/ftrace.c delete mode 100644 arch/nds32/kernel/head.S delete mode 100644 arch/nds32/kernel/irq.c delete mode 100644 arch/nds32/kernel/module.c delete mode 100644 arch/nds32/kernel/nds32_ksyms.c delete mode 100644 arch/nds32/kernel/perf_event_cpu.c delete mode 100644 arch/nds32/kernel/pm.c delete mode 100644 arch/nds32/kernel/process.c delete mode 100644 arch/nds32/kernel/ptrace.c delete mode 100644 arch/nds32/kernel/setup.c delete mode 100644 arch/nds32/kernel/signal.c delete mode 100644 arch/nds32/kernel/sleep.S delete mode 100644 arch/nds32/kernel/stacktrace.c delete mode 100644 arch/nds32/kernel/sys_nds32.c delete mode 100644 arch/nds32/kernel/syscall_table.c delete mode 100644 arch/nds32/kernel/time.c delete mode 100644 arch/nds32/kernel/traps.c delete mode 100644 arch/nds32/kernel/vdso.c delete mode 100644 arch/nds32/kernel/vdso/.gitignore delete mode 100644 arch/nds32/kernel/vdso/Makefile delete mode 100644 arch/nds32/kernel/vdso/datapage.S delete mode 100755 arch/nds32/kernel/vdso/gen_vdso_offsets.sh delete mode 100644 arch/nds32/kernel/vdso/gettimeofday.c delete mode 100644 arch/nds32/kernel/vdso/note.S delete mode 100644 arch/nds32/kernel/vdso/sigreturn.S delete mode 100644 arch/nds32/kernel/vdso/vdso.S delete mode 100644 arch/nds32/kernel/vdso/vdso.lds.S delete mode 100644 arch/nds32/kernel/vmlinux.lds.S delete mode 100644 arch/nds32/lib/Makefile delete mode 100644 arch/nds32/lib/clear_user.S delete mode 100644 arch/nds32/lib/copy_from_user.S delete mode 100644 arch/nds32/lib/copy_page.S delete mode 100644 arch/nds32/lib/copy_template.S delete mode 100644 arch/nds32/lib/copy_to_user.S delete mode 100644 arch/nds32/lib/memcpy.S delete mode 100644 arch/nds32/lib/memmove.S delete mode 100644 arch/nds32/lib/memset.S delete mode 100644 arch/nds32/lib/memzero.S delete mode 100644 arch/nds32/math-emu/Makefile delete mode 100644 arch/nds32/math-emu/faddd.c delete mode 100644 arch/nds32/math-emu/fadds.c delete mode 100644 arch/nds32/math-emu/fcmpd.c delete mode 100644 arch/nds32/math-emu/fcmps.c delete mode 100644 arch/nds32/math-emu/fd2s.c delete mode 100644 arch/nds32/math-emu/fd2si.c delete mode 100644 arch/nds32/math-emu/fd2siz.c delete mode 100644 arch/nds32/math-emu/fd2ui.c delete mode 100644 arch/nds32/math-emu/fd2uiz.c delete mode 100644 arch/nds32/math-emu/fdivd.c delete mode 100644 arch/nds32/math-emu/fdivs.c delete mode 100644 arch/nds32/math-emu/fmuld.c delete mode 100644 arch/nds32/math-emu/fmuls.c delete mode 100644 arch/nds32/math-emu/fnegd.c delete mode 100644 arch/nds32/math-emu/fnegs.c delete mode 100644 arch/nds32/math-emu/fpuemu.c delete mode 100644 arch/nds32/math-emu/fs2d.c delete mode 100644 arch/nds32/math-emu/fs2si.c delete mode 100644 arch/nds32/math-emu/fs2siz.c delete mode 100644 arch/nds32/math-emu/fs2ui.c delete mode 100644 arch/nds32/math-emu/fs2uiz.c delete mode 100644 arch/nds32/math-emu/fsi2d.c delete mode 100644 arch/nds32/math-emu/fsi2s.c delete mode 100644 arch/nds32/math-emu/fsqrtd.c delete mode 100644 arch/nds32/math-emu/fsqrts.c delete mode 100644 arch/nds32/math-emu/fsubd.c delete mode 100644 arch/nds32/math-emu/fsubs.c delete mode 100644 arch/nds32/math-emu/fui2d.c delete mode 100644 arch/nds32/math-emu/fui2s.c delete mode 100644 arch/nds32/mm/Makefile delete mode 100644 arch/nds32/mm/alignment.c delete mode 100644 arch/nds32/mm/cacheflush.c delete mode 100644 arch/nds32/mm/extable.c delete mode 100644 arch/nds32/mm/fault.c delete mode 100644 arch/nds32/mm/init.c delete mode 100644 arch/nds32/mm/mm-nds32.c delete mode 100644 arch/nds32/mm/mmap.c delete mode 100644 arch/nds32/mm/proc.c delete mode 100644 arch/nds32/mm/tlb.c delete mode 100644 drivers/clocksource/timer-atcpit100.c delete mode 100644 drivers/irqchip/irq-ativic32.c delete mode 100644 tools/perf/arch/nds32/Build delete mode 100644 tools/perf/arch/nds32/util/Build delete mode 100644 tools/perf/arch/nds32/util/header.c (limited to 'tools/include') diff --git a/Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt b/Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt deleted file mode 100644 index f4b4193d830e..000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt +++ /dev/null @@ -1,19 +0,0 @@ -* Andestech Internal Vector Interrupt Controller - -The Internal Vector Interrupt Controller (IVIC) is a basic interrupt controller -suitable for a simpler SoC platform not requiring a more sophisticated and -bigger External Vector Interrupt Controller. - - -Main node required properties: - -- compatible : should at least contain "andestech,ativic32". -- interrupt-controller : Identifies the node as an interrupt controller -- #interrupt-cells: 1 cells and refer to interrupt-controller/interrupts - -Examples: - intc: interrupt-controller { - compatible = "andestech,ativic32"; - #interrupt-cells = <1>; - interrupt-controller; - }; diff --git a/Documentation/devicetree/bindings/nds32/andestech-boards b/Documentation/devicetree/bindings/nds32/andestech-boards deleted file mode 100644 index f5d75693e3c7..000000000000 --- a/Documentation/devicetree/bindings/nds32/andestech-boards +++ /dev/null @@ -1,40 +0,0 @@ -Andestech(nds32) AE3XX Platform ------------------------------------------------------------------------------ -The AE3XX prototype demonstrates the AE3XX example platform on the FPGA. It -is composed of one Andestech(nds32) processor and AE3XX. - -Required properties (in root node): -- compatible = "andestech,ae3xx"; - -Example: -/dts-v1/; -/ { - compatible = "andestech,ae3xx"; - #address-cells = <1>; - #size-cells = <1>; - interrupt-parent = <&intc>; -}; - -Andestech(nds32) AG101P Platform ------------------------------------------------------------------------------ -AG101P is a generic SoC Platform IP that works with any of Andestech(nds32) -processors to provide a cost-effective and high performance solution for -majority of embedded systems in variety of application domains. Users may -simply attach their IP on one of the system buses together with certain glue -logics to complete a SoC solution for a specific application. With -comprehensive simulation and design environments, users may evaluate the -system performance of their applications and track bugs of their designs -efficiently. The optional hardware development platform further provides real -system environment for early prototyping and software/hardware co-development. - -Required properties (in root node): - compatible = "andestech,ag101p"; - -Example: -/dts-v1/; -/ { - compatible = "andestech,ag101p"; - #address-cells = <1>; - #size-cells = <1>; - interrupt-parent = <&intc>; -}; diff --git a/Documentation/devicetree/bindings/nds32/atl2c.txt b/Documentation/devicetree/bindings/nds32/atl2c.txt deleted file mode 100644 index da8ab8e7ae9b..000000000000 --- a/Documentation/devicetree/bindings/nds32/atl2c.txt +++ /dev/null @@ -1,28 +0,0 @@ -* Andestech L2 cache Controller - -The level-2 cache controller plays an important role in reducing memory latency -for high performance systems, such as thoese designs with AndesCore processors. -Level-2 cache controller in general enhances overall system performance -signigicantly and the system power consumption might be reduced as well by -reducing DRAM accesses. - -This binding specifies what properties must be available in the device tree -representation of an Andestech L2 cache controller. - -Required properties: - - compatible: - Usage: required - Value type: - Definition: "andestech,atl2c" - - reg : Physical base address and size of cache controller's memory mapped - - cache-unified : Specifies the cache is a unified cache. - - cache-level : Should be set to 2 for a level 2 cache. - -* Example - - cache-controller@e0500000 { - compatible = "andestech,atl2c"; - reg = <0xe0500000 0x1000>; - cache-unified; - cache-level = <2>; - }; diff --git a/Documentation/devicetree/bindings/nds32/cpus.txt b/Documentation/devicetree/bindings/nds32/cpus.txt deleted file mode 100644 index 6f9e311b6589..000000000000 --- a/Documentation/devicetree/bindings/nds32/cpus.txt +++ /dev/null @@ -1,38 +0,0 @@ -* Andestech Processor Binding - -This binding specifies what properties must be available in the device tree -representation of a Andestech Processor Core, which is the root node in the -tree. - -Required properties: - - - compatible: - Usage: required - Value type: - Definition: Should be "andestech,", "andestech,nds32v3" as fallback. - Must contain "andestech,nds32v3" as the most generic value, in addition to - one of the following identifiers for a particular CPU core: - "andestech,n13" - "andestech,n15" - "andestech,d15" - "andestech,n10" - "andestech,d10" - - device_type - Usage: required - Value type: - Definition: must be "cpu" - - reg: Contains CPU index. - - clock-frequency: Contains the clock frequency for CPU, in Hz. - -* Examples - -/ { - cpus { - cpu@0 { - device_type = "cpu"; - compatible = "andestech,n13", "andestech,nds32v3"; - reg = <0x0>; - clock-frequency = <60000000> - }; - }; -}; diff --git a/Documentation/devicetree/bindings/perf/nds32v3-pmu.txt b/Documentation/devicetree/bindings/perf/nds32v3-pmu.txt deleted file mode 100644 index 1bd15785b4ae..000000000000 --- a/Documentation/devicetree/bindings/perf/nds32v3-pmu.txt +++ /dev/null @@ -1,17 +0,0 @@ -* NDS32 Performance Monitor Units - -NDS32 core have a PMU for counting cpu and cache events like cache misses. -The NDS32 PMU representation in the device tree should be done as under: - -Required properties: - -- compatible : - "andestech,nds32v3-pmu" - -- interrupts : The interrupt number for NDS32 PMU is 13. - -Example: -pmu{ - compatible = "andestech,nds32v3-pmu"; - interrupts = <13>; -} diff --git a/Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt b/Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt deleted file mode 100644 index 4c9ea5989e35..000000000000 --- a/Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt +++ /dev/null @@ -1,33 +0,0 @@ -Andestech ATCPIT100 timer ------------------------------------------------------------------- -ATCPIT100 is a generic IP block from Andes Technology, embedded in -Andestech AE3XX platforms and other designs. - -This timer is a set of compact multi-function timers, which can be -used as pulse width modulators (PWM) as well as simple timers. - -It supports up to 4 PIT channels. Each PIT channel is a -multi-function timer and provide the following usage scenarios: -One 32-bit timer -Two 16-bit timers -Four 8-bit timers -One 16-bit PWM -One 16-bit timer and one 8-bit PWM -Two 8-bit timer and one 8-bit PWM - -Required properties: -- compatible : Should be "andestech,atcpit100" -- reg : Address and length of the register set -- interrupts : Reference to the timer interrupt -- clocks : a clock to provide the tick rate for "andestech,atcpit100" -- clock-names : should be "PCLK" for the peripheral clock source. - -Examples: - -timer0: timer@f0400000 { - compatible = "andestech,atcpit100"; - reg = <0xf0400000 0x1000>; - interrupts = <2>; - clocks = <&apb>; - clock-names = "PCLK"; -}; diff --git a/Documentation/features/core/cBPF-JIT/arch-support.txt b/Documentation/features/core/cBPF-JIT/arch-support.txt index e59b5215402d..77bd6974dd6d 100644 --- a/Documentation/features/core/cBPF-JIT/arch-support.txt +++ b/Documentation/features/core/cBPF-JIT/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/core/eBPF-JIT/arch-support.txt b/Documentation/features/core/eBPF-JIT/arch-support.txt index dcbd8679f514..d5ab547b2be6 100644 --- a/Documentation/features/core/eBPF-JIT/arch-support.txt +++ b/Documentation/features/core/eBPF-JIT/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/core/generic-idle-thread/arch-support.txt b/Documentation/features/core/generic-idle-thread/arch-support.txt index 4efcba7b5239..ddb3762ca7f5 100644 --- a/Documentation/features/core/generic-idle-thread/arch-support.txt +++ b/Documentation/features/core/generic-idle-thread/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | ok | | parisc: | ok | diff --git a/Documentation/features/core/jump-labels/arch-support.txt b/Documentation/features/core/jump-labels/arch-support.txt index 0c801d1bd2da..d5380ef68713 100644 --- a/Documentation/features/core/jump-labels/arch-support.txt +++ b/Documentation/features/core/jump-labels/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/core/thread-info-in-task/arch-support.txt b/Documentation/features/core/thread-info-in-task/arch-support.txt index bc74d8beea72..0654ba3a42ff 100644 --- a/Documentation/features/core/thread-info-in-task/arch-support.txt +++ b/Documentation/features/core/thread-info-in-task/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | ok | | nios2: | TODO | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/core/tracehook/arch-support.txt b/Documentation/features/core/tracehook/arch-support.txt index af34308fce7f..8e95dc0c7b90 100644 --- a/Documentation/features/core/tracehook/arch-support.txt +++ b/Documentation/features/core/tracehook/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | ok | | nios2: | ok | | openrisc: | ok | | parisc: | ok | diff --git a/Documentation/features/debug/KASAN/arch-support.txt b/Documentation/features/debug/KASAN/arch-support.txt index c244ac7eee26..407ca1d91242 100644 --- a/Documentation/features/debug/KASAN/arch-support.txt +++ b/Documentation/features/debug/KASAN/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/debug/debug-vm-pgtable/arch-support.txt b/Documentation/features/debug/debug-vm-pgtable/arch-support.txt index fa83403b4aec..83eafe1a7f68 100644 --- a/Documentation/features/debug/debug-vm-pgtable/arch-support.txt +++ b/Documentation/features/debug/debug-vm-pgtable/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/debug/gcov-profile-all/arch-support.txt b/Documentation/features/debug/gcov-profile-all/arch-support.txt index b39c1a5de3f3..49e0dda11227 100644 --- a/Documentation/features/debug/gcov-profile-all/arch-support.txt +++ b/Documentation/features/debug/gcov-profile-all/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | ok | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/debug/kcov/arch-support.txt b/Documentation/features/debug/kcov/arch-support.txt index 7e44013cc320..3d34b724ddae 100644 --- a/Documentation/features/debug/kcov/arch-support.txt +++ b/Documentation/features/debug/kcov/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/debug/kgdb/arch-support.txt b/Documentation/features/debug/kgdb/arch-support.txt index 2cb0576f9180..7aa073d908c5 100644 --- a/Documentation/features/debug/kgdb/arch-support.txt +++ b/Documentation/features/debug/kgdb/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | ok | | mips: | ok | - | nds32: | TODO | | nios2: | ok | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/debug/kmemleak/arch-support.txt b/Documentation/features/debug/kmemleak/arch-support.txt index e9ac415f8aec..5c784ff9768a 100644 --- a/Documentation/features/debug/kmemleak/arch-support.txt +++ b/Documentation/features/debug/kmemleak/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | ok | | mips: | ok | - | nds32: | ok | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt index 96156e8802a7..a1f6e98c6b1f 100644 --- a/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt +++ b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/debug/kprobes/arch-support.txt b/Documentation/features/debug/kprobes/arch-support.txt index ee95ed61909a..e7e7015175e7 100644 --- a/Documentation/features/debug/kprobes/arch-support.txt +++ b/Documentation/features/debug/kprobes/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/debug/kretprobes/arch-support.txt b/Documentation/features/debug/kretprobes/arch-support.txt index 612cb97d47b8..838eb53a6fa5 100644 --- a/Documentation/features/debug/kretprobes/arch-support.txt +++ b/Documentation/features/debug/kretprobes/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/debug/optprobes/arch-support.txt b/Documentation/features/debug/optprobes/arch-support.txt index d6ff141a6122..6358b00b1723 100644 --- a/Documentation/features/debug/optprobes/arch-support.txt +++ b/Documentation/features/debug/optprobes/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/debug/stackprotector/arch-support.txt b/Documentation/features/debug/stackprotector/arch-support.txt index ad4de22a71ab..f6cdf781305f 100644 --- a/Documentation/features/debug/stackprotector/arch-support.txt +++ b/Documentation/features/debug/stackprotector/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/debug/uprobes/arch-support.txt b/Documentation/features/debug/uprobes/arch-support.txt index 8bd5548a4485..0b871e797d24 100644 --- a/Documentation/features/debug/uprobes/arch-support.txt +++ b/Documentation/features/debug/uprobes/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/debug/user-ret-profiler/arch-support.txt b/Documentation/features/debug/user-ret-profiler/arch-support.txt index 2a3fe812a5fa..a2feda7adff1 100644 --- a/Documentation/features/debug/user-ret-profiler/arch-support.txt +++ b/Documentation/features/debug/user-ret-profiler/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/io/dma-contiguous/arch-support.txt b/Documentation/features/io/dma-contiguous/arch-support.txt index bece89586efa..9b407f26d45e 100644 --- a/Documentation/features/io/dma-contiguous/arch-support.txt +++ b/Documentation/features/io/dma-contiguous/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | ok | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/locking/cmpxchg-local/arch-support.txt b/Documentation/features/locking/cmpxchg-local/arch-support.txt index 52bdda004f5c..090520b0e02d 100644 --- a/Documentation/features/locking/cmpxchg-local/arch-support.txt +++ b/Documentation/features/locking/cmpxchg-local/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/locking/lockdep/arch-support.txt b/Documentation/features/locking/lockdep/arch-support.txt index a8cd163c8b7e..6d840b103537 100644 --- a/Documentation/features/locking/lockdep/arch-support.txt +++ b/Documentation/features/locking/lockdep/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | ok | | mips: | ok | - | nds32: | ok | | nios2: | TODO | | openrisc: | ok | | parisc: | TODO | diff --git a/Documentation/features/locking/queued-rwlocks/arch-support.txt b/Documentation/features/locking/queued-rwlocks/arch-support.txt index 8c85949752b3..de586be05d64 100644 --- a/Documentation/features/locking/queued-rwlocks/arch-support.txt +++ b/Documentation/features/locking/queued-rwlocks/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | ok | | parisc: | TODO | diff --git a/Documentation/features/locking/queued-spinlocks/arch-support.txt b/Documentation/features/locking/queued-spinlocks/arch-support.txt index 5f4e1b3841af..29d0c8b7b1c5 100644 --- a/Documentation/features/locking/queued-spinlocks/arch-support.txt +++ b/Documentation/features/locking/queued-spinlocks/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | ok | | parisc: | TODO | diff --git a/Documentation/features/perf/kprobes-event/arch-support.txt b/Documentation/features/perf/kprobes-event/arch-support.txt index 78f3fe080f0e..881a8a50e41e 100644 --- a/Documentation/features/perf/kprobes-event/arch-support.txt +++ b/Documentation/features/perf/kprobes-event/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | ok | | nios2: | TODO | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/perf/perf-regs/arch-support.txt b/Documentation/features/perf/perf-regs/arch-support.txt index 5bf3b1854a1f..7639a796a8e1 100644 --- a/Documentation/features/perf/perf-regs/arch-support.txt +++ b/Documentation/features/perf/perf-regs/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/perf/perf-stackdump/arch-support.txt b/Documentation/features/perf/perf-stackdump/arch-support.txt index d88659bb4fc1..df1a4c679a45 100644 --- a/Documentation/features/perf/perf-stackdump/arch-support.txt +++ b/Documentation/features/perf/perf-stackdump/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/sched/membarrier-sync-core/arch-support.txt b/Documentation/features/sched/membarrier-sync-core/arch-support.txt index 883d33b265d6..51b7afc937f1 100644 --- a/Documentation/features/sched/membarrier-sync-core/arch-support.txt +++ b/Documentation/features/sched/membarrier-sync-core/arch-support.txt @@ -40,7 +40,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/sched/numa-balancing/arch-support.txt b/Documentation/features/sched/numa-balancing/arch-support.txt index 9affb7c2c500..d0e308135434 100644 --- a/Documentation/features/sched/numa-balancing/arch-support.txt +++ b/Documentation/features/sched/numa-balancing/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | .. | | microblaze: | .. | | mips: | TODO | - | nds32: | TODO | | nios2: | .. | | openrisc: | .. | | parisc: | .. | diff --git a/Documentation/features/seccomp/seccomp-filter/arch-support.txt b/Documentation/features/seccomp/seccomp-filter/arch-support.txt index 26eec58ab819..05613c5ff560 100644 --- a/Documentation/features/seccomp/seccomp-filter/arch-support.txt +++ b/Documentation/features/seccomp/seccomp-filter/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/time/arch-tick-broadcast/arch-support.txt b/Documentation/features/time/arch-tick-broadcast/arch-support.txt index 8dcaab070c7b..b4c96ebab7e3 100644 --- a/Documentation/features/time/arch-tick-broadcast/arch-support.txt +++ b/Documentation/features/time/arch-tick-broadcast/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/time/clockevents/arch-support.txt b/Documentation/features/time/clockevents/arch-support.txt index 9a81cb03b1fd..3f6976052e2a 100644 --- a/Documentation/features/time/clockevents/arch-support.txt +++ b/Documentation/features/time/clockevents/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | ok | | mips: | ok | - | nds32: | ok | | nios2: | ok | | openrisc: | ok | | parisc: | TODO | diff --git a/Documentation/features/time/context-tracking/arch-support.txt b/Documentation/features/time/context-tracking/arch-support.txt index 4ed116c2ec39..bb1c1801553e 100644 --- a/Documentation/features/time/context-tracking/arch-support.txt +++ b/Documentation/features/time/context-tracking/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/time/irq-time-acct/arch-support.txt b/Documentation/features/time/irq-time-acct/arch-support.txt index bc30c15557c7..3cea25b80c8c 100644 --- a/Documentation/features/time/irq-time-acct/arch-support.txt +++ b/Documentation/features/time/irq-time-acct/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | .. | diff --git a/Documentation/features/time/virt-cpuacct/arch-support.txt b/Documentation/features/time/virt-cpuacct/arch-support.txt index 050de43bbbb9..5163a60a1c1e 100644 --- a/Documentation/features/time/virt-cpuacct/arch-support.txt +++ b/Documentation/features/time/virt-cpuacct/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/vm/ELF-ASLR/arch-support.txt b/Documentation/features/vm/ELF-ASLR/arch-support.txt index 2949c99fbb2f..73ec761f1e27 100644 --- a/Documentation/features/vm/ELF-ASLR/arch-support.txt +++ b/Documentation/features/vm/ELF-ASLR/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | ok | diff --git a/Documentation/features/vm/PG_uncached/arch-support.txt b/Documentation/features/vm/PG_uncached/arch-support.txt index 6cde38458596..9066a90b38d9 100644 --- a/Documentation/features/vm/PG_uncached/arch-support.txt +++ b/Documentation/features/vm/PG_uncached/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/vm/THP/arch-support.txt b/Documentation/features/vm/THP/arch-support.txt index 7dbd6967b37e..f717ab792e5a 100644 --- a/Documentation/features/vm/THP/arch-support.txt +++ b/Documentation/features/vm/THP/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | .. | | microblaze: | .. | | mips: | ok | - | nds32: | TODO | | nios2: | .. | | openrisc: | .. | | parisc: | TODO | diff --git a/Documentation/features/vm/TLB/arch-support.txt b/Documentation/features/vm/TLB/arch-support.txt index e1c3a4c4d107..6fa76a37f299 100644 --- a/Documentation/features/vm/TLB/arch-support.txt +++ b/Documentation/features/vm/TLB/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | .. | | microblaze: | .. | | mips: | TODO | - | nds32: | TODO | | nios2: | .. | | openrisc: | .. | | parisc: | TODO | diff --git a/Documentation/features/vm/huge-vmap/arch-support.txt b/Documentation/features/vm/huge-vmap/arch-support.txt index bc53905a0306..6e1792ee37fe 100644 --- a/Documentation/features/vm/huge-vmap/arch-support.txt +++ b/Documentation/features/vm/huge-vmap/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | TODO | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/vm/ioremap_prot/arch-support.txt b/Documentation/features/vm/ioremap_prot/arch-support.txt index 9a0c8783b84d..a6dcbe5f47b6 100644 --- a/Documentation/features/vm/ioremap_prot/arch-support.txt +++ b/Documentation/features/vm/ioremap_prot/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/Documentation/features/vm/pte_special/arch-support.txt b/Documentation/features/vm/pte_special/arch-support.txt index 40b969f3a6bb..376477749c42 100644 --- a/Documentation/features/vm/pte_special/arch-support.txt +++ b/Documentation/features/vm/pte_special/arch-support.txt @@ -17,7 +17,6 @@ | m68k: | TODO | | microblaze: | TODO | | mips: | ok | - | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | | parisc: | TODO | diff --git a/MAINTAINERS b/MAINTAINERS index 69a2935daf6c..d24a03cb0426 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1229,18 +1229,6 @@ S: Supported F: drivers/clk/analogbits/* F: include/linux/clk/analogbits* -ANDES ARCHITECTURE -M: Nick Hu -M: Greentime Hu -M: Vincent Chen -S: Supported -T: git https://git.kernel.org/pub/scm/linux/kernel/git/greentime/linux.git -F: Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt -F: Documentation/devicetree/bindings/nds32/ -F: arch/nds32/ -N: nds32 -K: nds32 - ANDROID CONFIG FRAGMENTS M: Rob Herring S: Supported diff --git a/arch/nds32/Kbuild b/arch/nds32/Kbuild deleted file mode 100644 index 4e39f7abdeb6..000000000000 --- a/arch/nds32/Kbuild +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - -# for cleaning -subdir- += boot diff --git a/arch/nds32/Kconfig b/arch/nds32/Kconfig deleted file mode 100644 index 013249430fa3..000000000000 --- a/arch/nds32/Kconfig +++ /dev/null @@ -1,101 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.rst. -# - -config NDS32 - def_bool y - select ARCH_32BIT_OFF_T - select ARCH_HAS_DMA_PREP_COHERENT - select ARCH_HAS_SYNC_DMA_FOR_CPU - select ARCH_HAS_SYNC_DMA_FOR_DEVICE - select ARCH_WANT_FRAME_POINTERS if FTRACE - select CLKSRC_MMIO - select CLONE_BACKWARDS - select COMMON_CLK - select DMA_DIRECT_REMAP - select GENERIC_ATOMIC64 - select GENERIC_CPU_DEVICES - select GENERIC_IRQ_CHIP - select GENERIC_IRQ_SHOW - select GENERIC_IOREMAP - select GENERIC_LIB_ASHLDI3 - select GENERIC_LIB_ASHRDI3 - select GENERIC_LIB_CMPDI2 - select GENERIC_LIB_LSHRDI3 - select GENERIC_LIB_MULDI3 - select GENERIC_LIB_UCMPDI2 - select GENERIC_TIME_VSYSCALL - select HAVE_ARCH_TRACEHOOK - select HAVE_DEBUG_KMEMLEAK - select HAVE_EXIT_THREAD - select HAVE_REGS_AND_STACK_ACCESS_API - select HAVE_PERF_EVENTS - select IRQ_DOMAIN - select LOCKDEP_SUPPORT - select MODULES_USE_ELF_RELA - select OF - select OF_EARLY_FLATTREE - select NO_IOPORT_MAP - select RTC_LIB - select THREAD_INFO_IN_TASK - select HAVE_FUNCTION_TRACER - select HAVE_FUNCTION_GRAPH_TRACER - select HAVE_FTRACE_MCOUNT_RECORD - select HAVE_DYNAMIC_FTRACE - select TRACE_IRQFLAGS_SUPPORT - help - Andes(nds32) Linux support. - -config GENERIC_CALIBRATE_DELAY - def_bool y - -config GENERIC_CSUM - def_bool y - -config GENERIC_HWEIGHT - def_bool y - -config GENERIC_LOCKBREAK - def_bool y - depends on PREEMPTION - -config STACKTRACE_SUPPORT - def_bool y - -config FIX_EARLYCON_MEM - def_bool y - -config PGTABLE_LEVELS - default 2 - -menu "System Type" -source "arch/nds32/Kconfig.cpu" -config NR_CPUS - int - default 1 - -config MMU - def_bool y - -config NDS32_BUILTIN_DTB - string "Builtin DTB" - default "" - help - User can use it to specify the dts of the SoC -endmenu - -menu "Kernel Features" -source "kernel/Kconfig.hz" -endmenu - -menu "Power management options" -config SYS_SUPPORTS_APM_EMULATION - bool - -config ARCH_SUSPEND_POSSIBLE - def_bool y - -source "kernel/power/Kconfig" -endmenu diff --git a/arch/nds32/Kconfig.cpu b/arch/nds32/Kconfig.cpu deleted file mode 100644 index c10759952485..000000000000 --- a/arch/nds32/Kconfig.cpu +++ /dev/null @@ -1,218 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -comment "Processor Features" - -config CPU_BIG_ENDIAN - def_bool !CPU_LITTLE_ENDIAN - -config CPU_LITTLE_ENDIAN - bool "Little endian" - default y - -config FPU - bool "FPU support" - default n - help - If FPU ISA is used in user space, this configuration shall be Y to - enable required support in kernel such as fpu context switch and - fpu exception handler. - - If no FPU ISA is used in user space, say N. - -config LAZY_FPU - bool "lazy FPU support" - depends on FPU - default y - help - Say Y here to enable the lazy FPU scheme. The lazy FPU scheme can - enhance system performance by reducing the context switch - frequency of the FPU register. - - For normal case, say Y. - -config SUPPORT_DENORMAL_ARITHMETIC - bool "Denormal arithmetic support" - depends on FPU - default n - help - Say Y here to enable arithmetic of denormalized number. Enabling - this feature can enhance the precision for tininess number. - However, performance loss in float point calculations is - possibly significant due to additional FPU exception. - - If the calculated tolerance for tininess number is not critical, - say N to prevent performance loss. - -config HWZOL - bool "hardware zero overhead loop support" - depends on CPU_D10 || CPU_D15 - default n - help - A set of Zero-Overhead Loop mechanism is provided to reduce the - instruction fetch and execution overhead of loop-control instructions. - It will save 3 registers($LB, $LC, $LE) for context saving if say Y. - You don't need to save these registers if you can make sure your user - program doesn't use these registers. - - If unsure, say N. - -config CPU_CACHE_ALIASING - bool "Aliasing cache" - depends on CPU_N10 || CPU_D10 || CPU_N13 || CPU_V3 - default y - help - If this CPU is using VIPT data cache and its cache way size is larger - than page size, say Y. If it is using PIPT data cache, say N. - - If unsure, say Y. - -choice - prompt "minimum CPU type" - default CPU_V3 - help - The data cache of N15/D15 is implemented as PIPT and it will not cause - the cache aliasing issue. The rest cpus(N13, N10 and D10) are - implemented as VIPT data cache. It may cause the cache aliasing issue - if its cache way size is larger than page size. You can specify the - CPU type directly or choose CPU_V3 if unsure. - - A kernel built for N10 is able to run on N15, D15, N13, N10 or D10. - A kernel built for N15 is able to run on N15 or D15. - A kernel built for D10 is able to run on D10 or D15. - A kernel built for D15 is able to run on D15. - A kernel built for N13 is able to run on N15, N13 or D15. - -config CPU_N15 - bool "AndesCore N15" -config CPU_N13 - bool "AndesCore N13" - select CPU_CACHE_ALIASING if ANDES_PAGE_SIZE_4KB -config CPU_N10 - bool "AndesCore N10" - select CPU_CACHE_ALIASING -config CPU_D15 - bool "AndesCore D15" -config CPU_D10 - bool "AndesCore D10" - select CPU_CACHE_ALIASING -config CPU_V3 - bool "AndesCore v3 compatible" - select CPU_CACHE_ALIASING -endchoice -choice - prompt "Paging -- page size " - default ANDES_PAGE_SIZE_4KB -config ANDES_PAGE_SIZE_4KB - bool "use 4KB page size" -config ANDES_PAGE_SIZE_8KB - bool "use 8KB page size" -endchoice - -config CPU_ICACHE_DISABLE - bool "Disable I-Cache" - help - Say Y here to disable the processor instruction cache. Unless - you have a reason not to or are unsure, say N. - -config CPU_DCACHE_DISABLE - bool "Disable D-Cache" - help - Say Y here to disable the processor data cache. Unless - you have a reason not to or are unsure, say N. - -config CPU_DCACHE_WRITETHROUGH - bool "Force write through D-cache" - depends on !CPU_DCACHE_DISABLE - help - Say Y here to use the data cache in writethrough mode. Unless you - specifically require this or are unsure, say N. - -config WBNA - bool "WBNA" - default n - help - Say Y here to enable write-back memory with no-write-allocation policy. - -config ALIGNMENT_TRAP - bool "Kernel support unaligned access handling by sw" - depends on PROC_FS - default n - help - Andes processors cannot load/store information which is not - naturally aligned on the bus, i.e., a 4 byte load must start at an - address divisible by 4. On 32-bit Andes processors, these non-aligned - load/store instructions will be emulated in software if you say Y - here, which has a severe performance impact. With an IP-only - configuration it is safe to say N, otherwise say Y. - -config HW_SUPPORT_UNALIGNMENT_ACCESS - bool "Kernel support unaligned access handling by hw" - depends on !ALIGNMENT_TRAP - default n - help - Andes processors load/store world/half-word instructions can access - unaligned memory locations without generating the Data Alignment - Check exceptions. With an IP-only configuration it is safe to say N, - otherwise say Y. - -config HIGHMEM - bool "High Memory Support" - depends on MMU && !CPU_CACHE_ALIASING - select KMAP_LOCAL - help - The address space of Andes processors is only 4 Gigabytes large - and it has to accommodate user address space, kernel address - space as well as some memory mapped IO. That means that, if you - have a large amount of physical memory and/or IO, not all of the - memory can be "permanently mapped" by the kernel. The physical - memory that is not permanently mapped is called "high memory". - - Depending on the selected kernel/user memory split, minimum - vmalloc space and actual amount of RAM, you may not need this - option which should result in a slightly faster kernel. - - If unsure, say N. - -config CACHE_L2 - bool "Support L2 cache" - default y - help - Say Y here to enable L2 cache if your SoC are integrated with L2CC. - If unsure, say N. - -config HW_PRE - bool "Enable hardware prefetcher" - default y - help - Say Y here to enable hardware prefetcher feature. - Only when CPU_VER.REV >= 0x09 can support. - -menu "Memory configuration" - -choice - prompt "Memory split" - depends on MMU - default VMSPLIT_3G_OPT - help - Select the desired split between kernel and user memory. - - If you are not absolutely sure what you are doing, leave this - option alone! - - config VMSPLIT_3G - bool "3G/1G user/kernel split" - config VMSPLIT_3G_OPT - bool "3G/1G user/kernel split (for full 1G low memory)" - config VMSPLIT_2G - bool "2G/2G user/kernel split" - config VMSPLIT_1G - bool "1G/3G user/kernel split" -endchoice - -config PAGE_OFFSET - hex - default 0x40000000 if VMSPLIT_1G - default 0x80000000 if VMSPLIT_2G - default 0xB0000000 if VMSPLIT_3G_OPT - default 0xC0000000 - -endmenu diff --git a/arch/nds32/Kconfig.debug b/arch/nds32/Kconfig.debug deleted file mode 100644 index 295942fe3fd5..000000000000 --- a/arch/nds32/Kconfig.debug +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# dummy file, do not delete diff --git a/arch/nds32/Makefile b/arch/nds32/Makefile deleted file mode 100644 index b33d5d81b6ae..000000000000 --- a/arch/nds32/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -LDFLAGS_vmlinux := --no-undefined -X -OBJCOPYFLAGS := -O binary -R .note -R .note.gnu.build-id -R .comment -S - -ifdef CONFIG_FUNCTION_TRACER -arch-y += -malways-save-lp -mno-relax -endif - -# Avoid generating FPU instructions -arch-y += -mno-ext-fpu-sp -mno-ext-fpu-dp -mfloat-abi=soft - -# Enable -KBUILD_CFLAGS += -isystem $(shell $(CC) -print-file-name=include) -KBUILD_CFLAGS += $(call cc-option, -mno-sched-prolog-epilog) -KBUILD_CFLAGS += -mcmodel=large - -KBUILD_CFLAGS +=$(arch-y) $(tune-y) -KBUILD_AFLAGS +=$(arch-y) $(tune-y) - -#Default value -head-y := arch/nds32/kernel/head.o -textaddr-y := $(CONFIG_PAGE_OFFSET)+0xc000 - -TEXTADDR := $(textaddr-y) - -export TEXTADDR - - -# If we have a machine-specific directory, then include it in the build. -core-y += arch/nds32/kernel/ arch/nds32/mm/ -core-$(CONFIG_FPU) += arch/nds32/math-emu/ -libs-y += arch/nds32/lib/ - -ifdef CONFIG_CPU_LITTLE_ENDIAN -KBUILD_CFLAGS += $(call cc-option, -EL) -KBUILD_AFLAGS += $(call cc-option, -EL) -KBUILD_LDFLAGS += $(call cc-option, -EL) -CHECKFLAGS += -D__NDS32_EL__ -else -KBUILD_CFLAGS += $(call cc-option, -EB) -KBUILD_AFLAGS += $(call cc-option, -EB) -KBUILD_LDFLAGS += $(call cc-option, -EB) -CHECKFLAGS += -D__NDS32_EB__ -endif - -boot := arch/nds32/boot -core-y += $(boot)/dts/ - -Image: vmlinux - $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ - - -PHONY += vdso_install -vdso_install: - $(Q)$(MAKE) $(build)=arch/nds32/kernel/vdso $@ - -prepare: vdso_prepare -vdso_prepare: prepare0 - $(Q)$(MAKE) $(build)=arch/nds32/kernel/vdso include/generated/vdso-offsets.h - -define archhelp - echo ' Image - kernel image (arch/$(ARCH)/boot/Image)' -endef diff --git a/arch/nds32/boot/.gitignore b/arch/nds32/boot/.gitignore deleted file mode 100644 index 9182a3a1ea0a..000000000000 --- a/arch/nds32/boot/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -/Image diff --git a/arch/nds32/boot/Makefile b/arch/nds32/boot/Makefile deleted file mode 100644 index c4cc0c2689f7..000000000000 --- a/arch/nds32/boot/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -targets := Image Image.gz - -$(obj)/Image: vmlinux FORCE - $(call if_changed,objcopy) - -$(obj)/Image.gz: $(obj)/Image FORCE - $(call if_changed,gzip) - -install: $(obj)/Image - $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ - $(obj)/Image System.map "$(INSTALL_PATH)" - -zinstall: $(obj)/Image.gz - $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ - $(obj)/Image.gz System.map "$(INSTALL_PATH)" diff --git a/arch/nds32/boot/dts/Makefile b/arch/nds32/boot/dts/Makefile deleted file mode 100644 index 4fc69562eae8..000000000000 --- a/arch/nds32/boot/dts/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_OF) += $(addsuffix .dtb.o, $(CONFIG_NDS32_BUILTIN_DTB)) diff --git a/arch/nds32/boot/dts/ae3xx.dts b/arch/nds32/boot/dts/ae3xx.dts deleted file mode 100644 index 16a9f54a805e..000000000000 --- a/arch/nds32/boot/dts/ae3xx.dts +++ /dev/null @@ -1,90 +0,0 @@ -/dts-v1/; -/ { - compatible = "andestech,ae3xx"; - #address-cells = <1>; - #size-cells = <1>; - interrupt-parent = <&intc>; - - chosen { - stdout-path = &serial0; - }; - - memory@0 { - device_type = "memory"; - reg = <0x00000000 0x40000000>; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - cpu@0 { - device_type = "cpu"; - compatible = "andestech,n13", "andestech,nds32v3"; - reg = <0>; - clock-frequency = <60000000>; - next-level-cache = <&L2>; - }; - }; - - intc: interrupt-controller { - compatible = "andestech,ativic32"; - #interrupt-cells = <1>; - interrupt-controller; - }; - - clock: clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <30000000>; - }; - - apb { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - serial0: serial@f0300000 { - compatible = "andestech,uart16550", "ns16550a"; - reg = <0xf0300000 0x1000>; - interrupts = <8>; - clock-frequency = <14745600>; - reg-shift = <2>; - reg-offset = <32>; - no-loopback-test = <1>; - }; - - timer0: timer@f0400000 { - compatible = "andestech,atcpit100"; - reg = <0xf0400000 0x1000>; - interrupts = <2>; - clocks = <&clock>; - clock-names = "PCLK"; - }; - }; - - ahb { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - L2: cache-controller@e0500000 { - compatible = "andestech,atl2c"; - reg = <0xe0500000 0x1000>; - cache-unified; - cache-level = <2>; - }; - - mac0: ethernet@e0100000 { - compatible = "andestech,atmac100"; - reg = <0xe0100000 0x1000>; - interrupts = <18>; - }; - }; - - pmu { - compatible = "andestech,nds32v3-pmu"; - interrupts= <13>; - }; -}; diff --git a/arch/nds32/configs/defconfig b/arch/nds32/configs/defconfig deleted file mode 100644 index f9a89cf00aa6..000000000000 --- a/arch/nds32/configs/defconfig +++ /dev/null @@ -1,104 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_USER_NS=y -CONFIG_RELAY=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_ALL=y -CONFIG_PROFILING=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_CACHE_L2 is not set -CONFIG_PREEMPT=y -# CONFIG_COMPACTION is not set -CONFIG_HZ_100=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_NET_KEY=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -# CONFIG_BLK_DEV is not set -CONFIG_NETDEVICES=y -# CONFIG_NET_CADENCE is not set -# CONFIG_NET_VENDOR_BROADCOM is not set -CONFIG_FTMAC100=y -# CONFIG_NET_VENDOR_INTEL is not set -# CONFIG_NET_VENDOR_MARVELL is not set -# CONFIG_NET_VENDOR_MICREL is not set -# CONFIG_NET_VENDOR_NATSEMI is not set -# CONFIG_NET_VENDOR_SEEQ is not set -# CONFIG_NET_VENDOR_STMICRO is not set -# CONFIG_NET_VENDOR_WIZNET is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_TOUCHSCREEN=y -# CONFIG_SERIO is not set -CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_SERIAL_8250=y -# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=3 -CONFIG_SERIAL_8250_RUNTIME_UARTS=3 -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -# CONFIG_HID_A4TECH is not set -# CONFIG_HID_APPLE is not set -# CONFIG_HID_BELKIN is not set -# CONFIG_HID_CHERRY is not set -# CONFIG_HID_CHICONY is not set -# CONFIG_HID_CYPRESS is not set -# CONFIG_HID_EZKEY is not set -# CONFIG_HID_ITE is not set -# CONFIG_HID_KENSINGTON is not set -# CONFIG_HID_LOGITECH is not set -# CONFIG_HID_MICROSOFT is not set -# CONFIG_HID_MONTEREY is not set -# CONFIG_USB_SUPPORT is not set -CONFIG_GENERIC_PHY=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_FS_ENCRYPTION=y -CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_CONFIGFS_FS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y -CONFIG_NFS_V4_1=y -CONFIG_NFS_USE_LEGACY_DNS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_INFO_DWARF4=y -CONFIG_GDB_SCRIPTS=y -CONFIG_READABLE_ASM=y -CONFIG_HEADERS_INSTALL=y -CONFIG_HEADERS_CHECK=y -CONFIG_DEBUG_SECTION_MISMATCH=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_PANIC_ON_OOPS=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_DEBUG_PREEMPT is not set -CONFIG_STACKTRACE=y -CONFIG_RCU_CPU_STALL_TIMEOUT=300 -# CONFIG_CRYPTO_HW is not set diff --git a/arch/nds32/include/asm/Kbuild b/arch/nds32/include/asm/Kbuild deleted file mode 100644 index 82a4453c9c2d..000000000000 --- a/arch/nds32/include/asm/Kbuild +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -generic-y += asm-offsets.h -generic-y += cmpxchg.h -generic-y += export.h -generic-y += gpio.h -generic-y += kvm_para.h -generic-y += parport.h -generic-y += user.h diff --git a/arch/nds32/include/asm/assembler.h b/arch/nds32/include/asm/assembler.h deleted file mode 100644 index 5e7c56926049..000000000000 --- a/arch/nds32/include/asm/assembler.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __NDS32_ASSEMBLER_H__ -#define __NDS32_ASSEMBLER_H__ - -.macro gie_disable - setgie.d - dsb -.endm - -.macro gie_enable - setgie.e - dsb -.endm - -.macro gie_save oldpsw - mfsr \oldpsw, $ir0 - setgie.d - dsb -.endm - -.macro gie_restore oldpsw - andi \oldpsw, \oldpsw, #0x1 - beqz \oldpsw, 7001f - setgie.e - dsb -7001: -.endm - - -#define USER(insn, reg, addr, opr) \ -9999: insn reg, addr, opr; \ - .section __ex_table,"a"; \ - .align 3; \ - .long 9999b, 9001f; \ - .previous - -#endif /* __NDS32_ASSEMBLER_H__ */ diff --git a/arch/nds32/include/asm/barrier.h b/arch/nds32/include/asm/barrier.h deleted file mode 100644 index 16413172fd50..000000000000 --- a/arch/nds32/include/asm/barrier.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __NDS32_ASM_BARRIER_H -#define __NDS32_ASM_BARRIER_H - -#ifndef __ASSEMBLY__ -#define mb() asm volatile("msync all":::"memory") -#define rmb() asm volatile("msync all":::"memory") -#define wmb() asm volatile("msync store":::"memory") -#include - -#endif /* __ASSEMBLY__ */ - -#endif /* __NDS32_ASM_BARRIER_H */ diff --git a/arch/nds32/include/asm/bitfield.h b/arch/nds32/include/asm/bitfield.h deleted file mode 100644 index b02a58e71f80..000000000000 --- a/arch/nds32/include/asm/bitfield.h +++ /dev/null @@ -1,985 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __NDS32_BITFIELD_H__ -#define __NDS32_BITFIELD_H__ -/****************************************************************************** - * cr0: CPU_VER (CPU Version Register) - *****************************************************************************/ -#define CPU_VER_offCFGID 0 /* Minor configuration */ -#define CPU_VER_offREV 16 /* Revision of the CPU version */ -#define CPU_VER_offCPUID 24 /* Major CPU versions */ - -#define CPU_VER_mskCFGID ( 0xFFFF << CPU_VER_offCFGID ) -#define CPU_VER_mskREV ( 0xFF << CPU_VER_offREV ) -#define CPU_VER_mskCPUID ( 0xFF << CPU_VER_offCPUID ) - -/****************************************************************************** - * cr1: ICM_CFG (Instruction Cache/Memory Configuration Register) - *****************************************************************************/ -#define ICM_CFG_offISET 0 /* I-cache sets (# of cache lines) per way */ -#define ICM_CFG_offIWAY 3 /* I-cache ways */ -#define ICM_CFG_offISZ 6 /* I-cache line size */ -#define ICM_CFG_offILCK 9 /* I-cache locking support */ -#define ICM_CFG_offILMB 10 /* On-chip ILM banks */ -#define ICM_CFG_offBSAV 13 /* ILM base register alignment version */ -/* bit 15:31 reserved */ - -#define ICM_CFG_mskISET ( 0x7 << ICM_CFG_offISET ) -#define ICM_CFG_mskIWAY ( 0x7 << ICM_CFG_offIWAY ) -#define ICM_CFG_mskISZ ( 0x7 << ICM_CFG_offISZ ) -#define ICM_CFG_mskILCK ( 0x1 << ICM_CFG_offILCK ) -#define ICM_CFG_mskILMB ( 0x7 << ICM_CFG_offILMB ) -#define ICM_CFG_mskBSAV ( 0x3 << ICM_CFG_offBSAV ) - -/****************************************************************************** - * cr2: DCM_CFG (Data Cache/Memory Configuration Register) - *****************************************************************************/ -#define DCM_CFG_offDSET 0 /* D-cache sets (# of cache lines) per way */ -#define DCM_CFG_offDWAY 3 /* D-cache ways */ -#define DCM_CFG_offDSZ 6 /* D-cache line size */ -#define DCM_CFG_offDLCK 9 /* D-cache locking support */ -#define DCM_CFG_offDLMB 10 /* On-chip DLM banks */ -#define DCM_CFG_offBSAV 13 /* DLM base register alignment version */ -/* bit 15:31 reserved */ - -#define DCM_CFG_mskDSET ( 0x7 << DCM_CFG_offDSET ) -#define DCM_CFG_mskDWAY ( 0x7 << DCM_CFG_offDWAY ) -#define DCM_CFG_mskDSZ ( 0x7 << DCM_CFG_offDSZ ) -#define DCM_CFG_mskDLCK ( 0x1 << DCM_CFG_offDLCK ) -#define DCM_CFG_mskDLMB ( 0x7 << DCM_CFG_offDLMB ) -#define DCM_CFG_mskBSAV ( 0x3 << DCM_CFG_offBSAV ) - -/****************************************************************************** - * cr3: MMU_CFG (MMU Configuration Register) - *****************************************************************************/ -#define MMU_CFG_offMMPS 0 /* Memory management protection scheme */ -#define MMU_CFG_offMMPV 2 /* Memory management protection version number */ -#define MMU_CFG_offFATB 7 /* Fully-associative or non-fully-associative TLB */ - -#define MMU_CFG_offTBW 8 /* TLB ways(non-associative) TBS */ -#define MMU_CFG_offTBS 11 /* TLB sets per way(non-associative) TBS */ -/* bit 14:14 reserved */ - -#define MMU_CFG_offEP8MIN4 15 /* 8KB page supported while minimum page is 4KB */ -#define MMU_CFG_offfEPSZ 16 /* Extra page size supported */ -#define MMU_CFG_offTLBLCK 24 /* TLB locking support */ -#define MMU_CFG_offHPTWK 25 /* Hardware Page Table Walker implemented */ -#define MMU_CFG_offDE 26 /* Default endian */ -#define MMU_CFG_offNTPT 27 /* Partitions for non-translated attributes */ -#define MMU_CFG_offIVTB 28 /* Invisible TLB */ -#define MMU_CFG_offVLPT 29 /* VLPT for fast TLB fill handling implemented */ -#define MMU_CFG_offNTME 30 /* Non-translated VA to PA mapping */ -/* bit 31 reserved */ - -#define MMU_CFG_mskMMPS ( 0x3 << MMU_CFG_offMMPS ) -#define MMU_CFG_mskMMPV ( 0x1F << MMU_CFG_offMMPV ) -#define MMU_CFG_mskFATB ( 0x1 << MMU_CFG_offFATB ) -#define MMU_CFG_mskTBW ( 0x7 << MMU_CFG_offTBW ) -#define MMU_CFG_mskTBS ( 0x7 << MMU_CFG_offTBS ) -#define MMU_CFG_mskEP8MIN4 ( 0x1 << MMU_CFG_offEP8MIN4 ) -#define MMU_CFG_mskfEPSZ ( 0xFF << MMU_CFG_offfEPSZ ) -#define MMU_CFG_mskTLBLCK ( 0x1 << MMU_CFG_offTLBLCK ) -#define MMU_CFG_mskHPTWK ( 0x1 << MMU_CFG_offHPTWK ) -#define MMU_CFG_mskDE ( 0x1 << MMU_CFG_offDE ) -#define MMU_CFG_mskNTPT ( 0x1 << MMU_CFG_offNTPT ) -#define MMU_CFG_mskIVTB ( 0x1 << MMU_CFG_offIVTB ) -#define MMU_CFG_mskVLPT ( 0x1 << MMU_CFG_offVLPT ) -#define MMU_CFG_mskNTME ( 0x1 << MMU_CFG_offNTME ) - -/****************************************************************************** - * cr4: MSC_CFG (Misc Configuration Register) - *****************************************************************************/ -#define MSC_CFG_offEDM 0 -#define MSC_CFG_offLMDMA 1 -#define MSC_CFG_offPFM 2 -#define MSC_CFG_offHSMP 3 -#define MSC_CFG_offTRACE 4 -#define MSC_CFG_offDIV 5 -#define MSC_CFG_offMAC 6 -#define MSC_CFG_offAUDIO 7 -#define MSC_CFG_offL2C 9 -#define MSC_CFG_offRDREG 10 -#define MSC_CFG_offADR24 11 -#define MSC_CFG_offINTLC 12 -#define MSC_CFG_offBASEV 13 -#define MSC_CFG_offNOD 16 -/* bit 13:31 reserved */ - -#define MSC_CFG_mskEDM ( 0x1 << MSC_CFG_offEDM ) -#define MSC_CFG_mskLMDMA ( 0x1 << MSC_CFG_offLMDMA ) -#define MSC_CFG_mskPFM ( 0x1 << MSC_CFG_offPFM ) -#define MSC_CFG_mskHSMP ( 0x1 << MSC_CFG_offHSMP ) -#define MSC_CFG_mskTRACE ( 0x1 << MSC_CFG_offTRACE ) -#define MSC_CFG_mskDIV ( 0x1 << MSC_CFG_offDIV ) -#define MSC_CFG_mskMAC ( 0x1 << MSC_CFG_offMAC ) -#define MSC_CFG_mskAUDIO ( 0x3 << MSC_CFG_offAUDIO ) -#define MSC_CFG_mskL2C ( 0x1 << MSC_CFG_offL2C ) -#define MSC_CFG_mskRDREG ( 0x1 << MSC_CFG_offRDREG ) -#define MSC_CFG_mskADR24 ( 0x1 << MSC_CFG_offADR24 ) -#define MSC_CFG_mskINTLC ( 0x1 << MSC_CFG_offINTLC ) -#define MSC_CFG_mskBASEV ( 0x7 << MSC_CFG_offBASEV ) -#define MSC_CFG_mskNOD ( 0x1 << MSC_CFG_offNOD ) - -/****************************************************************************** - * cr5: CORE_CFG (Core Identification Register) - *****************************************************************************/ -#define CORE_ID_offCOREID 0 -/* bit 4:31 reserved */ - -#define CORE_ID_mskCOREID ( 0xF << CORE_ID_offCOREID ) - -/****************************************************************************** - * cr6: FUCOP_EXIST (FPU and Coprocessor Existence Configuration Register) - *****************************************************************************/ -#define FUCOP_EXIST_offCP0EX 0 -#define FUCOP_EXIST_offCP1EX 1 -#define FUCOP_EXIST_offCP2EX 2 -#define FUCOP_EXIST_offCP3EX 3 -#define FUCOP_EXIST_offCP0ISFPU 31 - -#define FUCOP_EXIST_mskCP0EX ( 0x1 << FUCOP_EXIST_offCP0EX ) -#define FUCOP_EXIST_mskCP1EX ( 0x1 << FUCOP_EXIST_offCP1EX ) -#define FUCOP_EXIST_mskCP2EX ( 0x1 << FUCOP_EXIST_offCP2EX ) -#define FUCOP_EXIST_mskCP3EX ( 0x1 << FUCOP_EXIST_offCP3EX ) -#define FUCOP_EXIST_mskCP0ISFPU ( 0x1 << FUCOP_EXIST_offCP0ISFPU ) - -/****************************************************************************** - * ir0: PSW (Processor Status Word Register) - * ir1: IPSW (Interruption PSW Register) - * ir2: P_IPSW (Previous IPSW Register) - *****************************************************************************/ -#define PSW_offGIE 0 /* Global Interrupt Enable */ -#define PSW_offINTL 1 /* Interruption Stack Level */ -#define PSW_offPOM 3 /* Processor Operation Mode, User/Superuser */ -#define PSW_offBE 5 /* Endianness for data memory access, 1:MSB, 0:LSB */ -#define PSW_offIT 6 /* Enable instruction address translation */ -#define PSW_offDT 7 /* Enable data address translation */ -#define PSW_offIME 8 /* Instruction Machine Error flag */ -#define PSW_offDME 9 /* Data Machine Error flag */ -#define PSW_offDEX 10 /* Debug Exception */ -#define PSW_offHSS 11 /* Hardware Single Stepping */ -#define PSW_offDRBE 12 /* Device Register Endian Mode */ -#define PSW_offAEN 13 /* Audio ISA special feature */ -#define PSW_offWBNA 14 /* Write Back Non-Allocate */ -#define PSW_offIFCON 15 /* IFC On */ -#define PSW_offCPL 16 /* Current Priority Level */ -/* bit 19:31 reserved */ - -#define PSW_mskGIE ( 0x1 << PSW_offGIE ) -#define PSW_mskINTL ( 0x3 << PSW_offINTL ) -#define PSW_mskPOM ( 0x3 << PSW_offPOM ) -#define PSW_mskBE ( 0x1 << PSW_offBE ) -#define PSW_mskIT ( 0x1 << PSW_offIT ) -#define PSW_mskDT ( 0x1 << PSW_offDT ) -#define PSW_mskIME ( 0x1 << PSW_offIME ) -#define PSW_mskDME ( 0x1 << PSW_offDME ) -#define PSW_mskDEX ( 0x1 << PSW_offDEX ) -#define PSW_mskHSS ( 0x1 << PSW_offHSS ) -#define PSW_mskDRBE ( 0x1 << PSW_offDRBE ) -#define PSW_mskAEN ( 0x1 << PSW_offAEN ) -#define PSW_mskWBNA ( 0x1 << PSW_offWBNA ) -#define PSW_mskIFCON ( 0x1 << PSW_offIFCON ) -#define PSW_mskCPL ( 0x7 << PSW_offCPL ) - -#define PSW_SYSTEM ( 1 << PSW_offPOM ) -#define PSW_INTL_1 ( 1 << PSW_offINTL ) -#define PSW_CPL_NO ( 0 << PSW_offCPL ) -#define PSW_CPL_ANY ( 7 << PSW_offCPL ) - -#define PSW_clr (PSW_mskGIE|PSW_mskINTL|PSW_mskPOM|PSW_mskIT|PSW_mskDT|PSW_mskIME|PSW_mskWBNA) -#ifdef __NDS32_EB__ -#ifdef CONFIG_WBNA -#define PSW_init (PSW_mskWBNA|(1< - -#define PG_dcache_dirty PG_arch_1 - -void flush_icache_range(unsigned long start, unsigned long end); -#define flush_icache_range flush_icache_range - -void flush_icache_page(struct vm_area_struct *vma, struct page *page); -#define flush_icache_page flush_icache_page - -#ifdef CONFIG_CPU_CACHE_ALIASING -void flush_cache_mm(struct mm_struct *mm); -void flush_cache_dup_mm(struct mm_struct *mm); -void flush_cache_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end); -void flush_cache_page(struct vm_area_struct *vma, - unsigned long addr, unsigned long pfn); -void flush_cache_kmaps(void); -void flush_cache_vmap(unsigned long start, unsigned long end); -void flush_cache_vunmap(unsigned long start, unsigned long end); - -#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 -void flush_dcache_page(struct page *page); -void copy_to_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, void *src, int len); -void copy_from_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, void *src, int len); - -#define ARCH_HAS_FLUSH_ANON_PAGE -void flush_anon_page(struct vm_area_struct *vma, - struct page *page, unsigned long vaddr); - -#define ARCH_IMPLEMENTS_FLUSH_KERNEL_VMAP_RANGE 1 -void flush_kernel_vmap_range(void *addr, int size); -void invalidate_kernel_vmap_range(void *addr, int size); -#define flush_dcache_mmap_lock(mapping) xa_lock_irq(&(mapping)->i_pages) -#define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&(mapping)->i_pages) - -#else -void flush_icache_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long addr, int len); -#define flush_icache_user_page flush_icache_user_page - -#include -#endif - -#endif /* __NDS32_CACHEFLUSH_H__ */ diff --git a/arch/nds32/include/asm/current.h b/arch/nds32/include/asm/current.h deleted file mode 100644 index 65d30096142b..000000000000 --- a/arch/nds32/include/asm/current.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASM_NDS32_CURRENT_H -#define _ASM_NDS32_CURRENT_H - -#ifndef __ASSEMBLY__ -register struct task_struct *current asm("$r25"); -#endif /* __ASSEMBLY__ */ -#define tsk $r25 - -#endif /* _ASM_NDS32_CURRENT_H */ diff --git a/arch/nds32/include/asm/delay.h b/arch/nds32/include/asm/delay.h deleted file mode 100644 index 56ea3894f8f8..000000000000 --- a/arch/nds32/include/asm/delay.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __NDS32_DELAY_H__ -#define __NDS32_DELAY_H__ - -#include - -/* There is no clocksource cycle counter in the CPU. */ -static inline void __delay(unsigned long loops) -{ - __asm__ __volatile__(".align 2\n" - "1:\n" - "\taddi\t%0, %0, -1\n" - "\tbgtz\t%0, 1b\n" - :"=r"(loops) - :"0"(loops)); -} - -static inline void __udelay(unsigned long usecs, unsigned long lpj) -{ - usecs *= (unsigned long)(((0x8000000000000000ULL / (500000 / HZ)) + - 0x80000000ULL) >> 32); - usecs = (unsigned long)(((unsigned long long)usecs * lpj) >> 32); - __delay(usecs); -} - -#define udelay(usecs) __udelay((usecs), loops_per_jiffy) - -/* make sure "usecs *= ..." in udelay do not overflow. */ -#if HZ >= 1000 -#define MAX_UDELAY_MS 1 -#elif HZ <= 200 -#define MAX_UDELAY_MS 5 -#else -#define MAX_UDELAY_MS (1000 / HZ) -#endif - -#endif diff --git a/arch/nds32/include/asm/elf.h b/arch/nds32/include/asm/elf.h deleted file mode 100644 index 1853dc89b8ac..000000000000 --- a/arch/nds32/include/asm/elf.h +++ /dev/null @@ -1,180 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASMNDS32_ELF_H -#define __ASMNDS32_ELF_H - -/* - * ELF register definitions.. - */ - -#include -#include -#include - -typedef unsigned long elf_greg_t; -typedef unsigned long elf_freg_t[3]; - -extern unsigned int elf_hwcap; - -#define R_NDS32_NONE 0 -#define R_NDS32_16_RELA 19 -#define R_NDS32_32_RELA 20 -#define R_NDS32_9_PCREL_RELA 22 -#define R_NDS32_15_PCREL_RELA 23 -#define R_NDS32_17_PCREL_RELA 24 -#define R_NDS32_25_PCREL_RELA 25 -#define R_NDS32_HI20_RELA 26 -#define R_NDS32_LO12S3_RELA 27 -#define R_NDS32_LO12S2_RELA 28 -#define R_NDS32_LO12S1_RELA 29 -#define R_NDS32_LO12S0_RELA 30 -#define R_NDS32_SDA15S3_RELA 31 -#define R_NDS32_SDA15S2_RELA 32 -#define R_NDS32_SDA15S1_RELA 33 -#define R_NDS32_SDA15S0_RELA 34 -#define R_NDS32_GOT20 37 -#define R_NDS32_25_PLTREL 38 -#define R_NDS32_COPY 39 -#define R_NDS32_GLOB_DAT 40 -#define R_NDS32_JMP_SLOT 41 -#define R_NDS32_RELATIVE 42 -#define R_NDS32_GOTOFF 43 -#define R_NDS32_GOTPC20 44 -#define R_NDS32_GOT_HI20 45 -#define R_NDS32_GOT_LO12 46 -#define R_NDS32_GOTPC_HI20 47 -#define R_NDS32_GOTPC_LO12 48 -#define R_NDS32_GOTOFF_HI20 49 -#define R_NDS32_GOTOFF_LO12 50 -#define R_NDS32_INSN16 51 -#define R_NDS32_LABEL 52 -#define R_NDS32_LONGCALL1 53 -#define R_NDS32_LONGCALL2 54 -#define R_NDS32_LONGCALL3 55 -#define R_NDS32_LONGJUMP1 56 -#define R_NDS32_LONGJUMP2 57 -#define R_NDS32_LONGJUMP3 58 -#define R_NDS32_LOADSTORE 59 -#define R_NDS32_9_FIXED_RELA 60 -#define R_NDS32_15_FIXED_RELA 61 -#define R_NDS32_17_FIXED_RELA 62 -#define R_NDS32_25_FIXED_RELA 63 -#define R_NDS32_PLTREL_HI20 64 -#define R_NDS32_PLTREL_LO12 65 -#define R_NDS32_PLT_GOTREL_HI20 66 -#define R_NDS32_PLT_GOTREL_LO12 67 -#define R_NDS32_LO12S0_ORI_RELA 72 -#define R_NDS32_DWARF2_OP1_RELA 77 -#define R_NDS32_DWARF2_OP2_RELA 78 -#define R_NDS32_DWARF2_LEB_RELA 79 -#define R_NDS32_WORD_9_PCREL_RELA 94 -#define R_NDS32_LONGCALL4 107 -#define R_NDS32_RELA_NOP_MIX 192 -#define R_NDS32_RELA_NOP_MAX 255 - -#define ELF_NGREG (sizeof (struct user_pt_regs) / sizeof(elf_greg_t)) -#define ELF_CORE_COPY_REGS(dest, regs) \ - *(struct user_pt_regs *)&(dest) = (regs)->user_regs; - -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -/* Core file format: The core file is written in such a way that gdb - can understand it and provide useful information to the user (under - linux we use the 'trad-core' bfd). There are quite a number of - obstacles to being able to view the contents of the floating point - registers, and until these are solved you will not be able to view the - contents of them. Actually, you can read in the core file and look at - the contents of the user struct to find out what the floating point - registers contain. - The actual file contents are as follows: - UPAGE: 1 page consisting of a user struct that tells gdb what is present - in the file. Directly after this is a copy of the task_struct, which - is currently not used by gdb, but it may come in useful at some point. - All of the registers are stored as part of the upage. The upage should - always be only one page. - DATA: The data area is stored. We use current->end_text to - current->brk to pick up all of the user variables, plus any memory - that may have been malloced. No attempt is made to determine if a page - is demand-zero or if a page is totally unused, we just cover the entire - range. All of the addresses are rounded in such a way that an integral - number of pages is written. - STACK: We need the stack information in order to get a meaningful - backtrace. We need to write the data from (esp) to - current->start_stack, so we round each of these off in order to be able - to write an integer number of pages. - The minimum core file size is 3 pages, or 12288 bytes. -*/ - -struct user_fp { - unsigned long long fd_regs[32]; - unsigned long fpcsr; -}; - -typedef struct user_fp elf_fpregset_t; - -struct elf32_hdr; -#define elf_check_arch(x) ((x)->e_machine == EM_NDS32) - -/* - * These are used to set parameters in the core dumps. - */ -#define ELF_CLASS ELFCLASS32 -#ifdef __NDS32_EB__ -#define ELF_DATA ELFDATA2MSB -#else -#define ELF_DATA ELFDATA2LSB -#endif -#define ELF_ARCH EM_NDS32 -#define ELF_EXEC_PAGESIZE PAGE_SIZE - -/* This is the location that an ET_DYN program is loaded if exec'ed. Typical - use of this is to invoke "./ld.so someprog" to test out a new version of - the loader. We need to make sure that it is out of the way of the program - that it will "exec", and that there is sufficient room for the brk. */ - -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) - -/* When the program starts, a1 contains a pointer to a function to be - registered with atexit, as per the SVR4 ABI. A value of 0 means we - have no such handler. */ -#define ELF_PLAT_INIT(_r, load_addr) (_r)->uregs[0] = 0 - -/* This yields a mask that user programs can use to figure out what - instruction set this cpu supports. */ - -#define ELF_HWCAP (elf_hwcap) - -#ifdef __KERNEL__ - -#define ELF_PLATFORM (NULL) - -/* Old NetWinder binaries were compiled in such a way that the iBCS - heuristic always trips on them. Until these binaries become uncommon - enough not to care, don't trust the `ibcs' flag here. In any case - there is no other ELF system currently supported by iBCS. - @@ Could print a warning message to encourage users to upgrade. */ -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) - -#endif - - -#if IS_ENABLED(CONFIG_FPU) -#define FPU_AUX_ENT NEW_AUX_ENT(AT_FPUCW, FPCSR_INIT) -#else -#define FPU_AUX_ENT NEW_AUX_ENT(AT_IGNORE, 0) -#endif - -#define ARCH_DLINFO \ -do { \ - /* Optional FPU initialization */ \ - FPU_AUX_ENT; \ - \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, \ - (elf_addr_t)current->mm->context.vdso); \ -} while (0) -#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 -struct linux_binprm; -int arch_setup_additional_pages(struct linux_binprm *, int); - -#endif diff --git a/arch/nds32/include/asm/fixmap.h b/arch/nds32/include/asm/fixmap.h deleted file mode 100644 index 2fa09a2de428..000000000000 --- a/arch/nds32/include/asm/fixmap.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_FIXMAP_H -#define __ASM_NDS32_FIXMAP_H - -#ifdef CONFIG_HIGHMEM -#include -#include -#endif - -enum fixed_addresses { - FIX_HOLE, - FIX_KMAP_RESERVED, - FIX_KMAP_BEGIN, -#ifdef CONFIG_HIGHMEM - FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_MAX_IDX * NR_CPUS) - 1, -#endif - FIX_EARLYCON_MEM_BASE, - __end_of_fixed_addresses -}; -#define FIXADDR_TOP ((unsigned long) (-(16 * PAGE_SIZE))) -#define FIXADDR_SIZE ((__end_of_fixed_addresses) << PAGE_SHIFT) -#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) -#define FIXMAP_PAGE_IO __pgprot(PAGE_DEVICE) -void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot); - -#include -#endif /* __ASM_NDS32_FIXMAP_H */ diff --git a/arch/nds32/include/asm/fpu.h b/arch/nds32/include/asm/fpu.h deleted file mode 100644 index 8294ed4aaa2c..000000000000 --- a/arch/nds32/include/asm/fpu.h +++ /dev/null @@ -1,126 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2005-2018 Andes Technology Corporation */ - -#ifndef __ASM_NDS32_FPU_H -#define __ASM_NDS32_FPU_H - -#if IS_ENABLED(CONFIG_FPU) -#ifndef __ASSEMBLY__ -#include -#include -#include - -extern bool has_fpu; - -extern void save_fpu(struct task_struct *__tsk); -extern void load_fpu(const struct fpu_struct *fpregs); -extern bool do_fpu_exception(unsigned int subtype, struct pt_regs *regs); -extern int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu); - -#define test_tsk_fpu(regs) (regs->fucop_ctl & FUCOP_CTL_mskCP0EN) - -/* - * Initially load the FPU with signalling NANS. This bit pattern - * has the property that no matter whether considered as single or as - * double precision, it still represents a signalling NAN. - */ - -#define sNAN64 0xFFFFFFFFFFFFFFFFULL -#define sNAN32 0xFFFFFFFFUL - -#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) -/* - * Denormalized number is unsupported by nds32 FPU. Hence the operation - * is treated as underflow cases when the final result is a denormalized - * number. To enhance precision, underflow exception trap should be - * enabled by default and kerenl will re-execute it by fpu emulator - * when getting underflow exception. - */ -#define FPCSR_INIT (FPCSR_mskUDFE | FPCSR_mskIEXE) -#else -#define FPCSR_INIT 0x0UL -#endif - -extern const struct fpu_struct init_fpuregs; - -static inline void disable_ptreg_fpu(struct pt_regs *regs) -{ - regs->fucop_ctl &= ~FUCOP_CTL_mskCP0EN; -} - -static inline void enable_ptreg_fpu(struct pt_regs *regs) -{ - regs->fucop_ctl |= FUCOP_CTL_mskCP0EN; -} - -static inline void enable_fpu(void) -{ - unsigned long fucop_ctl; - - fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) | FUCOP_CTL_mskCP0EN; - __nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL); - __nds32__isb(); -} - -static inline void disable_fpu(void) -{ - unsigned long fucop_ctl; - - fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) & ~FUCOP_CTL_mskCP0EN; - __nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL); - __nds32__isb(); -} - -static inline void lose_fpu(void) -{ - preempt_disable(); -#if IS_ENABLED(CONFIG_LAZY_FPU) - if (last_task_used_math == current) { - last_task_used_math = NULL; -#else - if (test_tsk_fpu(task_pt_regs(current))) { -#endif - save_fpu(current); - } - disable_ptreg_fpu(task_pt_regs(current)); - preempt_enable(); -} - -static inline void own_fpu(void) -{ - preempt_disable(); -#if IS_ENABLED(CONFIG_LAZY_FPU) - if (last_task_used_math != current) { - if (last_task_used_math != NULL) - save_fpu(last_task_used_math); - load_fpu(¤t->thread.fpu); - last_task_used_math = current; - } -#else - if (!test_tsk_fpu(task_pt_regs(current))) { - load_fpu(¤t->thread.fpu); - } -#endif - enable_ptreg_fpu(task_pt_regs(current)); - preempt_enable(); -} - -#if !IS_ENABLED(CONFIG_LAZY_FPU) -static inline void unlazy_fpu(struct task_struct *tsk) -{ - preempt_disable(); - if (test_tsk_fpu(task_pt_regs(tsk))) - save_fpu(tsk); - preempt_enable(); -} -#endif /* !CONFIG_LAZY_FPU */ -static inline void clear_fpu(struct pt_regs *regs) -{ - preempt_disable(); - if (test_tsk_fpu(regs)) - disable_ptreg_fpu(regs); - preempt_enable(); -} -#endif /* CONFIG_FPU */ -#endif /* __ASSEMBLY__ */ -#endif /* __ASM_NDS32_FPU_H */ diff --git a/arch/nds32/include/asm/fpuemu.h b/arch/nds32/include/asm/fpuemu.h deleted file mode 100644 index 63e7ef5f7969..000000000000 --- a/arch/nds32/include/asm/fpuemu.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2005-2018 Andes Technology Corporation */ - -#ifndef __ARCH_NDS32_FPUEMU_H -#define __ARCH_NDS32_FPUEMU_H - -/* - * single precision - */ - -void fadds(void *ft, void *fa, void *fb); -void fsubs(void *ft, void *fa, void *fb); -void fmuls(void *ft, void *fa, void *fb); -void fdivs(void *ft, void *fa, void *fb); -void fs2d(void *ft, void *fa); -void fs2si(void *ft, void *fa); -void fs2si_z(void *ft, void *fa); -void fs2ui(void *ft, void *fa); -void fs2ui_z(void *ft, void *fa); -void fsi2s(void *ft, void *fa); -void fui2s(void *ft, void *fa); -void fsqrts(void *ft, void *fa); -void fnegs(void *ft, void *fa); -int fcmps(void *ft, void *fa, void *fb, int cop); - -/* - * double precision - */ -void faddd(void *ft, void *fa, void *fb); -void fsubd(void *ft, void *fa, void *fb); -void fmuld(void *ft, void *fa, void *fb); -void fdivd(void *ft, void *fa, void *fb); -void fsqrtd(void *ft, void *fa); -void fd2s(void *ft, void *fa); -void fd2si(void *ft, void *fa); -void fd2si_z(void *ft, void *fa); -void fd2ui(void *ft, void *fa); -void fd2ui_z(void *ft, void *fa); -void fsi2d(void *ft, void *fa); -void fui2d(void *ft, void *fa); -void fnegd(void *ft, void *fa); -int fcmpd(void *ft, void *fa, void *fb, int cop); - -#endif /* __ARCH_NDS32_FPUEMU_H */ diff --git a/arch/nds32/include/asm/ftrace.h b/arch/nds32/include/asm/ftrace.h deleted file mode 100644 index 2f96cc96aa35..000000000000 --- a/arch/nds32/include/asm/ftrace.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef __ASM_NDS32_FTRACE_H -#define __ASM_NDS32_FTRACE_H - -#ifdef CONFIG_FUNCTION_TRACER - -#define HAVE_FUNCTION_GRAPH_FP_TEST - -#define MCOUNT_ADDR ((unsigned long)(_mcount)) -/* mcount call is composed of three instructions: - * sethi + ori + jral - */ -#define MCOUNT_INSN_SIZE 12 - -extern void _mcount(unsigned long parent_ip); - -#ifdef CONFIG_DYNAMIC_FTRACE - -#define FTRACE_ADDR ((unsigned long)_ftrace_caller) - -#ifdef __NDS32_EL__ -#define INSN_NOP 0x09000040 -#define INSN_SIZE(insn) (((insn & 0x00000080) == 0) ? 4 : 2) -#define IS_SETHI(insn) ((insn & 0x000000fe) == 0x00000046) -#define ENDIAN_CONVERT(insn) be32_to_cpu(insn) -#else /* __NDS32_EB__ */ -#define INSN_NOP 0x40000009 -#define INSN_SIZE(insn) (((insn & 0x80000000) == 0) ? 4 : 2) -#define IS_SETHI(insn) ((insn & 0xfe000000) == 0x46000000) -#define ENDIAN_CONVERT(insn) (insn) -#endif - -extern void _ftrace_caller(unsigned long parent_ip); -static inline unsigned long ftrace_call_adjust(unsigned long addr) -{ - return addr; -} -struct dyn_arch_ftrace { -}; - -#endif /* CONFIG_DYNAMIC_FTRACE */ - -#endif /* CONFIG_FUNCTION_TRACER */ - -#endif /* __ASM_NDS32_FTRACE_H */ diff --git a/arch/nds32/include/asm/futex.h b/arch/nds32/include/asm/futex.h deleted file mode 100644 index 4223f473bd36..000000000000 --- a/arch/nds32/include/asm/futex.h +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __NDS32_FUTEX_H__ -#define __NDS32_FUTEX_H__ - -#include -#include -#include - -#define __futex_atomic_ex_table(err_reg) \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 4f\n" \ - " .long 2b, 4f\n" \ - " .popsection\n" \ - " .pushsection .fixup,\"ax\"\n" \ - "4: move %0, " err_reg "\n" \ - " b 3b\n" \ - " .popsection" - -#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ - smp_mb(); \ - asm volatile( \ - " movi $ta, #0\n" \ - "1: llw %1, [%2+$ta]\n" \ - " " insn "\n" \ - "2: scw %0, [%2+$ta]\n" \ - " beqz %0, 1b\n" \ - " movi %0, #0\n" \ - "3:\n" \ - __futex_atomic_ex_table("%4") \ - : "=&r" (ret), "=&r" (oldval) \ - : "r" (uaddr), "r" (oparg), "i" (-EFAULT) \ - : "cc", "memory") -static inline int -futex_atomic_cmpxchg_inatomic(u32 * uval, u32 __user * uaddr, - u32 oldval, u32 newval) -{ - int ret = 0; - u32 val, tmp, flags; - - if (!access_ok(uaddr, sizeof(u32))) - return -EFAULT; - - smp_mb(); - asm volatile (" movi $ta, #0\n" - "1: llw %1, [%6 + $ta]\n" - " sub %3, %1, %4\n" - " cmovz %2, %5, %3\n" - " cmovn %2, %1, %3\n" - "2: scw %2, [%6 + $ta]\n" - " beqz %2, 1b\n" - "3:\n " __futex_atomic_ex_table("%7") - :"+&r"(ret), "=&r"(val), "=&r"(tmp), "=&r"(flags) - :"r"(oldval), "r"(newval), "r"(uaddr), "i"(-EFAULT) - :"$ta", "memory"); - smp_mb(); - - *uval = val; - return ret; -} - -static inline int -arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) -{ - int oldval = 0, ret; - - if (!access_ok(uaddr, sizeof(u32))) - return -EFAULT; - switch (op) { - case FUTEX_OP_SET: - __futex_atomic_op("move %0, %3", ret, oldval, tmp, uaddr, - oparg); - break; - case FUTEX_OP_ADD: - __futex_atomic_op("add %0, %1, %3", ret, oldval, tmp, uaddr, - oparg); - break; - case FUTEX_OP_OR: - __futex_atomic_op("or %0, %1, %3", ret, oldval, tmp, uaddr, - oparg); - break; - case FUTEX_OP_ANDN: - __futex_atomic_op("and %0, %1, %3", ret, oldval, tmp, uaddr, - ~oparg); - break; - case FUTEX_OP_XOR: - __futex_atomic_op("xor %0, %1, %3", ret, oldval, tmp, uaddr, - oparg); - break; - default: - ret = -ENOSYS; - } - - if (!ret) - *oval = oldval; - - return ret; -} -#endif /* __NDS32_FUTEX_H__ */ diff --git a/arch/nds32/include/asm/highmem.h b/arch/nds32/include/asm/highmem.h deleted file mode 100644 index 16159a8716f2..000000000000 --- a/arch/nds32/include/asm/highmem.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASM_HIGHMEM_H -#define _ASM_HIGHMEM_H - -#include -#include - -/* - * Right now we initialize only a single pte table. It can be extended - * easily, subsequent pte tables have to be allocated in one physical - * chunk of RAM. - */ -/* - * Ordering is (from lower to higher memory addresses): - * - * high_memory - * Persistent kmap area - * PKMAP_BASE - * fixed_addresses - * FIXADDR_START - * FIXADDR_TOP - * Vmalloc area - * VMALLOC_START - * VMALLOC_END - */ -#define PKMAP_BASE ((FIXADDR_START - PGDIR_SIZE) & (PGDIR_MASK)) -#define LAST_PKMAP PTRS_PER_PTE -#define LAST_PKMAP_MASK (LAST_PKMAP - 1) -#define PKMAP_NR(virt) (((virt) - (PKMAP_BASE)) >> PAGE_SHIFT) -#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) - -static inline void flush_cache_kmaps(void) -{ - cpu_dcache_wbinval_all(); -} - -/* declarations for highmem.c */ -extern unsigned long highstart_pfn, highend_pfn; - -extern pte_t *pkmap_page_table; - -extern void kmap_init(void); - -/* - * FIXME: The below looks broken vs. a kmap_atomic() in task context which - * is interupted and another kmap_atomic() happens in interrupt context. - * But what do I know about nds32. -- tglx - */ -#define arch_kmap_local_post_map(vaddr, pteval) \ - do { \ - __nds32__tlbop_inv(vaddr); \ - __nds32__mtsr_dsb(vaddr, NDS32_SR_TLB_VPN); \ - __nds32__tlbop_rwr(pteval); \ - __nds32__isb(); \ - } while (0) - -#define arch_kmap_local_pre_unmap(vaddr) \ - do { \ - __nds32__tlbop_inv(vaddr); \ - __nds32__isb(); \ - } while (0) - -#endif diff --git a/arch/nds32/include/asm/io.h b/arch/nds32/include/asm/io.h deleted file mode 100644 index e57378d04006..000000000000 --- a/arch/nds32/include/asm/io.h +++ /dev/null @@ -1,84 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_IO_H -#define __ASM_NDS32_IO_H - -#include - -#define __raw_writeb __raw_writeb -static inline void __raw_writeb(u8 val, volatile void __iomem *addr) -{ - asm volatile("sbi %0, [%1]" : : "r" (val), "r" (addr)); -} - -#define __raw_writew __raw_writew -static inline void __raw_writew(u16 val, volatile void __iomem *addr) -{ - asm volatile("shi %0, [%1]" : : "r" (val), "r" (addr)); -} - -#define __raw_writel __raw_writel -static inline void __raw_writel(u32 val, volatile void __iomem *addr) -{ - asm volatile("swi %0, [%1]" : : "r" (val), "r" (addr)); -} - -#define __raw_readb __raw_readb -static inline u8 __raw_readb(const volatile void __iomem *addr) -{ - u8 val; - - asm volatile("lbi %0, [%1]" : "=r" (val) : "r" (addr)); - return val; -} - -#define __raw_readw __raw_readw -static inline u16 __raw_readw(const volatile void __iomem *addr) -{ - u16 val; - - asm volatile("lhi %0, [%1]" : "=r" (val) : "r" (addr)); - return val; -} - -#define __raw_readl __raw_readl -static inline u32 __raw_readl(const volatile void __iomem *addr) -{ - u32 val; - - asm volatile("lwi %0, [%1]" : "=r" (val) : "r" (addr)); - return val; -} - -#define __iormb() rmb() -#define __iowmb() wmb() - -/* - * {read,write}{b,w,l,q}_relaxed() are like the regular version, but - * are not guaranteed to provide ordering against spinlocks or memory - * accesses. - */ - -#define readb_relaxed(c) ({ u8 __v = __raw_readb(c); __v; }) -#define readw_relaxed(c) ({ u16 __v = le16_to_cpu((__force __le16)__raw_readw(c)); __v; }) -#define readl_relaxed(c) ({ u32 __v = le32_to_cpu((__force __le32)__raw_readl(c)); __v; }) -#define writeb_relaxed(v,c) ((void)__raw_writeb((v),(c))) -#define writew_relaxed(v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),(c))) -#define writel_relaxed(v,c) ((void)__raw_writel((__force u32)cpu_to_le32(v),(c))) - -/* - * {read,write}{b,w,l,q}() access little endian memory and return result in - * native endianness. - */ -#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; }) -#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; }) -#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; }) - -#define writeb(v,c) ({ __iowmb(); writeb_relaxed((v),(c)); }) -#define writew(v,c) ({ __iowmb(); writew_relaxed((v),(c)); }) -#define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); }) - -#include - -#endif /* __ASM_NDS32_IO_H */ diff --git a/arch/nds32/include/asm/irqflags.h b/arch/nds32/include/asm/irqflags.h deleted file mode 100644 index 51ef800bb301..000000000000 --- a/arch/nds32/include/asm/irqflags.h +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include - -#define arch_local_irq_disable() \ - GIE_DISABLE(); - -#define arch_local_irq_enable() \ - GIE_ENABLE(); -static inline unsigned long arch_local_irq_save(void) -{ - unsigned long flags; - flags = __nds32__mfsr(NDS32_SR_PSW) & PSW_mskGIE; - GIE_DISABLE(); - return flags; -} - -static inline unsigned long arch_local_save_flags(void) -{ - unsigned long flags; - flags = __nds32__mfsr(NDS32_SR_PSW) & PSW_mskGIE; - return flags; -} - -static inline void arch_local_irq_restore(unsigned long flags) -{ - if(flags) - GIE_ENABLE(); -} - -static inline int arch_irqs_disabled_flags(unsigned long flags) -{ - return !flags; -} - -static inline int arch_irqs_disabled(void) -{ - return arch_irqs_disabled_flags(arch_local_save_flags()); -} diff --git a/arch/nds32/include/asm/l2_cache.h b/arch/nds32/include/asm/l2_cache.h deleted file mode 100644 index 3ea48e19e6de..000000000000 --- a/arch/nds32/include/asm/l2_cache.h +++ /dev/null @@ -1,137 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef L2_CACHE_H -#define L2_CACHE_H - -/* CCTL_CMD_OP */ -#define L2_CA_CONF_OFF 0x0 -#define L2_IF_CONF_OFF 0x4 -#define L2CC_SETUP_OFF 0x8 -#define L2CC_PROT_OFF 0xC -#define L2CC_CTRL_OFF 0x10 -#define L2_INT_EN_OFF 0x20 -#define L2_STA_OFF 0x24 -#define RDERR_ADDR_OFF 0x28 -#define WRERR_ADDR_OFF 0x2c -#define EVDPTERR_ADDR_OFF 0x30 -#define IMPL3ERR_ADDR_OFF 0x34 -#define L2_CNT0_CTRL_OFF 0x40 -#define L2_EVNT_CNT0_OFF 0x44 -#define L2_CNT1_CTRL_OFF 0x48 -#define L2_EVNT_CNT1_OFF 0x4c -#define L2_CCTL_CMD_OFF 0x60 -#define L2_CCTL_STATUS_OFF 0x64 -#define L2_LINE_TAG_OFF 0x68 -#define L2_LINE_DPT_OFF 0x70 - -#define CCTL_CMD_L2_IX_INVAL 0x0 -#define CCTL_CMD_L2_PA_INVAL 0x1 -#define CCTL_CMD_L2_IX_WB 0x2 -#define CCTL_CMD_L2_PA_WB 0x3 -#define CCTL_CMD_L2_PA_WBINVAL 0x5 -#define CCTL_CMD_L2_SYNC 0xa - -/* CCTL_CMD_TYPE */ -#define CCTL_SINGLE_CMD 0 -#define CCTL_BLOCK_CMD 0x10 -#define CCTL_ALL_CMD 0x10 - -/****************************************************************************** - * L2_CA_CONF (Cache architecture configuration) - *****************************************************************************/ -#define L2_CA_CONF_offL2SET 0 -#define L2_CA_CONF_offL2WAY 4 -#define L2_CA_CONF_offL2CLSZ 8 -#define L2_CA_CONF_offL2DW 11 -#define L2_CA_CONF_offL2PT 14 -#define L2_CA_CONF_offL2VER 16 - -#define L2_CA_CONF_mskL2SET (0xFUL << L2_CA_CONF_offL2SET) -#define L2_CA_CONF_mskL2WAY (0xFUL << L2_CA_CONF_offL2WAY) -#define L2_CA_CONF_mskL2CLSZ (0x7UL << L2_CA_CONF_offL2CLSZ) -#define L2_CA_CONF_mskL2DW (0x7UL << L2_CA_CONF_offL2DW) -#define L2_CA_CONF_mskL2PT (0x3UL << L2_CA_CONF_offL2PT) -#define L2_CA_CONF_mskL2VER (0xFFFFUL << L2_CA_CONF_offL2VER) - -/****************************************************************************** - * L2CC_SETUP (L2CC Setup register) - *****************************************************************************/ -#define L2CC_SETUP_offPART 0 -#define L2CC_SETUP_mskPART (0x3UL << L2CC_SETUP_offPART) -#define L2CC_SETUP_offDDLATC 4 -#define L2CC_SETUP_mskDDLATC (0x3UL << L2CC_SETUP_offDDLATC) -#define L2CC_SETUP_offTDLATC 8 -#define L2CC_SETUP_mskTDLATC (0x3UL << L2CC_SETUP_offTDLATC) - -/****************************************************************************** - * L2CC_PROT (L2CC Protect register) - *****************************************************************************/ -#define L2CC_PROT_offMRWEN 31 -#define L2CC_PROT_mskMRWEN (0x1UL << L2CC_PROT_offMRWEN) - -/****************************************************************************** - * L2_CCTL_STATUS_Mn (The L2CCTL command working status for Master n) - *****************************************************************************/ -#define L2CC_CTRL_offEN 31 -#define L2CC_CTRL_mskEN (0x1UL << L2CC_CTRL_offEN) - -/****************************************************************************** - * L2_CCTL_STATUS_Mn (The L2CCTL command working status for Master n) - *****************************************************************************/ -#define L2_CCTL_STATUS_offCMD_COMP 31 -#define L2_CCTL_STATUS_mskCMD_COMP (0x1 << L2_CCTL_STATUS_offCMD_COMP) - -extern void __iomem *atl2c_base; -#include -#include -#include - -#define L2C_R_REG(offset) readl(atl2c_base + offset) -#define L2C_W_REG(offset, value) writel(value, atl2c_base + offset) - -#define L2_CMD_RDY() \ - do{;}while((L2C_R_REG(L2_CCTL_STATUS_OFF) & L2_CCTL_STATUS_mskCMD_COMP) == 0) - -static inline unsigned long L2_CACHE_SET(void) -{ - return 64 << ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2SET) >> - L2_CA_CONF_offL2SET); -} - -static inline unsigned long L2_CACHE_WAY(void) -{ - return 1 + - ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2WAY) >> - L2_CA_CONF_offL2WAY); -} - -static inline unsigned long L2_CACHE_LINE_SIZE(void) -{ - - return 4 << ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2CLSZ) >> - L2_CA_CONF_offL2CLSZ); -} - -static inline unsigned long GET_L2CC_CTRL_CPU(unsigned long cpu) -{ - if (cpu == smp_processor_id()) - return L2C_R_REG(L2CC_CTRL_OFF); - return L2C_R_REG(L2CC_CTRL_OFF + (cpu << 8)); -} - -static inline void SET_L2CC_CTRL_CPU(unsigned long cpu, unsigned long val) -{ - if (cpu == smp_processor_id()) - L2C_W_REG(L2CC_CTRL_OFF, val); - else - L2C_W_REG(L2CC_CTRL_OFF + (cpu << 8), val); -} - -static inline unsigned long GET_L2CC_STATUS_CPU(unsigned long cpu) -{ - if (cpu == smp_processor_id()) - return L2C_R_REG(L2_CCTL_STATUS_OFF); - return L2C_R_REG(L2_CCTL_STATUS_OFF + (cpu << 8)); -} -#endif diff --git a/arch/nds32/include/asm/linkage.h b/arch/nds32/include/asm/linkage.h deleted file mode 100644 index a696469abb70..000000000000 --- a/arch/nds32/include/asm/linkage.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_LINKAGE_H -#define __ASM_LINKAGE_H - -/* This file is required by include/linux/linkage.h */ -#define __ALIGN .align 2 -#define __ALIGN_STR ".align 2" - -#endif diff --git a/arch/nds32/include/asm/memory.h b/arch/nds32/include/asm/memory.h deleted file mode 100644 index 62faafbc28e4..000000000000 --- a/arch/nds32/include/asm/memory.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_MEMORY_H -#define __ASM_NDS32_MEMORY_H - -#include -#include - -#ifndef __ASSEMBLY__ -#include -#endif - -#ifndef PHYS_OFFSET -#define PHYS_OFFSET (0x0) -#endif - -/* - * TASK_SIZE - the maximum size of a user space task. - * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area - */ -#define TASK_SIZE ((CONFIG_PAGE_OFFSET) - (SZ_32M)) -#define TASK_UNMAPPED_BASE ALIGN(TASK_SIZE / 3, SZ_32M) -#define PAGE_OFFSET (CONFIG_PAGE_OFFSET) - -/* - * Physical vs virtual RAM address space conversion. These are - * private definitions which should NOT be used outside memory.h - * files. Use virt_to_phys/phys_to_virt/__pa/__va instead. - */ -#ifndef __virt_to_phys -#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) -#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) -#endif - -/* - * The module space lives between the addresses given by TASK_SIZE - * and PAGE_OFFSET - it must be within 32MB of the kernel text. - */ -#define MODULES_END (PAGE_OFFSET) -#define MODULES_VADDR (MODULES_END - SZ_32M) - -#if TASK_SIZE > MODULES_VADDR -#error Top of user space clashes with start of module space -#endif - -#ifndef __ASSEMBLY__ - -/* - * PFNs are used to describe any physical page; this means - * PFN 0 == physical address 0. - * - * This is the PFN of the first RAM page in the kernel - * direct-mapped view. We assume this is the first page - * of RAM in the mem_map as well. - */ -#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT) - -/* - * Drivers should NOT use these either. - */ -#define __pa(x) __virt_to_phys((unsigned long)(x)) -#define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) - -/* - * Conversion between a struct page and a physical address. - * - * Note: when converting an unknown physical address to a - * struct page, the resulting pointer must be validated - * using VALID_PAGE(). It must return an invalid struct page - * for any physical address not corresponding to a system - * RAM address. - * - * pfn_valid(pfn) indicates whether a PFN number is valid - * - * virt_to_page(k) convert a _valid_ virtual address to struct page * - * virt_addr_valid(k) indicates whether a virtual address is valid - */ -#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET -#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) - -#define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) -#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) - -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - -#endif - -#include - -#endif diff --git a/arch/nds32/include/asm/mmu.h b/arch/nds32/include/asm/mmu.h deleted file mode 100644 index 89d63afee455..000000000000 --- a/arch/nds32/include/asm/mmu.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __NDS32_MMU_H -#define __NDS32_MMU_H - -typedef struct { - unsigned int id; - void *vdso; -} mm_context_t; - -#endif diff --git a/arch/nds32/include/asm/mmu_context.h b/arch/nds32/include/asm/mmu_context.h deleted file mode 100644 index c651bc8cacdc..000000000000 --- a/arch/nds32/include/asm/mmu_context.h +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_MMU_CONTEXT_H -#define __ASM_NDS32_MMU_CONTEXT_H - -#include -#include -#include -#include - -#define init_new_context init_new_context -static inline int -init_new_context(struct task_struct *tsk, struct mm_struct *mm) -{ - mm->context.id = 0; - return 0; -} - -#define CID_BITS 9 -extern spinlock_t cid_lock; -extern unsigned int cpu_last_cid; - -static inline void __new_context(struct mm_struct *mm) -{ - unsigned int cid; - unsigned long flags; - - spin_lock_irqsave(&cid_lock, flags); - cid = cpu_last_cid; - cpu_last_cid += 1 << TLB_MISC_offCID; - if (cpu_last_cid == 0) - cpu_last_cid = 1 << TLB_MISC_offCID << CID_BITS; - - if ((cid & TLB_MISC_mskCID) == 0) - flush_tlb_all(); - spin_unlock_irqrestore(&cid_lock, flags); - - mm->context.id = cid; -} - -static inline void check_context(struct mm_struct *mm) -{ - if (unlikely - ((mm->context.id ^ cpu_last_cid) >> TLB_MISC_offCID >> CID_BITS)) - __new_context(mm); -} - -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk) -{ - unsigned int cpu = smp_processor_id(); - - if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) { - check_context(next); - cpu_switch_mm(next); - } -} - -#include - -#endif diff --git a/arch/nds32/include/asm/nds32.h b/arch/nds32/include/asm/nds32.h deleted file mode 100644 index 4994f6a9e0a0..000000000000 --- a/arch/nds32/include/asm/nds32.h +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASM_NDS32_NDS32_H_ -#define _ASM_NDS32_NDS32_H_ - -#include -#include - -#ifndef __ASSEMBLY__ -#include -#include -#include - -#ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE -#define FP_OFFSET (-3) -#else -#define FP_OFFSET (-2) -#endif -#define LP_OFFSET (-1) - -extern void __init early_trap_init(void); -static inline void GIE_ENABLE(void) -{ - mb(); - __nds32__gie_en(); -} - -static inline void GIE_DISABLE(void) -{ - mb(); - __nds32__gie_dis(); -} - -static inline unsigned long CACHE_SET(unsigned char cache) -{ - - if (cache == ICACHE) - return 64 << ((__nds32__mfsr(NDS32_SR_ICM_CFG) & ICM_CFG_mskISET) >> - ICM_CFG_offISET); - else - return 64 << ((__nds32__mfsr(NDS32_SR_DCM_CFG) & DCM_CFG_mskDSET) >> - DCM_CFG_offDSET); -} - -static inline unsigned long CACHE_WAY(unsigned char cache) -{ - - if (cache == ICACHE) - return 1 + - ((__nds32__mfsr(NDS32_SR_ICM_CFG) & ICM_CFG_mskIWAY) >> ICM_CFG_offIWAY); - else - return 1 + - ((__nds32__mfsr(NDS32_SR_DCM_CFG) & DCM_CFG_mskDWAY) >> DCM_CFG_offDWAY); -} - -static inline unsigned long CACHE_LINE_SIZE(unsigned char cache) -{ - - if (cache == ICACHE) - return 8 << - (((__nds32__mfsr(NDS32_SR_ICM_CFG) & ICM_CFG_mskISZ) >> ICM_CFG_offISZ) - 1); - else - return 8 << - (((__nds32__mfsr(NDS32_SR_DCM_CFG) & DCM_CFG_mskDSZ) >> DCM_CFG_offDSZ) - 1); -} - -#endif /* __ASSEMBLY__ */ - -#define IVB_BASE PHYS_OFFSET /* in user space for intr/exc/trap/break table base, 64KB aligned - * We defined at the start of the physical memory */ - -/* dispatched sub-entry exception handler numbering */ -#define RD_PROT 0 /* read protrection */ -#define WRT_PROT 1 /* write protection */ -#define NOEXEC 2 /* non executable */ -#define PAGE_MODIFY 3 /* page modified */ -#define ACC_BIT 4 /* access bit */ -#define RESVED_PTE 5 /* reserved PTE attribute */ -/* reserved 6 ~ 16 */ - -#endif /* _ASM_NDS32_NDS32_H_ */ diff --git a/arch/nds32/include/asm/nds32_fpu_inst.h b/arch/nds32/include/asm/nds32_fpu_inst.h deleted file mode 100644 index 1e4b86a90a48..000000000000 --- a/arch/nds32/include/asm/nds32_fpu_inst.h +++ /dev/null @@ -1,109 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2005-2018 Andes Technology Corporation */ - -#ifndef __NDS32_FPU_INST_H -#define __NDS32_FPU_INST_H - -#define cop0_op 0x35 - -/* - * COP0 field of opcodes. - */ -#define fs1_op 0x0 -#define fs2_op 0x4 -#define fd1_op 0x8 -#define fd2_op 0xc - -/* - * FS1 opcode. - */ -enum fs1 { - fadds_op, fsubs_op, fcpynss_op, fcpyss_op, - fmadds_op, fmsubs_op, fcmovns_op, fcmovzs_op, - fnmadds_op, fnmsubs_op, - fmuls_op = 0xc, fdivs_op, - fs1_f2op_op = 0xf -}; - -/* - * FS1/F2OP opcode. - */ -enum fs1_f2 { - fs2d_op, fsqrts_op, - fui2s_op = 0x8, fsi2s_op = 0xc, - fs2ui_op = 0x10, fs2ui_z_op = 0x14, - fs2si_op = 0x18, fs2si_z_op = 0x1c -}; - -/* - * FS2 opcode. - */ -enum fs2 { - fcmpeqs_op, fcmpeqs_e_op, fcmplts_op, fcmplts_e_op, - fcmples_op, fcmples_e_op, fcmpuns_op, fcmpuns_e_op -}; - -/* - * FD1 opcode. - */ -enum fd1 { - faddd_op, fsubd_op, fcpynsd_op, fcpysd_op, - fmaddd_op, fmsubd_op, fcmovnd_op, fcmovzd_op, - fnmaddd_op, fnmsubd_op, - fmuld_op = 0xc, fdivd_op, fd1_f2op_op = 0xf -}; - -/* - * FD1/F2OP opcode. - */ -enum fd1_f2 { - fd2s_op, fsqrtd_op, - fui2d_op = 0x8, fsi2d_op = 0xc, - fd2ui_op = 0x10, fd2ui_z_op = 0x14, - fd2si_op = 0x18, fd2si_z_op = 0x1c -}; - -/* - * FD2 opcode. - */ -enum fd2 { - fcmpeqd_op, fcmpeqd_e_op, fcmpltd_op, fcmpltd_e_op, - fcmpled_op, fcmpled_e_op, fcmpund_op, fcmpund_e_op -}; - -#define NDS32Insn(x) x - -#define I_OPCODE_off 25 -#define NDS32Insn_OPCODE(x) (NDS32Insn(x) >> I_OPCODE_off) - -#define I_OPCODE_offRt 20 -#define I_OPCODE_mskRt (0x1fUL << I_OPCODE_offRt) -#define NDS32Insn_OPCODE_Rt(x) \ - ((NDS32Insn(x) & I_OPCODE_mskRt) >> I_OPCODE_offRt) - -#define I_OPCODE_offRa 15 -#define I_OPCODE_mskRa (0x1fUL << I_OPCODE_offRa) -#define NDS32Insn_OPCODE_Ra(x) \ - ((NDS32Insn(x) & I_OPCODE_mskRa) >> I_OPCODE_offRa) - -#define I_OPCODE_offRb 10 -#define I_OPCODE_mskRb (0x1fUL << I_OPCODE_offRb) -#define NDS32Insn_OPCODE_Rb(x) \ - ((NDS32Insn(x) & I_OPCODE_mskRb) >> I_OPCODE_offRb) - -#define I_OPCODE_offbit1014 10 -#define I_OPCODE_mskbit1014 (0x1fUL << I_OPCODE_offbit1014) -#define NDS32Insn_OPCODE_BIT1014(x) \ - ((NDS32Insn(x) & I_OPCODE_mskbit1014) >> I_OPCODE_offbit1014) - -#define I_OPCODE_offbit69 6 -#define I_OPCODE_mskbit69 (0xfUL << I_OPCODE_offbit69) -#define NDS32Insn_OPCODE_BIT69(x) \ - ((NDS32Insn(x) & I_OPCODE_mskbit69) >> I_OPCODE_offbit69) - -#define I_OPCODE_offCOP0 0 -#define I_OPCODE_mskCOP0 (0x3fUL << I_OPCODE_offCOP0) -#define NDS32Insn_OPCODE_COP0(x) \ - ((NDS32Insn(x) & I_OPCODE_mskCOP0) >> I_OPCODE_offCOP0) - -#endif /* __NDS32_FPU_INST_H */ diff --git a/arch/nds32/include/asm/page.h b/arch/nds32/include/asm/page.h deleted file mode 100644 index add33a7f02c8..000000000000 --- a/arch/nds32/include/asm/page.h +++ /dev/null @@ -1,64 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2005-2017 Andes Technology Corporation - */ - -#ifndef _ASMNDS32_PAGE_H -#define _ASMNDS32_PAGE_H - -#ifdef CONFIG_ANDES_PAGE_SIZE_4KB -#define PAGE_SHIFT 12 -#endif -#ifdef CONFIG_ANDES_PAGE_SIZE_8KB -#define PAGE_SHIFT 13 -#endif -#include -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) - -#ifdef __KERNEL__ - -#ifndef __ASSEMBLY__ - -struct page; -struct vm_area_struct; -#ifdef CONFIG_CPU_CACHE_ALIASING -extern void copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr, struct vm_area_struct *vma); -extern void clear_user_highpage(struct page *page, unsigned long vaddr); - -void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, - struct page *to); -void clear_user_page(void *addr, unsigned long vaddr, struct page *page); -#define __HAVE_ARCH_COPY_USER_HIGHPAGE -#define clear_user_highpage clear_user_highpage -#else -#define clear_user_page(page, vaddr, pg) clear_page(page) -#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) -#endif - -void clear_page(void *page); -void copy_page(void *to, void *from); - -typedef unsigned long pte_t; -typedef unsigned long pgd_t; -typedef unsigned long pgprot_t; - -#define pte_val(x) (x) -#define pgd_val(x) (x) -#define pgprot_val(x) (x) - -#define __pte(x) (x) -#define __pgd(x) (x) -#define __pgprot(x) (x) - -typedef struct page *pgtable_t; - -#include -#include - -#endif /* !__ASSEMBLY__ */ - -#endif /* __KERNEL__ */ - -#endif diff --git a/arch/nds32/include/asm/perf_event.h b/arch/nds32/include/asm/perf_event.h deleted file mode 100644 index fcdff02acc14..000000000000 --- a/arch/nds32/include/asm/perf_event.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2008-2018 Andes Technology Corporation */ - -#ifndef __ASM_PERF_EVENT_H -#define __ASM_PERF_EVENT_H - -/* - * This file is request by Perf, - * please refer to tools/perf/design.txt for more details - */ -struct pt_regs; -unsigned long perf_instruction_pointer(struct pt_regs *regs); -unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) - -#endif diff --git a/arch/nds32/include/asm/pgalloc.h b/arch/nds32/include/asm/pgalloc.h deleted file mode 100644 index a08e1ebca70e..000000000000 --- a/arch/nds32/include/asm/pgalloc.h +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASMNDS32_PGALLOC_H -#define _ASMNDS32_PGALLOC_H - -#include -#include -#include -#include - -#define __HAVE_ARCH_PTE_ALLOC_ONE -#include /* for pte_{alloc,free}_one */ - -extern pgd_t *pgd_alloc(struct mm_struct *mm); -extern void pgd_free(struct mm_struct *mm, pgd_t * pgd); - -static inline pgtable_t pte_alloc_one(struct mm_struct *mm) -{ - pgtable_t pte; - - pte = __pte_alloc_one(mm, GFP_PGTABLE_USER); - if (pte) - cpu_dcache_wb_page((unsigned long)page_address(pte)); - - return pte; -} - -/* - * Populate the pmdp entry with a pointer to the pte. This pmd is part - * of the mm address space. - * - * Ensure that we always set both PMD entries. - */ -static inline void -pmd_populate_kernel(struct mm_struct *mm, pmd_t * pmdp, pte_t * ptep) -{ - unsigned long pte_ptr = (unsigned long)ptep; - unsigned long pmdval; - - BUG_ON(mm != &init_mm); - - /* - * The pmd must be loaded with the physical - * address of the PTE table - */ - pmdval = __pa(pte_ptr) | _PAGE_KERNEL_TABLE; - set_pmd(pmdp, __pmd(pmdval)); -} - -static inline void -pmd_populate(struct mm_struct *mm, pmd_t * pmdp, pgtable_t ptep) -{ - unsigned long pmdval; - - BUG_ON(mm == &init_mm); - - pmdval = page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE; - set_pmd(pmdp, __pmd(pmdval)); -} - -#endif diff --git a/arch/nds32/include/asm/pgtable.h b/arch/nds32/include/asm/pgtable.h deleted file mode 100644 index 419f984eef70..000000000000 --- a/arch/nds32/include/asm/pgtable.h +++ /dev/null @@ -1,377 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASMNDS32_PGTABLE_H -#define _ASMNDS32_PGTABLE_H - -#include -#include - -#include -#include -#ifndef __ASSEMBLY__ -#include -#include -#endif - -#ifdef CONFIG_ANDES_PAGE_SIZE_4KB -#define PGDIR_SHIFT 22 -#define PTRS_PER_PGD 1024 -#define PTRS_PER_PTE 1024 -#endif - -#ifdef CONFIG_ANDES_PAGE_SIZE_8KB -#define PGDIR_SHIFT 24 -#define PTRS_PER_PGD 256 -#define PTRS_PER_PTE 2048 -#endif - -#ifndef __ASSEMBLY__ -extern void __pte_error(const char *file, int line, unsigned long val); -extern void __pgd_error(const char *file, int line, unsigned long val); - -#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) -#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) -#endif /* !__ASSEMBLY__ */ - -#define PMD_SIZE (1UL << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1)) -#define PGDIR_SIZE (1UL << PGDIR_SHIFT) -#define PGDIR_MASK (~(PGDIR_SIZE-1)) - -/* - * This is the lowest virtual address we can permit any user space - * mapping to be mapped at. This is particularly important for - * non-high vector CPUs. - */ -#define FIRST_USER_ADDRESS 0x8000 - -#ifdef CONFIG_HIGHMEM -#define CONSISTENT_BASE ((PKMAP_BASE) - (SZ_2M)) -#define CONSISTENT_END (PKMAP_BASE) -#else -#define CONSISTENT_BASE (FIXADDR_START - SZ_2M) -#define CONSISTENT_END (FIXADDR_START) -#endif -#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT) - -#ifdef CONFIG_HIGHMEM -#ifndef __ASSEMBLY__ -#include -#endif -#endif - -#define VMALLOC_RESERVE SZ_128M -#define VMALLOC_END (CONSISTENT_BASE - PAGE_SIZE) -#define VMALLOC_START ((VMALLOC_END) - VMALLOC_RESERVE) -#define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define MAXMEM __pa(VMALLOC_START) -#define MAXMEM_PFN PFN_DOWN(MAXMEM) - -#define FIRST_USER_PGD_NR 0 -#define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) + FIRST_USER_PGD_NR) - -/* L2 PTE */ -#define _PAGE_V (1UL << 0) - -#define _PAGE_M_XKRW (0UL << 1) -#define _PAGE_M_UR_KR (1UL << 1) -#define _PAGE_M_UR_KRW (2UL << 1) -#define _PAGE_M_URW_KRW (3UL << 1) -#define _PAGE_M_KR (5UL << 1) -#define _PAGE_M_KRW (7UL << 1) - -#define _PAGE_D (1UL << 4) -#define _PAGE_E (1UL << 5) -#define _PAGE_A (1UL << 6) -#define _PAGE_G (1UL << 7) - -#define _PAGE_C_DEV (0UL << 8) -#define _PAGE_C_DEV_WB (1UL << 8) -#define _PAGE_C_MEM (2UL << 8) -#define _PAGE_C_MEM_SHRD_WB (4UL << 8) -#define _PAGE_C_MEM_SHRD_WT (5UL << 8) -#define _PAGE_C_MEM_WB (6UL << 8) -#define _PAGE_C_MEM_WT (7UL << 8) - -#define _PAGE_L (1UL << 11) - -#define _HAVE_PAGE_L (_PAGE_L) -#define _PAGE_FILE (1UL << 1) -#define _PAGE_YOUNG 0 -#define _PAGE_M_MASK _PAGE_M_KRW -#define _PAGE_C_MASK _PAGE_C_MEM_WT - -#ifdef CONFIG_SMP -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -#define _PAGE_CACHE_SHRD _PAGE_C_MEM_SHRD_WT -#else -#define _PAGE_CACHE_SHRD _PAGE_C_MEM_SHRD_WB -#endif -#else -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -#define _PAGE_CACHE_SHRD _PAGE_C_MEM_WT -#else -#define _PAGE_CACHE_SHRD _PAGE_C_MEM_WB -#endif -#endif - -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -#define _PAGE_CACHE _PAGE_C_MEM_WT -#else -#define _PAGE_CACHE _PAGE_C_MEM_WB -#endif - -#define _PAGE_IOREMAP \ - (_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_G | _PAGE_C_DEV) - -/* - * + Level 1 descriptor (PMD) - */ -#define PMD_TYPE_TABLE 0 - -#ifndef __ASSEMBLY__ - -#define _PAGE_USER_TABLE PMD_TYPE_TABLE -#define _PAGE_KERNEL_TABLE PMD_TYPE_TABLE - -#define PAGE_EXEC __pgprot(_PAGE_V | _PAGE_M_XKRW | _PAGE_E) -#define PAGE_NONE __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_A) -#define PAGE_READ __pgprot(_PAGE_V | _PAGE_M_UR_KR) -#define PAGE_RDWR __pgprot(_PAGE_V | _PAGE_M_URW_KRW | _PAGE_D) -#define PAGE_COPY __pgprot(_PAGE_V | _PAGE_M_UR_KR) - -#define PAGE_UXKRWX_V1 __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD) -#define PAGE_UXKRWX_V2 __pgprot(_PAGE_V | _PAGE_M_XKRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD) -#define PAGE_URXKRWX_V2 __pgprot(_PAGE_V | _PAGE_M_UR_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD) -#define PAGE_CACHE_L1 __pgprot(_HAVE_PAGE_L | _PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE) -#define PAGE_MEMORY __pgprot(_HAVE_PAGE_L | _PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD) -#define PAGE_KERNEL __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD) -#define PAGE_SHARED __pgprot(_PAGE_V | _PAGE_M_URW_KRW | _PAGE_D | _PAGE_CACHE_SHRD) -#define PAGE_DEVICE __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_G | _PAGE_C_DEV) -#endif /* __ASSEMBLY__ */ - -/* xwr */ -#define __P000 (PAGE_NONE | _PAGE_CACHE_SHRD) -#define __P001 (PAGE_READ | _PAGE_CACHE_SHRD) -#define __P010 (PAGE_COPY | _PAGE_CACHE_SHRD) -#define __P011 (PAGE_COPY | _PAGE_CACHE_SHRD) -#define __P100 (PAGE_EXEC | _PAGE_CACHE_SHRD) -#define __P101 (PAGE_READ | _PAGE_E | _PAGE_CACHE_SHRD) -#define __P110 (PAGE_COPY | _PAGE_E | _PAGE_CACHE_SHRD) -#define __P111 (PAGE_COPY | _PAGE_E | _PAGE_CACHE_SHRD) - -#define __S000 (PAGE_NONE | _PAGE_CACHE_SHRD) -#define __S001 (PAGE_READ | _PAGE_CACHE_SHRD) -#define __S010 (PAGE_RDWR | _PAGE_CACHE_SHRD) -#define __S011 (PAGE_RDWR | _PAGE_CACHE_SHRD) -#define __S100 (PAGE_EXEC | _PAGE_CACHE_SHRD) -#define __S101 (PAGE_READ | _PAGE_E | _PAGE_CACHE_SHRD) -#define __S110 (PAGE_RDWR | _PAGE_E | _PAGE_CACHE_SHRD) -#define __S111 (PAGE_RDWR | _PAGE_E | _PAGE_CACHE_SHRD) - -#ifndef __ASSEMBLY__ -/* - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -extern struct page *empty_zero_page; -extern void paging_init(void); -#define ZERO_PAGE(vaddr) (empty_zero_page) - -#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) -#define pfn_pte(pfn,prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))) - -#define pte_none(pte) !(pte_val(pte)) -#define pte_clear(mm,addr,ptep) set_pte_at((mm),(addr),(ptep), __pte(0)) -#define pte_page(pte) (pfn_to_page(pte_pfn(pte))) - -static unsigned long pmd_page_vaddr(pmd_t pmd) -{ - return ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)); -} - -#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) -/* - * Set a level 1 translation table entry, and clean it out of - * any caches such that the MMUs can load it correctly. - */ -static inline void set_pmd(pmd_t * pmdp, pmd_t pmd) -{ - - *pmdp = pmd; -#if !defined(CONFIG_CPU_DCACHE_DISABLE) && !defined(CONFIG_CPU_DCACHE_WRITETHROUGH) - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (pmdp):"memory"); - __nds32__msync_all(); - __nds32__dsb(); -#endif -} - -/* - * Set a PTE and flush it out - */ -static inline void set_pte(pte_t * ptep, pte_t pte) -{ - - *ptep = pte; -#if !defined(CONFIG_CPU_DCACHE_DISABLE) && !defined(CONFIG_CPU_DCACHE_WRITETHROUGH) - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (ptep):"memory"); - __nds32__msync_all(); - __nds32__dsb(); -#endif -} - -/* - * The following only work if pte_present() is true. - * Undefined behaviour if not.. - */ - -/* - * pte_write: this page is writeable for user mode - * pte_read: this page is readable for user mode - * pte_kernel_write: this page is writeable for kernel mode - * - * We don't have pte_kernel_read because kernel always can read. - * - * */ - -#define pte_present(pte) (pte_val(pte) & _PAGE_V) -#define pte_write(pte) ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_URW_KRW) -#define pte_read(pte) (((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_UR_KR) || \ - ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_UR_KRW) || \ - ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_URW_KRW)) -#define pte_kernel_write(pte) (((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_URW_KRW) || \ - ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_UR_KRW) || \ - ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_KRW) || \ - (((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_XKRW) && pte_exec(pte))) -#define pte_exec(pte) (pte_val(pte) & _PAGE_E) -#define pte_dirty(pte) (pte_val(pte) & _PAGE_D) -#define pte_young(pte) (pte_val(pte) & _PAGE_YOUNG) - -/* - * The following only works if pte_present() is not true. - */ -#define pte_file(pte) (pte_val(pte) & _PAGE_FILE) -#define pte_to_pgoff(x) (pte_val(x) >> 2) -#define pgoff_to_pte(x) __pte(((x) << 2) | _PAGE_FILE) - -#define PTE_FILE_MAX_BITS 29 - -#define PTE_BIT_FUNC(fn,op) \ -static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } - -static inline pte_t pte_wrprotect(pte_t pte) -{ - pte_val(pte) = pte_val(pte) & ~_PAGE_M_MASK; - pte_val(pte) = pte_val(pte) | _PAGE_M_UR_KR; - return pte; -} - -static inline pte_t pte_mkwrite(pte_t pte) -{ - pte_val(pte) = pte_val(pte) & ~_PAGE_M_MASK; - pte_val(pte) = pte_val(pte) | _PAGE_M_URW_KRW; - return pte; -} - -PTE_BIT_FUNC(exprotect, &=~_PAGE_E); -PTE_BIT_FUNC(mkexec, |=_PAGE_E); -PTE_BIT_FUNC(mkclean, &=~_PAGE_D); -PTE_BIT_FUNC(mkdirty, |=_PAGE_D); -PTE_BIT_FUNC(mkold, &=~_PAGE_YOUNG); -PTE_BIT_FUNC(mkyoung, |=_PAGE_YOUNG); - -/* - * Mark the prot value as uncacheable and unbufferable. - */ -#define pgprot_noncached(prot) __pgprot((pgprot_val(prot)&~_PAGE_C_MASK) | _PAGE_C_DEV) -#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot)&~_PAGE_C_MASK) | _PAGE_C_DEV_WB) - -#define pmd_none(pmd) (pmd_val(pmd)&0x1) -#define pmd_present(pmd) (!pmd_none(pmd)) -#define pmd_bad(pmd) pmd_none(pmd) - -#define copy_pmd(pmdpd,pmdps) set_pmd((pmdpd), *(pmdps)) -#define pmd_clear(pmdp) set_pmd((pmdp), __pmd(1)) - -static inline pmd_t __mk_pmd(pte_t * ptep, unsigned long prot) -{ - unsigned long ptr = (unsigned long)ptep; - pmd_t pmd; - - /* - * The pmd must be loaded with the physical - * address of the PTE table - */ - - pmd_val(pmd) = __virt_to_phys(ptr) | prot; - return pmd; -} - -#define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd))) - -/* - * Permanent address of a page. We never have highmem, so this is trivial. - */ -#define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT)) - -/* - * Conversion functions: convert a page and protection to a page entry, - * and a page entry and page directory to the page they refer to. - */ -#define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot) - -/* - * The "pgd_xxx()" functions here are trivial for a folded two-level - * setup: the pgd is never bad, and a pmd always exists (as it's folded - * into the pgd entry) - */ -#define pgd_none(pgd) (0) -#define pgd_bad(pgd) (0) -#define pgd_present(pgd) (1) -#define pgd_clear(pgdp) do { } while (0) - -#define page_pte_prot(page,prot) mk_pte(page, prot) -#define page_pte(page) mk_pte(page, __pgprot(0)) -/* - * L1PTE = $mr1 + ((virt >> PMD_SHIFT) << 2); - * L2PTE = (((virt >> PAGE_SHIFT) & (PTRS_PER_PTE -1 )) << 2); - * PPN = (phys & 0xfffff000); - * -*/ - -static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) -{ - const unsigned long mask = 0xfff; - pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); - return pte; -} - -extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; - -/* Encode and decode a swap entry. - * - * We support up to 32GB of swap on 4k machines - */ -#define __swp_type(x) (((x).val >> 2) & 0x7f) -#define __swp_offset(x) ((x).val >> 9) -#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 9) }) -#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) - -/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ -#define kern_addr_valid(addr) (1) - -/* - * We provide our own arch_get_unmapped_area to cope with VIPT caches. - */ -#define HAVE_ARCH_UNMAPPED_AREA - -/* - * remap a physical address `phys' of size `size' with page protection `prot' - * into virtual address `from' - */ - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASMNDS32_PGTABLE_H */ diff --git a/arch/nds32/include/asm/pmu.h b/arch/nds32/include/asm/pmu.h deleted file mode 100644 index e1ac0b0b8bcf..000000000000 --- a/arch/nds32/include/asm/pmu.h +++ /dev/null @@ -1,386 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2008-2018 Andes Technology Corporation */ - -#ifndef __ASM_PMU_H -#define __ASM_PMU_H - -#include -#include -#include -#include - -/* Has special meaning for perf core implementation */ -#define HW_OP_UNSUPPORTED 0x0 -#define C(_x) PERF_COUNT_HW_CACHE_##_x -#define CACHE_OP_UNSUPPORTED 0x0 - -/* Enough for both software and hardware defined events */ -#define SOFTWARE_EVENT_MASK 0xFF - -#define PFM_OFFSET_MAGIC_0 2 /* DO NOT START FROM 0 */ -#define PFM_OFFSET_MAGIC_1 (PFM_OFFSET_MAGIC_0 + 36) -#define PFM_OFFSET_MAGIC_2 (PFM_OFFSET_MAGIC_1 + 36) - -enum { PFMC0, PFMC1, PFMC2, MAX_COUNTERS }; - -u32 PFM_CTL_OVF[3] = { PFM_CTL_mskOVF0, PFM_CTL_mskOVF1, - PFM_CTL_mskOVF2 }; -u32 PFM_CTL_EN[3] = { PFM_CTL_mskEN0, PFM_CTL_mskEN1, - PFM_CTL_mskEN2 }; -u32 PFM_CTL_OFFSEL[3] = { PFM_CTL_offSEL0, PFM_CTL_offSEL1, - PFM_CTL_offSEL2 }; -u32 PFM_CTL_IE[3] = { PFM_CTL_mskIE0, PFM_CTL_mskIE1, PFM_CTL_mskIE2 }; -u32 PFM_CTL_KS[3] = { PFM_CTL_mskKS0, PFM_CTL_mskKS1, PFM_CTL_mskKS2 }; -u32 PFM_CTL_KU[3] = { PFM_CTL_mskKU0, PFM_CTL_mskKU1, PFM_CTL_mskKU2 }; -u32 PFM_CTL_SEL[3] = { PFM_CTL_mskSEL0, PFM_CTL_mskSEL1, PFM_CTL_mskSEL2 }; -/* - * Perf Events' indices - */ -#define NDS32_IDX_CYCLE_COUNTER 0 -#define NDS32_IDX_COUNTER0 1 -#define NDS32_IDX_COUNTER1 2 - -/* The events for a given PMU register set. */ -struct pmu_hw_events { - /* - * The events that are active on the PMU for the given index. - */ - struct perf_event *events[MAX_COUNTERS]; - - /* - * A 1 bit for an index indicates that the counter is being used for - * an event. A 0 means that the counter can be used. - */ - unsigned long used_mask[BITS_TO_LONGS(MAX_COUNTERS)]; - - /* - * Hardware lock to serialize accesses to PMU registers. Needed for the - * read/modify/write sequences. - */ - raw_spinlock_t pmu_lock; -}; - -struct nds32_pmu { - struct pmu pmu; - cpumask_t active_irqs; - char *name; - irqreturn_t (*handle_irq)(int irq_num, void *dev); - void (*enable)(struct perf_event *event); - void (*disable)(struct perf_event *event); - int (*get_event_idx)(struct pmu_hw_events *hw_events, - struct perf_event *event); - int (*set_event_filter)(struct hw_perf_event *evt, - struct perf_event_attr *attr); - u32 (*read_counter)(struct perf_event *event); - void (*write_counter)(struct perf_event *event, u32 val); - void (*start)(struct nds32_pmu *nds32_pmu); - void (*stop)(struct nds32_pmu *nds32_pmu); - void (*reset)(void *data); - int (*request_irq)(struct nds32_pmu *nds32_pmu, irq_handler_t handler); - void (*free_irq)(struct nds32_pmu *nds32_pmu); - int (*map_event)(struct perf_event *event); - int num_events; - atomic_t active_events; - u64 max_period; - struct platform_device *plat_device; - struct pmu_hw_events *(*get_hw_events)(void); -}; - -#define to_nds32_pmu(p) (container_of(p, struct nds32_pmu, pmu)) - -int nds32_pmu_register(struct nds32_pmu *nds32_pmu, int type); - -u64 nds32_pmu_event_update(struct perf_event *event); - -int nds32_pmu_event_set_period(struct perf_event *event); - -/* - * Common NDS32 SPAv3 event types - * - * Note: An implementation may not be able to count all of these events - * but the encodings are considered to be `reserved' in the case that - * they are not available. - * - * SEL_TOTAL_CYCLES will add an offset is due to ZERO is defined as - * NOT_SUPPORTED EVENT mapping in generic perf code. - * You will need to deal it in the event writing implementation. - */ -enum spav3_counter_0_perf_types { - SPAV3_0_SEL_BASE = -1 + PFM_OFFSET_MAGIC_0, /* counting symbol */ - SPAV3_0_SEL_TOTAL_CYCLES = 0 + PFM_OFFSET_MAGIC_0, - SPAV3_0_SEL_COMPLETED_INSTRUCTION = 1 + PFM_OFFSET_MAGIC_0, - SPAV3_0_SEL_LAST /* counting symbol */ -}; - -enum spav3_counter_1_perf_types { - SPAV3_1_SEL_BASE = -1 + PFM_OFFSET_MAGIC_1, /* counting symbol */ - SPAV3_1_SEL_TOTAL_CYCLES = 0 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_COMPLETED_INSTRUCTION = 1 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_CONDITIONAL_BRANCH = 2 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_TAKEN_CONDITIONAL_BRANCH = 3 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_PREFETCH_INSTRUCTION = 4 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_RET_INST = 5 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_JR_INST = 6 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_JAL_JRAL_INST = 7 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_NOP_INST = 8 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_SCW_INST = 9 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_ISB_DSB_INST = 10 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_CCTL_INST = 11 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_TAKEN_INTERRUPTS = 12 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_LOADS_COMPLETED = 13 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_UITLB_ACCESS = 14 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_UDTLB_ACCESS = 15 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_MTLB_ACCESS = 16 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_CODE_CACHE_ACCESS = 17 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_DATA_DEPENDENCY_STALL_CYCLES = 18 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_DATA_CACHE_MISS_STALL_CYCLES = 19 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_DATA_CACHE_ACCESS = 20 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_DATA_CACHE_MISS = 21 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_LOAD_DATA_CACHE_ACCESS = 22 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_STORE_DATA_CACHE_ACCESS = 23 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_ILM_ACCESS = 24 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_LSU_BIU_CYCLES = 25 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_HPTWK_BIU_CYCLES = 26 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_DMA_BIU_CYCLES = 27 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_CODE_CACHE_FILL_BIU_CYCLES = 28 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_LEGAL_UNALIGN_DCACHE_ACCESS = 29 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_PUSH25 = 30 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_SYSCALLS_INST = 31 + PFM_OFFSET_MAGIC_1, - SPAV3_1_SEL_LAST /* counting symbol */ -}; - -enum spav3_counter_2_perf_types { - SPAV3_2_SEL_BASE = -1 + PFM_OFFSET_MAGIC_2, /* counting symbol */ - SPAV3_2_SEL_TOTAL_CYCLES = 0 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_COMPLETED_INSTRUCTION = 1 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_CONDITIONAL_BRANCH_MISPREDICT = 2 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_TAKEN_CONDITIONAL_BRANCH_MISPREDICT = - 3 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_PREFETCH_INSTRUCTION_CACHE_HIT = 4 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_RET_MISPREDICT = 5 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_IMMEDIATE_J_INST = 6 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_MULTIPLY_INST = 7 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_16_BIT_INST = 8 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_FAILED_SCW_INST = 9 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_LD_AFTER_ST_CONFLICT_REPLAYS = 10 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_TAKEN_EXCEPTIONS = 12 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_STORES_COMPLETED = 13 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_UITLB_MISS = 14 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_UDTLB_MISS = 15 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_MTLB_MISS = 16 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_CODE_CACHE_MISS = 17 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_EMPTY_INST_QUEUE_STALL_CYCLES = 18 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_DATA_WRITE_BACK = 19 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_DATA_CACHE_MISS = 21 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_LOAD_DATA_CACHE_MISS = 22 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_STORE_DATA_CACHE_MISS = 23 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_DLM_ACCESS = 24 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_LSU_BIU_REQUEST = 25 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_HPTWK_BIU_REQUEST = 26 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_DMA_BIU_REQUEST = 27 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_CODE_CACHE_FILL_BIU_REQUEST = 28 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_EXTERNAL_EVENTS = 29 + PFM_OFFSET_MAGIC_2, - SPAV3_1_SEL_POP25 = 30 + PFM_OFFSET_MAGIC_2, - SPAV3_2_SEL_LAST /* counting symbol */ -}; - -/* Get converted event counter index */ -static inline int get_converted_event_idx(unsigned long event) -{ - int idx; - - if ((event) > SPAV3_0_SEL_BASE && event < SPAV3_0_SEL_LAST) { - idx = 0; - } else if ((event) > SPAV3_1_SEL_BASE && event < SPAV3_1_SEL_LAST) { - idx = 1; - } else if ((event) > SPAV3_2_SEL_BASE && event < SPAV3_2_SEL_LAST) { - idx = 2; - } else { - pr_err("GET_CONVERTED_EVENT_IDX PFM counter range error\n"); - return -EPERM; - } - - return idx; -} - -/* Get converted hardware event number */ -static inline u32 get_converted_evet_hw_num(u32 event) -{ - if (event > SPAV3_0_SEL_BASE && event < SPAV3_0_SEL_LAST) - event -= PFM_OFFSET_MAGIC_0; - else if (event > SPAV3_1_SEL_BASE && event < SPAV3_1_SEL_LAST) - event -= PFM_OFFSET_MAGIC_1; - else if (event > SPAV3_2_SEL_BASE && event < SPAV3_2_SEL_LAST) - event -= PFM_OFFSET_MAGIC_2; - else if (event != 0) - pr_err("GET_CONVERTED_EVENT_HW_NUM PFM counter range error\n"); - - return event; -} - -/* - * NDS32 HW events mapping - * - * The hardware events that we support. We do support cache operations but - * we have harvard caches and no way to combine instruction and data - * accesses/misses in hardware. - */ -static const unsigned int nds32_pfm_perf_map[PERF_COUNT_HW_MAX] = { - [PERF_COUNT_HW_CPU_CYCLES] = SPAV3_0_SEL_TOTAL_CYCLES, - [PERF_COUNT_HW_INSTRUCTIONS] = SPAV3_1_SEL_COMPLETED_INSTRUCTION, - [PERF_COUNT_HW_CACHE_REFERENCES] = SPAV3_1_SEL_DATA_CACHE_ACCESS, - [PERF_COUNT_HW_CACHE_MISSES] = SPAV3_2_SEL_DATA_CACHE_MISS, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_BRANCH_MISSES] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_REF_CPU_CYCLES] = HW_OP_UNSUPPORTED -}; - -static const unsigned int nds32_pfm_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX] = { - [C(L1D)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = - SPAV3_1_SEL_LOAD_DATA_CACHE_ACCESS, - [C(RESULT_MISS)] = - SPAV3_2_SEL_LOAD_DATA_CACHE_MISS, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = - SPAV3_1_SEL_STORE_DATA_CACHE_ACCESS, - [C(RESULT_MISS)] = - SPAV3_2_SEL_STORE_DATA_CACHE_MISS, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = - CACHE_OP_UNSUPPORTED, - }, - }, - [C(L1I)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = - SPAV3_1_SEL_CODE_CACHE_ACCESS, - [C(RESULT_MISS)] = - SPAV3_2_SEL_CODE_CACHE_MISS, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = - SPAV3_1_SEL_CODE_CACHE_ACCESS, - [C(RESULT_MISS)] = - SPAV3_2_SEL_CODE_CACHE_MISS, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - /* TODO: L2CC */ - [C(LL)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - /* NDS32 PMU does not support TLB read/write hit/miss, - * However, it can count access/miss, which mixed with read and write. - * Therefore, only READ counter will use it. - * We do as possible as we can. - */ - [C(DTLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = - SPAV3_1_SEL_UDTLB_ACCESS, - [C(RESULT_MISS)] = - SPAV3_2_SEL_UDTLB_MISS, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = - CACHE_OP_UNSUPPORTED, - }, - }, - [C(ITLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = - SPAV3_1_SEL_UITLB_ACCESS, - [C(RESULT_MISS)] = - SPAV3_2_SEL_UITLB_MISS, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = - CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = - CACHE_OP_UNSUPPORTED, - }, - }, - [C(BPU)] = { /* What is BPU? */ - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = - CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = - CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = - CACHE_OP_UNSUPPORTED, - }, - }, - [C(NODE)] = { /* What is NODE? */ - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = - CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = - CACHE_OP_UNSUPPORTED, - }, - }, -}; - -int nds32_pmu_map_event(struct perf_event *event, - const unsigned int (*event_map)[PERF_COUNT_HW_MAX], - const unsigned int (*cache_map)[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX], u32 raw_event_mask); - -#endif /* __ASM_PMU_H */ diff --git a/arch/nds32/include/asm/proc-fns.h b/arch/nds32/include/asm/proc-fns.h deleted file mode 100644 index 27c617fa77af..000000000000 --- a/arch/nds32/include/asm/proc-fns.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __NDS32_PROCFNS_H__ -#define __NDS32_PROCFNS_H__ - -#ifdef __KERNEL__ -#include - -struct mm_struct; -struct vm_area_struct; -extern void cpu_proc_init(void); -extern void cpu_proc_fin(void); -extern void cpu_do_idle(void); -extern void cpu_reset(unsigned long reset); -extern void cpu_switch_mm(struct mm_struct *mm); - -extern void cpu_dcache_inval_all(void); -extern void cpu_dcache_wbinval_all(void); -extern void cpu_dcache_inval_page(unsigned long page); -extern void cpu_dcache_wb_page(unsigned long page); -extern void cpu_dcache_wbinval_page(unsigned long page); -extern void cpu_dcache_inval_range(unsigned long start, unsigned long end); -extern void cpu_dcache_wb_range(unsigned long start, unsigned long end); -extern void cpu_dcache_wbinval_range(unsigned long start, unsigned long end); - -extern void cpu_icache_inval_all(void); -extern void cpu_icache_inval_page(unsigned long page); -extern void cpu_icache_inval_range(unsigned long start, unsigned long end); - -extern void cpu_cache_wbinval_page(unsigned long page, int flushi); -extern void cpu_cache_wbinval_range(unsigned long start, - unsigned long end, int flushi); -extern void cpu_cache_wbinval_range_check(struct vm_area_struct *vma, - unsigned long start, - unsigned long end, bool flushi, - bool wbd); - -extern void cpu_dma_wb_range(unsigned long start, unsigned long end); -extern void cpu_dma_inval_range(unsigned long start, unsigned long end); -extern void cpu_dma_wbinval_range(unsigned long start, unsigned long end); - -#endif /* __KERNEL__ */ -#endif /* __NDS32_PROCFNS_H__ */ diff --git a/arch/nds32/include/asm/processor.h b/arch/nds32/include/asm/processor.h deleted file mode 100644 index e6bfc74972bb..000000000000 --- a/arch/nds32/include/asm/processor.h +++ /dev/null @@ -1,104 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_PROCESSOR_H -#define __ASM_NDS32_PROCESSOR_H - -#ifdef __KERNEL__ - -#include -#include -#include - -#define KERNEL_STACK_SIZE PAGE_SIZE -#define STACK_TOP TASK_SIZE -#define STACK_TOP_MAX TASK_SIZE - -struct cpu_context { - unsigned long r6; - unsigned long r7; - unsigned long r8; - unsigned long r9; - unsigned long r10; - unsigned long r11; - unsigned long r12; - unsigned long r13; - unsigned long r14; - unsigned long fp; - unsigned long pc; - unsigned long sp; -}; - -struct thread_struct { - struct cpu_context cpu_context; /* cpu context */ - /* fault info */ - unsigned long address; - unsigned long trap_no; - unsigned long error_code; - - struct fpu_struct fpu; -}; - -#define INIT_THREAD { } - -#ifdef __NDS32_EB__ -#define PSW_DE PSW_mskBE -#else -#define PSW_DE 0x0 -#endif - -#ifdef CONFIG_WBNA -#define PSW_valWBNA PSW_mskWBNA -#else -#define PSW_valWBNA 0x0 -#endif - -#ifdef CONFIG_HWZOL -#define PSW_valINIT (PSW_CPL_ANY | PSW_mskAEN | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | PSW_mskGIE) -#else -#define PSW_valINIT (PSW_CPL_ANY | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | PSW_mskGIE) -#endif - -#define start_thread(regs,pc,stack) \ -({ \ - memzero(regs, sizeof(struct pt_regs)); \ - forget_syscall(regs); \ - regs->ipsw = PSW_valINIT; \ - regs->ir0 = (PSW_CPL_ANY | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | PSW_SYSTEM | PSW_INTL_1); \ - regs->ipc = pc; \ - regs->sp = stack; \ -}) - -/* Forward declaration, a strange C thing */ -struct task_struct; - -/* Free all resources held by a thread. */ -#define release_thread(thread) do { } while(0) -#if IS_ENABLED(CONFIG_FPU) -#if !IS_ENABLED(CONFIG_UNLAZU_FPU) -extern struct task_struct *last_task_used_math; -#endif -#endif - -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - -unsigned long __get_wchan(struct task_struct *p); - -#define cpu_relax() barrier() - -#define task_pt_regs(task) \ - ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \ - - 8) - 1) - -/* - * Create a new kernel thread - */ -extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags); - -#define KSTK_EIP(tsk) instruction_pointer(task_pt_regs(tsk)) -#define KSTK_ESP(tsk) user_stack_pointer(task_pt_regs(tsk)) - -#endif - -#endif /* __ASM_NDS32_PROCESSOR_H */ diff --git a/arch/nds32/include/asm/ptrace.h b/arch/nds32/include/asm/ptrace.h deleted file mode 100644 index 919ee223620c..000000000000 --- a/arch/nds32/include/asm/ptrace.h +++ /dev/null @@ -1,77 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_PTRACE_H -#define __ASM_NDS32_PTRACE_H - -#include - -/* - * If pt_regs.syscallno == NO_SYSCALL, then the thread is not executing - * a syscall -- i.e., its most recent entry into the kernel from - * userspace was not via syscall, or otherwise a tracer cancelled the - * syscall. - * - * This must have the value -1, for ABI compatibility with ptrace etc. - */ -#define NO_SYSCALL (-1) -#ifndef __ASSEMBLY__ -#include - -struct pt_regs { - union { - struct user_pt_regs user_regs; - struct { - long uregs[26]; - long fp; - long gp; - long lp; - long sp; - long ipc; -#if defined(CONFIG_HWZOL) - long lb; - long le; - long lc; -#else - long dummy[3]; -#endif - long syscallno; - }; - }; - long orig_r0; - long ir0; - long ipsw; - long pipsw; - long pipc; - long pp0; - long pp1; - long fucop_ctl; - long osp; -}; - -static inline bool in_syscall(struct pt_regs const *regs) -{ - return regs->syscallno != NO_SYSCALL; -} - -static inline void forget_syscall(struct pt_regs *regs) -{ - regs->syscallno = NO_SYSCALL; -} -static inline unsigned long regs_return_value(struct pt_regs *regs) -{ - return regs->uregs[0]; -} -extern void show_regs(struct pt_regs *); -/* Avoid circular header include via sched.h */ -struct task_struct; - -#define arch_has_single_step() (1) -#define user_mode(regs) (((regs)->ipsw & PSW_mskPOM) == 0) -#define interrupts_enabled(regs) (!!((regs)->ipsw & PSW_mskGIE)) -#define user_stack_pointer(regs) ((regs)->sp) -#define instruction_pointer(regs) ((regs)->ipc) -#define profile_pc(regs) instruction_pointer(regs) - -#endif /* __ASSEMBLY__ */ -#endif diff --git a/arch/nds32/include/asm/sfp-machine.h b/arch/nds32/include/asm/sfp-machine.h deleted file mode 100644 index b1a5caa332b5..000000000000 --- a/arch/nds32/include/asm/sfp-machine.h +++ /dev/null @@ -1,158 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2005-2018 Andes Technology Corporation */ - -#include - -#define _FP_W_TYPE_SIZE 32 -#define _FP_W_TYPE unsigned long -#define _FP_WS_TYPE signed long -#define _FP_I_TYPE long - -#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) -#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) -#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) - -#define _FP_MUL_MEAT_S(R, X, Y) \ - _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S, R, X, Y, umul_ppmm) -#define _FP_MUL_MEAT_D(R, X, Y) \ - _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D, R, X, Y, umul_ppmm) -#define _FP_MUL_MEAT_Q(R, X, Y) \ - _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q, R, X, Y, umul_ppmm) - -#define _FP_MUL_MEAT_DW_S(R, X, Y) \ - _FP_MUL_MEAT_DW_1_wide(_FP_WFRACBITS_S, R, X, Y, umul_ppmm) -#define _FP_MUL_MEAT_DW_D(R, X, Y) \ - _FP_MUL_MEAT_DW_2_wide(_FP_WFRACBITS_D, R, X, Y, umul_ppmm) - -#define _FP_DIV_MEAT_S(R, X, Y) _FP_DIV_MEAT_1_udiv_norm(S, R, X, Y) -#define _FP_DIV_MEAT_D(R, X, Y) _FP_DIV_MEAT_2_udiv(D, R, X, Y) - -#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1) -#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1 -#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1 -#define _FP_NANSIGN_S 0 -#define _FP_NANSIGN_D 0 -#define _FP_NANSIGN_Q 0 - -#define _FP_KEEPNANFRACP 1 -#define _FP_QNANNEGATEDP 0 - -#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ -do { \ - if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \ - && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) { \ - R##_s = Y##_s; \ - _FP_FRAC_COPY_##wc(R, Y); \ - } else { \ - R##_s = X##_s; \ - _FP_FRAC_COPY_##wc(R, X); \ - } \ - R##_c = FP_CLS_NAN; \ -} while (0) - -#define __FPU_FPCSR (current->thread.fpu.fpcsr) - -/* Obtain the current rounding mode. */ -#define FP_ROUNDMODE \ -({ \ - __FPU_FPCSR & FPCSR_mskRM; \ -}) - -#define FP_RND_NEAREST 0 -#define FP_RND_PINF 1 -#define FP_RND_MINF 2 -#define FP_RND_ZERO 3 - -#define FP_EX_INVALID FPCSR_mskIVO -#define FP_EX_DIVZERO FPCSR_mskDBZ -#define FP_EX_OVERFLOW FPCSR_mskOVF -#define FP_EX_UNDERFLOW FPCSR_mskUDF -#define FP_EX_INEXACT FPCSR_mskIEX - -#define SF_CEQ 2 -#define SF_CLT 1 -#define SF_CGT 3 -#define SF_CUN 4 - -#include - -#ifdef __BIG_ENDIAN__ -#define __BYTE_ORDER __BIG_ENDIAN -#define __LITTLE_ENDIAN 0 -#else -#define __BYTE_ORDER __LITTLE_ENDIAN -#define __BIG_ENDIAN 0 -#endif - -#define abort() do { } while (0) -#define umul_ppmm(w1, w0, u, v) \ -do { \ - UWtype __x0, __x1, __x2, __x3; \ - UHWtype __ul, __vl, __uh, __vh; \ - \ - __ul = __ll_lowpart(u); \ - __uh = __ll_highpart(u); \ - __vl = __ll_lowpart(v); \ - __vh = __ll_highpart(v); \ - \ - __x0 = (UWtype) __ul * __vl; \ - __x1 = (UWtype) __ul * __vh; \ - __x2 = (UWtype) __uh * __vl; \ - __x3 = (UWtype) __uh * __vh; \ - \ - __x1 += __ll_highpart(__x0); \ - __x1 += __x2; \ - if (__x1 < __x2) \ - __x3 += __ll_B; \ - \ - (w1) = __x3 + __ll_highpart(__x1); \ - (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0); \ -} while (0) - -#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -do { \ - UWtype __x; \ - __x = (al) + (bl); \ - (sh) = (ah) + (bh) + (__x < (al)); \ - (sl) = __x; \ -} while (0) - -#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -do { \ - UWtype __x; \ - __x = (al) - (bl); \ - (sh) = (ah) - (bh) - (__x > (al)); \ - (sl) = __x; \ -} while (0) - -#define udiv_qrnnd(q, r, n1, n0, d) \ -do { \ - UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \ - __d1 = __ll_highpart(d); \ - __d0 = __ll_lowpart(d); \ - \ - __r1 = (n1) % __d1; \ - __q1 = (n1) / __d1; \ - __m = (UWtype) __q1 * __d0; \ - __r1 = __r1 * __ll_B | __ll_highpart(n0); \ - if (__r1 < __m) { \ - __q1--, __r1 += (d); \ - if (__r1 >= (d)) \ - if (__r1 < __m) \ - __q1--, __r1 += (d); \ - } \ - __r1 -= __m; \ - __r0 = __r1 % __d1; \ - __q0 = __r1 / __d1; \ - __m = (UWtype) __q0 * __d0; \ - __r0 = __r0 * __ll_B | __ll_lowpart(n0); \ - if (__r0 < __m) { \ - __q0--, __r0 += (d); \ - if (__r0 >= (d)) \ - if (__r0 < __m) \ - __q0--, __r0 += (d); \ - } \ - __r0 -= __m; \ - (q) = (UWtype) __q1 * __ll_B | __q0; \ - (r) = __r0; \ -} while (0) diff --git a/arch/nds32/include/asm/shmparam.h b/arch/nds32/include/asm/shmparam.h deleted file mode 100644 index 3aeee946973d..000000000000 --- a/arch/nds32/include/asm/shmparam.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASMNDS32_SHMPARAM_H -#define _ASMNDS32_SHMPARAM_H - -/* - * This should be the size of the virtually indexed cache/ways, - * whichever is greater since the cache aliases every size/ways - * bytes. - */ -#define SHMLBA (4 * SZ_8K) /* attach addr a multiple of this */ - -/* - * Enforce SHMLBA in shmat - */ -#define __ARCH_FORCE_SHMLBA - -#endif /* _ASMNDS32_SHMPARAM_H */ diff --git a/arch/nds32/include/asm/stacktrace.h b/arch/nds32/include/asm/stacktrace.h deleted file mode 100644 index 6bf7c777bda4..000000000000 --- a/arch/nds32/include/asm/stacktrace.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2008-2018 Andes Technology Corporation */ - -#ifndef __ASM_STACKTRACE_H -#define __ASM_STACKTRACE_H - -/* Kernel callchain */ -struct stackframe { - unsigned long fp; - unsigned long sp; - unsigned long lp; -}; - -/* - * struct frame_tail: User callchain - * IMPORTANT: - * This struct is used for call-stack walking, - * the order and types matters. - * Do not use array, it only stores sizeof(pointer) - * - * The details can refer to arch/arm/kernel/perf_event.c - */ -struct frame_tail { - unsigned long stack_fp; - unsigned long stack_lp; -}; - -/* For User callchain with optimize for size */ -struct frame_tail_opt_size { - unsigned long stack_r6; - unsigned long stack_fp; - unsigned long stack_gp; - unsigned long stack_lp; -}; - -extern void -get_real_ret_addr(unsigned long *addr, struct task_struct *tsk, int *graph); - -#endif /* __ASM_STACKTRACE_H */ diff --git a/arch/nds32/include/asm/string.h b/arch/nds32/include/asm/string.h deleted file mode 100644 index cae8fe16de98..000000000000 --- a/arch/nds32/include/asm/string.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_STRING_H -#define __ASM_NDS32_STRING_H - -#define __HAVE_ARCH_MEMCPY -extern void *memcpy(void *, const void *, __kernel_size_t); - -#define __HAVE_ARCH_MEMMOVE -extern void *memmove(void *, const void *, __kernel_size_t); - -#define __HAVE_ARCH_MEMSET -extern void *memset(void *, int, __kernel_size_t); - -extern void *memzero(void *ptr, __kernel_size_t n); -#endif diff --git a/arch/nds32/include/asm/suspend.h b/arch/nds32/include/asm/suspend.h deleted file mode 100644 index 6ed2418af1ac..000000000000 --- a/arch/nds32/include/asm/suspend.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2008-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_SUSPEND_H -#define __ASM_NDS32_SUSPEND_H - -extern void suspend2ram(void); -extern void cpu_resume(void); -extern unsigned long wake_mask; - -#endif diff --git a/arch/nds32/include/asm/swab.h b/arch/nds32/include/asm/swab.h deleted file mode 100644 index 362a466f2976..000000000000 --- a/arch/nds32/include/asm/swab.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __NDS32_SWAB_H__ -#define __NDS32_SWAB_H__ - -#include -#include - -static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) -{ - __asm__("wsbh %0, %0\n\t" /* word swap byte within halfword */ - "rotri %0, %0, #16\n" - :"=r"(x) - :"0"(x)); - return x; -} - -static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) -{ - __asm__("wsbh %0, %0\n" /* word swap byte within halfword */ - :"=r"(x) - :"0"(x)); - return x; -} - -#define __arch_swab32(x) ___arch__swab32(x) -#define __arch_swab16(x) ___arch__swab16(x) - -#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) -#define __BYTEORDER_HAS_U64__ -#define __SWAB_64_THRU_32__ -#endif - -#endif /* __NDS32_SWAB_H__ */ diff --git a/arch/nds32/include/asm/syscall.h b/arch/nds32/include/asm/syscall.h deleted file mode 100644 index 90aa56c94af1..000000000000 --- a/arch/nds32/include/asm/syscall.h +++ /dev/null @@ -1,142 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASM_NDS32_SYSCALL_H -#define _ASM_NDS32_SYSCALL_H 1 - -#include -#include -struct task_struct; -struct pt_regs; - -/** - * syscall_get_nr - find what system call a task is executing - * @task: task of interest, must be blocked - * @regs: task_pt_regs() of @task - * - * If @task is executing a system call or is at system call - * tracing about to attempt one, returns the system call number. - * If @task is not executing a system call, i.e. it's blocked - * inside the kernel for a fault or signal, returns -1. - * - * Note this returns int even on 64-bit machines. Only 32 bits of - * system call number can be meaningful. If the actual arch value - * is 64 bits, this truncates to 32 bits so 0xffffffff means -1. - * - * It's only valid to call this when @task is known to be blocked. - */ -static inline int -syscall_get_nr(struct task_struct *task, struct pt_regs *regs) -{ - return regs->syscallno; -} - -/** - * syscall_rollback - roll back registers after an aborted system call - * @task: task of interest, must be in system call exit tracing - * @regs: task_pt_regs() of @task - * - * It's only valid to call this when @task is stopped for system - * call exit tracing (due to TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT), - * after tracehook_report_syscall_entry() returned nonzero to prevent - * the system call from taking place. - * - * This rolls back the register state in @regs so it's as if the - * system call instruction was a no-op. The registers containing - * the system call number and arguments are as they were before the - * system call instruction. This may not be the same as what the - * register state looked like at system call entry tracing. - */ -static inline void -syscall_rollback(struct task_struct *task, struct pt_regs *regs) -{ - regs->uregs[0] = regs->orig_r0; -} - -/** - * syscall_get_error - check result of traced system call - * @task: task of interest, must be blocked - * @regs: task_pt_regs() of @task - * - * Returns 0 if the system call succeeded, or -ERRORCODE if it failed. - * - * It's only valid to call this when @task is stopped for tracing on exit - * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. - */ -static inline long -syscall_get_error(struct task_struct *task, struct pt_regs *regs) -{ - unsigned long error = regs->uregs[0]; - return IS_ERR_VALUE(error) ? error : 0; -} - -/** - * syscall_get_return_value - get the return value of a traced system call - * @task: task of interest, must be blocked - * @regs: task_pt_regs() of @task - * - * Returns the return value of the successful system call. - * This value is meaningless if syscall_get_error() returned nonzero. - * - * It's only valid to call this when @task is stopped for tracing on exit - * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. - */ -static inline long -syscall_get_return_value(struct task_struct *task, struct pt_regs *regs) -{ - return regs->uregs[0]; -} - -/** - * syscall_set_return_value - change the return value of a traced system call - * @task: task of interest, must be blocked - * @regs: task_pt_regs() of @task - * @error: negative error code, or zero to indicate success - * @val: user return value if @error is zero - * - * This changes the results of the system call that user mode will see. - * If @error is zero, the user sees a successful system call with a - * return value of @val. If @error is nonzero, it's a negated errno - * code; the user sees a failed system call with this errno code. - * - * It's only valid to call this when @task is stopped for tracing on exit - * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. - */ -static inline void -syscall_set_return_value(struct task_struct *task, struct pt_regs *regs, - int error, long val) -{ - regs->uregs[0] = (long)error ? error : val; -} - -/** - * syscall_get_arguments - extract system call parameter values - * @task: task of interest, must be blocked - * @regs: task_pt_regs() of @task - * @args: array filled with argument values - * - * Fetches 6 arguments to the system call (from 0 through 5). The first - * argument is stored in @args[0], and so on. - * - * It's only valid to call this when @task is stopped for tracing on - * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. - */ -#define SYSCALL_MAX_ARGS 6 -static inline void -syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, - unsigned long *args) -{ - args[0] = regs->orig_r0; - args++; - memcpy(args, ®s->uregs[0] + 1, 5 * sizeof(args[0])); -} - -static inline int -syscall_get_arch(struct task_struct *task) -{ - return IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) - ? AUDIT_ARCH_NDS32BE : AUDIT_ARCH_NDS32; -} - -#endif /* _ASM_NDS32_SYSCALL_H */ diff --git a/arch/nds32/include/asm/syscalls.h b/arch/nds32/include/asm/syscalls.h deleted file mode 100644 index 4e7216082a67..000000000000 --- a/arch/nds32/include/asm/syscalls.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_SYSCALLS_H -#define __ASM_NDS32_SYSCALLS_H - -asmlinkage long sys_cacheflush(unsigned long addr, unsigned long len, unsigned int op); -asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset, loff_t len); -asmlinkage long sys_rt_sigreturn_wrapper(void); -asmlinkage long sys_fp_udfiex_crtl(int cmd, int act); - -#include - -#endif /* __ASM_NDS32_SYSCALLS_H */ diff --git a/arch/nds32/include/asm/thread_info.h b/arch/nds32/include/asm/thread_info.h deleted file mode 100644 index bd8f81cf2ce5..000000000000 --- a/arch/nds32/include/asm/thread_info.h +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_THREAD_INFO_H -#define __ASM_NDS32_THREAD_INFO_H - -#ifdef __KERNEL__ - -#define THREAD_SIZE_ORDER (1) -#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) - -#ifndef __ASSEMBLY__ - -struct task_struct; - -#include -#include - -/* - * low level task data that entry.S needs immediate access to. - * __switch_to() assumes cpu_context follows immediately after cpu_domain. - */ -struct thread_info { - unsigned long flags; /* low level flags */ - __s32 preempt_count; /* 0 => preemptable, <0 => bug */ -}; -#define INIT_THREAD_INFO(tsk) \ -{ \ - .preempt_count = INIT_PREEMPT_COUNT, \ -} -#define thread_saved_pc(tsk) ((unsigned long)(tsk->thread.cpu_context.pc)) -#define thread_saved_fp(tsk) ((unsigned long)(tsk->thread.cpu_context.fp)) -#endif - -/* - * thread information flags: - * TIF_SYSCALL_TRACE - syscall trace active - * TIF_SIGPENDING - signal pending - * TIF_NEED_RESCHED - rescheduling necessary - * TIF_NOTIFY_RESUME - callback before returning to user - * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED - */ -#define TIF_SIGPENDING 1 -#define TIF_NEED_RESCHED 2 -#define TIF_SINGLESTEP 3 -#define TIF_NOTIFY_RESUME 4 /* callback before returning to user */ -#define TIF_NOTIFY_SIGNAL 5 /* signal notifications exist */ -#define TIF_SYSCALL_TRACE 8 -#define TIF_POLLING_NRFLAG 17 -#define TIF_MEMDIE 18 -#define TIF_FREEZE 19 -#define TIF_RESTORE_SIGMASK 20 - -#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) -#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) -#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) -#define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) -#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) -#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) -#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) -#define _TIF_FREEZE (1 << TIF_FREEZE) -#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) - -/* - * Change these and you break ASM code in entry-common.S - */ -#define _TIF_WORK_MASK 0x000000ff -#define _TIF_WORK_SYSCALL_ENTRY (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP) -#define _TIF_WORK_SYSCALL_LEAVE (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP) - -#endif /* __KERNEL__ */ -#endif /* __ASM_NDS32_THREAD_INFO_H */ diff --git a/arch/nds32/include/asm/tlb.h b/arch/nds32/include/asm/tlb.h deleted file mode 100644 index 672603804a3b..000000000000 --- a/arch/nds32/include/asm/tlb.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASMNDS32_TLB_H -#define __ASMNDS32_TLB_H - -#include - -#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte) - -#endif diff --git a/arch/nds32/include/asm/tlbflush.h b/arch/nds32/include/asm/tlbflush.h deleted file mode 100644 index 97155366ea01..000000000000 --- a/arch/nds32/include/asm/tlbflush.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASMNDS32_TLBFLUSH_H -#define _ASMNDS32_TLBFLUSH_H - -#include -#include -#include - -static inline void local_flush_tlb_all(void) -{ - __nds32__tlbop_flua(); - __nds32__isb(); -} - -static inline void local_flush_tlb_mm(struct mm_struct *mm) -{ - __nds32__tlbop_flua(); - __nds32__isb(); -} - -static inline void local_flush_tlb_kernel_range(unsigned long start, - unsigned long end) -{ - while (start < end) { - __nds32__tlbop_inv(start); - __nds32__isb(); - start += PAGE_SIZE; - } -} - -void local_flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end); -void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); - -#define flush_tlb_all local_flush_tlb_all -#define flush_tlb_mm local_flush_tlb_mm -#define flush_tlb_range local_flush_tlb_range -#define flush_tlb_page local_flush_tlb_page -#define flush_tlb_kernel_range local_flush_tlb_kernel_range - -void update_mmu_cache(struct vm_area_struct *vma, - unsigned long address, pte_t * pte); - -#endif diff --git a/arch/nds32/include/asm/uaccess.h b/arch/nds32/include/asm/uaccess.h deleted file mode 100644 index 377548d4451a..000000000000 --- a/arch/nds32/include/asm/uaccess.h +++ /dev/null @@ -1,282 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASMANDES_UACCESS_H -#define _ASMANDES_UACCESS_H - -/* - * User space memory access functions - */ -#include -#include -#include -#include -#include - -#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" - -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry { - unsigned long insn, fixup; -}; - -extern int fixup_exception(struct pt_regs *regs); - -/* - * Single-value transfer routines. They automatically use the right - * size if we just have the right pointer type. Note that the functions - * which read from user space (*get_*) need to take care not to leak - * kernel data even if the calling code is buggy and fails to check - * the return value. This means zeroing out the destination variable - * or buffer on error. Normally this is done out of line by the - * fixup code, but there are a few places where it intrudes on the - * main code path. When we only write to user space, there is no - * problem. - * - * The "__xxx" versions of the user access functions do not verify the - * address space - it must have been done previously with a separate - * "access_ok()" call. - * - * The "xxx_error" versions set the third argument to EFAULT if an - * error occurs, and leave it unchanged on success. Note that these - * versions are void (ie, don't return a value as such). - */ - -#define get_user(x, ptr) \ -({ \ - long __gu_err = 0; \ - __get_user_check((x), (ptr), __gu_err); \ - __gu_err; \ -}) - -#define __get_user_error(x, ptr, err) \ -({ \ - __get_user_check((x), (ptr), (err)); \ - (void)0; \ -}) - -#define __get_user(x, ptr) \ -({ \ - long __gu_err = 0; \ - const __typeof__(*(ptr)) __user *__p = (ptr); \ - __get_user_err((x), __p, (__gu_err)); \ - __gu_err; \ -}) - -#define __get_user_check(x, ptr, err) \ -({ \ - const __typeof__(*(ptr)) __user *__p = (ptr); \ - might_fault(); \ - if (access_ok(__p, sizeof(*__p))) { \ - __get_user_err((x), __p, (err)); \ - } else { \ - (x) = 0; (err) = -EFAULT; \ - } \ -}) - -#define __get_user_err(x, ptr, err) \ -do { \ - unsigned long __gu_val; \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - __get_user_asm("lbi", __gu_val, (ptr), (err)); \ - break; \ - case 2: \ - __get_user_asm("lhi", __gu_val, (ptr), (err)); \ - break; \ - case 4: \ - __get_user_asm("lwi", __gu_val, (ptr), (err)); \ - break; \ - case 8: \ - __get_user_asm_dword(__gu_val, (ptr), (err)); \ - break; \ - default: \ - BUILD_BUG(); \ - break; \ - } \ - (x) = (__force __typeof__(*(ptr)))__gu_val; \ -} while (0) - -#define __get_user_asm(inst, x, addr, err) \ - __asm__ __volatile__ ( \ - "1: "inst" %1,[%2]\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: move %0, %3\n" \ - " move %1, #0\n" \ - " b 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .previous" \ - : "+r" (err), "=&r" (x) \ - : "r" (addr), "i" (-EFAULT) \ - : "cc") - -#ifdef __NDS32_EB__ -#define __gu_reg_oper0 "%H1" -#define __gu_reg_oper1 "%L1" -#else -#define __gu_reg_oper0 "%L1" -#define __gu_reg_oper1 "%H1" -#endif - -#define __get_user_asm_dword(x, addr, err) \ - __asm__ __volatile__ ( \ - "\n1:\tlwi " __gu_reg_oper0 ",[%2]\n" \ - "\n2:\tlwi " __gu_reg_oper1 ",[%2+4]\n" \ - "3:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "4: move %0, %3\n" \ - " b 3b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 4b\n" \ - " .long 2b, 4b\n" \ - " .previous" \ - : "+r"(err), "=&r"(x) \ - : "r"(addr), "i"(-EFAULT) \ - : "cc") - -#define put_user(x, ptr) \ -({ \ - long __pu_err = 0; \ - __put_user_check((x), (ptr), __pu_err); \ - __pu_err; \ -}) - -#define __put_user(x, ptr) \ -({ \ - long __pu_err = 0; \ - __typeof__(*(ptr)) __user *__p = (ptr); \ - __put_user_err((x), __p, __pu_err); \ - __pu_err; \ -}) - -#define __put_user_error(x, ptr, err) \ -({ \ - __put_user_err((x), (ptr), (err)); \ - (void)0; \ -}) - -#define __put_user_check(x, ptr, err) \ -({ \ - __typeof__(*(ptr)) __user *__p = (ptr); \ - might_fault(); \ - if (access_ok(__p, sizeof(*__p))) { \ - __put_user_err((x), __p, (err)); \ - } else { \ - (err) = -EFAULT; \ - } \ -}) - -#define __put_user_err(x, ptr, err) \ -do { \ - __typeof__(*(ptr)) __pu_val = (x); \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - __put_user_asm("sbi", __pu_val, (ptr), (err)); \ - break; \ - case 2: \ - __put_user_asm("shi", __pu_val, (ptr), (err)); \ - break; \ - case 4: \ - __put_user_asm("swi", __pu_val, (ptr), (err)); \ - break; \ - case 8: \ - __put_user_asm_dword(__pu_val, (ptr), (err)); \ - break; \ - default: \ - BUILD_BUG(); \ - break; \ - } \ -} while (0) - -#define __put_user_asm(inst, x, addr, err) \ - __asm__ __volatile__ ( \ - "1: "inst" %1,[%2]\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: move %0, %3\n" \ - " b 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .previous" \ - : "+r" (err) \ - : "r" (x), "r" (addr), "i" (-EFAULT) \ - : "cc") - -#ifdef __NDS32_EB__ -#define __pu_reg_oper0 "%H2" -#define __pu_reg_oper1 "%L2" -#else -#define __pu_reg_oper0 "%L2" -#define __pu_reg_oper1 "%H2" -#endif - -#define __put_user_asm_dword(x, addr, err) \ - __asm__ __volatile__ ( \ - "\n1:\tswi " __pu_reg_oper0 ",[%1]\n" \ - "\n2:\tswi " __pu_reg_oper1 ",[%1+4]\n" \ - "3:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "4: move %0, %3\n" \ - " b 3b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 4b\n" \ - " .long 2b, 4b\n" \ - " .previous" \ - : "+r"(err) \ - : "r"(addr), "r"(x), "i"(-EFAULT) \ - : "cc") - -extern unsigned long __arch_clear_user(void __user * addr, unsigned long n); -extern long strncpy_from_user(char *dest, const char __user * src, long count); -extern __must_check long strnlen_user(const char __user * str, long n); -extern unsigned long __arch_copy_from_user(void *to, const void __user * from, - unsigned long n); -extern unsigned long __arch_copy_to_user(void __user * to, const void *from, - unsigned long n); - -#define raw_copy_from_user __arch_copy_from_user -#define raw_copy_to_user __arch_copy_to_user - -#define INLINE_COPY_FROM_USER -#define INLINE_COPY_TO_USER -static inline unsigned long clear_user(void __user * to, unsigned long n) -{ - if (access_ok(to, n)) - n = __arch_clear_user(to, n); - return n; -} - -static inline unsigned long __clear_user(void __user * to, unsigned long n) -{ - return __arch_clear_user(to, n); -} - -#endif /* _ASMNDS32_UACCESS_H */ diff --git a/arch/nds32/include/asm/unistd.h b/arch/nds32/include/asm/unistd.h deleted file mode 100644 index bf5e2d440913..000000000000 --- a/arch/nds32/include/asm/unistd.h +++ /dev/null @@ -1,6 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#define __ARCH_WANT_SYS_CLONE - -#include diff --git a/arch/nds32/include/asm/vdso.h b/arch/nds32/include/asm/vdso.h deleted file mode 100644 index 89b113ffc3dc..000000000000 --- a/arch/nds32/include/asm/vdso.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2005-2017 Andes Technology Corporation - */ - -#ifndef __ASM_VDSO_H -#define __ASM_VDSO_H - -#ifdef __KERNEL__ - -#ifndef __ASSEMBLY__ - -#include - -#define VDSO_SYMBOL(base, name) \ -({ \ - (unsigned long)(vdso_offset_##name + (unsigned long)(base)); \ -}) - -#endif /* !__ASSEMBLY__ */ - -#endif /* __KERNEL__ */ - -#endif /* __ASM_VDSO_H */ diff --git a/arch/nds32/include/asm/vdso_datapage.h b/arch/nds32/include/asm/vdso_datapage.h deleted file mode 100644 index 74c68802021e..000000000000 --- a/arch/nds32/include/asm/vdso_datapage.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2012 ARM Limited -// Copyright (C) 2005-2017 Andes Technology Corporation -#ifndef __ASM_VDSO_DATAPAGE_H -#define __ASM_VDSO_DATAPAGE_H - -#ifdef __KERNEL__ - -#ifndef __ASSEMBLY__ - -struct vdso_data { - bool cycle_count_down; /* timer cyclye counter is decrease with time */ - u32 cycle_count_offset; /* offset of timer cycle counter register */ - u32 seq_count; /* sequence count - odd during updates */ - u32 xtime_coarse_sec; /* coarse time */ - u32 xtime_coarse_nsec; - - u32 wtm_clock_sec; /* wall to monotonic offset */ - u32 wtm_clock_nsec; - u32 xtime_clock_sec; /* CLOCK_REALTIME - seconds */ - u32 cs_mult; /* clocksource multiplier */ - u32 cs_shift; /* Cycle to nanosecond divisor (power of two) */ - u32 hrtimer_res; /* hrtimer resolution */ - - u64 cs_cycle_last; /* last cycle value */ - u64 cs_mask; /* clocksource mask */ - - u64 xtime_clock_nsec; /* CLOCK_REALTIME sub-ns base */ - u32 tz_minuteswest; /* timezone info for gettimeofday(2) */ - u32 tz_dsttime; -}; - -#endif /* !__ASSEMBLY__ */ - -#endif /* __KERNEL__ */ - -#endif /* __ASM_VDSO_DATAPAGE_H */ diff --git a/arch/nds32/include/asm/vdso_timer_info.h b/arch/nds32/include/asm/vdso_timer_info.h deleted file mode 100644 index 328439ce37db..000000000000 --- a/arch/nds32/include/asm/vdso_timer_info.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -extern struct timer_info_t timer_info; -#define EMPTY_VALUE ~(0UL) -#define EMPTY_TIMER_MAPPING EMPTY_VALUE -#define EMPTY_REG_OFFSET EMPTY_VALUE - -struct timer_info_t -{ - bool cycle_count_down; - unsigned long mapping_base; - unsigned long cycle_count_reg_offset; -}; diff --git a/arch/nds32/include/asm/vermagic.h b/arch/nds32/include/asm/vermagic.h deleted file mode 100644 index f772e7ba33f1..000000000000 --- a/arch/nds32/include/asm/vermagic.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASM_VERMAGIC_H -#define _ASM_VERMAGIC_H - -#define MODULE_ARCH_VERMAGIC "NDS32v3" - -#endif /* _ASM_VERMAGIC_H */ diff --git a/arch/nds32/include/asm/vmalloc.h b/arch/nds32/include/asm/vmalloc.h deleted file mode 100644 index caeed3898419..000000000000 --- a/arch/nds32/include/asm/vmalloc.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _ASM_NDS32_VMALLOC_H -#define _ASM_NDS32_VMALLOC_H - -#endif /* _ASM_NDS32_VMALLOC_H */ diff --git a/arch/nds32/include/uapi/asm/Kbuild b/arch/nds32/include/uapi/asm/Kbuild deleted file mode 100644 index e78470141932..000000000000 --- a/arch/nds32/include/uapi/asm/Kbuild +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -generic-y += ucontext.h diff --git a/arch/nds32/include/uapi/asm/auxvec.h b/arch/nds32/include/uapi/asm/auxvec.h deleted file mode 100644 index bc0b92ab8c15..000000000000 --- a/arch/nds32/include/uapi/asm/auxvec.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_AUXVEC_H -#define __ASM_AUXVEC_H - -/* - * This entry gives some information about the FPU initialization - * performed by the kernel. - */ -#define AT_FPUCW 18 /* Used FPU control word. */ - - -/* VDSO location */ -#define AT_SYSINFO_EHDR 33 - -#define AT_VECTOR_SIZE_ARCH 1 - -#endif diff --git a/arch/nds32/include/uapi/asm/byteorder.h b/arch/nds32/include/uapi/asm/byteorder.h deleted file mode 100644 index c264ef12c49c..000000000000 --- a/arch/nds32/include/uapi/asm/byteorder.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __NDS32_BYTEORDER_H__ -#define __NDS32_BYTEORDER_H__ - -#ifdef __NDS32_EB__ -#include -#else -#include -#endif - -#endif /* __NDS32_BYTEORDER_H__ */ diff --git a/arch/nds32/include/uapi/asm/cachectl.h b/arch/nds32/include/uapi/asm/cachectl.h deleted file mode 100644 index 31b9b439d819..000000000000 --- a/arch/nds32/include/uapi/asm/cachectl.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -// Copyright (C) 1994, 1995, 1996 by Ralf Baechle -// Copyright (C) 2005-2017 Andes Technology Corporation -#ifndef _ASM_CACHECTL -#define _ASM_CACHECTL - -/* - * Options for cacheflush system call - */ -#define ICACHE 0 /* flush instruction cache */ -#define DCACHE 1 /* writeback and flush data cache */ -#define BCACHE 2 /* flush instruction cache + writeback and flush data cache */ - -#endif /* _ASM_CACHECTL */ diff --git a/arch/nds32/include/uapi/asm/fp_udfiex_crtl.h b/arch/nds32/include/uapi/asm/fp_udfiex_crtl.h deleted file mode 100644 index f17396db16ec..000000000000 --- a/arch/nds32/include/uapi/asm/fp_udfiex_crtl.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* Copyright (C) 2005-2019 Andes Technology Corporation */ -#ifndef _FP_UDF_IEX_CRTL_H -#define _FP_UDF_IEX_CRTL_H - -/* - * The cmd list of sys_fp_udfiex_crtl() - */ -/* Disable UDF or IEX trap based on the content of parameter act */ -#define DISABLE_UDF_IEX_TRAP 0 -/* Enable UDF or IEX trap based on the content of parameter act */ -#define ENABLE_UDF_IEX_TRAP 1 -/* Get current status of UDF and IEX trap */ -#define GET_UDF_IEX_TRAP 2 - -#endif /* _FP_UDF_IEX_CRTL_H */ diff --git a/arch/nds32/include/uapi/asm/param.h b/arch/nds32/include/uapi/asm/param.h deleted file mode 100644 index 48d00328d328..000000000000 --- a/arch/nds32/include/uapi/asm/param.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __ASM_NDS32_PARAM_H -#define __ASM_NDS32_PARAM_H - -#define EXEC_PAGESIZE 8192 - -#include - -#endif /* __ASM_NDS32_PARAM_H */ diff --git a/arch/nds32/include/uapi/asm/ptrace.h b/arch/nds32/include/uapi/asm/ptrace.h deleted file mode 100644 index d76217c7c010..000000000000 --- a/arch/nds32/include/uapi/asm/ptrace.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef __UAPI_ASM_NDS32_PTRACE_H -#define __UAPI_ASM_NDS32_PTRACE_H - -#ifndef __ASSEMBLY__ - -/* - * User structures for general purpose register. - */ -struct user_pt_regs { - long uregs[26]; - long fp; - long gp; - long lp; - long sp; - long ipc; - long lb; - long le; - long lc; - long syscallno; -}; -#endif -#endif diff --git a/arch/nds32/include/uapi/asm/sigcontext.h b/arch/nds32/include/uapi/asm/sigcontext.h deleted file mode 100644 index 6c1e6648878f..000000000000 --- a/arch/nds32/include/uapi/asm/sigcontext.h +++ /dev/null @@ -1,84 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef _ASMNDS32_SIGCONTEXT_H -#define _ASMNDS32_SIGCONTEXT_H - -/* - * Signal context structure - contains all info to do with the state - * before the signal handler was invoked. Note: only add new entries - * to the end of the structure. - */ -struct fpu_struct { - unsigned long long fd_regs[32]; - unsigned long fpcsr; - /* - * When CONFIG_SUPPORT_DENORMAL_ARITHMETIC is defined, kernel prevents - * hardware from treating the denormalized output as an underflow case - * and rounding it to a normal number. Hence kernel enables the UDF and - * IEX trap in the fpcsr register to step in the calculation. - * However, the UDF and IEX trap enable bit in $fpcsr also lose - * their use. - * - * UDF_IEX_trap replaces the feature of UDF and IEX trap enable bit in - * $fpcsr to control the trap of underflow and inexact. The bit filed - * of UDF_IEX_trap is the same as $fpcsr, 10th bit is used to enable UDF - * exception trapping and 11th bit is used to enable IEX exception - * trapping. - * - * UDF_IEX_trap is only modified through fp_udfiex_crtl syscall. - * Therefore, UDF_IEX_trap needn't be saved and restored in each - * context switch. - */ - unsigned long UDF_IEX_trap; -}; - -struct zol_struct { - unsigned long nds32_lc; /* $LC */ - unsigned long nds32_le; /* $LE */ - unsigned long nds32_lb; /* $LB */ -}; - -struct sigcontext { - unsigned long trap_no; - unsigned long error_code; - unsigned long oldmask; - unsigned long nds32_r0; - unsigned long nds32_r1; - unsigned long nds32_r2; - unsigned long nds32_r3; - unsigned long nds32_r4; - unsigned long nds32_r5; - unsigned long nds32_r6; - unsigned long nds32_r7; - unsigned long nds32_r8; - unsigned long nds32_r9; - unsigned long nds32_r10; - unsigned long nds32_r11; - unsigned long nds32_r12; - unsigned long nds32_r13; - unsigned long nds32_r14; - unsigned long nds32_r15; - unsigned long nds32_r16; - unsigned long nds32_r17; - unsigned long nds32_r18; - unsigned long nds32_r19; - unsigned long nds32_r20; - unsigned long nds32_r21; - unsigned long nds32_r22; - unsigned long nds32_r23; - unsigned long nds32_r24; - unsigned long nds32_r25; - unsigned long nds32_fp; /* $r28 */ - unsigned long nds32_gp; /* $r29 */ - unsigned long nds32_lp; /* $r30 */ - unsigned long nds32_sp; /* $r31 */ - unsigned long nds32_ipc; - unsigned long fault_address; - unsigned long used_math_flag; - /* FPU Registers */ - struct fpu_struct fpu; - struct zol_struct zol; -}; - -#endif diff --git a/arch/nds32/include/uapi/asm/unistd.h b/arch/nds32/include/uapi/asm/unistd.h deleted file mode 100644 index 410795e280fe..000000000000 --- a/arch/nds32/include/uapi/asm/unistd.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -// Copyright (C) 2005-2017 Andes Technology Corporation - -#define __ARCH_WANT_STAT64 -#define __ARCH_WANT_SYNC_FILE_RANGE2 -#define __ARCH_WANT_SET_GET_RLIMIT -#define __ARCH_WANT_TIME32_SYSCALLS - -/* Use the standard ABI for syscalls */ -#include - -/* Additional NDS32 specific syscalls. */ -#define __NR_cacheflush (__NR_arch_specific_syscall) -#define __NR_fp_udfiex_crtl (__NR_arch_specific_syscall + 1) -__SYSCALL(__NR_cacheflush, sys_cacheflush) -__SYSCALL(__NR_fp_udfiex_crtl, sys_fp_udfiex_crtl) diff --git a/arch/nds32/kernel/.gitignore b/arch/nds32/kernel/.gitignore deleted file mode 100644 index bbb90f92d051..000000000000 --- a/arch/nds32/kernel/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -vmlinux.lds diff --git a/arch/nds32/kernel/Makefile b/arch/nds32/kernel/Makefile deleted file mode 100644 index 394df3f6442c..000000000000 --- a/arch/nds32/kernel/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the linux kernel. -# - -CPPFLAGS_vmlinux.lds := -DTEXTADDR=$(TEXTADDR) -AFLAGS_head.o := -DTEXTADDR=$(TEXTADDR) -# Object file lists. - -obj-y := ex-entry.o ex-exit.o ex-scall.o irq.o \ - process.o ptrace.o setup.o signal.o \ - sys_nds32.o time.o traps.o cacheinfo.o \ - dma.o syscall_table.o vdso.o - -obj-$(CONFIG_MODULES) += nds32_ksyms.o module.o -obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-$(CONFIG_FPU) += fpu.o -obj-$(CONFIG_OF) += devtree.o -obj-$(CONFIG_CACHE_L2) += atl2c.o -obj-$(CONFIG_PERF_EVENTS) += perf_event_cpu.o -obj-$(CONFIG_PM) += pm.o sleep.o -extra-y := head.o vmlinux.lds - -CFLAGS_fpu.o += -mext-fpu-sp -mext-fpu-dp - - -obj-y += vdso/ - -obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o - -ifdef CONFIG_FUNCTION_TRACER -CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) -endif diff --git a/arch/nds32/kernel/asm-offsets.c b/arch/nds32/kernel/asm-offsets.c deleted file mode 100644 index 3541d5981de7..000000000000 --- a/arch/nds32/kernel/asm-offsets.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include - -int main(void) -{ - DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); - DEFINE(TSK_TI_PREEMPT, - offsetof(struct task_struct, thread_info.preempt_count)); - DEFINE(THREAD_CPU_CONTEXT, - offsetof(struct task_struct, thread.cpu_context)); - DEFINE(OSP_OFFSET, offsetof(struct pt_regs, osp)); - DEFINE(SP_OFFSET, offsetof(struct pt_regs, sp)); - DEFINE(FUCOP_CTL_OFFSET, offsetof(struct pt_regs, fucop_ctl)); - DEFINE(IPSW_OFFSET, offsetof(struct pt_regs, ipsw)); - DEFINE(SYSCALLNO_OFFSET, offsetof(struct pt_regs, syscallno)); - DEFINE(IPC_OFFSET, offsetof(struct pt_regs, ipc)); - DEFINE(R0_OFFSET, offsetof(struct pt_regs, uregs[0])); - DEFINE(R15_OFFSET, offsetof(struct pt_regs, uregs[15])); - DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); - DEFINE(CLOCK_COARSE_RES, LOW_RES_NSEC); - return 0; -} diff --git a/arch/nds32/kernel/atl2c.c b/arch/nds32/kernel/atl2c.c deleted file mode 100644 index 0c5386e72098..000000000000 --- a/arch/nds32/kernel/atl2c.c +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include - -void __iomem *atl2c_base; -static const struct of_device_id atl2c_ids[] __initconst = { - {.compatible = "andestech,atl2c",}, - {} -}; - -static int __init atl2c_of_init(void) -{ - struct device_node *np; - struct resource res; - unsigned long tmp = 0; - unsigned long l2set, l2way, l2clsz; - - if (!(__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskL2C)) - return -ENODEV; - - np = of_find_matching_node(NULL, atl2c_ids); - if (!np) - return -ENODEV; - - if (of_address_to_resource(np, 0, &res)) - return -ENODEV; - - atl2c_base = ioremap(res.start, resource_size(&res)); - if (!atl2c_base) - return -ENOMEM; - - l2set = - 64 << ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2SET) >> - L2_CA_CONF_offL2SET); - l2way = - 1 + - ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2WAY) >> - L2_CA_CONF_offL2WAY); - l2clsz = - 4 << ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2CLSZ) >> - L2_CA_CONF_offL2CLSZ); - pr_info("L2:%luKB/%luS/%luW/%luB\n", - l2set * l2way * l2clsz / 1024, l2set, l2way, l2clsz); - - tmp = L2C_R_REG(L2CC_PROT_OFF); - tmp &= ~L2CC_PROT_mskMRWEN; - L2C_W_REG(L2CC_PROT_OFF, tmp); - - tmp = L2C_R_REG(L2CC_SETUP_OFF); - tmp &= ~L2CC_SETUP_mskPART; - L2C_W_REG(L2CC_SETUP_OFF, tmp); - - tmp = L2C_R_REG(L2CC_CTRL_OFF); - tmp |= L2CC_CTRL_mskEN; - L2C_W_REG(L2CC_CTRL_OFF, tmp); - - return 0; -} - -subsys_initcall(atl2c_of_init); diff --git a/arch/nds32/kernel/cacheinfo.c b/arch/nds32/kernel/cacheinfo.c deleted file mode 100644 index aab98e447feb..000000000000 --- a/arch/nds32/kernel/cacheinfo.c +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include - -static void ci_leaf_init(struct cacheinfo *this_leaf, - enum cache_type type, unsigned int level) -{ - char cache_type = (type & CACHE_TYPE_INST ? ICACHE : DCACHE); - - this_leaf->level = level; - this_leaf->type = type; - this_leaf->coherency_line_size = CACHE_LINE_SIZE(cache_type); - this_leaf->number_of_sets = CACHE_SET(cache_type); - this_leaf->ways_of_associativity = CACHE_WAY(cache_type); - this_leaf->size = this_leaf->number_of_sets * - this_leaf->coherency_line_size * this_leaf->ways_of_associativity; -#if defined(CONFIG_CPU_DCACHE_WRITETHROUGH) - this_leaf->attributes = CACHE_WRITE_THROUGH; -#else - this_leaf->attributes = CACHE_WRITE_BACK; -#endif -} - -int init_cache_level(unsigned int cpu) -{ - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); - - /* Only 1 level and I/D cache seperate. */ - this_cpu_ci->num_levels = 1; - this_cpu_ci->num_leaves = 2; - return 0; -} - -int populate_cache_leaves(unsigned int cpu) -{ - unsigned int level, idx; - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); - struct cacheinfo *this_leaf = this_cpu_ci->info_list; - - for (idx = 0, level = 1; level <= this_cpu_ci->num_levels && - idx < this_cpu_ci->num_leaves; idx++, level++) { - ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level); - ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level); - } - return 0; -} diff --git a/arch/nds32/kernel/devtree.c b/arch/nds32/kernel/devtree.c deleted file mode 100644 index bdce0fe5af9f..000000000000 --- a/arch/nds32/kernel/devtree.c +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include - -void __init early_init_devtree(void *params) -{ - if (!params || !early_init_dt_scan(params)) { - pr_crit("\n" - "Error: invalid device tree blob at (virtual address 0x%p)\n" - "\nPlease check your bootloader.", params); - - BUG_ON(1); - } - - dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name()); -} diff --git a/arch/nds32/kernel/dma.c b/arch/nds32/kernel/dma.c deleted file mode 100644 index 2ac8e6c82a61..000000000000 --- a/arch/nds32/kernel/dma.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include - -static inline void cache_op(phys_addr_t paddr, size_t size, - void (*fn)(unsigned long start, unsigned long end)) -{ - struct page *page = pfn_to_page(paddr >> PAGE_SHIFT); - unsigned offset = paddr & ~PAGE_MASK; - size_t left = size; - unsigned long start; - - do { - size_t len = left; - - if (PageHighMem(page)) { - void *addr; - - if (offset + len > PAGE_SIZE) { - if (offset >= PAGE_SIZE) { - page += offset >> PAGE_SHIFT; - offset &= ~PAGE_MASK; - } - len = PAGE_SIZE - offset; - } - - addr = kmap_atomic(page); - start = (unsigned long)(addr + offset); - fn(start, start + len); - kunmap_atomic(addr); - } else { - start = (unsigned long)phys_to_virt(paddr); - fn(start, start + size); - } - offset = 0; - page++; - left -= len; - } while (left); -} - -void arch_sync_dma_for_device(phys_addr_t paddr, size_t size, - enum dma_data_direction dir) -{ - switch (dir) { - case DMA_FROM_DEVICE: - break; - case DMA_TO_DEVICE: - case DMA_BIDIRECTIONAL: - cache_op(paddr, size, cpu_dma_wb_range); - break; - default: - BUG(); - } -} - -void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, - enum dma_data_direction dir) -{ - switch (dir) { - case DMA_TO_DEVICE: - break; - case DMA_FROM_DEVICE: - case DMA_BIDIRECTIONAL: - cache_op(paddr, size, cpu_dma_inval_range); - break; - default: - BUG(); - } -} - -void arch_dma_prep_coherent(struct page *page, size_t size) -{ - cache_op(page_to_phys(page), size, cpu_dma_wbinval_range); -} diff --git a/arch/nds32/kernel/ex-entry.S b/arch/nds32/kernel/ex-entry.S deleted file mode 100644 index 107d98a1d1b8..000000000000 --- a/arch/nds32/kernel/ex-entry.S +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_HWZOL - .macro push_zol - mfusr $r14, $LB - mfusr $r15, $LE - mfusr $r16, $LC - .endm -#endif - .macro skip_save_fucop_ctl -#if defined(CONFIG_FPU) -skip_fucop_ctl: - smw.adm $p0, [$sp], $p0, #0x1 - j fucop_ctl_done -#endif - .endm - - .macro save_user_regs -#if defined(CONFIG_FPU) - sethi $p0, hi20(has_fpu) - lbsi $p0, [$p0+lo12(has_fpu)] - beqz $p0, skip_fucop_ctl - mfsr $p0, $FUCOP_CTL - smw.adm $p0, [$sp], $p0, #0x1 - bclr $p0, $p0, #FUCOP_CTL_offCP0EN - mtsr $p0, $FUCOP_CTL -fucop_ctl_done: - /* move $SP to the bottom of pt_regs */ - addi $sp, $sp, -FUCOP_CTL_OFFSET -#else - smw.adm $sp, [$sp], $sp, #0x1 - /* move $SP to the bottom of pt_regs */ - addi $sp, $sp, -OSP_OFFSET -#endif - - /* push $r0 ~ $r25 */ - smw.bim $r0, [$sp], $r25 - /* push $fp, $gp, $lp */ - smw.bim $sp, [$sp], $sp, #0xe - - mfsr $r12, $SP_USR - mfsr $r13, $IPC -#ifdef CONFIG_HWZOL - push_zol -#endif - movi $r17, -1 - move $r18, $r0 - mfsr $r19, $PSW - mfsr $r20, $IPSW - mfsr $r21, $P_IPSW - mfsr $r22, $P_IPC - mfsr $r23, $P_P0 - mfsr $r24, $P_P1 - smw.bim $r12, [$sp], $r24, #0 - addi $sp, $sp, -FUCOP_CTL_OFFSET - - /* Initialize kernel space $fp */ - andi $p0, $r20, #PSW_mskPOM - movi $p1, #0x0 - cmovz $fp, $p1, $p0 - - andi $r16, $r19, #PSW_mskINTL - slti $r17, $r16, #4 - bnez $r17, 1f - addi $r17, $r19, #-2 - mtsr $r17, $PSW - isb -1: - /* If it was superuser mode, we don't need to update $r25 */ - bnez $p0, 2f - la $p0, __entry_task - lw $r25, [$p0] -2: - .endm - - .text - -/* - * Exception Vector - */ -exception_handlers: - .long unhandled_exceptions !Reset/NMI - .long unhandled_exceptions !TLB fill - .long do_page_fault !PTE not present - .long do_dispatch_tlb_misc !TLB misc - .long unhandled_exceptions !TLB VLPT - .long unhandled_exceptions !Machine Error - .long do_debug_trap !Debug related - .long do_dispatch_general !General exception - .long eh_syscall !Syscall - .long asm_do_IRQ !IRQ - - skip_save_fucop_ctl -common_exception_handler: - save_user_regs - mfsr $p0, $ITYPE - andi $p0, $p0, #ITYPE_mskVECTOR - srli $p0, $p0, #ITYPE_offVECTOR - andi $p1, $p0, #NDS32_VECTOR_mskNONEXCEPTION - bnez $p1, 1f - sethi $lp, hi20(ret_from_exception) - ori $lp, $lp, lo12(ret_from_exception) - sethi $p1, hi20(exception_handlers) - ori $p1, $p1, lo12(exception_handlers) - lw $p1, [$p1+$p0<<2] - move $r0, $p0 - mfsr $r1, $EVA - mfsr $r2, $ITYPE - move $r3, $sp - mfsr $r4, $OIPC - /* enable gie if it is enabled in IPSW. */ - mfsr $r21, $PSW - andi $r20, $r20, #PSW_mskGIE /* r20 is $IPSW*/ - or $r21, $r21, $r20 - mtsr $r21, $PSW - dsb - jr $p1 - /* syscall */ -1: - addi $p1, $p0, #-NDS32_VECTOR_offEXCEPTION - bnez $p1, 2f - sethi $lp, hi20(ret_from_exception) - ori $lp, $lp, lo12(ret_from_exception) - sethi $p1, hi20(exception_handlers) - ori $p1, $p1, lo12(exception_handlers) - lwi $p1, [$p1+#NDS32_VECTOR_offEXCEPTION<<2] - jr $p1 - - /* interrupt */ -2: -#ifdef CONFIG_TRACE_IRQFLAGS - jal __trace_hardirqs_off -#endif - move $r0, $sp - sethi $lp, hi20(ret_from_intr) - ori $lp, $lp, lo12(ret_from_intr) - sethi $p0, hi20(exception_handlers) - ori $p0, $p0, lo12(exception_handlers) - lwi $p0, [$p0+#NDS32_VECTOR_offINTERRUPT<<2] - jr $p0 - - .macro EXCEPTION_VECTOR_DEBUG - .align 4 - mfsr $p0, $EDM_CTL - andi $p0, $p0, EDM_CTL_mskV3_EDM_MODE - tnez $p0, SWID_RAISE_INTERRUPT_LEVEL - .endm - - .macro EXCEPTION_VECTOR - .align 4 - sethi $p0, hi20(common_exception_handler) - ori $p0, $p0, lo12(common_exception_handler) - jral.ton $p0, $p0 - .endm - - .section ".text.init", #alloc, #execinstr - .global exception_vector -exception_vector: -.rept 6 - EXCEPTION_VECTOR -.endr - EXCEPTION_VECTOR_DEBUG -.rept 121 - EXCEPTION_VECTOR -.endr - .align 4 - .global exception_vector_end -exception_vector_end: diff --git a/arch/nds32/kernel/ex-exit.S b/arch/nds32/kernel/ex-exit.S deleted file mode 100644 index b30699911b81..000000000000 --- a/arch/nds32/kernel/ex-exit.S +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include - - - -#ifdef CONFIG_HWZOL - .macro pop_zol - mtusr $r14, $LB - mtusr $r15, $LE - mtusr $r16, $LC - .endm -#endif - - .macro restore_user_regs_first - setgie.d - isb -#if defined(CONFIG_FPU) - addi $sp, $sp, OSP_OFFSET - lmw.adm $r12, [$sp], $r25, #0x0 - sethi $p0, hi20(has_fpu) - lbsi $p0, [$p0+lo12(has_fpu)] - beqz $p0, 2f - mtsr $r25, $FUCOP_CTL -2: -#else - addi $sp, $sp, FUCOP_CTL_OFFSET - lmw.adm $r12, [$sp], $r24, #0x0 -#endif - mtsr $r12, $SP_USR - mtsr $r13, $IPC -#ifdef CONFIG_HWZOL - pop_zol -#endif - mtsr $r19, $PSW - mtsr $r20, $IPSW - mtsr $r21, $P_IPSW - mtsr $r22, $P_IPC - mtsr $r23, $P_P0 - mtsr $r24, $P_P1 - lmw.adm $sp, [$sp], $sp, #0xe - .endm - - .macro restore_user_regs_last - pop $p0 - cmovn $sp, $p0, $p0 - - iret - nop - - .endm - - .macro restore_user_regs - restore_user_regs_first - lmw.adm $r0, [$sp], $r25, #0x0 - addi $sp, $sp, OSP_OFFSET - restore_user_regs_last - .endm - - .macro fast_restore_user_regs - restore_user_regs_first - lmw.adm $r1, [$sp], $r25, #0x0 - addi $sp, $sp, OSP_OFFSET-4 - restore_user_regs_last - .endm - -#ifdef CONFIG_PREEMPTION - .macro preempt_stop - .endm -#else - .macro preempt_stop - setgie.d - isb - .endm -#define resume_kernel no_work_pending -#endif - -ENTRY(ret_from_exception) - preempt_stop -ENTRY(ret_from_intr) - -/* - * judge Kernel or user mode - * - */ - lwi $p0, [$sp+(#IPSW_OFFSET)] ! Check if in nested interrupt - andi $p0, $p0, #PSW_mskINTL - bnez $p0, resume_kernel ! done with iret - j resume_userspace - - -/* - * This is the fast syscall return path. We do as little as - * possible here, and this includes saving $r0 back into the SVC - * stack. - * fixed: tsk - $r25, syscall # - $r7, syscall table pointer - $r8 - */ -ENTRY(ret_fast_syscall) - gie_disable - lwi $r1, [tsk+#TSK_TI_FLAGS] - andi $p1, $r1, #_TIF_WORK_MASK - bnez $p1, fast_work_pending - fast_restore_user_regs ! iret - -/* - * Ok, we need to do extra processing, - * enter the slow path returning from syscall, while pending work. - */ -fast_work_pending: - swi $r0, [$sp+(#R0_OFFSET)] ! what is different from ret_from_exception -work_pending: - andi $p1, $r1, #_TIF_NEED_RESCHED - bnez $p1, work_resched - - andi $p1, $r1, #_TIF_SIGPENDING|#_TIF_NOTIFY_RESUME|#_TIF_NOTIFY_SIGNAL - beqz $p1, no_work_pending - - move $r0, $sp ! 'regs' - gie_enable - bal do_notify_resume - b ret_slow_syscall -work_resched: - bal schedule ! path, return to user mode - -/* - * "slow" syscall return path. - */ -ENTRY(resume_userspace) -ENTRY(ret_slow_syscall) - gie_disable - lwi $p0, [$sp+(#IPSW_OFFSET)] ! Check if in nested interrupt - andi $p0, $p0, #PSW_mskINTL - bnez $p0, no_work_pending ! done with iret - lwi $r1, [tsk+#TSK_TI_FLAGS] - andi $p1, $r1, #_TIF_WORK_MASK - bnez $p1, work_pending ! handle work_resched, sig_pend - -no_work_pending: -#ifdef CONFIG_TRACE_IRQFLAGS - lwi $p0, [$sp+(#IPSW_OFFSET)] - andi $p0, $p0, #0x1 - la $r10, __trace_hardirqs_off - la $r9, __trace_hardirqs_on - cmovz $r9, $p0, $r10 - jral $r9 -#endif - restore_user_regs ! return from iret - - -/* - * preemptive kernel - */ -#ifdef CONFIG_PREEMPTION -resume_kernel: - gie_disable - lwi $t0, [tsk+#TSK_TI_PREEMPT] - bnez $t0, no_work_pending - - lwi $t0, [tsk+#TSK_TI_FLAGS] - andi $p1, $t0, #_TIF_NEED_RESCHED - beqz $p1, no_work_pending - - lwi $t0, [$sp+(#IPSW_OFFSET)] ! Interrupts off? - andi $t0, $t0, #1 - beqz $t0, no_work_pending - - jal preempt_schedule_irq - b no_work_pending -#endif - -/* - * This is how we return from a fork. - */ -ENTRY(ret_from_fork) - bal schedule_tail - beqz $r6, 1f ! r6 stores fn for kernel thread - move $r0, $r7 ! prepare kernel thread arg - jral $r6 -1: - lwi $r1, [tsk+#TSK_TI_FLAGS] ! check for syscall tracing - andi $p1, $r1, #_TIF_WORK_SYSCALL_LEAVE ! are we tracing syscalls? - beqz $p1, ret_slow_syscall - move $r0, $sp - bal syscall_trace_leave - b ret_slow_syscall diff --git a/arch/nds32/kernel/ex-scall.S b/arch/nds32/kernel/ex-scall.S deleted file mode 100644 index 270050f1b7b1..000000000000 --- a/arch/nds32/kernel/ex-scall.S +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include - -/* - * $r0 = previous task_struct, - * $r1 = next task_struct, - * previous and next are guaranteed not to be the same. - */ - -ENTRY(__switch_to) - - la $p0, __entry_task - sw $r1, [$p0] - addi $p1, $r0, #THREAD_CPU_CONTEXT - smw.bi $r6, [$p1], $r14, #0xb ! push r6~r14, fp, lp, sp - move $r25, $r1 -#if defined(CONFIG_FPU) - call _switch_fpu -#endif - addi $r1, $r25, #THREAD_CPU_CONTEXT - lmw.bi $r6, [$r1], $r14, #0xb ! pop r6~r14, fp, lp, sp - ret - - -#define tbl $r8 - -/* - * $r7 will be writen as syscall nr - */ - .macro get_scno - lwi $r7, [$sp + R15_OFFSET] - swi $r7, [$sp + SYSCALLNO_OFFSET] - .endm - - .macro updateipc - addi $r17, $r13, #4 ! $r13 is $IPC - swi $r17, [$sp + IPC_OFFSET] - .endm - -ENTRY(eh_syscall) - updateipc - - get_scno - gie_enable - - lwi $p0, [tsk+#TSK_TI_FLAGS] ! check for syscall tracing - - andi $p1, $p0, #_TIF_WORK_SYSCALL_ENTRY ! are we tracing syscalls? - bnez $p1, __sys_trace - - la $lp, ret_fast_syscall ! return address -jmp_systbl: - addi $p1, $r7, #-__NR_syscalls ! syscall number of syscall instruction is guarded by addembler - bgez $p1, _SCNO_EXCEED ! call sys_* routine - la tbl, sys_call_table ! load syscall table pointer - slli $p1, $r7, #2 - add $p1, tbl, $p1 - lwi $p1, [$p1] - jr $p1 ! no return - -_SCNO_EXCEED: - ori $r0, $r7, #0 - ori $r1, $sp, #0 - b bad_syscall - -/* - * This is the really slow path. We're going to be doing - * context switches, and waiting for our parent to respond. - */ -__sys_trace: - move $r0, $sp - bal syscall_trace_enter - move $r7, $r0 - la $lp, __sys_trace_return ! return address - - addi $p1, $r7, #1 - beqz $p1, ret_slow_syscall ! fatal signal is pending - - addi $p1, $sp, #R0_OFFSET ! pointer to regs - lmw.bi $r0, [$p1], $r5 ! have to reload $r0 - $r5 - b jmp_systbl - -__sys_trace_return: - swi $r0, [$sp+#R0_OFFSET] ! T: save returned $r0 - move $r0, $sp ! set pt_regs for syscall_trace_leave - bal syscall_trace_leave - b ret_slow_syscall - -ENTRY(sys_rt_sigreturn_wrapper) - addi $r0, $sp, #0 - b sys_rt_sigreturn -ENDPROC(sys_rt_sigreturn_wrapper) diff --git a/arch/nds32/kernel/fpu.c b/arch/nds32/kernel/fpu.c deleted file mode 100644 index 701c09a668de..000000000000 --- a/arch/nds32/kernel/fpu.c +++ /dev/null @@ -1,266 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include - -const struct fpu_struct init_fpuregs = { - .fd_regs = {[0 ... 31] = sNAN64}, - .fpcsr = FPCSR_INIT, -#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - .UDF_IEX_trap = 0 -#endif -}; - -void save_fpu(struct task_struct *tsk) -{ - unsigned int fpcfg, fpcsr; - - enable_fpu(); - fpcfg = ((__nds32__fmfcfg() & FPCFG_mskFREG) >> FPCFG_offFREG); - switch (fpcfg) { - case SP32_DP32_reg: - asm volatile ("fsdi $fd31, [%0+0xf8]\n\t" - "fsdi $fd30, [%0+0xf0]\n\t" - "fsdi $fd29, [%0+0xe8]\n\t" - "fsdi $fd28, [%0+0xe0]\n\t" - "fsdi $fd27, [%0+0xd8]\n\t" - "fsdi $fd26, [%0+0xd0]\n\t" - "fsdi $fd25, [%0+0xc8]\n\t" - "fsdi $fd24, [%0+0xc0]\n\t" - "fsdi $fd23, [%0+0xb8]\n\t" - "fsdi $fd22, [%0+0xb0]\n\t" - "fsdi $fd21, [%0+0xa8]\n\t" - "fsdi $fd20, [%0+0xa0]\n\t" - "fsdi $fd19, [%0+0x98]\n\t" - "fsdi $fd18, [%0+0x90]\n\t" - "fsdi $fd17, [%0+0x88]\n\t" - "fsdi $fd16, [%0+0x80]\n\t" - : /* no output */ - : "r" (&tsk->thread.fpu) - : "memory"); - fallthrough; - case SP32_DP16_reg: - asm volatile ("fsdi $fd15, [%0+0x78]\n\t" - "fsdi $fd14, [%0+0x70]\n\t" - "fsdi $fd13, [%0+0x68]\n\t" - "fsdi $fd12, [%0+0x60]\n\t" - "fsdi $fd11, [%0+0x58]\n\t" - "fsdi $fd10, [%0+0x50]\n\t" - "fsdi $fd9, [%0+0x48]\n\t" - "fsdi $fd8, [%0+0x40]\n\t" - : /* no output */ - : "r" (&tsk->thread.fpu) - : "memory"); - fallthrough; - case SP16_DP8_reg: - asm volatile ("fsdi $fd7, [%0+0x38]\n\t" - "fsdi $fd6, [%0+0x30]\n\t" - "fsdi $fd5, [%0+0x28]\n\t" - "fsdi $fd4, [%0+0x20]\n\t" - : /* no output */ - : "r" (&tsk->thread.fpu) - : "memory"); - fallthrough; - case SP8_DP4_reg: - asm volatile ("fsdi $fd3, [%1+0x18]\n\t" - "fsdi $fd2, [%1+0x10]\n\t" - "fsdi $fd1, [%1+0x8]\n\t" - "fsdi $fd0, [%1+0x0]\n\t" - "fmfcsr %0\n\t" - "swi %0, [%1+0x100]\n\t" - : "=&r" (fpcsr) - : "r"(&tsk->thread.fpu) - : "memory"); - } - disable_fpu(); -} - -void load_fpu(const struct fpu_struct *fpregs) -{ - unsigned int fpcfg, fpcsr; - - enable_fpu(); - fpcfg = ((__nds32__fmfcfg() & FPCFG_mskFREG) >> FPCFG_offFREG); - switch (fpcfg) { - case SP32_DP32_reg: - asm volatile ("fldi $fd31, [%0+0xf8]\n\t" - "fldi $fd30, [%0+0xf0]\n\t" - "fldi $fd29, [%0+0xe8]\n\t" - "fldi $fd28, [%0+0xe0]\n\t" - "fldi $fd27, [%0+0xd8]\n\t" - "fldi $fd26, [%0+0xd0]\n\t" - "fldi $fd25, [%0+0xc8]\n\t" - "fldi $fd24, [%0+0xc0]\n\t" - "fldi $fd23, [%0+0xb8]\n\t" - "fldi $fd22, [%0+0xb0]\n\t" - "fldi $fd21, [%0+0xa8]\n\t" - "fldi $fd20, [%0+0xa0]\n\t" - "fldi $fd19, [%0+0x98]\n\t" - "fldi $fd18, [%0+0x90]\n\t" - "fldi $fd17, [%0+0x88]\n\t" - "fldi $fd16, [%0+0x80]\n\t" - : /* no output */ - : "r" (fpregs)); - fallthrough; - case SP32_DP16_reg: - asm volatile ("fldi $fd15, [%0+0x78]\n\t" - "fldi $fd14, [%0+0x70]\n\t" - "fldi $fd13, [%0+0x68]\n\t" - "fldi $fd12, [%0+0x60]\n\t" - "fldi $fd11, [%0+0x58]\n\t" - "fldi $fd10, [%0+0x50]\n\t" - "fldi $fd9, [%0+0x48]\n\t" - "fldi $fd8, [%0+0x40]\n\t" - : /* no output */ - : "r" (fpregs)); - fallthrough; - case SP16_DP8_reg: - asm volatile ("fldi $fd7, [%0+0x38]\n\t" - "fldi $fd6, [%0+0x30]\n\t" - "fldi $fd5, [%0+0x28]\n\t" - "fldi $fd4, [%0+0x20]\n\t" - : /* no output */ - : "r" (fpregs)); - fallthrough; - case SP8_DP4_reg: - asm volatile ("fldi $fd3, [%1+0x18]\n\t" - "fldi $fd2, [%1+0x10]\n\t" - "fldi $fd1, [%1+0x8]\n\t" - "fldi $fd0, [%1+0x0]\n\t" - "lwi %0, [%1+0x100]\n\t" - "fmtcsr %0\n\t":"=&r" (fpcsr) - : "r"(fpregs)); - } - disable_fpu(); -} -void store_fpu_for_suspend(void) -{ -#ifdef CONFIG_LAZY_FPU - if (last_task_used_math != NULL) - save_fpu(last_task_used_math); - last_task_used_math = NULL; -#else - if (!used_math()) - return; - unlazy_fpu(current); -#endif - clear_fpu(task_pt_regs(current)); -} -inline void do_fpu_context_switch(struct pt_regs *regs) -{ - /* Enable to use FPU. */ - - if (!user_mode(regs)) { - pr_err("BUG: FPU is used in kernel mode.\n"); - BUG(); - return; - } - - enable_ptreg_fpu(regs); -#ifdef CONFIG_LAZY_FPU //Lazy FPU is used - if (last_task_used_math == current) - return; - if (last_task_used_math != NULL) - /* Other processes fpu state, save away */ - save_fpu(last_task_used_math); - last_task_used_math = current; -#endif - if (used_math()) { - load_fpu(¤t->thread.fpu); - } else { - /* First time FPU user. */ - load_fpu(&init_fpuregs); -#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - current->thread.fpu.UDF_IEX_trap = init_fpuregs.UDF_IEX_trap; -#endif - set_used_math(); - } - -} - -inline void fill_sigfpe_signo(unsigned int fpcsr, int *signo) -{ - if (fpcsr & FPCSR_mskOVFT) - *signo = FPE_FLTOVF; -#ifndef CONFIG_SUPPORT_DENORMAL_ARITHMETIC - else if (fpcsr & FPCSR_mskUDFT) - *signo = FPE_FLTUND; -#endif - else if (fpcsr & FPCSR_mskIVOT) - *signo = FPE_FLTINV; - else if (fpcsr & FPCSR_mskDBZT) - *signo = FPE_FLTDIV; - else if (fpcsr & FPCSR_mskIEXT) - *signo = FPE_FLTRES; -} - -inline void handle_fpu_exception(struct pt_regs *regs) -{ - unsigned int fpcsr; - int si_code = 0, si_signo = SIGFPE; -#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - unsigned long redo_except = FPCSR_mskDNIT|FPCSR_mskUDFT|FPCSR_mskIEXT; -#else - unsigned long redo_except = FPCSR_mskDNIT; -#endif - - lose_fpu(); - fpcsr = current->thread.fpu.fpcsr; - - if (fpcsr & redo_except) { - si_signo = do_fpuemu(regs, ¤t->thread.fpu); - fpcsr = current->thread.fpu.fpcsr; - if (!si_signo) { - current->thread.fpu.fpcsr &= ~(redo_except); - goto done; - } - } else if (fpcsr & FPCSR_mskRIT) { - if (!user_mode(regs)) - make_task_dead(SIGILL); - si_signo = SIGILL; - } - - switch (si_signo) { - case SIGFPE: - fill_sigfpe_signo(fpcsr, &si_code); - break; - case SIGILL: - show_regs(regs); - si_code = ILL_COPROC; - break; - case SIGBUS: - si_code = BUS_ADRERR; - break; - default: - break; - } - - force_sig_fault(si_signo, si_code, - (void __user *)instruction_pointer(regs)); -done: - own_fpu(); -} - -bool do_fpu_exception(unsigned int subtype, struct pt_regs *regs) -{ - int done = true; - /* Coprocessor disabled exception */ - if (subtype == FPU_DISABLE_EXCEPTION) { - preempt_disable(); - do_fpu_context_switch(regs); - preempt_enable(); - } - /* Coprocessor exception such as underflow and overflow */ - else if (subtype == FPU_EXCEPTION) - handle_fpu_exception(regs); - else - done = false; - return done; -} diff --git a/arch/nds32/kernel/ftrace.c b/arch/nds32/kernel/ftrace.c deleted file mode 100644 index 711bc8cd186d..000000000000 --- a/arch/nds32/kernel/ftrace.c +++ /dev/null @@ -1,278 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include - -#ifndef CONFIG_DYNAMIC_FTRACE -extern void (*ftrace_trace_function)(unsigned long, unsigned long, - struct ftrace_ops*, struct ftrace_regs*); -extern void ftrace_graph_caller(void); - -noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *fregs) -{ - __asm__ (""); /* avoid to optimize as pure function */ -} - -noinline void _mcount(unsigned long parent_ip) -{ - /* save all state by the compiler prologue */ - - unsigned long ip = (unsigned long)__builtin_return_address(0); - - if (ftrace_trace_function != ftrace_stub) - ftrace_trace_function(ip - MCOUNT_INSN_SIZE, parent_ip, - NULL, NULL); - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - if (ftrace_graph_return != (trace_func_graph_ret_t)ftrace_stub - || ftrace_graph_entry != ftrace_graph_entry_stub) - ftrace_graph_caller(); -#endif - - /* restore all state by the compiler epilogue */ -} -EXPORT_SYMBOL(_mcount); - -#else /* CONFIG_DYNAMIC_FTRACE */ - -noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *fregs) -{ - __asm__ (""); /* avoid to optimize as pure function */ -} - -noinline void __naked _mcount(unsigned long parent_ip) -{ - __asm__ (""); /* avoid to optimize as pure function */ -} -EXPORT_SYMBOL(_mcount); - -#define XSTR(s) STR(s) -#define STR(s) #s -void _ftrace_caller(unsigned long parent_ip) -{ - /* save all state needed by the compiler prologue */ - - /* - * prepare arguments for real tracing function - * first arg : __builtin_return_address(0) - MCOUNT_INSN_SIZE - * second arg : parent_ip - */ - __asm__ __volatile__ ( - "move $r1, %0 \n\t" - "addi $r0, %1, #-" XSTR(MCOUNT_INSN_SIZE) "\n\t" - : - : "r" (parent_ip), "r" (__builtin_return_address(0))); - - /* a placeholder for the call to a real tracing function */ - __asm__ __volatile__ ( - "ftrace_call: \n\t" - "nop \n\t" - "nop \n\t" - "nop \n\t"); - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - /* a placeholder for the call to ftrace_graph_caller */ - __asm__ __volatile__ ( - "ftrace_graph_call: \n\t" - "nop \n\t" - "nop \n\t" - "nop \n\t"); -#endif - /* restore all state needed by the compiler epilogue */ -} - -static unsigned long gen_sethi_insn(unsigned long addr) -{ - unsigned long opcode = 0x46000000; - unsigned long imm = addr >> 12; - unsigned long rt_num = 0xf << 20; - - return ENDIAN_CONVERT(opcode | rt_num | imm); -} - -static unsigned long gen_ori_insn(unsigned long addr) -{ - unsigned long opcode = 0x58000000; - unsigned long imm = addr & 0x0000fff; - unsigned long rt_num = 0xf << 20; - unsigned long ra_num = 0xf << 15; - - return ENDIAN_CONVERT(opcode | rt_num | ra_num | imm); -} - -static unsigned long gen_jral_insn(unsigned long addr) -{ - unsigned long opcode = 0x4a000001; - unsigned long rt_num = 0x1e << 20; - unsigned long rb_num = 0xf << 10; - - return ENDIAN_CONVERT(opcode | rt_num | rb_num); -} - -static void ftrace_gen_call_insn(unsigned long *call_insns, - unsigned long addr) -{ - call_insns[0] = gen_sethi_insn(addr); /* sethi $r15, imm20u */ - call_insns[1] = gen_ori_insn(addr); /* ori $r15, $r15, imm15u */ - call_insns[2] = gen_jral_insn(addr); /* jral $lp, $r15 */ -} - -static int __ftrace_modify_code(unsigned long pc, unsigned long *old_insn, - unsigned long *new_insn, bool validate) -{ - unsigned long orig_insn[3]; - - if (validate) { - if (copy_from_kernel_nofault(orig_insn, (void *)pc, - MCOUNT_INSN_SIZE)) - return -EFAULT; - if (memcmp(orig_insn, old_insn, MCOUNT_INSN_SIZE)) - return -EINVAL; - } - - if (copy_to_kernel_nofault((void *)pc, new_insn, MCOUNT_INSN_SIZE)) - return -EPERM; - - return 0; -} - -static int ftrace_modify_code(unsigned long pc, unsigned long *old_insn, - unsigned long *new_insn, bool validate) -{ - int ret; - - ret = __ftrace_modify_code(pc, old_insn, new_insn, validate); - if (ret) - return ret; - - flush_icache_range(pc, pc + MCOUNT_INSN_SIZE); - - return ret; -} - -int ftrace_update_ftrace_func(ftrace_func_t func) -{ - unsigned long pc = (unsigned long)&ftrace_call; - unsigned long old_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP}; - unsigned long new_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP}; - - if (func != ftrace_stub) - ftrace_gen_call_insn(new_insn, (unsigned long)func); - - return ftrace_modify_code(pc, old_insn, new_insn, false); -} - -int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) -{ - unsigned long pc = rec->ip; - unsigned long nop_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP}; - unsigned long call_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP}; - - ftrace_gen_call_insn(call_insn, addr); - - return ftrace_modify_code(pc, nop_insn, call_insn, true); -} - -int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, - unsigned long addr) -{ - unsigned long pc = rec->ip; - unsigned long nop_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP}; - unsigned long call_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP}; - - ftrace_gen_call_insn(call_insn, addr); - - return ftrace_modify_code(pc, call_insn, nop_insn, true); -} -#endif /* CONFIG_DYNAMIC_FTRACE */ - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER -void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, - unsigned long frame_pointer) -{ - unsigned long return_hooker = (unsigned long)&return_to_handler; - unsigned long old; - - if (unlikely(atomic_read(¤t->tracing_graph_pause))) - return; - - old = *parent; - - if (!function_graph_enter(old, self_addr, frame_pointer, NULL)) - *parent = return_hooker; -} - -noinline void ftrace_graph_caller(void) -{ - unsigned long *parent_ip = - (unsigned long *)(__builtin_frame_address(2) - 4); - - unsigned long selfpc = - (unsigned long)(__builtin_return_address(1) - MCOUNT_INSN_SIZE); - - unsigned long frame_pointer = - (unsigned long)__builtin_frame_address(3); - - prepare_ftrace_return(parent_ip, selfpc, frame_pointer); -} - -extern unsigned long ftrace_return_to_handler(unsigned long frame_pointer); -void __naked return_to_handler(void) -{ - __asm__ __volatile__ ( - /* save state needed by the ABI */ - "smw.adm $r0,[$sp],$r1,#0x0 \n\t" - - /* get original return address */ - "move $r0, $fp \n\t" - "bal ftrace_return_to_handler\n\t" - "move $lp, $r0 \n\t" - - /* restore state needed by the ABI */ - "lmw.bim $r0,[$sp],$r1,#0x0 \n\t"); -} - -#ifdef CONFIG_DYNAMIC_FTRACE -extern unsigned long ftrace_graph_call; - -static int ftrace_modify_graph_caller(bool enable) -{ - unsigned long pc = (unsigned long)&ftrace_graph_call; - unsigned long nop_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP}; - unsigned long call_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP}; - - ftrace_gen_call_insn(call_insn, (unsigned long)ftrace_graph_caller); - - if (enable) - return ftrace_modify_code(pc, nop_insn, call_insn, true); - else - return ftrace_modify_code(pc, call_insn, nop_insn, true); -} - -int ftrace_enable_ftrace_graph_caller(void) -{ - return ftrace_modify_graph_caller(true); -} - -int ftrace_disable_ftrace_graph_caller(void) -{ - return ftrace_modify_graph_caller(false); -} -#endif /* CONFIG_DYNAMIC_FTRACE */ - -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ - - -#ifdef CONFIG_TRACE_IRQFLAGS -noinline void __trace_hardirqs_off(void) -{ - trace_hardirqs_off(); -} -noinline void __trace_hardirqs_on(void) -{ - trace_hardirqs_on(); -} -#endif /* CONFIG_TRACE_IRQFLAGS */ diff --git a/arch/nds32/kernel/head.S b/arch/nds32/kernel/head.S deleted file mode 100644 index 7347f00451a9..000000000000 --- a/arch/nds32/kernel/head.S +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_CPU_BIG_ENDIAN -#define OF_DT_MAGIC 0xd00dfeed -#else -#define OF_DT_MAGIC 0xedfe0dd0 -#endif - - .globl swapper_pg_dir - .equ swapper_pg_dir, TEXTADDR - 0x4000 - -/* - * Kernel startup entry point. - */ - .section ".head.text", "ax" - .type _stext, %function -ENTRY(_stext) - setgie.d ! Disable interrupt - isb -/* - * Disable I/D-cache and enable it at a proper time - */ - mfsr $r0, $mr8 - li $r1, #~(CACHE_CTL_mskIC_EN|CACHE_CTL_mskDC_EN) - and $r0, $r0, $r1 - mtsr $r0, $mr8 - -/* - * Process device tree blob - */ - andi $r0,$r2,#0x3 - li $r10, 0 - bne $r0, $r10, _nodtb - lwi $r0, [$r2] - li $r1, OF_DT_MAGIC - bne $r0, $r1, _nodtb - move $r10, $r2 -_nodtb: - -/* - * Create a temporary mapping area for booting, before start_kernel - */ - sethi $r4, hi20(swapper_pg_dir) - li $p0, (PAGE_OFFSET - PHYS_OFFSET) - sub $r4, $r4, $p0 - tlbop FlushAll ! invalidate TLB\n" - isb - mtsr $r4, $L1_PPTB ! load page table pointer\n" - -#ifdef CONFIG_CPU_DCACHE_DISABLE - #define MMU_CTL_NTCC MMU_CTL_CACHEABLE_NON -#else - #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - #define MMU_CTL_NTCC MMU_CTL_CACHEABLE_WT - #else - #define MMU_CTL_NTCC MMU_CTL_CACHEABLE_WB - #endif -#endif - -/* set NTC cacheability, mutliple page size in use */ - mfsr $r3, $MMU_CTL -#if CONFIG_MEMORY_START >= 0xc0000000 - ori $r3, $r3, (MMU_CTL_NTCC << MMU_CTL_offNTC3) -#elif CONFIG_MEMORY_START >= 0x80000000 - ori $r3, $r3, (MMU_CTL_NTCC << MMU_CTL_offNTC2) -#elif CONFIG_MEMORY_START >= 0x40000000 - ori $r3, $r3, (MMU_CTL_NTCC << MMU_CTL_offNTC1) -#else - ori $r3, $r3, (MMU_CTL_NTCC << MMU_CTL_offNTC0) -#endif - -#ifdef CONFIG_ANDES_PAGE_SIZE_4KB - ori $r3, $r3, #(MMU_CTL_mskMPZIU) -#else - ori $r3, $r3, #(MMU_CTL_mskMPZIU|MMU_CTL_D8KB) -#endif -#ifdef CONFIG_HW_SUPPORT_UNALIGNMENT_ACCESS - li $r0, #MMU_CTL_UNA - or $r3, $r3, $r0 -#endif - mtsr $r3, $MMU_CTL - isb - -/* set page size and size of kernel image */ - mfsr $r0, $MMU_CFG - srli $r3, $r0, MMU_CFG_offfEPSZ - zeb $r3, $r3 - bnez $r3, _extra_page_size_support -#ifdef CONFIG_ANDES_PAGE_SIZE_4KB - li $r5, #SZ_4K ! Use 4KB page size -#else - li $r5, #SZ_8K ! Use 8KB page size - li $r3, #1 -#endif - mtsr $r3, $TLB_MISC - b _image_size_check - -_extra_page_size_support: ! Use epzs pages size - clz $r6, $r3 - subri $r2, $r6, #31 - li $r3, #1 - sll $r3, $r3, $r2 - /* MMU_CFG.EPSZ value -> meaning */ - mul $r5, $r3, $r3 - slli $r5, $r5, #14 - /* MMU_CFG.EPSZ -> TLB_MISC.ACC_PSZ */ - addi $r3, $r2, #0x2 - mtsr $r3, $TLB_MISC - -_image_size_check: - /* calculate the image maximum size accepted by TLB config */ - andi $r6, $r0, MMU_CFG_mskTBW - andi $r0, $r0, MMU_CFG_mskTBS - srli $r6, $r6, MMU_CFG_offTBW - srli $r0, $r0, MMU_CFG_offTBS - addi $r6, $r6, #0x1 ! MMU_CFG.TBW value -> meaning - addi $r0, $r0, #0x2 ! MMU_CFG.TBS value -> meaning - sll $r0, $r6, $r0 ! entries = k-way * n-set - mul $r6, $r0, $r5 ! max size = entries * page size - /* check kernel image size */ - la $r3, (_end - PAGE_OFFSET) - bgt $r3, $r6, __error - - li $r2, #(PHYS_OFFSET + TLB_DATA_kernel_text_attr) - li $r3, PAGE_OFFSET - add $r6, $r6, $r3 - -_tlb: - mtsr $r3, $TLB_VPN - dsb - tlbop $r2, RWR - isb - add $r3, $r3, $r5 - add $r2, $r2, $r5 - bgt $r6, $r3, _tlb - mfsr $r3, $TLB_MISC ! setup access page size - li $r2, #~0xf - and $r3, $r3, $r2 -#ifdef CONFIG_ANDES_PAGE_SIZE_8KB - ori $r3, $r3, #0x1 -#endif - mtsr $r3, $TLB_MISC - - mfsr $r0, $MISC_CTL ! Enable BTB, RTP, shadow sp, and HW_PRE - ori $r0, $r0, #MISC_init - mtsr $r0, $MISC_CTL - - mfsr $p1, $PSW - li $r15, #~PSW_clr ! clear WBNA|DME|IME|DT|IT|POM|INTL|GIE - and $p1, $p1, $r15 - ori $p1, $p1, #PSW_init - mtsr $p1, $IPSW ! when iret, it will automatically enable MMU - la $lp, __mmap_switched - mtsr $lp, $IPC - iret - nop - - .type __switch_data, %object -__switch_data: - .long __bss_start ! $r6 - .long _end ! $r7 - .long __atags_pointer ! $atag_pointer - .long init_task ! $r9, move to $r25 - .long init_thread_union + THREAD_SIZE ! $sp - - -/* - * The following fragment of code is executed with the MMU on in MMU mode, - * and uses absolute addresses; this is not position independent. - */ - .align - .type __mmap_switched, %function -__mmap_switched: - la $r3, __switch_data - lmw.bim $r6, [$r3], $r9, #0b0001 - move $r25, $r9 - move $fp, #0 ! Clear BSS (and zero $fp) - beq $r7, $r6, _RRT -1: swi.bi $fp, [$r6], #4 - bne $r7, $r6, 1b - swi $r10, [$r8] - -_RRT: - b start_kernel - -__error: - b __error diff --git a/arch/nds32/kernel/irq.c b/arch/nds32/kernel/irq.c deleted file mode 100644 index 6ff5a672be27..000000000000 --- a/arch/nds32/kernel/irq.c +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include - -void __init init_IRQ(void) -{ - irqchip_init(); -} diff --git a/arch/nds32/kernel/module.c b/arch/nds32/kernel/module.c deleted file mode 100644 index 3897fd14a21d..000000000000 --- a/arch/nds32/kernel/module.c +++ /dev/null @@ -1,278 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include - -void *module_alloc(unsigned long size) -{ - return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, - GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, - __builtin_return_address(0)); -} - -void module_free(struct module *module, void *region) -{ - vfree(region); -} - -int module_frob_arch_sections(Elf_Ehdr * hdr, - Elf_Shdr * sechdrs, - char *secstrings, struct module *mod) -{ - return 0; -} - -void do_reloc16(unsigned int val, unsigned int *loc, unsigned int val_mask, - unsigned int val_shift, unsigned int loc_mask, - unsigned int partial_in_place, unsigned int swap) -{ - unsigned int tmp = 0, tmp2 = 0; - - __asm__ __volatile__("\tlhi.bi\t%0, [%2], 0\n" - "\tbeqz\t%3, 1f\n" - "\twsbh\t%0, %1\n" - "1:\n":"=r"(tmp):"0"(tmp), "r"(loc), "r"(swap) - ); - - tmp2 = tmp & loc_mask; - if (partial_in_place) { - tmp &= (~loc_mask); - tmp = - tmp2 | ((tmp + ((val & val_mask) >> val_shift)) & val_mask); - } else { - tmp = tmp2 | ((val & val_mask) >> val_shift); - } - - __asm__ __volatile__("\tbeqz\t%3, 2f\n" - "\twsbh\t%0, %1\n" - "2:\n" - "\tshi.bi\t%0, [%2], 0\n":"=r"(tmp):"0"(tmp), - "r"(loc), "r"(swap) - ); -} - -void do_reloc32(unsigned int val, unsigned int *loc, unsigned int val_mask, - unsigned int val_shift, unsigned int loc_mask, - unsigned int partial_in_place, unsigned int swap) -{ - unsigned int tmp = 0, tmp2 = 0; - - __asm__ __volatile__("\tlmw.bi\t%0, [%2], %0, 0\n" - "\tbeqz\t%3, 1f\n" - "\twsbh\t%0, %1\n" - "\trotri\t%0, %1, 16\n" - "1:\n":"=r"(tmp):"0"(tmp), "r"(loc), "r"(swap) - ); - - tmp2 = tmp & loc_mask; - if (partial_in_place) { - tmp &= (~loc_mask); - tmp = - tmp2 | ((tmp + ((val & val_mask) >> val_shift)) & val_mask); - } else { - tmp = tmp2 | ((val & val_mask) >> val_shift); - } - - __asm__ __volatile__("\tbeqz\t%3, 2f\n" - "\twsbh\t%0, %1\n" - "\trotri\t%0, %1, 16\n" - "2:\n" - "\tsmw.bi\t%0, [%2], %0, 0\n":"=r"(tmp):"0"(tmp), - "r"(loc), "r"(swap) - ); -} - -static inline int exceed_limit(int offset, unsigned int val_mask, - struct module *module, Elf32_Rela * rel, - unsigned int relindex, unsigned int reloc_order) -{ - int abs_off = offset < 0 ? ~offset : offset; - - if (abs_off & (~val_mask)) { - pr_err("\n%s: relocation type %d out of range.\n" - "please rebuild the kernel module with gcc option \"-Wa,-mno-small-text\".\n", - module->name, ELF32_R_TYPE(rel->r_info)); - pr_err("section %d reloc %d offset 0x%x relative 0x%x.\n", - relindex, reloc_order, rel->r_offset, offset); - return true; - } - return false; -} - -#ifdef __NDS32_EL__ -#define NEED_SWAP 1 -#else -#define NEED_SWAP 0 -#endif - -int -apply_relocate_add(Elf32_Shdr * sechdrs, const char *strtab, - unsigned int symindex, unsigned int relindex, - struct module *module) -{ - Elf32_Shdr *symsec = sechdrs + symindex; - Elf32_Shdr *relsec = sechdrs + relindex; - Elf32_Shdr *dstsec = sechdrs + relsec->sh_info; - Elf32_Rela *rel = (void *)relsec->sh_addr; - unsigned int i; - - for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rela); i++, rel++) { - Elf32_Addr *loc; - Elf32_Sym *sym; - Elf32_Addr v; - s32 offset; - - offset = ELF32_R_SYM(rel->r_info); - if (offset < 0 - || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { - pr_err("%s: bad relocation\n", module->name); - pr_err("section %d reloc %d\n", relindex, i); - return -ENOEXEC; - } - - sym = ((Elf32_Sym *) symsec->sh_addr) + offset; - - if (rel->r_offset < 0 - || rel->r_offset > dstsec->sh_size - sizeof(u16)) { - pr_err("%s: out of bounds relocation\n", module->name); - pr_err("section %d reloc %d offset 0x%0x size %d\n", - relindex, i, rel->r_offset, dstsec->sh_size); - return -ENOEXEC; - } - - loc = (Elf32_Addr *) (dstsec->sh_addr + rel->r_offset); - v = sym->st_value + rel->r_addend; - - switch (ELF32_R_TYPE(rel->r_info)) { - case R_NDS32_NONE: - case R_NDS32_INSN16: - case R_NDS32_LABEL: - case R_NDS32_LONGCALL1: - case R_NDS32_LONGCALL2: - case R_NDS32_LONGCALL3: - case R_NDS32_LONGCALL4: - case R_NDS32_LONGJUMP1: - case R_NDS32_LONGJUMP2: - case R_NDS32_LONGJUMP3: - case R_NDS32_9_FIXED_RELA: - case R_NDS32_15_FIXED_RELA: - case R_NDS32_17_FIXED_RELA: - case R_NDS32_25_FIXED_RELA: - case R_NDS32_LOADSTORE: - case R_NDS32_DWARF2_OP1_RELA: - case R_NDS32_DWARF2_OP2_RELA: - case R_NDS32_DWARF2_LEB_RELA: - case R_NDS32_RELA_NOP_MIX ... R_NDS32_RELA_NOP_MAX: - break; - - case R_NDS32_32_RELA: - do_reloc32(v, loc, 0xffffffff, 0, 0, 0, 0); - break; - - case R_NDS32_HI20_RELA: - do_reloc32(v, loc, 0xfffff000, 12, 0xfff00000, 0, - NEED_SWAP); - break; - - case R_NDS32_LO12S3_RELA: - do_reloc32(v, loc, 0x00000fff, 3, 0xfffff000, 0, - NEED_SWAP); - break; - - case R_NDS32_LO12S2_RELA: - do_reloc32(v, loc, 0x00000fff, 2, 0xfffff000, 0, - NEED_SWAP); - break; - - case R_NDS32_LO12S1_RELA: - do_reloc32(v, loc, 0x00000fff, 1, 0xfffff000, 0, - NEED_SWAP); - break; - - case R_NDS32_LO12S0_RELA: - case R_NDS32_LO12S0_ORI_RELA: - do_reloc32(v, loc, 0x00000fff, 0, 0xfffff000, 0, - NEED_SWAP); - break; - - case R_NDS32_9_PCREL_RELA: - if (exceed_limit - ((v - (Elf32_Addr) loc), 0x000000ff, module, rel, - relindex, i)) - return -ENOEXEC; - do_reloc16(v - (Elf32_Addr) loc, loc, 0x000001ff, 1, - 0xffffff00, 0, NEED_SWAP); - break; - - case R_NDS32_15_PCREL_RELA: - if (exceed_limit - ((v - (Elf32_Addr) loc), 0x00003fff, module, rel, - relindex, i)) - return -ENOEXEC; - do_reloc32(v - (Elf32_Addr) loc, loc, 0x00007fff, 1, - 0xffffc000, 0, NEED_SWAP); - break; - - case R_NDS32_17_PCREL_RELA: - if (exceed_limit - ((v - (Elf32_Addr) loc), 0x0000ffff, module, rel, - relindex, i)) - return -ENOEXEC; - do_reloc32(v - (Elf32_Addr) loc, loc, 0x0001ffff, 1, - 0xffff0000, 0, NEED_SWAP); - break; - - case R_NDS32_25_PCREL_RELA: - if (exceed_limit - ((v - (Elf32_Addr) loc), 0x00ffffff, module, rel, - relindex, i)) - return -ENOEXEC; - do_reloc32(v - (Elf32_Addr) loc, loc, 0x01ffffff, 1, - 0xff000000, 0, NEED_SWAP); - break; - case R_NDS32_WORD_9_PCREL_RELA: - if (exceed_limit - ((v - (Elf32_Addr) loc), 0x000000ff, module, rel, - relindex, i)) - return -ENOEXEC; - do_reloc32(v - (Elf32_Addr) loc, loc, 0x000001ff, 1, - 0xffffff00, 0, NEED_SWAP); - break; - - case R_NDS32_SDA15S3_RELA: - case R_NDS32_SDA15S2_RELA: - case R_NDS32_SDA15S1_RELA: - case R_NDS32_SDA15S0_RELA: - pr_err("%s: unsupported relocation type %d.\n", - module->name, ELF32_R_TYPE(rel->r_info)); - pr_err - ("Small data section access doesn't work in the kernel space; " - "please rebuild the kernel module with gcc option -mcmodel=large.\n"); - pr_err("section %d reloc %d offset 0x%x size %d\n", - relindex, i, rel->r_offset, dstsec->sh_size); - break; - - default: - pr_err("%s: unsupported relocation type %d.\n", - module->name, ELF32_R_TYPE(rel->r_info)); - pr_err("section %d reloc %d offset 0x%x size %d\n", - relindex, i, rel->r_offset, dstsec->sh_size); - } - } - return 0; -} - -int -module_finalize(const Elf32_Ehdr * hdr, const Elf_Shdr * sechdrs, - struct module *module) -{ - return 0; -} - -void module_arch_cleanup(struct module *mod) -{ -} diff --git a/arch/nds32/kernel/nds32_ksyms.c b/arch/nds32/kernel/nds32_ksyms.c deleted file mode 100644 index 20719e42ae36..000000000000 --- a/arch/nds32/kernel/nds32_ksyms.c +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* mem functions */ -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memzero); - -/* user mem (segment) */ -EXPORT_SYMBOL(__arch_copy_from_user); -EXPORT_SYMBOL(__arch_copy_to_user); -EXPORT_SYMBOL(__arch_clear_user); diff --git a/arch/nds32/kernel/perf_event_cpu.c b/arch/nds32/kernel/perf_event_cpu.c deleted file mode 100644 index a78a879e7ef1..000000000000 --- a/arch/nds32/kernel/perf_event_cpu.c +++ /dev/null @@ -1,1500 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2008-2017 Andes Technology Corporation - * - * Reference ARMv7: Jean Pihet - * 2010 (c) MontaVista Software, LLC. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* Set at runtime when we know what CPU type we are. */ -static struct nds32_pmu *cpu_pmu; - -static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); -static void nds32_pmu_start(struct nds32_pmu *cpu_pmu); -static void nds32_pmu_stop(struct nds32_pmu *cpu_pmu); -static struct platform_device_id cpu_pmu_plat_device_ids[] = { - {.name = "nds32-pfm"}, - {}, -}; - -static int nds32_pmu_map_cache_event(const unsigned int (*cache_map) - [PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX], u64 config) -{ - unsigned int cache_type, cache_op, cache_result, ret; - - cache_type = (config >> 0) & 0xff; - if (cache_type >= PERF_COUNT_HW_CACHE_MAX) - return -EINVAL; - - cache_op = (config >> 8) & 0xff; - if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) - return -EINVAL; - - cache_result = (config >> 16) & 0xff; - if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) - return -EINVAL; - - ret = (int)(*cache_map)[cache_type][cache_op][cache_result]; - - if (ret == CACHE_OP_UNSUPPORTED) - return -ENOENT; - - return ret; -} - -static int -nds32_pmu_map_hw_event(const unsigned int (*event_map)[PERF_COUNT_HW_MAX], - u64 config) -{ - int mapping; - - if (config >= PERF_COUNT_HW_MAX) - return -ENOENT; - - mapping = (*event_map)[config]; - return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping; -} - -static int nds32_pmu_map_raw_event(u32 raw_event_mask, u64 config) -{ - int ev_type = (int)(config & raw_event_mask); - int idx = config >> 8; - - switch (idx) { - case 0: - ev_type = PFM_OFFSET_MAGIC_0 + ev_type; - if (ev_type >= SPAV3_0_SEL_LAST || ev_type <= SPAV3_0_SEL_BASE) - return -ENOENT; - break; - case 1: - ev_type = PFM_OFFSET_MAGIC_1 + ev_type; - if (ev_type >= SPAV3_1_SEL_LAST || ev_type <= SPAV3_1_SEL_BASE) - return -ENOENT; - break; - case 2: - ev_type = PFM_OFFSET_MAGIC_2 + ev_type; - if (ev_type >= SPAV3_2_SEL_LAST || ev_type <= SPAV3_2_SEL_BASE) - return -ENOENT; - break; - default: - return -ENOENT; - } - - return ev_type; -} - -int -nds32_pmu_map_event(struct perf_event *event, - const unsigned int (*event_map)[PERF_COUNT_HW_MAX], - const unsigned int (*cache_map) - [PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX], u32 raw_event_mask) -{ - u64 config = event->attr.config; - - switch (event->attr.type) { - case PERF_TYPE_HARDWARE: - return nds32_pmu_map_hw_event(event_map, config); - case PERF_TYPE_HW_CACHE: - return nds32_pmu_map_cache_event(cache_map, config); - case PERF_TYPE_RAW: - return nds32_pmu_map_raw_event(raw_event_mask, config); - } - - return -ENOENT; -} - -static int nds32_spav3_map_event(struct perf_event *event) -{ - return nds32_pmu_map_event(event, &nds32_pfm_perf_map, - &nds32_pfm_perf_cache_map, SOFTWARE_EVENT_MASK); -} - -static inline u32 nds32_pfm_getreset_flags(void) -{ - /* Read overflow status */ - u32 val = __nds32__mfsr(NDS32_SR_PFM_CTL); - u32 old_val = val; - - /* Write overflow bit to clear status, and others keep it 0 */ - u32 ov_flag = PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]; - - __nds32__mtsr(val | ov_flag, NDS32_SR_PFM_CTL); - - return old_val; -} - -static inline int nds32_pfm_has_overflowed(u32 pfm) -{ - u32 ov_flag = PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]; - - return pfm & ov_flag; -} - -static inline int nds32_pfm_counter_has_overflowed(u32 pfm, int idx) -{ - u32 mask = 0; - - switch (idx) { - case 0: - mask = PFM_CTL_OVF[0]; - break; - case 1: - mask = PFM_CTL_OVF[1]; - break; - case 2: - mask = PFM_CTL_OVF[2]; - break; - default: - pr_err("%s index wrong\n", __func__); - break; - } - return pfm & mask; -} - -/* - * Set the next IRQ period, based on the hwc->period_left value. - * To be called with the event disabled in hw: - */ -int nds32_pmu_event_set_period(struct perf_event *event) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - s64 left = local64_read(&hwc->period_left); - s64 period = hwc->sample_period; - int ret = 0; - - /* The period may have been changed by PERF_EVENT_IOC_PERIOD */ - if (unlikely(period != hwc->last_period)) - left = period - (hwc->last_period - left); - - if (unlikely(left <= -period)) { - left = period; - local64_set(&hwc->period_left, left); - hwc->last_period = period; - ret = 1; - } - - if (unlikely(left <= 0)) { - left += period; - local64_set(&hwc->period_left, left); - hwc->last_period = period; - ret = 1; - } - - if (left > (s64)nds32_pmu->max_period) - left = nds32_pmu->max_period; - - /* - * The hw event starts counting from this event offset, - * mark it to be able to extract future "deltas": - */ - local64_set(&hwc->prev_count, (u64)(-left)); - - nds32_pmu->write_counter(event, (u64)(-left) & nds32_pmu->max_period); - - perf_event_update_userpage(event); - - return ret; -} - -static irqreturn_t nds32_pmu_handle_irq(int irq_num, void *dev) -{ - u32 pfm; - struct perf_sample_data data; - struct nds32_pmu *cpu_pmu = (struct nds32_pmu *)dev; - struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events(); - struct pt_regs *regs; - int idx; - /* - * Get and reset the IRQ flags - */ - pfm = nds32_pfm_getreset_flags(); - - /* - * Did an overflow occur? - */ - if (!nds32_pfm_has_overflowed(pfm)) - return IRQ_NONE; - - /* - * Handle the counter(s) overflow(s) - */ - regs = get_irq_regs(); - - nds32_pmu_stop(cpu_pmu); - for (idx = 0; idx < cpu_pmu->num_events; ++idx) { - struct perf_event *event = cpuc->events[idx]; - struct hw_perf_event *hwc; - - /* Ignore if we don't have an event. */ - if (!event) - continue; - - /* - * We have a single interrupt for all counters. Check that - * each counter has overflowed before we process it. - */ - if (!nds32_pfm_counter_has_overflowed(pfm, idx)) - continue; - - hwc = &event->hw; - nds32_pmu_event_update(event); - perf_sample_data_init(&data, 0, hwc->last_period); - if (!nds32_pmu_event_set_period(event)) - continue; - - if (perf_event_overflow(event, &data, regs)) - cpu_pmu->disable(event); - } - nds32_pmu_start(cpu_pmu); - /* - * Handle the pending perf events. - * - * Note: this call *must* be run with interrupts disabled. For - * platforms that can have the PMU interrupts raised as an NMI, this - * will not work. - */ - irq_work_run(); - - return IRQ_HANDLED; -} - -static inline int nds32_pfm_counter_valid(struct nds32_pmu *cpu_pmu, int idx) -{ - return ((idx >= 0) && (idx < cpu_pmu->num_events)); -} - -static inline int nds32_pfm_disable_counter(int idx) -{ - unsigned int val = __nds32__mfsr(NDS32_SR_PFM_CTL); - u32 mask = 0; - - mask = PFM_CTL_EN[idx]; - val &= ~mask; - val &= ~(PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]); - __nds32__mtsr_isb(val, NDS32_SR_PFM_CTL); - return idx; -} - -/* - * Add an event filter to a given event. - */ -static int nds32_pmu_set_event_filter(struct hw_perf_event *event, - struct perf_event_attr *attr) -{ - unsigned long config_base = 0; - int idx = event->idx; - unsigned long no_kernel_tracing = 0; - unsigned long no_user_tracing = 0; - /* If index is -1, do not do anything */ - if (idx == -1) - return 0; - - no_kernel_tracing = PFM_CTL_KS[idx]; - no_user_tracing = PFM_CTL_KU[idx]; - /* - * Default: enable both kernel and user mode tracing. - */ - if (attr->exclude_user) - config_base |= no_user_tracing; - - if (attr->exclude_kernel) - config_base |= no_kernel_tracing; - - /* - * Install the filter into config_base as this is used to - * construct the event type. - */ - event->config_base |= config_base; - return 0; -} - -static inline void nds32_pfm_write_evtsel(int idx, u32 evnum) -{ - u32 offset = 0; - u32 ori_val = __nds32__mfsr(NDS32_SR_PFM_CTL); - u32 ev_mask = 0; - u32 no_kernel_mask = 0; - u32 no_user_mask = 0; - u32 val; - - offset = PFM_CTL_OFFSEL[idx]; - /* Clear previous mode selection, and write new one */ - no_kernel_mask = PFM_CTL_KS[idx]; - no_user_mask = PFM_CTL_KU[idx]; - ori_val &= ~no_kernel_mask; - ori_val &= ~no_user_mask; - if (evnum & no_kernel_mask) - ori_val |= no_kernel_mask; - - if (evnum & no_user_mask) - ori_val |= no_user_mask; - - /* Clear previous event selection */ - ev_mask = PFM_CTL_SEL[idx]; - ori_val &= ~ev_mask; - evnum &= SOFTWARE_EVENT_MASK; - - /* undo the linear mapping */ - evnum = get_converted_evet_hw_num(evnum); - val = ori_val | (evnum << offset); - val &= ~(PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]); - __nds32__mtsr_isb(val, NDS32_SR_PFM_CTL); -} - -static inline int nds32_pfm_enable_counter(int idx) -{ - unsigned int val = __nds32__mfsr(NDS32_SR_PFM_CTL); - u32 mask = 0; - - mask = PFM_CTL_EN[idx]; - val |= mask; - val &= ~(PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]); - __nds32__mtsr_isb(val, NDS32_SR_PFM_CTL); - return idx; -} - -static inline int nds32_pfm_enable_intens(int idx) -{ - unsigned int val = __nds32__mfsr(NDS32_SR_PFM_CTL); - u32 mask = 0; - - mask = PFM_CTL_IE[idx]; - val |= mask; - val &= ~(PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]); - __nds32__mtsr_isb(val, NDS32_SR_PFM_CTL); - return idx; -} - -static inline int nds32_pfm_disable_intens(int idx) -{ - unsigned int val = __nds32__mfsr(NDS32_SR_PFM_CTL); - u32 mask = 0; - - mask = PFM_CTL_IE[idx]; - val &= ~mask; - val &= ~(PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]); - __nds32__mtsr_isb(val, NDS32_SR_PFM_CTL); - return idx; -} - -static int event_requires_mode_exclusion(struct perf_event_attr *attr) -{ - /* Other modes NDS32 does not support */ - return attr->exclude_user || attr->exclude_kernel; -} - -static void nds32_pmu_enable_event(struct perf_event *event) -{ - unsigned long flags; - unsigned int evnum = 0; - struct hw_perf_event *hwc = &event->hw; - struct nds32_pmu *cpu_pmu = to_nds32_pmu(event->pmu); - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); - int idx = hwc->idx; - - if (!nds32_pfm_counter_valid(cpu_pmu, idx)) { - pr_err("CPU enabling wrong pfm counter IRQ enable\n"); - return; - } - - /* - * Enable counter and interrupt, and set the counter to count - * the event that we're interested in. - */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); - - /* - * Disable counter - */ - nds32_pfm_disable_counter(idx); - - /* - * Check whether we need to exclude the counter from certain modes. - */ - if ((!cpu_pmu->set_event_filter || - cpu_pmu->set_event_filter(hwc, &event->attr)) && - event_requires_mode_exclusion(&event->attr)) { - pr_notice - ("NDS32 performance counters do not support mode exclusion\n"); - hwc->config_base = 0; - } - /* Write event */ - evnum = hwc->config_base; - nds32_pfm_write_evtsel(idx, evnum); - - /* - * Enable interrupt for this counter - */ - nds32_pfm_enable_intens(idx); - - /* - * Enable counter - */ - nds32_pfm_enable_counter(idx); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); -} - -static void nds32_pmu_disable_event(struct perf_event *event) -{ - unsigned long flags; - struct hw_perf_event *hwc = &event->hw; - struct nds32_pmu *cpu_pmu = to_nds32_pmu(event->pmu); - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); - int idx = hwc->idx; - - if (!nds32_pfm_counter_valid(cpu_pmu, idx)) { - pr_err("CPU disabling wrong pfm counter IRQ enable %d\n", idx); - return; - } - - /* - * Disable counter and interrupt - */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); - - /* - * Disable counter - */ - nds32_pfm_disable_counter(idx); - - /* - * Disable interrupt for this counter - */ - nds32_pfm_disable_intens(idx); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); -} - -static inline u32 nds32_pmu_read_counter(struct perf_event *event) -{ - struct nds32_pmu *cpu_pmu = to_nds32_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - int idx = hwc->idx; - u32 count = 0; - - if (!nds32_pfm_counter_valid(cpu_pmu, idx)) { - pr_err("CPU reading wrong counter %d\n", idx); - } else { - switch (idx) { - case PFMC0: - count = __nds32__mfsr(NDS32_SR_PFMC0); - break; - case PFMC1: - count = __nds32__mfsr(NDS32_SR_PFMC1); - break; - case PFMC2: - count = __nds32__mfsr(NDS32_SR_PFMC2); - break; - default: - pr_err - ("%s: CPU has no performance counters %d\n", - __func__, idx); - } - } - return count; -} - -static inline void nds32_pmu_write_counter(struct perf_event *event, u32 value) -{ - struct nds32_pmu *cpu_pmu = to_nds32_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - int idx = hwc->idx; - - if (!nds32_pfm_counter_valid(cpu_pmu, idx)) { - pr_err("CPU writing wrong counter %d\n", idx); - } else { - switch (idx) { - case PFMC0: - __nds32__mtsr_isb(value, NDS32_SR_PFMC0); - break; - case PFMC1: - __nds32__mtsr_isb(value, NDS32_SR_PFMC1); - break; - case PFMC2: - __nds32__mtsr_isb(value, NDS32_SR_PFMC2); - break; - default: - pr_err - ("%s: CPU has no performance counters %d\n", - __func__, idx); - } - } -} - -static int nds32_pmu_get_event_idx(struct pmu_hw_events *cpuc, - struct perf_event *event) -{ - int idx; - struct hw_perf_event *hwc = &event->hw; - /* - * Current implementation maps cycles, instruction count and cache-miss - * to specific counter. - * However, multiple of the 3 counters are able to count these events. - * - * - * SOFTWARE_EVENT_MASK mask for getting event num , - * This is defined by Jia-Rung, you can change the polocies. - * However, do not exceed 8 bits. This is hardware specific. - * The last number is SPAv3_2_SEL_LAST. - */ - unsigned long evtype = hwc->config_base & SOFTWARE_EVENT_MASK; - - idx = get_converted_event_idx(evtype); - /* - * Try to get the counter for correpsonding event - */ - if (evtype == SPAV3_0_SEL_TOTAL_CYCLES) { - if (!test_and_set_bit(idx, cpuc->used_mask)) - return idx; - if (!test_and_set_bit(NDS32_IDX_COUNTER0, cpuc->used_mask)) - return NDS32_IDX_COUNTER0; - if (!test_and_set_bit(NDS32_IDX_COUNTER1, cpuc->used_mask)) - return NDS32_IDX_COUNTER1; - } else if (evtype == SPAV3_1_SEL_COMPLETED_INSTRUCTION) { - if (!test_and_set_bit(idx, cpuc->used_mask)) - return idx; - else if (!test_and_set_bit(NDS32_IDX_COUNTER1, cpuc->used_mask)) - return NDS32_IDX_COUNTER1; - else if (!test_and_set_bit - (NDS32_IDX_CYCLE_COUNTER, cpuc->used_mask)) - return NDS32_IDX_CYCLE_COUNTER; - } else { - if (!test_and_set_bit(idx, cpuc->used_mask)) - return idx; - } - return -EAGAIN; -} - -static void nds32_pmu_start(struct nds32_pmu *cpu_pmu) -{ - unsigned long flags; - unsigned int val; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); - - raw_spin_lock_irqsave(&events->pmu_lock, flags); - - /* Enable all counters , NDS PFM has 3 counters */ - val = __nds32__mfsr(NDS32_SR_PFM_CTL); - val |= (PFM_CTL_EN[0] | PFM_CTL_EN[1] | PFM_CTL_EN[2]); - val &= ~(PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]); - __nds32__mtsr_isb(val, NDS32_SR_PFM_CTL); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); -} - -static void nds32_pmu_stop(struct nds32_pmu *cpu_pmu) -{ - unsigned long flags; - unsigned int val; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); - - raw_spin_lock_irqsave(&events->pmu_lock, flags); - - /* Disable all counters , NDS PFM has 3 counters */ - val = __nds32__mfsr(NDS32_SR_PFM_CTL); - val &= ~(PFM_CTL_EN[0] | PFM_CTL_EN[1] | PFM_CTL_EN[2]); - val &= ~(PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]); - __nds32__mtsr_isb(val, NDS32_SR_PFM_CTL); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); -} - -static void nds32_pmu_reset(void *info) -{ - u32 val = 0; - - val |= (PFM_CTL_OVF[0] | PFM_CTL_OVF[1] | PFM_CTL_OVF[2]); - __nds32__mtsr(val, NDS32_SR_PFM_CTL); - __nds32__mtsr(0, NDS32_SR_PFM_CTL); - __nds32__mtsr(0, NDS32_SR_PFMC0); - __nds32__mtsr(0, NDS32_SR_PFMC1); - __nds32__mtsr(0, NDS32_SR_PFMC2); -} - -static void nds32_pmu_init(struct nds32_pmu *cpu_pmu) -{ - cpu_pmu->handle_irq = nds32_pmu_handle_irq; - cpu_pmu->enable = nds32_pmu_enable_event; - cpu_pmu->disable = nds32_pmu_disable_event; - cpu_pmu->read_counter = nds32_pmu_read_counter; - cpu_pmu->write_counter = nds32_pmu_write_counter; - cpu_pmu->get_event_idx = nds32_pmu_get_event_idx; - cpu_pmu->start = nds32_pmu_start; - cpu_pmu->stop = nds32_pmu_stop; - cpu_pmu->reset = nds32_pmu_reset; - cpu_pmu->max_period = 0xFFFFFFFF; /* Maximum counts */ -}; - -static u32 nds32_read_num_pfm_events(void) -{ - /* NDS32 SPAv3 PMU support 3 counter */ - return 3; -} - -static int device_pmu_init(struct nds32_pmu *cpu_pmu) -{ - nds32_pmu_init(cpu_pmu); - /* - * This name should be devive-specific name, whatever you like :) - * I think "PMU" will be a good generic name. - */ - cpu_pmu->name = "nds32v3-pmu"; - cpu_pmu->map_event = nds32_spav3_map_event; - cpu_pmu->num_events = nds32_read_num_pfm_events(); - cpu_pmu->set_event_filter = nds32_pmu_set_event_filter; - return 0; -} - -/* - * CPU PMU identification and probing. - */ -static int probe_current_pmu(struct nds32_pmu *pmu) -{ - int ret; - - get_cpu(); - ret = -ENODEV; - /* - * If ther are various CPU types with its own PMU, initialize with - * - * the corresponding one - */ - device_pmu_init(pmu); - put_cpu(); - return ret; -} - -static void nds32_pmu_enable(struct pmu *pmu) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(pmu); - struct pmu_hw_events *hw_events = nds32_pmu->get_hw_events(); - int enabled = bitmap_weight(hw_events->used_mask, - nds32_pmu->num_events); - - if (enabled) - nds32_pmu->start(nds32_pmu); -} - -static void nds32_pmu_disable(struct pmu *pmu) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(pmu); - - nds32_pmu->stop(nds32_pmu); -} - -static void nds32_pmu_release_hardware(struct nds32_pmu *nds32_pmu) -{ - nds32_pmu->free_irq(nds32_pmu); - pm_runtime_put_sync(&nds32_pmu->plat_device->dev); -} - -static irqreturn_t nds32_pmu_dispatch_irq(int irq, void *dev) -{ - struct nds32_pmu *nds32_pmu = (struct nds32_pmu *)dev; - int ret; - u64 start_clock, finish_clock; - - start_clock = local_clock(); - ret = nds32_pmu->handle_irq(irq, dev); - finish_clock = local_clock(); - - perf_sample_event_took(finish_clock - start_clock); - return ret; -} - -static int nds32_pmu_reserve_hardware(struct nds32_pmu *nds32_pmu) -{ - int err; - struct platform_device *pmu_device = nds32_pmu->plat_device; - - if (!pmu_device) - return -ENODEV; - - pm_runtime_get_sync(&pmu_device->dev); - err = nds32_pmu->request_irq(nds32_pmu, nds32_pmu_dispatch_irq); - if (err) { - nds32_pmu_release_hardware(nds32_pmu); - return err; - } - - return 0; -} - -static int -validate_event(struct pmu *pmu, struct pmu_hw_events *hw_events, - struct perf_event *event) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(event->pmu); - - if (is_software_event(event)) - return 1; - - if (event->pmu != pmu) - return 0; - - if (event->state < PERF_EVENT_STATE_OFF) - return 1; - - if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec) - return 1; - - return nds32_pmu->get_event_idx(hw_events, event) >= 0; -} - -static int validate_group(struct perf_event *event) -{ - struct perf_event *sibling, *leader = event->group_leader; - struct pmu_hw_events fake_pmu; - DECLARE_BITMAP(fake_used_mask, MAX_COUNTERS); - /* - * Initialize the fake PMU. We only need to populate the - * used_mask for the purposes of validation. - */ - memset(fake_used_mask, 0, sizeof(fake_used_mask)); - - if (!validate_event(event->pmu, &fake_pmu, leader)) - return -EINVAL; - - for_each_sibling_event(sibling, leader) { - if (!validate_event(event->pmu, &fake_pmu, sibling)) - return -EINVAL; - } - - if (!validate_event(event->pmu, &fake_pmu, event)) - return -EINVAL; - - return 0; -} - -static int __hw_perf_event_init(struct perf_event *event) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - int mapping; - - mapping = nds32_pmu->map_event(event); - - if (mapping < 0) { - pr_debug("event %x:%llx not supported\n", event->attr.type, - event->attr.config); - return mapping; - } - - /* - * We don't assign an index until we actually place the event onto - * hardware. Use -1 to signify that we haven't decided where to put it - * yet. For SMP systems, each core has it's own PMU so we can't do any - * clever allocation or constraints checking at this point. - */ - hwc->idx = -1; - hwc->config_base = 0; - hwc->config = 0; - hwc->event_base = 0; - - /* - * Check whether we need to exclude the counter from certain modes. - */ - if ((!nds32_pmu->set_event_filter || - nds32_pmu->set_event_filter(hwc, &event->attr)) && - event_requires_mode_exclusion(&event->attr)) { - pr_debug - ("NDS performance counters do not support mode exclusion\n"); - return -EOPNOTSUPP; - } - - /* - * Store the event encoding into the config_base field. - */ - hwc->config_base |= (unsigned long)mapping; - - if (!hwc->sample_period) { - /* - * For non-sampling runs, limit the sample_period to half - * of the counter width. That way, the new counter value - * is far less likely to overtake the previous one unless - * you have some serious IRQ latency issues. - */ - hwc->sample_period = nds32_pmu->max_period >> 1; - hwc->last_period = hwc->sample_period; - local64_set(&hwc->period_left, hwc->sample_period); - } - - if (event->group_leader != event) { - if (validate_group(event) != 0) - return -EINVAL; - } - - return 0; -} - -static int nds32_pmu_event_init(struct perf_event *event) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(event->pmu); - int err = 0; - atomic_t *active_events = &nds32_pmu->active_events; - - /* does not support taken branch sampling */ - if (has_branch_stack(event)) - return -EOPNOTSUPP; - - if (nds32_pmu->map_event(event) == -ENOENT) - return -ENOENT; - - if (!atomic_inc_not_zero(active_events)) { - if (atomic_read(active_events) == 0) { - /* Register irq handler */ - err = nds32_pmu_reserve_hardware(nds32_pmu); - } - - if (!err) - atomic_inc(active_events); - } - - if (err) - return err; - - err = __hw_perf_event_init(event); - - return err; -} - -static void nds32_start(struct perf_event *event, int flags) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - /* - * NDS pmu always has to reprogram the period, so ignore - * PERF_EF_RELOAD, see the comment below. - */ - if (flags & PERF_EF_RELOAD) - WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); - - hwc->state = 0; - /* Set the period for the event. */ - nds32_pmu_event_set_period(event); - - nds32_pmu->enable(event); -} - -static int nds32_pmu_add(struct perf_event *event, int flags) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(event->pmu); - struct pmu_hw_events *hw_events = nds32_pmu->get_hw_events(); - struct hw_perf_event *hwc = &event->hw; - int idx; - int err = 0; - - perf_pmu_disable(event->pmu); - - /* If we don't have a space for the counter then finish early. */ - idx = nds32_pmu->get_event_idx(hw_events, event); - if (idx < 0) { - err = idx; - goto out; - } - - /* - * If there is an event in the counter we are going to use then make - * sure it is disabled. - */ - event->hw.idx = idx; - nds32_pmu->disable(event); - hw_events->events[idx] = event; - - hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; - if (flags & PERF_EF_START) - nds32_start(event, PERF_EF_RELOAD); - - /* Propagate our changes to the userspace mapping. */ - perf_event_update_userpage(event); - -out: - perf_pmu_enable(event->pmu); - return err; -} - -u64 nds32_pmu_event_update(struct perf_event *event) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - u64 delta, prev_raw_count, new_raw_count; - -again: - prev_raw_count = local64_read(&hwc->prev_count); - new_raw_count = nds32_pmu->read_counter(event); - - if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, - new_raw_count) != prev_raw_count) { - goto again; - } - /* - * Whether overflow or not, "unsigned substraction" - * will always get their delta - */ - delta = (new_raw_count - prev_raw_count) & nds32_pmu->max_period; - - local64_add(delta, &event->count); - local64_sub(delta, &hwc->period_left); - - return new_raw_count; -} - -static void nds32_stop(struct perf_event *event, int flags) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - /* - * NDS pmu always has to update the counter, so ignore - * PERF_EF_UPDATE, see comments in nds32_start(). - */ - if (!(hwc->state & PERF_HES_STOPPED)) { - nds32_pmu->disable(event); - nds32_pmu_event_update(event); - hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; - } -} - -static void nds32_pmu_del(struct perf_event *event, int flags) -{ - struct nds32_pmu *nds32_pmu = to_nds32_pmu(event->pmu); - struct pmu_hw_events *hw_events = nds32_pmu->get_hw_events(); - struct hw_perf_event *hwc = &event->hw; - int idx = hwc->idx; - - nds32_stop(event, PERF_EF_UPDATE); - hw_events->events[idx] = NULL; - clear_bit(idx, hw_events->used_mask); - - perf_event_update_userpage(event); -} - -static void nds32_pmu_read(struct perf_event *event) -{ - nds32_pmu_event_update(event); -} - -/* Please refer to SPAv3 for more hardware specific details */ -PMU_FORMAT_ATTR(event, "config:0-63"); - -static struct attribute *nds32_arch_formats_attr[] = { - &format_attr_event.attr, - NULL, -}; - -static struct attribute_group nds32_pmu_format_group = { - .name = "format", - .attrs = nds32_arch_formats_attr, -}; - -static ssize_t nds32_pmu_cpumask_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return 0; -} - -static DEVICE_ATTR(cpus, 0444, nds32_pmu_cpumask_show, NULL); - -static struct attribute *nds32_pmu_common_attrs[] = { - &dev_attr_cpus.attr, - NULL, -}; - -static struct attribute_group nds32_pmu_common_group = { - .attrs = nds32_pmu_common_attrs, -}; - -static const struct attribute_group *nds32_pmu_attr_groups[] = { - &nds32_pmu_format_group, - &nds32_pmu_common_group, - NULL, -}; - -static void nds32_init(struct nds32_pmu *nds32_pmu) -{ - atomic_set(&nds32_pmu->active_events, 0); - - nds32_pmu->pmu = (struct pmu) { - .pmu_enable = nds32_pmu_enable, - .pmu_disable = nds32_pmu_disable, - .attr_groups = nds32_pmu_attr_groups, - .event_init = nds32_pmu_event_init, - .add = nds32_pmu_add, - .del = nds32_pmu_del, - .start = nds32_start, - .stop = nds32_stop, - .read = nds32_pmu_read, - }; -} - -int nds32_pmu_register(struct nds32_pmu *nds32_pmu, int type) -{ - nds32_init(nds32_pmu); - pm_runtime_enable(&nds32_pmu->plat_device->dev); - pr_info("enabled with %s PMU driver, %d counters available\n", - nds32_pmu->name, nds32_pmu->num_events); - return perf_pmu_register(&nds32_pmu->pmu, nds32_pmu->name, type); -} - -static struct pmu_hw_events *cpu_pmu_get_cpu_events(void) -{ - return this_cpu_ptr(&cpu_hw_events); -} - -static int cpu_pmu_request_irq(struct nds32_pmu *cpu_pmu, irq_handler_t handler) -{ - int err, irq, irqs; - struct platform_device *pmu_device = cpu_pmu->plat_device; - - if (!pmu_device) - return -ENODEV; - - irqs = min(pmu_device->num_resources, num_possible_cpus()); - if (irqs < 1) { - pr_err("no irqs for PMUs defined\n"); - return -ENODEV; - } - - irq = platform_get_irq(pmu_device, 0); - err = request_irq(irq, handler, IRQF_NOBALANCING, "nds32-pfm", - cpu_pmu); - if (err) { - pr_err("unable to request IRQ%d for NDS PMU counters\n", - irq); - return err; - } - return 0; -} - -static void cpu_pmu_free_irq(struct nds32_pmu *cpu_pmu) -{ - int irq; - struct platform_device *pmu_device = cpu_pmu->plat_device; - - irq = platform_get_irq(pmu_device, 0); - if (irq >= 0) - free_irq(irq, cpu_pmu); -} - -static void cpu_pmu_init(struct nds32_pmu *cpu_pmu) -{ - int cpu; - struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu); - - raw_spin_lock_init(&events->pmu_lock); - - cpu_pmu->get_hw_events = cpu_pmu_get_cpu_events; - cpu_pmu->request_irq = cpu_pmu_request_irq; - cpu_pmu->free_irq = cpu_pmu_free_irq; - - /* Ensure the PMU has sane values out of reset. */ - if (cpu_pmu->reset) - on_each_cpu(cpu_pmu->reset, cpu_pmu, 1); -} - -static const struct of_device_id cpu_pmu_of_device_ids[] = { - {.compatible = "andestech,nds32v3-pmu", - .data = device_pmu_init}, - {}, -}; - -static int cpu_pmu_device_probe(struct platform_device *pdev) -{ - const struct of_device_id *of_id; - int (*init_fn)(struct nds32_pmu *nds32_pmu); - struct device_node *node = pdev->dev.of_node; - struct nds32_pmu *pmu; - int ret = -ENODEV; - - if (cpu_pmu) { - pr_notice("[perf] attempt to register multiple PMU devices!\n"); - return -ENOSPC; - } - - pmu = kzalloc(sizeof(*pmu), GFP_KERNEL); - if (!pmu) - return -ENOMEM; - - of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node); - if (node && of_id) { - init_fn = of_id->data; - ret = init_fn(pmu); - } else { - ret = probe_current_pmu(pmu); - } - - if (ret) { - pr_notice("[perf] failed to probe PMU!\n"); - goto out_free; - } - - cpu_pmu = pmu; - cpu_pmu->plat_device = pdev; - cpu_pmu_init(cpu_pmu); - ret = nds32_pmu_register(cpu_pmu, PERF_TYPE_RAW); - - if (!ret) - return 0; - -out_free: - pr_notice("[perf] failed to register PMU devices!\n"); - kfree(pmu); - return ret; -} - -static struct platform_driver cpu_pmu_driver = { - .driver = { - .name = "nds32-pfm", - .of_match_table = cpu_pmu_of_device_ids, - }, - .probe = cpu_pmu_device_probe, - .id_table = cpu_pmu_plat_device_ids, -}; - -static int __init register_pmu_driver(void) -{ - int err = 0; - - err = platform_driver_register(&cpu_pmu_driver); - if (err) - pr_notice("[perf] PMU initialization failed\n"); - else - pr_notice("[perf] PMU initialization done\n"); - - return err; -} - -device_initcall(register_pmu_driver); - -/* - * References: arch/nds32/kernel/traps.c:__dump() - * You will need to know the NDS ABI first. - */ -static int unwind_frame_kernel(struct stackframe *frame) -{ - int graph = 0; -#ifdef CONFIG_FRAME_POINTER - /* 0x3 means misalignment */ - if (!kstack_end((void *)frame->fp) && - !((unsigned long)frame->fp & 0x3) && - ((unsigned long)frame->fp >= TASK_SIZE)) { - /* - * The array index is based on the ABI, the below graph - * illustrate the reasons. - * Function call procedure: "smw" and "lmw" will always - * update SP and FP for you automatically. - * - * Stack Relative Address - * | | 0 - * ---- - * |LP| <-- SP(before smw) <-- FP(after smw) -1 - * ---- - * |FP| -2 - * ---- - * | | <-- SP(after smw) -3 - */ - frame->lp = ((unsigned long *)frame->fp)[-1]; - frame->fp = ((unsigned long *)frame->fp)[FP_OFFSET]; - /* make sure CONFIG_FUNCTION_GRAPH_TRACER is turned on */ - if (__kernel_text_address(frame->lp)) - frame->lp = ftrace_graph_ret_addr - (NULL, &graph, frame->lp, NULL); - - return 0; - } else { - return -EPERM; - } -#else - /* - * You can refer to arch/nds32/kernel/traps.c:__dump() - * Treat "sp" as "fp", but the "sp" is one frame ahead of "fp". - * And, the "sp" is not always correct. - * - * Stack Relative Address - * | | 0 - * ---- - * |LP| <-- SP(before smw) -1 - * ---- - * | | <-- SP(after smw) -2 - * ---- - */ - if (!kstack_end((void *)frame->sp)) { - frame->lp = ((unsigned long *)frame->sp)[1]; - /* TODO: How to deal with the value in first - * "sp" is not correct? - */ - if (__kernel_text_address(frame->lp)) - frame->lp = ftrace_graph_ret_addr - (tsk, &graph, frame->lp, NULL); - - frame->sp = ((unsigned long *)frame->sp) + 1; - - return 0; - } else { - return -EPERM; - } -#endif -} - -static void notrace -walk_stackframe(struct stackframe *frame, - int (*fn_record)(struct stackframe *, void *), - void *data) -{ - while (1) { - int ret; - - if (fn_record(frame, data)) - break; - - ret = unwind_frame_kernel(frame); - if (ret < 0) - break; - } -} - -/* - * Gets called by walk_stackframe() for every stackframe. This will be called - * whist unwinding the stackframe and is like a subroutine return so we use - * the PC. - */ -static int callchain_trace(struct stackframe *fr, void *data) -{ - struct perf_callchain_entry_ctx *entry = data; - - perf_callchain_store(entry, fr->lp); - return 0; -} - -/* - * Get the return address for a single stackframe and return a pointer to the - * next frame tail. - */ -static unsigned long -user_backtrace(struct perf_callchain_entry_ctx *entry, unsigned long fp) -{ - struct frame_tail buftail; - unsigned long lp = 0; - unsigned long *user_frame_tail = - (unsigned long *)(fp - (unsigned long)sizeof(buftail)); - - /* Check accessibility of one struct frame_tail beyond */ - if (!access_ok(user_frame_tail, sizeof(buftail))) - return 0; - if (__copy_from_user_inatomic - (&buftail, user_frame_tail, sizeof(buftail))) - return 0; - - /* - * Refer to unwind_frame_kernel() for more illurstration - */ - lp = buftail.stack_lp; /* ((unsigned long *)fp)[-1] */ - fp = buftail.stack_fp; /* ((unsigned long *)fp)[FP_OFFSET] */ - perf_callchain_store(entry, lp); - return fp; -} - -static unsigned long -user_backtrace_opt_size(struct perf_callchain_entry_ctx *entry, - unsigned long fp) -{ - struct frame_tail_opt_size buftail; - unsigned long lp = 0; - - unsigned long *user_frame_tail = - (unsigned long *)(fp - (unsigned long)sizeof(buftail)); - - /* Check accessibility of one struct frame_tail beyond */ - if (!access_ok(user_frame_tail, sizeof(buftail))) - return 0; - if (__copy_from_user_inatomic - (&buftail, user_frame_tail, sizeof(buftail))) - return 0; - - /* - * Refer to unwind_frame_kernel() for more illurstration - */ - lp = buftail.stack_lp; /* ((unsigned long *)fp)[-1] */ - fp = buftail.stack_fp; /* ((unsigned long *)fp)[FP_OFFSET] */ - - perf_callchain_store(entry, lp); - return fp; -} - -/* - * This will be called when the target is in user mode - * This function will only be called when we use - * "PERF_SAMPLE_CALLCHAIN" in - * kernel/events/core.c:perf_prepare_sample() - * - * How to trigger perf_callchain_[user/kernel] : - * $ perf record -e cpu-clock --call-graph fp ./program - * $ perf report --call-graph - */ -unsigned long leaf_fp; -void -perf_callchain_user(struct perf_callchain_entry_ctx *entry, - struct pt_regs *regs) -{ - unsigned long fp = 0; - unsigned long gp = 0; - unsigned long lp = 0; - unsigned long sp = 0; - unsigned long *user_frame_tail; - - leaf_fp = 0; - - perf_callchain_store(entry, regs->ipc); - fp = regs->fp; - gp = regs->gp; - lp = regs->lp; - sp = regs->sp; - if (entry->nr < PERF_MAX_STACK_DEPTH && - (unsigned long)fp && !((unsigned long)fp & 0x7) && fp > sp) { - user_frame_tail = - (unsigned long *)(fp - (unsigned long)sizeof(fp)); - - if (!access_ok(user_frame_tail, sizeof(fp))) - return; - - if (__copy_from_user_inatomic - (&leaf_fp, user_frame_tail, sizeof(fp))) - return; - - if (leaf_fp == lp) { - /* - * Maybe this is non leaf function - * with optimize for size, - * or maybe this is the function - * with optimize for size - */ - struct frame_tail buftail; - - user_frame_tail = - (unsigned long *)(fp - - (unsigned long)sizeof(buftail)); - - if (!access_ok(user_frame_tail, sizeof(buftail))) - return; - - if (__copy_from_user_inatomic - (&buftail, user_frame_tail, sizeof(buftail))) - return; - - if (buftail.stack_fp == gp) { - /* non leaf function with optimize - * for size condition - */ - struct frame_tail_opt_size buftail_opt_size; - - user_frame_tail = - (unsigned long *)(fp - (unsigned long) - sizeof(buftail_opt_size)); - - if (!access_ok(user_frame_tail, - sizeof(buftail_opt_size))) - return; - - if (__copy_from_user_inatomic - (&buftail_opt_size, user_frame_tail, - sizeof(buftail_opt_size))) - return; - - perf_callchain_store(entry, lp); - fp = buftail_opt_size.stack_fp; - - while ((entry->nr < PERF_MAX_STACK_DEPTH) && - (unsigned long)fp && - !((unsigned long)fp & 0x7) && - fp > sp) { - sp = fp; - fp = user_backtrace_opt_size(entry, fp); - } - - } else { - /* this is the function - * without optimize for size - */ - fp = buftail.stack_fp; - perf_callchain_store(entry, lp); - while ((entry->nr < PERF_MAX_STACK_DEPTH) && - (unsigned long)fp && - !((unsigned long)fp & 0x7) && - fp > sp) { - sp = fp; - fp = user_backtrace(entry, fp); - } - } - } else { - /* this is leaf function */ - fp = leaf_fp; - perf_callchain_store(entry, lp); - - /* previous function callcahin */ - while ((entry->nr < PERF_MAX_STACK_DEPTH) && - (unsigned long)fp && - !((unsigned long)fp & 0x7) && fp > sp) { - sp = fp; - fp = user_backtrace(entry, fp); - } - } - return; - } -} - -/* This will be called when the target is in kernel mode */ -void -perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, - struct pt_regs *regs) -{ - struct stackframe fr; - - fr.fp = regs->fp; - fr.lp = regs->lp; - fr.sp = regs->sp; - walk_stackframe(&fr, callchain_trace, entry); -} - -unsigned long perf_instruction_pointer(struct pt_regs *regs) -{ - return instruction_pointer(regs); -} - -unsigned long perf_misc_flags(struct pt_regs *regs) -{ - int misc = 0; - - if (user_mode(regs)) - misc |= PERF_RECORD_MISC_USER; - else - misc |= PERF_RECORD_MISC_KERNEL; - - return misc; -} diff --git a/arch/nds32/kernel/pm.c b/arch/nds32/kernel/pm.c deleted file mode 100644 index e25700e125d8..000000000000 --- a/arch/nds32/kernel/pm.c +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2008-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include - -unsigned int resume_addr; -unsigned int *phy_addr_sp_tmp; - -static void nds32_suspend2ram(void) -{ - pgd_t *pgdv; - p4d_t *p4dv; - pud_t *pudv; - pmd_t *pmdv; - pte_t *ptev; - - pgdv = (pgd_t *)__va((__nds32__mfsr(NDS32_SR_L1_PPTB) & - L1_PPTB_mskBASE)) + pgd_index((unsigned int)cpu_resume); - - p4dv = p4d_offset(pgdv, (unsigned int)cpu_resume); - pudv = pud_offset(p4dv, (unsigned int)cpu_resume); - pmdv = pmd_offset(pudv, (unsigned int)cpu_resume); - ptev = pte_offset_map(pmdv, (unsigned int)cpu_resume); - - resume_addr = ((*ptev) & TLB_DATA_mskPPN) - | ((unsigned int)cpu_resume & 0x00000fff); - - suspend2ram(); -} - -static void nds32_suspend_cpu(void) -{ - while (!(__nds32__mfsr(NDS32_SR_INT_PEND) & wake_mask)) - __asm__ volatile ("standby no_wake_grant\n\t"); -} - -static int nds32_pm_valid(suspend_state_t state) -{ - switch (state) { - case PM_SUSPEND_ON: - case PM_SUSPEND_STANDBY: - case PM_SUSPEND_MEM: - return 1; - default: - return 0; - } -} - -static int nds32_pm_enter(suspend_state_t state) -{ - pr_debug("%s:state:%d\n", __func__, state); - switch (state) { - case PM_SUSPEND_STANDBY: - nds32_suspend_cpu(); - return 0; - case PM_SUSPEND_MEM: - nds32_suspend2ram(); - return 0; - default: - return -EINVAL; - } -} - -static const struct platform_suspend_ops nds32_pm_ops = { - .valid = nds32_pm_valid, - .enter = nds32_pm_enter, -}; - -static int __init nds32_pm_init(void) -{ - pr_debug("Enter %s\n", __func__); - suspend_set_ops(&nds32_pm_ops); - return 0; -} -late_initcall(nds32_pm_init); diff --git a/arch/nds32/kernel/process.c b/arch/nds32/kernel/process.c deleted file mode 100644 index d35c1f63fa11..000000000000 --- a/arch/nds32/kernel/process.c +++ /dev/null @@ -1,256 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if IS_ENABLED(CONFIG_LAZY_FPU) -struct task_struct *last_task_used_math; -#endif - -extern void setup_mm_for_reboot(char mode); - -extern inline void arch_reset(char mode) -{ - if (mode == 's') { - /* Use cpu handler, jump to 0 */ - cpu_reset(0); - } -} - -void (*pm_power_off) (void); -EXPORT_SYMBOL(pm_power_off); - -static char reboot_mode_nds32 = 'h'; - -int __init reboot_setup(char *str) -{ - reboot_mode_nds32 = str[0]; - return 1; -} - -static int cpub_pwroff(void) -{ - return 0; -} - -__setup("reboot=", reboot_setup); - -void machine_halt(void) -{ - cpub_pwroff(); -} - -EXPORT_SYMBOL(machine_halt); - -void machine_power_off(void) -{ - if (pm_power_off) - pm_power_off(); -} - -EXPORT_SYMBOL(machine_power_off); - -void machine_restart(char *cmd) -{ - /* - * Clean and disable cache, and turn off interrupts - */ - cpu_proc_fin(); - - /* - * Tell the mm system that we are going to reboot - - * we may need it to insert some 1:1 mappings so that - * soft boot works. - */ - setup_mm_for_reboot(reboot_mode_nds32); - - /* Execute kernel restart handler call chain */ - do_kernel_restart(cmd); - - /* - * Now call the architecture specific reboot code. - */ - arch_reset(reboot_mode_nds32); - - /* - * Whoops - the architecture was unable to reboot. - * Tell the user! - */ - mdelay(1000); - pr_info("Reboot failed -- System halted\n"); - while (1) ; -} - -EXPORT_SYMBOL(machine_restart); - -void show_regs(struct pt_regs *regs) -{ - printk("PC is at %pS\n", (void *)instruction_pointer(regs)); - printk("LP is at %pS\n", (void *)regs->lp); - pr_info("pc : [<%08lx>] lp : [<%08lx>] %s\n" - "sp : %08lx fp : %08lx gp : %08lx\n", - instruction_pointer(regs), - regs->lp, print_tainted(), regs->sp, regs->fp, regs->gp); - pr_info("r25: %08lx r24: %08lx\n", regs->uregs[25], regs->uregs[24]); - - pr_info("r23: %08lx r22: %08lx r21: %08lx r20: %08lx\n", - regs->uregs[23], regs->uregs[22], - regs->uregs[21], regs->uregs[20]); - pr_info("r19: %08lx r18: %08lx r17: %08lx r16: %08lx\n", - regs->uregs[19], regs->uregs[18], - regs->uregs[17], regs->uregs[16]); - pr_info("r15: %08lx r14: %08lx r13: %08lx r12: %08lx\n", - regs->uregs[15], regs->uregs[14], - regs->uregs[13], regs->uregs[12]); - pr_info("r11: %08lx r10: %08lx r9 : %08lx r8 : %08lx\n", - regs->uregs[11], regs->uregs[10], - regs->uregs[9], regs->uregs[8]); - pr_info("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", - regs->uregs[7], regs->uregs[6], regs->uregs[5], regs->uregs[4]); - pr_info("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", - regs->uregs[3], regs->uregs[2], regs->uregs[1], regs->uregs[0]); - pr_info(" IRQs o%s Segment user\n", - interrupts_enabled(regs) ? "n" : "ff"); -} - -EXPORT_SYMBOL(show_regs); - -void exit_thread(struct task_struct *tsk) -{ -#if defined(CONFIG_FPU) && defined(CONFIG_LAZY_FPU) - if (last_task_used_math == tsk) - last_task_used_math = NULL; -#endif -} - -void flush_thread(void) -{ -#if defined(CONFIG_FPU) - clear_fpu(task_pt_regs(current)); - clear_used_math(); -# ifdef CONFIG_LAZY_FPU - if (last_task_used_math == current) - last_task_used_math = NULL; -# endif -#endif -} - -DEFINE_PER_CPU(struct task_struct *, __entry_task); - -asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); -int copy_thread(unsigned long clone_flags, unsigned long stack_start, - unsigned long stk_sz, struct task_struct *p, unsigned long tls) -{ - struct pt_regs *childregs = task_pt_regs(p); - - memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); - - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { - memset(childregs, 0, sizeof(struct pt_regs)); - /* kernel thread fn */ - p->thread.cpu_context.r6 = stack_start; - /* kernel thread argument */ - p->thread.cpu_context.r7 = stk_sz; - } else { - *childregs = *current_pt_regs(); - if (stack_start) - childregs->sp = stack_start; - /* child get zero as ret. */ - childregs->uregs[0] = 0; - childregs->osp = 0; - if (clone_flags & CLONE_SETTLS) - childregs->uregs[25] = tls; - } - /* cpu context switching */ - p->thread.cpu_context.pc = (unsigned long)ret_from_fork; - p->thread.cpu_context.sp = (unsigned long)childregs; - -#if IS_ENABLED(CONFIG_FPU) - if (used_math()) { -# if !IS_ENABLED(CONFIG_LAZY_FPU) - unlazy_fpu(current); -# else - preempt_disable(); - if (last_task_used_math == current) - save_fpu(current); - preempt_enable(); -# endif - p->thread.fpu = current->thread.fpu; - clear_fpu(task_pt_regs(p)); - set_stopped_child_used_math(p); - } -#endif - -#ifdef CONFIG_HWZOL - childregs->lb = 0; - childregs->le = 0; - childregs->lc = 0; -#endif - - return 0; -} - -#if IS_ENABLED(CONFIG_FPU) -struct task_struct *_switch_fpu(struct task_struct *prev, struct task_struct *next) -{ -#if !IS_ENABLED(CONFIG_LAZY_FPU) - unlazy_fpu(prev); -#endif - if (!(next->flags & PF_KTHREAD)) - clear_fpu(task_pt_regs(next)); - return prev; -} -#endif - -/* - * fill in the fpe structure for a core dump... - */ -int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu) -{ - int fpvalid = 0; -#if IS_ENABLED(CONFIG_FPU) - struct task_struct *tsk = current; - - fpvalid = tsk_used_math(tsk); - if (fpvalid) { - lose_fpu(); - memcpy(fpu, &tsk->thread.fpu, sizeof(*fpu)); - } -#endif - return fpvalid; -} - -EXPORT_SYMBOL(dump_fpu); - -unsigned long __get_wchan(struct task_struct *p) -{ - unsigned long fp, lr; - unsigned long stack_start, stack_end; - int count = 0; - - if (IS_ENABLED(CONFIG_FRAME_POINTER)) { - stack_start = (unsigned long)end_of_stack(p); - stack_end = (unsigned long)task_stack_page(p) + THREAD_SIZE; - - fp = thread_saved_fp(p); - do { - if (fp < stack_start || fp > stack_end) - return 0; - lr = ((unsigned long *)fp)[0]; - if (!in_sched_functions(lr)) - return lr; - fp = *(unsigned long *)(fp + 4); - } while (count++ < 16); - } - return 0; -} diff --git a/arch/nds32/kernel/ptrace.c b/arch/nds32/kernel/ptrace.c deleted file mode 100644 index d0eda870fbc2..000000000000 --- a/arch/nds32/kernel/ptrace.c +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include - -enum nds32_regset { - REGSET_GPR, -}; - -static int gpr_get(struct task_struct *target, - const struct user_regset *regset, - struct membuf to) -{ - return membuf_write(&to, &task_pt_regs(target)->user_regs, - sizeof(struct user_pt_regs)); -} - -static int gpr_set(struct task_struct *target, const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user * ubuf) -{ - int err; - struct user_pt_regs newregs = task_pt_regs(target)->user_regs; - - err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1); - if (err) - return err; - - task_pt_regs(target)->user_regs = newregs; - return 0; -} - -static const struct user_regset nds32_regsets[] = { - [REGSET_GPR] = { - .core_note_type = NT_PRSTATUS, - .n = sizeof(struct user_pt_regs) / sizeof(u32), - .size = sizeof(elf_greg_t), - .align = sizeof(elf_greg_t), - .regset_get = gpr_get, - .set = gpr_set} -}; - -static const struct user_regset_view nds32_user_view = { - .name = "nds32", - .e_machine = EM_NDS32, - .regsets = nds32_regsets, - .n = ARRAY_SIZE(nds32_regsets) -}; - -const struct user_regset_view *task_user_regset_view(struct task_struct *task) -{ - return &nds32_user_view; -} - -void ptrace_disable(struct task_struct *child) -{ - user_disable_single_step(child); -} - -/* do_ptrace() - * - * Provide ptrace defined service. - */ -long arch_ptrace(struct task_struct *child, long request, unsigned long addr, - unsigned long data) -{ - int ret = -EIO; - - switch (request) { - default: - ret = ptrace_request(child, request, addr, data); - break; - } - - return ret; -} - -void user_enable_single_step(struct task_struct *child) -{ - struct pt_regs *regs; - regs = task_pt_regs(child); - regs->ipsw |= PSW_mskHSS; - set_tsk_thread_flag(child, TIF_SINGLESTEP); -} - -void user_disable_single_step(struct task_struct *child) -{ - struct pt_regs *regs; - regs = task_pt_regs(child); - regs->ipsw &= ~PSW_mskHSS; - clear_tsk_thread_flag(child, TIF_SINGLESTEP); -} - -/* sys_trace() - * - * syscall trace handler. - */ - -asmlinkage int syscall_trace_enter(struct pt_regs *regs) -{ - if (test_thread_flag(TIF_SYSCALL_TRACE)) { - if (tracehook_report_syscall_entry(regs)) - forget_syscall(regs); - } - return regs->syscallno; -} - -asmlinkage void syscall_trace_leave(struct pt_regs *regs) -{ - int step = test_thread_flag(TIF_SINGLESTEP); - if (step || test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(regs, step); - -} diff --git a/arch/nds32/kernel/setup.c b/arch/nds32/kernel/setup.c deleted file mode 100644 index b3d34d646652..000000000000 --- a/arch/nds32/kernel/setup.c +++ /dev/null @@ -1,369 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HWCAP_MFUSR_PC 0x000001 -#define HWCAP_EXT 0x000002 -#define HWCAP_EXT2 0x000004 -#define HWCAP_FPU 0x000008 -#define HWCAP_AUDIO 0x000010 -#define HWCAP_BASE16 0x000020 -#define HWCAP_STRING 0x000040 -#define HWCAP_REDUCED_REGS 0x000080 -#define HWCAP_VIDEO 0x000100 -#define HWCAP_ENCRYPT 0x000200 -#define HWCAP_EDM 0x000400 -#define HWCAP_LMDMA 0x000800 -#define HWCAP_PFM 0x001000 -#define HWCAP_HSMP 0x002000 -#define HWCAP_TRACE 0x004000 -#define HWCAP_DIV 0x008000 -#define HWCAP_MAC 0x010000 -#define HWCAP_L2C 0x020000 -#define HWCAP_FPU_DP 0x040000 -#define HWCAP_V2 0x080000 -#define HWCAP_DX_REGS 0x100000 -#define HWCAP_HWPRE 0x200000 - -unsigned long cpu_id, cpu_rev, cpu_cfgid; -bool has_fpu = false; -char cpu_series; -char *endianness = NULL; - -unsigned int __atags_pointer __initdata; -unsigned int elf_hwcap; -EXPORT_SYMBOL(elf_hwcap); - -/* - * The following string table, must sync with HWCAP_xx bitmask, - * which is defined above - */ -static const char *hwcap_str[] = { - "mfusr_pc", - "perf1", - "perf2", - "fpu", - "audio", - "16b", - "string", - "reduced_regs", - "video", - "encrypt", - "edm", - "lmdma", - "pfm", - "hsmp", - "trace", - "div", - "mac", - "l2c", - "fpu_dp", - "v2", - "dx_regs", - "hw_pre", - NULL, -}; - -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -#define WRITE_METHOD "write through" -#else -#define WRITE_METHOD "write back" -#endif - -struct cache_info L1_cache_info[2]; -static void __init dump_cpu_info(int cpu) -{ - int i, p = 0; - char str[sizeof(hwcap_str) + 16]; - - for (i = 0; hwcap_str[i]; i++) { - if (elf_hwcap & (1 << i)) { - sprintf(str + p, "%s ", hwcap_str[i]); - p += strlen(hwcap_str[i]) + 1; - } - } - - pr_info("CPU%d Features: %s\n", cpu, str); - - L1_cache_info[ICACHE].ways = CACHE_WAY(ICACHE); - L1_cache_info[ICACHE].line_size = CACHE_LINE_SIZE(ICACHE); - L1_cache_info[ICACHE].sets = CACHE_SET(ICACHE); - L1_cache_info[ICACHE].size = - L1_cache_info[ICACHE].ways * L1_cache_info[ICACHE].line_size * - L1_cache_info[ICACHE].sets / 1024; - pr_info("L1I:%dKB/%dS/%dW/%dB\n", L1_cache_info[ICACHE].size, - L1_cache_info[ICACHE].sets, L1_cache_info[ICACHE].ways, - L1_cache_info[ICACHE].line_size); - L1_cache_info[DCACHE].ways = CACHE_WAY(DCACHE); - L1_cache_info[DCACHE].line_size = CACHE_LINE_SIZE(DCACHE); - L1_cache_info[DCACHE].sets = CACHE_SET(DCACHE); - L1_cache_info[DCACHE].size = - L1_cache_info[DCACHE].ways * L1_cache_info[DCACHE].line_size * - L1_cache_info[DCACHE].sets / 1024; - pr_info("L1D:%dKB/%dS/%dW/%dB\n", L1_cache_info[DCACHE].size, - L1_cache_info[DCACHE].sets, L1_cache_info[DCACHE].ways, - L1_cache_info[DCACHE].line_size); - pr_info("L1 D-Cache is %s\n", WRITE_METHOD); - if (L1_cache_info[DCACHE].size != L1_CACHE_BYTES) - pr_crit - ("The cache line size(%d) of this processor is not the same as L1_CACHE_BYTES(%d).\n", - L1_cache_info[DCACHE].size, L1_CACHE_BYTES); -#ifdef CONFIG_CPU_CACHE_ALIASING - { - int aliasing_num; - aliasing_num = - L1_cache_info[ICACHE].size * 1024 / PAGE_SIZE / - L1_cache_info[ICACHE].ways; - L1_cache_info[ICACHE].aliasing_num = aliasing_num; - L1_cache_info[ICACHE].aliasing_mask = - (aliasing_num - 1) << PAGE_SHIFT; - aliasing_num = - L1_cache_info[DCACHE].size * 1024 / PAGE_SIZE / - L1_cache_info[DCACHE].ways; - L1_cache_info[DCACHE].aliasing_num = aliasing_num; - L1_cache_info[DCACHE].aliasing_mask = - (aliasing_num - 1) << PAGE_SHIFT; - } -#endif -#ifdef CONFIG_FPU - /* Disable fpu and enable when it is used. */ - if (has_fpu) - disable_fpu(); -#endif -} - -static void __init setup_cpuinfo(void) -{ - unsigned long tmp = 0, cpu_name; - - cpu_dcache_inval_all(); - cpu_icache_inval_all(); - __nds32__isb(); - - cpu_id = (__nds32__mfsr(NDS32_SR_CPU_VER) & CPU_VER_mskCPUID) >> CPU_VER_offCPUID; - cpu_name = ((cpu_id) & 0xf0) >> 4; - cpu_series = cpu_name ? cpu_name - 10 + 'A' : 'N'; - cpu_id = cpu_id & 0xf; - cpu_rev = (__nds32__mfsr(NDS32_SR_CPU_VER) & CPU_VER_mskREV) >> CPU_VER_offREV; - cpu_cfgid = (__nds32__mfsr(NDS32_SR_CPU_VER) & CPU_VER_mskCFGID) >> CPU_VER_offCFGID; - - pr_info("CPU:%c%ld, CPU_VER 0x%08x(id %lu, rev %lu, cfg %lu)\n", - cpu_series, cpu_id, __nds32__mfsr(NDS32_SR_CPU_VER), cpu_id, cpu_rev, cpu_cfgid); - - elf_hwcap |= HWCAP_MFUSR_PC; - - if (((__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskBASEV) >> MSC_CFG_offBASEV) == 0) { - if (__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskDIV) - elf_hwcap |= HWCAP_DIV; - - if ((__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskMAC) - || (cpu_id == 12 && cpu_rev < 4)) - elf_hwcap |= HWCAP_MAC; - } else { - elf_hwcap |= HWCAP_V2; - elf_hwcap |= HWCAP_DIV; - elf_hwcap |= HWCAP_MAC; - } - - if (cpu_cfgid & 0x0001) - elf_hwcap |= HWCAP_EXT; - - if (cpu_cfgid & 0x0002) - elf_hwcap |= HWCAP_BASE16; - - if (cpu_cfgid & 0x0004) - elf_hwcap |= HWCAP_EXT2; - - if (cpu_cfgid & 0x0008) { - elf_hwcap |= HWCAP_FPU; - has_fpu = true; - } - if (cpu_cfgid & 0x0010) - elf_hwcap |= HWCAP_STRING; - - if (__nds32__mfsr(NDS32_SR_MMU_CFG) & MMU_CFG_mskDE) - endianness = "MSB"; - else - endianness = "LSB"; - - if (__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskEDM) - elf_hwcap |= HWCAP_EDM; - - if (__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskLMDMA) - elf_hwcap |= HWCAP_LMDMA; - - if (__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskPFM) - elf_hwcap |= HWCAP_PFM; - - if (__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskHSMP) - elf_hwcap |= HWCAP_HSMP; - - if (__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskTRACE) - elf_hwcap |= HWCAP_TRACE; - - if (__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskAUDIO) - elf_hwcap |= HWCAP_AUDIO; - - if (__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskL2C) - elf_hwcap |= HWCAP_L2C; - -#ifdef CONFIG_HW_PRE - if (__nds32__mfsr(NDS32_SR_MISC_CTL) & MISC_CTL_makHWPRE_EN) - elf_hwcap |= HWCAP_HWPRE; -#endif - - tmp = __nds32__mfsr(NDS32_SR_CACHE_CTL); - if (!IS_ENABLED(CONFIG_CPU_DCACHE_DISABLE)) - tmp |= CACHE_CTL_mskDC_EN; - - if (!IS_ENABLED(CONFIG_CPU_ICACHE_DISABLE)) - tmp |= CACHE_CTL_mskIC_EN; - __nds32__mtsr_isb(tmp, NDS32_SR_CACHE_CTL); - - dump_cpu_info(smp_processor_id()); -} - -static void __init setup_memory(void) -{ - unsigned long ram_start_pfn; - unsigned long free_ram_start_pfn; - phys_addr_t memory_start, memory_end; - - memory_end = memory_start = 0; - - /* Find main memory where is the kernel */ - memory_start = memblock_start_of_DRAM(); - memory_end = memblock_end_of_DRAM(); - - if (!memory_end) { - panic("No memory!"); - } - - ram_start_pfn = PFN_UP(memblock_start_of_DRAM()); - /* free_ram_start_pfn is first page after kernel */ - free_ram_start_pfn = PFN_UP(__pa(&_end)); - max_pfn = PFN_DOWN(memblock_end_of_DRAM()); - /* it could update max_pfn */ - if (max_pfn - ram_start_pfn <= MAXMEM_PFN) - max_low_pfn = max_pfn; - else { - max_low_pfn = MAXMEM_PFN + ram_start_pfn; - if (!IS_ENABLED(CONFIG_HIGHMEM)) - max_pfn = MAXMEM_PFN + ram_start_pfn; - } - /* high_memory is related with VMALLOC */ - high_memory = (void *)__va(max_low_pfn * PAGE_SIZE); - min_low_pfn = free_ram_start_pfn; - - /* - * initialize the boot-time allocator (with low memory only). - * - * This makes the memory from the end of the kernel to the end of - * RAM usable. - */ - memblock_set_bottom_up(true); - memblock_reserve(PFN_PHYS(ram_start_pfn), PFN_PHYS(free_ram_start_pfn - ram_start_pfn)); - - early_init_fdt_reserve_self(); - early_init_fdt_scan_reserved_mem(); - - memblock_dump_all(); -} - -void __init setup_arch(char **cmdline_p) -{ - early_init_devtree(__atags_pointer ? \ - phys_to_virt(__atags_pointer) : __dtb_start); - - setup_cpuinfo(); - - setup_initial_init_mm(_stext, _etext, _edata, _end); - - /* setup bootmem allocator */ - setup_memory(); - - /* paging_init() sets up the MMU and marks all pages as reserved */ - paging_init(); - - /* invalidate all TLB entries because the new mapping is created */ - __nds32__tlbop_flua(); - - /* use generic way to parse */ - parse_early_param(); - - unflatten_and_copy_device_tree(); - - *cmdline_p = boot_command_line; - early_trap_init(); -} - -static int c_show(struct seq_file *m, void *v) -{ - int i; - - seq_printf(m, "Processor\t: %c%ld (id %lu, rev %lu, cfg %lu)\n", - cpu_series, cpu_id, cpu_id, cpu_rev, cpu_cfgid); - - seq_printf(m, "L1I\t\t: %luKB/%luS/%luW/%luB\n", - CACHE_SET(ICACHE) * CACHE_WAY(ICACHE) * - CACHE_LINE_SIZE(ICACHE) / 1024, CACHE_SET(ICACHE), - CACHE_WAY(ICACHE), CACHE_LINE_SIZE(ICACHE)); - - seq_printf(m, "L1D\t\t: %luKB/%luS/%luW/%luB\n", - CACHE_SET(DCACHE) * CACHE_WAY(DCACHE) * - CACHE_LINE_SIZE(DCACHE) / 1024, CACHE_SET(DCACHE), - CACHE_WAY(DCACHE), CACHE_LINE_SIZE(DCACHE)); - - seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", - loops_per_jiffy / (500000 / HZ), - (loops_per_jiffy / (5000 / HZ)) % 100); - - /* dump out the processor features */ - seq_puts(m, "Features\t: "); - - for (i = 0; hwcap_str[i]; i++) - if (elf_hwcap & (1 << i)) - seq_printf(m, "%s ", hwcap_str[i]); - - seq_puts(m, "\n\n"); - - return 0; -} - -static void *c_start(struct seq_file *m, loff_t * pos) -{ - return *pos < 1 ? (void *)1 : NULL; -} - -static void *c_next(struct seq_file *m, void *v, loff_t * pos) -{ - ++*pos; - return NULL; -} - -static void c_stop(struct seq_file *m, void *v) -{ -} - -struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = c_show -}; diff --git a/arch/nds32/kernel/signal.c b/arch/nds32/kernel/signal.c deleted file mode 100644 index 7e3ca430a223..000000000000 --- a/arch/nds32/kernel/signal.c +++ /dev/null @@ -1,384 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -struct rt_sigframe { - struct siginfo info; - struct ucontext uc; -}; -#if IS_ENABLED(CONFIG_FPU) -static inline int restore_sigcontext_fpu(struct pt_regs *regs, - struct sigcontext __user *sc) -{ - struct task_struct *tsk = current; - unsigned long used_math_flag; - int ret = 0; - - clear_used_math(); - __get_user_error(used_math_flag, &sc->used_math_flag, ret); - - if (!used_math_flag) - return 0; - set_used_math(); - -#if IS_ENABLED(CONFIG_LAZY_FPU) - preempt_disable(); - if (current == last_task_used_math) { - last_task_used_math = NULL; - disable_ptreg_fpu(regs); - } - preempt_enable(); -#else - clear_fpu(regs); -#endif - - return __copy_from_user(&tsk->thread.fpu, &sc->fpu, - sizeof(struct fpu_struct)); -} - -static inline int setup_sigcontext_fpu(struct pt_regs *regs, - struct sigcontext __user *sc) -{ - struct task_struct *tsk = current; - int ret = 0; - - __put_user_error(used_math(), &sc->used_math_flag, ret); - - if (!used_math()) - return ret; - - preempt_disable(); -#if IS_ENABLED(CONFIG_LAZY_FPU) - if (last_task_used_math == tsk) - save_fpu(last_task_used_math); -#else - unlazy_fpu(tsk); -#endif - ret = __copy_to_user(&sc->fpu, &tsk->thread.fpu, - sizeof(struct fpu_struct)); - preempt_enable(); - return ret; -} -#endif - -static int restore_sigframe(struct pt_regs *regs, - struct rt_sigframe __user * sf) -{ - sigset_t set; - int err; - - err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); - if (err == 0) { - set_current_blocked(&set); - } - - __get_user_error(regs->uregs[0], &sf->uc.uc_mcontext.nds32_r0, err); - __get_user_error(regs->uregs[1], &sf->uc.uc_mcontext.nds32_r1, err); - __get_user_error(regs->uregs[2], &sf->uc.uc_mcontext.nds32_r2, err); - __get_user_error(regs->uregs[3], &sf->uc.uc_mcontext.nds32_r3, err); - __get_user_error(regs->uregs[4], &sf->uc.uc_mcontext.nds32_r4, err); - __get_user_error(regs->uregs[5], &sf->uc.uc_mcontext.nds32_r5, err); - __get_user_error(regs->uregs[6], &sf->uc.uc_mcontext.nds32_r6, err); - __get_user_error(regs->uregs[7], &sf->uc.uc_mcontext.nds32_r7, err); - __get_user_error(regs->uregs[8], &sf->uc.uc_mcontext.nds32_r8, err); - __get_user_error(regs->uregs[9], &sf->uc.uc_mcontext.nds32_r9, err); - __get_user_error(regs->uregs[10], &sf->uc.uc_mcontext.nds32_r10, err); - __get_user_error(regs->uregs[11], &sf->uc.uc_mcontext.nds32_r11, err); - __get_user_error(regs->uregs[12], &sf->uc.uc_mcontext.nds32_r12, err); - __get_user_error(regs->uregs[13], &sf->uc.uc_mcontext.nds32_r13, err); - __get_user_error(regs->uregs[14], &sf->uc.uc_mcontext.nds32_r14, err); - __get_user_error(regs->uregs[15], &sf->uc.uc_mcontext.nds32_r15, err); - __get_user_error(regs->uregs[16], &sf->uc.uc_mcontext.nds32_r16, err); - __get_user_error(regs->uregs[17], &sf->uc.uc_mcontext.nds32_r17, err); - __get_user_error(regs->uregs[18], &sf->uc.uc_mcontext.nds32_r18, err); - __get_user_error(regs->uregs[19], &sf->uc.uc_mcontext.nds32_r19, err); - __get_user_error(regs->uregs[20], &sf->uc.uc_mcontext.nds32_r20, err); - __get_user_error(regs->uregs[21], &sf->uc.uc_mcontext.nds32_r21, err); - __get_user_error(regs->uregs[22], &sf->uc.uc_mcontext.nds32_r22, err); - __get_user_error(regs->uregs[23], &sf->uc.uc_mcontext.nds32_r23, err); - __get_user_error(regs->uregs[24], &sf->uc.uc_mcontext.nds32_r24, err); - __get_user_error(regs->uregs[25], &sf->uc.uc_mcontext.nds32_r25, err); - - __get_user_error(regs->fp, &sf->uc.uc_mcontext.nds32_fp, err); - __get_user_error(regs->gp, &sf->uc.uc_mcontext.nds32_gp, err); - __get_user_error(regs->lp, &sf->uc.uc_mcontext.nds32_lp, err); - __get_user_error(regs->sp, &sf->uc.uc_mcontext.nds32_sp, err); - __get_user_error(regs->ipc, &sf->uc.uc_mcontext.nds32_ipc, err); -#if defined(CONFIG_HWZOL) - __get_user_error(regs->lc, &sf->uc.uc_mcontext.zol.nds32_lc, err); - __get_user_error(regs->le, &sf->uc.uc_mcontext.zol.nds32_le, err); - __get_user_error(regs->lb, &sf->uc.uc_mcontext.zol.nds32_lb, err); -#endif -#if IS_ENABLED(CONFIG_FPU) - err |= restore_sigcontext_fpu(regs, &sf->uc.uc_mcontext); -#endif - /* - * Avoid sys_rt_sigreturn() restarting. - */ - forget_syscall(regs); - return err; -} - -asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) -{ - struct rt_sigframe __user *frame; - - /* Always make any pending restarted system calls return -EINTR */ - current->restart_block.fn = do_no_restart_syscall; - - /* - * Since we stacked the signal on a 64-bit boundary, - * then 'sp' should be two-word aligned here. If it's - * not, then the user is trying to mess with us. - */ - if (regs->sp & 7) - goto badframe; - - frame = (struct rt_sigframe __user *)regs->sp; - - if (!access_ok(frame, sizeof(*frame))) - goto badframe; - - if (restore_sigframe(regs, frame)) - goto badframe; - - if (restore_altstack(&frame->uc.uc_stack)) - goto badframe; - - return regs->uregs[0]; - -badframe: - force_sig(SIGSEGV); - return 0; -} - -static int -setup_sigframe(struct rt_sigframe __user * sf, struct pt_regs *regs, - sigset_t * set) -{ - int err = 0; - - __put_user_error(regs->uregs[0], &sf->uc.uc_mcontext.nds32_r0, err); - __put_user_error(regs->uregs[1], &sf->uc.uc_mcontext.nds32_r1, err); - __put_user_error(regs->uregs[2], &sf->uc.uc_mcontext.nds32_r2, err); - __put_user_error(regs->uregs[3], &sf->uc.uc_mcontext.nds32_r3, err); - __put_user_error(regs->uregs[4], &sf->uc.uc_mcontext.nds32_r4, err); - __put_user_error(regs->uregs[5], &sf->uc.uc_mcontext.nds32_r5, err); - __put_user_error(regs->uregs[6], &sf->uc.uc_mcontext.nds32_r6, err); - __put_user_error(regs->uregs[7], &sf->uc.uc_mcontext.nds32_r7, err); - __put_user_error(regs->uregs[8], &sf->uc.uc_mcontext.nds32_r8, err); - __put_user_error(regs->uregs[9], &sf->uc.uc_mcontext.nds32_r9, err); - __put_user_error(regs->uregs[10], &sf->uc.uc_mcontext.nds32_r10, err); - __put_user_error(regs->uregs[11], &sf->uc.uc_mcontext.nds32_r11, err); - __put_user_error(regs->uregs[12], &sf->uc.uc_mcontext.nds32_r12, err); - __put_user_error(regs->uregs[13], &sf->uc.uc_mcontext.nds32_r13, err); - __put_user_error(regs->uregs[14], &sf->uc.uc_mcontext.nds32_r14, err); - __put_user_error(regs->uregs[15], &sf->uc.uc_mcontext.nds32_r15, err); - __put_user_error(regs->uregs[16], &sf->uc.uc_mcontext.nds32_r16, err); - __put_user_error(regs->uregs[17], &sf->uc.uc_mcontext.nds32_r17, err); - __put_user_error(regs->uregs[18], &sf->uc.uc_mcontext.nds32_r18, err); - __put_user_error(regs->uregs[19], &sf->uc.uc_mcontext.nds32_r19, err); - __put_user_error(regs->uregs[20], &sf->uc.uc_mcontext.nds32_r20, err); - - __put_user_error(regs->uregs[21], &sf->uc.uc_mcontext.nds32_r21, err); - __put_user_error(regs->uregs[22], &sf->uc.uc_mcontext.nds32_r22, err); - __put_user_error(regs->uregs[23], &sf->uc.uc_mcontext.nds32_r23, err); - __put_user_error(regs->uregs[24], &sf->uc.uc_mcontext.nds32_r24, err); - __put_user_error(regs->uregs[25], &sf->uc.uc_mcontext.nds32_r25, err); - __put_user_error(regs->fp, &sf->uc.uc_mcontext.nds32_fp, err); - __put_user_error(regs->gp, &sf->uc.uc_mcontext.nds32_gp, err); - __put_user_error(regs->lp, &sf->uc.uc_mcontext.nds32_lp, err); - __put_user_error(regs->sp, &sf->uc.uc_mcontext.nds32_sp, err); - __put_user_error(regs->ipc, &sf->uc.uc_mcontext.nds32_ipc, err); -#if defined(CONFIG_HWZOL) - __put_user_error(regs->lc, &sf->uc.uc_mcontext.zol.nds32_lc, err); - __put_user_error(regs->le, &sf->uc.uc_mcontext.zol.nds32_le, err); - __put_user_error(regs->lb, &sf->uc.uc_mcontext.zol.nds32_lb, err); -#endif -#if IS_ENABLED(CONFIG_FPU) - err |= setup_sigcontext_fpu(regs, &sf->uc.uc_mcontext); -#endif - - __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, - err); - __put_user_error(current->thread.error_code, - &sf->uc.uc_mcontext.error_code, err); - __put_user_error(current->thread.address, - &sf->uc.uc_mcontext.fault_address, err); - __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); - - err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); - - return err; -} - -static inline void __user *get_sigframe(struct ksignal *ksig, - struct pt_regs *regs, int framesize) -{ - unsigned long sp; - - /* Default to using normal stack */ - sp = regs->sp; - - /* - * If we are on the alternate signal stack and would overflow it, don't. - * Return an always-bogus address instead so we will die with SIGSEGV. - */ - if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) - return (void __user __force *)(-1UL); - - /* This is the X/Open sanctioned signal stack switching. */ - sp = (sigsp(sp, ksig) - framesize); - - /* - * nds32 mandates 8-byte alignment - */ - sp &= ~0x7UL; - - return (void __user *)sp; -} - -static int -setup_return(struct pt_regs *regs, struct ksignal *ksig, void __user * frame) -{ - unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler; - unsigned long retcode; - - retcode = VDSO_SYMBOL(current->mm->context.vdso, rt_sigtramp); - regs->uregs[0] = ksig->sig; - regs->sp = (unsigned long)frame; - regs->lp = retcode; - regs->ipc = handler; - - return 0; -} - -static int -setup_rt_frame(struct ksignal *ksig, sigset_t * set, struct pt_regs *regs) -{ - struct rt_sigframe __user *frame = - get_sigframe(ksig, regs, sizeof(*frame)); - int err = 0; - - if (!access_ok(frame, sizeof(*frame))) - return -EFAULT; - - __put_user_error(0, &frame->uc.uc_flags, err); - __put_user_error(NULL, &frame->uc.uc_link, err); - - err |= __save_altstack(&frame->uc.uc_stack, regs->sp); - err |= setup_sigframe(frame, regs, set); - if (err == 0) { - setup_return(regs, ksig, frame); - if (ksig->ka.sa.sa_flags & SA_SIGINFO) { - err |= copy_siginfo_to_user(&frame->info, &ksig->info); - regs->uregs[1] = (unsigned long)&frame->info; - regs->uregs[2] = (unsigned long)&frame->uc; - } - } - return err; -} - -/* - * OK, we're invoking a handler - */ -static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) -{ - int ret; - sigset_t *oldset = sigmask_to_save(); - - if (in_syscall(regs)) { - /* Avoid additional syscall restarting via ret_slow_syscall. */ - forget_syscall(regs); - - switch (regs->uregs[0]) { - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - regs->uregs[0] = -EINTR; - break; - case -ERESTARTSYS: - if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { - regs->uregs[0] = -EINTR; - break; - } - fallthrough; - case -ERESTARTNOINTR: - regs->uregs[0] = regs->orig_r0; - regs->ipc -= 4; - break; - } - } - /* - * Set up the stack frame - */ - ret = setup_rt_frame(ksig, oldset, regs); - - signal_setup_done(ret, ksig, 0); -} - -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - * - * Note that we go through the signals twice: once to check the signals that - * the kernel can handle, and then we build all the user-level signal handling - * stack-frames in one go after that. - */ -static void do_signal(struct pt_regs *regs) -{ - struct ksignal ksig; - - if (get_signal(&ksig)) { - handle_signal(&ksig, regs); - return; - } - - /* - * If we were from a system call, check for system call restarting... - */ - if (in_syscall(regs)) { - /* Restart the system call - no handlers present */ - - /* Avoid additional syscall restarting via ret_slow_syscall. */ - forget_syscall(regs); - - switch (regs->uregs[0]) { - case -ERESTART_RESTARTBLOCK: - regs->uregs[15] = __NR_restart_syscall; - fallthrough; - case -ERESTARTNOHAND: - case -ERESTARTSYS: - case -ERESTARTNOINTR: - regs->uregs[0] = regs->orig_r0; - regs->ipc -= 0x4; - break; - } - } - restore_saved_sigmask(); -} - -asmlinkage void -do_notify_resume(struct pt_regs *regs, unsigned int thread_flags) -{ - if (thread_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) - do_signal(regs); - - if (thread_flags & _TIF_NOTIFY_RESUME) - tracehook_notify_resume(regs); -} diff --git a/arch/nds32/kernel/sleep.S b/arch/nds32/kernel/sleep.S deleted file mode 100644 index ca4e61f3656f..000000000000 --- a/arch/nds32/kernel/sleep.S +++ /dev/null @@ -1,131 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2017 Andes Technology Corporation */ - -#include - -.data -.global sp_tmp -sp_tmp: -.long - -.text -.globl suspend2ram -.globl cpu_resume - -suspend2ram: - pushm $r0, $r31 -#if defined(CONFIG_HWZOL) - mfusr $r0, $lc - mfusr $r1, $le - mfusr $r2, $lb -#endif - mfsr $r3, $mr0 - mfsr $r4, $mr1 - mfsr $r5, $mr4 - mfsr $r6, $mr6 - mfsr $r7, $mr7 - mfsr $r8, $mr8 - mfsr $r9, $ir0 - mfsr $r10, $ir1 - mfsr $r11, $ir2 - mfsr $r12, $ir3 - mfsr $r13, $ir9 - mfsr $r14, $ir10 - mfsr $r15, $ir12 - mfsr $r16, $ir13 - mfsr $r17, $ir14 - mfsr $r18, $ir15 - pushm $r0, $r19 -#if defined(CONFIG_FPU) - jal store_fpu_for_suspend -#endif - tlbop FlushAll - isb - - // transfer $sp from va to pa - sethi $r0, hi20(PAGE_OFFSET) - ori $r0, $r0, lo12(PAGE_OFFSET) - movi $r2, PHYS_OFFSET - sub $r1, $sp, $r0 - add $r2, $r1, $r2 - - // store pa($sp) to sp_tmp - sethi $r1, hi20(sp_tmp) - swi $r2, [$r1 + lo12(sp_tmp)] - - pushm $r16, $r25 - pushm $r29, $r30 -#ifdef CONFIG_CACHE_L2 - jal dcache_wb_all_level -#else - jal cpu_dcache_wb_all -#endif - popm $r29, $r30 - popm $r16, $r25 - - // get wake_mask and loop in standby - la $r1, wake_mask - lwi $r1, [$r1] -self_loop: - standby wake_grant - mfsr $r2, $ir15 - and $r2, $r1, $r2 - beqz $r2, self_loop - - // set ipc to resume address - la $r1, resume_addr - lwi $r1, [$r1] - mtsr $r1, $ipc - isb - - // reset psw, turn off the address translation - li $r2, 0x7000a - mtsr $r2, $ipsw - isb - - iret -cpu_resume: - // translate the address of sp_tmp variable to pa - la $r1, sp_tmp - sethi $r0, hi20(PAGE_OFFSET) - ori $r0, $r0, lo12(PAGE_OFFSET) - movi $r2, PHYS_OFFSET - sub $r1, $r1, $r0 - add $r1, $r1, $r2 - - // access the sp_tmp to get stack pointer - lwi $sp, [$r1] - - popm $r0, $r19 -#if defined(CONFIG_HWZOL) - mtusr $r0, $lb - mtusr $r1, $lc - mtusr $r2, $le -#endif - mtsr $r3, $mr0 - mtsr $r4, $mr1 - mtsr $r5, $mr4 - mtsr $r6, $mr6 - mtsr $r7, $mr7 - mtsr $r8, $mr8 - // set original psw to ipsw - mtsr $r9, $ir1 - - mtsr $r11, $ir2 - mtsr $r12, $ir3 - - // set ipc to RR - la $r13, RR - mtsr $r13, $ir9 - - mtsr $r14, $ir10 - mtsr $r15, $ir12 - mtsr $r16, $ir13 - mtsr $r17, $ir14 - mtsr $r18, $ir15 - popm $r0, $r31 - - isb - iret -RR: - ret diff --git a/arch/nds32/kernel/stacktrace.c b/arch/nds32/kernel/stacktrace.c deleted file mode 100644 index d974c0c1c65f..000000000000 --- a/arch/nds32/kernel/stacktrace.c +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include - -void save_stack_trace(struct stack_trace *trace) -{ - save_stack_trace_tsk(current, trace); -} -EXPORT_SYMBOL_GPL(save_stack_trace); - -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) -{ - unsigned long *fpn; - int skip = trace->skip; - int savesched; - int graph_idx = 0; - - if (tsk == current) { - __asm__ __volatile__("\tori\t%0, $fp, #0\n":"=r"(fpn)); - savesched = 1; - } else { - fpn = (unsigned long *)thread_saved_fp(tsk); - savesched = 0; - } - - while (!kstack_end(fpn) && !((unsigned long)fpn & 0x3) - && (fpn >= (unsigned long *)TASK_SIZE)) { - unsigned long lpp, fpp; - - lpp = fpn[LP_OFFSET]; - fpp = fpn[FP_OFFSET]; - if (!__kernel_text_address(lpp)) - break; - else - lpp = ftrace_graph_ret_addr(tsk, &graph_idx, lpp, NULL); - - if (savesched || !in_sched_functions(lpp)) { - if (skip) { - skip--; - } else { - trace->entries[trace->nr_entries++] = lpp; - if (trace->nr_entries >= trace->max_entries) - break; - } - } - fpn = (unsigned long *)fpp; - } -} -EXPORT_SYMBOL_GPL(save_stack_trace_tsk); diff --git a/arch/nds32/kernel/sys_nds32.c b/arch/nds32/kernel/sys_nds32.c deleted file mode 100644 index cb2d1e219bb3..000000000000 --- a/arch/nds32/kernel/sys_nds32.c +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include - -#include -#include -#include -#include - -SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, - unsigned long, prot, unsigned long, flags, - unsigned long, fd, unsigned long, pgoff) -{ - if (pgoff & (~PAGE_MASK >> 12)) - return -EINVAL; - - return sys_mmap_pgoff(addr, len, prot, flags, fd, - pgoff >> (PAGE_SHIFT - 12)); -} - -SYSCALL_DEFINE4(fadvise64_64_wrapper,int, fd, int, advice, loff_t, offset, - loff_t, len) -{ - return sys_fadvise64_64(fd, offset, len, advice); -} - -SYSCALL_DEFINE3(cacheflush, unsigned int, start, unsigned int, end, int, cache) -{ - struct vm_area_struct *vma; - bool flushi = true, wbd = true; - - vma = find_vma(current->mm, start); - if (!vma) - return -EFAULT; - switch (cache) { - case ICACHE: - wbd = false; - break; - case DCACHE: - flushi = false; - break; - case BCACHE: - break; - default: - return -EINVAL; - } - cpu_cache_wbinval_range_check(vma, start, end, flushi, wbd); - - return 0; -} - -SYSCALL_DEFINE2(fp_udfiex_crtl, unsigned int, cmd, unsigned int, act) -{ -#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - int old_udf_iex; - - if (!used_math()) { - load_fpu(&init_fpuregs); - current->thread.fpu.UDF_IEX_trap = init_fpuregs.UDF_IEX_trap; - set_used_math(); - } - - old_udf_iex = current->thread.fpu.UDF_IEX_trap; - act &= (FPCSR_mskUDFE | FPCSR_mskIEXE); - - switch (cmd) { - case DISABLE_UDF_IEX_TRAP: - current->thread.fpu.UDF_IEX_trap &= ~act; - break; - case ENABLE_UDF_IEX_TRAP: - current->thread.fpu.UDF_IEX_trap |= act; - break; - case GET_UDF_IEX_TRAP: - break; - default: - return -EINVAL; - } - return old_udf_iex; -#else - return -ENOTSUPP; -#endif -} diff --git a/arch/nds32/kernel/syscall_table.c b/arch/nds32/kernel/syscall_table.c deleted file mode 100644 index 7879c061b87f..000000000000 --- a/arch/nds32/kernel/syscall_table.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include - -#undef __SYSCALL -#define __SYSCALL(nr, call) [nr] = (call), - -#define sys_rt_sigreturn sys_rt_sigreturn_wrapper -#define sys_fadvise64_64 sys_fadvise64_64_wrapper -void *sys_call_table[__NR_syscalls] __aligned(8192) = { - [0 ... __NR_syscalls - 1] = sys_ni_syscall, -#include -}; diff --git a/arch/nds32/kernel/time.c b/arch/nds32/kernel/time.c deleted file mode 100644 index 574a3d0a8539..000000000000 --- a/arch/nds32/kernel/time.c +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include - -void __init time_init(void) -{ - of_clk_init(NULL); - timer_probe(); -} diff --git a/arch/nds32/kernel/traps.c b/arch/nds32/kernel/traps.c deleted file mode 100644 index c0a8f3344fb9..000000000000 --- a/arch/nds32/kernel/traps.c +++ /dev/null @@ -1,354 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -extern void show_pte(struct mm_struct *mm, unsigned long addr); - -/* - * Dump out the contents of some memory nicely... - */ -void dump_mem(const char *lvl, unsigned long bottom, unsigned long top) -{ - unsigned long first; - int i; - - pr_emerg("%s(0x%08lx to 0x%08lx)\n", lvl, bottom, top); - - for (first = bottom & ~31; first < top; first += 32) { - unsigned long p; - char str[sizeof(" 12345678") * 8 + 1]; - - memset(str, ' ', sizeof(str)); - str[sizeof(str) - 1] = '\0'; - - for (p = first, i = 0; i < 8 && p < top; i++, p += 4) { - if (p >= bottom && p < top) { - unsigned long val; - - if (get_kernel_nofault(val, - (unsigned long *)p) == 0) - sprintf(str + i * 9, " %08lx", val); - else - sprintf(str + i * 9, " ????????"); - } - } - pr_emerg("%s%04lx:%s\n", lvl, first & 0xffff, str); - } -} - -EXPORT_SYMBOL(dump_mem); - -#define LOOP_TIMES (100) -static void __dump(struct task_struct *tsk, unsigned long *base_reg, - const char *loglvl) -{ - unsigned long ret_addr; - int cnt = LOOP_TIMES, graph = 0; - printk("%sCall Trace:\n", loglvl); - if (!IS_ENABLED(CONFIG_FRAME_POINTER)) { - while (!kstack_end(base_reg)) { - ret_addr = *base_reg++; - if (__kernel_text_address(ret_addr)) { - ret_addr = ftrace_graph_ret_addr( - tsk, &graph, ret_addr, NULL); - print_ip_sym(loglvl, ret_addr); - } - if (--cnt < 0) - break; - } - } else { - while (!kstack_end((void *)base_reg) && - !((unsigned long)base_reg & 0x3) && - ((unsigned long)base_reg >= TASK_SIZE)) { - unsigned long next_fp; - ret_addr = base_reg[LP_OFFSET]; - next_fp = base_reg[FP_OFFSET]; - if (__kernel_text_address(ret_addr)) { - - ret_addr = ftrace_graph_ret_addr( - tsk, &graph, ret_addr, NULL); - print_ip_sym(loglvl, ret_addr); - } - if (--cnt < 0) - break; - base_reg = (unsigned long *)next_fp; - } - } - printk("%s\n", loglvl); -} - -void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl) -{ - unsigned long *base_reg; - - if (!tsk) - tsk = current; - if (!IS_ENABLED(CONFIG_FRAME_POINTER)) { - if (tsk != current) - base_reg = (unsigned long *)(tsk->thread.cpu_context.sp); - else - __asm__ __volatile__("\tori\t%0, $sp, #0\n":"=r"(base_reg)); - } else { - if (tsk != current) - base_reg = (unsigned long *)(tsk->thread.cpu_context.fp); - else - __asm__ __volatile__("\tori\t%0, $fp, #0\n":"=r"(base_reg)); - } - __dump(tsk, base_reg, loglvl); - barrier(); -} - -DEFINE_SPINLOCK(die_lock); - -/* - * This function is protected against re-entrancy. - */ -void __noreturn die(const char *str, struct pt_regs *regs, int err) -{ - struct task_struct *tsk = current; - static int die_counter; - - console_verbose(); - spin_lock_irq(&die_lock); - bust_spinlocks(1); - - pr_emerg("Internal error: %s: %x [#%d]\n", str, err, ++die_counter); - print_modules(); - pr_emerg("CPU: %i\n", smp_processor_id()); - show_regs(regs); - pr_emerg("Process %s (pid: %d, stack limit = 0x%p)\n", - tsk->comm, tsk->pid, end_of_stack(tsk)); - - if (!user_mode(regs) || in_interrupt()) { - dump_mem("Stack: ", regs->sp, (regs->sp + PAGE_SIZE) & PAGE_MASK); - dump_stack(); - } - - bust_spinlocks(0); - spin_unlock_irq(&die_lock); - make_task_dead(SIGSEGV); -} - -EXPORT_SYMBOL(die); - -void die_if_kernel(const char *str, struct pt_regs *regs, int err) -{ - if (user_mode(regs)) - return; - - die(str, regs, err); -} - -int bad_syscall(int n, struct pt_regs *regs) -{ - if (current->personality != PER_LINUX) { - send_sig(SIGSEGV, current, 1); - return regs->uregs[0]; - } - - force_sig_fault(SIGILL, ILL_ILLTRP, - (void __user *)instruction_pointer(regs) - 4); - die_if_kernel("Oops - bad syscall", regs, n); - return regs->uregs[0]; -} - -void __pte_error(const char *file, int line, unsigned long val) -{ - pr_emerg("%s:%d: bad pte %08lx.\n", file, line, val); -} - -void __pmd_error(const char *file, int line, unsigned long val) -{ - pr_emerg("%s:%d: bad pmd %08lx.\n", file, line, val); -} - -void __pgd_error(const char *file, int line, unsigned long val) -{ - pr_emerg("%s:%d: bad pgd %08lx.\n", file, line, val); -} - -extern char *exception_vector, *exception_vector_end; -void __init early_trap_init(void) -{ - unsigned long ivb = 0; - unsigned long base = PAGE_OFFSET; - - memcpy((unsigned long *)base, (unsigned long *)&exception_vector, - ((unsigned long)&exception_vector_end - - (unsigned long)&exception_vector)); - ivb = __nds32__mfsr(NDS32_SR_IVB); - /* Check platform support. */ - if (((ivb & IVB_mskNIVIC) >> IVB_offNIVIC) < 2) - panic - ("IVIC mode is not allowed on the platform with interrupt controller\n"); - __nds32__mtsr((ivb & ~IVB_mskESZ) | (IVB_valESZ16 << IVB_offESZ) | - IVB_BASE, NDS32_SR_IVB); - __nds32__mtsr(INT_MASK_INITAIAL_VAL, NDS32_SR_INT_MASK); - - /* - * 0x800 = 128 vectors * 16byte. - * It should be enough to flush a page. - */ - cpu_cache_wbinval_page(base, true); -} - -static void send_sigtrap(struct pt_regs *regs, int error_code, int si_code) -{ - struct task_struct *tsk = current; - - tsk->thread.trap_no = ENTRY_DEBUG_RELATED; - tsk->thread.error_code = error_code; - - force_sig_fault(SIGTRAP, si_code, - (void __user *)instruction_pointer(regs)); -} - -void do_debug_trap(unsigned long entry, unsigned long addr, - unsigned long type, struct pt_regs *regs) -{ - if (notify_die(DIE_OOPS, "Oops", regs, addr, type, SIGTRAP) - == NOTIFY_STOP) - return; - - if (user_mode(regs)) { - /* trap_signal */ - send_sigtrap(regs, 0, TRAP_BRKPT); - } else { - /* kernel_trap */ - if (!fixup_exception(regs)) - die("unexpected kernel_trap", regs, 0); - } -} - -void unhandled_interruption(struct pt_regs *regs) -{ - pr_emerg("unhandled_interruption\n"); - show_regs(regs); - if (!user_mode(regs)) - make_task_dead(SIGKILL); - force_sig(SIGKILL); -} - -void unhandled_exceptions(unsigned long entry, unsigned long addr, - unsigned long type, struct pt_regs *regs) -{ - pr_emerg("Unhandled Exception: entry: %lx addr:%lx itype:%lx\n", entry, - addr, type); - show_regs(regs); - if (!user_mode(regs)) - make_task_dead(SIGKILL); - force_sig(SIGKILL); -} - -extern int do_page_fault(unsigned long entry, unsigned long addr, - unsigned int error_code, struct pt_regs *regs); - -/* - * 2:DEF dispatch for TLB MISC exception handler -*/ - -void do_dispatch_tlb_misc(unsigned long entry, unsigned long addr, - unsigned long type, struct pt_regs *regs) -{ - type = type & (ITYPE_mskINST | ITYPE_mskETYPE); - if ((type & ITYPE_mskETYPE) < 5) { - /* Permission exceptions */ - do_page_fault(entry, addr, type, regs); - } else - unhandled_exceptions(entry, addr, type, regs); -} - -void do_revinsn(struct pt_regs *regs) -{ - pr_emerg("Reserved Instruction\n"); - show_regs(regs); - if (!user_mode(regs)) - make_task_dead(SIGILL); - force_sig(SIGILL); -} - -#ifdef CONFIG_ALIGNMENT_TRAP -extern int unalign_access_mode; -extern int do_unaligned_access(unsigned long addr, struct pt_regs *regs); -#endif -void do_dispatch_general(unsigned long entry, unsigned long addr, - unsigned long itype, struct pt_regs *regs, - unsigned long oipc) -{ - unsigned int swid = itype >> ITYPE_offSWID; - unsigned long type = itype & (ITYPE_mskINST | ITYPE_mskETYPE); - if (type == ETYPE_ALIGNMENT_CHECK) { -#ifdef CONFIG_ALIGNMENT_TRAP - /* Alignment check */ - if (user_mode(regs) && unalign_access_mode) { - int ret; - ret = do_unaligned_access(addr, regs); - - if (ret == 0) - return; - - if (ret == -EFAULT) - pr_emerg - ("Unhandled unaligned access exception\n"); - } -#endif - do_page_fault(entry, addr, type, regs); - } else if (type == ETYPE_RESERVED_INSTRUCTION) { - /* Reserved instruction */ - do_revinsn(regs); - } else if (type == ETYPE_COPROCESSOR) { - /* Coprocessor */ -#if IS_ENABLED(CONFIG_FPU) - unsigned int fucop_exist = __nds32__mfsr(NDS32_SR_FUCOP_EXIST); - unsigned int cpid = ((itype & ITYPE_mskCPID) >> ITYPE_offCPID); - - if ((cpid == FPU_CPID) && - (fucop_exist & FUCOP_EXIST_mskCP0ISFPU)) { - unsigned int subtype = (itype & ITYPE_mskSTYPE); - - if (true == do_fpu_exception(subtype, regs)) - return; - } -#endif - unhandled_exceptions(entry, addr, type, regs); - } else if (type == ETYPE_TRAP && swid == SWID_RAISE_INTERRUPT_LEVEL) { - /* trap, used on v3 EDM target debugging workaround */ - /* - * DIPC(OIPC) is passed as parameter before - * interrupt is enabled, so the DIPC will not be corrupted - * even though interrupts are coming in - */ - /* - * 1. update ipc - * 2. update pt_regs ipc with oipc - * 3. update pt_regs ipsw (clear DEX) - */ - __asm__ volatile ("mtsr %0, $IPC\n\t"::"r" (oipc)); - regs->ipc = oipc; - if (regs->pipsw & PSW_mskDEX) { - pr_emerg - ("Nested Debug exception is possibly happened\n"); - pr_emerg("ipc:%08x pipc:%08x\n", - (unsigned int)regs->ipc, - (unsigned int)regs->pipc); - } - do_debug_trap(entry, addr, itype, regs); - regs->ipsw &= ~PSW_mskDEX; - } else - unhandled_exceptions(entry, addr, type, regs); -} diff --git a/arch/nds32/kernel/vdso.c b/arch/nds32/kernel/vdso.c deleted file mode 100644 index e16009a07971..000000000000 --- a/arch/nds32/kernel/vdso.c +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2012 ARM Limited -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -extern struct cache_info L1_cache_info[2]; -extern char vdso_start[], vdso_end[]; -static unsigned long vdso_pages __ro_after_init; -static unsigned long timer_mapping_base; - -struct timer_info_t timer_info = { - .cycle_count_down = true, - .mapping_base = EMPTY_TIMER_MAPPING, - .cycle_count_reg_offset = EMPTY_REG_OFFSET -}; -/* - * The vDSO data page. - */ -static struct page *no_pages[] = { NULL }; - -static union { - struct vdso_data data; - u8 page[PAGE_SIZE]; -} vdso_data_store __page_aligned_data; -struct vdso_data *vdso_data = &vdso_data_store.data; -static struct vm_special_mapping vdso_spec[2] __ro_after_init = { - { - .name = "[vvar]", - .pages = no_pages, - }, - { - .name = "[vdso]", - }, -}; - -static void get_timer_node_info(void) -{ - timer_mapping_base = timer_info.mapping_base; - vdso_data->cycle_count_offset = - timer_info.cycle_count_reg_offset; - vdso_data->cycle_count_down = - timer_info.cycle_count_down; -} - -static int __init vdso_init(void) -{ - int i; - struct page **vdso_pagelist; - - if (memcmp(vdso_start, "\177ELF", 4)) { - pr_err("vDSO is not a valid ELF object!\n"); - return -EINVAL; - } - /* Creat a timer io mapping to get clock cycles counter */ - get_timer_node_info(); - - vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT; - pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n", - vdso_pages + 1, vdso_pages, vdso_start, 1L, vdso_data); - - /* Allocate the vDSO pagelist */ - vdso_pagelist = kcalloc(vdso_pages, sizeof(struct page *), GFP_KERNEL); - if (vdso_pagelist == NULL) - return -ENOMEM; - - for (i = 0; i < vdso_pages; i++) - vdso_pagelist[i] = virt_to_page(vdso_start + i * PAGE_SIZE); - vdso_spec[1].pages = &vdso_pagelist[0]; - - return 0; -} - -arch_initcall(vdso_init); - -unsigned long inline vdso_random_addr(unsigned long vdso_mapping_len) -{ - unsigned long start = current->mm->mmap_base, end, offset, addr; - start = PAGE_ALIGN(start); - - /* Round the lowest possible end address up to a PMD boundary. */ - end = (start + vdso_mapping_len + PMD_SIZE - 1) & PMD_MASK; - if (end >= TASK_SIZE) - end = TASK_SIZE; - end -= vdso_mapping_len; - - if (end > start) { - offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1); - addr = start + (offset << PAGE_SHIFT); - } else { - addr = start; - } - return addr; -} - -int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) -{ - struct mm_struct *mm = current->mm; - unsigned long vdso_base, vdso_text_len, vdso_mapping_len; - struct vm_area_struct *vma; - unsigned long addr = 0; - pgprot_t prot; - int ret, vvar_page_num = 2; - - vdso_text_len = vdso_pages << PAGE_SHIFT; - - if(timer_mapping_base == EMPTY_VALUE) - vvar_page_num = 1; - /* Be sure to map the data page */ - vdso_mapping_len = vdso_text_len + vvar_page_num * PAGE_SIZE; -#ifdef CONFIG_CPU_CACHE_ALIASING - vdso_mapping_len += L1_cache_info[DCACHE].aliasing_num - 1; -#endif - - if (mmap_write_lock_killable(mm)) - return -EINTR; - - addr = vdso_random_addr(vdso_mapping_len); - vdso_base = get_unmapped_area(NULL, addr, vdso_mapping_len, 0, 0); - if (IS_ERR_VALUE(vdso_base)) { - ret = vdso_base; - goto up_fail; - } - -#ifdef CONFIG_CPU_CACHE_ALIASING - { - unsigned int aliasing_mask = - L1_cache_info[DCACHE].aliasing_mask; - unsigned int page_colour_ofs; - page_colour_ofs = ((unsigned int)vdso_data & aliasing_mask) - - (vdso_base & aliasing_mask); - vdso_base += page_colour_ofs & aliasing_mask; - } -#endif - - vma = _install_special_mapping(mm, vdso_base, vvar_page_num * PAGE_SIZE, - VM_READ | VM_MAYREAD, &vdso_spec[0]); - if (IS_ERR(vma)) { - ret = PTR_ERR(vma); - goto up_fail; - } - - /*Map vdata to user space */ - ret = io_remap_pfn_range(vma, vdso_base, - virt_to_phys(vdso_data) >> PAGE_SHIFT, - PAGE_SIZE, vma->vm_page_prot); - if (ret) - goto up_fail; - - /*Map timer to user space */ - vdso_base += PAGE_SIZE; - prot = __pgprot(_PAGE_V | _PAGE_M_UR_KR | _PAGE_D | _PAGE_C_DEV); - ret = io_remap_pfn_range(vma, vdso_base, timer_mapping_base >> PAGE_SHIFT, - PAGE_SIZE, prot); - if (ret) - goto up_fail; - - /*Map vdso to user space */ - vdso_base += PAGE_SIZE; - mm->context.vdso = (void *)vdso_base; - vma = _install_special_mapping(mm, vdso_base, vdso_text_len, - VM_READ | VM_EXEC | - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, - &vdso_spec[1]); - if (IS_ERR(vma)) { - ret = PTR_ERR(vma); - goto up_fail; - } - - mmap_write_unlock(mm); - return 0; - -up_fail: - mm->context.vdso = NULL; - mmap_write_unlock(mm); - return ret; -} - -static void vdso_write_begin(struct vdso_data *vdata) -{ - ++vdso_data->seq_count; - smp_wmb(); /* Pairs with smp_rmb in vdso_read_retry */ -} - -static void vdso_write_end(struct vdso_data *vdata) -{ - smp_wmb(); /* Pairs with smp_rmb in vdso_read_begin */ - ++vdso_data->seq_count; -} - -void update_vsyscall(struct timekeeper *tk) -{ - vdso_write_begin(vdso_data); - vdso_data->cs_mask = tk->tkr_mono.mask; - vdso_data->cs_mult = tk->tkr_mono.mult; - vdso_data->cs_shift = tk->tkr_mono.shift; - vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; - vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec; - vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; - vdso_data->xtime_clock_sec = tk->xtime_sec; - vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; - vdso_data->xtime_coarse_sec = tk->xtime_sec; - vdso_data->xtime_coarse_nsec = tk->tkr_mono.xtime_nsec >> - tk->tkr_mono.shift; - vdso_data->hrtimer_res = hrtimer_resolution; - vdso_write_end(vdso_data); -} - -void update_vsyscall_tz(void) -{ - vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; - vdso_data->tz_dsttime = sys_tz.tz_dsttime; -} diff --git a/arch/nds32/kernel/vdso/.gitignore b/arch/nds32/kernel/vdso/.gitignore deleted file mode 100644 index 652e31d82582..000000000000 --- a/arch/nds32/kernel/vdso/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -vdso.lds diff --git a/arch/nds32/kernel/vdso/Makefile b/arch/nds32/kernel/vdso/Makefile deleted file mode 100644 index 55df25ef0057..000000000000 --- a/arch/nds32/kernel/vdso/Makefile +++ /dev/null @@ -1,79 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Building a vDSO image for AArch64. -# -# Author: Will Deacon -# Heavily based on the vDSO Makefiles for other archs. -# - -obj-vdso := note.o datapage.o sigreturn.o gettimeofday.o - -# Build rules -targets := $(obj-vdso) vdso.so vdso.so.dbg -obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) - -ccflags-y := -shared -fno-common -fno-builtin -nostdlib -fPIC -Wl,-shared -g \ - -Wl,-soname=linux-vdso.so.1 -Wl,--hash-style=sysv - -# Disable gcov profiling for VDSO code -GCOV_PROFILE := n - - -obj-y += vdso.o -targets += vdso.lds -CPPFLAGS_vdso.lds += -P -C -U$(ARCH) - -# Force dependency -$(obj)/vdso.o : $(obj)/vdso.so - -# Link rule for the .so file, .lds has to be first -$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE - $(call if_changed,vdsold) - - -# Strip rule for the .so file -$(obj)/%.so: OBJCOPYFLAGS := -S -$(obj)/%.so: $(obj)/%.so.dbg FORCE - $(call if_changed,objcopy) - -# Generate VDSO offsets using helper script -gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh -quiet_cmd_vdsosym = VDSOSYM $@ - cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ - -include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE - $(call if_changed,vdsosym) - - - -# Assembly rules for the .S files - -sigreturn.o : sigreturn.S - $(call if_changed_dep,vdsoas) - -note.o : note.S - $(call if_changed_dep,vdsoas) - -datapage.o : datapage.S - $(call if_changed_dep,vdsoas) - -gettimeofday.o : gettimeofday.c FORCE - $(call if_changed_dep,vdsocc) - -# Actual build commands -quiet_cmd_vdsold = VDSOL $@ - cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $(real-prereqs) -o $@ -quiet_cmd_vdsoas = VDSOA $@ - cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $< -quiet_cmd_vdsocc = VDSOA $@ - cmd_vdsocc = $(CC) $(c_flags) -c -o $@ $< - -# Install commands for the unstripped file -quiet_cmd_vdso_install = INSTALL $@ - cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ - -vdso.so: $(obj)/vdso.so.dbg - @mkdir -p $(MODLIB)/vdso - $(call cmd,vdso_install) - -vdso_install: vdso.so diff --git a/arch/nds32/kernel/vdso/datapage.S b/arch/nds32/kernel/vdso/datapage.S deleted file mode 100644 index 4a62c3cab1c8..000000000000 --- a/arch/nds32/kernel/vdso/datapage.S +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include - -ENTRY(__get_timerpage) - sethi $r0, hi20(. + PAGE_SIZE + 8) - ori $r0, $r0, lo12(. + PAGE_SIZE + 4) - mfusr $r1, $pc - sub $r0, $r1, $r0 - ret -ENDPROC(__get_timerpage) - -ENTRY(__get_datapage) - sethi $r0, hi20(. + 2*PAGE_SIZE + 8) - ori $r0, $r0, lo12(. + 2*PAGE_SIZE + 4) - mfusr $r1, $pc - sub $r0, $r1, $r0 - ret -ENDPROC(__get_datapage) diff --git a/arch/nds32/kernel/vdso/gen_vdso_offsets.sh b/arch/nds32/kernel/vdso/gen_vdso_offsets.sh deleted file mode 100755 index 01924ff071ad..000000000000 --- a/arch/nds32/kernel/vdso/gen_vdso_offsets.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# -# Match symbols in the DSO that look like VDSO_*; produce a header file -# of constant offsets into the shared object. -# -# Doing this inside the Makefile will break the $(filter-out) function, -# causing Kbuild to rebuild the vdso-offsets header file every time. -# -# Author: Will Deacon -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define X(x) #x -#define Y(x) X(x) - -extern struct vdso_data *__get_datapage(void); -extern struct vdso_data *__get_timerpage(void); - -static notrace unsigned int __vdso_read_begin(const struct vdso_data *vdata) -{ - u32 seq; -repeat: - seq = READ_ONCE(vdata->seq_count); - if (seq & 1) { - cpu_relax(); - goto repeat; - } - return seq; -} - -static notrace unsigned int vdso_read_begin(const struct vdso_data *vdata) -{ - unsigned int seq; - - seq = __vdso_read_begin(vdata); - - smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */ - return seq; -} - -static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start) -{ - smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */ - return vdata->seq_count != start; -} - -static notrace long clock_gettime_fallback(clockid_t _clkid, - struct __kernel_old_timespec *_ts) -{ - register struct __kernel_old_timespec *ts asm("$r1") = _ts; - register clockid_t clkid asm("$r0") = _clkid; - register long ret asm("$r0"); - - asm volatile ("movi $r15, %3\n" - "syscall 0x0\n" - :"=r" (ret) - :"r"(clkid), "r"(ts), "i"(__NR_clock_gettime) - :"$r15", "memory"); - - return ret; -} - -static notrace int do_realtime_coarse(struct __kernel_old_timespec *ts, - struct vdso_data *vdata) -{ - u32 seq; - - do { - seq = vdso_read_begin(vdata); - - ts->tv_sec = vdata->xtime_coarse_sec; - ts->tv_nsec = vdata->xtime_coarse_nsec; - - } while (vdso_read_retry(vdata, seq)); - return 0; -} - -static notrace int do_monotonic_coarse(struct __kernel_old_timespec *ts, - struct vdso_data *vdata) -{ - u32 seq; - u64 ns; - - do { - seq = vdso_read_begin(vdata); - - ts->tv_sec = vdata->xtime_coarse_sec + vdata->wtm_clock_sec; - ns = vdata->xtime_coarse_nsec + vdata->wtm_clock_nsec; - - } while (vdso_read_retry(vdata, seq)); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - -static notrace inline u64 vgetsns(struct vdso_data *vdso) -{ - u32 cycle_now; - u32 cycle_delta; - u32 *timer_cycle_base; - - timer_cycle_base = - (u32 *) ((char *)__get_timerpage() + vdso->cycle_count_offset); - cycle_now = readl_relaxed(timer_cycle_base); - if (true == vdso->cycle_count_down) - cycle_now = ~(*timer_cycle_base); - cycle_delta = cycle_now - (u32) vdso->cs_cycle_last; - return ((u64) cycle_delta & vdso->cs_mask) * vdso->cs_mult; -} - -static notrace int do_realtime(struct __kernel_old_timespec *ts, struct vdso_data *vdata) -{ - unsigned count; - u64 ns; - do { - count = vdso_read_begin(vdata); - ts->tv_sec = vdata->xtime_clock_sec; - ns = vdata->xtime_clock_nsec; - ns += vgetsns(vdata); - ns >>= vdata->cs_shift; - } while (vdso_read_retry(vdata, count)); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - -static notrace int do_monotonic(struct __kernel_old_timespec *ts, struct vdso_data *vdata) -{ - u64 ns; - u32 seq; - - do { - seq = vdso_read_begin(vdata); - - ts->tv_sec = vdata->xtime_clock_sec; - ns = vdata->xtime_clock_nsec; - ns += vgetsns(vdata); - ns >>= vdata->cs_shift; - - ts->tv_sec += vdata->wtm_clock_sec; - ns += vdata->wtm_clock_nsec; - - } while (vdso_read_retry(vdata, seq)); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - -notrace int __vdso_clock_gettime(clockid_t clkid, struct __kernel_old_timespec *ts) -{ - struct vdso_data *vdata; - int ret = -1; - - vdata = __get_datapage(); - if (vdata->cycle_count_offset == EMPTY_REG_OFFSET) - return clock_gettime_fallback(clkid, ts); - - switch (clkid) { - case CLOCK_REALTIME_COARSE: - ret = do_realtime_coarse(ts, vdata); - break; - case CLOCK_MONOTONIC_COARSE: - ret = do_monotonic_coarse(ts, vdata); - break; - case CLOCK_REALTIME: - ret = do_realtime(ts, vdata); - break; - case CLOCK_MONOTONIC: - ret = do_monotonic(ts, vdata); - break; - default: - break; - } - - if (ret) - ret = clock_gettime_fallback(clkid, ts); - - return ret; -} - -static notrace int clock_getres_fallback(clockid_t _clk_id, - struct __kernel_old_timespec *_res) -{ - register clockid_t clk_id asm("$r0") = _clk_id; - register struct __kernel_old_timespec *res asm("$r1") = _res; - register int ret asm("$r0"); - - asm volatile ("movi $r15, %3\n" - "syscall 0x0\n" - :"=r" (ret) - :"r"(clk_id), "r"(res), "i"(__NR_clock_getres) - :"$r15", "memory"); - - return ret; -} - -notrace int __vdso_clock_getres(clockid_t clk_id, struct __kernel_old_timespec *res) -{ - struct vdso_data *vdata = __get_datapage(); - - if (res == NULL) - return 0; - switch (clk_id) { - case CLOCK_REALTIME: - case CLOCK_MONOTONIC: - case CLOCK_MONOTONIC_RAW: - res->tv_sec = 0; - res->tv_nsec = vdata->hrtimer_res; - break; - case CLOCK_REALTIME_COARSE: - case CLOCK_MONOTONIC_COARSE: - res->tv_sec = 0; - res->tv_nsec = CLOCK_COARSE_RES; - break; - default: - return clock_getres_fallback(clk_id, res); - } - return 0; -} - -static notrace inline int gettimeofday_fallback(struct __kernel_old_timeval *_tv, - struct timezone *_tz) -{ - register struct __kernel_old_timeval *tv asm("$r0") = _tv; - register struct timezone *tz asm("$r1") = _tz; - register int ret asm("$r0"); - - asm volatile ("movi $r15, %3\n" - "syscall 0x0\n" - :"=r" (ret) - :"r"(tv), "r"(tz), "i"(__NR_gettimeofday) - :"$r15", "memory"); - - return ret; -} - -notrace int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) -{ - struct __kernel_old_timespec ts; - struct vdso_data *vdata; - int ret; - - vdata = __get_datapage(); - - if (vdata->cycle_count_offset == EMPTY_REG_OFFSET) - return gettimeofday_fallback(tv, tz); - - ret = do_realtime(&ts, vdata); - - if (tv) { - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / 1000; - } - if (tz) { - tz->tz_minuteswest = vdata->tz_minuteswest; - tz->tz_dsttime = vdata->tz_dsttime; - } - - return ret; -} diff --git a/arch/nds32/kernel/vdso/note.S b/arch/nds32/kernel/vdso/note.S deleted file mode 100644 index 0aeaa19b05f0..000000000000 --- a/arch/nds32/kernel/vdso/note.S +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2012 ARM Limited -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include - -ELFNOTE_START(Linux, 0, "a") - .long LINUX_VERSION_CODE -ELFNOTE_END diff --git a/arch/nds32/kernel/vdso/sigreturn.S b/arch/nds32/kernel/vdso/sigreturn.S deleted file mode 100644 index 67e4d1d1612a..000000000000 --- a/arch/nds32/kernel/vdso/sigreturn.S +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2012 ARM Limited -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include - - .text - -ENTRY(__kernel_rt_sigreturn) - .cfi_startproc - movi $r15, __NR_rt_sigreturn - /* - * The SWID of syscall should be __NR_rt_sigreturn to synchronize - * the unwinding scheme in gcc - */ - syscall __NR_rt_sigreturn - .cfi_endproc -ENDPROC(__kernel_rt_sigreturn) diff --git a/arch/nds32/kernel/vdso/vdso.S b/arch/nds32/kernel/vdso/vdso.S deleted file mode 100644 index 16737c11e55b..000000000000 --- a/arch/nds32/kernel/vdso/vdso.S +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2012 ARM Limited -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include - - .globl vdso_start, vdso_end - .section .rodata - .balign PAGE_SIZE -vdso_start: - .incbin "arch/nds32/kernel/vdso/vdso.so" - .balign PAGE_SIZE -vdso_end: - - .previous diff --git a/arch/nds32/kernel/vdso/vdso.lds.S b/arch/nds32/kernel/vdso/vdso.lds.S deleted file mode 100644 index 1f2b16004594..000000000000 --- a/arch/nds32/kernel/vdso/vdso.lds.S +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-2.0 - * Copyright (C) 2005-2017 Andes Technology Corporation - */ - - -#include -#include -#include - -OUTPUT_ARCH(nds32) - -SECTIONS -{ - . = SIZEOF_HEADERS; - - .hash : { *(.hash) } :text - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - - .note : { *(.note.*) } :text :note - - - .text : { *(.text*) } :text - - .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr - .eh_frame : { KEEP (*(.eh_frame)) } :text - - .dynamic : { *(.dynamic) } :text :dynamic - - .rodata : { *(.rodata*) } :text - - - /DISCARD/ : { - *(.note.GNU-stack) - *(.data .data.* .gnu.linkonce.d.* .sdata*) - *(.bss .sbss .dynbss .dynsbss) - } -} - -/* - * We must supply the ELF program headers explicitly to get just one - * PT_LOAD segment, and set the flags explicitly to make segments read-only. - */ -PHDRS -{ - text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ - dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ - note PT_NOTE FLAGS(4); /* PF_R */ - eh_frame_hdr PT_GNU_EH_FRAME; -} - -/* - * This controls what symbols we export from the DSO. - */ -VERSION -{ - LINUX_4 { - global: - __kernel_rt_sigreturn; - __vdso_gettimeofday; - __vdso_clock_getres; - __vdso_clock_gettime; - local: *; - }; -} - -/* - * Make the rt_sigreturn code visible to the kernel. - */ -VDSO_rt_sigtramp = __kernel_rt_sigreturn; diff --git a/arch/nds32/kernel/vmlinux.lds.S b/arch/nds32/kernel/vmlinux.lds.S deleted file mode 100644 index 6a91b965fb1e..000000000000 --- a/arch/nds32/kernel/vmlinux.lds.S +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include - -#define LOAD_OFFSET (PAGE_OFFSET - PHYS_OFFSET) -#include - -OUTPUT_ARCH(nds32) -ENTRY(_stext_lma) -jiffies = jiffies_64; - -#if defined(CONFIG_GCOV_KERNEL) -#define NDS32_EXIT_KEEP(x) x -#else -#define NDS32_EXIT_KEEP(x) -#endif - -SECTIONS -{ - _stext_lma = TEXTADDR - LOAD_OFFSET; - . = TEXTADDR; - __init_begin = .; - HEAD_TEXT_SECTION - .exit.text : { - NDS32_EXIT_KEEP(EXIT_TEXT) - } - INIT_TEXT_SECTION(PAGE_SIZE) - INIT_DATA_SECTION(16) - .exit.data : { - NDS32_EXIT_KEEP(EXIT_DATA) - } - PERCPU_SECTION(L1_CACHE_BYTES) - __init_end = .; - - . = ALIGN(PAGE_SIZE); - _stext = .; - /* Real text segment */ - .text : AT(ADDR(.text) - LOAD_OFFSET) { - _text = .; /* Text and read-only data */ - TEXT_TEXT - SCHED_TEXT - CPUIDLE_TEXT - LOCK_TEXT - KPROBES_TEXT - IRQENTRY_TEXT - SOFTIRQENTRY_TEXT - *(.fixup) - } - - _etext = .; /* End of text and rodata section */ - - _sdata = .; - RO_DATA(PAGE_SIZE) - RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) - _edata = .; - - EXCEPTION_TABLE(16) - BSS_SECTION(4, 4, 4) - _end = .; - - STABS_DEBUG - DWARF_DEBUG - ELF_DETAILS - - DISCARDS -} diff --git a/arch/nds32/lib/Makefile b/arch/nds32/lib/Makefile deleted file mode 100644 index dddbc15d6b37..000000000000 --- a/arch/nds32/lib/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -lib-y := copy_page.o memcpy.o memmove.o \ - memset.o memzero.o \ - copy_from_user.o copy_to_user.o clear_user.o diff --git a/arch/nds32/lib/clear_user.S b/arch/nds32/lib/clear_user.S deleted file mode 100644 index 805dfcd25bf8..000000000000 --- a/arch/nds32/lib/clear_user.S +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include - -/* Prototype: int __arch_clear_user(void *addr, size_t sz) - * Purpose : clear some user memory - * Params : addr - user memory address to clear - * : sz - number of bytes to clear - * Returns : number of bytes NOT cleared - */ - .text - .align 5 -ENTRY(__arch_clear_user) - add $r5, $r0, $r1 - beqz $r1, clear_exit - xor $p1, $p1, $p1 ! Use $p1=0 to clear mem - srli $p0, $r1, #2 ! $p0 = number of word to clear - andi $r1, $r1, #3 ! Bytes less than a word to copy - beqz $p0, byte_clear ! Only less than a word to clear -word_clear: -USER( smw.bim,$p1, [$r0], $p1) ! Clear the word - addi $p0, $p0, #-1 ! Decrease word count - bnez $p0, word_clear ! Continue looping to clear all words - beqz $r1, clear_exit ! No left bytes to copy -byte_clear: -USER( sbi.bi, $p1, [$r0], #1) ! Clear the byte - addi $r1, $r1, #-1 ! Decrease byte count - bnez $r1, byte_clear ! Continue looping to clear all left bytes -clear_exit: - move $r0, $r1 ! Set return value - ret - - .section .fixup,"ax" - .align 0 -9001: - sub $r0, $r5, $r0 ! Bytes left to copy - ret - .previous -ENDPROC(__arch_clear_user) diff --git a/arch/nds32/lib/copy_from_user.S b/arch/nds32/lib/copy_from_user.S deleted file mode 100644 index ad1857b20067..000000000000 --- a/arch/nds32/lib/copy_from_user.S +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include - -.macro lbi1 dst, addr, adj -USER( lbi.bi, \dst, [\addr], \adj) -.endm - -.macro sbi1 src, addr, adj -sbi.bi \src, [\addr], \adj -.endm - -.macro lmw1 start_reg, addr, end_reg -USER( lmw.bim, \start_reg, [\addr], \end_reg) -.endm - -.macro smw1 start_reg, addr, end_reg -smw.bim \start_reg, [\addr], \end_reg -.endm - - -/* Prototype: int __arch_copy_from_user(void *to, const char *from, size_t n) - * Purpose : copy a block from user memory to kernel memory - * Params : to - kernel memory - * : from - user memory - * : n - number of bytes to copy - * Returns : Number of bytes NOT copied. - */ - -.text -ENTRY(__arch_copy_from_user) - add $r5, $r0, $r2 -#include "copy_template.S" - move $r0, $r2 - ret -.section .fixup,"ax" -.align 2 -9001: - sub $r0, $r5, $r0 - ret -.previous -ENDPROC(__arch_copy_from_user) diff --git a/arch/nds32/lib/copy_page.S b/arch/nds32/lib/copy_page.S deleted file mode 100644 index f8701ed161a8..000000000000 --- a/arch/nds32/lib/copy_page.S +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include - - .text -ENTRY(copy_page) - pushm $r2, $r10 - movi $r2, PAGE_SIZE >> 5 -.Lcopy_loop: - lmw.bim $r3, [$r1], $r10 - smw.bim $r3, [$r0], $r10 - subi45 $r2, #1 - bnez38 $r2, .Lcopy_loop - popm $r2, $r10 - ret -ENDPROC(copy_page) -EXPORT_SYMBOL(copy_page) - -ENTRY(clear_page) - pushm $r1, $r9 - movi $r1, PAGE_SIZE >> 5 - movi55 $r2, #0 - movi55 $r3, #0 - movi55 $r4, #0 - movi55 $r5, #0 - movi55 $r6, #0 - movi55 $r7, #0 - movi55 $r8, #0 - movi55 $r9, #0 -.Lclear_loop: - smw.bim $r2, [$r0], $r9 - subi45 $r1, #1 - bnez38 $r1, .Lclear_loop - popm $r1, $r9 - ret -ENDPROC(clear_page) -EXPORT_SYMBOL(clear_page) diff --git a/arch/nds32/lib/copy_template.S b/arch/nds32/lib/copy_template.S deleted file mode 100644 index 3a9a2de468c2..000000000000 --- a/arch/nds32/lib/copy_template.S +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - - - beq $r1, $r0, quit_memcpy - beqz $r2, quit_memcpy - srli $r3, $r2, #5 ! check if len < cache-line size 32 - beqz $r3, word_copy_entry - andi $r4, $r0, #0x3 ! check byte-align - beqz $r4, unalign_word_copy_entry - - addi $r4, $r4,#-4 - abs $r4, $r4 ! check how many un-align byte to copy - sub $r2, $r2, $r4 ! update $R2 - -unalign_byte_copy: - lbi1 $r3, $r1, #1 - addi $r4, $r4, #-1 - sbi1 $r3, $r0, #1 - bnez $r4, unalign_byte_copy - beqz $r2, quit_memcpy - -unalign_word_copy_entry: - andi $r3, $r0, 0x1f ! check cache-line unaligncount - beqz $r3, cache_copy - - addi $r3, $r3, #-32 - abs $r3, $r3 - sub $r2, $r2, $r3 ! update $R2 - -unalign_word_copy: - lmw1 $r4, $r1, $r4 - addi $r3, $r3, #-4 - smw1 $r4, $r0, $r4 - bnez $r3, unalign_word_copy - beqz $r2, quit_memcpy - - addi $r3, $r2, #-32 ! to check $r2< cache_line , than go to word_copy - bltz $r3, word_copy_entry -cache_copy: - srli $r3, $r2, #5 - beqz $r3, word_copy_entry -3: - lmw1 $r17, $r1, $r24 - addi $r3, $r3, #-1 - smw1 $r17, $r0, $r24 - bnez $r3, 3b - -word_copy_entry: - andi $r2, $r2, #31 - - beqz $r2, quit_memcpy -5: - srli $r3, $r2, #2 - beqz $r3, byte_copy -word_copy: - lmw1 $r4, $r1, $r4 - addi $r3, $r3, #-1 - smw1 $r4, $r0, $r4 - bnez $r3, word_copy - andi $r2, $r2, #3 - beqz $r2, quit_memcpy -byte_copy: - lbi1 $r3, $r1, #1 - addi $r2, $r2, #-1 - - sbi1 $r3, $r0, #1 - bnez $r2, byte_copy -quit_memcpy: diff --git a/arch/nds32/lib/copy_to_user.S b/arch/nds32/lib/copy_to_user.S deleted file mode 100644 index 3230044dcfb8..000000000000 --- a/arch/nds32/lib/copy_to_user.S +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include - -.macro lbi1 dst, addr, adj -lbi.bi \dst, [\addr], \adj -.endm - -.macro sbi1 src, addr, adj -USER( sbi.bi, \src, [\addr], \adj) -.endm - -.macro lmw1 start_reg, addr, end_reg -lmw.bim \start_reg, [\addr], \end_reg -.endm - -.macro smw1 start_reg, addr, end_reg -USER( smw.bim, \start_reg, [\addr], \end_reg) -.endm - - -/* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n) - * Purpose : copy a block to user memory from kernel memory - * Params : to - user memory - * : from - kernel memory - * : n - number of bytes to copy - * Returns : Number of bytes NOT copied. - */ - -.text -ENTRY(__arch_copy_to_user) - add $r5, $r0, $r2 -#include "copy_template.S" - move $r0, $r2 - ret -.section .fixup,"ax" -.align 2 -9001: - sub $r0, $r5, $r0 - ret -.previous -ENDPROC(__arch_copy_to_user) diff --git a/arch/nds32/lib/memcpy.S b/arch/nds32/lib/memcpy.S deleted file mode 100644 index a2345ea721e4..000000000000 --- a/arch/nds32/lib/memcpy.S +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include - - -.macro lbi1 dst, addr, adj -lbi.bi \dst, [\addr], \adj -.endm - -.macro sbi1 src, addr, adj -sbi.bi \src, [\addr], \adj -.endm - -.macro lmw1 start_reg, addr, end_reg -lmw.bim \start_reg, [\addr], \end_reg -.endm - -.macro smw1 start_reg, addr, end_reg -smw.bim \start_reg, [\addr], \end_reg -.endm - -.text -ENTRY(memcpy) - move $r5, $r0 -#include "copy_template.S" - move $r0, $r5 - ret - -ENDPROC(memcpy) diff --git a/arch/nds32/lib/memmove.S b/arch/nds32/lib/memmove.S deleted file mode 100644 index c823aada2271..000000000000 --- a/arch/nds32/lib/memmove.S +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include - -/* - void *memmove(void *dst, const void *src, int n); - - dst: $r0 - src: $r1 - n : $r2 - ret: $r0 - pointer to the memory area dst. -*/ - .text - -ENTRY(memmove) - move $r5, $r0 ! Set return value = det - beq $r0, $r1, exit_memcpy ! Exit when det = src - beqz $r2, exit_memcpy ! Exit when n = 0 - pushm $t0, $t1 ! Save reg - srli $p1, $r2, #2 ! $p1 is how many words to copy - - ! Avoid data lost when memory overlap - ! Copy data reversely when src < dst - slt $p0, $r0, $r1 ! check if $r0 < $r1 - beqz $p0, do_reverse ! branch if dst > src - - ! No reverse, dst < src - andi $r2, $r2, #3 ! How many bytes are less than a word - li $t0, #1 ! Determining copy direction in byte_cpy - beqz $p1, byte_cpy ! When n is less than a word - -word_cpy: - lmw.bim $p0, [$r1], $p0 ! Read a word from src - addi $p1, $p1, #-1 ! How many words left to copy - smw.bim $p0, [$r0], $p0 ! Copy the word to det - bnez $p1, word_cpy ! If remained words > 0 - beqz $r2, end_memcpy ! No left bytes to copy - b byte_cpy - -do_reverse: - add $r0, $r0, $r2 ! Start with the end of $r0 - add $r1, $r1, $r2 ! Start with the end of $r1 - andi $r2, $r2, #3 ! How many bytes are less than a word - li $t0, #-1 ! Determining copy direction in byte_cpy - beqz $p1, reverse_byte_cpy ! When n is less than a word - -reverse_word_cpy: - lmw.adm $p0, [$r1], $p0 ! Read a word from src - addi $p1, $p1, #-1 ! How many words left to copy - smw.adm $p0, [$r0], $p0 ! Copy the word to det - bnez $p1, reverse_word_cpy ! If remained words > 0 - beqz $r2, end_memcpy ! No left bytes to copy - -reverse_byte_cpy: - addi $r0, $r0, #-1 - addi $r1, $r1, #-1 -byte_cpy: ! Less than 4 bytes to copy now - lb.bi $p0, [$r1], $t0 ! Read a byte from src - addi $r2, $r2, #-1 ! How many bytes left to copy - sb.bi $p0, [$r0], $t0 ! copy the byte to det - bnez $r2, byte_cpy ! If remained bytes > 0 - -end_memcpy: - popm $t0, $t1 -exit_memcpy: - move $r0, $r5 - ret - -ENDPROC(memmove) diff --git a/arch/nds32/lib/memset.S b/arch/nds32/lib/memset.S deleted file mode 100644 index 193cb6ce21a9..000000000000 --- a/arch/nds32/lib/memset.S +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include - - .text -ENTRY(memset) - move $r5, $r0 ! Return value - beqz $r2, end_memset ! Exit when len = 0 - srli $p1, $r2, 2 ! $p1 is how many words to copy - andi $r2, $r2, 3 ! How many bytes are less than a word - beqz $p1, byte_set ! When n is less than a word - - ! set $r1 from ??????ab to abababab - andi $r1, $r1, #0x00ff ! $r1 = 000000ab - slli $p0, $r1, #8 ! $p0 = 0000ab00 - or $r1, $r1, $p0 ! $r1 = 0000abab - slli $p0, $r1, #16 ! $p0 = abab0000 - or $r1, $r1, $p0 ! $r1 = abababab -word_set: - addi $p1, $p1, #-1 ! How many words left to copy - smw.bim $r1, [$r0], $r1 ! Copy the word to det - bnez $p1, word_set ! Still words to set, continue looping - beqz $r2, end_memset ! No left byte to set -byte_set: ! Less than 4 bytes left to set - addi $r2, $r2, #-1 ! Decrease len by 1 - sbi.bi $r1, [$r0], #1 ! Set data of the next byte to $r1 - bnez $r2, byte_set ! Still bytes left to set -end_memset: - move $r0, $r5 - ret - -ENDPROC(memset) diff --git a/arch/nds32/lib/memzero.S b/arch/nds32/lib/memzero.S deleted file mode 100644 index f055972c9343..000000000000 --- a/arch/nds32/lib/memzero.S +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include - - .text -ENTRY(memzero) - beqz $r1, 1f - push $lp - move $r2, $r1 - move $r1, #0 - push $r0 - bal memset - pop $r0 - pop $lp -1: - ret -ENDPROC(memzero) diff --git a/arch/nds32/math-emu/Makefile b/arch/nds32/math-emu/Makefile deleted file mode 100644 index 3bed7e5d5d05..000000000000 --- a/arch/nds32/math-emu/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the Linux/nds32 kernel FPU emulation. -# - -obj-y := fpuemu.o \ - fdivd.o fmuld.o fsubd.o faddd.o fs2d.o fsqrtd.o fcmpd.o fnegs.o \ - fd2si.o fd2ui.o fd2siz.o fd2uiz.o fsi2d.o fui2d.o \ - fdivs.o fmuls.o fsubs.o fadds.o fd2s.o fsqrts.o fcmps.o fnegd.o \ - fs2si.o fs2ui.o fs2siz.o fs2uiz.o fsi2s.o fui2s.o diff --git a/arch/nds32/math-emu/faddd.c b/arch/nds32/math-emu/faddd.c deleted file mode 100644 index f7fd4e3c3904..000000000000 --- a/arch/nds32/math-emu/faddd.c +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -void faddd(void *ft, void *fa, void *fb) -{ - FP_DECL_D(A); - FP_DECL_D(B); - FP_DECL_D(R); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - FP_UNPACK_DP(B, fb); - - FP_ADD_D(R, A, B); - - FP_PACK_DP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - -} diff --git a/arch/nds32/math-emu/fadds.c b/arch/nds32/math-emu/fadds.c deleted file mode 100644 index f5af6ca8cca5..000000000000 --- a/arch/nds32/math-emu/fadds.c +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -void fadds(void *ft, void *fa, void *fb) -{ - FP_DECL_S(A); - FP_DECL_S(B); - FP_DECL_S(R); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - FP_UNPACK_SP(B, fb); - - FP_ADD_S(R, A, B); - - FP_PACK_SP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - -} diff --git a/arch/nds32/math-emu/fcmpd.c b/arch/nds32/math-emu/fcmpd.c deleted file mode 100644 index 0ea225abe880..000000000000 --- a/arch/nds32/math-emu/fcmpd.c +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include -#include -#include -int fcmpd(void *ft, void *fa, void *fb, int cmpop) -{ - FP_DECL_D(A); - FP_DECL_D(B); - FP_DECL_EX; - long cmp; - - FP_UNPACK_DP(A, fa); - FP_UNPACK_DP(B, fb); - - FP_CMP_D(cmp, A, B, SF_CUN); - cmp += 2; - if (cmp == SF_CGT) - *(long *)ft = 0; - else - *(long *)ft = (cmp & cmpop) ? 1 : 0; - - return 0; -} diff --git a/arch/nds32/math-emu/fcmps.c b/arch/nds32/math-emu/fcmps.c deleted file mode 100644 index 681480758213..000000000000 --- a/arch/nds32/math-emu/fcmps.c +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include -#include -#include -int fcmps(void *ft, void *fa, void *fb, int cmpop) -{ - FP_DECL_S(A); - FP_DECL_S(B); - FP_DECL_EX; - long cmp; - - FP_UNPACK_SP(A, fa); - FP_UNPACK_SP(B, fb); - - FP_CMP_S(cmp, A, B, SF_CUN); - cmp += 2; - if (cmp == SF_CGT) - *(int *)ft = 0x0; - else - *(int *)ft = (cmp & cmpop) ? 0x1 : 0x0; - - return 0; -} diff --git a/arch/nds32/math-emu/fd2s.c b/arch/nds32/math-emu/fd2s.c deleted file mode 100644 index 1328371e8170..000000000000 --- a/arch/nds32/math-emu/fd2s.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -#include -void fd2s(void *ft, void *fa) -{ - FP_DECL_D(A); - FP_DECL_S(R); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - - FP_CONV(S, D, 1, 2, R, A); - - FP_PACK_SP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fd2si.c b/arch/nds32/math-emu/fd2si.c deleted file mode 100644 index fae3e16a0a10..000000000000 --- a/arch/nds32/math-emu/fd2si.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fd2si(void *ft, void *fa) -{ - int r; - - FP_DECL_D(A); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - - if (A_c == FP_CLS_INF) { - *(int *)ft = (A_s == 0) ? 0x7fffffff : 0x80000000; - __FPU_FPCSR |= FP_EX_INVALID; - } else if (A_c == FP_CLS_NAN) { - *(int *)ft = 0xffffffff; - __FPU_FPCSR |= FP_EX_INVALID; - } else { - FP_TO_INT_ROUND_D(r, A, 32, 1); - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - *(int *)ft = r; - } - -} diff --git a/arch/nds32/math-emu/fd2siz.c b/arch/nds32/math-emu/fd2siz.c deleted file mode 100644 index 92fe6774f112..000000000000 --- a/arch/nds32/math-emu/fd2siz.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fd2si_z(void *ft, void *fa) -{ - int r; - - FP_DECL_D(A); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - - if (A_c == FP_CLS_INF) { - *(int *)ft = (A_s == 0) ? 0x7fffffff : 0x80000000; - __FPU_FPCSR |= FP_EX_INVALID; - } else if (A_c == FP_CLS_NAN) { - *(int *)ft = 0xffffffff; - __FPU_FPCSR |= FP_EX_INVALID; - } else { - FP_TO_INT_D(r, A, 32, 1); - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - *(int *)ft = r; - } - -} diff --git a/arch/nds32/math-emu/fd2ui.c b/arch/nds32/math-emu/fd2ui.c deleted file mode 100644 index a0423b699aa4..000000000000 --- a/arch/nds32/math-emu/fd2ui.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fd2ui(void *ft, void *fa) -{ - unsigned int r; - - FP_DECL_D(A); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - - if (A_c == FP_CLS_INF) { - *(unsigned int *)ft = (A_s == 0) ? 0xffffffff : 0x00000000; - __FPU_FPCSR |= FP_EX_INVALID; - } else if (A_c == FP_CLS_NAN) { - *(unsigned int *)ft = 0xffffffff; - __FPU_FPCSR |= FP_EX_INVALID; - } else { - FP_TO_INT_ROUND_D(r, A, 32, 0); - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - *(unsigned int *)ft = r; - } - -} diff --git a/arch/nds32/math-emu/fd2uiz.c b/arch/nds32/math-emu/fd2uiz.c deleted file mode 100644 index 8ae17cfce90d..000000000000 --- a/arch/nds32/math-emu/fd2uiz.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fd2ui_z(void *ft, void *fa) -{ - unsigned int r; - - FP_DECL_D(A); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - - if (A_c == FP_CLS_INF) { - *(unsigned int *)ft = (A_s == 0) ? 0xffffffff : 0x00000000; - __FPU_FPCSR |= FP_EX_INVALID; - } else if (A_c == FP_CLS_NAN) { - *(unsigned int *)ft = 0xffffffff; - __FPU_FPCSR |= FP_EX_INVALID; - } else { - FP_TO_INT_D(r, A, 32, 0); - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - *(unsigned int *)ft = r; - } - -} diff --git a/arch/nds32/math-emu/fdivd.c b/arch/nds32/math-emu/fdivd.c deleted file mode 100644 index 458e7e98b08e..000000000000 --- a/arch/nds32/math-emu/fdivd.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation - -#include -#include -#include -#include - -void fdivd(void *ft, void *fa, void *fb) -{ - FP_DECL_D(A); - FP_DECL_D(B); - FP_DECL_D(R); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - FP_UNPACK_DP(B, fb); - - if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) - FP_SET_EXCEPTION(FP_EX_DIVZERO); - - FP_DIV_D(R, A, B); - - FP_PACK_DP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fdivs.c b/arch/nds32/math-emu/fdivs.c deleted file mode 100644 index c7d202159ce2..000000000000 --- a/arch/nds32/math-emu/fdivs.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -void fdivs(void *ft, void *fa, void *fb) -{ - FP_DECL_S(A); - FP_DECL_S(B); - FP_DECL_S(R); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - FP_UNPACK_SP(B, fb); - - if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) - FP_SET_EXCEPTION(FP_EX_DIVZERO); - - FP_DIV_S(R, A, B); - - FP_PACK_SP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fmuld.c b/arch/nds32/math-emu/fmuld.c deleted file mode 100644 index f3c77a45ddc2..000000000000 --- a/arch/nds32/math-emu/fmuld.c +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -void fmuld(void *ft, void *fa, void *fb) -{ - FP_DECL_D(A); - FP_DECL_D(B); - FP_DECL_D(R); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - FP_UNPACK_DP(B, fb); - - FP_MUL_D(R, A, B); - - FP_PACK_DP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fmuls.c b/arch/nds32/math-emu/fmuls.c deleted file mode 100644 index cf150df938f9..000000000000 --- a/arch/nds32/math-emu/fmuls.c +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -void fmuls(void *ft, void *fa, void *fb) -{ - FP_DECL_S(A); - FP_DECL_S(B); - FP_DECL_S(R); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - FP_UNPACK_SP(B, fb); - - FP_MUL_S(R, A, B); - - FP_PACK_SP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fnegd.c b/arch/nds32/math-emu/fnegd.c deleted file mode 100644 index de7ea6a0873e..000000000000 --- a/arch/nds32/math-emu/fnegd.c +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -void fnegd(void *ft, void *fa) -{ - FP_DECL_D(A); - FP_DECL_D(R); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - - FP_NEG_D(R, A); - - FP_PACK_DP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fnegs.c b/arch/nds32/math-emu/fnegs.c deleted file mode 100644 index 07270b326a77..000000000000 --- a/arch/nds32/math-emu/fnegs.c +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -void fnegs(void *ft, void *fa) -{ - FP_DECL_S(A); - FP_DECL_S(R); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - - FP_NEG_S(R, A); - - FP_PACK_SP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fpuemu.c b/arch/nds32/math-emu/fpuemu.c deleted file mode 100644 index 46558a15c0dc..000000000000 --- a/arch/nds32/math-emu/fpuemu.c +++ /dev/null @@ -1,406 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation - -#include -#include -#include -#include -#include - -#define DPFROMREG(dp, x) (dp = (void *)((unsigned long *)fpu_reg + 2*x)) -#ifdef __NDS32_EL__ -#define SPFROMREG(sp, x)\ - ((sp) = (void *)((unsigned long *)fpu_reg + (x^1))) -#else -#define SPFROMREG(sp, x) ((sp) = (void *)((unsigned long *)fpu_reg + x)) -#endif - -#define DEF3OP(name, p, f1, f2) \ -void fpemu_##name##p(void *ft, void *fa, void *fb) \ -{ \ - f1(fa, fa, fb); \ - f2(ft, ft, fa); \ -} - -#define DEF3OPNEG(name, p, f1, f2, f3) \ -void fpemu_##name##p(void *ft, void *fa, void *fb) \ -{ \ - f1(fa, fa, fb); \ - f2(ft, ft, fa); \ - f3(ft, ft); \ -} -DEF3OP(fmadd, s, fmuls, fadds); -DEF3OP(fmsub, s, fmuls, fsubs); -DEF3OP(fmadd, d, fmuld, faddd); -DEF3OP(fmsub, d, fmuld, fsubd); -DEF3OPNEG(fnmadd, s, fmuls, fadds, fnegs); -DEF3OPNEG(fnmsub, s, fmuls, fsubs, fnegs); -DEF3OPNEG(fnmadd, d, fmuld, faddd, fnegd); -DEF3OPNEG(fnmsub, d, fmuld, fsubd, fnegd); - -static const unsigned char cmptab[8] = { - SF_CEQ, - SF_CEQ, - SF_CLT, - SF_CLT, - SF_CLT | SF_CEQ, - SF_CLT | SF_CEQ, - SF_CUN, - SF_CUN -}; - -enum ARGTYPE { - S1S = 1, - S2S, - S1D, - CS, - D1D, - D2D, - D1S, - CD -}; -union func_t { - void (*t)(void *ft, void *fa, void *fb); - void (*b)(void *ft, void *fa); -}; -/* - * Emulate a single FPU arithmetic instruction. - */ -static int fpu_emu(struct fpu_struct *fpu_reg, unsigned long insn) -{ - int rfmt; /* resulting format */ - union func_t func; - int ftype = 0; - - switch (rfmt = NDS32Insn_OPCODE_COP0(insn)) { - case fs1_op:{ - switch (NDS32Insn_OPCODE_BIT69(insn)) { - case fadds_op: - func.t = fadds; - ftype = S2S; - break; - case fsubs_op: - func.t = fsubs; - ftype = S2S; - break; - case fmadds_op: - func.t = fpemu_fmadds; - ftype = S2S; - break; - case fmsubs_op: - func.t = fpemu_fmsubs; - ftype = S2S; - break; - case fnmadds_op: - func.t = fpemu_fnmadds; - ftype = S2S; - break; - case fnmsubs_op: - func.t = fpemu_fnmsubs; - ftype = S2S; - break; - case fmuls_op: - func.t = fmuls; - ftype = S2S; - break; - case fdivs_op: - func.t = fdivs; - ftype = S2S; - break; - case fs1_f2op_op: - switch (NDS32Insn_OPCODE_BIT1014(insn)) { - case fs2d_op: - func.b = fs2d; - ftype = S1D; - break; - case fs2si_op: - func.b = fs2si; - ftype = S1S; - break; - case fs2si_z_op: - func.b = fs2si_z; - ftype = S1S; - break; - case fs2ui_op: - func.b = fs2ui; - ftype = S1S; - break; - case fs2ui_z_op: - func.b = fs2ui_z; - ftype = S1S; - break; - case fsi2s_op: - func.b = fsi2s; - ftype = S1S; - break; - case fui2s_op: - func.b = fui2s; - ftype = S1S; - break; - case fsqrts_op: - func.b = fsqrts; - ftype = S1S; - break; - default: - return SIGILL; - } - break; - default: - return SIGILL; - } - break; - } - case fs2_op: - switch (NDS32Insn_OPCODE_BIT69(insn)) { - case fcmpeqs_op: - case fcmpeqs_e_op: - case fcmplts_op: - case fcmplts_e_op: - case fcmples_op: - case fcmples_e_op: - case fcmpuns_op: - case fcmpuns_e_op: - ftype = CS; - break; - default: - return SIGILL; - } - break; - case fd1_op:{ - switch (NDS32Insn_OPCODE_BIT69(insn)) { - case faddd_op: - func.t = faddd; - ftype = D2D; - break; - case fsubd_op: - func.t = fsubd; - ftype = D2D; - break; - case fmaddd_op: - func.t = fpemu_fmaddd; - ftype = D2D; - break; - case fmsubd_op: - func.t = fpemu_fmsubd; - ftype = D2D; - break; - case fnmaddd_op: - func.t = fpemu_fnmaddd; - ftype = D2D; - break; - case fnmsubd_op: - func.t = fpemu_fnmsubd; - ftype = D2D; - break; - case fmuld_op: - func.t = fmuld; - ftype = D2D; - break; - case fdivd_op: - func.t = fdivd; - ftype = D2D; - break; - case fd1_f2op_op: - switch (NDS32Insn_OPCODE_BIT1014(insn)) { - case fd2s_op: - func.b = fd2s; - ftype = D1S; - break; - case fd2si_op: - func.b = fd2si; - ftype = D1S; - break; - case fd2si_z_op: - func.b = fd2si_z; - ftype = D1S; - break; - case fd2ui_op: - func.b = fd2ui; - ftype = D1S; - break; - case fd2ui_z_op: - func.b = fd2ui_z; - ftype = D1S; - break; - case fsi2d_op: - func.b = fsi2d; - ftype = D1S; - break; - case fui2d_op: - func.b = fui2d; - ftype = D1S; - break; - case fsqrtd_op: - func.b = fsqrtd; - ftype = D1D; - break; - default: - return SIGILL; - } - break; - default: - return SIGILL; - - } - break; - } - - case fd2_op: - switch (NDS32Insn_OPCODE_BIT69(insn)) { - case fcmpeqd_op: - case fcmpeqd_e_op: - case fcmpltd_op: - case fcmpltd_e_op: - case fcmpled_op: - case fcmpled_e_op: - case fcmpund_op: - case fcmpund_e_op: - ftype = CD; - break; - default: - return SIGILL; - } - break; - - default: - return SIGILL; - } - - switch (ftype) { - case S1S:{ - void *ft, *fa; - - SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn)); - SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn)); - func.b(ft, fa); - break; - } - case S2S:{ - void *ft, *fa, *fb; - - SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn)); - SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn)); - SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn)); - func.t(ft, fa, fb); - break; - } - case S1D:{ - void *ft, *fa; - - DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn)); - SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn)); - func.b(ft, fa); - break; - } - case CS:{ - unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn); - void *ft, *fa, *fb; - - SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn)); - SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn)); - SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn)); - if (cmpop < 0x8) { - cmpop = cmptab[cmpop]; - fcmps(ft, fa, fb, cmpop); - } else - return SIGILL; - break; - } - case D1D:{ - void *ft, *fa; - - DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn)); - DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn)); - func.b(ft, fa); - break; - } - case D2D:{ - void *ft, *fa, *fb; - - DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn)); - DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn)); - DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn)); - func.t(ft, fa, fb); - break; - } - case D1S:{ - void *ft, *fa; - - SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn)); - DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn)); - func.b(ft, fa); - break; - } - case CD:{ - unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn); - void *ft, *fa, *fb; - - SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn)); - DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn)); - DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn)); - if (cmpop < 0x8) { - cmpop = cmptab[cmpop]; - fcmpd(ft, fa, fb, cmpop); - } else - return SIGILL; - break; - } - default: - return SIGILL; - } - - /* - * If an exception is required, generate a tidy SIGFPE exception. - */ -#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - if (((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE_NO_UDF_IEXE) - || ((fpu_reg->fpcsr << 5) & (fpu_reg->UDF_IEX_trap))) { -#else - if ((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE) { -#endif - return SIGFPE; - } - return 0; -} - -int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu) -{ - unsigned long insn = 0, addr = regs->ipc; - unsigned long emulpc, contpc; - unsigned char *pc = (void *)&insn; - char c; - int i = 0, ret; - - for (i = 0; i < 4; i++) { - if (__get_user(c, (unsigned char *)addr++)) - return SIGBUS; - *pc++ = c; - } - - insn = be32_to_cpu(insn); - - emulpc = regs->ipc; - contpc = regs->ipc + 4; - - if (NDS32Insn_OPCODE(insn) != cop0_op) - return SIGILL; - - switch (NDS32Insn_OPCODE_COP0(insn)) { - case fs1_op: - case fs2_op: - case fd1_op: - case fd2_op: - { - /* a real fpu computation instruction */ - ret = fpu_emu(fpu, insn); - if (!ret) - regs->ipc = contpc; - } - break; - - default: - return SIGILL; - } - - return ret; -} diff --git a/arch/nds32/math-emu/fs2d.c b/arch/nds32/math-emu/fs2d.c deleted file mode 100644 index 0e8db9035631..000000000000 --- a/arch/nds32/math-emu/fs2d.c +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation - -#include -#include -#include -#include -#include - -void fs2d(void *ft, void *fa) -{ - FP_DECL_S(A); - FP_DECL_D(R); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - - FP_CONV(D, S, 2, 1, R, A); - - FP_PACK_DP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fs2si.c b/arch/nds32/math-emu/fs2si.c deleted file mode 100644 index b4931d60980e..000000000000 --- a/arch/nds32/math-emu/fs2si.c +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fs2si(void *ft, void *fa) -{ - int r; - - FP_DECL_S(A); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - - if (A_c == FP_CLS_INF) { - *(int *)ft = (A_s == 0) ? 0x7fffffff : 0x80000000; - __FPU_FPCSR |= FP_EX_INVALID; - } else if (A_c == FP_CLS_NAN) { - *(int *)ft = 0xffffffff; - __FPU_FPCSR |= FP_EX_INVALID; - } else { - FP_TO_INT_ROUND_S(r, A, 32, 1); - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - *(int *)ft = r; - } -} diff --git a/arch/nds32/math-emu/fs2siz.c b/arch/nds32/math-emu/fs2siz.c deleted file mode 100644 index 1c2b99ce3e38..000000000000 --- a/arch/nds32/math-emu/fs2siz.c +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fs2si_z(void *ft, void *fa) -{ - int r; - - FP_DECL_S(A); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - - if (A_c == FP_CLS_INF) { - *(int *)ft = (A_s == 0) ? 0x7fffffff : 0x80000000; - __FPU_FPCSR |= FP_EX_INVALID; - } else if (A_c == FP_CLS_NAN) { - *(int *)ft = 0xffffffff; - __FPU_FPCSR |= FP_EX_INVALID; - } else { - FP_TO_INT_S(r, A, 32, 1); - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - *(int *)ft = r; - } -} diff --git a/arch/nds32/math-emu/fs2ui.c b/arch/nds32/math-emu/fs2ui.c deleted file mode 100644 index c337f0384d06..000000000000 --- a/arch/nds32/math-emu/fs2ui.c +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fs2ui(void *ft, void *fa) -{ - unsigned int r; - - FP_DECL_S(A); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - - if (A_c == FP_CLS_INF) { - *(unsigned int *)ft = (A_s == 0) ? 0xffffffff : 0x00000000; - __FPU_FPCSR |= FP_EX_INVALID; - } else if (A_c == FP_CLS_NAN) { - *(unsigned int *)ft = 0xffffffff; - __FPU_FPCSR |= FP_EX_INVALID; - } else { - FP_TO_INT_ROUND_S(r, A, 32, 0); - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - *(unsigned int *)ft = r; - } -} diff --git a/arch/nds32/math-emu/fs2uiz.c b/arch/nds32/math-emu/fs2uiz.c deleted file mode 100644 index 22c5e4768044..000000000000 --- a/arch/nds32/math-emu/fs2uiz.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fs2ui_z(void *ft, void *fa) -{ - unsigned int r; - - FP_DECL_S(A); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - - if (A_c == FP_CLS_INF) { - *(unsigned int *)ft = (A_s == 0) ? 0xffffffff : 0x00000000; - __FPU_FPCSR |= FP_EX_INVALID; - } else if (A_c == FP_CLS_NAN) { - *(unsigned int *)ft = 0xffffffff; - __FPU_FPCSR |= FP_EX_INVALID; - } else { - FP_TO_INT_S(r, A, 32, 0); - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - *(unsigned int *)ft = r; - } - -} diff --git a/arch/nds32/math-emu/fsi2d.c b/arch/nds32/math-emu/fsi2d.c deleted file mode 100644 index 6b04cec0c5c5..000000000000 --- a/arch/nds32/math-emu/fsi2d.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fsi2d(void *ft, void *fa) -{ - int a = *(int *)fa; - - FP_DECL_D(R); - FP_DECL_EX; - - FP_FROM_INT_D(R, a, 32, int); - - FP_PACK_DP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - -} diff --git a/arch/nds32/math-emu/fsi2s.c b/arch/nds32/math-emu/fsi2s.c deleted file mode 100644 index 689864a5df90..000000000000 --- a/arch/nds32/math-emu/fsi2s.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fsi2s(void *ft, void *fa) -{ - int a = *(int *)fa; - - FP_DECL_S(R); - FP_DECL_EX; - - FP_FROM_INT_S(R, a, 32, int); - - FP_PACK_SP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - -} diff --git a/arch/nds32/math-emu/fsqrtd.c b/arch/nds32/math-emu/fsqrtd.c deleted file mode 100644 index c3a8dbd81d4e..000000000000 --- a/arch/nds32/math-emu/fsqrtd.c +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation - -#include -#include -#include -#include -void fsqrtd(void *ft, void *fa) -{ - FP_DECL_D(A); - FP_DECL_D(R); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - - FP_SQRT_D(R, A); - - FP_PACK_DP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fsqrts.c b/arch/nds32/math-emu/fsqrts.c deleted file mode 100644 index 4c6f94b27328..000000000000 --- a/arch/nds32/math-emu/fsqrts.c +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation - -#include -#include -#include -#include -void fsqrts(void *ft, void *fa) -{ - FP_DECL_S(A); - FP_DECL_S(R); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - - FP_SQRT_S(R, A); - - FP_PACK_SP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fsubd.c b/arch/nds32/math-emu/fsubd.c deleted file mode 100644 index 81b6a0d02a1f..000000000000 --- a/arch/nds32/math-emu/fsubd.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -void fsubd(void *ft, void *fa, void *fb) -{ - - FP_DECL_D(A); - FP_DECL_D(B); - FP_DECL_D(R); - FP_DECL_EX; - - FP_UNPACK_DP(A, fa); - FP_UNPACK_DP(B, fb); - - if (B_c != FP_CLS_NAN) - B_s ^= 1; - - FP_ADD_D(R, A, B); - - FP_PACK_DP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fsubs.c b/arch/nds32/math-emu/fsubs.c deleted file mode 100644 index 61ddd9708465..000000000000 --- a/arch/nds32/math-emu/fsubs.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2018 Andes Technology Corporation -#include - -#include -#include -#include -void fsubs(void *ft, void *fa, void *fb) -{ - - FP_DECL_S(A); - FP_DECL_S(B); - FP_DECL_S(R); - FP_DECL_EX; - - FP_UNPACK_SP(A, fa); - FP_UNPACK_SP(B, fb); - - if (B_c != FP_CLS_NAN) - B_s ^= 1; - - FP_ADD_S(R, A, B); - - FP_PACK_SP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; -} diff --git a/arch/nds32/math-emu/fui2d.c b/arch/nds32/math-emu/fui2d.c deleted file mode 100644 index 9689d33a8d50..000000000000 --- a/arch/nds32/math-emu/fui2d.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fui2d(void *ft, void *fa) -{ - unsigned int a = *(unsigned int *)fa; - - FP_DECL_D(R); - FP_DECL_EX; - - FP_FROM_INT_D(R, a, 32, int); - - FP_PACK_DP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - -} diff --git a/arch/nds32/math-emu/fui2s.c b/arch/nds32/math-emu/fui2s.c deleted file mode 100644 index f70f0762547d..000000000000 --- a/arch/nds32/math-emu/fui2s.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2019 Andes Technology Corporation -#include - -#include -#include -#include - -void fui2s(void *ft, void *fa) -{ - unsigned int a = *(unsigned int *)fa; - - FP_DECL_S(R); - FP_DECL_EX; - - FP_FROM_INT_S(R, a, 32, int); - - FP_PACK_SP(ft, R); - - __FPU_FPCSR |= FP_CUR_EXCEPTIONS; - -} diff --git a/arch/nds32/mm/Makefile b/arch/nds32/mm/Makefile deleted file mode 100644 index 14fb2e8eb036..000000000000 --- a/arch/nds32/mm/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-y := extable.o tlb.o fault.o init.o mmap.o \ - mm-nds32.o cacheflush.o proc.o - -obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o - -ifdef CONFIG_FUNCTION_TRACER -CFLAGS_REMOVE_proc.o = $(CC_FLAGS_FTRACE) -endif -CFLAGS_proc.o += -fomit-frame-pointer diff --git a/arch/nds32/mm/alignment.c b/arch/nds32/mm/alignment.c deleted file mode 100644 index 9c2c0a454da8..000000000000 --- a/arch/nds32/mm/alignment.c +++ /dev/null @@ -1,575 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include - -#define DEBUG(enable, tagged, ...) \ - do{ \ - if (enable) { \ - if (tagged) \ - pr_warn("[ %30s() ] ", __func__); \ - pr_warn(__VA_ARGS__); \ - } \ - } while (0) - -#define RT(inst) (((inst) >> 20) & 0x1FUL) -#define RA(inst) (((inst) >> 15) & 0x1FUL) -#define RB(inst) (((inst) >> 10) & 0x1FUL) -#define SV(inst) (((inst) >> 8) & 0x3UL) -#define IMM(inst) (((inst) >> 0) & 0x7FFFUL) - -#define RA3(inst) (((inst) >> 3) & 0x7UL) -#define RT3(inst) (((inst) >> 6) & 0x7UL) -#define IMM3U(inst) (((inst) >> 0) & 0x7UL) - -#define RA5(inst) (((inst) >> 0) & 0x1FUL) -#define RT4(inst) (((inst) >> 5) & 0xFUL) - -#define GET_IMMSVAL(imm_value) \ - (((imm_value >> 14) & 0x1) ? (imm_value - 0x8000) : imm_value) - -#define __get8_data(val,addr,err) \ - __asm__( \ - "1: lbi.bi %1, [%2], #1\n" \ - "2:\n" \ - " .pushsection .text.fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: movi %0, #1\n" \ - " j 2b\n" \ - " .popsection\n" \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .popsection\n" \ - : "=r" (err), "=&r" (val), "=r" (addr) \ - : "0" (err), "2" (addr)) - -#define get16_data(addr, val_ptr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - __get8_data(v,a,err); \ - *val_ptr = v << 0; \ - __get8_data(v,a,err); \ - *val_ptr |= v << 8; \ - if (err) \ - goto fault; \ - *val_ptr = le16_to_cpu(*val_ptr); \ - } while(0) - -#define get32_data(addr, val_ptr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - __get8_data(v,a,err); \ - *val_ptr = v << 0; \ - __get8_data(v,a,err); \ - *val_ptr |= v << 8; \ - __get8_data(v,a,err); \ - *val_ptr |= v << 16; \ - __get8_data(v,a,err); \ - *val_ptr |= v << 24; \ - if (err) \ - goto fault; \ - *val_ptr = le32_to_cpu(*val_ptr); \ - } while(0) - -#define get_data(addr, val_ptr, len) \ - if (len == 2) \ - get16_data(addr, val_ptr); \ - else \ - get32_data(addr, val_ptr); - -#define set16_data(addr, val) \ - do { \ - unsigned int err = 0, *ptr = addr ; \ - val = le32_to_cpu(val); \ - __asm__( \ - "1: sbi.bi %2, [%1], #1\n" \ - " srli %2, %2, #8\n" \ - "2: sbi %2, [%1]\n" \ - "3:\n" \ - " .pushsection .text.fixup,\"ax\"\n" \ - " .align 2\n" \ - "4: movi %0, #1\n" \ - " j 3b\n" \ - " .popsection\n" \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 4b\n" \ - " .long 2b, 4b\n" \ - " .popsection\n" \ - : "=r" (err), "+r" (ptr), "+r" (val) \ - : "0" (err) \ - ); \ - if (err) \ - goto fault; \ - } while(0) - -#define set32_data(addr, val) \ - do { \ - unsigned int err = 0, *ptr = addr ; \ - val = le32_to_cpu(val); \ - __asm__( \ - "1: sbi.bi %2, [%1], #1\n" \ - " srli %2, %2, #8\n" \ - "2: sbi.bi %2, [%1], #1\n" \ - " srli %2, %2, #8\n" \ - "3: sbi.bi %2, [%1], #1\n" \ - " srli %2, %2, #8\n" \ - "4: sbi %2, [%1]\n" \ - "5:\n" \ - " .pushsection .text.fixup,\"ax\"\n" \ - " .align 2\n" \ - "6: movi %0, #1\n" \ - " j 5b\n" \ - " .popsection\n" \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 6b\n" \ - " .long 2b, 6b\n" \ - " .long 3b, 6b\n" \ - " .long 4b, 6b\n" \ - " .popsection\n" \ - : "=r" (err), "+r" (ptr), "+r" (val) \ - : "0" (err) \ - ); \ - if (err) \ - goto fault; \ - } while(0) -#define set_data(addr, val, len) \ - if (len == 2) \ - set16_data(addr, val); \ - else \ - set32_data(addr, val); -#define NDS32_16BIT_INSTRUCTION 0x80000000 - -extern pte_t va_present(struct mm_struct *mm, unsigned long addr); -extern pte_t va_kernel_present(unsigned long addr); -extern int va_readable(struct pt_regs *regs, unsigned long addr); -extern int va_writable(struct pt_regs *regs, unsigned long addr); - -int unalign_access_mode = 0, unalign_access_debug = 0; - -static inline unsigned long *idx_to_addr(struct pt_regs *regs, int idx) -{ - /* this should be consistent with ptrace.h */ - if (idx >= 0 && idx <= 25) /* R0-R25 */ - return ®s->uregs[0] + idx; - else if (idx >= 28 && idx <= 30) /* FP, GP, LP */ - return ®s->fp + (idx - 28); - else if (idx == 31) /* SP */ - return ®s->sp; - else - return NULL; /* cause a segfault */ -} - -static inline unsigned long get_inst(unsigned long addr) -{ - return be32_to_cpu(get_unaligned((u32 *) addr)); -} - -static inline unsigned long sign_extend(unsigned long val, int len) -{ - unsigned long ret = 0; - unsigned char *s, *t; - int i = 0; - - val = cpu_to_le32(val); - - s = (void *)&val; - t = (void *)&ret; - - while (i++ < len) - *t++ = *s++; - - if (((*(t - 1)) & 0x80) && (i < 4)) { - - while (i++ <= 4) - *t++ = 0xff; - } - - return le32_to_cpu(ret); -} - -static inline int do_16(unsigned long inst, struct pt_regs *regs) -{ - int imm, regular, load, len, addr_mode, idx_mode; - unsigned long unaligned_addr, target_val, source_idx, target_idx, - shift = 0; - switch ((inst >> 9) & 0x3F) { - - case 0x12: /* LHI333 */ - imm = 1; - regular = 1; - load = 1; - len = 2; - addr_mode = 3; - idx_mode = 3; - break; - case 0x10: /* LWI333 */ - imm = 1; - regular = 1; - load = 1; - len = 4; - addr_mode = 3; - idx_mode = 3; - break; - case 0x11: /* LWI333.bi */ - imm = 1; - regular = 0; - load = 1; - len = 4; - addr_mode = 3; - idx_mode = 3; - break; - case 0x1A: /* LWI450 */ - imm = 0; - regular = 1; - load = 1; - len = 4; - addr_mode = 5; - idx_mode = 4; - break; - case 0x16: /* SHI333 */ - imm = 1; - regular = 1; - load = 0; - len = 2; - addr_mode = 3; - idx_mode = 3; - break; - case 0x14: /* SWI333 */ - imm = 1; - regular = 1; - load = 0; - len = 4; - addr_mode = 3; - idx_mode = 3; - break; - case 0x15: /* SWI333.bi */ - imm = 1; - regular = 0; - load = 0; - len = 4; - addr_mode = 3; - idx_mode = 3; - break; - case 0x1B: /* SWI450 */ - imm = 0; - regular = 1; - load = 0; - len = 4; - addr_mode = 5; - idx_mode = 4; - break; - - default: - return -EFAULT; - } - - if (addr_mode == 3) { - unaligned_addr = *idx_to_addr(regs, RA3(inst)); - source_idx = RA3(inst); - } else { - unaligned_addr = *idx_to_addr(regs, RA5(inst)); - source_idx = RA5(inst); - } - - if (idx_mode == 3) - target_idx = RT3(inst); - else - target_idx = RT4(inst); - - if (imm) - shift = IMM3U(inst) * len; - - if (regular) - unaligned_addr += shift; - - if (load) { - if (!access_ok((void *)unaligned_addr, len)) - return -EACCES; - - get_data(unaligned_addr, &target_val, len); - *idx_to_addr(regs, target_idx) = target_val; - } else { - if (!access_ok((void *)unaligned_addr, len)) - return -EACCES; - target_val = *idx_to_addr(regs, target_idx); - set_data((void *)unaligned_addr, target_val, len); - } - - if (!regular) - *idx_to_addr(regs, source_idx) = unaligned_addr + shift; - regs->ipc += 2; - - return 0; -fault: - return -EACCES; -} - -static inline int do_32(unsigned long inst, struct pt_regs *regs) -{ - int imm, regular, load, len, sign_ext; - unsigned long unaligned_addr, target_val, shift; - - unaligned_addr = *idx_to_addr(regs, RA(inst)); - - switch ((inst >> 25) << 1) { - - case 0x02: /* LHI */ - imm = 1; - regular = 1; - load = 1; - len = 2; - sign_ext = 0; - break; - case 0x0A: /* LHI.bi */ - imm = 1; - regular = 0; - load = 1; - len = 2; - sign_ext = 0; - break; - case 0x22: /* LHSI */ - imm = 1; - regular = 1; - load = 1; - len = 2; - sign_ext = 1; - break; - case 0x2A: /* LHSI.bi */ - imm = 1; - regular = 0; - load = 1; - len = 2; - sign_ext = 1; - break; - case 0x04: /* LWI */ - imm = 1; - regular = 1; - load = 1; - len = 4; - sign_ext = 0; - break; - case 0x0C: /* LWI.bi */ - imm = 1; - regular = 0; - load = 1; - len = 4; - sign_ext = 0; - break; - case 0x12: /* SHI */ - imm = 1; - regular = 1; - load = 0; - len = 2; - sign_ext = 0; - break; - case 0x1A: /* SHI.bi */ - imm = 1; - regular = 0; - load = 0; - len = 2; - sign_ext = 0; - break; - case 0x14: /* SWI */ - imm = 1; - regular = 1; - load = 0; - len = 4; - sign_ext = 0; - break; - case 0x1C: /* SWI.bi */ - imm = 1; - regular = 0; - load = 0; - len = 4; - sign_ext = 0; - break; - - default: - switch (inst & 0xff) { - - case 0x01: /* LH */ - imm = 0; - regular = 1; - load = 1; - len = 2; - sign_ext = 0; - break; - case 0x05: /* LH.bi */ - imm = 0; - regular = 0; - load = 1; - len = 2; - sign_ext = 0; - break; - case 0x11: /* LHS */ - imm = 0; - regular = 1; - load = 1; - len = 2; - sign_ext = 1; - break; - case 0x15: /* LHS.bi */ - imm = 0; - regular = 0; - load = 1; - len = 2; - sign_ext = 1; - break; - case 0x02: /* LW */ - imm = 0; - regular = 1; - load = 1; - len = 4; - sign_ext = 0; - break; - case 0x06: /* LW.bi */ - imm = 0; - regular = 0; - load = 1; - len = 4; - sign_ext = 0; - break; - case 0x09: /* SH */ - imm = 0; - regular = 1; - load = 0; - len = 2; - sign_ext = 0; - break; - case 0x0D: /* SH.bi */ - imm = 0; - regular = 0; - load = 0; - len = 2; - sign_ext = 0; - break; - case 0x0A: /* SW */ - imm = 0; - regular = 1; - load = 0; - len = 4; - sign_ext = 0; - break; - case 0x0E: /* SW.bi */ - imm = 0; - regular = 0; - load = 0; - len = 4; - sign_ext = 0; - break; - - default: - return -EFAULT; - } - } - - if (imm) - shift = GET_IMMSVAL(IMM(inst)) * len; - else - shift = *idx_to_addr(regs, RB(inst)) << SV(inst); - - if (regular) - unaligned_addr += shift; - - if (load) { - - if (!access_ok((void *)unaligned_addr, len)) - return -EACCES; - - get_data(unaligned_addr, &target_val, len); - - if (sign_ext) - *idx_to_addr(regs, RT(inst)) = - sign_extend(target_val, len); - else - *idx_to_addr(regs, RT(inst)) = target_val; - } else { - - if (!access_ok((void *)unaligned_addr, len)) - return -EACCES; - - target_val = *idx_to_addr(regs, RT(inst)); - set_data((void *)unaligned_addr, target_val, len); - } - - if (!regular) - *idx_to_addr(regs, RA(inst)) = unaligned_addr + shift; - - regs->ipc += 4; - - return 0; -fault: - return -EACCES; -} - -int do_unaligned_access(unsigned long addr, struct pt_regs *regs) -{ - unsigned long inst; - int ret = -EFAULT; - - inst = get_inst(regs->ipc); - - DEBUG((unalign_access_debug > 0), 1, - "Faulting addr: 0x%08lx, pc: 0x%08lx [inst: 0x%08lx ]\n", addr, - regs->ipc, inst); - - if (inst & NDS32_16BIT_INSTRUCTION) - ret = do_16((inst >> 16) & 0xffff, regs); - else - ret = do_32(inst, regs); - - return ret; -} - -#ifdef CONFIG_PROC_FS - -static struct ctl_table alignment_tbl[3] = { - { - .procname = "enable", - .data = &unalign_access_mode, - .maxlen = sizeof(unalign_access_mode), - .mode = 0666, - .proc_handler = &proc_dointvec - } - , - { - .procname = "debug_info", - .data = &unalign_access_debug, - .maxlen = sizeof(unalign_access_debug), - .mode = 0644, - .proc_handler = &proc_dointvec - } - , - {} -}; - -static struct ctl_table nds32_sysctl_table[2] = { - { - .procname = "unaligned_access", - .mode = 0555, - .child = alignment_tbl}, - {} -}; - -static struct ctl_path nds32_path[2] = { - {.procname = "nds32"}, - {} -}; - -/* - * Initialize nds32 alignment-correction interface - */ -static int __init nds32_sysctl_init(void) -{ - register_sysctl_paths(nds32_path, nds32_sysctl_table); - return 0; -} - -__initcall(nds32_sysctl_init); -#endif /* CONFIG_PROC_FS */ diff --git a/arch/nds32/mm/cacheflush.c b/arch/nds32/mm/cacheflush.c deleted file mode 100644 index 07aac65d1cab..000000000000 --- a/arch/nds32/mm/cacheflush.c +++ /dev/null @@ -1,338 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct cache_info L1_cache_info[2]; - -void flush_icache_range(unsigned long start, unsigned long end) -{ - unsigned long line_size, flags; - line_size = L1_cache_info[DCACHE].line_size; - start = start & ~(line_size - 1); - end = (end + line_size - 1) & ~(line_size - 1); - local_irq_save(flags); - cpu_cache_wbinval_range(start, end, 1); - local_irq_restore(flags); -} -EXPORT_SYMBOL(flush_icache_range); - -void flush_icache_page(struct vm_area_struct *vma, struct page *page) -{ - unsigned long flags; - unsigned long kaddr; - local_irq_save(flags); - kaddr = (unsigned long)kmap_atomic(page); - cpu_cache_wbinval_page(kaddr, vma->vm_flags & VM_EXEC); - kunmap_atomic((void *)kaddr); - local_irq_restore(flags); -} - -void flush_icache_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long addr, int len) -{ - unsigned long kaddr; - kaddr = (unsigned long)kmap_atomic(page) + (addr & ~PAGE_MASK); - flush_icache_range(kaddr, kaddr + len); - kunmap_atomic((void *)kaddr); -} - -void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, - pte_t * pte) -{ - struct page *page; - unsigned long pfn = pte_pfn(*pte); - unsigned long flags; - - if (!pfn_valid(pfn)) - return; - - if (vma->vm_mm == current->active_mm) { - local_irq_save(flags); - __nds32__mtsr_dsb(addr, NDS32_SR_TLB_VPN); - __nds32__tlbop_rwr(*pte); - __nds32__isb(); - local_irq_restore(flags); - } - page = pfn_to_page(pfn); - - if ((test_and_clear_bit(PG_dcache_dirty, &page->flags)) || - (vma->vm_flags & VM_EXEC)) { - unsigned long kaddr; - local_irq_save(flags); - kaddr = (unsigned long)kmap_atomic(page); - cpu_cache_wbinval_page(kaddr, vma->vm_flags & VM_EXEC); - kunmap_atomic((void *)kaddr); - local_irq_restore(flags); - } -} -#ifdef CONFIG_CPU_CACHE_ALIASING -extern pte_t va_present(struct mm_struct *mm, unsigned long addr); - -static inline unsigned long aliasing(unsigned long addr, unsigned long page) -{ - return ((addr & PAGE_MASK) ^ page) & (SHMLBA - 1); -} - -static inline unsigned long kremap0(unsigned long uaddr, unsigned long pa) -{ - unsigned long kaddr, pte; - -#define BASE_ADDR0 0xffffc000 - kaddr = BASE_ADDR0 | (uaddr & L1_cache_info[DCACHE].aliasing_mask); - pte = (pa | PAGE_KERNEL); - __nds32__mtsr_dsb(kaddr, NDS32_SR_TLB_VPN); - __nds32__tlbop_rwlk(pte); - __nds32__isb(); - return kaddr; -} - -static inline void kunmap01(unsigned long kaddr) -{ - __nds32__tlbop_unlk(kaddr); - __nds32__tlbop_inv(kaddr); - __nds32__isb(); -} - -static inline unsigned long kremap1(unsigned long uaddr, unsigned long pa) -{ - unsigned long kaddr, pte; - -#define BASE_ADDR1 0xffff8000 - kaddr = BASE_ADDR1 | (uaddr & L1_cache_info[DCACHE].aliasing_mask); - pte = (pa | PAGE_KERNEL); - __nds32__mtsr_dsb(kaddr, NDS32_SR_TLB_VPN); - __nds32__tlbop_rwlk(pte); - __nds32__isb(); - return kaddr; -} - -void flush_cache_mm(struct mm_struct *mm) -{ - unsigned long flags; - - local_irq_save(flags); - cpu_dcache_wbinval_all(); - cpu_icache_inval_all(); - local_irq_restore(flags); -} - -void flush_cache_dup_mm(struct mm_struct *mm) -{ -} - -void flush_cache_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - unsigned long flags; - - if ((end - start) > 8 * PAGE_SIZE) { - cpu_dcache_wbinval_all(); - if (vma->vm_flags & VM_EXEC) - cpu_icache_inval_all(); - return; - } - local_irq_save(flags); - while (start < end) { - if (va_present(vma->vm_mm, start)) - cpu_cache_wbinval_page(start, vma->vm_flags & VM_EXEC); - start += PAGE_SIZE; - } - local_irq_restore(flags); - return; -} - -void flush_cache_page(struct vm_area_struct *vma, - unsigned long addr, unsigned long pfn) -{ - unsigned long vto, flags; - - local_irq_save(flags); - vto = kremap0(addr, pfn << PAGE_SHIFT); - cpu_cache_wbinval_page(vto, vma->vm_flags & VM_EXEC); - kunmap01(vto); - local_irq_restore(flags); -} - -void flush_cache_vmap(unsigned long start, unsigned long end) -{ - cpu_dcache_wbinval_all(); - cpu_icache_inval_all(); -} - -void flush_cache_vunmap(unsigned long start, unsigned long end) -{ - cpu_dcache_wbinval_all(); - cpu_icache_inval_all(); -} - -void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, - struct page *to) -{ - cpu_dcache_wbinval_page((unsigned long)vaddr); - cpu_icache_inval_page((unsigned long)vaddr); - copy_page(vto, vfrom); - cpu_dcache_wbinval_page((unsigned long)vto); - cpu_icache_inval_page((unsigned long)vto); -} - -void clear_user_page(void *addr, unsigned long vaddr, struct page *page) -{ - cpu_dcache_wbinval_page((unsigned long)vaddr); - cpu_icache_inval_page((unsigned long)vaddr); - clear_page(addr); - cpu_dcache_wbinval_page((unsigned long)addr); - cpu_icache_inval_page((unsigned long)addr); -} - -void copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr, struct vm_area_struct *vma) -{ - unsigned long vto, vfrom, flags, kto, kfrom, pfrom, pto; - kto = ((unsigned long)page_address(to) & PAGE_MASK); - kfrom = ((unsigned long)page_address(from) & PAGE_MASK); - pto = page_to_phys(to); - pfrom = page_to_phys(from); - - local_irq_save(flags); - if (aliasing(vaddr, (unsigned long)kfrom)) - cpu_dcache_wb_page((unsigned long)kfrom); - vto = kremap0(vaddr, pto); - vfrom = kremap1(vaddr, pfrom); - copy_page((void *)vto, (void *)vfrom); - kunmap01(vfrom); - kunmap01(vto); - local_irq_restore(flags); -} - -EXPORT_SYMBOL(copy_user_highpage); - -void clear_user_highpage(struct page *page, unsigned long vaddr) -{ - unsigned long vto, flags, kto; - - kto = ((unsigned long)page_address(page) & PAGE_MASK); - - local_irq_save(flags); - if (aliasing(kto, vaddr) && kto != 0) { - cpu_dcache_inval_page(kto); - cpu_icache_inval_page(kto); - } - vto = kremap0(vaddr, page_to_phys(page)); - clear_page((void *)vto); - kunmap01(vto); - local_irq_restore(flags); -} - -EXPORT_SYMBOL(clear_user_highpage); - -void flush_dcache_page(struct page *page) -{ - struct address_space *mapping; - - mapping = page_mapping_file(page); - if (mapping && !mapping_mapped(mapping)) - set_bit(PG_dcache_dirty, &page->flags); - else { - unsigned long kaddr, flags; - - kaddr = (unsigned long)page_address(page); - local_irq_save(flags); - cpu_dcache_wbinval_page(kaddr); - if (mapping) { - unsigned long vaddr, kto; - - vaddr = page->index << PAGE_SHIFT; - if (aliasing(vaddr, kaddr)) { - kto = kremap0(vaddr, page_to_phys(page)); - cpu_dcache_wbinval_page(kto); - kunmap01(kto); - } - } - local_irq_restore(flags); - } -} -EXPORT_SYMBOL(flush_dcache_page); - -void copy_to_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, void *src, int len) -{ - unsigned long line_size, start, end, vto, flags; - - local_irq_save(flags); - vto = kremap0(vaddr, page_to_phys(page)); - dst = (void *)(vto | (vaddr & (PAGE_SIZE - 1))); - memcpy(dst, src, len); - if (vma->vm_flags & VM_EXEC) { - line_size = L1_cache_info[DCACHE].line_size; - start = (unsigned long)dst & ~(line_size - 1); - end = - ((unsigned long)dst + len + line_size - 1) & ~(line_size - - 1); - cpu_cache_wbinval_range(start, end, 1); - } - kunmap01(vto); - local_irq_restore(flags); -} - -void copy_from_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, void *src, int len) -{ - unsigned long vto, flags; - - local_irq_save(flags); - vto = kremap0(vaddr, page_to_phys(page)); - src = (void *)(vto | (vaddr & (PAGE_SIZE - 1))); - memcpy(dst, src, len); - kunmap01(vto); - local_irq_restore(flags); -} - -void flush_anon_page(struct vm_area_struct *vma, - struct page *page, unsigned long vaddr) -{ - unsigned long kaddr, flags, ktmp; - if (!PageAnon(page)) - return; - - if (vma->vm_mm != current->active_mm) - return; - - local_irq_save(flags); - if (vma->vm_flags & VM_EXEC) - cpu_icache_inval_page(vaddr & PAGE_MASK); - kaddr = (unsigned long)page_address(page); - if (aliasing(vaddr, kaddr)) { - ktmp = kremap0(vaddr, page_to_phys(page)); - cpu_dcache_wbinval_page(ktmp); - kunmap01(ktmp); - } - local_irq_restore(flags); -} - -void flush_kernel_vmap_range(void *addr, int size) -{ - unsigned long flags; - local_irq_save(flags); - cpu_dcache_wb_range((unsigned long)addr, (unsigned long)addr + size); - local_irq_restore(flags); -} -EXPORT_SYMBOL(flush_kernel_vmap_range); - -void invalidate_kernel_vmap_range(void *addr, int size) -{ - unsigned long flags; - local_irq_save(flags); - cpu_dcache_inval_range((unsigned long)addr, (unsigned long)addr + size); - local_irq_restore(flags); -} -EXPORT_SYMBOL(invalidate_kernel_vmap_range); -#endif diff --git a/arch/nds32/mm/extable.c b/arch/nds32/mm/extable.c deleted file mode 100644 index db7f0a7c8966..000000000000 --- a/arch/nds32/mm/extable.c +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include - -int fixup_exception(struct pt_regs *regs) -{ - const struct exception_table_entry *fixup; - - fixup = search_exception_tables(instruction_pointer(regs)); - if (fixup) - regs->ipc = fixup->fixup; - - return fixup != NULL; -} diff --git a/arch/nds32/mm/fault.c b/arch/nds32/mm/fault.c deleted file mode 100644 index 636977a1c8b9..000000000000 --- a/arch/nds32/mm/fault.c +++ /dev/null @@ -1,396 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -extern void __noreturn die(const char *str, struct pt_regs *regs, long err); - -/* - * This is useful to dump out the page tables associated with - * 'addr' in mm 'mm'. - */ -void show_pte(struct mm_struct *mm, unsigned long addr) -{ - pgd_t *pgd; - if (!mm) - mm = &init_mm; - - pr_alert("pgd = %p\n", mm->pgd); - pgd = pgd_offset(mm, addr); - pr_alert("[%08lx] *pgd=%08lx", addr, pgd_val(*pgd)); - - do { - p4d_t *p4d; - pud_t *pud; - pmd_t *pmd; - - if (pgd_none(*pgd)) - break; - - if (pgd_bad(*pgd)) { - pr_alert("(bad)"); - break; - } - - p4d = p4d_offset(pgd, addr); - pud = pud_offset(p4d, addr); - pmd = pmd_offset(pud, addr); -#if PTRS_PER_PMD != 1 - pr_alert(", *pmd=%08lx", pmd_val(*pmd)); -#endif - - if (pmd_none(*pmd)) - break; - - if (pmd_bad(*pmd)) { - pr_alert("(bad)"); - break; - } - - if (IS_ENABLED(CONFIG_HIGHMEM)) - { - pte_t *pte; - /* We must not map this if we have highmem enabled */ - pte = pte_offset_map(pmd, addr); - pr_alert(", *pte=%08lx", pte_val(*pte)); - pte_unmap(pte); - } - } while (0); - - pr_alert("\n"); -} - -void do_page_fault(unsigned long entry, unsigned long addr, - unsigned int error_code, struct pt_regs *regs) -{ - struct task_struct *tsk; - struct mm_struct *mm; - struct vm_area_struct *vma; - int si_code; - vm_fault_t fault; - unsigned int mask = VM_ACCESS_FLAGS; - unsigned int flags = FAULT_FLAG_DEFAULT; - - error_code = error_code & (ITYPE_mskINST | ITYPE_mskETYPE); - tsk = current; - mm = tsk->mm; - si_code = SEGV_MAPERR; - /* - * We fault-in kernel-space virtual memory on-demand. The - * 'reference' page table is init_mm.pgd. - * - * NOTE! We MUST NOT take any locks for this case. We may - * be in an interrupt or a critical region, and should - * only copy the information from the master page table, - * nothing more. - */ - if (addr >= TASK_SIZE) { - if (user_mode(regs)) - goto bad_area_nosemaphore; - - if (addr >= TASK_SIZE && addr < VMALLOC_END - && (entry == ENTRY_PTE_NOT_PRESENT)) - goto vmalloc_fault; - else - goto no_context; - } - - /* Send a signal to the task for handling the unalignment access. */ - if (entry == ENTRY_GENERAL_EXCPETION - && error_code == ETYPE_ALIGNMENT_CHECK) { - if (user_mode(regs)) - goto bad_area_nosemaphore; - else - goto no_context; - } - - /* - * If we're in an interrupt or have no user - * context, we must not take the fault.. - */ - if (unlikely(faulthandler_disabled() || !mm)) - goto no_context; - - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); - - /* - * As per x86, we may deadlock here. However, since the kernel only - * validly references user space from well defined areas of the code, - * we can bug out early if this is from code which shouldn't. - */ - if (unlikely(!mmap_read_trylock(mm))) { - if (!user_mode(regs) && - !search_exception_tables(instruction_pointer(regs))) - goto no_context; -retry: - mmap_read_lock(mm); - } else { - /* - * The above down_read_trylock() might have succeeded in which - * case, we'll have missed the might_sleep() from down_read(). - */ - might_sleep(); - if (IS_ENABLED(CONFIG_DEBUG_VM)) { - if (!user_mode(regs) && - !search_exception_tables(instruction_pointer(regs))) - goto no_context; - } - } - - vma = find_vma(mm, addr); - - if (unlikely(!vma)) - goto bad_area; - - if (vma->vm_start <= addr) - goto good_area; - - if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) - goto bad_area; - - if (unlikely(expand_stack(vma, addr))) - goto bad_area; - - /* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ - -good_area: - si_code = SEGV_ACCERR; - - /* first do some preliminary protection checks */ - if (entry == ENTRY_PTE_NOT_PRESENT) { - if (error_code & ITYPE_mskINST) - mask = VM_EXEC; - else { - mask = VM_READ | VM_WRITE; - } - } else if (entry == ENTRY_TLB_MISC) { - switch (error_code & ITYPE_mskETYPE) { - case RD_PROT: - mask = VM_READ; - break; - case WRT_PROT: - mask = VM_WRITE; - flags |= FAULT_FLAG_WRITE; - break; - case NOEXEC: - mask = VM_EXEC; - break; - case PAGE_MODIFY: - mask = VM_WRITE; - flags |= FAULT_FLAG_WRITE; - break; - case ACC_BIT: - BUG(); - default: - break; - } - - } - if (!(vma->vm_flags & mask)) - goto bad_area; - - /* - * If for any reason at all we couldn't handle the fault, - * make sure we exit gracefully rather than endlessly redo - * the fault. - */ - - fault = handle_mm_fault(vma, addr, flags, regs); - - /* - * If we need to retry but a fatal signal is pending, handle the - * signal first. We do not need to release the mmap_lock because it - * would already be released in __lock_page_or_retry in mm/filemap.c. - */ - if (fault_signal_pending(fault, regs)) { - if (!user_mode(regs)) - goto no_context; - return; - } - - if (unlikely(fault & VM_FAULT_ERROR)) { - if (fault & VM_FAULT_OOM) - goto out_of_memory; - else if (fault & VM_FAULT_SIGBUS) - goto do_sigbus; - else - goto bad_area; - } - - if (fault & VM_FAULT_RETRY) { - flags |= FAULT_FLAG_TRIED; - - /* No need to mmap_read_unlock(mm) as we would - * have already released it in __lock_page_or_retry - * in mm/filemap.c. - */ - goto retry; - } - - mmap_read_unlock(mm); - return; - - /* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - mmap_read_unlock(mm); - -bad_area_nosemaphore: - - /* User mode accesses just cause a SIGSEGV */ - - if (user_mode(regs)) { - tsk->thread.address = addr; - tsk->thread.error_code = error_code; - tsk->thread.trap_no = entry; - force_sig_fault(SIGSEGV, si_code, (void __user *)addr); - return; - } - -no_context: - - /* Are we prepared to handle this kernel fault? - * - * (The kernel has valid exception-points in the source - * when it acesses user-memory. When it fails in one - * of those points, we find it in a table and do a jump - * to some fixup code that loads an appropriate error - * code) - */ - - { - const struct exception_table_entry *entry; - - if ((entry = - search_exception_tables(instruction_pointer(regs))) != - NULL) { - /* Adjust the instruction pointer in the stackframe */ - instruction_pointer(regs) = entry->fixup; - return; - } - } - - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - - bust_spinlocks(1); - pr_alert("Unable to handle kernel %s at virtual address %08lx\n", - (addr < PAGE_SIZE) ? "NULL pointer dereference" : - "paging request", addr); - - show_pte(mm, addr); - die("Oops", regs, error_code); - - /* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ - -out_of_memory: - mmap_read_unlock(mm); - if (!user_mode(regs)) - goto no_context; - pagefault_out_of_memory(); - return; - -do_sigbus: - mmap_read_unlock(mm); - - /* Kernel mode? Handle exceptions or die */ - if (!user_mode(regs)) - goto no_context; - - /* - * Send a sigbus - */ - tsk->thread.address = addr; - tsk->thread.error_code = error_code; - tsk->thread.trap_no = entry; - force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)addr); - - return; - -vmalloc_fault: - { - /* - * Synchronize this task's top level page-table - * with the 'reference' page table. - * - * Use current_pgd instead of tsk->active_mm->pgd - * since the latter might be unavailable if this - * code is executed in a misfortunately run irq - * (like inside schedule() between switch_mm and - * switch_to...). - */ - - unsigned int index = pgd_index(addr); - pgd_t *pgd, *pgd_k; - p4d_t *p4d, *p4d_k; - pud_t *pud, *pud_k; - pmd_t *pmd, *pmd_k; - pte_t *pte_k; - - pgd = (pgd_t *) __va(__nds32__mfsr(NDS32_SR_L1_PPTB)) + index; - pgd_k = init_mm.pgd + index; - - if (!pgd_present(*pgd_k)) - goto no_context; - - p4d = p4d_offset(pgd, addr); - p4d_k = p4d_offset(pgd_k, addr); - if (!p4d_present(*p4d_k)) - goto no_context; - - pud = pud_offset(p4d, addr); - pud_k = pud_offset(p4d_k, addr); - if (!pud_present(*pud_k)) - goto no_context; - - pmd = pmd_offset(pud, addr); - pmd_k = pmd_offset(pud_k, addr); - if (!pmd_present(*pmd_k)) - goto no_context; - - if (!pmd_present(*pmd)) - set_pmd(pmd, *pmd_k); - else - BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); - - /* - * Since the vmalloc area is global, we don't - * need to copy individual PTE's, it is enough to - * copy the pgd pointer into the pte page of the - * root task. If that is there, we'll find our pte if - * it exists. - */ - - /* Make sure the actual PTE exists as well to - * catch kernel vmalloc-area accesses to non-mapped - * addres. If we don't do this, this will just - * silently loop forever. - */ - - pte_k = pte_offset_kernel(pmd_k, addr); - if (!pte_present(*pte_k)) - goto no_context; - - return; - } -} diff --git a/arch/nds32/mm/init.c b/arch/nds32/mm/init.c deleted file mode 100644 index f63f839738c4..000000000000 --- a/arch/nds32/mm/init.c +++ /dev/null @@ -1,263 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 1995-2005 Russell King -// Copyright (C) 2012 ARM Ltd. -// Copyright (C) 2013-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); -DEFINE_SPINLOCK(anon_alias_lock); -extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; - -/* - * empty_zero_page is a special page that is used for - * zero-initialized data and COW. - */ -struct page *empty_zero_page; -EXPORT_SYMBOL(empty_zero_page); - -static void __init zone_sizes_init(void) -{ - unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 }; - - max_zone_pfn[ZONE_NORMAL] = max_low_pfn; -#ifdef CONFIG_HIGHMEM - max_zone_pfn[ZONE_HIGHMEM] = max_pfn; -#endif - free_area_init(max_zone_pfn); - -} - -/* - * Map all physical memory under high_memory into kernel's address space. - * - * This is explicitly coded for two-level page tables, so if you need - * something else then this needs to change. - */ -static void __init map_ram(void) -{ - unsigned long v, p, e; - pgd_t *pge; - p4d_t *p4e; - pud_t *pue; - pmd_t *pme; - pte_t *pte; - /* These mark extents of read-only kernel pages... - * ...from vmlinux.lds.S - */ - - p = (u32) memblock_start_of_DRAM() & PAGE_MASK; - e = min((u32) memblock_end_of_DRAM(), (u32) __pa(high_memory)); - - v = (u32) __va(p); - pge = pgd_offset_k(v); - - while (p < e) { - int j; - p4e = p4d_offset(pge, v); - pue = pud_offset(p4e, v); - pme = pmd_offset(pue, v); - - if ((u32) pue != (u32) pge || (u32) pme != (u32) pge) { - panic("%s: Kernel hardcoded for " - "two-level page tables", __func__); - } - - /* Alloc one page for holding PTE's... */ - pte = memblock_alloc(PAGE_SIZE, PAGE_SIZE); - if (!pte) - panic("%s: Failed to allocate %lu bytes align=0x%lx\n", - __func__, PAGE_SIZE, PAGE_SIZE); - set_pmd(pme, __pmd(__pa(pte) + _PAGE_KERNEL_TABLE)); - - /* Fill the newly allocated page with PTE'S */ - for (j = 0; p < e && j < PTRS_PER_PTE; - v += PAGE_SIZE, p += PAGE_SIZE, j++, pte++) { - /* Create mapping between p and v. */ - /* TODO: more fine grant for page access permission */ - set_pte(pte, __pte(p + pgprot_val(PAGE_KERNEL))); - } - - pge++; - } -} -static pmd_t *fixmap_pmd_p; -static void __init fixedrange_init(void) -{ - unsigned long vaddr; - pmd_t *pmd; -#ifdef CONFIG_HIGHMEM - pte_t *pte; -#endif /* CONFIG_HIGHMEM */ - - /* - * Fixed mappings: - */ - vaddr = __fix_to_virt(__end_of_fixed_addresses - 1); - pmd = pmd_off_k(vaddr); - fixmap_pmd_p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); - if (!fixmap_pmd_p) - panic("%s: Failed to allocate %lu bytes align=0x%lx\n", - __func__, PAGE_SIZE, PAGE_SIZE); - set_pmd(pmd, __pmd(__pa(fixmap_pmd_p) + _PAGE_KERNEL_TABLE)); - -#ifdef CONFIG_HIGHMEM - /* - * Permanent kmaps: - */ - vaddr = PKMAP_BASE; - - pmd = pmd_off_k(vaddr); - pte = memblock_alloc(PAGE_SIZE, PAGE_SIZE); - if (!pte) - panic("%s: Failed to allocate %lu bytes align=0x%lx\n", - __func__, PAGE_SIZE, PAGE_SIZE); - set_pmd(pmd, __pmd(__pa(pte) + _PAGE_KERNEL_TABLE)); - pkmap_page_table = pte; -#endif /* CONFIG_HIGHMEM */ -} - -/* - * paging_init() sets up the page tables, initialises the zone memory - * maps, and sets up the zero page, bad page and bad page tables. - */ -void __init paging_init(void) -{ - int i; - void *zero_page; - - pr_info("Setting up paging and PTEs.\n"); - /* clear out the init_mm.pgd that will contain the kernel's mappings */ - for (i = 0; i < PTRS_PER_PGD; i++) - swapper_pg_dir[i] = __pgd(1); - - map_ram(); - - fixedrange_init(); - - /* allocate space for empty_zero_page */ - zero_page = memblock_alloc(PAGE_SIZE, PAGE_SIZE); - if (!zero_page) - panic("%s: Failed to allocate %lu bytes align=0x%lx\n", - __func__, PAGE_SIZE, PAGE_SIZE); - zone_sizes_init(); - - empty_zero_page = virt_to_page(zero_page); - flush_dcache_page(empty_zero_page); -} - -static inline void __init free_highmem(void) -{ -#ifdef CONFIG_HIGHMEM - unsigned long pfn; - for (pfn = PFN_UP(__pa(high_memory)); pfn < max_pfn; pfn++) { - phys_addr_t paddr = (phys_addr_t) pfn << PAGE_SHIFT; - if (!memblock_is_reserved(paddr)) - free_highmem_page(pfn_to_page(pfn)); - } -#endif -} - -static void __init set_max_mapnr_init(void) -{ - max_mapnr = max_pfn; -} - -/* - * mem_init() marks the free areas in the mem_map and tells us how much - * memory is free. This is done after various parts of the system have - * claimed their memory after the kernel image. - */ -void __init mem_init(void) -{ - phys_addr_t memory_start = memblock_start_of_DRAM(); - BUG_ON(!mem_map); - set_max_mapnr_init(); - - free_highmem(); - - /* this will put all low memory onto the freelists */ - memblock_free_all(); - - pr_info("virtual kernel memory layout:\n" - " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" -#ifdef CONFIG_HIGHMEM - " pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n" -#endif - " consist : 0x%08lx - 0x%08lx (%4ld MB)\n" - " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" - " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" - " .init : 0x%08lx - 0x%08lx (%4ld kB)\n" - " .data : 0x%08lx - 0x%08lx (%4ld kB)\n" - " .text : 0x%08lx - 0x%08lx (%4ld kB)\n", - FIXADDR_START, FIXADDR_TOP, (FIXADDR_TOP - FIXADDR_START) >> 10, -#ifdef CONFIG_HIGHMEM - PKMAP_BASE, PKMAP_BASE + LAST_PKMAP * PAGE_SIZE, - (LAST_PKMAP * PAGE_SIZE) >> 10, -#endif - CONSISTENT_BASE, CONSISTENT_END, - ((CONSISTENT_END) - (CONSISTENT_BASE)) >> 20, VMALLOC_START, - (unsigned long)VMALLOC_END, (VMALLOC_END - VMALLOC_START) >> 20, - (unsigned long)__va(memory_start), (unsigned long)high_memory, - ((unsigned long)high_memory - - (unsigned long)__va(memory_start)) >> 20, - (unsigned long)&__init_begin, (unsigned long)&__init_end, - ((unsigned long)&__init_end - - (unsigned long)&__init_begin) >> 10, (unsigned long)&_etext, - (unsigned long)&_edata, - ((unsigned long)&_edata - (unsigned long)&_etext) >> 10, - (unsigned long)&_text, (unsigned long)&_etext, - ((unsigned long)&_etext - (unsigned long)&_text) >> 10); - - /* - * Check boundaries twice: Some fundamental inconsistencies can - * be detected at build time already. - */ -#ifdef CONFIG_HIGHMEM - BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > FIXADDR_START); - BUILD_BUG_ON((CONSISTENT_END) > PKMAP_BASE); -#endif - BUILD_BUG_ON(VMALLOC_END > CONSISTENT_BASE); - BUILD_BUG_ON(VMALLOC_START >= VMALLOC_END); - -#ifdef CONFIG_HIGHMEM - BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > FIXADDR_START); - BUG_ON(CONSISTENT_END > PKMAP_BASE); -#endif - BUG_ON(VMALLOC_END > CONSISTENT_BASE); - BUG_ON(VMALLOC_START >= VMALLOC_END); - BUG_ON((unsigned long)high_memory > VMALLOC_START); - - return; -} - -void __set_fixmap(enum fixed_addresses idx, - phys_addr_t phys, pgprot_t flags) -{ - unsigned long addr = __fix_to_virt(idx); - pte_t *pte; - - BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses); - - pte = (pte_t *)&fixmap_pmd_p[pte_index(addr)]; - - if (pgprot_val(flags)) { - set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); - } else { - pte_clear(&init_mm, addr, pte); - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); - } -} diff --git a/arch/nds32/mm/mm-nds32.c b/arch/nds32/mm/mm-nds32.c deleted file mode 100644 index f2778f2b39f6..000000000000 --- a/arch/nds32/mm/mm-nds32.c +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include - -#define __HAVE_ARCH_PGD_FREE -#include - -#define FIRST_KERNEL_PGD_NR (USER_PTRS_PER_PGD) - -/* - * need to get a page for level 1 - */ - -pgd_t *pgd_alloc(struct mm_struct *mm) -{ - pgd_t *new_pgd, *init_pgd; - int i; - - new_pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, 0); - if (!new_pgd) - return NULL; - for (i = 0; i < PTRS_PER_PGD; i++) { - (*new_pgd) = 1; - new_pgd++; - } - new_pgd -= PTRS_PER_PGD; - - init_pgd = pgd_offset_k(0); - - memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, - (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); - - cpu_dcache_wb_range((unsigned long)new_pgd, - (unsigned long)new_pgd + - PTRS_PER_PGD * sizeof(pgd_t)); - inc_lruvec_page_state(virt_to_page((unsigned long *)new_pgd), - NR_PAGETABLE); - - return new_pgd; -} - -void pgd_free(struct mm_struct *mm, pgd_t * pgd) -{ - pmd_t *pmd; - struct page *pte; - - if (!pgd) - return; - - pmd = (pmd_t *) pgd; - if (pmd_none(*pmd)) - goto free; - if (pmd_bad(*pmd)) { - pmd_ERROR(*pmd); - pmd_clear(pmd); - goto free; - } - - pte = pmd_page(*pmd); - pmd_clear(pmd); - dec_lruvec_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE); - pte_free(mm, pte); - mm_dec_nr_ptes(mm); - pmd_free(mm, pmd); -free: - free_pages((unsigned long)pgd, 0); -} - -/* - * In order to soft-boot, we need to insert a 1:1 mapping in place of - * the user-mode pages. This will then ensure that we have predictable - * results when turning the mmu off - */ -void setup_mm_for_reboot(char mode) -{ - unsigned long pmdval; - pgd_t *pgd; - p4d_t *p4d; - pud_t *pud; - pmd_t *pmd; - int i; - - if (current->mm && current->mm->pgd) - pgd = current->mm->pgd; - else - pgd = init_mm.pgd; - - for (i = 0; i < USER_PTRS_PER_PGD; i++) { - pmdval = (i << PGDIR_SHIFT); - p4d = p4d_offset(pgd, i << PGDIR_SHIFT); - pud = pud_offset(p4d, i << PGDIR_SHIFT); - pmd = pmd_offset(pud + i, i << PGDIR_SHIFT); - set_pmd(pmd, __pmd(pmdval)); - } -} diff --git a/arch/nds32/mm/mmap.c b/arch/nds32/mm/mmap.c deleted file mode 100644 index 1bdf5e7d1b43..000000000000 --- a/arch/nds32/mm/mmap.c +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include - -#define COLOUR_ALIGN(addr,pgoff) \ - ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ - (((pgoff)<mm; - struct vm_area_struct *vma; - int do_align = 0; - struct vm_unmapped_area_info info; - int aliasing = 0; - if(IS_ENABLED(CONFIG_CPU_CACHE_ALIASING)) - aliasing = 1; - - /* - * We only need to do colour alignment if either the I or D - * caches alias. - */ - if (aliasing) - do_align = filp || (flags & MAP_SHARED); - - /* - * We enforce the MAP_FIXED case. - */ - if (flags & MAP_FIXED) { - if (aliasing && flags & MAP_SHARED && - (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)) - return -EINVAL; - return addr; - } - - if (len > TASK_SIZE) - return -ENOMEM; - - if (addr) { - if (do_align) - addr = COLOUR_ALIGN(addr, pgoff); - else - addr = PAGE_ALIGN(addr); - - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - - info.flags = 0; - info.length = len; - info.low_limit = mm->mmap_base; - info.high_limit = TASK_SIZE; - info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; - info.align_offset = pgoff << PAGE_SHIFT; - return vm_unmapped_area(&info); -} diff --git a/arch/nds32/mm/proc.c b/arch/nds32/mm/proc.c deleted file mode 100644 index 848c845f5f33..000000000000 --- a/arch/nds32/mm/proc.c +++ /dev/null @@ -1,536 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -extern struct cache_info L1_cache_info[2]; - -int va_kernel_present(unsigned long addr) -{ - pmd_t *pmd; - pte_t *ptep, pte; - - pmd = pmd_off_k(addr); - if (!pmd_none(*pmd)) { - ptep = pte_offset_map(pmd, addr); - pte = *ptep; - if (pte_present(pte)) - return pte; - } - return 0; -} - -pte_t va_present(struct mm_struct * mm, unsigned long addr) -{ - pgd_t *pgd; - p4d_t *p4d; - pud_t *pud; - pmd_t *pmd; - pte_t *ptep, pte; - - pgd = pgd_offset(mm, addr); - if (!pgd_none(*pgd)) { - p4d = p4d_offset(pgd, addr); - if (!p4d_none(*p4d)) { - pud = pud_offset(p4d, addr); - if (!pud_none(*pud)) { - pmd = pmd_offset(pud, addr); - if (!pmd_none(*pmd)) { - ptep = pte_offset_map(pmd, addr); - pte = *ptep; - if (pte_present(pte)) - return pte; - } - } - } - } - return 0; - -} - -int va_readable(struct pt_regs *regs, unsigned long addr) -{ - struct mm_struct *mm = current->mm; - pte_t pte; - int ret = 0; - - if (user_mode(regs)) { - /* user mode */ - pte = va_present(mm, addr); - if (!pte && pte_read(pte)) - ret = 1; - } else { - /* superuser mode is always readable, so we can only - * check it is present or not*/ - return (! !va_kernel_present(addr)); - } - return ret; -} - -int va_writable(struct pt_regs *regs, unsigned long addr) -{ - struct mm_struct *mm = current->mm; - pte_t pte; - int ret = 0; - - if (user_mode(regs)) { - /* user mode */ - pte = va_present(mm, addr); - if (!pte && pte_write(pte)) - ret = 1; - } else { - /* superuser mode */ - pte = va_kernel_present(addr); - if (!pte && pte_kernel_write(pte)) - ret = 1; - } - return ret; -} - -/* - * All - */ -void cpu_icache_inval_all(void) -{ - unsigned long end, line_size; - - line_size = L1_cache_info[ICACHE].line_size; - end = - line_size * L1_cache_info[ICACHE].ways * L1_cache_info[ICACHE].sets; - - do { - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); - } while (end > 0); - __nds32__isb(); -} - -void cpu_dcache_inval_all(void) -{ - __nds32__cctl_l1d_invalall(); -} - -#ifdef CONFIG_CACHE_L2 -void dcache_wb_all_level(void) -{ - unsigned long flags, cmd; - local_irq_save(flags); - __nds32__cctl_l1d_wball_alvl(); - /* Section 1: Ensure the section 2 & 3 program code execution after */ - __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); - - /* Section 2: Confirm the writeback all level is done in CPU and L2C */ - cmd = CCTL_CMD_L2_SYNC; - L2_CMD_RDY(); - L2C_W_REG(L2_CCTL_CMD_OFF, cmd); - L2_CMD_RDY(); - - /* Section 3: Writeback whole L2 cache */ - cmd = CCTL_ALL_CMD | CCTL_CMD_L2_IX_WB; - L2_CMD_RDY(); - L2C_W_REG(L2_CCTL_CMD_OFF, cmd); - L2_CMD_RDY(); - __nds32__msync_all(); - local_irq_restore(flags); -} -EXPORT_SYMBOL(dcache_wb_all_level); -#endif - -void cpu_dcache_wb_all(void) -{ - __nds32__cctl_l1d_wball_one_lvl(); - __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); -} - -void cpu_dcache_wbinval_all(void) -{ -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - unsigned long flags; - local_irq_save(flags); -#endif - cpu_dcache_wb_all(); - cpu_dcache_inval_all(); -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - local_irq_restore(flags); -#endif -} - -/* - * Page - */ -void cpu_icache_inval_page(unsigned long start) -{ - unsigned long line_size, end; - - line_size = L1_cache_info[ICACHE].line_size; - end = start + PAGE_SIZE; - - do { - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); - } while (end != start); - __nds32__isb(); -} - -void cpu_dcache_inval_page(unsigned long start) -{ - unsigned long line_size, end; - - line_size = L1_cache_info[DCACHE].line_size; - end = start + PAGE_SIZE; - - do { - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); - } while (end != start); -} - -void cpu_dcache_wb_page(unsigned long start) -{ -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - unsigned long line_size, end; - - line_size = L1_cache_info[DCACHE].line_size; - end = start + PAGE_SIZE; - - do { - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); - end -= line_size; - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); - } while (end != start); - __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); -#endif -} - -void cpu_dcache_wbinval_page(unsigned long start) -{ - unsigned long line_size, end; - - line_size = L1_cache_info[DCACHE].line_size; - end = start + PAGE_SIZE; - - do { - end -= line_size; -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); -#endif - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); - end -= line_size; -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); -#endif - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); - end -= line_size; -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); -#endif - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); - end -= line_size; -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); -#endif - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); - } while (end != start); - __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); -} - -void cpu_cache_wbinval_page(unsigned long page, int flushi) -{ - cpu_dcache_wbinval_page(page); - if (flushi) - cpu_icache_inval_page(page); -} - -/* - * Range - */ -void cpu_icache_inval_range(unsigned long start, unsigned long end) -{ - unsigned long line_size; - - line_size = L1_cache_info[ICACHE].line_size; - - while (end > start) { - __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (start)); - start += line_size; - } - __nds32__isb(); -} - -void cpu_dcache_inval_range(unsigned long start, unsigned long end) -{ - unsigned long line_size; - - line_size = L1_cache_info[DCACHE].line_size; - - while (end > start) { - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start)); - start += line_size; - } -} - -void cpu_dcache_wb_range(unsigned long start, unsigned long end) -{ -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - unsigned long line_size; - - line_size = L1_cache_info[DCACHE].line_size; - - while (end > start) { - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start)); - start += line_size; - } - __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); -#endif -} - -void cpu_dcache_wbinval_range(unsigned long start, unsigned long end) -{ - unsigned long line_size; - - line_size = L1_cache_info[DCACHE].line_size; - - while (end > start) { -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start)); -#endif - __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start)); - start += line_size; - } - __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); -} - -void cpu_cache_wbinval_range(unsigned long start, unsigned long end, int flushi) -{ - unsigned long line_size, align_start, align_end; - - line_size = L1_cache_info[DCACHE].line_size; - align_start = start & ~(line_size - 1); - align_end = (end + line_size - 1) & ~(line_size - 1); - cpu_dcache_wbinval_range(align_start, align_end); - - if (flushi) { - line_size = L1_cache_info[ICACHE].line_size; - align_start = start & ~(line_size - 1); - align_end = (end + line_size - 1) & ~(line_size - 1); - cpu_icache_inval_range(align_start, align_end); - } -} - -void cpu_cache_wbinval_range_check(struct vm_area_struct *vma, - unsigned long start, unsigned long end, - bool flushi, bool wbd) -{ - unsigned long line_size, t_start, t_end; - - if (!flushi && !wbd) - return; - line_size = L1_cache_info[DCACHE].line_size; - start = start & ~(line_size - 1); - end = (end + line_size - 1) & ~(line_size - 1); - - if ((end - start) > (8 * PAGE_SIZE)) { - if (wbd) - cpu_dcache_wbinval_all(); - if (flushi) - cpu_icache_inval_all(); - return; - } - - t_start = (start + PAGE_SIZE) & PAGE_MASK; - t_end = ((end - 1) & PAGE_MASK); - - if ((start & PAGE_MASK) == t_end) { - if (va_present(vma->vm_mm, start)) { - if (wbd) - cpu_dcache_wbinval_range(start, end); - if (flushi) - cpu_icache_inval_range(start, end); - } - return; - } - - if (va_present(vma->vm_mm, start)) { - if (wbd) - cpu_dcache_wbinval_range(start, t_start); - if (flushi) - cpu_icache_inval_range(start, t_start); - } - - if (va_present(vma->vm_mm, end - 1)) { - if (wbd) - cpu_dcache_wbinval_range(t_end, end); - if (flushi) - cpu_icache_inval_range(t_end, end); - } - - while (t_start < t_end) { - if (va_present(vma->vm_mm, t_start)) { - if (wbd) - cpu_dcache_wbinval_page(t_start); - if (flushi) - cpu_icache_inval_page(t_start); - } - t_start += PAGE_SIZE; - } -} - -#ifdef CONFIG_CACHE_L2 -static inline void cpu_l2cache_op(unsigned long start, unsigned long end, unsigned long op) -{ - if (atl2c_base) { - unsigned long p_start = __pa(start); - unsigned long p_end = __pa(end); - unsigned long cmd; - unsigned long line_size; - /* TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE */ - line_size = L2_CACHE_LINE_SIZE(); - p_start = p_start & (~(line_size - 1)); - p_end = (p_end + line_size - 1) & (~(line_size - 1)); - cmd = - (p_start & ~(line_size - 1)) | op | - CCTL_SINGLE_CMD; - do { - L2_CMD_RDY(); - L2C_W_REG(L2_CCTL_CMD_OFF, cmd); - cmd += line_size; - p_start += line_size; - } while (p_end > p_start); - cmd = CCTL_CMD_L2_SYNC; - L2_CMD_RDY(); - L2C_W_REG(L2_CCTL_CMD_OFF, cmd); - L2_CMD_RDY(); - } -} -#else -#define cpu_l2cache_op(start,end,op) do { } while (0) -#endif -/* - * DMA - */ -void cpu_dma_wb_range(unsigned long start, unsigned long end) -{ - unsigned long line_size; - unsigned long flags; - line_size = L1_cache_info[DCACHE].line_size; - start = start & (~(line_size - 1)); - end = (end + line_size - 1) & (~(line_size - 1)); - if (unlikely(start == end)) - return; - - local_irq_save(flags); - cpu_dcache_wb_range(start, end); - cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_WB); - __nds32__msync_all(); - local_irq_restore(flags); -} - -void cpu_dma_inval_range(unsigned long start, unsigned long end) -{ - unsigned long line_size; - unsigned long old_start = start; - unsigned long old_end = end; - unsigned long flags; - line_size = L1_cache_info[DCACHE].line_size; - start = start & (~(line_size - 1)); - end = (end + line_size - 1) & (~(line_size - 1)); - if (unlikely(start == end)) - return; - local_irq_save(flags); - if (start != old_start) { - cpu_dcache_wbinval_range(start, start + line_size); - cpu_l2cache_op(start, start + line_size, CCTL_CMD_L2_PA_WBINVAL); - } - if (end != old_end) { - cpu_dcache_wbinval_range(end - line_size, end); - cpu_l2cache_op(end - line_size, end, CCTL_CMD_L2_PA_WBINVAL); - } - cpu_dcache_inval_range(start, end); - cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_INVAL); - __nds32__msync_all(); - local_irq_restore(flags); - -} - -void cpu_dma_wbinval_range(unsigned long start, unsigned long end) -{ - unsigned long line_size; - unsigned long flags; - line_size = L1_cache_info[DCACHE].line_size; - start = start & (~(line_size - 1)); - end = (end + line_size - 1) & (~(line_size - 1)); - if (unlikely(start == end)) - return; - - local_irq_save(flags); - cpu_dcache_wbinval_range(start, end); - cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_WBINVAL); - __nds32__msync_all(); - local_irq_restore(flags); -} - -void cpu_proc_init(void) -{ -} - -void cpu_proc_fin(void) -{ -} - -void cpu_do_idle(void) -{ - __nds32__standby_no_wake_grant(); -} - -void cpu_reset(unsigned long reset) -{ - u32 tmp; - GIE_DISABLE(); - tmp = __nds32__mfsr(NDS32_SR_CACHE_CTL); - tmp &= ~(CACHE_CTL_mskIC_EN | CACHE_CTL_mskDC_EN); - __nds32__mtsr_isb(tmp, NDS32_SR_CACHE_CTL); - cpu_dcache_wbinval_all(); - cpu_icache_inval_all(); - - __asm__ __volatile__("jr.toff %0\n\t"::"r"(reset)); -} - -void cpu_switch_mm(struct mm_struct *mm) -{ - unsigned long cid; - cid = __nds32__mfsr(NDS32_SR_TLB_MISC); - cid = (cid & ~TLB_MISC_mskCID) | mm->context.id; - __nds32__mtsr_dsb(cid, NDS32_SR_TLB_MISC); - __nds32__mtsr_isb(__pa(mm->pgd), NDS32_SR_L1_PPTB); -} diff --git a/arch/nds32/mm/tlb.c b/arch/nds32/mm/tlb.c deleted file mode 100644 index dd41f5e0712f..000000000000 --- a/arch/nds32/mm/tlb.c +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include - -unsigned int cpu_last_cid = { TLB_MISC_mskCID + (2 << TLB_MISC_offCID) }; - -DEFINE_SPINLOCK(cid_lock); - -void local_flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - unsigned long flags, ocid, ncid; - - if ((end - start) > 0x400000) { - __nds32__tlbop_flua(); - __nds32__isb(); - return; - } - - spin_lock_irqsave(&cid_lock, flags); - ocid = __nds32__mfsr(NDS32_SR_TLB_MISC); - ncid = (ocid & ~TLB_MISC_mskCID) | vma->vm_mm->context.id; - __nds32__mtsr_dsb(ncid, NDS32_SR_TLB_MISC); - while (start < end) { - __nds32__tlbop_inv(start); - __nds32__isb(); - start += PAGE_SIZE; - } - __nds32__mtsr_dsb(ocid, NDS32_SR_TLB_MISC); - spin_unlock_irqrestore(&cid_lock, flags); -} - -void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) -{ - unsigned long flags, ocid, ncid; - - spin_lock_irqsave(&cid_lock, flags); - ocid = __nds32__mfsr(NDS32_SR_TLB_MISC); - ncid = (ocid & ~TLB_MISC_mskCID) | vma->vm_mm->context.id; - __nds32__mtsr_dsb(ncid, NDS32_SR_TLB_MISC); - __nds32__tlbop_inv(addr); - __nds32__isb(); - __nds32__mtsr_dsb(ocid, NDS32_SR_TLB_MISC); - spin_unlock_irqrestore(&cid_lock, flags); -} diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index cfb8ea0df3b1..ae95d06a4a8f 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -617,15 +617,6 @@ config CLKSRC_ST_LPC Enable this option to use the Low Power controller timer as clocksource. -config ATCPIT100_TIMER - bool "ATCPIT100 timer driver" - depends on NDS32 || COMPILE_TEST - depends on HAS_IOMEM - select TIMER_OF - default NDS32 - help - This option enables support for the Andestech ATCPIT100 timers. - config RISCV_TIMER bool "Timer for the RISC-V platform" if COMPILE_TEST depends on GENERIC_SCHED_CLOCK && RISCV && RISCV_SBI diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index fa5f624eadb6..9c85ee2bb373 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -81,7 +81,6 @@ obj-$(CONFIG_INGENIC_SYSOST) += ingenic-sysost.o obj-$(CONFIG_INGENIC_TIMER) += ingenic-timer.o obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o obj-$(CONFIG_X86_NUMACHIP) += numachip.o -obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o obj-$(CONFIG_CLINT_TIMER) += timer-clint.o obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o diff --git a/drivers/clocksource/timer-atcpit100.c b/drivers/clocksource/timer-atcpit100.c deleted file mode 100644 index b4bd2f5b801d..000000000000 --- a/drivers/clocksource/timer-atcpit100.c +++ /dev/null @@ -1,266 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation -/* - * Andestech ATCPIT100 Timer Device Driver Implementation - * Rick Chen, Andes Technology Corporation - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "timer-of.h" -#ifdef CONFIG_NDS32 -#include -#endif - -/* - * Definition of register offsets - */ - -/* ID and Revision Register */ -#define ID_REV 0x0 - -/* Configuration Register */ -#define CFG 0x10 - -/* Interrupt Enable Register */ -#define INT_EN 0x14 -#define CH_INT_EN(c, i) ((1<event_handler(evt); - - return IRQ_HANDLED; -} - -static struct timer_of to = { - .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE, - - .clkevt = { - .name = "atcpit100_tick", - .rating = 300, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_state_shutdown = atcpit100_clkevt_shutdown, - .set_state_periodic = atcpit100_clkevt_set_periodic, - .set_state_oneshot = atcpit100_clkevt_set_oneshot, - .tick_resume = atcpit100_clkevt_shutdown, - .set_next_event = atcpit100_clkevt_next_event, - .cpumask = cpu_possible_mask, - }, - - .of_irq = { - .handler = atcpit100_timer_interrupt, - .flags = IRQF_TIMER | IRQF_IRQPOLL, - }, - - /* - * FIXME: we currently only support clocking using PCLK - * and using EXTCLK is not supported in the driver. - */ - .of_clk = { - .name = "PCLK", - } -}; - -static u64 notrace atcpit100_timer_sched_read(void) -{ - return ~readl(timer_of_base(&to) + CH1_CNT); -} - -#ifdef CONFIG_NDS32 -static void fill_vdso_need_info(struct device_node *node) -{ - struct resource timer_res; - of_address_to_resource(node, 0, &timer_res); - timer_info.mapping_base = (unsigned long)timer_res.start; - timer_info.cycle_count_down = true; - timer_info.cycle_count_reg_offset = CH1_CNT; -} -#endif - -static int __init atcpit100_timer_init(struct device_node *node) -{ - int ret; - u32 val; - void __iomem *base; - - ret = timer_of_init(node, &to); - if (ret) - return ret; - - base = timer_of_base(&to); - - sched_clock_register(atcpit100_timer_sched_read, 32, - timer_of_rate(&to)); - - ret = clocksource_mmio_init(base + CH1_CNT, - node->name, timer_of_rate(&to), 300, 32, - clocksource_mmio_readl_down); - - if (ret) { - pr_err("Failed to register clocksource\n"); - return ret; - } - - /* clear channel 0 timer0 interrupt */ - atcpit100_timer_clear_interrupt(base); - - clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), - TIMER_SYNC_TICKS, 0xffffffff); - atcpit100_ch0_tmr0_en(base); - atcpit100_ch1_tmr0_en(base); - atcpit100_clocksource_start(base); - atcpit100_clkevt_time_start(base); - - /* Enable channel 0 timer0 interrupt */ - val = readl(base + INT_EN); - writel(val | CH0INT0EN, base + INT_EN); - -#ifdef CONFIG_NDS32 - fill_vdso_need_info(node); -#endif - - return ret; -} - -TIMER_OF_DECLARE(atcpit100, "andestech,atcpit100", atcpit100_timer_init); diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c1f611cbfbf8..c6161b0b0cb6 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -92,7 +92,6 @@ obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o -obj-$(CONFIG_NDS32) += irq-ativic32.o obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o obj-$(CONFIG_CSKY_MPINTC) += irq-csky-mpintc.o obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o diff --git a/drivers/irqchip/irq-ativic32.c b/drivers/irqchip/irq-ativic32.c deleted file mode 100644 index 223dd2f97d28..000000000000 --- a/drivers/irqchip/irq-ativic32.c +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -unsigned long wake_mask; - -static void ativic32_ack_irq(struct irq_data *data) -{ - __nds32__mtsr_dsb(BIT(data->hwirq), NDS32_SR_INT_PEND2); -} - -static void ativic32_mask_irq(struct irq_data *data) -{ - unsigned long int_mask2 = __nds32__mfsr(NDS32_SR_INT_MASK2); - __nds32__mtsr_dsb(int_mask2 & (~(BIT(data->hwirq))), NDS32_SR_INT_MASK2); -} - -static void ativic32_unmask_irq(struct irq_data *data) -{ - unsigned long int_mask2 = __nds32__mfsr(NDS32_SR_INT_MASK2); - __nds32__mtsr_dsb(int_mask2 | (BIT(data->hwirq)), NDS32_SR_INT_MASK2); -} - -static int nointc_set_wake(struct irq_data *data, unsigned int on) -{ - unsigned long int_mask = __nds32__mfsr(NDS32_SR_INT_MASK); - static unsigned long irq_orig_bit; - u32 bit = 1 << data->hwirq; - - if (on) { - if (int_mask & bit) - __assign_bit(data->hwirq, &irq_orig_bit, true); - else - __assign_bit(data->hwirq, &irq_orig_bit, false); - - __assign_bit(data->hwirq, &int_mask, true); - __assign_bit(data->hwirq, &wake_mask, true); - - } else { - if (!(irq_orig_bit & bit)) - __assign_bit(data->hwirq, &int_mask, false); - - __assign_bit(data->hwirq, &wake_mask, false); - __assign_bit(data->hwirq, &irq_orig_bit, false); - } - - __nds32__mtsr_dsb(int_mask, NDS32_SR_INT_MASK); - - return 0; -} - -static struct irq_chip ativic32_chip = { - .name = "ativic32", - .irq_ack = ativic32_ack_irq, - .irq_mask = ativic32_mask_irq, - .irq_unmask = ativic32_unmask_irq, - .irq_set_wake = nointc_set_wake, -}; - -static unsigned int __initdata nivic_map[6] = { 6, 2, 10, 16, 24, 32 }; - -static struct irq_domain *root_domain; -static int ativic32_irq_domain_map(struct irq_domain *id, unsigned int virq, - irq_hw_number_t hw) -{ - - unsigned long int_trigger_type; - u32 type; - struct irq_data *irq_data; - int_trigger_type = __nds32__mfsr(NDS32_SR_INT_TRIGGER); - irq_data = irq_get_irq_data(virq); - if (!irq_data) - return -EINVAL; - - if (int_trigger_type & (BIT(hw))) { - irq_set_chip_and_handler(virq, &ativic32_chip, handle_edge_irq); - type = IRQ_TYPE_EDGE_RISING; - } else { - irq_set_chip_and_handler(virq, &ativic32_chip, handle_level_irq); - type = IRQ_TYPE_LEVEL_HIGH; - } - - irqd_set_trigger_type(irq_data, type); - return 0; -} - -static const struct irq_domain_ops ativic32_ops = { - .map = ativic32_irq_domain_map, - .xlate = irq_domain_xlate_onecell -}; - -static irq_hw_number_t get_intr_src(void) -{ - return ((__nds32__mfsr(NDS32_SR_ITYPE) & ITYPE_mskVECTOR) >> ITYPE_offVECTOR) - - NDS32_VECTOR_offINTERRUPT; -} - -static void ativic32_handle_irq(struct pt_regs *regs) -{ - irq_hw_number_t hwirq = get_intr_src(); - generic_handle_domain_irq(root_domain, hwirq); -} - -/* - * TODO: convert nds32 to GENERIC_IRQ_MULTI_HANDLER so that this entry logic - * can live in arch code. - */ -asmlinkage void asm_do_IRQ(struct pt_regs *regs) -{ - struct pt_regs *old_regs; - - irq_enter(); - old_regs = set_irq_regs(regs); - ativic32_handle_irq(regs); - set_irq_regs(old_regs); - irq_exit(); -} - -int __init ativic32_init_irq(struct device_node *node, struct device_node *parent) -{ - unsigned long int_vec_base, nivic, nr_ints; - - if (WARN(parent, "non-root ativic32 are not supported")) - return -EINVAL; - - int_vec_base = __nds32__mfsr(NDS32_SR_IVB); - - if (((int_vec_base & IVB_mskIVIC_VER) >> IVB_offIVIC_VER) == 0) - panic("Unable to use atcivic32 for this cpu.\n"); - - nivic = (int_vec_base & IVB_mskNIVIC) >> IVB_offNIVIC; - if (nivic >= ARRAY_SIZE(nivic_map)) - panic("The number of input for ativic32 is not supported.\n"); - - nr_ints = nivic_map[nivic]; - - root_domain = irq_domain_add_linear(node, nr_ints, - &ativic32_ops, NULL); - - if (!root_domain) - panic("%s: unable to create IRQ domain\n", node->full_name); - - return 0; -} -IRQCHIP_DECLARE(ativic32, "andestech,ativic32", ativic32_init_irq); diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig index 3d1e9a302148..c699bd6bcbb9 100644 --- a/drivers/net/ethernet/faraday/Kconfig +++ b/drivers/net/ethernet/faraday/Kconfig @@ -6,7 +6,7 @@ config NET_VENDOR_FARADAY bool "Faraday devices" default y - depends on ARM || NDS32 || COMPILE_TEST + depends on ARM || COMPILE_TEST help If you have a network (Ethernet) card belonging to this class, say Y. @@ -19,24 +19,22 @@ if NET_VENDOR_FARADAY config FTMAC100 tristate "Faraday FTMAC100 10/100 Ethernet support" - depends on ARM || NDS32 || COMPILE_TEST + depends on ARM || COMPILE_TEST depends on !64BIT || BROKEN select MII help This driver supports the FTMAC100 10/100 Ethernet controller - from Faraday. It is used on Faraday A320, Andes AG101 and some - other ARM/NDS32 SoC's. + from Faraday. It is used on Faraday A320 and some other ARM SoC's. config FTGMAC100 tristate "Faraday FTGMAC100 Gigabit Ethernet support" - depends on ARM || NDS32 || COMPILE_TEST + depends on ARM || COMPILE_TEST depends on !64BIT || BROKEN select PHYLIB select MDIO_ASPEED if MACH_ASPEED_G6 select CRC32 help This driver supports the FTGMAC100 Gigabit Ethernet controller - from Faraday. It is used on Faraday A369, Andes AG102 and some - other ARM/NDS32 SoC's. + from Faraday. It is used on Faraday A369 and some other ARM SoC's. endif # NET_VENDOR_FARADAY diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index fcc46380e7c9..40c50fa2dd70 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -9,7 +9,7 @@ config VGA_CONSOLE bool "VGA text console" if EXPERT || !X86 depends on !4xx && !PPC_8xx && !SPARC && !M68K && !PARISC && !SUPERH && \ (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ - !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !NDS32 && !S390 && !UML + !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !S390 && !UML default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 3ccb2c70add4..6a4645a57976 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -362,9 +362,6 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL(_PLT)?\\s_?mcount\$"; $type = ".quad"; $alignment = 2; -} elsif ($arch eq "nds32") { - $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_NDS32_HI20_RELA\\s+_mcount\$"; - $alignment = 2; } elsif ($arch eq "csky") { $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_CKCORE_PCREL_JSR_IMM26BY2\\s+_mcount\$"; $alignment = 2; diff --git a/tools/include/asm/barrier.h b/tools/include/asm/barrier.h index dc696c151e1c..8d378c57cb01 100644 --- a/tools/include/asm/barrier.h +++ b/tools/include/asm/barrier.h @@ -24,8 +24,6 @@ #include "../../arch/ia64/include/asm/barrier.h" #elif defined(__xtensa__) #include "../../arch/xtensa/include/asm/barrier.h" -#elif defined(__nds32__) -#include "../../arch/nds32/include/asm/barrier.h" #else #include #endif diff --git a/tools/perf/arch/nds32/Build b/tools/perf/arch/nds32/Build deleted file mode 100644 index e4e5f33c84d8..000000000000 --- a/tools/perf/arch/nds32/Build +++ /dev/null @@ -1 +0,0 @@ -perf-y += util/ diff --git a/tools/perf/arch/nds32/util/Build b/tools/perf/arch/nds32/util/Build deleted file mode 100644 index d0bc205fe49a..000000000000 --- a/tools/perf/arch/nds32/util/Build +++ /dev/null @@ -1 +0,0 @@ -perf-y += header.o diff --git a/tools/perf/arch/nds32/util/header.c b/tools/perf/arch/nds32/util/header.c deleted file mode 100644 index ef9dbdbe7968..000000000000 --- a/tools/perf/arch/nds32/util/header.c +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#include -#include -#include -#include "header.h" - -#define STR_LEN 1024 - -char *get_cpuid_str(struct perf_pmu *pmu) -{ - /* In nds32, we only have one cpu */ - char *buf = NULL; - struct cpu_map *cpus; - const char *sysfs = sysfs__mountpoint(); - - if (!sysfs || !pmu || !pmu->cpus) - return NULL; - - buf = malloc(STR_LEN); - if (!buf) - return NULL; - - cpus = cpu_map__get(pmu->cpus); - sprintf(buf, "0x%x", cpus->nr - 1); - cpu_map__put(cpus); - return buf; -} diff --git a/tools/testing/selftests/vDSO/vdso_config.h b/tools/testing/selftests/vDSO/vdso_config.h index 6188b16827d1..cdfed403ba13 100644 --- a/tools/testing/selftests/vDSO/vdso_config.h +++ b/tools/testing/selftests/vDSO/vdso_config.h @@ -53,10 +53,6 @@ #if __riscv_xlen == 32 #define VDSO_32BIT 1 #endif -#else /* nds32 */ -#define VDSO_VERSION 4 -#define VDSO_NAMES 1 -#define VDSO_32BIT 1 #endif static const char *versions[6] = { -- cgit From b530e9e1063ed2b817eae7eec6ed2daa8be11608 Mon Sep 17 00:00:00 2001 From: Toke Høiland-Jørgensen Date: Wed, 9 Mar 2022 11:53:42 +0100 Subject: bpf: Add "live packet" mode for XDP in BPF_PROG_RUN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for running XDP programs through BPF_PROG_RUN in a mode that enables live packet processing of the resulting frames. Previous uses of BPF_PROG_RUN for XDP returned the XDP program return code and the modified packet data to userspace, which is useful for unit testing of XDP programs. The existing BPF_PROG_RUN for XDP allows userspace to set the ingress ifindex and RXQ number as part of the context object being passed to the kernel. This patch reuses that code, but adds a new mode with different semantics, which can be selected with the new BPF_F_TEST_XDP_LIVE_FRAMES flag. When running BPF_PROG_RUN in this mode, the XDP program return codes will be honoured: returning XDP_PASS will result in the frame being injected into the networking stack as if it came from the selected networking interface, while returning XDP_TX and XDP_REDIRECT will result in the frame being transmitted out that interface. XDP_TX is translated into an XDP_REDIRECT operation to the same interface, since the real XDP_TX action is only possible from within the network drivers themselves, not from the process context where BPF_PROG_RUN is executed. Internally, this new mode of operation creates a page pool instance while setting up the test run, and feeds pages from that into the XDP program. The setup cost of this is amortised over the number of repetitions specified by userspace. To support the performance testing use case, we further optimise the setup step so that all pages in the pool are pre-initialised with the packet data, and pre-computed context and xdp_frame objects stored at the start of each page. This makes it possible to entirely avoid touching the page content on each XDP program invocation, and enables sending up to 9 Mpps/core on my test box. Because the data pages are recycled by the page pool, and the test runner doesn't re-initialise them for each run, subsequent invocations of the XDP program will see the packet data in the state it was after the last time it ran on that particular page. This means that an XDP program that modifies the packet before redirecting it has to be careful about which assumptions it makes about the packet content, but that is only an issue for the most naively written programs. Enabling the new flag is only allowed when not setting ctx_out and data_out in the test specification, since using it means frames will be redirected somewhere else, so they can't be returned. Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Alexei Starovoitov Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/20220309105346.100053-2-toke@redhat.com --- include/uapi/linux/bpf.h | 3 + kernel/bpf/Kconfig | 1 + kernel/bpf/syscall.c | 2 +- net/bpf/test_run.c | 334 +++++++++++++++++++++++++++++++++++++++-- tools/include/uapi/linux/bpf.h | 3 + 5 files changed, 328 insertions(+), 15 deletions(-) (limited to 'tools/include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 4eebea830613..bc23020b638d 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1232,6 +1232,8 @@ enum { /* If set, run the test on the cpu specified by bpf_attr.test.cpu */ #define BPF_F_TEST_RUN_ON_CPU (1U << 0) +/* If set, XDP frames will be transmitted after processing */ +#define BPF_F_TEST_XDP_LIVE_FRAMES (1U << 1) /* type for BPF_ENABLE_STATS */ enum bpf_stats_type { @@ -1393,6 +1395,7 @@ union bpf_attr { __aligned_u64 ctx_out; __u32 flags; __u32 cpu; + __u32 batch_size; } test; struct { /* anonymous struct used by BPF_*_GET_*_ID */ diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig index c3cf0b86eeb2..d56ee177d5f8 100644 --- a/kernel/bpf/Kconfig +++ b/kernel/bpf/Kconfig @@ -30,6 +30,7 @@ config BPF_SYSCALL select TASKS_TRACE_RCU select BINARY_PRINTF select NET_SOCK_MSG if NET + select PAGE_POOL if NET default n help Enable the bpf() system call that allows to manipulate BPF programs diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index db402ebc5570..9beb585be5a6 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -3336,7 +3336,7 @@ static int bpf_prog_query(const union bpf_attr *attr, } } -#define BPF_PROG_TEST_RUN_LAST_FIELD test.cpu +#define BPF_PROG_TEST_RUN_LAST_FIELD test.batch_size static int bpf_prog_test_run(const union bpf_attr *attr, union bpf_attr __user *uattr) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index ba410b069824..25169908be4a 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -53,10 +54,11 @@ static void bpf_test_timer_leave(struct bpf_test_timer *t) rcu_read_unlock(); } -static bool bpf_test_timer_continue(struct bpf_test_timer *t, u32 repeat, int *err, u32 *duration) +static bool bpf_test_timer_continue(struct bpf_test_timer *t, int iterations, + u32 repeat, int *err, u32 *duration) __must_hold(rcu) { - t->i++; + t->i += iterations; if (t->i >= repeat) { /* We're done. */ t->time_spent += ktime_get_ns() - t->time_start; @@ -88,6 +90,286 @@ reset: return false; } +/* We put this struct at the head of each page with a context and frame + * initialised when the page is allocated, so we don't have to do this on each + * repetition of the test run. + */ +struct xdp_page_head { + struct xdp_buff orig_ctx; + struct xdp_buff ctx; + struct xdp_frame frm; + u8 data[]; +}; + +struct xdp_test_data { + struct xdp_buff *orig_ctx; + struct xdp_rxq_info rxq; + struct net_device *dev; + struct page_pool *pp; + struct xdp_frame **frames; + struct sk_buff **skbs; + u32 batch_size; + u32 frame_cnt; +}; + +#define TEST_XDP_FRAME_SIZE (PAGE_SIZE - sizeof(struct xdp_page_head) \ + - sizeof(struct skb_shared_info)) +#define TEST_XDP_MAX_BATCH 256 + +static void xdp_test_run_init_page(struct page *page, void *arg) +{ + struct xdp_page_head *head = phys_to_virt(page_to_phys(page)); + struct xdp_buff *new_ctx, *orig_ctx; + u32 headroom = XDP_PACKET_HEADROOM; + struct xdp_test_data *xdp = arg; + size_t frm_len, meta_len; + struct xdp_frame *frm; + void *data; + + orig_ctx = xdp->orig_ctx; + frm_len = orig_ctx->data_end - orig_ctx->data_meta; + meta_len = orig_ctx->data - orig_ctx->data_meta; + headroom -= meta_len; + + new_ctx = &head->ctx; + frm = &head->frm; + data = &head->data; + memcpy(data + headroom, orig_ctx->data_meta, frm_len); + + xdp_init_buff(new_ctx, TEST_XDP_FRAME_SIZE, &xdp->rxq); + xdp_prepare_buff(new_ctx, data, headroom, frm_len, true); + new_ctx->data = new_ctx->data_meta + meta_len; + + xdp_update_frame_from_buff(new_ctx, frm); + frm->mem = new_ctx->rxq->mem; + + memcpy(&head->orig_ctx, new_ctx, sizeof(head->orig_ctx)); +} + +static int xdp_test_run_setup(struct xdp_test_data *xdp, struct xdp_buff *orig_ctx) +{ + struct xdp_mem_info mem = {}; + struct page_pool *pp; + int err = -ENOMEM; + struct page_pool_params pp_params = { + .order = 0, + .flags = 0, + .pool_size = xdp->batch_size, + .nid = NUMA_NO_NODE, + .max_len = TEST_XDP_FRAME_SIZE, + .init_callback = xdp_test_run_init_page, + .init_arg = xdp, + }; + + xdp->frames = kvmalloc_array(xdp->batch_size, sizeof(void *), GFP_KERNEL); + if (!xdp->frames) + return -ENOMEM; + + xdp->skbs = kvmalloc_array(xdp->batch_size, sizeof(void *), GFP_KERNEL); + if (!xdp->skbs) + goto err_skbs; + + pp = page_pool_create(&pp_params); + if (IS_ERR(pp)) { + err = PTR_ERR(pp); + goto err_pp; + } + + /* will copy 'mem.id' into pp->xdp_mem_id */ + err = xdp_reg_mem_model(&mem, MEM_TYPE_PAGE_POOL, pp); + if (err) + goto err_mmodel; + + xdp->pp = pp; + + /* We create a 'fake' RXQ referencing the original dev, but with an + * xdp_mem_info pointing to our page_pool + */ + xdp_rxq_info_reg(&xdp->rxq, orig_ctx->rxq->dev, 0, 0); + xdp->rxq.mem.type = MEM_TYPE_PAGE_POOL; + xdp->rxq.mem.id = pp->xdp_mem_id; + xdp->dev = orig_ctx->rxq->dev; + xdp->orig_ctx = orig_ctx; + + return 0; + +err_mmodel: + page_pool_destroy(pp); +err_pp: + kfree(xdp->skbs); +err_skbs: + kfree(xdp->frames); + return err; +} + +static void xdp_test_run_teardown(struct xdp_test_data *xdp) +{ + page_pool_destroy(xdp->pp); + kfree(xdp->frames); + kfree(xdp->skbs); +} + +static bool ctx_was_changed(struct xdp_page_head *head) +{ + return head->orig_ctx.data != head->ctx.data || + head->orig_ctx.data_meta != head->ctx.data_meta || + head->orig_ctx.data_end != head->ctx.data_end; +} + +static void reset_ctx(struct xdp_page_head *head) +{ + if (likely(!ctx_was_changed(head))) + return; + + head->ctx.data = head->orig_ctx.data; + head->ctx.data_meta = head->orig_ctx.data_meta; + head->ctx.data_end = head->orig_ctx.data_end; + xdp_update_frame_from_buff(&head->ctx, &head->frm); +} + +static int xdp_recv_frames(struct xdp_frame **frames, int nframes, + struct sk_buff **skbs, + struct net_device *dev) +{ + gfp_t gfp = __GFP_ZERO | GFP_ATOMIC; + int i, n; + LIST_HEAD(list); + + n = kmem_cache_alloc_bulk(skbuff_head_cache, gfp, nframes, (void **)skbs); + if (unlikely(n == 0)) { + for (i = 0; i < nframes; i++) + xdp_return_frame(frames[i]); + return -ENOMEM; + } + + for (i = 0; i < nframes; i++) { + struct xdp_frame *xdpf = frames[i]; + struct sk_buff *skb = skbs[i]; + + skb = __xdp_build_skb_from_frame(xdpf, skb, dev); + if (!skb) { + xdp_return_frame(xdpf); + continue; + } + + list_add_tail(&skb->list, &list); + } + netif_receive_skb_list(&list); + + return 0; +} + +static int xdp_test_run_batch(struct xdp_test_data *xdp, struct bpf_prog *prog, + u32 repeat) +{ + struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); + int err = 0, act, ret, i, nframes = 0, batch_sz; + struct xdp_frame **frames = xdp->frames; + struct xdp_page_head *head; + struct xdp_frame *frm; + bool redirect = false; + struct xdp_buff *ctx; + struct page *page; + + batch_sz = min_t(u32, repeat, xdp->batch_size); + + local_bh_disable(); + xdp_set_return_frame_no_direct(); + + for (i = 0; i < batch_sz; i++) { + page = page_pool_dev_alloc_pages(xdp->pp); + if (!page) { + err = -ENOMEM; + goto out; + } + + head = phys_to_virt(page_to_phys(page)); + reset_ctx(head); + ctx = &head->ctx; + frm = &head->frm; + xdp->frame_cnt++; + + act = bpf_prog_run_xdp(prog, ctx); + + /* if program changed pkt bounds we need to update the xdp_frame */ + if (unlikely(ctx_was_changed(head))) { + ret = xdp_update_frame_from_buff(ctx, frm); + if (ret) { + xdp_return_buff(ctx); + continue; + } + } + + switch (act) { + case XDP_TX: + /* we can't do a real XDP_TX since we're not in the + * driver, so turn it into a REDIRECT back to the same + * index + */ + ri->tgt_index = xdp->dev->ifindex; + ri->map_id = INT_MAX; + ri->map_type = BPF_MAP_TYPE_UNSPEC; + fallthrough; + case XDP_REDIRECT: + redirect = true; + ret = xdp_do_redirect_frame(xdp->dev, ctx, frm, prog); + if (ret) + xdp_return_buff(ctx); + break; + case XDP_PASS: + frames[nframes++] = frm; + break; + default: + bpf_warn_invalid_xdp_action(NULL, prog, act); + fallthrough; + case XDP_DROP: + xdp_return_buff(ctx); + break; + } + } + +out: + if (redirect) + xdp_do_flush(); + if (nframes) { + ret = xdp_recv_frames(frames, nframes, xdp->skbs, xdp->dev); + if (ret) + err = ret; + } + + xdp_clear_return_frame_no_direct(); + local_bh_enable(); + return err; +} + +static int bpf_test_run_xdp_live(struct bpf_prog *prog, struct xdp_buff *ctx, + u32 repeat, u32 batch_size, u32 *time) + +{ + struct xdp_test_data xdp = { .batch_size = batch_size }; + struct bpf_test_timer t = { .mode = NO_MIGRATE }; + int ret; + + if (!repeat) + repeat = 1; + + ret = xdp_test_run_setup(&xdp, ctx); + if (ret) + return ret; + + bpf_test_timer_enter(&t); + do { + xdp.frame_cnt = 0; + ret = xdp_test_run_batch(&xdp, prog, repeat - t.i); + if (unlikely(ret < 0)) + break; + } while (bpf_test_timer_continue(&t, xdp.frame_cnt, repeat, &ret, time)); + bpf_test_timer_leave(&t); + + xdp_test_run_teardown(&xdp); + return ret; +} + static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *retval, u32 *time, bool xdp) { @@ -119,7 +401,7 @@ static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, *retval = bpf_prog_run_xdp(prog, ctx); else *retval = bpf_prog_run(prog, ctx); - } while (bpf_test_timer_continue(&t, repeat, &ret, time)); + } while (bpf_test_timer_continue(&t, 1, repeat, &ret, time)); bpf_reset_run_ctx(old_ctx); bpf_test_timer_leave(&t); @@ -446,7 +728,7 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog, int b = 2, err = -EFAULT; u32 retval = 0; - if (kattr->test.flags || kattr->test.cpu) + if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size) return -EINVAL; switch (prog->expected_attach_type) { @@ -510,7 +792,7 @@ int bpf_prog_test_run_raw_tp(struct bpf_prog *prog, /* doesn't support data_in/out, ctx_out, duration, or repeat */ if (kattr->test.data_in || kattr->test.data_out || kattr->test.ctx_out || kattr->test.duration || - kattr->test.repeat) + kattr->test.repeat || kattr->test.batch_size) return -EINVAL; if (ctx_size_in < prog->aux->max_ctx_offset || @@ -741,7 +1023,7 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, void *data; int ret; - if (kattr->test.flags || kattr->test.cpu) + if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size) return -EINVAL; data = bpf_test_init(kattr, kattr->test.data_size_in, @@ -922,7 +1204,9 @@ static void xdp_convert_buff_to_md(struct xdp_buff *xdp, struct xdp_md *xdp_md) int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, union bpf_attr __user *uattr) { + bool do_live = (kattr->test.flags & BPF_F_TEST_XDP_LIVE_FRAMES); u32 tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + u32 batch_size = kattr->test.batch_size; u32 size = kattr->test.data_size_in; u32 headroom = XDP_PACKET_HEADROOM; u32 retval, duration, max_data_sz; @@ -938,6 +1222,18 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, prog->expected_attach_type == BPF_XDP_CPUMAP) return -EINVAL; + if (kattr->test.flags & ~BPF_F_TEST_XDP_LIVE_FRAMES) + return -EINVAL; + + if (do_live) { + if (!batch_size) + batch_size = NAPI_POLL_WEIGHT; + else if (batch_size > TEST_XDP_MAX_BATCH) + return -E2BIG; + } else if (batch_size) { + return -EINVAL; + } + ctx = bpf_ctx_init(kattr, sizeof(struct xdp_md)); if (IS_ERR(ctx)) return PTR_ERR(ctx); @@ -946,14 +1242,20 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, /* There can't be user provided data before the meta data */ if (ctx->data_meta || ctx->data_end != size || ctx->data > ctx->data_end || - unlikely(xdp_metalen_invalid(ctx->data))) + unlikely(xdp_metalen_invalid(ctx->data)) || + (do_live && (kattr->test.data_out || kattr->test.ctx_out))) goto free_ctx; /* Meta data is allocated from the headroom */ headroom -= ctx->data; } max_data_sz = 4096 - headroom - tailroom; - size = min_t(u32, size, max_data_sz); + if (size > max_data_sz) { + /* disallow live data mode for jumbo frames */ + if (do_live) + goto free_ctx; + size = max_data_sz; + } data = bpf_test_init(kattr, size, max_data_sz, headroom, tailroom); if (IS_ERR(data)) { @@ -1011,7 +1313,10 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, if (repeat > 1) bpf_prog_change_xdp(NULL, prog); - ret = bpf_test_run(prog, &xdp, repeat, &retval, &duration, true); + if (do_live) + ret = bpf_test_run_xdp_live(prog, &xdp, repeat, batch_size, &duration); + else + ret = bpf_test_run(prog, &xdp, repeat, &retval, &duration, true); /* We convert the xdp_buff back to an xdp_md before checking the return * code so the reference count of any held netdevice will be decremented * even if the test run failed. @@ -1073,7 +1378,7 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog, if (prog->type != BPF_PROG_TYPE_FLOW_DISSECTOR) return -EINVAL; - if (kattr->test.flags || kattr->test.cpu) + if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size) return -EINVAL; if (size < ETH_HLEN) @@ -1108,7 +1413,7 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog, do { retval = bpf_flow_dissect(prog, &ctx, eth->h_proto, ETH_HLEN, size, flags); - } while (bpf_test_timer_continue(&t, repeat, &ret, &duration)); + } while (bpf_test_timer_continue(&t, 1, repeat, &ret, &duration)); bpf_test_timer_leave(&t); if (ret < 0) @@ -1140,7 +1445,7 @@ int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kat if (prog->type != BPF_PROG_TYPE_SK_LOOKUP) return -EINVAL; - if (kattr->test.flags || kattr->test.cpu) + if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size) return -EINVAL; if (kattr->test.data_in || kattr->test.data_size_in || kattr->test.data_out || @@ -1203,7 +1508,7 @@ int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kat do { ctx.selected_sk = NULL; retval = BPF_PROG_SK_LOOKUP_RUN_ARRAY(progs, ctx, bpf_prog_run); - } while (bpf_test_timer_continue(&t, repeat, &ret, &duration)); + } while (bpf_test_timer_continue(&t, 1, repeat, &ret, &duration)); bpf_test_timer_leave(&t); if (ret < 0) @@ -1242,7 +1547,8 @@ int bpf_prog_test_run_syscall(struct bpf_prog *prog, /* doesn't support data_in/out, ctx_out, duration, or repeat or flags */ if (kattr->test.data_in || kattr->test.data_out || kattr->test.ctx_out || kattr->test.duration || - kattr->test.repeat || kattr->test.flags) + kattr->test.repeat || kattr->test.flags || + kattr->test.batch_size) return -EINVAL; if (ctx_size_in < prog->aux->max_ctx_offset || diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 4eebea830613..bc23020b638d 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1232,6 +1232,8 @@ enum { /* If set, run the test on the cpu specified by bpf_attr.test.cpu */ #define BPF_F_TEST_RUN_ON_CPU (1U << 0) +/* If set, XDP frames will be transmitted after processing */ +#define BPF_F_TEST_XDP_LIVE_FRAMES (1U << 1) /* type for BPF_ENABLE_STATS */ enum bpf_stats_type { @@ -1393,6 +1395,7 @@ union bpf_attr { __aligned_u64 ctx_out; __u32 flags; __u32 cpu; + __u32 batch_size; } test; struct { /* anonymous struct used by BPF_*_GET_*_ID */ -- cgit From 9bb984f28d5bcb917d35d930fcfb89f90f9449fd Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Wed, 9 Mar 2022 01:05:09 -0800 Subject: bpf: Remove BPF_SKB_DELIVERY_TIME_NONE and rename s/delivery_time_/tstamp_/ This patch is to simplify the uapi bpf.h regarding to the tstamp type and use a similar way as the kernel to describe the value stored in __sk_buff->tstamp. My earlier thought was to avoid describing the semantic and clock base for the rcv timestamp until there is more clarity on the use case, so the __sk_buff->delivery_time_type naming instead of __sk_buff->tstamp_type. With some thoughts, it can reuse the UNSPEC naming. This patch first removes BPF_SKB_DELIVERY_TIME_NONE and also rename BPF_SKB_DELIVERY_TIME_UNSPEC to BPF_SKB_TSTAMP_UNSPEC and BPF_SKB_DELIVERY_TIME_MONO to BPF_SKB_TSTAMP_DELIVERY_MONO. The semantic of BPF_SKB_TSTAMP_DELIVERY_MONO is the same: __sk_buff->tstamp has delivery time in mono clock base. BPF_SKB_TSTAMP_UNSPEC means __sk_buff->tstamp has the (rcv) tstamp at ingress and the delivery time at egress. At egress, the clock base could be found from skb->sk->sk_clockid. __sk_buff->tstamp == 0 naturally means NONE, so NONE is not needed. With BPF_SKB_TSTAMP_UNSPEC for the rcv tstamp at ingress, the __sk_buff->delivery_time_type is also renamed to __sk_buff->tstamp_type which was also suggested in the earlier discussion: https://lore.kernel.org/bpf/b181acbe-caf8-502d-4b7b-7d96b9fc5d55@iogearbox.net/ The above will then make __sk_buff->tstamp and __sk_buff->tstamp_type the same as its kernel skb->tstamp and skb->mono_delivery_time counter part. The internal kernel function bpf_skb_convert_dtime_type_read() is then renamed to bpf_skb_convert_tstamp_type_read() and it can be simplified with the BPF_SKB_DELIVERY_TIME_NONE gone. A BPF_ALU32_IMM(BPF_AND) insn is also saved by using BPF_JMP32_IMM(BPF_JSET). The bpf helper bpf_skb_set_delivery_time() is also renamed to bpf_skb_set_tstamp(). The arg name is changed from dtime to tstamp also. It only allows setting tstamp 0 for BPF_SKB_TSTAMP_UNSPEC and it could be relaxed later if there is use case to change mono delivery time to non mono. prog->delivery_time_access is also renamed to prog->tstamp_type_access. Signed-off-by: Martin KaFai Lau Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20220309090509.3712315-1-kafai@fb.com --- include/linux/filter.h | 2 +- include/uapi/linux/bpf.h | 40 ++++++++++--------- net/core/filter.c | 88 ++++++++++++++++-------------------------- tools/include/uapi/linux/bpf.h | 40 ++++++++++--------- 4 files changed, 77 insertions(+), 93 deletions(-) (limited to 'tools/include') diff --git a/include/linux/filter.h b/include/linux/filter.h index 9bf26307247f..05ed9bd31b45 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -573,7 +573,7 @@ struct bpf_prog { enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */ call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */ call_get_func_ip:1, /* Do we call get_func_ip() */ - delivery_time_access:1; /* Accessed __sk_buff->delivery_time_type */ + tstamp_type_access:1; /* Accessed __sk_buff->tstamp_type */ enum bpf_prog_type type; /* Type of BPF program */ enum bpf_attach_type expected_attach_type; /* For some prog types */ u32 len; /* Number of filter blocks */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index bc23020b638d..d288a0a9f797 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5090,23 +5090,22 @@ union bpf_attr { * 0 on success, or a negative error in case of failure. On error * *dst* buffer is zeroed out. * - * long bpf_skb_set_delivery_time(struct sk_buff *skb, u64 dtime, u32 dtime_type) + * long bpf_skb_set_tstamp(struct sk_buff *skb, u64 tstamp, u32 tstamp_type) * Description - * Set a *dtime* (delivery time) to the __sk_buff->tstamp and also - * change the __sk_buff->delivery_time_type to *dtime_type*. + * Change the __sk_buff->tstamp_type to *tstamp_type* + * and set *tstamp* to the __sk_buff->tstamp together. * - * When setting a delivery time (non zero *dtime*) to - * __sk_buff->tstamp, only BPF_SKB_DELIVERY_TIME_MONO *dtime_type* - * is supported. It is the only delivery_time_type that will be - * kept after bpf_redirect_*(). - * - * If there is no need to change the __sk_buff->delivery_time_type, - * the delivery time can be directly written to __sk_buff->tstamp + * If there is no need to change the __sk_buff->tstamp_type, + * the tstamp value can be directly written to __sk_buff->tstamp * instead. * - * *dtime* 0 and *dtime_type* BPF_SKB_DELIVERY_TIME_NONE - * can be used to clear any delivery time stored in - * __sk_buff->tstamp. + * BPF_SKB_TSTAMP_DELIVERY_MONO is the only tstamp that + * will be kept during bpf_redirect_*(). A non zero + * *tstamp* must be used with the BPF_SKB_TSTAMP_DELIVERY_MONO + * *tstamp_type*. + * + * A BPF_SKB_TSTAMP_UNSPEC *tstamp_type* can only be used + * with a zero *tstamp*. * * Only IPv4 and IPv6 skb->protocol are supported. * @@ -5119,7 +5118,7 @@ union bpf_attr { * Return * 0 on success. * **-EINVAL** for invalid input - * **-EOPNOTSUPP** for unsupported delivery_time_type and protocol + * **-EOPNOTSUPP** for unsupported protocol */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5314,7 +5313,7 @@ union bpf_attr { FN(xdp_load_bytes), \ FN(xdp_store_bytes), \ FN(copy_from_user_task), \ - FN(skb_set_delivery_time), \ + FN(skb_set_tstamp), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper @@ -5505,9 +5504,12 @@ union { \ } __attribute__((aligned(8))) enum { - BPF_SKB_DELIVERY_TIME_NONE, - BPF_SKB_DELIVERY_TIME_UNSPEC, - BPF_SKB_DELIVERY_TIME_MONO, + BPF_SKB_TSTAMP_UNSPEC, + BPF_SKB_TSTAMP_DELIVERY_MONO, /* tstamp has mono delivery time */ + /* For any BPF_SKB_TSTAMP_* that the bpf prog cannot handle, + * the bpf prog should handle it like BPF_SKB_TSTAMP_UNSPEC + * and try to deduce it by ingress, egress or skb->sk->sk_clockid. + */ }; /* user accessible mirror of in-kernel sk_buff. @@ -5550,7 +5552,7 @@ struct __sk_buff { __u32 gso_segs; __bpf_md_ptr(struct bpf_sock *, sk); __u32 gso_size; - __u8 delivery_time_type; + __u8 tstamp_type; __u32 :24; /* Padding, future use. */ __u64 hwtstamp; }; diff --git a/net/core/filter.c b/net/core/filter.c index f914e4b13b18..03655f2074ae 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -7388,36 +7388,36 @@ static const struct bpf_func_proto bpf_sock_ops_reserve_hdr_opt_proto = { .arg3_type = ARG_ANYTHING, }; -BPF_CALL_3(bpf_skb_set_delivery_time, struct sk_buff *, skb, - u64, dtime, u32, dtime_type) +BPF_CALL_3(bpf_skb_set_tstamp, struct sk_buff *, skb, + u64, tstamp, u32, tstamp_type) { /* skb_clear_delivery_time() is done for inet protocol */ if (skb->protocol != htons(ETH_P_IP) && skb->protocol != htons(ETH_P_IPV6)) return -EOPNOTSUPP; - switch (dtime_type) { - case BPF_SKB_DELIVERY_TIME_MONO: - if (!dtime) + switch (tstamp_type) { + case BPF_SKB_TSTAMP_DELIVERY_MONO: + if (!tstamp) return -EINVAL; - skb->tstamp = dtime; + skb->tstamp = tstamp; skb->mono_delivery_time = 1; break; - case BPF_SKB_DELIVERY_TIME_NONE: - if (dtime) + case BPF_SKB_TSTAMP_UNSPEC: + if (tstamp) return -EINVAL; skb->tstamp = 0; skb->mono_delivery_time = 0; break; default: - return -EOPNOTSUPP; + return -EINVAL; } return 0; } -static const struct bpf_func_proto bpf_skb_set_delivery_time_proto = { - .func = bpf_skb_set_delivery_time, +static const struct bpf_func_proto bpf_skb_set_tstamp_proto = { + .func = bpf_skb_set_tstamp, .gpl_only = false, .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_CTX, @@ -7786,8 +7786,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_tcp_gen_syncookie_proto; case BPF_FUNC_sk_assign: return &bpf_sk_assign_proto; - case BPF_FUNC_skb_set_delivery_time: - return &bpf_skb_set_delivery_time_proto; + case BPF_FUNC_skb_set_tstamp: + return &bpf_skb_set_tstamp_proto; #endif default: return bpf_sk_base_func_proto(func_id); @@ -8127,9 +8127,9 @@ static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type return false; info->reg_type = PTR_TO_SOCK_COMMON_OR_NULL; break; - case offsetof(struct __sk_buff, delivery_time_type): + case offsetof(struct __sk_buff, tstamp_type): return false; - case offsetofend(struct __sk_buff, delivery_time_type) ... offsetof(struct __sk_buff, hwtstamp) - 1: + case offsetofend(struct __sk_buff, tstamp_type) ... offsetof(struct __sk_buff, hwtstamp) - 1: /* Explicitly prohibit access to padding in __sk_buff. */ return false; default: @@ -8484,14 +8484,14 @@ static bool tc_cls_act_is_valid_access(int off, int size, break; case bpf_ctx_range_till(struct __sk_buff, family, local_port): return false; - case offsetof(struct __sk_buff, delivery_time_type): + case offsetof(struct __sk_buff, tstamp_type): /* The convert_ctx_access() on reading and writing * __sk_buff->tstamp depends on whether the bpf prog - * has used __sk_buff->delivery_time_type or not. - * Thus, we need to set prog->delivery_time_access + * has used __sk_buff->tstamp_type or not. + * Thus, we need to set prog->tstamp_type_access * earlier during is_valid_access() here. */ - ((struct bpf_prog *)prog)->delivery_time_access = 1; + ((struct bpf_prog *)prog)->tstamp_type_access = 1; return size == sizeof(__u8); } @@ -8888,42 +8888,22 @@ static u32 flow_dissector_convert_ctx_access(enum bpf_access_type type, return insn - insn_buf; } -static struct bpf_insn *bpf_convert_dtime_type_read(const struct bpf_insn *si, - struct bpf_insn *insn) +static struct bpf_insn *bpf_convert_tstamp_type_read(const struct bpf_insn *si, + struct bpf_insn *insn) { __u8 value_reg = si->dst_reg; __u8 skb_reg = si->src_reg; + /* AX is needed because src_reg and dst_reg could be the same */ __u8 tmp_reg = BPF_REG_AX; *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, PKT_VLAN_PRESENT_OFFSET); - *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, - SKB_MONO_DELIVERY_TIME_MASK); - *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 2); - /* value_reg = BPF_SKB_DELIVERY_TIME_MONO */ - *insn++ = BPF_MOV32_IMM(value_reg, BPF_SKB_DELIVERY_TIME_MONO); - *insn++ = BPF_JMP_A(IS_ENABLED(CONFIG_NET_CLS_ACT) ? 10 : 5); - - *insn++ = BPF_LDX_MEM(BPF_DW, tmp_reg, skb_reg, - offsetof(struct sk_buff, tstamp)); - *insn++ = BPF_JMP_IMM(BPF_JNE, tmp_reg, 0, 2); - /* value_reg = BPF_SKB_DELIVERY_TIME_NONE */ - *insn++ = BPF_MOV32_IMM(value_reg, BPF_SKB_DELIVERY_TIME_NONE); - *insn++ = BPF_JMP_A(IS_ENABLED(CONFIG_NET_CLS_ACT) ? 6 : 1); - -#ifdef CONFIG_NET_CLS_ACT - *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, PKT_VLAN_PRESENT_OFFSET); - *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, TC_AT_INGRESS_MASK); - *insn++ = BPF_JMP32_IMM(BPF_JEQ, tmp_reg, 0, 2); - /* At ingress, value_reg = 0 */ - *insn++ = BPF_MOV32_IMM(value_reg, 0); + *insn++ = BPF_JMP32_IMM(BPF_JSET, tmp_reg, + SKB_MONO_DELIVERY_TIME_MASK, 2); + *insn++ = BPF_MOV32_IMM(value_reg, BPF_SKB_TSTAMP_UNSPEC); *insn++ = BPF_JMP_A(1); -#endif - - /* value_reg = BPF_SKB_DELIVERYT_TIME_UNSPEC */ - *insn++ = BPF_MOV32_IMM(value_reg, BPF_SKB_DELIVERY_TIME_UNSPEC); + *insn++ = BPF_MOV32_IMM(value_reg, BPF_SKB_TSTAMP_DELIVERY_MONO); - /* 15 insns with CONFIG_NET_CLS_ACT */ return insn; } @@ -8956,11 +8936,11 @@ static struct bpf_insn *bpf_convert_tstamp_read(const struct bpf_prog *prog, __u8 skb_reg = si->src_reg; #ifdef CONFIG_NET_CLS_ACT - /* If the delivery_time_type is read, + /* If the tstamp_type is read, * the bpf prog is aware the tstamp could have delivery time. - * Thus, read skb->tstamp as is if delivery_time_access is true. + * Thus, read skb->tstamp as is if tstamp_type_access is true. */ - if (!prog->delivery_time_access) { + if (!prog->tstamp_type_access) { /* AX is needed because src_reg and dst_reg could be the same */ __u8 tmp_reg = BPF_REG_AX; @@ -8990,13 +8970,13 @@ static struct bpf_insn *bpf_convert_tstamp_write(const struct bpf_prog *prog, __u8 skb_reg = si->dst_reg; #ifdef CONFIG_NET_CLS_ACT - /* If the delivery_time_type is read, + /* If the tstamp_type is read, * the bpf prog is aware the tstamp could have delivery time. - * Thus, write skb->tstamp as is if delivery_time_access is true. + * Thus, write skb->tstamp as is if tstamp_type_access is true. * Otherwise, writing at ingress will have to clear the * mono_delivery_time bit also. */ - if (!prog->delivery_time_access) { + if (!prog->tstamp_type_access) { __u8 tmp_reg = BPF_REG_AX; *insn++ = BPF_LDX_MEM(BPF_B, tmp_reg, skb_reg, PKT_VLAN_PRESENT_OFFSET); @@ -9329,8 +9309,8 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type, insn = bpf_convert_tstamp_read(prog, si, insn); break; - case offsetof(struct __sk_buff, delivery_time_type): - insn = bpf_convert_dtime_type_read(si, insn); + case offsetof(struct __sk_buff, tstamp_type): + insn = bpf_convert_tstamp_type_read(si, insn); break; case offsetof(struct __sk_buff, gso_segs): diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index bc23020b638d..d288a0a9f797 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5090,23 +5090,22 @@ union bpf_attr { * 0 on success, or a negative error in case of failure. On error * *dst* buffer is zeroed out. * - * long bpf_skb_set_delivery_time(struct sk_buff *skb, u64 dtime, u32 dtime_type) + * long bpf_skb_set_tstamp(struct sk_buff *skb, u64 tstamp, u32 tstamp_type) * Description - * Set a *dtime* (delivery time) to the __sk_buff->tstamp and also - * change the __sk_buff->delivery_time_type to *dtime_type*. + * Change the __sk_buff->tstamp_type to *tstamp_type* + * and set *tstamp* to the __sk_buff->tstamp together. * - * When setting a delivery time (non zero *dtime*) to - * __sk_buff->tstamp, only BPF_SKB_DELIVERY_TIME_MONO *dtime_type* - * is supported. It is the only delivery_time_type that will be - * kept after bpf_redirect_*(). - * - * If there is no need to change the __sk_buff->delivery_time_type, - * the delivery time can be directly written to __sk_buff->tstamp + * If there is no need to change the __sk_buff->tstamp_type, + * the tstamp value can be directly written to __sk_buff->tstamp * instead. * - * *dtime* 0 and *dtime_type* BPF_SKB_DELIVERY_TIME_NONE - * can be used to clear any delivery time stored in - * __sk_buff->tstamp. + * BPF_SKB_TSTAMP_DELIVERY_MONO is the only tstamp that + * will be kept during bpf_redirect_*(). A non zero + * *tstamp* must be used with the BPF_SKB_TSTAMP_DELIVERY_MONO + * *tstamp_type*. + * + * A BPF_SKB_TSTAMP_UNSPEC *tstamp_type* can only be used + * with a zero *tstamp*. * * Only IPv4 and IPv6 skb->protocol are supported. * @@ -5119,7 +5118,7 @@ union bpf_attr { * Return * 0 on success. * **-EINVAL** for invalid input - * **-EOPNOTSUPP** for unsupported delivery_time_type and protocol + * **-EOPNOTSUPP** for unsupported protocol */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5314,7 +5313,7 @@ union bpf_attr { FN(xdp_load_bytes), \ FN(xdp_store_bytes), \ FN(copy_from_user_task), \ - FN(skb_set_delivery_time), \ + FN(skb_set_tstamp), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper @@ -5505,9 +5504,12 @@ union { \ } __attribute__((aligned(8))) enum { - BPF_SKB_DELIVERY_TIME_NONE, - BPF_SKB_DELIVERY_TIME_UNSPEC, - BPF_SKB_DELIVERY_TIME_MONO, + BPF_SKB_TSTAMP_UNSPEC, + BPF_SKB_TSTAMP_DELIVERY_MONO, /* tstamp has mono delivery time */ + /* For any BPF_SKB_TSTAMP_* that the bpf prog cannot handle, + * the bpf prog should handle it like BPF_SKB_TSTAMP_UNSPEC + * and try to deduce it by ingress, egress or skb->sk->sk_clockid. + */ }; /* user accessible mirror of in-kernel sk_buff. @@ -5550,7 +5552,7 @@ struct __sk_buff { __u32 gso_segs; __bpf_md_ptr(struct bpf_sock *, sk); __u32 gso_size; - __u8 delivery_time_type; + __u8 tstamp_type; __u32 :24; /* Padding, future use. */ __u64 hwtstamp; }; -- cgit From 58617014405ad5c9f94f464444f4972dabb71ca7 Mon Sep 17 00:00:00 2001 From: Hengqi Chen Date: Thu, 10 Mar 2022 23:53:35 +0800 Subject: bpf: Fix comment for helper bpf_current_task_under_cgroup() Fix the descriptions of the return values of helper bpf_current_task_under_cgroup(). Fixes: c6b5fb8690fa ("bpf: add documentation for eBPF helpers (42-50)") Signed-off-by: Hengqi Chen Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20220310155335.1278783-1-hengqi.chen@gmail.com --- include/uapi/linux/bpf.h | 4 ++-- tools/include/uapi/linux/bpf.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index d288a0a9f797..e9978a916c3e 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -2302,8 +2302,8 @@ union bpf_attr { * Return * The return value depends on the result of the test, and can be: * - * * 0, if current task belongs to the cgroup2. - * * 1, if current task does not belong to the cgroup2. + * * 1, if current task belongs to the cgroup2. + * * 0, if current task does not belong to the cgroup2. * * A negative error code, if an error occurred. * * long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index d288a0a9f797..e9978a916c3e 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -2302,8 +2302,8 @@ union bpf_attr { * Return * The return value depends on the result of the test, and can be: * - * * 0, if current task belongs to the cgroup2. - * * 1, if current task does not belong to the cgroup2. + * * 1, if current task belongs to the cgroup2. + * * 0, if current task does not belong to the cgroup2. * * A negative error code, if an error occurred. * * long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) -- cgit From 174b16946e39ebd369097e0f773536c91a8c1a4c Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Wed, 2 Mar 2022 12:13:58 +0100 Subject: bpf-lsm: Introduce new helper bpf_ima_file_hash() ima_file_hash() has been modified to calculate the measurement of a file on demand, if it has not been already performed by IMA or the measurement is not fresh. For compatibility reasons, ima_inode_hash() remains unchanged. Keep the same approach in eBPF and introduce the new helper bpf_ima_file_hash() to take advantage of the modified behavior of ima_file_hash(). Signed-off-by: Roberto Sassu Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20220302111404.193900-4-roberto.sassu@huawei.com --- include/uapi/linux/bpf.h | 11 +++++++++++ kernel/bpf/bpf_lsm.c | 20 ++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 11 +++++++++++ 3 files changed, 42 insertions(+) (limited to 'tools/include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index e9978a916c3e..99fab54ae9c0 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5119,6 +5119,16 @@ union bpf_attr { * 0 on success. * **-EINVAL** for invalid input * **-EOPNOTSUPP** for unsupported protocol + * + * long bpf_ima_file_hash(struct file *file, void *dst, u32 size) + * Description + * Returns a calculated IMA hash of the *file*. + * If the hash is larger than *size*, then only *size* + * bytes will be copied to *dst* + * Return + * The **hash_algo** is returned on success, + * **-EOPNOTSUP** if the hash calculation failed or **-EINVAL** if + * invalid arguments are passed. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5314,6 +5324,7 @@ union bpf_attr { FN(xdp_store_bytes), \ FN(copy_from_user_task), \ FN(skb_set_tstamp), \ + FN(ima_file_hash), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index 9e4ecc990647..e8d27af5bbcc 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -99,6 +99,24 @@ static const struct bpf_func_proto bpf_ima_inode_hash_proto = { .allowed = bpf_ima_inode_hash_allowed, }; +BPF_CALL_3(bpf_ima_file_hash, struct file *, file, void *, dst, u32, size) +{ + return ima_file_hash(file, dst, size); +} + +BTF_ID_LIST_SINGLE(bpf_ima_file_hash_btf_ids, struct, file) + +static const struct bpf_func_proto bpf_ima_file_hash_proto = { + .func = bpf_ima_file_hash, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_BTF_ID, + .arg1_btf_id = &bpf_ima_file_hash_btf_ids[0], + .arg2_type = ARG_PTR_TO_UNINIT_MEM, + .arg3_type = ARG_CONST_SIZE, + .allowed = bpf_ima_inode_hash_allowed, +}; + static const struct bpf_func_proto * bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -121,6 +139,8 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_bprm_opts_set_proto; case BPF_FUNC_ima_inode_hash: return prog->aux->sleepable ? &bpf_ima_inode_hash_proto : NULL; + case BPF_FUNC_ima_file_hash: + return prog->aux->sleepable ? &bpf_ima_file_hash_proto : NULL; default: return tracing_prog_func_proto(func_id, prog); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e9978a916c3e..99fab54ae9c0 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5119,6 +5119,16 @@ union bpf_attr { * 0 on success. * **-EINVAL** for invalid input * **-EOPNOTSUPP** for unsupported protocol + * + * long bpf_ima_file_hash(struct file *file, void *dst, u32 size) + * Description + * Returns a calculated IMA hash of the *file*. + * If the hash is larger than *size*, then only *size* + * bytes will be copied to *dst* + * Return + * The **hash_algo** is returned on success, + * **-EOPNOTSUP** if the hash calculation failed or **-EINVAL** if + * invalid arguments are passed. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5314,6 +5324,7 @@ union bpf_attr { FN(xdp_store_bytes), \ FN(copy_from_user_task), \ FN(skb_set_tstamp), \ + FN(ima_file_hash), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From 7177a4792660c605906582ef0bb8f6bb7ff971a1 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 15 Oct 2021 10:31:44 +0200 Subject: tools compiler.h: Remove duplicate #ifndef noinline block The same three lines also appear a bit earlier in the same file. Reviewed-by: Miguel Ojeda Signed-off-by: Rasmus Villemoes Cc: Ard Biesheuvel Link: https://lore.kernel.org/r/20211015083144.2767725-1-linux@rasmusvillemoes.dk Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/compiler.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'tools/include') diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index ff872dc2637c..90ba44a99199 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -102,10 +102,6 @@ # define __init #endif -#ifndef noinline -# define noinline -#endif - #include /* -- cgit From c8c301abeae58ec756b8fcb2178a632bd3c9e284 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 8 Mar 2022 16:30:18 +0100 Subject: x86/ibt: Add ANNOTATE_NOENDBR In order to have objtool warn about code references to !ENDBR instruction, we need an annotation to allow this for non-control-flow instances -- consider text range checks, text patching, or return trampolines etc. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Kees Cook Acked-by: Josh Poimboeuf Link: https://lore.kernel.org/r/20220308154317.578968224@infradead.org --- include/linux/objtool.h | 16 ++++++++++++++++ tools/include/linux/objtool.h | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'tools/include') diff --git a/include/linux/objtool.h b/include/linux/objtool.h index aca52db2f3f3..f797368820c8 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -77,6 +77,12 @@ struct unwind_hint { #define STACK_FRAME_NON_STANDARD_FP(func) #endif +#define ANNOTATE_NOENDBR \ + "986: \n\t" \ + ".pushsection .discard.noendbr\n\t" \ + _ASM_PTR " 986b\n\t" \ + ".popsection\n\t" + #else /* __ASSEMBLY__ */ /* @@ -129,6 +135,13 @@ struct unwind_hint { .popsection .endm +.macro ANNOTATE_NOENDBR +.Lhere_\@: + .pushsection .discard.noendbr + .quad .Lhere_\@ + .popsection +.endm + #endif /* __ASSEMBLY__ */ #else /* !CONFIG_STACK_VALIDATION */ @@ -139,12 +152,15 @@ struct unwind_hint { "\n\t" #define STACK_FRAME_NON_STANDARD(func) #define STACK_FRAME_NON_STANDARD_FP(func) +#define ANNOTATE_NOENDBR #else #define ANNOTATE_INTRA_FUNCTION_CALL .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0 .endm .macro STACK_FRAME_NON_STANDARD func:req .endm +.macro ANNOTATE_NOENDBR +.endm #endif #endif /* CONFIG_STACK_VALIDATION */ diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h index aca52db2f3f3..f797368820c8 100644 --- a/tools/include/linux/objtool.h +++ b/tools/include/linux/objtool.h @@ -77,6 +77,12 @@ struct unwind_hint { #define STACK_FRAME_NON_STANDARD_FP(func) #endif +#define ANNOTATE_NOENDBR \ + "986: \n\t" \ + ".pushsection .discard.noendbr\n\t" \ + _ASM_PTR " 986b\n\t" \ + ".popsection\n\t" + #else /* __ASSEMBLY__ */ /* @@ -129,6 +135,13 @@ struct unwind_hint { .popsection .endm +.macro ANNOTATE_NOENDBR +.Lhere_\@: + .pushsection .discard.noendbr + .quad .Lhere_\@ + .popsection +.endm + #endif /* __ASSEMBLY__ */ #else /* !CONFIG_STACK_VALIDATION */ @@ -139,12 +152,15 @@ struct unwind_hint { "\n\t" #define STACK_FRAME_NON_STANDARD(func) #define STACK_FRAME_NON_STANDARD_FP(func) +#define ANNOTATE_NOENDBR #else #define ANNOTATE_INTRA_FUNCTION_CALL .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0 .endm .macro STACK_FRAME_NON_STANDARD func:req .endm +.macro ANNOTATE_NOENDBR +.endm #endif #endif /* CONFIG_STACK_VALIDATION */ -- cgit From dca5da2abe406168b85f97e22109710ebe0bda08 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 14 Mar 2022 18:05:52 +0100 Subject: x86,objtool: Move the ASM_REACHABLE annotation to objtool.h Because we need a variant for .S files too. Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/Yi9gOW9f1GGwwUD6@hirez.programming.kicks-ass.net --- arch/x86/include/asm/bug.h | 1 + arch/x86/include/asm/irq_stack.h | 1 + include/linux/compiler.h | 7 ------- include/linux/objtool.h | 16 ++++++++++++++++ tools/include/linux/objtool.h | 16 ++++++++++++++++ 5 files changed, 34 insertions(+), 7 deletions(-) (limited to 'tools/include') diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h index bab883c0b6fe..4d20a293c6fd 100644 --- a/arch/x86/include/asm/bug.h +++ b/arch/x86/include/asm/bug.h @@ -4,6 +4,7 @@ #include #include +#include /* * Despite that some emulators terminate on UD2, we use it for WARN(). diff --git a/arch/x86/include/asm/irq_stack.h b/arch/x86/include/asm/irq_stack.h index 05af249d6bec..63f818aedf77 100644 --- a/arch/x86/include/asm/irq_stack.h +++ b/arch/x86/include/asm/irq_stack.h @@ -3,6 +3,7 @@ #define _ASM_X86_IRQ_STACK_H #include +#include #include diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 0f7fd205ab7e..219aa5ddbc73 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -125,18 +125,11 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, }) #define annotate_unreachable() __annotate_unreachable(__COUNTER__) -#define ASM_REACHABLE \ - "998:\n\t" \ - ".pushsection .discard.reachable\n\t" \ - ".long 998b - .\n\t" \ - ".popsection\n\t" - /* Annotate a C jump table to allow objtool to follow the code flow */ #define __annotate_jump_table __section(".rodata..c_jump_table") #else #define annotate_unreachable() -# define ASM_REACHABLE #define __annotate_jump_table #endif diff --git a/include/linux/objtool.h b/include/linux/objtool.h index f797368820c8..586d35720f13 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -83,6 +83,12 @@ struct unwind_hint { _ASM_PTR " 986b\n\t" \ ".popsection\n\t" +#define ASM_REACHABLE \ + "998:\n\t" \ + ".pushsection .discard.reachable\n\t" \ + ".long 998b - .\n\t" \ + ".popsection\n\t" + #else /* __ASSEMBLY__ */ /* @@ -142,6 +148,13 @@ struct unwind_hint { .popsection .endm +.macro REACHABLE +.Lhere_\@: + .pushsection .discard.reachable + .long .Lhere_\@ - . + .popsection +.endm + #endif /* __ASSEMBLY__ */ #else /* !CONFIG_STACK_VALIDATION */ @@ -153,6 +166,7 @@ struct unwind_hint { #define STACK_FRAME_NON_STANDARD(func) #define STACK_FRAME_NON_STANDARD_FP(func) #define ANNOTATE_NOENDBR +#define ASM_REACHABLE #else #define ANNOTATE_INTRA_FUNCTION_CALL .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0 @@ -161,6 +175,8 @@ struct unwind_hint { .endm .macro ANNOTATE_NOENDBR .endm +.macro REACHABLE +.endm #endif #endif /* CONFIG_STACK_VALIDATION */ diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h index f797368820c8..586d35720f13 100644 --- a/tools/include/linux/objtool.h +++ b/tools/include/linux/objtool.h @@ -83,6 +83,12 @@ struct unwind_hint { _ASM_PTR " 986b\n\t" \ ".popsection\n\t" +#define ASM_REACHABLE \ + "998:\n\t" \ + ".pushsection .discard.reachable\n\t" \ + ".long 998b - .\n\t" \ + ".popsection\n\t" + #else /* __ASSEMBLY__ */ /* @@ -142,6 +148,13 @@ struct unwind_hint { .popsection .endm +.macro REACHABLE +.Lhere_\@: + .pushsection .discard.reachable + .long .Lhere_\@ - . + .popsection +.endm + #endif /* __ASSEMBLY__ */ #else /* !CONFIG_STACK_VALIDATION */ @@ -153,6 +166,7 @@ struct unwind_hint { #define STACK_FRAME_NON_STANDARD(func) #define STACK_FRAME_NON_STANDARD_FP(func) #define ANNOTATE_NOENDBR +#define ASM_REACHABLE #else #define ANNOTATE_INTRA_FUNCTION_CALL .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0 @@ -161,6 +175,8 @@ struct unwind_hint { .endm .macro ANNOTATE_NOENDBR .endm +.macro REACHABLE +.endm #endif #endif /* CONFIG_STACK_VALIDATION */ -- cgit From 0dcac272540613d41c05e89679e4ddb978b612f1 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 16 Mar 2022 13:24:09 +0100 Subject: bpf: Add multi kprobe link Adding new link type BPF_LINK_TYPE_KPROBE_MULTI that attaches kprobe program through fprobe API. The fprobe API allows to attach probe on multiple functions at once very fast, because it works on top of ftrace. On the other hand this limits the probe point to the function entry or return. The kprobe program gets the same pt_regs input ctx as when it's attached through the perf API. Adding new attach type BPF_TRACE_KPROBE_MULTI that allows attachment kprobe to multiple function with new link. User provides array of addresses or symbols with count to attach the kprobe program to. The new link_create uapi interface looks like: struct { __u32 flags; __u32 cnt; __aligned_u64 syms; __aligned_u64 addrs; } kprobe_multi; The flags field allows single BPF_TRACE_KPROBE_MULTI bit to create return multi kprobe. Signed-off-by: Masami Hiramatsu Signed-off-by: Jiri Olsa Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20220316122419.933957-4-jolsa@kernel.org --- include/linux/bpf_types.h | 1 + include/linux/trace_events.h | 7 ++ include/uapi/linux/bpf.h | 13 +++ kernel/bpf/syscall.c | 26 ++++- kernel/trace/bpf_trace.c | 211 +++++++++++++++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 13 +++ 6 files changed, 266 insertions(+), 5 deletions(-) (limited to 'tools/include') diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index 48a91c51c015..3e24ad0c4b3c 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -140,3 +140,4 @@ BPF_LINK_TYPE(BPF_LINK_TYPE_XDP, xdp) #ifdef CONFIG_PERF_EVENTS BPF_LINK_TYPE(BPF_LINK_TYPE_PERF_EVENT, perf) #endif +BPF_LINK_TYPE(BPF_LINK_TYPE_KPROBE_MULTI, kprobe_multi) diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index dcea51fb60e2..8f0e9e7cb493 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -15,6 +15,7 @@ struct array_buffer; struct tracer; struct dentry; struct bpf_prog; +union bpf_attr; const char *trace_print_flags_seq(struct trace_seq *p, const char *delim, unsigned long flags, @@ -738,6 +739,7 @@ void bpf_put_raw_tracepoint(struct bpf_raw_event_map *btp); int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id, u32 *fd_type, const char **buf, u64 *probe_offset, u64 *probe_addr); +int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog); #else static inline unsigned int trace_call_bpf(struct trace_event_call *call, void *ctx) { @@ -779,6 +781,11 @@ static inline int bpf_get_perf_event_info(const struct perf_event *event, { return -EOPNOTSUPP; } +static inline int +bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) +{ + return -EOPNOTSUPP; +} #endif enum { diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 99fab54ae9c0..d77f47af7752 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -997,6 +997,7 @@ enum bpf_attach_type { BPF_SK_REUSEPORT_SELECT, BPF_SK_REUSEPORT_SELECT_OR_MIGRATE, BPF_PERF_EVENT, + BPF_TRACE_KPROBE_MULTI, __MAX_BPF_ATTACH_TYPE }; @@ -1011,6 +1012,7 @@ enum bpf_link_type { BPF_LINK_TYPE_NETNS = 5, BPF_LINK_TYPE_XDP = 6, BPF_LINK_TYPE_PERF_EVENT = 7, + BPF_LINK_TYPE_KPROBE_MULTI = 8, MAX_BPF_LINK_TYPE, }; @@ -1118,6 +1120,11 @@ enum bpf_link_type { */ #define BPF_F_XDP_HAS_FRAGS (1U << 5) +/* link_create.kprobe_multi.flags used in LINK_CREATE command for + * BPF_TRACE_KPROBE_MULTI attach type to create return probe. + */ +#define BPF_F_KPROBE_MULTI_RETURN (1U << 0) + /* When BPF ldimm64's insn[0].src_reg != 0 then this can have * the following extensions: * @@ -1475,6 +1482,12 @@ union bpf_attr { */ __u64 bpf_cookie; } perf_event; + struct { + __u32 flags; + __u32 cnt; + __aligned_u64 syms; + __aligned_u64 addrs; + } kprobe_multi; }; } link_create; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 9beb585be5a6..b8bb67ee6c57 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -32,6 +32,7 @@ #include #include #include +#include #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ @@ -3022,6 +3023,11 @@ out_put_file: fput(perf_file); return err; } +#else +static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_PERF_EVENTS */ #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd @@ -4255,7 +4261,7 @@ static int tracing_bpf_link_attach(const union bpf_attr *attr, bpfptr_t uattr, return -EINVAL; } -#define BPF_LINK_CREATE_LAST_FIELD link_create.iter_info_len +#define BPF_LINK_CREATE_LAST_FIELD link_create.kprobe_multi.addrs static int link_create(union bpf_attr *attr, bpfptr_t uattr) { enum bpf_prog_type ptype; @@ -4279,7 +4285,6 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr) ret = tracing_bpf_link_attach(attr, uattr, prog); goto out; case BPF_PROG_TYPE_PERF_EVENT: - case BPF_PROG_TYPE_KPROBE: case BPF_PROG_TYPE_TRACEPOINT: if (attr->link_create.attach_type != BPF_PERF_EVENT) { ret = -EINVAL; @@ -4287,6 +4292,14 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr) } ptype = prog->type; break; + case BPF_PROG_TYPE_KPROBE: + if (attr->link_create.attach_type != BPF_PERF_EVENT && + attr->link_create.attach_type != BPF_TRACE_KPROBE_MULTI) { + ret = -EINVAL; + goto out; + } + ptype = prog->type; + break; default: ptype = attach_type_to_prog_type(attr->link_create.attach_type); if (ptype == BPF_PROG_TYPE_UNSPEC || ptype != prog->type) { @@ -4318,13 +4331,16 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr) ret = bpf_xdp_link_attach(attr, prog); break; #endif -#ifdef CONFIG_PERF_EVENTS case BPF_PROG_TYPE_PERF_EVENT: case BPF_PROG_TYPE_TRACEPOINT: - case BPF_PROG_TYPE_KPROBE: ret = bpf_perf_link_attach(attr, prog); break; -#endif + case BPF_PROG_TYPE_KPROBE: + if (attr->link_create.attach_type == BPF_PERF_EVENT) + ret = bpf_perf_link_attach(attr, prog); + else + ret = bpf_kprobe_multi_link_attach(attr, prog); + break; default: ret = -EINVAL; } diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index a2024ba32a20..fffa2171fae4 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -2181,3 +2182,213 @@ static int __init bpf_event_init(void) fs_initcall(bpf_event_init); #endif /* CONFIG_MODULES */ + +#ifdef CONFIG_FPROBE +struct bpf_kprobe_multi_link { + struct bpf_link link; + struct fprobe fp; + unsigned long *addrs; +}; + +static void bpf_kprobe_multi_link_release(struct bpf_link *link) +{ + struct bpf_kprobe_multi_link *kmulti_link; + + kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link); + unregister_fprobe(&kmulti_link->fp); +} + +static void bpf_kprobe_multi_link_dealloc(struct bpf_link *link) +{ + struct bpf_kprobe_multi_link *kmulti_link; + + kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link); + kvfree(kmulti_link->addrs); + kfree(kmulti_link); +} + +static const struct bpf_link_ops bpf_kprobe_multi_link_lops = { + .release = bpf_kprobe_multi_link_release, + .dealloc = bpf_kprobe_multi_link_dealloc, +}; + +static int +kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link, + struct pt_regs *regs) +{ + int err; + + if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1)) { + err = 0; + goto out; + } + + migrate_disable(); + rcu_read_lock(); + err = bpf_prog_run(link->link.prog, regs); + rcu_read_unlock(); + migrate_enable(); + + out: + __this_cpu_dec(bpf_prog_active); + return err; +} + +static void +kprobe_multi_link_handler(struct fprobe *fp, unsigned long entry_ip, + struct pt_regs *regs) +{ + unsigned long saved_ip = instruction_pointer(regs); + struct bpf_kprobe_multi_link *link; + + /* + * Because fprobe's regs->ip is set to the next instruction of + * dynamic-ftrace instruction, correct entry ip must be set, so + * that the bpf program can access entry address via regs as same + * as kprobes. + * + * Both kprobe and kretprobe see the entry ip of traced function + * as instruction pointer. + */ + instruction_pointer_set(regs, entry_ip); + + link = container_of(fp, struct bpf_kprobe_multi_link, fp); + kprobe_multi_link_prog_run(link, regs); + + instruction_pointer_set(regs, saved_ip); +} + +static int +kprobe_multi_resolve_syms(const void *usyms, u32 cnt, + unsigned long *addrs) +{ + unsigned long addr, size; + const char **syms; + int err = -ENOMEM; + unsigned int i; + char *func; + + size = cnt * sizeof(*syms); + syms = kvzalloc(size, GFP_KERNEL); + if (!syms) + return -ENOMEM; + + func = kmalloc(KSYM_NAME_LEN, GFP_KERNEL); + if (!func) + goto error; + + if (copy_from_user(syms, usyms, size)) { + err = -EFAULT; + goto error; + } + + for (i = 0; i < cnt; i++) { + err = strncpy_from_user(func, syms[i], KSYM_NAME_LEN); + if (err == KSYM_NAME_LEN) + err = -E2BIG; + if (err < 0) + goto error; + err = -EINVAL; + addr = kallsyms_lookup_name(func); + if (!addr) + goto error; + if (!kallsyms_lookup_size_offset(addr, &size, NULL)) + goto error; + addr = ftrace_location_range(addr, addr + size - 1); + if (!addr) + goto error; + addrs[i] = addr; + } + + err = 0; +error: + kvfree(syms); + kfree(func); + return err; +} + +int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) +{ + struct bpf_kprobe_multi_link *link = NULL; + struct bpf_link_primer link_primer; + unsigned long *addrs; + u32 flags, cnt, size; + void __user *uaddrs; + void __user *usyms; + int err; + + /* no support for 32bit archs yet */ + if (sizeof(u64) != sizeof(void *)) + return -EOPNOTSUPP; + + if (prog->expected_attach_type != BPF_TRACE_KPROBE_MULTI) + return -EINVAL; + + flags = attr->link_create.kprobe_multi.flags; + if (flags & ~BPF_F_KPROBE_MULTI_RETURN) + return -EINVAL; + + uaddrs = u64_to_user_ptr(attr->link_create.kprobe_multi.addrs); + usyms = u64_to_user_ptr(attr->link_create.kprobe_multi.syms); + if (!!uaddrs == !!usyms) + return -EINVAL; + + cnt = attr->link_create.kprobe_multi.cnt; + if (!cnt) + return -EINVAL; + + size = cnt * sizeof(*addrs); + addrs = kvmalloc(size, GFP_KERNEL); + if (!addrs) + return -ENOMEM; + + if (uaddrs) { + if (copy_from_user(addrs, uaddrs, size)) { + err = -EFAULT; + goto error; + } + } else { + err = kprobe_multi_resolve_syms(usyms, cnt, addrs); + if (err) + goto error; + } + + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) { + err = -ENOMEM; + goto error; + } + + bpf_link_init(&link->link, BPF_LINK_TYPE_KPROBE_MULTI, + &bpf_kprobe_multi_link_lops, prog); + + err = bpf_link_prime(&link->link, &link_primer); + if (err) + goto error; + + if (flags & BPF_F_KPROBE_MULTI_RETURN) + link->fp.exit_handler = kprobe_multi_link_handler; + else + link->fp.entry_handler = kprobe_multi_link_handler; + + link->addrs = addrs; + + err = register_fprobe_ips(&link->fp, addrs, cnt); + if (err) { + bpf_link_cleanup(&link_primer); + return err; + } + + return bpf_link_settle(&link_primer); + +error: + kfree(link); + kvfree(addrs); + return err; +} +#else /* !CONFIG_FPROBE */ +int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) +{ + return -EOPNOTSUPP; +} +#endif diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 99fab54ae9c0..d77f47af7752 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -997,6 +997,7 @@ enum bpf_attach_type { BPF_SK_REUSEPORT_SELECT, BPF_SK_REUSEPORT_SELECT_OR_MIGRATE, BPF_PERF_EVENT, + BPF_TRACE_KPROBE_MULTI, __MAX_BPF_ATTACH_TYPE }; @@ -1011,6 +1012,7 @@ enum bpf_link_type { BPF_LINK_TYPE_NETNS = 5, BPF_LINK_TYPE_XDP = 6, BPF_LINK_TYPE_PERF_EVENT = 7, + BPF_LINK_TYPE_KPROBE_MULTI = 8, MAX_BPF_LINK_TYPE, }; @@ -1118,6 +1120,11 @@ enum bpf_link_type { */ #define BPF_F_XDP_HAS_FRAGS (1U << 5) +/* link_create.kprobe_multi.flags used in LINK_CREATE command for + * BPF_TRACE_KPROBE_MULTI attach type to create return probe. + */ +#define BPF_F_KPROBE_MULTI_RETURN (1U << 0) + /* When BPF ldimm64's insn[0].src_reg != 0 then this can have * the following extensions: * @@ -1475,6 +1482,12 @@ union bpf_attr { */ __u64 bpf_cookie; } perf_event; + struct { + __u32 flags; + __u32 cnt; + __aligned_u64 syms; + __aligned_u64 addrs; + } kprobe_multi; }; } link_create; -- cgit From ca74823c6e16dd42b7cf60d9fdde80e2a81a67bb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 16 Mar 2022 13:24:12 +0100 Subject: bpf: Add cookie support to programs attached with kprobe multi link Adding support to call bpf_get_attach_cookie helper from kprobe programs attached with kprobe multi link. The cookie is provided by array of u64 values, where each value is paired with provided function address or symbol with the same array index. When cookie array is provided it's sorted together with addresses (check bpf_kprobe_multi_cookie_swap). This way we can find cookie based on the address in bpf_get_attach_cookie helper. Suggested-by: Andrii Nakryiko Signed-off-by: Jiri Olsa Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20220316122419.933957-7-jolsa@kernel.org --- include/uapi/linux/bpf.h | 1 + kernel/bpf/syscall.c | 2 +- kernel/trace/bpf_trace.c | 114 ++++++++++++++++++++++++++++++++++++++++- tools/include/uapi/linux/bpf.h | 1 + 4 files changed, 116 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index d77f47af7752..7604e7d5438f 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1487,6 +1487,7 @@ union bpf_attr { __u32 cnt; __aligned_u64 syms; __aligned_u64 addrs; + __aligned_u64 cookies; } kprobe_multi; }; } link_create; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index b8bb67ee6c57..cdaa1152436a 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -4261,7 +4261,7 @@ static int tracing_bpf_link_attach(const union bpf_attr *attr, bpfptr_t uattr, return -EINVAL; } -#define BPF_LINK_CREATE_LAST_FIELD link_create.kprobe_multi.addrs +#define BPF_LINK_CREATE_LAST_FIELD link_create.kprobe_multi.cookies static int link_create(union bpf_attr *attr, bpfptr_t uattr) { enum bpf_prog_type ptype; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 0e7f8c9bc756..9a7b6be655e4 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include @@ -78,6 +80,7 @@ u64 bpf_get_stack(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); static int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size, u64 flags, const struct btf **btf, s32 *btf_id); +static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx, u64 ip); /** * trace_call_bpf - invoke BPF program @@ -1050,6 +1053,18 @@ static const struct bpf_func_proto bpf_get_func_ip_proto_kprobe_multi = { .arg1_type = ARG_PTR_TO_CTX, }; +BPF_CALL_1(bpf_get_attach_cookie_kprobe_multi, struct pt_regs *, regs) +{ + return bpf_kprobe_multi_cookie(current->bpf_ctx, instruction_pointer(regs)); +} + +static const struct bpf_func_proto bpf_get_attach_cookie_proto_kmulti = { + .func = bpf_get_attach_cookie_kprobe_multi, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +}; + BPF_CALL_1(bpf_get_attach_cookie_trace, void *, ctx) { struct bpf_trace_run_ctx *run_ctx; @@ -1297,7 +1312,9 @@ kprobe_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) &bpf_get_func_ip_proto_kprobe_multi : &bpf_get_func_ip_proto_kprobe; case BPF_FUNC_get_attach_cookie: - return &bpf_get_attach_cookie_proto_trace; + return prog->expected_attach_type == BPF_TRACE_KPROBE_MULTI ? + &bpf_get_attach_cookie_proto_kmulti : + &bpf_get_attach_cookie_proto_trace; default: return bpf_tracing_func_proto(func_id, prog); } @@ -2203,6 +2220,13 @@ struct bpf_kprobe_multi_link { struct bpf_link link; struct fprobe fp; unsigned long *addrs; + /* + * The run_ctx here is used to get struct bpf_kprobe_multi_link in + * get_attach_cookie helper, so it can't be used to store data. + */ + struct bpf_run_ctx run_ctx; + u64 *cookies; + u32 cnt; }; static void bpf_kprobe_multi_link_release(struct bpf_link *link) @@ -2219,6 +2243,7 @@ static void bpf_kprobe_multi_link_dealloc(struct bpf_link *link) kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link); kvfree(kmulti_link->addrs); + kvfree(kmulti_link->cookies); kfree(kmulti_link); } @@ -2227,10 +2252,60 @@ static const struct bpf_link_ops bpf_kprobe_multi_link_lops = { .dealloc = bpf_kprobe_multi_link_dealloc, }; +static void bpf_kprobe_multi_cookie_swap(void *a, void *b, int size, const void *priv) +{ + const struct bpf_kprobe_multi_link *link = priv; + unsigned long *addr_a = a, *addr_b = b; + u64 *cookie_a, *cookie_b; + unsigned long tmp1; + u64 tmp2; + + cookie_a = link->cookies + (addr_a - link->addrs); + cookie_b = link->cookies + (addr_b - link->addrs); + + /* swap addr_a/addr_b and cookie_a/cookie_b values */ + tmp1 = *addr_a; *addr_a = *addr_b; *addr_b = tmp1; + tmp2 = *cookie_a; *cookie_a = *cookie_b; *cookie_b = tmp2; +} + +static int __bpf_kprobe_multi_cookie_cmp(const void *a, const void *b) +{ + const unsigned long *addr_a = a, *addr_b = b; + + if (*addr_a == *addr_b) + return 0; + return *addr_a < *addr_b ? -1 : 1; +} + +static int bpf_kprobe_multi_cookie_cmp(const void *a, const void *b, const void *priv) +{ + return __bpf_kprobe_multi_cookie_cmp(a, b); +} + +static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx, u64 ip) +{ + struct bpf_kprobe_multi_link *link; + unsigned long *addr; + u64 *cookie; + + if (WARN_ON_ONCE(!ctx)) + return 0; + link = container_of(ctx, struct bpf_kprobe_multi_link, run_ctx); + if (!link->cookies) + return 0; + addr = bsearch(&ip, link->addrs, link->cnt, sizeof(ip), + __bpf_kprobe_multi_cookie_cmp); + if (!addr) + return 0; + cookie = link->cookies + (addr - link->addrs); + return *cookie; +} + static int kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link, struct pt_regs *regs) { + struct bpf_run_ctx *old_run_ctx; int err; if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1)) { @@ -2240,7 +2315,9 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link, migrate_disable(); rcu_read_lock(); + old_run_ctx = bpf_set_run_ctx(&link->run_ctx); err = bpf_prog_run(link->link.prog, regs); + bpf_reset_run_ctx(old_run_ctx); rcu_read_unlock(); migrate_enable(); @@ -2326,9 +2403,11 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr { struct bpf_kprobe_multi_link *link = NULL; struct bpf_link_primer link_primer; + void __user *ucookies; unsigned long *addrs; u32 flags, cnt, size; void __user *uaddrs; + u64 *cookies = NULL; void __user *usyms; int err; @@ -2368,6 +2447,19 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr goto error; } + ucookies = u64_to_user_ptr(attr->link_create.kprobe_multi.cookies); + if (ucookies) { + cookies = kvmalloc(size, GFP_KERNEL); + if (!cookies) { + err = -ENOMEM; + goto error; + } + if (copy_from_user(cookies, ucookies, size)) { + err = -EFAULT; + goto error; + } + } + link = kzalloc(sizeof(*link), GFP_KERNEL); if (!link) { err = -ENOMEM; @@ -2387,6 +2479,21 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr link->fp.entry_handler = kprobe_multi_link_handler; link->addrs = addrs; + link->cookies = cookies; + link->cnt = cnt; + + if (cookies) { + /* + * Sorting addresses will trigger sorting cookies as well + * (check bpf_kprobe_multi_cookie_swap). This way we can + * find cookie based on the address in bpf_get_attach_cookie + * helper. + */ + sort_r(addrs, cnt, sizeof(*addrs), + bpf_kprobe_multi_cookie_cmp, + bpf_kprobe_multi_cookie_swap, + link); + } err = register_fprobe_ips(&link->fp, addrs, cnt); if (err) { @@ -2399,6 +2506,7 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr error: kfree(link); kvfree(addrs); + kvfree(cookies); return err; } #else /* !CONFIG_FPROBE */ @@ -2406,4 +2514,8 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr { return -EOPNOTSUPP; } +static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx, u64 ip) +{ + return 0; +} #endif diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index d77f47af7752..7604e7d5438f 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1487,6 +1487,7 @@ union bpf_attr { __u32 cnt; __aligned_u64 syms; __aligned_u64 addrs; + __aligned_u64 cookies; } kprobe_multi; }; } link_create; -- cgit From c724c866bb70cb8c607081a26823a1f0ebde4387 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 23 Mar 2022 16:05:29 -0700 Subject: linux/types.h: remove unnecessary __bitwise__ There are no users of "__bitwise__" except the definition of "__bitwise". Remove __bitwise__ and define __bitwise directly. This is a follow-up to 05de97003c77 ("linux/types.h: enable endian checks for all sparse builds"). [akpm@linux-foundation.org: change the tools/include/linux/types.h definition also] Link: https://lkml.kernel.org/r/20220310220927.245704-2-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Cc: Michael S. Tsirkin Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Nick Desaulniers Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/uapi/linux/types.h | 5 ++--- tools/include/linux/types.h | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'tools/include') diff --git a/include/uapi/linux/types.h b/include/uapi/linux/types.h index f6d2f83cbe29..71696f424ac8 100644 --- a/include/uapi/linux/types.h +++ b/include/uapi/linux/types.h @@ -20,11 +20,10 @@ */ #ifdef __CHECKER__ -#define __bitwise__ __attribute__((bitwise)) +#define __bitwise __attribute__((bitwise)) #else -#define __bitwise__ +#define __bitwise #endif -#define __bitwise __bitwise__ typedef __u16 __bitwise __le16; typedef __u16 __bitwise __be16; diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h index 6e14a533ab4e..6c18c54e7d7f 100644 --- a/tools/include/linux/types.h +++ b/tools/include/linux/types.h @@ -43,11 +43,10 @@ typedef __u8 u8; typedef __s8 s8; #ifdef __CHECKER__ -#define __bitwise__ __attribute__((bitwise)) +#define __bitwise __attribute__((bitwise)) #else -#define __bitwise__ +#define __bitwise #endif -#define __bitwise __bitwise__ #define __force #define __user -- cgit From 98870605b3742c38353b50b6dbad33fab9de415f Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 24 Mar 2022 16:37:32 +0800 Subject: bpf: Sync comments for bpf_get_stack Commit ee2a098851bf missed updating the comments for helper bpf_get_stack in tools/include/uapi/linux/bpf.h. Sync it. Fixes: ee2a098851bf ("bpf: Adjust BPF stack helper functions to accommodate skip > 0") Signed-off-by: Geliang Tang Signed-off-by: Alexei Starovoitov Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/ce54617746b7ed5e9ba3b844e55e74cb8a60e0b5.1648110794.git.geliang.tang@suse.com --- tools/include/uapi/linux/bpf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 7604e7d5438f..d14b10b85e51 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -3009,8 +3009,8 @@ union bpf_attr { * * # sysctl kernel.perf_event_max_stack= * Return - * A non-negative value equal to or less than *size* on success, - * or a negative error in case of failure. + * The non-negative copied *buf* length equal to or less than + * *size* on success, or a negative error in case of failure. * * long bpf_skb_load_bytes_relative(const void *skb, u32 offset, void *to, u32 len, u32 start_header) * Description @@ -4316,8 +4316,8 @@ union bpf_attr { * * # sysctl kernel.perf_event_max_stack= * Return - * A non-negative value equal to or less than *size* on success, - * or a negative error in case of failure. + * The non-negative copied *buf* length equal to or less than + * *size* on success, or a negative error in case of failure. * * long bpf_load_hdr_opt(struct bpf_sock_ops *skops, void *searchby_res, u32 len, u64 flags) * Description -- cgit From 6d05e1398507fc3509debc397bb9dfa18fc5230e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 Sep 2019 11:30:30 -0300 Subject: tools headers UAPI: Sync asm-generic/mman-common.h with the kernel To pick the changes from: 9457056ac426e5ed ("mm: madvise: MADV_DONTNEED_LOCKED") That result in these changes in the tools: $ diff -u tools/include/uapi/asm-generic/mman-common.h include/uapi/asm-generic/mman-common.h --- tools/include/uapi/asm-generic/mman-common.h 2022-03-29 16:17:50.461694991 -0300 +++ include/uapi/asm-generic/mman-common.h 2022-03-27 19:12:48.923250468 -0300 @@ -75,6 +75,8 @@ #define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */ #define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */ +#define MADV_DONTNEED_LOCKED 24 /* like DONTNEED, but drop locked pages too */ + /* compatibility flags */ #define MAP_FILE 0 $ tools/perf/trace/beauty/madvise_behavior.sh > before $ cp include/uapi/asm-generic/mman-common.h tools/include/uapi/asm-generic/mman-common.h $ tools/perf/trace/beauty/madvise_behavior.sh > after $ diff -u before after --- before 2022-03-29 16:18:04.091044244 -0300 +++ after 2022-03-29 16:18:11.692238906 -0300 @@ -20,6 +20,7 @@ [21] = "PAGEOUT", [22] = "POPULATE_READ", [23] = "POPULATE_WRITE", + [24] = "DONTNEED_LOCKED", [100] = "HWPOISON", [101] = "SOFT_OFFLINE", }; $ I.e. now when madvise gets those behaviours as args, 'perf trace' will be able to translate from the number to a human readable string and to use the strings in tracepoint filter expressions. This addresses the following perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/asm-generic/mman-common.h' differs from latest version at 'include/uapi/asm-generic/mman-common.h' diff -u tools/include/uapi/asm-generic/mman-common.h include/uapi/asm-generic/mman-common.h Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Johannes Weiner Cc: Namhyung Kim Link: http://lore.kernel.org/lkml/YkNcUfeh795yqGMV@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/asm-generic/mman-common.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/include') diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h index 1567a3294c3d..6c1aa92a92e4 100644 --- a/tools/include/uapi/asm-generic/mman-common.h +++ b/tools/include/uapi/asm-generic/mman-common.h @@ -75,6 +75,8 @@ #define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */ #define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */ +#define MADV_DONTNEED_LOCKED 24 /* like DONTNEED, but drop locked pages too */ + /* compatibility flags */ #define MAP_FILE 0 -- cgit From 7ceda0cfcafee15e377ab532b37625bacda5eb84 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 9 May 2021 09:39:02 -0300 Subject: tools headers UAPI: Sync linux/kvm.h with the kernel sources To pick the changes in: 6d8491910fcd3324 ("KVM: x86: Introduce KVM_CAP_DISABLE_QUIRKS2") ef11c9463ae00630 ("KVM: s390: Add vm IOCTL for key checked guest absolute memory access") e9e9feebcbc14b17 ("KVM: s390: Add optional storage key checking to MEMOP IOCTL") That just rebuilds perf, as these patches don't add any new KVM ioctl to be harvested for the the 'perf trace' ioctl syscall argument beautifiers. This is also by now used by tools/testing/selftests/kvm/, a simple test build succeeded. This silences this perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/kvm.h' differs from latest version at 'include/uapi/linux/kvm.h' diff -u tools/include/uapi/linux/kvm.h include/uapi/linux/kvm.h Cc: Christian Borntraeger Cc: Janis Schoetterl-Glausch Cc: Oliver Upton Cc: Paolo Bonzini Link: http://lore.kernel.org/lkml/YkSCOWHQdir1lhdJ@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/kvm.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index bbc6b7c2dc1b..91a6fe4e02c0 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -562,9 +562,12 @@ struct kvm_s390_mem_op { __u32 op; /* type of operation */ __u64 buf; /* buffer in userspace */ union { - __u8 ar; /* the access register number */ + struct { + __u8 ar; /* the access register number */ + __u8 key; /* access key, ignored if flag unset */ + }; __u32 sida_offset; /* offset into the sida */ - __u8 reserved[32]; /* should be set to 0 */ + __u8 reserved[32]; /* ignored */ }; }; /* types for kvm_s390_mem_op->op */ @@ -572,9 +575,12 @@ struct kvm_s390_mem_op { #define KVM_S390_MEMOP_LOGICAL_WRITE 1 #define KVM_S390_MEMOP_SIDA_READ 2 #define KVM_S390_MEMOP_SIDA_WRITE 3 +#define KVM_S390_MEMOP_ABSOLUTE_READ 4 +#define KVM_S390_MEMOP_ABSOLUTE_WRITE 5 /* flags for kvm_s390_mem_op->flags */ #define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0) #define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1) +#define KVM_S390_MEMOP_F_SKEY_PROTECTION (1ULL << 2) /* for KVM_INTERRUPT */ struct kvm_interrupt { @@ -1137,6 +1143,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_PPC_AIL_MODE_3 210 #define KVM_CAP_S390_MEM_OP_EXTENSION 211 #define KVM_CAP_PMU_CAPABILITY 212 +#define KVM_CAP_DISABLE_QUIRKS2 213 #ifdef KVM_CAP_IRQ_ROUTING -- cgit From f444b2d15f7a025416ace9ec298f0b93ef68be68 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 13 Nov 2021 11:08:31 -0300 Subject: tools headers UAPI: Sync drm/i915_drm.h with the kernel sources To pick up the changes in: caa574ffc4aaf4f2 ("drm/i915/uapi: document behaviour for DG2 64K support") That don't add any new ioctl, so no changes in tooling. This silences this perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/drm/i915_drm.h' differs from latest version at 'include/uapi/drm/i915_drm.h' diff -u tools/include/uapi/drm/i915_drm.h include/uapi/drm/i915_drm.h Cc: Lucas De Marchi Cc: Matthew Auld Link: http://lore.kernel.org/lkml/YkSChHqaOApscFQ0@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/drm/i915_drm.h | 45 ++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'tools/include') diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index 914ebd9290e5..05c3642aaece 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h @@ -1118,10 +1118,16 @@ struct drm_i915_gem_exec_object2 { /** * When the EXEC_OBJECT_PINNED flag is specified this is populated by * the user with the GTT offset at which this object will be pinned. + * * When the I915_EXEC_NO_RELOC flag is specified this must contain the * presumed_offset of the object. + * * During execbuffer2 the kernel populates it with the value of the * current GTT offset of the object, for future presumed_offset writes. + * + * See struct drm_i915_gem_create_ext for the rules when dealing with + * alignment restrictions with I915_MEMORY_CLASS_DEVICE, on devices with + * minimum page sizes, like DG2. */ __u64 offset; @@ -3144,11 +3150,40 @@ struct drm_i915_gem_create_ext { * * The (page-aligned) allocated size for the object will be returned. * - * Note that for some devices we have might have further minimum - * page-size restrictions(larger than 4K), like for device local-memory. - * However in general the final size here should always reflect any - * rounding up, if for example using the I915_GEM_CREATE_EXT_MEMORY_REGIONS - * extension to place the object in device local-memory. + * + * DG2 64K min page size implications: + * + * On discrete platforms, starting from DG2, we have to contend with GTT + * page size restrictions when dealing with I915_MEMORY_CLASS_DEVICE + * objects. Specifically the hardware only supports 64K or larger GTT + * page sizes for such memory. The kernel will already ensure that all + * I915_MEMORY_CLASS_DEVICE memory is allocated using 64K or larger page + * sizes underneath. + * + * Note that the returned size here will always reflect any required + * rounding up done by the kernel, i.e 4K will now become 64K on devices + * such as DG2. + * + * Special DG2 GTT address alignment requirement: + * + * The GTT alignment will also need to be at least 2M for such objects. + * + * Note that due to how the hardware implements 64K GTT page support, we + * have some further complications: + * + * 1) The entire PDE (which covers a 2MB virtual address range), must + * contain only 64K PTEs, i.e mixing 4K and 64K PTEs in the same + * PDE is forbidden by the hardware. + * + * 2) We still need to support 4K PTEs for I915_MEMORY_CLASS_SYSTEM + * objects. + * + * To keep things simple for userland, we mandate that any GTT mappings + * must be aligned to and rounded up to 2MB. The kernel will internally + * pad them out to the next 2MB boundary. As this only wastes virtual + * address space and avoids userland having to copy any needlessly + * complicated PDE sharing scheme (coloring) and only affects DG2, this + * is deemed to be a good compromise. */ __u64 size; /** -- cgit From 66df0fdb5981052f3ad97c9879eda93712bdefc2 Mon Sep 17 00:00:00 2001 From: Haiyue Wang Date: Sun, 3 Apr 2022 19:53:26 +0800 Subject: bpf: Correct the comment for BTF kind bitfield The commit 8fd886911a6a ("bpf: Add BTF_KIND_FLOAT to uapi") has extended the BTF kind bitfield from 4 to 5 bits, correct the comment. Signed-off-by: Haiyue Wang Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20220403115327.205964-1-haiyue.wang@intel.com --- include/uapi/linux/btf.h | 4 ++-- tools/include/uapi/linux/btf.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/include') diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h index b0d8fea1951d..a9162a6c0284 100644 --- a/include/uapi/linux/btf.h +++ b/include/uapi/linux/btf.h @@ -33,8 +33,8 @@ struct btf_type { /* "info" bits arrangement * bits 0-15: vlen (e.g. # of struct's members) * bits 16-23: unused - * bits 24-27: kind (e.g. int, ptr, array...etc) - * bits 28-30: unused + * bits 24-28: kind (e.g. int, ptr, array...etc) + * bits 29-30: unused * bit 31: kind_flag, currently used by * struct, union and fwd */ diff --git a/tools/include/uapi/linux/btf.h b/tools/include/uapi/linux/btf.h index b0d8fea1951d..a9162a6c0284 100644 --- a/tools/include/uapi/linux/btf.h +++ b/tools/include/uapi/linux/btf.h @@ -33,8 +33,8 @@ struct btf_type { /* "info" bits arrangement * bits 0-15: vlen (e.g. # of struct's members) * bits 16-23: unused - * bits 24-27: kind (e.g. int, ptr, array...etc) - * bits 28-30: unused + * bits 24-28: kind (e.g. int, ptr, array...etc) + * bits 29-30: unused * bit 31: kind_flag, currently used by * struct, union and fwd */ -- cgit From 940442deea98b3280061095dd811e6136f1b41f6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 14 Apr 2020 09:12:55 -0300 Subject: tools include UAPI: Sync linux/vhost.h with the kernel sources To get the changes in: b04d910af330b55e ("vdpa: support exposing the count of vqs to userspace") a61280ddddaa45f9 ("vdpa: support exposing the config size to userspace") Silencing this perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/vhost.h' differs from latest version at 'include/uapi/linux/vhost.h' diff -u tools/include/uapi/linux/vhost.h include/uapi/linux/vhost.h $ diff -u tools/include/uapi/linux/vhost.h include/uapi/linux/vhost.h --- tools/include/uapi/linux/vhost.h 2021-07-15 16:17:01.840818309 -0300 +++ include/uapi/linux/vhost.h 2022-04-02 18:55:05.702522387 -0300 @@ -150,4 +150,11 @@ /* Get the valid iova range */ #define VHOST_VDPA_GET_IOVA_RANGE _IOR(VHOST_VIRTIO, 0x78, \ struct vhost_vdpa_iova_range) + +/* Get the config size */ +#define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32) + +/* Get the count of all virtqueues */ +#define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) + #endif $ tools/perf/trace/beauty/vhost_virtio_ioctl.sh > before $ cp include/uapi/linux/vhost.h tools/include/uapi/linux/vhost.h $ tools/perf/trace/beauty/vhost_virtio_ioctl.sh > after $ diff -u before after --- before 2022-04-04 14:52:25.036375145 -0300 +++ after 2022-04-04 14:52:31.906549976 -0300 @@ -38,4 +38,6 @@ [0x73] = "VDPA_GET_CONFIG", [0x76] = "VDPA_GET_VRING_NUM", [0x78] = "VDPA_GET_IOVA_RANGE", + [0x79] = "VDPA_GET_CONFIG_SIZE", + [0x80] = "VDPA_GET_VQS_COUNT", }; $ Cc: Longpeng Cc: Michael S. Tsirkin Link: https://lore.kernel.org/lkml/YksxoFcOARk%2Fldev@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/vhost.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/vhost.h b/tools/include/uapi/linux/vhost.h index c998860d7bbc..5d99e7c242a2 100644 --- a/tools/include/uapi/linux/vhost.h +++ b/tools/include/uapi/linux/vhost.h @@ -150,4 +150,11 @@ /* Get the valid iova range */ #define VHOST_VDPA_GET_IOVA_RANGE _IOR(VHOST_VIRTIO, 0x78, \ struct vhost_vdpa_iova_range) + +/* Get the config size */ +#define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32) + +/* Get the count of all virtqueues */ +#define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) + #endif -- cgit From 0738599856542bab0ebcd73cab9d8f15bddedcee Mon Sep 17 00:00:00 2001 From: Vladimir Isaev Date: Sat, 9 Apr 2022 01:44:42 +0300 Subject: libbpf: Add ARC support to bpf_tracing.h Add PT_REGS macros suitable for ARCompact and ARCv2. Signed-off-by: Vladimir Isaev Signed-off-by: Sergey Matyukevich Signed-off-by: Andrii Nakryiko Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20220408224442.599566-1-geomatsi@gmail.com --- tools/include/uapi/asm/bpf_perf_event.h | 2 ++ tools/lib/bpf/bpf_tracing.h | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'tools/include') diff --git a/tools/include/uapi/asm/bpf_perf_event.h b/tools/include/uapi/asm/bpf_perf_event.h index 39acc149d843..d7dfeab0d71a 100644 --- a/tools/include/uapi/asm/bpf_perf_event.h +++ b/tools/include/uapi/asm/bpf_perf_event.h @@ -1,5 +1,7 @@ #if defined(__aarch64__) #include "../../arch/arm64/include/uapi/asm/bpf_perf_event.h" +#elif defined(__arc__) +#include "../../arch/arc/include/uapi/asm/bpf_perf_event.h" #elif defined(__s390__) #include "../../arch/s390/include/uapi/asm/bpf_perf_event.h" #elif defined(__riscv) diff --git a/tools/lib/bpf/bpf_tracing.h b/tools/lib/bpf/bpf_tracing.h index e3a8c947e89f..01ce121c302d 100644 --- a/tools/lib/bpf/bpf_tracing.h +++ b/tools/lib/bpf/bpf_tracing.h @@ -27,6 +27,9 @@ #elif defined(__TARGET_ARCH_riscv) #define bpf_target_riscv #define bpf_target_defined +#elif defined(__TARGET_ARCH_arc) + #define bpf_target_arc + #define bpf_target_defined #else /* Fall back to what the compiler says */ @@ -54,6 +57,9 @@ #elif defined(__riscv) && __riscv_xlen == 64 #define bpf_target_riscv #define bpf_target_defined +#elif defined(__arc__) + #define bpf_target_arc + #define bpf_target_defined #endif /* no compiler target */ #endif @@ -233,6 +239,23 @@ struct pt_regs___arm64 { /* riscv does not select ARCH_HAS_SYSCALL_WRAPPER. */ #define PT_REGS_SYSCALL_REGS(ctx) ctx +#elif defined(bpf_target_arc) + +/* arc provides struct user_pt_regs instead of struct pt_regs to userspace */ +#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x)) +#define __PT_PARM1_REG scratch.r0 +#define __PT_PARM2_REG scratch.r1 +#define __PT_PARM3_REG scratch.r2 +#define __PT_PARM4_REG scratch.r3 +#define __PT_PARM5_REG scratch.r4 +#define __PT_RET_REG scratch.blink +#define __PT_FP_REG __unsupported__ +#define __PT_RC_REG scratch.r0 +#define __PT_SP_REG scratch.sp +#define __PT_IP_REG scratch.ret +/* arc does not select ARCH_HAS_SYSCALL_WRAPPER. */ +#define PT_REGS_SYSCALL_REGS(ctx) ctx + #endif #if defined(bpf_target_defined) -- cgit From 9c2970fbb425cca0256ecf0f96490e4f253fda24 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:13 +0100 Subject: tools/nolibc: use pselect6 on RISCV This arch doesn't provide the old-style select() syscall, we have to use pselect6(). Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index c1c285fe494a..ad23712f9cb5 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -1256,7 +1256,10 @@ struct sys_stat_struct { * - 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. + * + * On riscv, select() is not implemented so we have to use pselect6(). */ +#define __ARCH_WANT_SYS_PSELECT6 #define my_syscall0(num) \ ({ \ -- cgit From 930c4acc064edacd2c9d5bec1a66acacb2fb2589 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:14 +0100 Subject: tools/nolibc: guard the main file against multiple inclusion Including nolibc.h multiple times results in build errors due to multiple definitions. Let's add a guard against multiple inclusions. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index ad23712f9cb5..4660637d9b17 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -80,6 +80,8 @@ * https://w3challs.com/syscalls/ * */ +#ifndef _NOLIBC_H +#define _NOLIBC_H #include #include @@ -2582,3 +2584,5 @@ dev_t makedev(unsigned int major, unsigned int minor) { return ((major & 0xfff) << 8) | (minor & 0xff); } + +#endif /* _NOLIBC_H */ -- cgit From 967cce191f50090d5cbd3841ee2bbb7835afeae2 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:15 +0100 Subject: tools/nolibc/std: move the standard type definitions to std.h The ordering of includes and definitions for now is a bit of a mess, as for example asm/signal.h is included after int definitions, but plenty of structures are defined later as they rely on other includes. Let's move the standard type definitions to a dedicated file that is included first. We also move NULL there. This way all other includes are aware of it, and we can bring asm/signal.h back to the top of the file. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 42 +++++-------------------------------- tools/include/nolibc/std.h | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 37 deletions(-) create mode 100644 tools/include/nolibc/std.h (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 4660637d9b17..186a78c25326 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -83,7 +83,12 @@ #ifndef _NOLIBC_H #define _NOLIBC_H +/* standard type definitions */ +#include "std.h" + +/* system includes */ #include +#include // for SIGCHLD #include #include #include @@ -106,40 +111,6 @@ static int errno; */ #define MAX_ERRNO 4095 -/* Declare a few quite common macros and types that usually are in stdlib.h, - * stdint.h, ctype.h, unistd.h and a few other common locations. - */ - -#define NULL ((void *)0) - -/* stdint types */ -typedef unsigned char uint8_t; -typedef signed char int8_t; -typedef unsigned short uint16_t; -typedef signed short int16_t; -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 signed long ssize_t; -typedef unsigned long uintptr_t; -typedef signed long intptr_t; -typedef signed long ptrdiff_t; - -/* for stat() */ -typedef unsigned int dev_t; -typedef unsigned long ino_t; -typedef unsigned int mode_t; -typedef signed int pid_t; -typedef unsigned int uid_t; -typedef unsigned int gid_t; -typedef unsigned long nlink_t; -typedef signed long off_t; -typedef signed long blksize_t; -typedef signed long blkcnt_t; -typedef signed long time_t; - /* for poll() */ struct pollfd { int fd; @@ -248,9 +219,6 @@ struct stat { #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define WIFEXITED(status) (((status) & 0x7f) == 0) -/* for SIGCHLD */ -#include - /* Below comes the architecture-specific code. For each architecture, we have * the syscall declarations and the _start code definition. This is the only * global part. On all architectures the kernel puts everything in the stack diff --git a/tools/include/nolibc/std.h b/tools/include/nolibc/std.h new file mode 100644 index 000000000000..1747ae125392 --- /dev/null +++ b/tools/include/nolibc/std.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * Standard definitions and types for NOLIBC + * Copyright (C) 2017-2021 Willy Tarreau + */ + +#ifndef _NOLIBC_STD_H +#define _NOLIBC_STD_H + +/* Declare a few quite common macros and types that usually are in stdlib.h, + * stdint.h, ctype.h, unistd.h and a few other common locations. Please place + * integer type definitions and generic macros here, but avoid OS-specific and + * syscall-specific stuff, as this file is expected to be included very early. + */ + +/* note: may already be defined */ +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* stdint types */ +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned short uint16_t; +typedef signed short int16_t; +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 signed long ssize_t; +typedef unsigned long uintptr_t; +typedef signed long intptr_t; +typedef signed long ptrdiff_t; + +/* those are commonly provided by sys/types.h */ +typedef unsigned int dev_t; +typedef unsigned long ino_t; +typedef unsigned int mode_t; +typedef signed int pid_t; +typedef unsigned int uid_t; +typedef unsigned int gid_t; +typedef unsigned long nlink_t; +typedef signed long off_t; +typedef signed long blksize_t; +typedef signed long blkcnt_t; +typedef signed long time_t; + +#endif /* _NOLIBC_STD_H */ -- cgit From cc7a492ad0a076dff5cb4281b1516676d7924fcf Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:16 +0100 Subject: tools/nolibc/types: split syscall-specific definitions into their own files The macros and type definitions used by a number of syscalls were moved to types.h where they will be easier to maintain. A few of them are arch-specific and must not be moved there (e.g. O_*, sys_stat_struct). A warning about them was placed at the top of the file. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 110 +--------------------------------- tools/include/nolibc/types.h | 133 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 108 deletions(-) create mode 100644 tools/include/nolibc/types.h (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 186a78c25326..3719959e6f57 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -94,7 +94,9 @@ #include #include #include +#include "types.h" +/* Used by programs to avoid std includes */ #define NOLIBC /* this way it will be removed if unused */ @@ -111,114 +113,6 @@ static int errno; */ #define MAX_ERRNO 4095 -/* for poll() */ -struct pollfd { - int fd; - short int events; - short int revents; -}; - -/* for getdents64() */ -struct linux_dirent64 { - uint64_t d_ino; - int64_t d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[]; -}; - -/* commonly an fd_set represents 256 FDs */ -#define FD_SETSIZE 256 -typedef struct { uint32_t fd32[FD_SETSIZE/32]; } fd_set; - -/* needed by wait4() */ -struct rusage { - struct timeval ru_utime; - struct timeval ru_stime; - long ru_maxrss; - long ru_ixrss; - long ru_idrss; - long ru_isrss; - long ru_minflt; - long ru_majflt; - long ru_nswap; - long ru_inblock; - long ru_oublock; - long ru_msgsnd; - long ru_msgrcv; - long ru_nsignals; - long ru_nvcsw; - long ru_nivcsw; -}; - -/* stat flags (WARNING, octal here) */ -#define S_IFDIR 0040000 -#define S_IFCHR 0020000 -#define S_IFBLK 0060000 -#define S_IFREG 0100000 -#define S_IFIFO 0010000 -#define S_IFLNK 0120000 -#define S_IFSOCK 0140000 -#define S_IFMT 0170000 - -#define S_ISDIR(mode) (((mode) & S_IFDIR) == S_IFDIR) -#define S_ISCHR(mode) (((mode) & S_IFCHR) == S_IFCHR) -#define S_ISBLK(mode) (((mode) & S_IFBLK) == S_IFBLK) -#define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG) -#define S_ISFIFO(mode) (((mode) & S_IFIFO) == S_IFIFO) -#define S_ISLNK(mode) (((mode) & S_IFLNK) == S_IFLNK) -#define S_ISSOCK(mode) (((mode) & S_IFSOCK) == S_IFSOCK) - -#define DT_UNKNOWN 0 -#define DT_FIFO 1 -#define DT_CHR 2 -#define DT_DIR 4 -#define DT_BLK 6 -#define DT_REG 8 -#define DT_LNK 10 -#define DT_SOCK 12 - -/* all the *at functions */ -#ifndef AT_FDCWD -#define AT_FDCWD -100 -#endif - -/* lseek */ -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 - -/* reboot */ -#define LINUX_REBOOT_MAGIC1 0xfee1dead -#define LINUX_REBOOT_MAGIC2 0x28121969 -#define LINUX_REBOOT_CMD_HALT 0xcdef0123 -#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc -#define LINUX_REBOOT_CMD_RESTART 0x01234567 -#define LINUX_REBOOT_CMD_SW_SUSPEND 0xd000fce2 - - -/* The format of the struct as returned by the libc to the application, which - * significantly differs from the format returned by the stat() syscall flavours. - */ -struct stat { - dev_t st_dev; /* ID of device containing file */ - ino_t st_ino; /* inode number */ - mode_t st_mode; /* protection */ - nlink_t st_nlink; /* number of hard links */ - uid_t st_uid; /* user ID of owner */ - gid_t st_gid; /* group ID of owner */ - dev_t st_rdev; /* device ID (if special file) */ - off_t st_size; /* total size, in bytes */ - blksize_t st_blksize; /* blocksize for file system I/O */ - blkcnt_t st_blocks; /* number of 512B blocks allocated */ - time_t st_atime; /* time of last access */ - time_t st_mtime; /* time of last modification */ - time_t st_ctime; /* time of last status change */ -}; - -#define WEXITSTATUS(status) (((status) & 0xff00) >> 8) -#define WIFEXITED(status) (((status) & 0x7f) == 0) - /* Below comes the architecture-specific code. For each architecture, we have * the syscall declarations and the _start code definition. This is the only * global part. On all architectures the kernel puts everything in the stack diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h new file mode 100644 index 000000000000..2f09abaf95f1 --- /dev/null +++ b/tools/include/nolibc/types.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * Special types used by various syscalls for NOLIBC + * Copyright (C) 2017-2021 Willy Tarreau + */ + +#ifndef _NOLIBC_TYPES_H +#define _NOLIBC_TYPES_H + +#include "std.h" +#include + + +/* 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. + */ + +/* stat flags (WARNING, octal here) */ +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFBLK 0060000 +#define S_IFREG 0100000 +#define S_IFIFO 0010000 +#define S_IFLNK 0120000 +#define S_IFSOCK 0140000 +#define S_IFMT 0170000 + +#define S_ISDIR(mode) (((mode) & S_IFDIR) == S_IFDIR) +#define S_ISCHR(mode) (((mode) & S_IFCHR) == S_IFCHR) +#define S_ISBLK(mode) (((mode) & S_IFBLK) == S_IFBLK) +#define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG) +#define S_ISFIFO(mode) (((mode) & S_IFIFO) == S_IFIFO) +#define S_ISLNK(mode) (((mode) & S_IFLNK) == S_IFLNK) +#define S_ISSOCK(mode) (((mode) & S_IFSOCK) == S_IFSOCK) + +/* dirent types */ +#define DT_UNKNOWN 0x0 +#define DT_FIFO 0x1 +#define DT_CHR 0x2 +#define DT_DIR 0x4 +#define DT_BLK 0x6 +#define DT_REG 0x8 +#define DT_LNK 0xa +#define DT_SOCK 0xc + +/* commonly an fd_set represents 256 FDs */ +#define FD_SETSIZE 256 + +/* Special FD used by all the *at functions */ +#ifndef AT_FDCWD +#define AT_FDCWD (-100) +#endif + +/* whence values for lseek() */ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +/* cmd for reboot() */ +#define LINUX_REBOOT_MAGIC1 0xfee1dead +#define LINUX_REBOOT_MAGIC2 0x28121969 +#define LINUX_REBOOT_CMD_HALT 0xcdef0123 +#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc +#define LINUX_REBOOT_CMD_RESTART 0x01234567 +#define LINUX_REBOOT_CMD_SW_SUSPEND 0xd000fce2 + +/* Macros used on waitpid()'s return status */ +#define WEXITSTATUS(status) (((status) & 0xff00) >> 8) +#define WIFEXITED(status) (((status) & 0x7f) == 0) + + +/* for select() */ +typedef struct { + uint32_t fd32[FD_SETSIZE / 32]; +} fd_set; + +/* for poll() */ +struct pollfd { + int fd; + short int events; + short int revents; +}; + +/* for getdents64() */ +struct linux_dirent64 { + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[]; +}; + +/* needed by wait4() */ +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; + +/* The format of the struct as returned by the libc to the application, which + * significantly differs from the format returned by the stat() syscall flavours. + */ +struct stat { + dev_t st_dev; /* ID of device containing file */ + ino_t st_ino; /* inode number */ + mode_t st_mode; /* protection */ + nlink_t st_nlink; /* number of hard links */ + uid_t st_uid; /* user ID of owner */ + gid_t st_gid; /* group ID of owner */ + dev_t st_rdev; /* device ID (if special file) */ + off_t st_size; /* total size, in bytes */ + blksize_t st_blksize; /* blocksize for file system I/O */ + blkcnt_t st_blocks; /* number of 512B blocks allocated */ + time_t st_atime; /* time of last access */ + time_t st_mtime; /* time of last modification */ + time_t st_ctime; /* time of last status change */ +}; + +#endif /* _NOLIBC_TYPES_H */ -- cgit From 271661c1cde5ff47eb7af9946866cd66b70dc328 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:17 +0100 Subject: tools/nolibc/arch: split arch-specific code into individual files In order to ease maintenance, this splits the arch-specific code into one file per architecture. A common file "arch.h" is used to include the right file among arch-* based on the detected architecture. Projects which are already split per architecture could simply rename these files to $arch/arch.h and get rid of the common arch.h. For this reason, include guards were placed into each arch-specific file. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-aarch64.h | 199 ++++++ tools/include/nolibc/arch-arm.h | 204 ++++++ tools/include/nolibc/arch-i386.h | 196 ++++++ tools/include/nolibc/arch-mips.h | 215 +++++++ tools/include/nolibc/arch-riscv.h | 204 ++++++ tools/include/nolibc/arch-x86_64.h | 215 +++++++ tools/include/nolibc/arch.h | 32 + tools/include/nolibc/nolibc.h | 1187 +---------------------------------- 8 files changed, 1266 insertions(+), 1186 deletions(-) create mode 100644 tools/include/nolibc/arch-aarch64.h create mode 100644 tools/include/nolibc/arch-arm.h create mode 100644 tools/include/nolibc/arch-i386.h create mode 100644 tools/include/nolibc/arch-mips.h create mode 100644 tools/include/nolibc/arch-riscv.h create mode 100644 tools/include/nolibc/arch-x86_64.h create mode 100644 tools/include/nolibc/arch.h (limited to 'tools/include') diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h new file mode 100644 index 000000000000..443de5fb7f54 --- /dev/null +++ b/tools/include/nolibc/arch-aarch64.h @@ -0,0 +1,199 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * AARCH64 specific definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_ARCH_AARCH64_H +#define _NOLIBC_ARCH_AARCH64_H + +/* O_* macros for fcntl/open are architecture-specific */ +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_CREAT 0x40 +#define O_EXCL 0x80 +#define O_NOCTTY 0x100 +#define O_TRUNC 0x200 +#define O_APPEND 0x400 +#define O_NONBLOCK 0x800 +#define O_DIRECTORY 0x4000 + +/* 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]; +}; + +/* Syscalls for AARCH64 : + * - registers are 64-bit + * - stack is 16-byte aligned + * - syscall number is passed in x8 + * - arguments are in x0, x1, x2, x3, x4, x5 + * - the system call is performed by calling svc 0 + * - syscall return comes in x0. + * - 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. + * + * On aarch64, select() is not implemented so we have to use pselect6(). + */ +#define __ARCH_WANT_SYS_PSELECT6 + +#define my_syscall0(num) \ +({ \ + register long _num asm("x8") = (num); \ + register long _arg1 asm("x0"); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + register long _num asm("x8") = (num); \ + register long _arg1 asm("x0") = (long)(arg1); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num asm("x8") = (num); \ + register long _arg1 asm("x0") = (long)(arg1); \ + register long _arg2 asm("x1") = (long)(arg2); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), "r"(_arg2), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num asm("x8") = (num); \ + register long _arg1 asm("x0") = (long)(arg1); \ + register long _arg2 asm("x1") = (long)(arg2); \ + register long _arg3 asm("x2") = (long)(arg3); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num asm("x8") = (num); \ + register long _arg1 asm("x0") = (long)(arg1); \ + register long _arg2 asm("x1") = (long)(arg2); \ + register long _arg3 asm("x2") = (long)(arg3); \ + register long _arg4 asm("x3") = (long)(arg4); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num asm("x8") = (num); \ + register long _arg1 asm("x0") = (long)(arg1); \ + register long _arg2 asm("x1") = (long)(arg2); \ + register long _arg3 asm("x2") = (long)(arg3); \ + register long _arg4 asm("x3") = (long)(arg4); \ + register long _arg5 asm("x4") = (long)(arg5); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r" (_arg1) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num asm("x8") = (num); \ + register long _arg1 asm("x0") = (long)(arg1); \ + register long _arg2 asm("x1") = (long)(arg2); \ + register long _arg3 asm("x2") = (long)(arg3); \ + register long _arg4 asm("x3") = (long)(arg4); \ + register long _arg5 asm("x4") = (long)(arg5); \ + register long _arg6 asm("x5") = (long)(arg6); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r" (_arg1) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_arg6), "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +/* startup code */ +asm(".section .text\n" + ".global _start\n" + "_start:\n" + "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 + "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" + ""); + +#endif // _NOLIBC_ARCH_AARCH64_H diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h new file mode 100644 index 000000000000..66f687ad987f --- /dev/null +++ b/tools/include/nolibc/arch-arm.h @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * ARM specific definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_ARCH_ARM_H +#define _NOLIBC_ARCH_ARM_H + +/* O_* macros for fcntl/open are architecture-specific */ +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_CREAT 0x40 +#define O_EXCL 0x80 +#define O_NOCTTY 0x100 +#define O_TRUNC 0x200 +#define O_APPEND 0x400 +#define O_NONBLOCK 0x800 +#define O_DIRECTORY 0x4000 + +/* 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]; +}; + +/* Syscalls for ARM in ARM or Thumb modes : + * - registers are 32-bit + * - stack is 8-byte aligned + * ( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html) + * - syscall number is passed in r7 + * - arguments are in r0, r1, r2, r3, r4, r5 + * - the system call is performed by calling svc #0 + * - syscall return comes in r0. + * - only lr is clobbered. + * - 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. + * - the syscall number is always specified last in order to allow to force + * some registers before (gcc refuses a %-register at the last position). + * + * Also, ARM supports the old_select syscall if newselect is not available + */ +#define __ARCH_WANT_SYS_OLD_SELECT + +#define my_syscall0(num) \ +({ \ + register long _num asm("r7") = (num); \ + register long _arg1 asm("r0"); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + register long _num asm("r7") = (num); \ + register long _arg1 asm("r0") = (long)(arg1); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ +}) + +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num asm("r7") = (num); \ + register long _arg1 asm("r0") = (long)(arg1); \ + register long _arg2 asm("r1") = (long)(arg2); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), "r"(_arg2), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ +}) + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num asm("r7") = (num); \ + register long _arg1 asm("r0") = (long)(arg1); \ + register long _arg2 asm("r1") = (long)(arg2); \ + register long _arg3 asm("r2") = (long)(arg3); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ +}) + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num asm("r7") = (num); \ + register long _arg1 asm("r0") = (long)(arg1); \ + register long _arg2 asm("r1") = (long)(arg2); \ + register long _arg3 asm("r2") = (long)(arg3); \ + register long _arg4 asm("r3") = (long)(arg4); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ +}) + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num asm("r7") = (num); \ + register long _arg1 asm("r0") = (long)(arg1); \ + register long _arg2 asm("r1") = (long)(arg2); \ + register long _arg3 asm("r2") = (long)(arg3); \ + register long _arg4 asm("r3") = (long)(arg4); \ + register long _arg5 asm("r4") = (long)(arg5); \ + \ + asm volatile ( \ + "svc #0\n" \ + : "=r" (_arg1) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ +}) + +/* startup code */ +asm(".section .text\n" + ".global _start\n" + "_start:\n" +#if defined(__THUMBEB__) || defined(__THUMBEL__) + /* We enter here in 32-bit mode but if some previous functions were in + * 16-bit mode, the assembler cannot know, so we need to tell it we're in + * 32-bit now, then switch to 16-bit (is there a better way to do it than + * adding 1 by hand ?) and tell the asm we're now in 16-bit mode so that + * it generates correct instructions. Note that we do not support thumb1. + */ + ".code 32\n" + "add r0, pc, #1\n" + "bx r0\n" + ".code 16\n" +#endif + "pop {%r0}\n" // argc was in the stack + "mov %r1, %sp\n" // argv = sp + "add %r2, %r1, %r0, lsl #2\n" // envp = argv + 4*argc ... + "add %r2, %r2, $4\n" // ... + 4 + "and %r3, %r1, $-8\n" // AAPCS : sp must be 8-byte aligned in the + "mov %sp, %r3\n" // callee, an bl doesn't push (lr=pc) + "bl main\n" // main() returns the status code, we'll exit with it. + "movs r7, $1\n" // NR_exit == 1 + "svc $0x00\n" + ""); + +#endif // _NOLIBC_ARCH_ARM_H diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h new file mode 100644 index 000000000000..32f42e2cee26 --- /dev/null +++ b/tools/include/nolibc/arch-i386.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * i386 specific definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_ARCH_I386_H +#define _NOLIBC_ARCH_I386_H + +/* O_* macros for fcntl/open are architecture-specific */ +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_CREAT 0x40 +#define O_EXCL 0x80 +#define O_NOCTTY 0x100 +#define O_TRUNC 0x200 +#define O_APPEND 0x400 +#define O_NONBLOCK 0x800 +#define O_DIRECTORY 0x10000 + +/* 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]; +}; + +/* Syscalls for i386 : + * - mostly similar to x86_64 + * - registers are 32-bit + * - syscall number is passed in eax + * - arguments are in ebx, ecx, edx, esi, edi, ebp respectively + * - all registers are preserved (except eax of course) + * - the system call is performed by calling int $0x80 + * - syscall return comes in eax + * - 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. + * - the syscall number is always specified last in order to allow to force + * some registers before (gcc refuses a %-register at the last position). + * + * Also, i386 supports the old_select syscall if newselect is not available + */ +#define __ARCH_WANT_SYS_OLD_SELECT + +#define my_syscall0(num) \ +({ \ + long _ret; \ + register long _num asm("eax") = (num); \ + \ + asm volatile ( \ + "int $0x80\n" \ + : "=a" (_ret) \ + : "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + long _ret; \ + register long _num asm("eax") = (num); \ + register long _arg1 asm("ebx") = (long)(arg1); \ + \ + asm volatile ( \ + "int $0x80\n" \ + : "=a" (_ret) \ + : "r"(_arg1), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall2(num, arg1, arg2) \ +({ \ + long _ret; \ + register long _num asm("eax") = (num); \ + register long _arg1 asm("ebx") = (long)(arg1); \ + register long _arg2 asm("ecx") = (long)(arg2); \ + \ + asm volatile ( \ + "int $0x80\n" \ + : "=a" (_ret) \ + : "r"(_arg1), "r"(_arg2), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + long _ret; \ + register long _num asm("eax") = (num); \ + register long _arg1 asm("ebx") = (long)(arg1); \ + register long _arg2 asm("ecx") = (long)(arg2); \ + register long _arg3 asm("edx") = (long)(arg3); \ + \ + asm volatile ( \ + "int $0x80\n" \ + : "=a" (_ret) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + long _ret; \ + register long _num asm("eax") = (num); \ + register long _arg1 asm("ebx") = (long)(arg1); \ + register long _arg2 asm("ecx") = (long)(arg2); \ + register long _arg3 asm("edx") = (long)(arg3); \ + register long _arg4 asm("esi") = (long)(arg4); \ + \ + asm volatile ( \ + "int $0x80\n" \ + : "=a" (_ret) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + long _ret; \ + register long _num asm("eax") = (num); \ + register long _arg1 asm("ebx") = (long)(arg1); \ + register long _arg2 asm("ecx") = (long)(arg2); \ + register long _arg3 asm("edx") = (long)(arg3); \ + register long _arg4 asm("esi") = (long)(arg4); \ + register long _arg5 asm("edi") = (long)(arg5); \ + \ + asm volatile ( \ + "int $0x80\n" \ + : "=a" (_ret) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ +}) + +/* startup code */ +/* + * i386 System V ABI mandates: + * 1) last pushed argument must be 16-byte aligned. + * 2) The deepest stack frame should be set to zero + * + */ +asm(".section .text\n" + ".global _start\n" + "_start:\n" + "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) + "xor %ebp, %ebp\n" // zero the stack frame + "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 + ""); + +#endif // _NOLIBC_ARCH_I386_H diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h new file mode 100644 index 000000000000..e330201dde6a --- /dev/null +++ b/tools/include/nolibc/arch-mips.h @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * MIPS specific definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_ARCH_MIPS_H +#define _NOLIBC_ARCH_MIPS_H + +/* O_* macros for fcntl/open are architecture-specific */ +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_APPEND 0x0008 +#define O_NONBLOCK 0x0080 +#define O_CREAT 0x0100 +#define O_TRUNC 0x0200 +#define O_EXCL 0x0400 +#define O_NOCTTY 0x0800 +#define O_DIRECTORY 0x10000 + +/* 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]; +}; + +/* Syscalls for MIPS ABI O32 : + * - WARNING! there's always a delayed slot! + * - WARNING again, the syntax is different, registers take a '$' and numbers + * do not. + * - registers are 32-bit + * - stack is 8-byte aligned + * - syscall number is passed in v0 (starts at 0xfa0). + * - arguments are in a0, a1, a2, a3, then the stack. The caller needs to + * leave some room in the stack for the callee to save a0..a3 if needed. + * - Many registers are clobbered, in fact only a0..a2 and s0..s8 are + * preserved. See: https://www.linux-mips.org/wiki/Syscall as well as + * scall32-o32.S in the kernel sources. + * - the system call is performed by calling "syscall" + * - syscall return comes in v0, and register a3 needs to be checked to know + * if an error occurred, in which case errno is in v0. + * - 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 my_syscall0(num) \ +({ \ + register long _num asm("v0") = (num); \ + register long _arg4 asm("a3"); \ + \ + 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" \ + ); \ + _arg4 ? -_num : _num; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + register long _num asm("v0") = (num); \ + register long _arg1 asm("a0") = (long)(arg1); \ + register long _arg4 asm("a3"); \ + \ + 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" \ + ); \ + _arg4 ? -_num : _num; \ +}) + +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num asm("v0") = (num); \ + register long _arg1 asm("a0") = (long)(arg1); \ + register long _arg2 asm("a1") = (long)(arg2); \ + register long _arg4 asm("a3"); \ + \ + 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" \ + ); \ + _arg4 ? -_num : _num; \ +}) + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + 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"); \ + \ + 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" \ + ); \ + _arg4 ? -_num : _num; \ +}) + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + 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); \ + \ + 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" \ + ); \ + _arg4 ? -_num : _num; \ +}) + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + 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); \ + \ + asm volatile ( \ + "addiu $sp, $sp, -32\n" \ + "sw %7, 16($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) \ + : "memory", "cc", "at", "v1", "hi", "lo", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + ); \ + _arg4 ? -_num : _num; \ +}) + +/* startup code, note that it's called __start on MIPS */ +asm(".section .text\n" + ".set nomips16\n" + ".global __start\n" + ".set noreorder\n" + ".option pic0\n" + ".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 + "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" + ""); + +#endif // _NOLIBC_ARCH_MIPS_H diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h new file mode 100644 index 000000000000..9d5ff78f606b --- /dev/null +++ b/tools/include/nolibc/arch-riscv.h @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * RISCV (32 and 64) specific definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_ARCH_RISCV_H +#define _NOLIBC_ARCH_RISCV_H + +/* O_* macros for fcntl/open are architecture-specific */ +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_CREAT 0x100 +#define O_EXCL 0x200 +#define O_NOCTTY 0x400 +#define O_TRUNC 0x1000 +#define O_APPEND 0x2000 +#define O_NONBLOCK 0x4000 +#define O_DIRECTORY 0x200000 + +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" +#elif __riscv_xlen == 32 +#define PTRLOG "2" +#define SZREG "4" +#endif + +/* Syscalls for RISCV : + * - stack is 16-byte aligned + * - syscall number is passed in a7 + * - arguments are in a0, a1, a2, a3, a4, a5 + * - the system call is performed by calling ecall + * - syscall return comes in a0 + * - 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. + * + * On riscv, select() is not implemented so we have to use pselect6(). + */ +#define __ARCH_WANT_SYS_PSELECT6 + +#define my_syscall0(num) \ +({ \ + register long _num asm("a7") = (num); \ + register long _arg1 asm("a0"); \ + \ + asm volatile ( \ + "ecall\n\t" \ + : "=r"(_arg1) \ + : "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + register long _num asm("a7") = (num); \ + register long _arg1 asm("a0") = (long)(arg1); \ + \ + asm volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num asm("a7") = (num); \ + register long _arg1 asm("a0") = (long)(arg1); \ + register long _arg2 asm("a1") = (long)(arg2); \ + \ + asm volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num asm("a7") = (num); \ + register long _arg1 asm("a0") = (long)(arg1); \ + register long _arg2 asm("a1") = (long)(arg2); \ + register long _arg3 asm("a2") = (long)(arg3); \ + \ + asm volatile ( \ + "ecall\n\t" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num asm("a7") = (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); \ + \ + asm volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num asm("a7") = (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 asm("a4") = (long)(arg5); \ + \ + asm volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num asm("a7") = (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 asm("a4") = (long)(arg5); \ + register long _arg6 asm("a5") = (long)(arg6); \ + \ + asm volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +/* startup code */ +asm(".section .text\n" + ".global _start\n" + "_start:\n" + ".option push\n" + ".option norelax\n" + "lla gp, __global_pointer$\n" + ".option pop\n" + "ld 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 + "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" + ""); + +#endif // _NOLIBC_ARCH_RISCV_H diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h new file mode 100644 index 000000000000..83c4b458ada7 --- /dev/null +++ b/tools/include/nolibc/arch-x86_64.h @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * x86_64 specific definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_ARCH_X86_64_H +#define _NOLIBC_ARCH_X86_64_H + +/* O_* macros for fcntl/open are architecture-specific */ +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_CREAT 0x40 +#define O_EXCL 0x80 +#define O_NOCTTY 0x100 +#define O_TRUNC 0x200 +#define O_APPEND 0x400 +#define O_NONBLOCK 0x800 +#define O_DIRECTORY 0x10000 + +/* 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]; +}; + +/* Syscalls for x86_64 : + * - registers are 64-bit + * - syscall number is passed in rax + * - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively + * - the system call is performed by calling the syscall instruction + * - syscall return comes in rax + * - rcx and r11 are clobbered, others are preserved. + * - 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. + * - the syscall number is always specified last in order to allow to force + * some registers before (gcc refuses a %-register at the last position). + * - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1 + * Calling Conventions. + * + * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI + * + */ + +#define my_syscall0(num) \ +({ \ + long _ret; \ + register long _num asm("rax") = (num); \ + \ + asm volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + long _ret; \ + register long _num asm("rax") = (num); \ + register long _arg1 asm("rdi") = (long)(arg1); \ + \ + asm volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "r"(_arg1), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall2(num, arg1, arg2) \ +({ \ + long _ret; \ + register long _num asm("rax") = (num); \ + register long _arg1 asm("rdi") = (long)(arg1); \ + register long _arg2 asm("rsi") = (long)(arg2); \ + \ + asm volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "r"(_arg1), "r"(_arg2), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + long _ret; \ + register long _num asm("rax") = (num); \ + register long _arg1 asm("rdi") = (long)(arg1); \ + register long _arg2 asm("rsi") = (long)(arg2); \ + register long _arg3 asm("rdx") = (long)(arg3); \ + \ + asm volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + long _ret; \ + register long _num asm("rax") = (num); \ + register long _arg1 asm("rdi") = (long)(arg1); \ + register long _arg2 asm("rsi") = (long)(arg2); \ + register long _arg3 asm("rdx") = (long)(arg3); \ + register long _arg4 asm("r10") = (long)(arg4); \ + \ + asm volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + long _ret; \ + register long _num asm("rax") = (num); \ + register long _arg1 asm("rdi") = (long)(arg1); \ + register long _arg2 asm("rsi") = (long)(arg2); \ + register long _arg3 asm("rdx") = (long)(arg3); \ + register long _arg4 asm("r10") = (long)(arg4); \ + register long _arg5 asm("r8") = (long)(arg5); \ + \ + asm volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ +}) + +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + long _ret; \ + register long _num asm("rax") = (num); \ + register long _arg1 asm("rdi") = (long)(arg1); \ + register long _arg2 asm("rsi") = (long)(arg2); \ + register long _arg3 asm("rdx") = (long)(arg3); \ + register long _arg4 asm("r10") = (long)(arg4); \ + register long _arg5 asm("r8") = (long)(arg5); \ + register long _arg6 asm("r9") = (long)(arg6); \ + \ + asm volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_arg6), "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ +}) + +/* startup code */ +/* + * x86-64 System V ABI mandates: + * 1) %rsp must be 16-byte aligned right before the function call. + * 2) The deepest stack frame should be zero (the %rbp). + * + */ +asm(".section .text\n" + ".global _start\n" + "_start:\n" + "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) + "xor %ebp, %ebp\n" // zero the stack frame + "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 + ""); + +#endif // _NOLIBC_ARCH_X86_64_H diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h new file mode 100644 index 000000000000..4c6992321b0d --- /dev/null +++ b/tools/include/nolibc/arch.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * Copyright (C) 2017-2022 Willy Tarreau + */ + +/* Below comes the architecture-specific code. For each architecture, we have + * the syscall declarations and the _start code definition. This is the only + * global part. On all architectures the kernel puts everything in the stack + * before jumping to _start just above us, without any return address (_start + * is not a function but an entry pint). So at the stack pointer we find argc. + * Then argv[] begins, and ends at the first NULL. Then we have envp which + * starts and ends with a NULL as well. So envp=argv+argc+1. + */ + +#ifndef _NOLIBC_ARCH_H +#define _NOLIBC_ARCH_H + +#if defined(__x86_64__) +#include "arch-x86_64.h" +#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) +#include "arch-i386.h" +#elif defined(__ARM_EABI__) +#include "arch-arm.h" +#elif defined(__aarch64__) +#include "arch-aarch64.h" +#elif defined(__mips__) && defined(_ABIO32) +#include "arch-mips.h" +#elif defined(__riscv) +#include "arch-riscv.h" +#endif + +#endif /* _NOLIBC_ARCH_H */ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 3719959e6f57..ccad3998d824 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -94,6 +94,7 @@ #include #include #include +#include "arch.h" #include "types.h" /* Used by programs to avoid std includes */ @@ -113,1192 +114,6 @@ static int errno; */ #define MAX_ERRNO 4095 -/* Below comes the architecture-specific code. For each architecture, we have - * the syscall declarations and the _start code definition. This is the only - * global part. On all architectures the kernel puts everything in the stack - * before jumping to _start just above us, without any return address (_start - * is not a function but an entry pint). So at the stack pointer we find argc. - * Then argv[] begins, and ends at the first NULL. Then we have envp which - * starts and ends with a NULL as well. So envp=argv+argc+1. - */ - -#if defined(__x86_64__) -/* Syscalls for x86_64 : - * - registers are 64-bit - * - syscall number is passed in rax - * - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively - * - the system call is performed by calling the syscall instruction - * - syscall return comes in rax - * - rcx and r11 are clobbered, others are preserved. - * - 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. - * - the syscall number is always specified last in order to allow to force - * some registers before (gcc refuses a %-register at the last position). - * - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1 - * Calling Conventions. - * - * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI - * - */ - -#define my_syscall0(num) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall1(num, arg1) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall2(num, arg1, arg2) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - register long _arg4 asm("r10") = (long)(arg4); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - register long _arg4 asm("r10") = (long)(arg4); \ - register long _arg5 asm("r8") = (long)(arg5); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - register long _arg4 asm("r10") = (long)(arg4); \ - register long _arg5 asm("r8") = (long)(arg5); \ - register long _arg6 asm("r9") = (long)(arg6); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_arg6), "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -/* startup code */ -/* - * x86-64 System V ABI mandates: - * 1) %rsp must be 16-byte aligned right before the function call. - * 2) The deepest stack frame should be zero (the %rbp). - * - */ -asm(".section .text\n" - ".global _start\n" - "_start:\n" - "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) - "xor %ebp, %ebp\n" // zero the stack frame - "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 - ""); - -/* fcntl / open */ -#define O_RDONLY 0 -#define O_WRONLY 1 -#define O_RDWR 2 -#define O_CREAT 0x40 -#define O_EXCL 0x80 -#define O_NOCTTY 0x100 -#define O_TRUNC 0x200 -#define O_APPEND 0x400 -#define O_NONBLOCK 0x800 -#define O_DIRECTORY 0x10000 - -/* 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]; -}; - -#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) -/* Syscalls for i386 : - * - mostly similar to x86_64 - * - registers are 32-bit - * - syscall number is passed in eax - * - arguments are in ebx, ecx, edx, esi, edi, ebp respectively - * - all registers are preserved (except eax of course) - * - the system call is performed by calling int $0x80 - * - syscall return comes in eax - * - 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. - * - the syscall number is always specified last in order to allow to force - * some registers before (gcc refuses a %-register at the last position). - * - * Also, i386 supports the old_select syscall if newselect is not available - */ -#define __ARCH_WANT_SYS_OLD_SELECT - -#define my_syscall0(num) \ -({ \ - long _ret; \ - register long _num asm("eax") = (num); \ - \ - asm volatile ( \ - "int $0x80\n" \ - : "=a" (_ret) \ - : "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall1(num, arg1) \ -({ \ - long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ - \ - asm volatile ( \ - "int $0x80\n" \ - : "=a" (_ret) \ - : "r"(_arg1), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall2(num, arg1, arg2) \ -({ \ - long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ - register long _arg2 asm("ecx") = (long)(arg2); \ - \ - asm volatile ( \ - "int $0x80\n" \ - : "=a" (_ret) \ - : "r"(_arg1), "r"(_arg2), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ - register long _arg2 asm("ecx") = (long)(arg2); \ - register long _arg3 asm("edx") = (long)(arg3); \ - \ - asm volatile ( \ - "int $0x80\n" \ - : "=a" (_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ - register long _arg2 asm("ecx") = (long)(arg2); \ - register long _arg3 asm("edx") = (long)(arg3); \ - register long _arg4 asm("esi") = (long)(arg4); \ - \ - asm volatile ( \ - "int $0x80\n" \ - : "=a" (_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ - register long _arg2 asm("ecx") = (long)(arg2); \ - register long _arg3 asm("edx") = (long)(arg3); \ - register long _arg4 asm("esi") = (long)(arg4); \ - register long _arg5 asm("edi") = (long)(arg5); \ - \ - asm volatile ( \ - "int $0x80\n" \ - : "=a" (_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ -}) - -/* startup code */ -/* - * i386 System V ABI mandates: - * 1) last pushed argument must be 16-byte aligned. - * 2) The deepest stack frame should be set to zero - * - */ -asm(".section .text\n" - ".global _start\n" - "_start:\n" - "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) - "xor %ebp, %ebp\n" // zero the stack frame - "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 - ""); - -/* fcntl / open */ -#define O_RDONLY 0 -#define O_WRONLY 1 -#define O_RDWR 2 -#define O_CREAT 0x40 -#define O_EXCL 0x80 -#define O_NOCTTY 0x100 -#define O_TRUNC 0x200 -#define O_APPEND 0x400 -#define O_NONBLOCK 0x800 -#define O_DIRECTORY 0x10000 - -/* 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]; -}; - -#elif defined(__ARM_EABI__) -/* Syscalls for ARM in ARM or Thumb modes : - * - registers are 32-bit - * - stack is 8-byte aligned - * ( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html) - * - syscall number is passed in r7 - * - arguments are in r0, r1, r2, r3, r4, r5 - * - the system call is performed by calling svc #0 - * - syscall return comes in r0. - * - only lr is clobbered. - * - 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. - * - the syscall number is always specified last in order to allow to force - * some registers before (gcc refuses a %-register at the last position). - * - * Also, ARM supports the old_select syscall if newselect is not available - */ -#define __ARCH_WANT_SYS_OLD_SELECT - -#define my_syscall0(num) \ -({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0"); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ -}) - -#define my_syscall1(num, arg1) \ -({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_arg1), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ -}) - -#define my_syscall2(num, arg1, arg2) \ -({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ - register long _arg2 asm("r1") = (long)(arg2); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_arg1), "r"(_arg2), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ -}) - -#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ - register long _arg2 asm("r1") = (long)(arg2); \ - register long _arg3 asm("r2") = (long)(arg3); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ -}) - -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ - register long _arg2 asm("r1") = (long)(arg2); \ - register long _arg3 asm("r2") = (long)(arg3); \ - register long _arg4 asm("r3") = (long)(arg4); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ -}) - -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ - register long _arg2 asm("r1") = (long)(arg2); \ - register long _arg3 asm("r2") = (long)(arg3); \ - register long _arg4 asm("r3") = (long)(arg4); \ - register long _arg5 asm("r4") = (long)(arg5); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r" (_arg1) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ -}) - -/* startup code */ -asm(".section .text\n" - ".global _start\n" - "_start:\n" -#if defined(__THUMBEB__) || defined(__THUMBEL__) - /* We enter here in 32-bit mode but if some previous functions were in - * 16-bit mode, the assembler cannot know, so we need to tell it we're in - * 32-bit now, then switch to 16-bit (is there a better way to do it than - * adding 1 by hand ?) and tell the asm we're now in 16-bit mode so that - * it generates correct instructions. Note that we do not support thumb1. - */ - ".code 32\n" - "add r0, pc, #1\n" - "bx r0\n" - ".code 16\n" -#endif - "pop {%r0}\n" // argc was in the stack - "mov %r1, %sp\n" // argv = sp - "add %r2, %r1, %r0, lsl #2\n" // envp = argv + 4*argc ... - "add %r2, %r2, $4\n" // ... + 4 - "and %r3, %r1, $-8\n" // AAPCS : sp must be 8-byte aligned in the - "mov %sp, %r3\n" // callee, an bl doesn't push (lr=pc) - "bl main\n" // main() returns the status code, we'll exit with it. - "movs r7, $1\n" // NR_exit == 1 - "svc $0x00\n" - ""); - -/* fcntl / open */ -#define O_RDONLY 0 -#define O_WRONLY 1 -#define O_RDWR 2 -#define O_CREAT 0x40 -#define O_EXCL 0x80 -#define O_NOCTTY 0x100 -#define O_TRUNC 0x200 -#define O_APPEND 0x400 -#define O_NONBLOCK 0x800 -#define O_DIRECTORY 0x4000 - -/* 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]; -}; - -#elif defined(__aarch64__) -/* Syscalls for AARCH64 : - * - registers are 64-bit - * - stack is 16-byte aligned - * - syscall number is passed in x8 - * - arguments are in x0, x1, x2, x3, x4, x5 - * - the system call is performed by calling svc 0 - * - syscall return comes in x0. - * - 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. - * - * On aarch64, select() is not implemented so we have to use pselect6(). - */ -#define __ARCH_WANT_SYS_PSELECT6 - -#define my_syscall0(num) \ -({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0"); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall1(num, arg1) \ -({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_arg1), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall2(num, arg1, arg2) \ -({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_arg1), "r"(_arg2), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ - register long _arg3 asm("x2") = (long)(arg3); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ - register long _arg3 asm("x2") = (long)(arg3); \ - register long _arg4 asm("x3") = (long)(arg4); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ - register long _arg3 asm("x2") = (long)(arg3); \ - register long _arg4 asm("x3") = (long)(arg4); \ - register long _arg5 asm("x4") = (long)(arg5); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r" (_arg1) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ - register long _arg3 asm("x2") = (long)(arg3); \ - register long _arg4 asm("x3") = (long)(arg4); \ - register long _arg5 asm("x4") = (long)(arg5); \ - register long _arg6 asm("x5") = (long)(arg6); \ - \ - asm volatile ( \ - "svc #0\n" \ - : "=r" (_arg1) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_arg6), "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -/* startup code */ -asm(".section .text\n" - ".global _start\n" - "_start:\n" - "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 - "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" - ""); - -/* fcntl / open */ -#define O_RDONLY 0 -#define O_WRONLY 1 -#define O_RDWR 2 -#define O_CREAT 0x40 -#define O_EXCL 0x80 -#define O_NOCTTY 0x100 -#define O_TRUNC 0x200 -#define O_APPEND 0x400 -#define O_NONBLOCK 0x800 -#define O_DIRECTORY 0x4000 - -/* 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]; -}; - -#elif defined(__mips__) && defined(_ABIO32) -/* Syscalls for MIPS ABI O32 : - * - WARNING! there's always a delayed slot! - * - WARNING again, the syntax is different, registers take a '$' and numbers - * do not. - * - registers are 32-bit - * - stack is 8-byte aligned - * - syscall number is passed in v0 (starts at 0xfa0). - * - arguments are in a0, a1, a2, a3, then the stack. The caller needs to - * leave some room in the stack for the callee to save a0..a3 if needed. - * - Many registers are clobbered, in fact only a0..a2 and s0..s8 are - * preserved. See: https://www.linux-mips.org/wiki/Syscall as well as - * scall32-o32.S in the kernel sources. - * - the system call is performed by calling "syscall" - * - syscall return comes in v0, and register a3 needs to be checked to know - * if an error occurred, in which case errno is in v0. - * - 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 my_syscall0(num) \ -({ \ - register long _num asm("v0") = (num); \ - register long _arg4 asm("a3"); \ - \ - 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" \ - ); \ - _arg4 ? -_num : _num; \ -}) - -#define my_syscall1(num, arg1) \ -({ \ - register long _num asm("v0") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ - register long _arg4 asm("a3"); \ - \ - 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" \ - ); \ - _arg4 ? -_num : _num; \ -}) - -#define my_syscall2(num, arg1, arg2) \ -({ \ - register long _num asm("v0") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ - register long _arg2 asm("a1") = (long)(arg2); \ - register long _arg4 asm("a3"); \ - \ - 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" \ - ); \ - _arg4 ? -_num : _num; \ -}) - -#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - 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"); \ - \ - 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" \ - ); \ - _arg4 ? -_num : _num; \ -}) - -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - 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); \ - \ - 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" \ - ); \ - _arg4 ? -_num : _num; \ -}) - -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - 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); \ - \ - asm volatile ( \ - "addiu $sp, $sp, -32\n" \ - "sw %7, 16($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) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ - ); \ - _arg4 ? -_num : _num; \ -}) - -/* startup code, note that it's called __start on MIPS */ -asm(".section .text\n" - ".set nomips16\n" - ".global __start\n" - ".set noreorder\n" - ".option pic0\n" - ".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 - "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" - ""); - -/* fcntl / open */ -#define O_RDONLY 0 -#define O_WRONLY 1 -#define O_RDWR 2 -#define O_APPEND 0x0008 -#define O_NONBLOCK 0x0080 -#define O_CREAT 0x0100 -#define O_TRUNC 0x0200 -#define O_EXCL 0x0400 -#define O_NOCTTY 0x0800 -#define O_DIRECTORY 0x10000 - -/* 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]; -}; - -#elif defined(__riscv) - -#if __riscv_xlen == 64 -#define PTRLOG "3" -#define SZREG "8" -#elif __riscv_xlen == 32 -#define PTRLOG "2" -#define SZREG "4" -#endif - -/* Syscalls for RISCV : - * - stack is 16-byte aligned - * - syscall number is passed in a7 - * - arguments are in a0, a1, a2, a3, a4, a5 - * - the system call is performed by calling ecall - * - syscall return comes in a0 - * - 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. - * - * On riscv, select() is not implemented so we have to use pselect6(). - */ -#define __ARCH_WANT_SYS_PSELECT6 - -#define my_syscall0(num) \ -({ \ - register long _num asm("a7") = (num); \ - register long _arg1 asm("a0"); \ - \ - asm volatile ( \ - "ecall\n\t" \ - : "=r"(_arg1) \ - : "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall1(num, arg1) \ -({ \ - register long _num asm("a7") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ - \ - asm volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall2(num, arg1, arg2) \ -({ \ - register long _num asm("a7") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ - register long _arg2 asm("a1") = (long)(arg2); \ - \ - asm volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - register long _num asm("a7") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ - register long _arg2 asm("a1") = (long)(arg2); \ - register long _arg3 asm("a2") = (long)(arg3); \ - \ - asm volatile ( \ - "ecall\n\t" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - register long _num asm("a7") = (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); \ - \ - asm volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - register long _num asm("a7") = (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 asm("a4") = (long)(arg5); \ - \ - asm volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - register long _num asm("a7") = (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 asm("a4") = (long)(arg5); \ - register long _arg6 asm("a5") = (long)(arg6); \ - \ - asm volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ -}) - -/* startup code */ -asm(".section .text\n" - ".global _start\n" - "_start:\n" - ".option push\n" - ".option norelax\n" - "lla gp, __global_pointer$\n" - ".option pop\n" - "ld 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 - "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" - ""); - -/* fcntl / open */ -#define O_RDONLY 0 -#define O_WRONLY 1 -#define O_RDWR 2 -#define O_CREAT 0x100 -#define O_EXCL 0x200 -#define O_NOCTTY 0x400 -#define O_TRUNC 0x1000 -#define O_APPEND 0x2000 -#define O_NONBLOCK 0x4000 -#define O_DIRECTORY 0x200000 - -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; -}; - -#endif - /* Below are the C functions used to declare the raw syscalls. They try to be * architecture-agnostic, and return either a success or -errno. Declaring them -- cgit From bd8c8fbb866fe524b769a853f2b3525c227165fa Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:18 +0100 Subject: tools/nolibc/sys: split the syscall definitions into their own file The syscall definitions were moved to sys.h. They were arranged in a more easily maintainable order, whereby the sys_xxx() and xxx() functions were grouped together, which also enlights the occasional mappings such as wait relying on wait4(). Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 965 +-------------------------------- tools/include/nolibc/sys.h | 1189 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1192 insertions(+), 962 deletions(-) create mode 100644 tools/include/nolibc/sys.h (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index ccad3998d824..2af56ec760e2 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -83,869 +83,18 @@ #ifndef _NOLIBC_H #define _NOLIBC_H -/* standard type definitions */ #include "std.h" - -/* system includes */ -#include -#include // for SIGCHLD -#include -#include -#include -#include -#include #include "arch.h" #include "types.h" +#include "sys.h" /* Used by programs to avoid std includes */ #define NOLIBC -/* this way it will be removed if unused */ -static int errno; - -#ifndef NOLIBC_IGNORE_ERRNO -#define SET_ERRNO(v) do { errno = (v); } while (0) -#else -#define SET_ERRNO(v) do { } while (0) -#endif - -/* errno codes all ensure that they will not conflict with a valid pointer - * because they all correspond to the highest addressable memory page. - */ -#define MAX_ERRNO 4095 - - -/* Below are the C functions used to declare the raw syscalls. They try to be - * architecture-agnostic, and return either a success or -errno. Declaring them - * static will lead to them being inlined in most cases, but it's still possible - * to reference them by a pointer if needed. - */ -static __attribute__((unused)) -void *sys_brk(void *addr) -{ - return (void *)my_syscall1(__NR_brk, addr); -} - -static __attribute__((noreturn,unused)) -void sys_exit(int status) -{ - my_syscall1(__NR_exit, status & 255); - while(1); // shut the "noreturn" warnings. -} - -static __attribute__((unused)) -int sys_chdir(const char *path) -{ - return my_syscall1(__NR_chdir, path); -} - -static __attribute__((unused)) -int sys_chmod(const char *path, mode_t mode) -{ -#ifdef __NR_fchmodat - return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); -#elif defined(__NR_chmod) - return my_syscall2(__NR_chmod, path, mode); -#else -#error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod() -#endif -} - -static __attribute__((unused)) -int sys_chown(const char *path, uid_t owner, gid_t group) -{ -#ifdef __NR_fchownat - return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); -#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() -#endif -} - -static __attribute__((unused)) -int sys_chroot(const char *path) -{ - return my_syscall1(__NR_chroot, path); -} - -static __attribute__((unused)) -int sys_close(int fd) -{ - return my_syscall1(__NR_close, fd); -} - -static __attribute__((unused)) -int sys_dup(int fd) -{ - return my_syscall1(__NR_dup, fd); -} - -#ifdef __NR_dup3 -static __attribute__((unused)) -int sys_dup3(int old, int new, int flags) -{ - return my_syscall3(__NR_dup3, old, new, flags); -} -#endif - -static __attribute__((unused)) -int sys_dup2(int old, int new) -{ -#ifdef __NR_dup3 - return my_syscall3(__NR_dup3, old, new, 0); -#elif defined(__NR_dup2) - return my_syscall2(__NR_dup2, old, new); -#else -#error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2() -#endif -} - -static __attribute__((unused)) -int sys_execve(const char *filename, char *const argv[], char *const envp[]) -{ - return my_syscall3(__NR_execve, filename, argv, envp); -} - -static __attribute__((unused)) -pid_t sys_fork(void) -{ -#ifdef __NR_clone - /* note: some archs only have clone() and not fork(). Different archs - * have a different API, but most archs have the flags on first arg and - * will not use the rest with no other flag. - */ - return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); -#elif defined(__NR_fork) - return my_syscall0(__NR_fork); -#else -#error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork() -#endif -} - -static __attribute__((unused)) -int sys_fsync(int fd) -{ - return my_syscall1(__NR_fsync, fd); -} - -static __attribute__((unused)) -int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) -{ - return my_syscall3(__NR_getdents64, fd, dirp, count); -} - -static __attribute__((unused)) -pid_t sys_getpgid(pid_t pid) -{ - return my_syscall1(__NR_getpgid, pid); -} - -static __attribute__((unused)) -pid_t sys_getpgrp(void) -{ - return sys_getpgid(0); -} - -static __attribute__((unused)) -pid_t sys_getpid(void) -{ - return my_syscall0(__NR_getpid); -} - -static __attribute__((unused)) -pid_t sys_gettid(void) -{ - return my_syscall0(__NR_gettid); -} - -static __attribute__((unused)) -int sys_gettimeofday(struct timeval *tv, struct timezone *tz) -{ - return my_syscall2(__NR_gettimeofday, tv, tz); -} - -static __attribute__((unused)) -int sys_ioctl(int fd, unsigned long req, void *value) -{ - return my_syscall3(__NR_ioctl, fd, req, value); -} - -static __attribute__((unused)) -int sys_kill(pid_t pid, int signal) -{ - return my_syscall2(__NR_kill, pid, signal); -} - -static __attribute__((unused)) -int sys_link(const char *old, const char *new) -{ -#ifdef __NR_linkat - return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); -#elif defined(__NR_link) - return my_syscall2(__NR_link, old, new); -#else -#error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link() -#endif -} - -static __attribute__((unused)) -off_t sys_lseek(int fd, off_t offset, int whence) -{ - return my_syscall3(__NR_lseek, fd, offset, whence); -} - -static __attribute__((unused)) -int sys_mkdir(const char *path, mode_t mode) -{ -#ifdef __NR_mkdirat - return my_syscall3(__NR_mkdirat, AT_FDCWD, path, 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() -#endif -} - -static __attribute__((unused)) -long sys_mknod(const char *path, mode_t mode, dev_t dev) -{ -#ifdef __NR_mknodat - return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, 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() -#endif -} - -static __attribute__((unused)) -int sys_mount(const char *src, const char *tgt, const char *fst, - unsigned long flags, const void *data) -{ - return my_syscall5(__NR_mount, src, tgt, fst, flags, data); -} - -static __attribute__((unused)) -int sys_open(const char *path, int flags, mode_t mode) -{ -#ifdef __NR_openat - return my_syscall4(__NR_openat, AT_FDCWD, path, flags, 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() -#endif -} - -static __attribute__((unused)) -int sys_pivot_root(const char *new, const char *old) -{ - return my_syscall2(__NR_pivot_root, new, old); -} - -static __attribute__((unused)) -int sys_poll(struct pollfd *fds, int nfds, int timeout) -{ -#if defined(__NR_ppoll) - struct timespec t; - - if (timeout >= 0) { - t.tv_sec = timeout / 1000; - t.tv_nsec = (timeout % 1000) * 1000000; - } - return my_syscall4(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL); -#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() -#endif -} - -static __attribute__((unused)) -ssize_t sys_read(int fd, void *buf, size_t count) -{ - return my_syscall3(__NR_read, fd, buf, count); -} - -static __attribute__((unused)) -ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) -{ - return my_syscall4(__NR_reboot, magic1, magic2, cmd, arg); -} - -static __attribute__((unused)) -int sys_sched_yield(void) -{ - return my_syscall0(__NR_sched_yield); -} - -static __attribute__((unused)) -int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) -{ -#if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect) - struct sel_arg_struct { - unsigned long n; - fd_set *r, *w, *e; - struct timeval *t; - } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout }; - return my_syscall1(__NR_select, &arg); -#elif defined(__ARCH_WANT_SYS_PSELECT6) && defined(__NR_pselect6) - struct timespec t; - - if (timeout) { - t.tv_sec = timeout->tv_sec; - t.tv_nsec = timeout->tv_usec * 1000; - } - return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); -#elif defined(__NR__newselect) || defined(__NR_select) -#ifndef __NR__newselect -#define __NR__newselect __NR_select -#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() -#endif -} - -static __attribute__((unused)) -int sys_setpgid(pid_t pid, pid_t pgid) -{ - return my_syscall2(__NR_setpgid, pid, pgid); -} - -static __attribute__((unused)) -pid_t sys_setsid(void) -{ - return my_syscall0(__NR_setsid); -} - -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_atime = stat.st_atime; - buf->st_mtime = stat.st_mtime; - buf->st_ctime = stat.st_ctime; - return ret; -} - - -static __attribute__((unused)) -int sys_symlink(const char *old, const char *new) -{ -#ifdef __NR_symlinkat - return my_syscall3(__NR_symlinkat, old, AT_FDCWD, 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() -#endif -} - -static __attribute__((unused)) -mode_t sys_umask(mode_t mode) -{ - return my_syscall1(__NR_umask, mode); -} - -static __attribute__((unused)) -int sys_umount2(const char *path, int flags) -{ - return my_syscall2(__NR_umount2, path, flags); -} - -static __attribute__((unused)) -int sys_unlink(const char *path) -{ -#ifdef __NR_unlinkat - return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); -#elif defined(__NR_unlink) - return my_syscall1(__NR_unlink, path); -#else -#error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink() -#endif -} - -static __attribute__((unused)) -pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) -{ - return my_syscall4(__NR_wait4, pid, status, options, rusage); -} - -static __attribute__((unused)) -pid_t sys_waitpid(pid_t pid, int *status, int options) -{ - return sys_wait4(pid, status, options, 0); -} - -static __attribute__((unused)) -pid_t sys_wait(int *status) -{ - return sys_waitpid(-1, status, 0); -} - -static __attribute__((unused)) -ssize_t sys_write(int fd, const void *buf, size_t count) -{ - return my_syscall3(__NR_write, fd, buf, count); -} - - -/* Below are the libc-compatible syscalls which return x or -1 and set errno. - * They rely on the functions above. Similarly they're marked static so that it - * is possible to assign pointers to them if needed. - */ - -static __attribute__((unused)) -int brk(void *addr) -{ - void *ret = sys_brk(addr); - - if (!ret) { - SET_ERRNO(ENOMEM); - return -1; - } - return 0; -} - -static __attribute__((noreturn,unused)) -void exit(int status) -{ - sys_exit(status); -} - -static __attribute__((unused)) -int chdir(const char *path) -{ - int ret = sys_chdir(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -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; -} - -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; -} - -static __attribute__((unused)) -int chroot(const char *path) -{ - int ret = sys_chroot(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -static __attribute__((unused)) -int close(int fd) -{ - int ret = sys_close(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -static __attribute__((unused)) -int dup(int fd) -{ - int ret = sys_dup(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -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; -} - -#ifdef __NR_dup3 -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; -} -#endif - -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; -} - -static __attribute__((unused)) -pid_t fork(void) -{ - pid_t ret = sys_fork(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -static __attribute__((unused)) -int fsync(int fd) -{ - int ret = sys_fsync(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -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; -} - -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; -} - -static __attribute__((unused)) -pid_t getpgrp(void) -{ - pid_t ret = sys_getpgrp(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -static __attribute__((unused)) -pid_t getpid(void) -{ - pid_t ret = sys_getpid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -static __attribute__((unused)) -pid_t gettid(void) -{ - pid_t ret = sys_gettid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -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; -} - -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; -} - -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; -} - -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; -} - 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; -} - -static __attribute__((unused)) -int mkdir(const char *path, mode_t mode) -{ - int ret = sys_mkdir(path, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -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; -} - -static __attribute__((unused)) -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; -} - -static __attribute__((unused)) -int open(const char *path, int flags, mode_t mode) -{ - int ret = sys_open(path, flags, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -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; -} - -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; -} - -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; -} - -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; -} - -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)) - return ret + inc; - - SET_ERRNO(ENOMEM); - return (void *)-1; -} - -static __attribute__((unused)) -int sched_yield(void) -{ - int ret = sys_sched_yield(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -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; -} - -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; -} - -static __attribute__((unused)) -pid_t setsid(void) +int tcsetpgrp(int fd, pid_t pid) { - pid_t ret = sys_setsid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return ioctl(fd, TIOCSPGRP, &pid); } static __attribute__((unused)) @@ -972,114 +121,6 @@ int msleep(unsigned int msecs) return 0; } -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; -} - -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; -} - -static __attribute__((unused)) -int tcsetpgrp(int fd, pid_t pid) -{ - return ioctl(fd, TIOCSPGRP, &pid); -} - -static __attribute__((unused)) -mode_t umask(mode_t mode) -{ - return sys_umask(mode); -} - -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; -} - -static __attribute__((unused)) -int unlink(const char *path) -{ - int ret = sys_unlink(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -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; -} - -static __attribute__((unused)) -pid_t waitpid(pid_t pid, int *status, int options) -{ - pid_t ret = sys_waitpid(pid, status, options); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -static __attribute__((unused)) -pid_t wait(int *status) -{ - pid_t ret = sys_wait(status); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - -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; -} - /* some size-optimized reimplementations of a few common str* and mem* * functions. They're marked static, except memcpy() and raise() which are used * by libgcc on ARM, so they are marked weak instead in order not to cause an diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h new file mode 100644 index 000000000000..98689f668ed3 --- /dev/null +++ b/tools/include/nolibc/sys.h @@ -0,0 +1,1189 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * Syscall definitions for NOLIBC (those in man(2)) + * Copyright (C) 2017-2021 Willy Tarreau + */ + +#ifndef _NOLIBC_SYS_H +#define _NOLIBC_SYS_H + +#include "std.h" + +/* system includes */ +#include +#include // for SIGCHLD +#include +#include +#include +#include +#include + +#include "arch.h" +#include "types.h" + +/* this way it will be removed if unused */ +static int errno; + +#ifndef NOLIBC_IGNORE_ERRNO +#define SET_ERRNO(v) do { errno = (v); } while (0) +#else +#define SET_ERRNO(v) do { } while (0) +#endif + + +/* errno codes all ensure that they will not conflict with a valid pointer + * because they all correspond to the highest addressable memory page. + */ +#define MAX_ERRNO 4095 + + +/* 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 + * versions: + * - the "internal" ones, which matches the raw syscall interface at the + * kernel level, which may sometimes slightly differ from the documented + * libc-level ones. For example most of them return either a valid value + * or -errno. All of these are prefixed with "sys_". They may be called + * by non-portable applications if desired. + * + * - the "exported" ones, whose interface must closely match the one + * documented in man(2), that applications are supposed to expect. These + * ones rely on the internal ones, and set errno. + * + * Each syscall will be defined with the two functions, sorted in alphabetical + * order applied to the exported names. + * + * In case of doubt about the relevance of a function here, only those which + * set errno should be defined here. Wrappers like those appearing in man(3) + * should not be placed here. + */ + + +/* + * int brk(void *addr); + * void *sbrk(intptr_t inc) + */ + +static __attribute__((unused)) +void *sys_brk(void *addr) +{ + return (void *)my_syscall1(__NR_brk, addr); +} + +static __attribute__((unused)) +int brk(void *addr) +{ + void *ret = sys_brk(addr); + + if (!ret) { + SET_ERRNO(ENOMEM); + return -1; + } + return 0; +} + +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)) + return ret + inc; + + SET_ERRNO(ENOMEM); + return (void *)-1; +} + + +/* + * int chdir(const char *path); + */ + +static __attribute__((unused)) +int sys_chdir(const char *path) +{ + return my_syscall1(__NR_chdir, path); +} + +static __attribute__((unused)) +int chdir(const char *path) +{ + int ret = sys_chdir(path); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int chmod(const char *path, mode_t mode); + */ + +static __attribute__((unused)) +int sys_chmod(const char *path, mode_t mode) +{ +#ifdef __NR_fchmodat + return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); +#elif defined(__NR_chmod) + return my_syscall2(__NR_chmod, path, mode); +#else +#error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod() +#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; +} + + +/* + * int chown(const char *path, uid_t owner, gid_t group); + */ + +static __attribute__((unused)) +int sys_chown(const char *path, uid_t owner, gid_t group) +{ +#ifdef __NR_fchownat + return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); +#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() +#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; +} + + +/* + * int chroot(const char *path); + */ + +static __attribute__((unused)) +int sys_chroot(const char *path) +{ + return my_syscall1(__NR_chroot, path); +} + +static __attribute__((unused)) +int chroot(const char *path) +{ + int ret = sys_chroot(path); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int close(int fd); + */ + +static __attribute__((unused)) +int sys_close(int fd) +{ + return my_syscall1(__NR_close, fd); +} + +static __attribute__((unused)) +int close(int fd) +{ + int ret = sys_close(fd); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int dup(int fd); + */ + +static __attribute__((unused)) +int sys_dup(int fd) +{ + return my_syscall1(__NR_dup, fd); +} + +static __attribute__((unused)) +int dup(int fd) +{ + int ret = sys_dup(fd); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int dup2(int old, int new); + */ + +static __attribute__((unused)) +int sys_dup2(int old, int new) +{ +#ifdef __NR_dup3 + return my_syscall3(__NR_dup3, old, new, 0); +#elif defined(__NR_dup2) + return my_syscall2(__NR_dup2, old, new); +#else +#error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2() +#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; +} + + +/* + * int dup3(int old, int new, int flags); + */ + +#ifdef __NR_dup3 +static __attribute__((unused)) +int sys_dup3(int old, int new, int flags) +{ + return my_syscall3(__NR_dup3, old, new, 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; +} +#endif + + +/* + * int execve(const char *filename, char *const argv[], char *const envp[]); + */ + +static __attribute__((unused)) +int sys_execve(const char *filename, char *const argv[], char *const envp[]) +{ + return my_syscall3(__NR_execve, filename, argv, 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; +} + + +/* + * void exit(int status); + */ + +static __attribute__((noreturn,unused)) +void sys_exit(int status) +{ + my_syscall1(__NR_exit, status & 255); + while(1); // shut the "noreturn" warnings. +} + +static __attribute__((noreturn,unused)) +void exit(int status) +{ + sys_exit(status); +} + + +/* + * pid_t fork(void); + */ + +static __attribute__((unused)) +pid_t sys_fork(void) +{ +#ifdef __NR_clone + /* note: some archs only have clone() and not fork(). Different archs + * have a different API, but most archs have the flags on first arg and + * will not use the rest with no other flag. + */ + return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); +#elif defined(__NR_fork) + return my_syscall0(__NR_fork); +#else +#error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork() +#endif +} + +static __attribute__((unused)) +pid_t fork(void) +{ + pid_t ret = sys_fork(); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int fsync(int fd); + */ + +static __attribute__((unused)) +int sys_fsync(int fd) +{ + return my_syscall1(__NR_fsync, fd); +} + +static __attribute__((unused)) +int fsync(int fd) +{ + int ret = sys_fsync(fd); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int getdents64(int fd, struct linux_dirent64 *dirp, int count); + */ + +static __attribute__((unused)) +int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) +{ + return my_syscall3(__NR_getdents64, fd, dirp, 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; +} + + +/* + * pid_t getpgid(pid_t pid); + */ + +static __attribute__((unused)) +pid_t sys_getpgid(pid_t pid) +{ + return my_syscall1(__NR_getpgid, 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; +} + + +/* + * pid_t getpgrp(void); + */ + +static __attribute__((unused)) +pid_t sys_getpgrp(void) +{ + return sys_getpgid(0); +} + +static __attribute__((unused)) +pid_t getpgrp(void) +{ + pid_t ret = sys_getpgrp(); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * pid_t getpid(void); + */ + +static __attribute__((unused)) +pid_t sys_getpid(void) +{ + return my_syscall0(__NR_getpid); +} + +static __attribute__((unused)) +pid_t getpid(void) +{ + pid_t ret = sys_getpid(); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * pid_t gettid(void); + */ + +static __attribute__((unused)) +pid_t sys_gettid(void) +{ + return my_syscall0(__NR_gettid); +} + +static __attribute__((unused)) +pid_t gettid(void) +{ + pid_t ret = sys_gettid(); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int gettimeofday(struct timeval *tv, struct timezone *tz); + */ + +static __attribute__((unused)) +int sys_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + return my_syscall2(__NR_gettimeofday, tv, tz); +} + +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; +} + + +/* + * int ioctl(int fd, unsigned long req, void *value); + */ + +static __attribute__((unused)) +int sys_ioctl(int fd, unsigned long req, void *value) +{ + return my_syscall3(__NR_ioctl, fd, req, 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; +} + +/* + * int kill(pid_t pid, int signal); + */ + +static __attribute__((unused)) +int sys_kill(pid_t pid, int signal) +{ + return my_syscall2(__NR_kill, pid, 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; +} + + +/* + * int link(const char *old, const char *new); + */ + +static __attribute__((unused)) +int sys_link(const char *old, const char *new) +{ +#ifdef __NR_linkat + return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); +#elif defined(__NR_link) + return my_syscall2(__NR_link, old, new); +#else +#error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link() +#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; +} + + +/* + * off_t lseek(int fd, off_t offset, int whence); + */ + +static __attribute__((unused)) +off_t sys_lseek(int fd, off_t offset, int whence) +{ + return my_syscall3(__NR_lseek, fd, offset, whence); +} + +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; +} + + +/* + * int mkdir(const char *path, mode_t mode); + */ + +static __attribute__((unused)) +int sys_mkdir(const char *path, mode_t mode) +{ +#ifdef __NR_mkdirat + return my_syscall3(__NR_mkdirat, AT_FDCWD, path, 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() +#endif +} + +static __attribute__((unused)) +int mkdir(const char *path, mode_t mode) +{ + int ret = sys_mkdir(path, mode); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int mknod(const char *path, mode_t mode, dev_t dev); + */ + +static __attribute__((unused)) +long sys_mknod(const char *path, mode_t mode, dev_t dev) +{ +#ifdef __NR_mknodat + return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, 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() +#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; +} + + +/* + * int mount(const char *source, const char *target, + * const char *fstype, unsigned long flags, + * const void *data); + */ +static __attribute__((unused)) +int sys_mount(const char *src, const char *tgt, const char *fst, + unsigned long flags, const void *data) +{ + return my_syscall5(__NR_mount, src, tgt, fst, flags, data); +} + +static __attribute__((unused)) +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; +} + + +/* + * int open(const char *path, int flags, mode_t mode); + */ + +static __attribute__((unused)) +int sys_open(const char *path, int flags, mode_t mode) +{ +#ifdef __NR_openat + return my_syscall4(__NR_openat, AT_FDCWD, path, flags, 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() +#endif +} + +static __attribute__((unused)) +int open(const char *path, int flags, mode_t mode) +{ + int ret = sys_open(path, flags, mode); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int pivot_root(const char *new, const char *old); + */ + +static __attribute__((unused)) +int sys_pivot_root(const char *new, const char *old) +{ + return my_syscall2(__NR_pivot_root, new, 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; +} + + +/* + * int poll(struct pollfd *fds, int nfds, int timeout); + */ + +static __attribute__((unused)) +int sys_poll(struct pollfd *fds, int nfds, int timeout) +{ +#if defined(__NR_ppoll) + struct timespec t; + + if (timeout >= 0) { + t.tv_sec = timeout / 1000; + t.tv_nsec = (timeout % 1000) * 1000000; + } + return my_syscall4(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL); +#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() +#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; +} + + +/* + * ssize_t read(int fd, void *buf, size_t count); + */ + +static __attribute__((unused)) +ssize_t sys_read(int fd, void *buf, size_t count) +{ + return my_syscall3(__NR_read, fd, buf, 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; +} + + +/* + * int reboot(int cmd); + * is among LINUX_REBOOT_CMD_* + */ + +static __attribute__((unused)) +ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) +{ + return my_syscall4(__NR_reboot, magic1, magic2, cmd, 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; +} + + +/* + * int sched_yield(void); + */ + +static __attribute__((unused)) +int sys_sched_yield(void) +{ + return my_syscall0(__NR_sched_yield); +} + +static __attribute__((unused)) +int sched_yield(void) +{ + int ret = sys_sched_yield(); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int select(int nfds, fd_set *read_fds, fd_set *write_fds, + * fd_set *except_fds, struct timeval *timeout); + */ + +static __attribute__((unused)) +int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) +{ +#if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect) + struct sel_arg_struct { + unsigned long n; + fd_set *r, *w, *e; + struct timeval *t; + } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout }; + return my_syscall1(__NR_select, &arg); +#elif defined(__ARCH_WANT_SYS_PSELECT6) && defined(__NR_pselect6) + struct timespec t; + + if (timeout) { + t.tv_sec = timeout->tv_sec; + t.tv_nsec = timeout->tv_usec * 1000; + } + return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); +#elif defined(__NR__newselect) || defined(__NR_select) +#ifndef __NR__newselect +#define __NR__newselect __NR_select +#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() +#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; +} + + +/* + * int setpgid(pid_t pid, pid_t pgid); + */ + +static __attribute__((unused)) +int sys_setpgid(pid_t pid, pid_t pgid) +{ + return my_syscall2(__NR_setpgid, pid, 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; +} + + +/* + * pid_t setsid(void); + */ + +static __attribute__((unused)) +pid_t sys_setsid(void) +{ + return my_syscall0(__NR_setsid); +} + +static __attribute__((unused)) +pid_t setsid(void) +{ + pid_t ret = sys_setsid(); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * int stat(const char *path, struct stat *buf); + * Warning: the struct stat's layout is arch-dependent. + */ + +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_atime = stat.st_atime; + buf->st_mtime = stat.st_mtime; + buf->st_ctime = stat.st_ctime; + return ret; +} + +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; +} + + +/* + * int symlink(const char *old, const char *new); + */ + +static __attribute__((unused)) +int sys_symlink(const char *old, const char *new) +{ +#ifdef __NR_symlinkat + return my_syscall3(__NR_symlinkat, old, AT_FDCWD, 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() +#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; +} + + +/* + * mode_t umask(mode_t mode); + */ + +static __attribute__((unused)) +mode_t sys_umask(mode_t mode) +{ + return my_syscall1(__NR_umask, mode); +} + +static __attribute__((unused)) +mode_t umask(mode_t mode) +{ + return sys_umask(mode); +} + + +/* + * int umount2(const char *path, int flags); + */ + +static __attribute__((unused)) +int sys_umount2(const char *path, int flags) +{ + return my_syscall2(__NR_umount2, path, 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; +} + + +/* + * int unlink(const char *path); + */ + +static __attribute__((unused)) +int sys_unlink(const char *path) +{ +#ifdef __NR_unlinkat + return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); +#elif defined(__NR_unlink) + return my_syscall1(__NR_unlink, path); +#else +#error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink() +#endif +} + +static __attribute__((unused)) +int unlink(const char *path) +{ + int ret = sys_unlink(path); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + +/* + * pid_t wait(int *status); + * pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage); + * pid_t waitpid(pid_t pid, int *status, int options); + */ + +static __attribute__((unused)) +pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) +{ + return my_syscall4(__NR_wait4, pid, status, options, rusage); +} + +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; +} + +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; +} + + +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; +} + + +/* + * ssize_t write(int fd, const void *buf, size_t count); + */ + +static __attribute__((unused)) +ssize_t sys_write(int fd, const void *buf, size_t count) +{ + return my_syscall3(__NR_write, fd, buf, 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; +} + + +#endif /* _NOLIBC_SYS_H */ -- cgit From 06fdba53e0a9a897ba00c3602f14b3498b321655 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:19 +0100 Subject: tools/nolibc/stdlib: extract the stdlib-specific functions to their own file The new file stdlib.h contains the definitions of functions that are usually found in stdlib.h. Many more could certainly be added. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 67 +--------------------------------- tools/include/nolibc/stdlib.h | 85 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 66 deletions(-) create mode 100644 tools/include/nolibc/stdlib.h (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 2af56ec760e2..ed909a8daa1a 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -87,40 +87,11 @@ #include "arch.h" #include "types.h" #include "sys.h" +#include "stdlib.h" /* Used by programs to avoid std includes */ #define NOLIBC -static __attribute__((unused)) -int tcsetpgrp(int fd, pid_t pid) -{ - return ioctl(fd, TIOCSPGRP, &pid); -} - -static __attribute__((unused)) -unsigned int sleep(unsigned int seconds) -{ - struct timeval my_timeval = { seconds, 0 }; - - if (sys_select(0, 0, 0, 0, &my_timeval) < 0) - return my_timeval.tv_sec + !!my_timeval.tv_usec; - else - return 0; -} - -static __attribute__((unused)) -int msleep(unsigned int msecs) -{ - struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 }; - - if (sys_select(0, 0, 0, 0, &my_timeval) < 0) - return (my_timeval.tv_sec * 1000) + - (my_timeval.tv_usec / 1000) + - !!(my_timeval.tv_usec % 1000); - else - return 0; -} - /* some size-optimized reimplementations of a few common str* and mem* * functions. They're marked static, except memcpy() and raise() which are used * by libgcc on ARM, so they are marked weak instead in order not to cause an @@ -216,35 +187,6 @@ int isdigit(int c) return (unsigned int)(c - '0') <= 9; } -static __attribute__((unused)) -long atol(const char *s) -{ - unsigned long ret = 0; - unsigned long d; - int neg = 0; - - if (*s == '-') { - neg = 1; - s++; - } - - while (1) { - d = (*s++) - '0'; - if (d > 9) - break; - ret *= 10; - ret += d; - } - - return neg ? -ret : ret; -} - -static __attribute__((unused)) -int atoi(const char *s) -{ - return atol(s); -} - static __attribute__((unused)) const char *ltoa(long in) { @@ -273,13 +215,6 @@ void *memcpy(void *dst, const void *src, size_t len) return memmove(dst, src, len); } -/* needed by libgcc for divide by zero */ -__attribute__((weak,unused)) -int raise(int signal) -{ - return kill(getpid(), signal); -} - /* Here come a few helper functions */ static __attribute__((unused)) diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h new file mode 100644 index 000000000000..09a506aadbbe --- /dev/null +++ b/tools/include/nolibc/stdlib.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * stdlib function definitions for NOLIBC + * Copyright (C) 2017-2021 Willy Tarreau + */ + +#ifndef _NOLIBC_STDLIB_H +#define _NOLIBC_STDLIB_H + +#include "std.h" +#include "arch.h" +#include "types.h" +#include "sys.h" + +/* + * As much as possible, please keep functions alphabetically sorted. + */ + +static __attribute__((unused)) +long atol(const char *s) +{ + unsigned long ret = 0; + unsigned long d; + int neg = 0; + + if (*s == '-') { + neg = 1; + s++; + } + + while (1) { + d = (*s++) - '0'; + if (d > 9) + break; + ret *= 10; + ret += d; + } + + return neg ? -ret : ret; +} + +static __attribute__((unused)) +int atoi(const char *s) +{ + return atol(s); +} + +static __attribute__((unused)) +int msleep(unsigned int msecs) +{ + struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 }; + + if (sys_select(0, 0, 0, 0, &my_timeval) < 0) + return (my_timeval.tv_sec * 1000) + + (my_timeval.tv_usec / 1000) + + !!(my_timeval.tv_usec % 1000); + else + return 0; +} + +/* This one is not marked static as it's needed by libgcc for divide by zero */ +__attribute__((weak,unused)) +int raise(int signal) +{ + return kill(getpid(), signal); +} + +static __attribute__((unused)) +unsigned int sleep(unsigned int seconds) +{ + struct timeval my_timeval = { seconds, 0 }; + + if (sys_select(0, 0, 0, 0, &my_timeval) < 0) + return my_timeval.tv_sec + !!my_timeval.tv_usec; + else + return 0; +} + +static __attribute__((unused)) +int tcsetpgrp(int fd, pid_t pid) +{ + return ioctl(fd, TIOCSPGRP, &pid); +} + +#endif /* _NOLIBC_STDLIB_H */ -- cgit From c91eb033895593a998c5a49d562fb760ab2fa5bb Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:20 +0100 Subject: tools/nolibc/string: split the string functions into string.h The string manipulation functions (mem*, str*) are now found in string.h. The file depends on almost nothing and will be usable from other includes if needed. Maybe more functions could be added. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 96 +------------------------------------ tools/include/nolibc/string.h | 107 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 95 deletions(-) create mode 100644 tools/include/nolibc/string.h (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index ed909a8daa1a..b06bd5cb5651 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -88,99 +88,11 @@ #include "types.h" #include "sys.h" #include "stdlib.h" +#include "string.h" /* Used by programs to avoid std includes */ #define NOLIBC -/* some size-optimized reimplementations of a few common str* and mem* - * functions. They're marked static, except memcpy() and raise() which are used - * by libgcc on ARM, so they are marked weak instead in order not to cause an - * error when building a program made of multiple files (not recommended). - */ - -static __attribute__((unused)) -void *memmove(void *dst, const void *src, size_t len) -{ - ssize_t pos = (dst <= src) ? -1 : (long)len; - void *ret = dst; - - while (len--) { - pos += (dst <= src) ? 1 : -1; - ((char *)dst)[pos] = ((char *)src)[pos]; - } - return ret; -} - -static __attribute__((unused)) -void *memset(void *dst, int b, size_t len) -{ - char *p = dst; - - while (len--) - *(p++) = b; - return dst; -} - -static __attribute__((unused)) -int memcmp(const void *s1, const void *s2, size_t n) -{ - size_t ofs = 0; - char c1 = 0; - - while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) { - ofs++; - } - return c1; -} - -static __attribute__((unused)) -char *strcpy(char *dst, const char *src) -{ - char *ret = dst; - - while ((*dst++ = *src++)); - return ret; -} - -static __attribute__((unused)) -char *strchr(const char *s, int c) -{ - while (*s) { - if (*s == (char)c) - return (char *)s; - s++; - } - return NULL; -} - -static __attribute__((unused)) -char *strrchr(const char *s, int c) -{ - const char *ret = NULL; - - while (*s) { - if (*s == (char)c) - ret = s; - s++; - } - return (char *)ret; -} - -static __attribute__((unused)) -size_t nolibc_strlen(const char *str) -{ - size_t len; - - for (len = 0; str[len]; len++); - return len; -} - -#define strlen(str) ({ \ - __builtin_constant_p((str)) ? \ - __builtin_strlen((str)) : \ - nolibc_strlen((str)); \ -}) - static __attribute__((unused)) int isdigit(int c) { @@ -209,12 +121,6 @@ const char *ltoa(long in) return pos + 1; } -__attribute__((weak,unused)) -void *memcpy(void *dst, const void *src, size_t len) -{ - return memmove(dst, src, len); -} - /* Here come a few helper functions */ static __attribute__((unused)) diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h new file mode 100644 index 000000000000..8a23cda2d450 --- /dev/null +++ b/tools/include/nolibc/string.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * string function definitions for NOLIBC + * Copyright (C) 2017-2021 Willy Tarreau + */ + +#ifndef _NOLIBC_STRING_H +#define _NOLIBC_STRING_H + +#include "std.h" + +/* + * As much as possible, please keep functions alphabetically sorted. + */ + +static __attribute__((unused)) +int memcmp(const void *s1, const void *s2, size_t n) +{ + size_t ofs = 0; + char c1 = 0; + + while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) { + ofs++; + } + return c1; +} + +static __attribute__((unused)) +void *memmove(void *dst, const void *src, size_t len) +{ + ssize_t pos = (dst <= src) ? -1 : (long)len; + void *ret = dst; + + while (len--) { + pos += (dst <= src) ? 1 : -1; + ((char *)dst)[pos] = ((char *)src)[pos]; + } + return ret; +} + +/* must be exported, as it's used by libgcc on ARM */ +__attribute__((weak,unused)) +void *memcpy(void *dst, const void *src, size_t len) +{ + return memmove(dst, src, len); +} + +static __attribute__((unused)) +void *memset(void *dst, int b, size_t len) +{ + char *p = dst; + + while (len--) + *(p++) = b; + return dst; +} + +static __attribute__((unused)) +char *strchr(const char *s, int c) +{ + while (*s) { + if (*s == (char)c) + return (char *)s; + s++; + } + return NULL; +} + +static __attribute__((unused)) +char *strcpy(char *dst, const char *src) +{ + char *ret = dst; + + while ((*dst++ = *src++)); + return ret; +} + +/* this function is only used with arguments that are not constants */ +static __attribute__((unused)) +size_t nolibc_strlen(const char *str) +{ + size_t len; + + for (len = 0; str[len]; len++); + return len; +} + +#define strlen(str) ({ \ + __builtin_constant_p((str)) ? \ + __builtin_strlen((str)) : \ + nolibc_strlen((str)); \ +}) + +static __attribute__((unused)) +char *strrchr(const char *s, int c) +{ + const char *ret = NULL; + + while (*s) { + if (*s == (char)c) + ret = s; + s++; + } + return (char *)ret; +} + +#endif /* _NOLIBC_STRING_H */ -- cgit From 62a2af077493df4ebea22df4de8df4aea3c882cc Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:21 +0100 Subject: tools/nolibc/ctype: split the is* functions to ctype.h In fact there's only isdigit() for now. More should definitely be added. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/ctype.h | 22 ++++++++++++++++++++++ tools/include/nolibc/nolibc.h | 7 +------ 2 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 tools/include/nolibc/ctype.h (limited to 'tools/include') diff --git a/tools/include/nolibc/ctype.h b/tools/include/nolibc/ctype.h new file mode 100644 index 000000000000..6735bd906f25 --- /dev/null +++ b/tools/include/nolibc/ctype.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * ctype function definitions for NOLIBC + * Copyright (C) 2017-2021 Willy Tarreau + */ + +#ifndef _NOLIBC_CTYPE_H +#define _NOLIBC_CTYPE_H + +#include "std.h" + +/* + * As much as possible, please keep functions alphabetically sorted. + */ + +static __attribute__((unused)) +int isdigit(int c) +{ + return (unsigned int)(c - '0') <= 9; +} + +#endif /* _NOLIBC_CTYPE_H */ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index b06bd5cb5651..c96c6cb7f3ae 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -87,18 +87,13 @@ #include "arch.h" #include "types.h" #include "sys.h" +#include "ctype.h" #include "stdlib.h" #include "string.h" /* Used by programs to avoid std includes */ #define NOLIBC -static __attribute__((unused)) -int isdigit(int c) -{ - return (unsigned int)(c - '0') <= 9; -} - static __attribute__((unused)) const char *ltoa(long in) { -- cgit From 50850c38b290c22da37a77e24c9382933b200c8c Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:22 +0100 Subject: tools/nolibc/ctype: add the missing is* functions There was only isdigit, this commit adds the other ones. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/ctype.h | 79 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/ctype.h b/tools/include/nolibc/ctype.h index 6735bd906f25..e3000b2992d7 100644 --- a/tools/include/nolibc/ctype.h +++ b/tools/include/nolibc/ctype.h @@ -13,10 +13,87 @@ * As much as possible, please keep functions alphabetically sorted. */ +static __attribute__((unused)) +int isascii(int c) +{ + /* 0x00..0x7f */ + return (unsigned int)c <= 0x7f; +} + +static __attribute__((unused)) +int isblank(int c) +{ + return c == '\t' || c == ' '; +} + +static __attribute__((unused)) +int iscntrl(int c) +{ + /* 0x00..0x1f, 0x7f */ + return (unsigned int)c < 0x20 || c == 0x7f; +} + static __attribute__((unused)) int isdigit(int c) { - return (unsigned int)(c - '0') <= 9; + return (unsigned int)(c - '0') < 10; +} + +static __attribute__((unused)) +int isgraph(int c) +{ + /* 0x21..0x7e */ + return (unsigned int)(c - 0x21) < 0x5e; +} + +static __attribute__((unused)) +int islower(int c) +{ + return (unsigned int)(c - 'a') < 26; +} + +static __attribute__((unused)) +int isprint(int c) +{ + /* 0x20..0x7e */ + return (unsigned int)(c - 0x20) < 0x5f; +} + +static __attribute__((unused)) +int isspace(int c) +{ + /* \t is 0x9, \n is 0xA, \v is 0xB, \f is 0xC, \r is 0xD */ + return ((unsigned int)c == ' ') || (unsigned int)(c - 0x09) < 5; +} + +static __attribute__((unused)) +int isupper(int c) +{ + return (unsigned int)(c - 'A') < 26; +} + +static __attribute__((unused)) +int isxdigit(int c) +{ + return isdigit(c) || (unsigned int)(c - 'A') < 6 || (unsigned int)(c - 'a') < 6; +} + +static __attribute__((unused)) +int isalpha(int c) +{ + return islower(c) || isupper(c); +} + +static __attribute__((unused)) +int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} + +static __attribute__((unused)) +int ispunct(int c) +{ + return isgraph(c) && !isalnum(c); } #endif /* _NOLIBC_CTYPE_H */ -- cgit From 8cb98b3fce152e8ba46d1e25515deab08d7ec271 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 Feb 2022 09:52:10 +0100 Subject: tools/nolibc/types: move the FD_* functions to macros in types.h FD_SET, FD_CLR, FD_ISSET, FD_ZERO are often expected to be macros and not functions. In addition we already have a file dedicated to such macros and types used by syscalls, it's types.h, so let's move them there and turn them to macros. FD_CLR() and FD_ISSET() were missing, so they were added. FD_ZERO() now deals with its own loop so that it doesn't rely on memset() that sets one byte at a time. Cc: David Laight Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 14 -------------- tools/include/nolibc/types.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 14 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index c96c6cb7f3ae..2267d98337ea 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -118,20 +118,6 @@ const char *ltoa(long in) /* Here come a few helper functions */ -static __attribute__((unused)) -void FD_ZERO(fd_set *set) -{ - memset(set, 0, sizeof(*set)); -} - -static __attribute__((unused)) -void FD_SET(int fd, fd_set *set) -{ - if (fd < 0 || fd >= FD_SETSIZE) - return; - set->fd32[fd / 32] |= 1 << (fd & 31); -} - /* WARNING, it only deals with the 4096 first majors and 256 first minors */ static __attribute__((unused)) dev_t makedev(unsigned int major, unsigned int minor) diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index 2f09abaf95f1..a4dda0a22fc2 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -75,6 +75,36 @@ typedef struct { uint32_t fd32[FD_SETSIZE / 32]; } fd_set; +#define FD_CLR(fd, set) do { \ + fd_set *__set = (set); \ + int __fd = (fd); \ + if (__fd >= 0) \ + __set->fd32[__fd / 32] &= ~(1U << (__fd & 31)); \ + } while (0) + +#define FD_SET(fd, set) do { \ + fd_set *__set = (set); \ + int __fd = (fd); \ + if (__fd >= 0) \ + __set->fd32[__fd / 32] |= 1U << (__fd & 31); \ + } while (0) + +#define FD_ISSET(fd, set) ({ \ + fd_set *__set = (set); \ + int __fd = (fd); \ + int __r = 0; \ + if (__fd >= 0) \ + __r = !!(__set->fd32[__fd / 32] & 1U << (__fd & 31)); \ + __r; \ + }) + +#define FD_ZERO(set) do { \ + fd_set *__set = (set); \ + int __idx; \ + for (__idx = 0; __idx < FD_SETSIZE / 32; __idx ++) \ + __set->fd32[__idx] = 0; \ + } while (0) + /* for poll() */ struct pollfd { int fd; -- cgit From 306c9fd4c686eebf4e0487bc4ad5dca8e68c19be Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 Feb 2022 09:53:01 +0100 Subject: tools/nolibc/types: make FD_SETSIZE configurable The macro was hard-coded to 256 but it's common to see it redefined. Let's support this and make sure we always allocate enough entries for the cases where it wouldn't be multiple of 32. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/types.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index a4dda0a22fc2..563dbbad0496 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -45,7 +45,9 @@ #define DT_SOCK 0xc /* commonly an fd_set represents 256 FDs */ +#ifndef FD_SETSIZE #define FD_SETSIZE 256 +#endif /* Special FD used by all the *at functions */ #ifndef AT_FDCWD @@ -72,7 +74,7 @@ /* for select() */ typedef struct { - uint32_t fd32[FD_SETSIZE / 32]; + uint32_t fd32[(FD_SETSIZE + 31) / 32]; } fd_set; #define FD_CLR(fd, set) do { \ @@ -101,7 +103,7 @@ typedef struct { #define FD_ZERO(set) do { \ fd_set *__set = (set); \ int __idx; \ - for (__idx = 0; __idx < FD_SETSIZE / 32; __idx ++) \ + for (__idx = 0; __idx < (FD_SETSIZE+31) / 32; __idx ++) \ __set->fd32[__idx] = 0; \ } while (0) -- cgit From eba6d00d38e7c26dd5b948ed75200d05f67d8266 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:25 +0100 Subject: tools/nolibc/types: move makedev to types.h and make it a macro The makedev() man page says it's supposed to be a macro and that some OSes have it with the other ones in sys/types.h so it now makes sense to move it to types.h as a macro. Let's also define major() and minor() that perform the reverse operation. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 9 --------- tools/include/nolibc/types.h | 5 +++++ 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 2267d98337ea..23fb81414b1b 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -116,13 +116,4 @@ const char *ltoa(long in) return pos + 1; } -/* Here come a few helper functions */ - -/* WARNING, it only deals with the 4096 first majors and 256 first minors */ -static __attribute__((unused)) -dev_t makedev(unsigned int major, unsigned int minor) -{ - return ((major & 0xfff) << 8) | (minor & 0xff); -} - #endif /* _NOLIBC_H */ diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index 563dbbad0496..b1bff5e717b6 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -162,4 +162,9 @@ struct stat { time_t st_ctime; /* time of last status change */ }; +/* WARNING, it only deals with the 4096 first majors and 256 first minors */ +#define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff))) +#define major(dev) ((unsigned int)(((dev) >> 8) & 0xfff)) +#define minor(dev) ((unsigned int)(((dev) & 0xff)) + #endif /* _NOLIBC_TYPES_H */ -- cgit From 56d68a3c1f41ca0843fd9151654c35f4925d911b Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:26 +0100 Subject: tools/nolibc/stdlib: move ltoa() to stdlib.h This function is not standard and performs the opposite of atol(). Let's move it with atol(). It's been split between a reentrant function and one using a static buffer. There's no more definition in nolibc.h anymore now. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 22 ---------------------- tools/include/nolibc/stdlib.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 22 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 23fb81414b1b..a349c88c45ff 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -94,26 +94,4 @@ /* Used by programs to avoid std includes */ #define NOLIBC -static __attribute__((unused)) -const char *ltoa(long in) -{ - /* large enough for -9223372036854775808 */ - static char buffer[21]; - char *pos = buffer + sizeof(buffer) - 1; - int neg = in < 0; - unsigned long n = neg ? -in : in; - - *pos-- = '\0'; - do { - *pos-- = '0' + n % 10; - n /= 10; - if (pos < buffer) - return pos + 1; - } while (n); - - if (neg) - *pos-- = '-'; - return pos + 1; -} - #endif /* _NOLIBC_H */ diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 09a506aadbbe..84fc4353fb01 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -45,6 +45,38 @@ int atoi(const char *s) return atol(s); } +/* performs the opposite of atol() using a user-fed buffer. The buffer must be + * at least 21 bytes long (large enough for "-9223372036854775808"). + */ +static __attribute__((unused)) +const char *ltoa_r(long in, char *buffer) +{ + char *pos = buffer + 21 - 1; + int neg = in < 0; + unsigned long n = neg ? -in : in; + + *pos-- = '\0'; + do { + *pos-- = '0' + n % 10; + n /= 10; + if (pos < buffer) + return pos + 1; + } while (n); + + if (neg) + *pos-- = '-'; + return pos + 1; +} + +/* performs the opposite of atol() using a statically allocated buffer */ +static __attribute__((unused)) +const char *ltoa(long in) +{ + /* large enough for -9223372036854775808 */ + static char buffer[21]; + return ltoa_r(in, buffer); +} + static __attribute__((unused)) int msleep(unsigned int msecs) { -- cgit From 66c397c4d2e15871c50940c168b7d4a76aaa08a9 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:27 +0100 Subject: tools/nolibc/stdlib: replace the ltoa() function with more efficient ones The original ltoa() function and the reentrant one ltoa_r() present a number of drawbacks. The divide by 10 generates calls to external code from libgcc_s, and the number does not necessarily start at the beginning of the buffer. Let's rewrite these functions so that they do not involve a divide and only use loops on powers of 10, and implement both signed and unsigned variants, always starting from the buffer's first character. Instead of using a static buffer for each function, we're now using a common one. In order to avoid confusion with the ltoa() name, the new functions are called itoa_r() and utoa_r() to distinguish the signed and unsigned versions, and for convenience for their callers, these functions now reutrn the number of characters emitted. The ltoa_r() function is just an inline mapping to the signed one and which returns the buffer. The functions are quite small (86 bytes on x86_64, 68 on armv7) and do not depend anymore on external code. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 109 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 21 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 84fc4353fb01..dbb45631c7ca 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -12,6 +12,13 @@ #include "types.h" #include "sys.h" + +/* Buffer used to store int-to-ASCII conversions. Will only be implemented if + * any of the related functions is implemented. The area is large enough to + * store "18446744073709551615" or "-9223372036854775808" and the final zero. + */ +static __attribute__((unused)) char itoa_buffer[21]; + /* * As much as possible, please keep functions alphabetically sorted. */ @@ -45,36 +52,96 @@ int atoi(const char *s) return atol(s); } -/* performs the opposite of atol() using a user-fed buffer. The buffer must be - * at least 21 bytes long (large enough for "-9223372036854775808"). +/* Converts the unsigned long integer to its string representation into + * buffer , which must be long enough to store the number and the + * trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for + * 4294967295 in 32-bit). The buffer is filled from the first byte, and the + * number of characters emitted (not counting the trailing zero) is returned. + * The function is constructed in a way to optimize the code size and avoid + * any divide that could add a dependency on large external functions. */ static __attribute__((unused)) -const char *ltoa_r(long in, char *buffer) +int utoa_r(unsigned long in, char *buffer) { - char *pos = buffer + 21 - 1; - int neg = in < 0; - unsigned long n = neg ? -in : in; + unsigned long lim; + int digits = 0; + int pos = (~0UL > 0xfffffffful) ? 19 : 9; + int dig; - *pos-- = '\0'; do { - *pos-- = '0' + n % 10; - n /= 10; - if (pos < buffer) - return pos + 1; - } while (n); - - if (neg) - *pos-- = '-'; - return pos + 1; + for (dig = 0, lim = 1; dig < pos; dig++) + lim *= 10; + + if (digits || in >= lim || !pos) { + for (dig = 0; in >= lim; dig++) + in -= lim; + buffer[digits++] = '0' + dig; + } + } while (pos--); + + buffer[digits] = 0; + return digits; } -/* performs the opposite of atol() using a statically allocated buffer */ +/* Converts the signed long integer to its string representation into + * buffer , which must be long enough to store the number and the + * trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for + * -2147483648 in 32-bit). The buffer is filled from the first byte, and the + * number of characters emitted (not counting the trailing zero) is returned. + */ static __attribute__((unused)) -const char *ltoa(long in) +int itoa_r(long in, char *buffer) +{ + char *ptr = buffer; + int len = 0; + + if (in < 0) { + in = -in; + *(ptr++) = '-'; + len++; + } + len += utoa_r(in, ptr); + return len; +} + +/* for historical compatibility, same as above but returns the pointer to the + * buffer. + */ +static inline __attribute__((unused)) +char *ltoa_r(long in, char *buffer) +{ + itoa_r(in, buffer); + return buffer; +} + +/* converts long integer to a string using the static itoa_buffer and + * returns the pointer to that string. + */ +static inline __attribute__((unused)) +char *itoa(long in) +{ + itoa_r(in, itoa_buffer); + return itoa_buffer; +} + +/* converts long integer to a string using the static itoa_buffer and + * returns the pointer to that string. Same as above, for compatibility. + */ +static inline __attribute__((unused)) +char *ltoa(long in) +{ + itoa_r(in, itoa_buffer); + return itoa_buffer; +} + +/* converts unsigned long integer to a string using the static itoa_buffer + * and returns the pointer to that string. + */ +static inline __attribute__((unused)) +char *utoa(unsigned long in) { - /* large enough for -9223372036854775808 */ - static char buffer[21]; - return ltoa_r(in, buffer); + utoa_r(in, itoa_buffer); + return itoa_buffer; } static __attribute__((unused)) -- cgit From b1c21e7d99cdab987fb858679fbc012868caac40 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:28 +0100 Subject: tools/nolibc/stdlib: add i64toa() and u64toa() These are 64-bit variants of the itoa() and utoa() functions. They also support reentrant ones, and use the same itoa_buffer. The functions are a bit larger than the previous ones in 32-bit mode (86 and 98 bytes on x86_64 and armv7 respectively), which is why we continue to provide them as separate functions. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index dbb45631c7ca..d972871bf2ba 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -144,6 +144,78 @@ char *utoa(unsigned long in) return itoa_buffer; } +/* Converts the unsigned 64-bit integer to its string representation into + * buffer , which must be long enough to store the number and the + * trailing zero (21 bytes for 18446744073709551615). The buffer is filled from + * the first byte, and the number of characters emitted (not counting the + * trailing zero) is returned. The function is constructed in a way to optimize + * the code size and avoid any divide that could add a dependency on large + * external functions. + */ +static __attribute__((unused)) +int u64toa_r(uint64_t in, char *buffer) +{ + unsigned long long lim; + int digits = 0; + int pos = 19; /* start with the highest possible digit */ + int dig; + + do { + for (dig = 0, lim = 1; dig < pos; dig++) + lim *= 10; + + if (digits || in >= lim || !pos) { + for (dig = 0; in >= lim; dig++) + in -= lim; + buffer[digits++] = '0' + dig; + } + } while (pos--); + + buffer[digits] = 0; + return digits; +} + +/* Converts the signed 64-bit integer to its string representation into + * buffer , which must be long enough to store the number and the + * trailing zero (21 bytes for -9223372036854775808). The buffer is filled from + * the first byte, and the number of characters emitted (not counting the + * trailing zero) is returned. + */ +static __attribute__((unused)) +int i64toa_r(int64_t in, char *buffer) +{ + char *ptr = buffer; + int len = 0; + + if (in < 0) { + in = -in; + *(ptr++) = '-'; + len++; + } + len += u64toa_r(in, ptr); + return len; +} + +/* converts int64_t to a string using the static itoa_buffer and returns + * the pointer to that string. + */ +static inline __attribute__((unused)) +char *i64toa(int64_t in) +{ + i64toa_r(in, itoa_buffer); + return itoa_buffer; +} + +/* converts uint64_t to a string using the static itoa_buffer and returns + * the pointer to that string. + */ +static inline __attribute__((unused)) +char *u64toa(uint64_t in) +{ + u64toa_r(in, itoa_buffer); + return itoa_buffer; +} + static __attribute__((unused)) int msleep(unsigned int msecs) { -- cgit From 5f493178ef3187b939d3068563e5da6045085c2a Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:29 +0100 Subject: tools/nolibc/stdlib: add utoh() and u64toh() This adds a pair of functions to emit hex values. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 80 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index d972871bf2ba..82a4cf606d3c 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -52,6 +52,46 @@ int atoi(const char *s) return atol(s); } +/* Converts the unsigned long integer to its hex representation into + * buffer , which must be long enough to store the number and the + * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The + * buffer is filled from the first byte, and the number of characters emitted + * (not counting the trailing zero) is returned. The function is constructed + * in a way to optimize the code size and avoid any divide that could add a + * dependency on large external functions. + */ +static __attribute__((unused)) +int utoh_r(unsigned long in, char *buffer) +{ + signed char pos = (~0UL > 0xfffffffful) ? 60 : 28; + int digits = 0; + int dig; + + do { + dig = in >> pos; + in -= (uint64_t)dig << pos; + pos -= 4; + if (dig || digits || pos < 0) { + if (dig > 9) + dig += 'a' - '0' - 10; + buffer[digits++] = '0' + dig; + } + } while (pos >= 0); + + buffer[digits] = 0; + return digits; +} + +/* converts unsigned long to an hex string using the static itoa_buffer + * and returns the pointer to that string. + */ +static inline __attribute__((unused)) +char *utoh(unsigned long in) +{ + utoh_r(in, itoa_buffer); + return itoa_buffer; +} + /* Converts the unsigned long integer to its string representation into * buffer , which must be long enough to store the number and the * trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for @@ -144,6 +184,46 @@ char *utoa(unsigned long in) return itoa_buffer; } +/* Converts the unsigned 64-bit integer to its hex representation into + * buffer , which must be long enough to store the number and the + * trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from + * the first byte, and the number of characters emitted (not counting the + * trailing zero) is returned. The function is constructed in a way to optimize + * the code size and avoid any divide that could add a dependency on large + * external functions. + */ +static __attribute__((unused)) +int u64toh_r(uint64_t in, char *buffer) +{ + signed char pos = 60; + int digits = 0; + int dig; + + do { + dig = in >> pos; + in -= (uint64_t)dig << pos; + pos -= 4; + if (dig || digits || pos < 0) { + if (dig > 9) + dig += 'a' - '0' - 10; + buffer[digits++] = '0' + dig; + } + } while (pos >= 0); + + buffer[digits] = 0; + return digits; +} + +/* converts uint64_t to an hex string using the static itoa_buffer and + * returns the pointer to that string. + */ +static inline __attribute__((unused)) +char *u64toh(uint64_t in) +{ + u64toh_r(in, itoa_buffer); + return itoa_buffer; +} + /* Converts the unsigned 64-bit integer to its string representation into * buffer , which must be long enough to store the number and the * trailing zero (21 bytes for 18446744073709551615). The buffer is filled from -- cgit From 4e383a66acfe16827ce7fbc0e60c56782a83fc92 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:30 +0100 Subject: tools/nolibc/stdio: add a minimal set of stdio functions This only provides getchar(), putchar(), and puts(). Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/stdio.h | 57 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tools/include/nolibc/stdio.h (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index a349c88c45ff..7eaa09fe9f4d 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -88,6 +88,7 @@ #include "types.h" #include "sys.h" #include "ctype.h" +#include "stdio.h" #include "stdlib.h" #include "string.h" diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h new file mode 100644 index 000000000000..4c6af3016e2e --- /dev/null +++ b/tools/include/nolibc/stdio.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * minimal stdio function definitions for NOLIBC + * Copyright (C) 2017-2021 Willy Tarreau + */ + +#ifndef _NOLIBC_STDIO_H +#define _NOLIBC_STDIO_H + +#include "std.h" +#include "arch.h" +#include "types.h" +#include "sys.h" +#include "stdlib.h" +#include "string.h" + +#ifndef EOF +#define EOF (-1) +#endif + +static __attribute__((unused)) +int getchar(void) +{ + unsigned char ch; + + if (read(0, &ch, 1) <= 0) + return EOF; + return ch; +} + +static __attribute__((unused)) +int putchar(int c) +{ + unsigned char ch = c; + + if (write(1, &ch, 1) <= 0) + return EOF; + return ch; +} + +static __attribute__((unused)) +int puts(const char *s) +{ + size_t len = strlen(s); + ssize_t ret; + + while (len > 0) { + ret = write(1, s, len); + if (ret <= 0) + return EOF; + s += ret; + len -= ret; + } + return putchar('\n'); +} + +#endif /* _NOLIBC_STDIO_H */ -- cgit From 99b037cbd5a22e34202d32aad15bcfa1c06d1d80 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:31 +0100 Subject: tools/nolibc/stdio: add stdin/stdout/stderr and fget*/fput* functions The standard puts() function always emits the trailing LF which makes it unconvenient for small string concatenation. fputs() ought to be used instead but it requires a FILE*. This adds 3 dummy FILE* values (stdin, stdout, stderr) which are in fact pointers to struct FILE of one byte. We reserve 3 pointer values for them, -3, -2 and -1, so that they are ordered, easing the tests and mapping to integer. >From this, fgetc(), fputc(), fgets() and fputs() were implemented, and the previous putchar() and getchar() now remap to these. The standard getc() and putc() macros were also implemented as pointing to these ones. There is absolutely no buffering, fgetc() and fgets() read one byte at a time, fputc() writes one byte at a time, and only fputs() which knows the string's length writes all of it at once. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdio.h | 95 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 4c6af3016e2e..149c5ca59aad 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -18,40 +18,123 @@ #define EOF (-1) #endif +/* just define FILE as a non-empty type */ +typedef struct FILE { + char dummy[1]; +} FILE; + +/* We define the 3 common stdio files as constant invalid pointers that + * are easily recognized. + */ +static __attribute__((unused)) FILE* const stdin = (FILE*)-3; +static __attribute__((unused)) FILE* const stdout = (FILE*)-2; +static __attribute__((unused)) FILE* const stderr = (FILE*)-1; + +/* getc(), fgetc(), getchar() */ + +#define getc(stream) fgetc(stream) + static __attribute__((unused)) -int getchar(void) +int fgetc(FILE* stream) { unsigned char ch; + int fd; - if (read(0, &ch, 1) <= 0) + if (stream < stdin || stream > stderr) + return EOF; + + fd = 3 + (long)stream; + + if (read(fd, &ch, 1) <= 0) return EOF; return ch; } static __attribute__((unused)) -int putchar(int c) +int getchar(void) +{ + return fgetc(stdin); +} + + +/* putc(), fputc(), putchar() */ + +#define putc(c, stream) fputc(c, stream) + +static __attribute__((unused)) +int fputc(int c, FILE* stream) { unsigned char ch = c; + int fd; - if (write(1, &ch, 1) <= 0) + if (stream < stdin || stream > stderr) + return EOF; + + fd = 3 + (long)stream; + + if (write(fd, &ch, 1) <= 0) return EOF; return ch; } static __attribute__((unused)) -int puts(const char *s) +int putchar(int c) +{ + return fputc(c, stdout); +} + + +/* puts(), fputs(). Note that puts() emits '\n' but not fputs(). */ + +static __attribute__((unused)) +int fputs(const char *s, FILE *stream) { size_t len = strlen(s); ssize_t ret; + int fd; + + if (stream < stdin || stream > stderr) + return EOF; + + fd = 3 + (long)stream; while (len > 0) { - ret = write(1, s, len); + ret = write(fd, s, len); if (ret <= 0) return EOF; s += ret; len -= ret; } + return 0; +} + +static __attribute__((unused)) +int puts(const char *s) +{ + if (fputs(s, stdout) == EOF) + return EOF; return putchar('\n'); } + +/* fgets() */ +static __attribute__((unused)) +char *fgets(char *s, int size, FILE *stream) +{ + int ofs; + int c; + + for (ofs = 0; ofs + 1 < size;) { + c = fgetc(stream); + if (c == EOF) + break; + s[ofs++] = c; + if (c == '\n') + break; + } + if (ofs < size) + s[ofs] = 0; + return ofs ? s : NULL; +} + #endif /* _NOLIBC_STDIO_H */ -- cgit From e3e19052d54db8d492b8f82f8516139469bad5d3 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:32 +0100 Subject: tools/nolibc/stdio: add fwrite() to stdio We'll use it to write substrings. It relies on a simpler _fwrite() that only takes one size. fputs() was also modified to rely on it. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdio.h | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 149c5ca59aad..996bf89a30d2 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -84,12 +84,14 @@ int putchar(int c) } -/* puts(), fputs(). Note that puts() emits '\n' but not fputs(). */ +/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */ +/* internal fwrite()-like function which only takes a size and returns 0 on + * success or EOF on error. It automatically retries on short writes. + */ static __attribute__((unused)) -int fputs(const char *s, FILE *stream) +int _fwrite(const void *buf, size_t size, FILE *stream) { - size_t len = strlen(s); ssize_t ret; int fd; @@ -98,16 +100,35 @@ int fputs(const char *s, FILE *stream) fd = 3 + (long)stream; - while (len > 0) { - ret = write(fd, s, len); + while (size) { + ret = write(fd, buf, size); if (ret <= 0) return EOF; - s += ret; - len -= ret; + size -= ret; + buf += ret; } return 0; } +static __attribute__((unused)) +size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream) +{ + size_t written; + + for (written = 0; written < nmemb; written++) { + if (_fwrite(s, size, stream) != 0) + break; + s += size; + } + return written; +} + +static __attribute__((unused)) +int fputs(const char *s, FILE *stream) +{ + return _fwrite(s, strlen(s), stream); +} + static __attribute__((unused)) int puts(const char *s) { -- cgit From 7e4346f4a3a611a6233ba388080c1426545da4fc Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:33 +0100 Subject: tools/nolibc/stdio: add a minimal [vf]printf() implementation This adds a minimal vfprintf() implementation as well as the commonly used fprintf() and printf() that rely on it. For now the function supports: - formats: %s, %c, %u, %d, %x - modifiers: %l and %ll - unknown chars are considered as modifiers and are ignored It is designed to remain minimalist, despite this printf() is 549 bytes on x86_64. It would be wise not to add too many formats. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdio.h | 128 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 996bf89a30d2..a73cf24cb68d 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_STDIO_H #define _NOLIBC_STDIO_H +#include + #include "std.h" #include "arch.h" #include "types.h" @@ -158,4 +160,130 @@ char *fgets(char *s, int size, FILE *stream) return ofs ? s : NULL; } + +/* minimal vfprintf(). It supports the following formats: + * - %[l*]{d,u,c,x} + * - %s + * - unknown modifiers are ignored. + */ +static __attribute__((unused)) +int vfprintf(FILE *stream, const char *fmt, va_list args) +{ + char escape, lpref, c; + unsigned long long v; + unsigned int written; + size_t len, ofs; + char tmpbuf[21]; + const char *outstr; + + written = ofs = escape = lpref = 0; + while (1) { + c = fmt[ofs++]; + + if (escape) { + /* we're in an escape sequence, ofs == 1 */ + escape = 0; + if (c == 'c' || c == 'd' || c == 'u' || c == 'x') { + if (lpref) { + if (lpref > 1) + v = va_arg(args, unsigned long long); + else + v = va_arg(args, unsigned long); + } else + v = va_arg(args, unsigned int); + + if (c == 'd') { + /* sign-extend the value */ + if (lpref == 0) + v = (long long)(int)v; + else if (lpref == 1) + v = (long long)(long)v; + } + + switch (c) { + case 'd': + i64toa_r(v, tmpbuf); + break; + case 'u': + u64toa_r(v, tmpbuf); + break; + case 'x': + u64toh_r(v, tmpbuf); + break; + default: /* 'c' */ + tmpbuf[0] = v; + tmpbuf[1] = 0; + break; + } + outstr = tmpbuf; + } + else if (c == 's') { + outstr = va_arg(args, char *); + } + else if (c == '%') { + /* queue it verbatim */ + continue; + } + else { + /* modifiers or final 0 */ + if (c == 'l') { + /* long format prefix, maintain the escape */ + lpref++; + } + escape = 1; + goto do_escape; + } + len = strlen(outstr); + goto flush_str; + } + + /* not an escape sequence */ + if (c == 0 || c == '%') { + /* flush pending data on escape or end */ + escape = 1; + lpref = 0; + outstr = fmt; + len = ofs - 1; + flush_str: + if (_fwrite(outstr, len, stream) != 0) + break; + + written += len; + do_escape: + if (c == 0) + break; + fmt += ofs; + ofs = 0; + continue; + } + + /* literal char, just queue it */ + } + return written; +} + +static __attribute__((unused)) +int fprintf(FILE *stream, const char *fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + ret = vfprintf(stream, fmt, args); + va_end(args); + return ret; +} + +static __attribute__((unused)) +int printf(const char *fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + ret = vfprintf(stdout, fmt, args); + va_end(args); + return ret; +} + #endif /* _NOLIBC_STDIO_H */ -- cgit From 51469d5ab38fd1ac2182da8cd49eea3420b8000b Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:34 +0100 Subject: tools/nolibc/types: define EXIT_SUCCESS and EXIT_FAILURE These ones are found in some examples found in man pages and ease portability tests. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/types.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index b1bff5e717b6..e0749dc0bd06 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -71,6 +71,9 @@ #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define WIFEXITED(status) (((status) & 0x7f) == 0) +/* standard exit() codes */ +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 /* for select() */ typedef struct { -- cgit From acab7bcdb1bc14d5a6a0c3c1d2b9bd681172cf47 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:35 +0100 Subject: tools/nolibc/stdio: add perror() to report the errno value It doesn't contain the text for the error codes, but instead displays "errno=" followed by the errno value. Just like the regular errno, if a non-empty message is passed, it's placed followed with ": " on the output before the errno code. The message is emitted on stderr. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdio.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index a73cf24cb68d..5f1cf32470d3 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -286,4 +286,10 @@ int printf(const char *fmt, ...) return ret; } +static __attribute__((unused)) +void perror(const char *msg) +{ + fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); +} + #endif /* _NOLIBC_STDIO_H */ -- cgit From a7604ba149e76d0449484116e7bf9cd0c26dafb2 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:36 +0100 Subject: tools/nolibc/sys: make open() take a vararg on the 3rd argument Let's pass a vararg to open() so that it remains compatible with existing code. The arg is only dereferenced when flags contain O_CREAT. The function is generally not inlined anymore, causing an extra call (total 16 extra bytes) but it's still optimized for constant propagation, limiting the excess to no more than 16 bytes in practice when open() is called without O_CREAT, and ~40 with O_CREAT, which remains reasonable. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/sys.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 98689f668ed3..539af457a91b 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -7,6 +7,7 @@ #ifndef _NOLIBC_SYS_H #define _NOLIBC_SYS_H +#include #include "std.h" /* system includes */ @@ -719,7 +720,7 @@ int mount(const char *src, const char *tgt, /* - * int open(const char *path, int flags, mode_t mode); + * int open(const char *path, int flags[, mode_t mode]); */ static __attribute__((unused)) @@ -735,9 +736,20 @@ int sys_open(const char *path, int flags, mode_t mode) } static __attribute__((unused)) -int open(const char *path, int flags, mode_t mode) +int open(const char *path, int flags, ...) { - int ret = sys_open(path, flags, mode); + mode_t mode = 0; + int ret; + + if (flags & O_CREAT) { + va_list args; + + va_start(args, flags); + mode = va_arg(args, mode_t); + va_end(args); + } + + ret = sys_open(path, flags, mode); if (ret < 0) { SET_ERRNO(-ret); -- cgit From ac90226d53051c1ae0f0e1b71596fb038ddb6cf6 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:37 +0100 Subject: tools/nolibc/stdlib: avoid a 64-bit shift in u64toh_r() The build of printf() on mips requires libgcc for functions __ashldi3 and __lshrdi3 due to 64-bit shifts when scanning the input number. These are not really needed in fact since we scan the number 4 bits at a time. Let's arrange the loop to perform two 32-bit shifts instead on 32-bit platforms. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 82a4cf606d3c..db47362a750f 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -200,14 +200,18 @@ int u64toh_r(uint64_t in, char *buffer) int dig; do { - dig = in >> pos; - in -= (uint64_t)dig << pos; + if (sizeof(long) >= 8) { + dig = (in >> pos) & 0xF; + } else { + /* 32-bit platforms: avoid a 64-bit shift */ + uint32_t d = (pos >= 32) ? (in >> 32) : in; + dig = (d >> (pos & 31)) & 0xF; + } + if (dig > 9) + dig += 'a' - '0' - 10; pos -= 4; - if (dig || digits || pos < 0) { - if (dig > 9) - dig += 'a' - '0' - 10; + if (dig || digits || pos < 0) buffer[digits++] = '0' + dig; - } } while (pos >= 0); buffer[digits] = 0; -- cgit From 6e277371a5c4c73deb799aabfd5613ee3758e810 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:38 +0100 Subject: tools/nolibc/stdlib: make raise() use the lower level syscalls only raise() doesn't set errno, so there's no point calling kill(), better call sys_kill(), which also reduces the function's size. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index db47362a750f..4cc1fdf6791e 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -317,7 +317,7 @@ int msleep(unsigned int msecs) __attribute__((weak,unused)) int raise(int signal) { - return kill(getpid(), signal); + return sys_kill(sys_getpid(), signal); } static __attribute__((unused)) -- cgit From 830acd088edc1604ee46916188491ef634441fc6 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:39 +0100 Subject: tools/nolibc/sys: make getpgrp(), getpid(), gettid() not set errno These syscalls never fail so there is no need to extract and set errno for them. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/sys.h | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 539af457a91b..ef017cc0a580 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -458,13 +458,7 @@ pid_t sys_getpgrp(void) static __attribute__((unused)) pid_t getpgrp(void) { - pid_t ret = sys_getpgrp(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return sys_getpgrp(); } @@ -481,13 +475,7 @@ pid_t sys_getpid(void) static __attribute__((unused)) pid_t getpid(void) { - pid_t ret = sys_getpid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return sys_getpid(); } @@ -504,13 +492,7 @@ pid_t sys_gettid(void) static __attribute__((unused)) pid_t gettid(void) { - pid_t ret = sys_gettid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return sys_gettid(); } -- cgit From d8dcc2d8d93e5d4263ca9f8c5bdfb713f82fe923 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:40 +0100 Subject: tools/nolibc/string: use unidirectional variants for memcpy() Till now memcpy() relies on memmove(), but it's always included for libgcc, so we have a larger than needed function. Let's implement two unidirectional variants to copy from bottom to top and from top to bottom, and use the former for memcpy(). The variants are optimized to be compact, and at the same time the compiler is sometimes able to detect the loop and to replace it with a "rep movsb". The new function is 24 bytes instead of 52 on x86_64. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index 8a23cda2d450..6d8fad7a92e6 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -25,6 +25,28 @@ int memcmp(const void *s1, const void *s2, size_t n) return c1; } +static __attribute__((unused)) +void *_nolibc_memcpy_up(void *dst, const void *src, size_t len) +{ + size_t pos = 0; + + while (pos < len) { + ((char *)dst)[pos] = ((const char *)src)[pos]; + pos++; + } + return dst; +} + +static __attribute__((unused)) +void *_nolibc_memcpy_down(void *dst, const void *src, size_t len) +{ + while (len) { + len--; + ((char *)dst)[len] = ((const char *)src)[len]; + } + return dst; +} + static __attribute__((unused)) void *memmove(void *dst, const void *src, size_t len) { @@ -42,7 +64,7 @@ void *memmove(void *dst, const void *src, size_t len) __attribute__((weak,unused)) void *memcpy(void *dst, const void *src, size_t len) { - return memmove(dst, src, len); + return _nolibc_memcpy_up(dst, src, len); } static __attribute__((unused)) -- cgit From d76232ff8be662b8851e975d13d59cad4bf423d3 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:41 +0100 Subject: tools/nolibc/string: slightly simplify memmove() The direction test inside the loop was not always completely optimized, resulting in a larger than necessary function. This change adds a direction variable that is set out of the loop. Now the function is down to 48 bytes on x86, 32 on ARM and 68 on mips. It's worth noting that other approaches were attempted (including relying on the up and down functions) but they were only slightly beneficial on x86 and cost more on others. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index 6d8fad7a92e6..b831a02de83f 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -50,14 +50,22 @@ void *_nolibc_memcpy_down(void *dst, const void *src, size_t len) static __attribute__((unused)) void *memmove(void *dst, const void *src, size_t len) { - ssize_t pos = (dst <= src) ? -1 : (long)len; - void *ret = dst; + size_t dir, pos; - while (len--) { - pos += (dst <= src) ? 1 : -1; - ((char *)dst)[pos] = ((char *)src)[pos]; + pos = len; + dir = -1; + + if (dst < src) { + pos = -1; + dir = 1; } - return ret; + + while (len) { + pos += dir; + ((char *)dst)[pos] = ((const char *)src)[pos]; + len--; + } + return dst; } /* must be exported, as it's used by libgcc on ARM */ -- cgit From b312eb0b8711dbfbe2b45681926eb553e8ac8de3 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:42 +0100 Subject: tools/nolibc/string: add strncpy() and strlcpy() These are minimal variants. strncpy() always fills the destination for chars, while strlcpy() copies no more than including the zero and returns the source's length. The respective sizes on various archs are: strncpy(): x86:0x1f mips:0x30 arm:0x20 strlcpy(): x86:0x17 mips:0x34 arm:0x1a Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index b831a02de83f..7c274efcdfae 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -121,6 +121,34 @@ size_t nolibc_strlen(const char *str) nolibc_strlen((str)); \ }) +static __attribute__((unused)) +size_t strlcpy(char *dst, const char *src, size_t size) +{ + size_t len; + char c; + + for (len = 0;;) { + c = src[len]; + if (len < size) + dst[len] = c; + if (!c) + break; + len++; + } + return len; +} + +static __attribute__((unused)) +char *strncpy(char *dst, const char *src, size_t size) +{ + size_t len; + + for (len = 0; len < size; len++) + if ((dst[len] = *src)) + src++; + return dst; +} + static __attribute__((unused)) char *strrchr(const char *s, int c) { -- cgit From d9390de638cd9788090c6299273a41a8cfa0b499 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:43 +0100 Subject: tools/nolibc/string: add tiny versions of strncat() and strlcat() While these functions are often dangerous, forcing the user to work around their absence is often much worse. Let's provide small versions of each of them. The respective sizes in bytes on a few architectures are: strncat(): x86:0x33 mips:0x68 arm:0x3c strlcat(): x86:0x25 mips:0x4c arm:0x2c The two are quite different, and strncat() is even different from strncpy() in that it limits the amount of data it copies and will always terminate the output by one zero, while strlcat() will always limit the total output to the specified size and will put a zero if possible. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index 7c274efcdfae..c550c9ba8f4c 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -121,6 +121,28 @@ size_t nolibc_strlen(const char *str) nolibc_strlen((str)); \ }) +static __attribute__((unused)) +size_t strlcat(char *dst, const char *src, size_t size) +{ + size_t len; + char c; + + for (len = 0; dst[len]; len++) + ; + + for (;;) { + c = *src; + if (len < size) + dst[len] = c; + if (!c) + break; + len++; + src++; + } + + return len; +} + static __attribute__((unused)) size_t strlcpy(char *dst, const char *src, size_t size) { @@ -138,6 +160,25 @@ size_t strlcpy(char *dst, const char *src, size_t size) return len; } +static __attribute__((unused)) +char *strncat(char *dst, const char *src, size_t size) +{ + char *orig = dst; + + while (*dst) + dst++; + + while (size && (*dst = *src)) { + src++; + dst++; + size--; + } + + *dst = 0; + return orig; +} + + static __attribute__((unused)) char *strncpy(char *dst, const char *src, size_t size) { -- cgit From 07f47ea06fe9d38c5e8d9068fba2468ed8bb8b59 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:44 +0100 Subject: tools/nolibc: move exported functions to their own section Some functions like raise() and memcpy() are permanently exported because they're needed by libgcc on certain platforms. However most of the time they are not needed and needlessly take space. Let's move them to their own sub-section, called .text.nolibc_. This allows ld to get rid of them if unused when passed --gc-sections. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 2 +- tools/include/nolibc/string.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 4cc1fdf6791e..da08ff30c15a 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -314,7 +314,7 @@ int msleep(unsigned int msecs) } /* This one is not marked static as it's needed by libgcc for divide by zero */ -__attribute__((weak,unused)) +__attribute__((weak,unused,section(".text.nolibc_raise"))) int raise(int signal) { return sys_kill(sys_getpid(), signal); diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index c550c9ba8f4c..c1661589cb3c 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -69,7 +69,7 @@ void *memmove(void *dst, const void *src, size_t len) } /* must be exported, as it's used by libgcc on ARM */ -__attribute__((weak,unused)) +__attribute__((weak,unused,section(".text.nolibc_memcpy"))) void *memcpy(void *dst, const void *src, size_t len) { return _nolibc_memcpy_up(dst, src, len); -- cgit From dffeb81af5fe5eedccf5ea4a8a120d8c3accd26e Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:45 +0100 Subject: tools/nolibc/arch: mark the _start symbol as weak By doing so we can link together multiple C files that have been compiled with nolibc and which each have a _start symbol. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-aarch64.h | 1 + tools/include/nolibc/arch-arm.h | 1 + tools/include/nolibc/arch-i386.h | 1 + tools/include/nolibc/arch-mips.h | 1 + tools/include/nolibc/arch-riscv.h | 1 + tools/include/nolibc/arch-x86_64.h | 1 + 6 files changed, 6 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index 443de5fb7f54..87d9e434820c 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -183,6 +183,7 @@ struct sys_stat_struct { /* startup code */ asm(".section .text\n" + ".weak _start\n" ".global _start\n" "_start:\n" "ldr x0, [sp]\n" // argc (x0) was in the stack diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index 66f687ad987f..001a3c8c9ad5 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -176,6 +176,7 @@ struct sys_stat_struct { /* startup code */ asm(".section .text\n" + ".weak _start\n" ".global _start\n" "_start:\n" #if defined(__THUMBEB__) || defined(__THUMBEL__) diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index 32f42e2cee26..d7e4d53325a3 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -175,6 +175,7 @@ struct sys_stat_struct { * */ asm(".section .text\n" + ".weak _start\n" ".global _start\n" "_start:\n" "pop %eax\n" // argc (first arg, %eax) diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index e330201dde6a..c9a6aac87c6d 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -190,6 +190,7 @@ struct sys_stat_struct { /* startup code, note that it's called __start on MIPS */ asm(".section .text\n" + ".weak __start\n" ".set nomips16\n" ".global __start\n" ".set noreorder\n" diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index 9d5ff78f606b..bc10b7b5706d 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -184,6 +184,7 @@ struct sys_stat_struct { /* startup code */ asm(".section .text\n" + ".weak _start\n" ".global _start\n" "_start:\n" ".option push\n" diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index 83c4b458ada7..fe517c16cd4d 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -198,6 +198,7 @@ struct sys_stat_struct { * */ asm(".section .text\n" + ".weak _start\n" ".global _start\n" "_start:\n" "pop %rdi\n" // argc (first arg, %rdi) -- cgit From 023033fe343cdf2ba83ab762f8de69241c7fc086 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:46 +0100 Subject: tools/nolibc/types: define PATH_MAX and MAXPATHLEN These ones are often used and commonly set by applications to fallback values. Let's fix them both to agree on PATH_MAX=4096 by default, as is already present in linux/limits.h. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/types.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index e0749dc0bd06..e4026e740b56 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -49,6 +49,17 @@ #define FD_SETSIZE 256 #endif +/* PATH_MAX and MAXPATHLEN are often used and found with plenty of different + * values. + */ +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN (PATH_MAX) +#endif + /* Special FD used by all the *at functions */ #ifndef AT_FDCWD #define AT_FDCWD (-100) -- cgit From 8d304a3740232f018fca19d529cbc8d13afac755 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:47 +0100 Subject: tools/nolibc/string: export memset() and memmove() "clang -Os" and "gcc -Ofast" without -ffreestanding may ignore memset() and memmove(), hoping to provide their builtin equivalents, and finally not find them. Thus we must export these functions for these rare cases. Note that as they're set in their own sections, they will be eliminated by the linker if not used. In addition, they do not prevent gcc from identifying them and replacing them with the shorter "rep movsb" or "rep stosb" when relevant. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index c1661589cb3c..4554b6fcb400 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -47,7 +47,10 @@ void *_nolibc_memcpy_down(void *dst, const void *src, size_t len) return dst; } -static __attribute__((unused)) +/* might be ignored by the compiler without -ffreestanding, then found as + * missing. + */ +__attribute__((weak,unused,section(".text.nolibc_memmove"))) void *memmove(void *dst, const void *src, size_t len) { size_t dir, pos; @@ -75,7 +78,10 @@ void *memcpy(void *dst, const void *src, size_t len) return _nolibc_memcpy_up(dst, src, len); } -static __attribute__((unused)) +/* might be ignored by the compiler without -ffreestanding, then found as + * missing. + */ +__attribute__((weak,unused,section(".text.nolibc_memset"))) void *memset(void *dst, int b, size_t len) { char *p = dst; -- cgit From 45a794bf7cee2988278802aeb64f7fc075f45f7f Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:48 +0100 Subject: tools/nolibc/errno: extract errno.h from sys.h This allows us to provide a minimal errno.h to ease porting applications that use it. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/errno.h | 27 +++++++++++++++++++++++++++ tools/include/nolibc/stdio.h | 1 + tools/include/nolibc/sys.h | 17 +---------------- 3 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 tools/include/nolibc/errno.h (limited to 'tools/include') diff --git a/tools/include/nolibc/errno.h b/tools/include/nolibc/errno.h new file mode 100644 index 000000000000..06893d6dfb7a --- /dev/null +++ b/tools/include/nolibc/errno.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * Minimal errno definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_ERRNO_H +#define _NOLIBC_ERRNO_H + +#include + +/* this way it will be removed if unused */ +static int errno; + +#ifndef NOLIBC_IGNORE_ERRNO +#define SET_ERRNO(v) do { errno = (v); } while (0) +#else +#define SET_ERRNO(v) do { } while (0) +#endif + + +/* errno codes all ensure that they will not conflict with a valid pointer + * because they all correspond to the highest addressable memory page. + */ +#define MAX_ERRNO 4095 + +#endif /* _NOLIBC_ERRNO_H */ diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 5f1cf32470d3..cb4d3ab3a565 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -11,6 +11,7 @@ #include "std.h" #include "arch.h" +#include "errno.h" #include "types.h" #include "sys.h" #include "stdlib.h" diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index ef017cc0a580..28437863c63f 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -14,29 +14,14 @@ #include #include // for SIGCHLD #include -#include #include #include #include #include "arch.h" +#include "errno.h" #include "types.h" -/* this way it will be removed if unused */ -static int errno; - -#ifndef NOLIBC_IGNORE_ERRNO -#define SET_ERRNO(v) do { errno = (v); } while (0) -#else -#define SET_ERRNO(v) do { } while (0) -#endif - - -/* errno codes all ensure that they will not conflict with a valid pointer - * because they all correspond to the highest addressable memory page. - */ -#define MAX_ERRNO 4095 - /* Functions in this file only describe syscalls. They're declared static so * that the compiler usually decides to inline them while still being allowed -- cgit From 4619de344657c23101e8976b816466910dfb2759 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:49 +0100 Subject: tools/nolibc/unistd: extract msleep(), sleep(), tcsetpgrp() to unistd.h These functions are normally provided by unistd.h. For ease of porting, let's create the file and move them there. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/stdlib.h | 30 ---------------------------- tools/include/nolibc/unistd.h | 46 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 30 deletions(-) create mode 100644 tools/include/nolibc/unistd.h (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 7eaa09fe9f4d..686726518431 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -91,6 +91,7 @@ #include "stdio.h" #include "stdlib.h" #include "string.h" +#include "unistd.h" /* Used by programs to avoid std includes */ #define NOLIBC diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index da08ff30c15a..0e6bca4ee089 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -300,19 +300,6 @@ char *u64toa(uint64_t in) return itoa_buffer; } -static __attribute__((unused)) -int msleep(unsigned int msecs) -{ - struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 }; - - if (sys_select(0, 0, 0, 0, &my_timeval) < 0) - return (my_timeval.tv_sec * 1000) + - (my_timeval.tv_usec / 1000) + - !!(my_timeval.tv_usec % 1000); - else - return 0; -} - /* This one is not marked static as it's needed by libgcc for divide by zero */ __attribute__((weak,unused,section(".text.nolibc_raise"))) int raise(int signal) @@ -320,21 +307,4 @@ int raise(int signal) return sys_kill(sys_getpid(), signal); } -static __attribute__((unused)) -unsigned int sleep(unsigned int seconds) -{ - struct timeval my_timeval = { seconds, 0 }; - - if (sys_select(0, 0, 0, 0, &my_timeval) < 0) - return my_timeval.tv_sec + !!my_timeval.tv_usec; - else - return 0; -} - -static __attribute__((unused)) -int tcsetpgrp(int fd, pid_t pid) -{ - return ioctl(fd, TIOCSPGRP, &pid); -} - #endif /* _NOLIBC_STDLIB_H */ diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h new file mode 100644 index 000000000000..87b448ff2191 --- /dev/null +++ b/tools/include/nolibc/unistd.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * unistd function definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_UNISTD_H +#define _NOLIBC_UNISTD_H + +#include "std.h" +#include "arch.h" +#include "types.h" +#include "sys.h" + + +static __attribute__((unused)) +int msleep(unsigned int msecs) +{ + struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 }; + + if (sys_select(0, 0, 0, 0, &my_timeval) < 0) + return (my_timeval.tv_sec * 1000) + + (my_timeval.tv_usec / 1000) + + !!(my_timeval.tv_usec % 1000); + else + return 0; +} + +static __attribute__((unused)) +unsigned int sleep(unsigned int seconds) +{ + struct timeval my_timeval = { seconds, 0 }; + + if (sys_select(0, 0, 0, 0, &my_timeval) < 0) + return my_timeval.tv_sec + !!my_timeval.tv_usec; + else + return 0; +} + +static __attribute__((unused)) +int tcsetpgrp(int fd, pid_t pid) +{ + return ioctl(fd, TIOCSPGRP, &pid); +} + +#endif /* _NOLIBC_UNISTD_H */ -- cgit From 180a9797b03472e6881066d9752f2f0d81e1880f Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:50 +0100 Subject: tools/nolibc/unistd: add usleep() This call is trivial to implement based on select() to complete sleep() and msleep(), let's add it. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/unistd.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index 87b448ff2191..1c25e20ee360 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -37,6 +37,14 @@ unsigned int sleep(unsigned int seconds) return 0; } +static __attribute__((unused)) +int usleep(unsigned int usecs) +{ + struct timeval my_timeval = { usecs / 1000000, usecs % 1000000 }; + + return sys_select(0, 0, 0, 0, &my_timeval); +} + static __attribute__((unused)) int tcsetpgrp(int fd, pid_t pid) { -- cgit From 99cb50ab94b2aa11c756c4ba14ef09197a7ebe7b Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:51 +0100 Subject: tools/nolibc/signal: move raise() to signal.h This function is normally found in signal.h, and providing the file eases porting of existing programs. Let's move it there. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/signal.h | 22 ++++++++++++++++++++++ tools/include/nolibc/stdlib.h | 7 ------- 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 tools/include/nolibc/signal.h (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 686726518431..0f375e901a36 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -88,6 +88,7 @@ #include "types.h" #include "sys.h" #include "ctype.h" +#include "signal.h" #include "stdio.h" #include "stdlib.h" #include "string.h" diff --git a/tools/include/nolibc/signal.h b/tools/include/nolibc/signal.h new file mode 100644 index 000000000000..ef47e71e2be3 --- /dev/null +++ b/tools/include/nolibc/signal.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * signal function definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_SIGNAL_H +#define _NOLIBC_SIGNAL_H + +#include "std.h" +#include "arch.h" +#include "types.h" +#include "sys.h" + +/* This one is not marked static as it's needed by libgcc for divide by zero */ +__attribute__((weak,unused,section(".text.nolibc_raise"))) +int raise(int signal) +{ + return sys_kill(sys_getpid(), signal); +} + +#endif /* _NOLIBC_SIGNAL_H */ diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 0e6bca4ee089..b46bebd48ba2 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -300,11 +300,4 @@ char *u64toa(uint64_t in) return itoa_buffer; } -/* This one is not marked static as it's needed by libgcc for divide by zero */ -__attribute__((weak,unused,section(".text.nolibc_raise"))) -int raise(int signal) -{ - return sys_kill(sys_getpid(), signal); -} - #endif /* _NOLIBC_STDLIB_H */ -- cgit From cec1505321020287c3acc5a63dd75859ebf5ad0d Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:52 +0100 Subject: tools/nolibc/time: create time.h with time() The time() syscall is used by a few simple applications, and is trivial to implement based on gettimeofday() that we already have. Let's create the file to ease porting and provide the function. It never returns any error, though it may segfault in case of invalid pointer, like other implementations relying on gettimeofday(). Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/time.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tools/include/nolibc/time.h (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 0f375e901a36..561dcdb83cee 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -92,6 +92,7 @@ #include "stdio.h" #include "stdlib.h" #include "string.h" +#include "time.h" #include "unistd.h" /* Used by programs to avoid std includes */ diff --git a/tools/include/nolibc/time.h b/tools/include/nolibc/time.h new file mode 100644 index 000000000000..d18b7661fdd7 --- /dev/null +++ b/tools/include/nolibc/time.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * time function definitions for NOLIBC + * Copyright (C) 2017-2022 Willy Tarreau + */ + +#ifndef _NOLIBC_TIME_H +#define _NOLIBC_TIME_H + +#include "std.h" +#include "arch.h" +#include "types.h" +#include "sys.h" + +static __attribute__((unused)) +time_t time(time_t *tptr) +{ + struct timeval tv; + + /* note, cannot fail here */ + sys_gettimeofday(&tv, NULL); + + if (tptr) + *tptr = tv.tv_sec; + return tv.tv_sec; +} + +#endif /* _NOLIBC_TIME_H */ -- cgit From c4486e97283d0b3d72a8eeda91e53e2ea9b62fbe Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:53 +0100 Subject: tools/nolibc: also mention how to build by just setting the include path Now that a few basic include files are provided, some simple portable programs may build, which will save them from having to surround their includes with #ifndef NOLIBC. This patch mentions how to proceed, and enumerates the list of files that are covered. A comprehensive list of required include files is available here: https://en.cppreference.com/w/c/header Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 561dcdb83cee..b2bc48d3cfe4 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -57,22 +57,32 @@ * having to specify anything. * * Finally some very common libc-level functions are provided. It is the case - * for a few functions usually found in string.h, ctype.h, or stdlib.h. Nothing - * is currently provided regarding stdio emulation. + * for a few functions usually found in string.h, ctype.h, or stdlib.h. * - * The macro NOLIBC is always defined, so that it is possible for a program to - * check this macro to know if it is being built against and decide to disable - * some features or simply not to include some standard libc files. - * - * Ideally this file should be split in multiple files for easier long term - * maintenance, but provided as a single file as it is now, it's quite - * convenient to use. Maybe some variations involving a set of includes at the - * top could work. + * The nolibc.h file is only a convenient entry point which includes all other + * files. It also defines the NOLIBC macro, so that it is possible for a + * program to check this macro to know if it is being built against and decide + * to disable some features or simply not to include some standard libc files. * * A simple static executable may be built this way : * $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ * -static -include nolibc.h -o hello hello.c -lgcc * + * Simple programs meant to be reasonably portable to various libc and using + * only a few common includes, may also be built by simply making the include + * path point to the nolibc directory: + * $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ + * -I../nolibc -o hello hello.c -lgcc + * + * The available standard (but limited) include files are: + * ctype.h, errno.h, signal.h, stdio.h, stdlib.h, string.h, time.h + * + * In addition, the following ones are expected to be provided by the compiler: + * float.h, stdarg.h, stddef.h + * + * The following ones which are part to the C standard are not provided: + * assert.h, locale.h, math.h, setjmp.h, limits.h + * * A very useful calling convention table may be found here : * http://man7.org/linux/man-pages/man2/syscall.2.html * -- cgit From f0f04f28d5ae483b3b354cb3b63a3bab0b00cee4 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 7 Feb 2022 17:23:54 +0100 Subject: tools/nolibc/stdlib: implement abort() libgcc uses it for certain divide functions, so it must be exported. Like for memset() we do that in its own section so that the linker can strip it when not needed. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index b46bebd48ba2..733105c574ee 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -23,6 +23,14 @@ static __attribute__((unused)) char itoa_buffer[21]; * As much as possible, please keep functions alphabetically sorted. */ +/* must be exported, as it's used by libgcc for various divide functions */ +__attribute__((weak,unused,noreturn,section(".text.nolibc_abort"))) +void abort(void) +{ + sys_kill(sys_getpid(), SIGABRT); + for (;;); +} + static __attribute__((unused)) long atol(const char *s) { -- cgit From 170b230d22e89681ebca1a3d972dca441c8e4be5 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 21 Mar 2022 18:33:07 +0100 Subject: tools/nolibc/stdio: make printf(%s) accept NULL It's often convenient to support this, especially in test programs where a NULL may correspond to an allocation error or a non-existing value. Let's make printf("%s") support being passed a NULL. In this case it prints "(null)" like glibc's printf(). Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdio.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index cb4d3ab3a565..559ebe052a75 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -220,6 +220,8 @@ int vfprintf(FILE *stream, const char *fmt, va_list args) } else if (c == 's') { outstr = va_arg(args, char *); + if (!outstr) + outstr="(null)"; } else if (c == '%') { /* queue it verbatim */ -- cgit From 077d0a392446981cde2e8dd23090140bdd9fb728 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 21 Mar 2022 18:33:08 +0100 Subject: tools/nolibc/stdlib: add a simple getenv() implementation This implementation relies on an extern definition of the environ variable, that the caller must declare and initialize from envp. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 733105c574ee..aca8616335e3 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -60,6 +60,29 @@ int atoi(const char *s) return atol(s); } +/* Tries to find the environment variable named in the environment array + * pointed to by global variable "environ" which must be 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. + */ +static __attribute__((unused)) +char *getenv(const char *name) +{ + extern char **environ; + int idx, i; + + if (environ) { + for (idx = 0; environ[idx]; idx++) { + for (i = 0; name[i] && name[i] == environ[idx][i];) + i++; + if (!name[i] && environ[idx][i] == '=') + return &environ[idx][i+1]; + } + } + return NULL; +} + /* Converts the unsigned long integer to its hex representation into * buffer , which must be long enough to store the number and the * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The -- cgit From bd845a193aae4b99da5215fcfff0e9014b9f7b96 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 21 Mar 2022 18:33:09 +0100 Subject: tools/nolibc/stdio: add support for '%p' to vfprintf() %p remains quite useful in test code, and the code path can easily be merged with the existing "%x" thus only adds ~50 bytes, thus let's add it. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdio.h | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 559ebe052a75..15dedf8d0902 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -163,7 +163,7 @@ char *fgets(char *s, int size, FILE *stream) /* minimal vfprintf(). It supports the following formats: - * - %[l*]{d,u,c,x} + * - %[l*]{d,u,c,x,p} * - %s * - unknown modifiers are ignored. */ @@ -184,8 +184,12 @@ int vfprintf(FILE *stream, const char *fmt, va_list args) if (escape) { /* we're in an escape sequence, ofs == 1 */ escape = 0; - if (c == 'c' || c == 'd' || c == 'u' || c == 'x') { - if (lpref) { + if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') { + char *out = tmpbuf; + + if (c == 'p') + v = va_arg(args, unsigned long); + else if (lpref) { if (lpref > 1) v = va_arg(args, unsigned long long); else @@ -202,18 +206,22 @@ int vfprintf(FILE *stream, const char *fmt, va_list args) } switch (c) { + case 'c': + out[0] = v; + out[1] = 0; + break; case 'd': - i64toa_r(v, tmpbuf); + i64toa_r(v, out); break; case 'u': - u64toa_r(v, tmpbuf); - break; - case 'x': - u64toh_r(v, tmpbuf); + u64toa_r(v, out); break; - default: /* 'c' */ - tmpbuf[0] = v; - tmpbuf[1] = 0; + case 'p': + *(out++) = '0'; + *(out++) = 'x'; + /* fall through */ + default: /* 'x' and 'p' above */ + u64toh_r(v, out); break; } outstr = tmpbuf; -- cgit From 0e7b492943ec8cfdc7fffd9304d496315f781ea7 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 21 Mar 2022 18:33:10 +0100 Subject: tools/nolibc/string: add strcmp() and strncmp() We need these functions all the time, including when checking environment variables and parsing command-line arguments. These implementations were optimized to show optimal code size on a wide range of compilers (22 bytes return included for strcmp(), 33 for strncmp()). Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index 4554b6fcb400..0d5e870c7c0b 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -102,6 +102,17 @@ char *strchr(const char *s, int c) return NULL; } +static __attribute__((unused)) +int strcmp(const char *a, const char *b) +{ + unsigned int c; + int diff; + + while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) + ; + return diff; +} + static __attribute__((unused)) char *strcpy(char *dst, const char *src) { @@ -184,6 +195,18 @@ char *strncat(char *dst, const char *src, size_t size) return orig; } +static __attribute__((unused)) +int strncmp(const char *a, const char *b, size_t size) +{ + unsigned int c; + int diff = 0; + + while (size-- && + !(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) + ; + + return diff; +} static __attribute__((unused)) char *strncpy(char *dst, const char *src, size_t size) -- cgit From 54abe3590fd350afb9cde2398dd3f4ba5bf6d167 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 21 Mar 2022 18:33:11 +0100 Subject: tools/nolibc/sys: add syscall definition for getppid() This is essentially for completeness as it's not the most often used in regtests. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/sys.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 28437863c63f..4d4308d5d111 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -464,6 +464,23 @@ pid_t getpid(void) } +/* + * pid_t getppid(void); + */ + +static __attribute__((unused)) +pid_t sys_getppid(void) +{ + return my_syscall0(__NR_getppid); +} + +static __attribute__((unused)) +pid_t getppid(void) +{ + return sys_getppid(); +} + + /* * pid_t gettid(void); */ -- cgit From 96d2a1313fe00927b33bb0ccbc3e8cd731826f7d Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 21 Mar 2022 18:33:12 +0100 Subject: tools/nolibc/types: add poll() and waitpid() flag definitions - POLLIN etc were missing, so poll() could only be used with timeouts. - WNOHANG was not defined and is convenient to check if a child is still running Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/types.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index e4026e740b56..357e60ad38a8 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -82,6 +82,9 @@ #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define WIFEXITED(status) (((status) & 0x7f) == 0) +/* waitpid() flags */ +#define WNOHANG 1 + /* standard exit() codes */ #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 @@ -122,6 +125,13 @@ typedef struct { } while (0) /* for poll() */ +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 + struct pollfd { int fd; short int events; -- cgit From 24326164687b303e3a7a5b8ef83c0f34c5582b2c Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 21 Mar 2022 18:33:13 +0100 Subject: tools/nolibc: add a makefile to install headers This provides a target "headers_standalone" which installs the nolibc's arch-specific headers with "arch.h" taken from the current arch (or a concatenation of both i386 and x86_64 for arch=x86), then installs kernel headers. This creates a convenient sysroot which is directly usable by a bare-metal compiler to create any executable. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/Makefile | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tools/include/nolibc/Makefile (limited to 'tools/include') diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile new file mode 100644 index 000000000000..7a16d917c185 --- /dev/null +++ b/tools/include/nolibc/Makefile @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for nolibc installation and tests +include ../../scripts/Makefile.include + +# we're in ".../tools/include/nolibc" +ifeq ($(srctree),) +srctree := $(patsubst %/tools/include/,%,$(dir $(CURDIR))) +endif + +nolibc_arch := $(patsubst arm64,aarch64,$(ARCH)) +arch_file := arch-$(nolibc_arch).h +all_files := ctype.h errno.h nolibc.h signal.h std.h stdio.h stdlib.h string.h \ + sys.h time.h types.h unistd.h + +# install all headers needed to support a bare-metal compiler +all: + +# Note: when ARCH is "x86" we concatenate both x86_64 and i386 +headers: + $(Q)mkdir -p $(OUTPUT)sysroot + $(Q)mkdir -p $(OUTPUT)sysroot/include + $(Q)cp $(all_files) $(OUTPUT)sysroot/include/ + $(Q)if [ "$(ARCH)" = "x86" ]; then \ + sed -e \ + 's,^#ifndef _NOLIBC_ARCH_X86_64_H,#if !defined(_NOLIBC_ARCH_X86_64_H) \&\& defined(__x86_64__),' \ + arch-x86_64.h; \ + sed -e \ + 's,^#ifndef _NOLIBC_ARCH_I386_H,#if !defined(_NOLIBC_ARCH_I386_H) \&\& !defined(__x86_64__),' \ + arch-i386.h; \ + elif [ -e "$(arch_file)" ]; then \ + cat $(arch_file); \ + else \ + echo "Fatal: architecture $(ARCH) not yet supported by nolibc." >&2; \ + exit 1; \ + fi > $(OUTPUT)sysroot/include/arch.h + +headers_standalone: headers + $(Q)$(MAKE) -C $(srctree) headers + $(Q)$(MAKE) -C $(srctree) headers_install INSTALL_HDR_PATH=$(OUTPUT)/sysroot + +clean: + $(call QUIET_CLEAN, nolibc) rm -rf "$(OUTPUT)sysroot" -- cgit From 96980b833a21c6dc29d0dfdc8f211fb8a10256a7 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 23 Mar 2022 08:18:06 +0100 Subject: tools/nolibc/string: do not use __builtin_strlen() at -O0 clang wants to use strlen() for __builtin_strlen() at -O0. We don't really care about -O0 but it at least ought to build, so let's make sure we don't choke on this, by dropping the optimizationn for constant strings in this case. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index 0d5e870c7c0b..75a453870498 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -122,7 +122,9 @@ char *strcpy(char *dst, const char *src) return ret; } -/* this function is only used with arguments that are not constants */ +/* this function is only used with arguments that are not constants or when + * it's not known because optimizations are disabled. + */ static __attribute__((unused)) size_t nolibc_strlen(const char *str) { @@ -132,11 +134,18 @@ size_t nolibc_strlen(const char *str) return len; } +/* do not trust __builtin_constant_p() at -O0, as clang will emit a test and + * the two branches, then will rely on an external definition of strlen(). + */ +#if defined(__OPTIMIZE__) #define strlen(str) ({ \ __builtin_constant_p((str)) ? \ __builtin_strlen((str)) : \ nolibc_strlen((str)); \ }) +#else +#define strlen(str) nolibc_strlen((str)) +#endif static __attribute__((unused)) size_t strlcat(char *dst, const char *src, size_t size) -- cgit From 2475d37ac30b8a850d3dd4fcbcb20895928b73fd Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 23 Mar 2022 08:18:07 +0100 Subject: tools/nolibc/stdlib: only reference the external environ when inlined When building with gcc at -O0 we're seeing link errors due to the "environ" variable being referenced by getenv(). The problem is that at -O0 gcc will not inline getenv() and will not drop the external reference. One solution would be to locally declare the variable as weak, but then it would appear in all programs even those not using it, and would be confusing to users of getenv() who would forget to set environ to envp. An alternate approach used in this patch consists in always inlining the outer part of getenv() that references this extern so that it's always dropped when not used. The biggest part of the function was now moved to a new function called _getenv() that's still not inlined by default. Reported-by: Ammar Faizi Signed-off-by: Willy Tarreau Tested-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index aca8616335e3..8a07e263f0d0 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -60,16 +60,17 @@ int atoi(const char *s) return atol(s); } -/* Tries to find the environment variable named in the environment array - * pointed to by global variable "environ" which must be 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() tries to find the environment variable named in the + * environment array pointed to by global variable "environ" which must be + * 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. */ static __attribute__((unused)) -char *getenv(const char *name) +char *_getenv(const char *name, char **environ) { - extern char **environ; int idx, i; if (environ) { @@ -83,6 +84,13 @@ char *getenv(const char *name) return NULL; } +static inline __attribute__((unused,always_inline)) +char *getenv(const char *name) +{ + extern char **environ; + return _getenv(name, environ); +} + /* Converts the unsigned long integer to its hex representation into * buffer , which must be long enough to store the number and the * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The -- cgit From 5312aaa5d567f0dfc11681ad991a78e9da43fe7b Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Tue, 29 Mar 2022 17:17:29 +0700 Subject: tools/nolibc: x86-64: Update System V ABI document link The old link no longer works, update it. Acked-by: Willy Tarreau Signed-off-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-x86_64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index fe517c16cd4d..a7b70ea51b68 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -61,7 +61,7 @@ struct sys_stat_struct { * - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1 * Calling Conventions. * - * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI + * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/home * */ -- cgit From 37d62758e773939636b8fa64a1a39a8a0d3a9f8c Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Tue, 29 Mar 2022 17:17:30 +0700 Subject: tools/nolibc: Replace `asm` with `__asm__` Replace `asm` with `__asm__` to support compilation with -std flag. Using `asm` with -std flag makes GCC think `asm()` is a function call instead of an inline assembly. GCC doc says: For the C language, the `asm` keyword is a GNU extension. When writing C code that can be compiled with `-ansi` and the `-std` options that select C dialects without GNU extensions, use `__asm__` instead of `asm`. Link: https://gcc.gnu.org/onlinedocs/gcc/Basic-Asm.html Reported-by: Alviro Iskandar Setiawan Acked-by: Willy Tarreau Signed-off-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-aarch64.h | 74 ++++++++++++++++++------------------- tools/include/nolibc/arch-arm.h | 58 ++++++++++++++--------------- tools/include/nolibc/arch-i386.h | 56 ++++++++++++++-------------- tools/include/nolibc/arch-mips.h | 62 +++++++++++++++---------------- tools/include/nolibc/arch-riscv.h | 74 ++++++++++++++++++------------------- tools/include/nolibc/arch-x86_64.h | 72 ++++++++++++++++++------------------ 6 files changed, 198 insertions(+), 198 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index 87d9e434820c..b68443f63980 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -64,10 +64,10 @@ struct sys_stat_struct { #define my_syscall0(num) \ ({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0"); \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0"); \ \ - asm volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -78,10 +78,10 @@ struct sys_stat_struct { #define my_syscall1(num, arg1) \ ({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0") = (long)(arg1); \ \ - asm volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), \ @@ -93,11 +93,11 @@ struct sys_stat_struct { #define my_syscall2(num, arg1, arg2) \ ({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ + 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), \ @@ -109,12 +109,12 @@ struct sys_stat_struct { #define my_syscall3(num, arg1, arg2, arg3) \ ({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ - register long _arg3 asm("x2") = (long)(arg3); \ + register long _num __asm__ ("x8") = (num); \ + 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), \ @@ -126,13 +126,13 @@ struct sys_stat_struct { #define my_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ - register long _arg3 asm("x2") = (long)(arg3); \ - register long _arg4 asm("x3") = (long)(arg4); \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0") = (long)(arg1); \ + 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), \ @@ -144,14 +144,14 @@ struct sys_stat_struct { #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ - register long _arg3 asm("x2") = (long)(arg3); \ - register long _arg4 asm("x3") = (long)(arg4); \ - register long _arg5 asm("x4") = (long)(arg5); \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0") = (long)(arg1); \ + register long _arg2 __asm__ ("x1") = (long)(arg2); \ + 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), \ @@ -163,15 +163,15 @@ struct sys_stat_struct { #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ - register long _num asm("x8") = (num); \ - register long _arg1 asm("x0") = (long)(arg1); \ - register long _arg2 asm("x1") = (long)(arg2); \ - register long _arg3 asm("x2") = (long)(arg3); \ - register long _arg4 asm("x3") = (long)(arg4); \ - register long _arg5 asm("x4") = (long)(arg5); \ - register long _arg6 asm("x5") = (long)(arg6); \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0") = (long)(arg1); \ + register long _arg2 __asm__ ("x1") = (long)(arg2); \ + register long _arg3 __asm__ ("x2") = (long)(arg3); \ + 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), \ @@ -182,7 +182,7 @@ struct sys_stat_struct { }) /* startup code */ -asm(".section .text\n" +__asm__ (".section .text\n" ".weak _start\n" ".global _start\n" "_start:\n" diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index 001a3c8c9ad5..55fd9439b2e2 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -77,10 +77,10 @@ struct sys_stat_struct { #define my_syscall0(num) \ ({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0"); \ + register long _num __asm__ ("r7") = (num); \ + register long _arg1 __asm__ ("r0"); \ \ - asm volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -91,10 +91,10 @@ struct sys_stat_struct { #define my_syscall1(num, arg1) \ ({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ + register long _num __asm__ ("r7") = (num); \ + register long _arg1 __asm__ ("r0") = (long)(arg1); \ \ - asm volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), \ @@ -106,11 +106,11 @@ struct sys_stat_struct { #define my_syscall2(num, arg1, arg2) \ ({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ - register long _arg2 asm("r1") = (long)(arg2); \ + register long _num __asm__ ("r7") = (num); \ + register long _arg1 __asm__ ("r0") = (long)(arg1); \ + register long _arg2 __asm__ ("r1") = (long)(arg2); \ \ - asm volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), \ @@ -122,12 +122,12 @@ struct sys_stat_struct { #define my_syscall3(num, arg1, arg2, arg3) \ ({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ - register long _arg2 asm("r1") = (long)(arg2); \ - register long _arg3 asm("r2") = (long)(arg3); \ + register long _num __asm__ ("r7") = (num); \ + 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 ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -139,13 +139,13 @@ struct sys_stat_struct { #define my_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ - register long _arg2 asm("r1") = (long)(arg2); \ - register long _arg3 asm("r2") = (long)(arg3); \ - register long _arg4 asm("r3") = (long)(arg4); \ + register long _num __asm__ ("r7") = (num); \ + register long _arg1 __asm__ ("r0") = (long)(arg1); \ + 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 ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -157,14 +157,14 @@ struct sys_stat_struct { #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ - register long _num asm("r7") = (num); \ - register long _arg1 asm("r0") = (long)(arg1); \ - register long _arg2 asm("r1") = (long)(arg2); \ - register long _arg3 asm("r2") = (long)(arg3); \ - register long _arg4 asm("r3") = (long)(arg4); \ - register long _arg5 asm("r4") = (long)(arg5); \ + register long _num __asm__ ("r7") = (num); \ + register long _arg1 __asm__ ("r0") = (long)(arg1); \ + register long _arg2 __asm__ ("r1") = (long)(arg2); \ + 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 ( \ "svc #0\n" \ : "=r" (_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -175,7 +175,7 @@ struct sys_stat_struct { }) /* startup code */ -asm(".section .text\n" +__asm__ (".section .text\n" ".weak _start\n" ".global _start\n" "_start:\n" diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index d7e4d53325a3..136d5739e456 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -66,9 +66,9 @@ struct sys_stat_struct { #define my_syscall0(num) \ ({ \ long _ret; \ - register long _num asm("eax") = (num); \ + register long _num __asm__ ("eax") = (num); \ \ - asm volatile ( \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "0"(_num) \ @@ -80,10 +80,10 @@ struct sys_stat_struct { #define my_syscall1(num, arg1) \ ({ \ long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ + register long _num __asm__ ("eax") = (num); \ + register long _arg1 __asm__ ("ebx") = (long)(arg1); \ \ - asm volatile ( \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), \ @@ -96,11 +96,11 @@ struct sys_stat_struct { #define my_syscall2(num, arg1, arg2) \ ({ \ long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ - register long _arg2 asm("ecx") = (long)(arg2); \ + 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), \ @@ -113,12 +113,12 @@ struct sys_stat_struct { #define my_syscall3(num, arg1, arg2, arg3) \ ({ \ long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ - register long _arg2 asm("ecx") = (long)(arg2); \ - register long _arg3 asm("edx") = (long)(arg3); \ + register long _num __asm__ ("eax") = (num); \ + 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), \ @@ -131,13 +131,13 @@ struct sys_stat_struct { #define my_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ - register long _arg2 asm("ecx") = (long)(arg2); \ - register long _arg3 asm("edx") = (long)(arg3); \ - register long _arg4 asm("esi") = (long)(arg4); \ + register long _num __asm__ ("eax") = (num); \ + register long _arg1 __asm__ ("ebx") = (long)(arg1); \ + 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), \ @@ -150,14 +150,14 @@ struct sys_stat_struct { #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ long _ret; \ - register long _num asm("eax") = (num); \ - register long _arg1 asm("ebx") = (long)(arg1); \ - register long _arg2 asm("ecx") = (long)(arg2); \ - register long _arg3 asm("edx") = (long)(arg3); \ - register long _arg4 asm("esi") = (long)(arg4); \ - register long _arg5 asm("edi") = (long)(arg5); \ + register long _num __asm__ ("eax") = (num); \ + register long _arg1 __asm__ ("ebx") = (long)(arg1); \ + register long _arg2 __asm__ ("ecx") = (long)(arg2); \ + 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), \ @@ -174,7 +174,7 @@ struct sys_stat_struct { * 2) The deepest stack frame should be set to zero * */ -asm(".section .text\n" +__asm__ (".section .text\n" ".weak _start\n" ".global _start\n" "_start:\n" diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index c9a6aac87c6d..cd587e539d7d 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -69,10 +69,10 @@ struct sys_stat_struct { #define my_syscall0(num) \ ({ \ - register long _num asm("v0") = (num); \ - register long _arg4 asm("a3"); \ + 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" \ @@ -86,11 +86,11 @@ struct sys_stat_struct { #define my_syscall1(num, arg1) \ ({ \ - register long _num asm("v0") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ - register long _arg4 asm("a3"); \ + 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" \ @@ -105,12 +105,12 @@ struct sys_stat_struct { #define my_syscall2(num, arg1, arg2) \ ({ \ - register long _num asm("v0") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ - register long _arg2 asm("a1") = (long)(arg2); \ - register long _arg4 asm("a3"); \ + register long _num __asm__ ("v0") = (num); \ + 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" \ @@ -125,13 +125,13 @@ struct sys_stat_struct { #define my_syscall3(num, arg1, arg2, arg3) \ ({ \ - 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"); \ + 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"); \ \ - asm volatile ( \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ @@ -146,13 +146,13 @@ struct sys_stat_struct { #define my_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ - 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 _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); \ \ - asm volatile ( \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ @@ -167,14 +167,14 @@ struct sys_stat_struct { #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ - 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 _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); \ \ - asm volatile ( \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "sw %7, 16($sp)\n" \ "syscall\n " \ @@ -189,7 +189,7 @@ struct sys_stat_struct { }) /* startup code, note that it's called __start on MIPS */ -asm(".section .text\n" +__asm__ (".section .text\n" ".weak __start\n" ".set nomips16\n" ".global __start\n" diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index bc10b7b5706d..8ec4c05fa69b 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -66,10 +66,10 @@ struct sys_stat_struct { #define my_syscall0(num) \ ({ \ - register long _num asm("a7") = (num); \ - register long _arg1 asm("a0"); \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0"); \ \ - asm volatile ( \ + __asm__ volatile ( \ "ecall\n\t" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -80,10 +80,10 @@ struct sys_stat_struct { #define my_syscall1(num, arg1) \ ({ \ - register long _num asm("a7") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ \ - asm volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_num) \ @@ -94,11 +94,11 @@ struct sys_stat_struct { #define my_syscall2(num, arg1, arg2) \ ({ \ - register long _num asm("a7") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ - register long _arg2 asm("a1") = (long)(arg2); \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ \ - asm volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), \ @@ -110,12 +110,12 @@ struct sys_stat_struct { #define my_syscall3(num, arg1, arg2, arg3) \ ({ \ - register long _num asm("a7") = (num); \ - register long _arg1 asm("a0") = (long)(arg1); \ - register long _arg2 asm("a1") = (long)(arg2); \ - register long _arg3 asm("a2") = (long)(arg3); \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + 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,13 +127,13 @@ struct sys_stat_struct { #define my_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ - register long _num asm("a7") = (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 _num __asm__ ("a7") = (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); \ \ - asm volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -145,14 +145,14 @@ struct sys_stat_struct { #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ - register long _num asm("a7") = (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 asm("a4") = (long)(arg5); \ + register long _num __asm__ ("a7") = (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 __asm__ ("a4") = (long)(arg5); \ \ - asm volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -164,15 +164,15 @@ struct sys_stat_struct { #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ - register long _num asm("a7") = (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 asm("a4") = (long)(arg5); \ - register long _arg6 asm("a5") = (long)(arg6); \ + register long _num __asm__ ("a7") = (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 __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), \ @@ -183,7 +183,7 @@ struct sys_stat_struct { }) /* startup code */ -asm(".section .text\n" +__asm__ (".section .text\n" ".weak _start\n" ".global _start\n" "_start:\n" diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index a7b70ea51b68..490530429ac9 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -68,9 +68,9 @@ struct sys_stat_struct { #define my_syscall0(num) \ ({ \ long _ret; \ - register long _num asm("rax") = (num); \ + register long _num __asm__ ("rax") = (num); \ \ - asm volatile ( \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "0"(_num) \ @@ -82,10 +82,10 @@ struct sys_stat_struct { #define my_syscall1(num, arg1) \ ({ \ long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ + register long _num __asm__ ("rax") = (num); \ + register long _arg1 __asm__ ("rdi") = (long)(arg1); \ \ - asm volatile ( \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), \ @@ -98,11 +98,11 @@ struct sys_stat_struct { #define my_syscall2(num, arg1, arg2) \ ({ \ long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ + 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), \ @@ -115,12 +115,12 @@ struct sys_stat_struct { #define my_syscall3(num, arg1, arg2, arg3) \ ({ \ long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ + register long _num __asm__ ("rax") = (num); \ + 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), \ @@ -133,13 +133,13 @@ struct sys_stat_struct { #define my_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - register long _arg4 asm("r10") = (long)(arg4); \ + register long _num __asm__ ("rax") = (num); \ + register long _arg1 __asm__ ("rdi") = (long)(arg1); \ + 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), \ @@ -152,14 +152,14 @@ struct sys_stat_struct { #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - register long _arg4 asm("r10") = (long)(arg4); \ - register long _arg5 asm("r8") = (long)(arg5); \ + register long _num __asm__ ("rax") = (num); \ + register long _arg1 __asm__ ("rdi") = (long)(arg1); \ + register long _arg2 __asm__ ("rsi") = (long)(arg2); \ + 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), \ @@ -172,15 +172,15 @@ struct sys_stat_struct { #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - register long _arg4 asm("r10") = (long)(arg4); \ - register long _arg5 asm("r8") = (long)(arg5); \ - register long _arg6 asm("r9") = (long)(arg6); \ + register long _num __asm__ ("rax") = (num); \ + register long _arg1 __asm__ ("rdi") = (long)(arg1); \ + register long _arg2 __asm__ ("rsi") = (long)(arg2); \ + register long _arg3 __asm__ ("rdx") = (long)(arg3); \ + 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), \ @@ -197,7 +197,7 @@ struct sys_stat_struct { * 2) The deepest stack frame should be zero (the %rbp). * */ -asm(".section .text\n" +__asm__ (".section .text\n" ".weak _start\n" ".global _start\n" "_start:\n" -- cgit From 1590c59836dace3a20945bad049fe8802c4e6f3f Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Tue, 29 Mar 2022 17:17:31 +0700 Subject: tools/nolibc: Remove .global _start from the entry point code Building with clang yields the following error: ``` :3:1: error: _start changed binding to STB_GLOBAL .global _start ^ 1 error generated. ``` Make sure only specify one between `.global _start` and `.weak _start`. Remove `.global _start`. Cc: llvm@lists.linux.dev Reviewed-by: Nick Desaulniers Acked-by: Willy Tarreau Signed-off-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-aarch64.h | 1 - tools/include/nolibc/arch-arm.h | 1 - tools/include/nolibc/arch-i386.h | 1 - tools/include/nolibc/arch-mips.h | 1 - tools/include/nolibc/arch-riscv.h | 1 - tools/include/nolibc/arch-x86_64.h | 1 - 6 files changed, 6 deletions(-) (limited to 'tools/include') diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index b68443f63980..f68baf8f395f 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -184,7 +184,6 @@ struct sys_stat_struct { /* startup code */ __asm__ (".section .text\n" ".weak _start\n" - ".global _start\n" "_start:\n" "ldr x0, [sp]\n" // argc (x0) was in the stack "add x1, sp, 8\n" // argv (x1) = sp diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index 55fd9439b2e2..f31be8e967d6 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -177,7 +177,6 @@ struct sys_stat_struct { /* startup code */ __asm__ (".section .text\n" ".weak _start\n" - ".global _start\n" "_start:\n" #if defined(__THUMBEB__) || defined(__THUMBEL__) /* We enter here in 32-bit mode but if some previous functions were in diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index 136d5739e456..10aada40680d 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -176,7 +176,6 @@ struct sys_stat_struct { */ __asm__ (".section .text\n" ".weak _start\n" - ".global _start\n" "_start:\n" "pop %eax\n" // argc (first arg, %eax) "mov %esp, %ebx\n" // argv[] (second arg, %ebx) diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index cd587e539d7d..5fc5b8029bff 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -192,7 +192,6 @@ struct sys_stat_struct { __asm__ (".section .text\n" ".weak __start\n" ".set nomips16\n" - ".global __start\n" ".set noreorder\n" ".option pic0\n" ".ent __start\n" diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index 8ec4c05fa69b..95e2b7924925 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -185,7 +185,6 @@ struct sys_stat_struct { /* startup code */ __asm__ (".section .text\n" ".weak _start\n" - ".global _start\n" "_start:\n" ".option push\n" ".option norelax\n" diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index 490530429ac9..0e1e9eb8545d 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -199,7 +199,6 @@ struct sys_stat_struct { */ __asm__ (".section .text\n" ".weak _start\n" - ".global _start\n" "_start:\n" "pop %rdi\n" // argc (first arg, %rdi) "mov %rsp, %rsi\n" // argv[] (second arg, %rsi) -- cgit From f4738ff74c74241c2458269bb6afb64000ec1001 Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Tue, 29 Mar 2022 17:17:32 +0700 Subject: tools/nolibc: i386: Implement syscall with 6 arguments On i386, the 6th argument of syscall goes in %ebp. However, both Clang and GCC cannot use %ebp in the clobber list and in the "r" constraint without using -fomit-frame-pointer. To make it always available for any kind of compilation, the below workaround is implemented. 1) Push the 6-th argument. 2) Push %ebp. 3) Load the 6-th argument from 4(%esp) to %ebp. 4) Do the syscall (int $0x80). 5) Pop %ebp (restore the old value of %ebp). 6) Add %esp by 4 (undo the stack pointer). Cc: x86@kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/lkml/2e335ac54db44f1d8496583d97f9dab0@AcuMS.aculab.com Suggested-by: David Laight Acked-by: Willy Tarreau Signed-off-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-i386.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index 10aada40680d..d7e7212346e2 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -167,6 +167,29 @@ struct sys_stat_struct { _ret; \ }) +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + long _eax = (long)(num); \ + long _arg6 = (long)(arg6); /* Always in memory */ \ + __asm__ volatile ( \ + "pushl %[_arg6]\n\t" \ + "pushl %%ebp\n\t" \ + "movl 4(%%esp),%%ebp\n\t" \ + "int $0x80\n\t" \ + "popl %%ebp\n\t" \ + "addl $4,%%esp\n\t" \ + : "+a"(_eax) /* %eax */ \ + : "b"(arg1), /* %ebx */ \ + "c"(arg2), /* %ecx */ \ + "d"(arg3), /* %edx */ \ + "S"(arg4), /* %esi */ \ + "D"(arg5), /* %edi */ \ + [_arg6]"m"(_arg6) /* memory */ \ + : "memory", "cc" \ + ); \ + _eax; \ +}) + /* startup code */ /* * i386 System V ABI mandates: -- cgit From 544fa1a2d3e61c954ab531f2c790bc79c1745606 Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Tue, 29 Mar 2022 17:17:33 +0700 Subject: tools/nolibc/sys: Implement `mmap()` and `munmap()` Implement mmap() and munmap(). Currently, they are only available for architecures that have my_syscall6 macro. For architectures that don't have, this function will return -1 with errno set to ENOSYS (Function not implemented). This has been tested on x86 and i386. Notes for i386: 1) The common mmap() syscall implementation uses __NR_mmap2 instead of __NR_mmap. 2) The offset must be shifted-right by 12-bit. Acked-by: Willy Tarreau Signed-off-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/sys.h | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 4d4308d5d111..08491070387b 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -14,6 +14,7 @@ #include #include // for SIGCHLD #include +#include #include #include #include @@ -675,6 +676,67 @@ int mknod(const char *path, mode_t mode, dev_t dev) return ret; } +#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 + +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 -ENOSYS; +#else + + int n; + +#if defined(__i386__) + n = __NR_mmap2; + offset >>= 12; +#else + n = __NR_mmap; +#endif + + return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); +#endif +} + +static __attribute__((unused)) +void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) +{ + void *ret = sys_mmap(addr, length, prot, flags, fd, offset); + + if ((unsigned long)ret >= -4095UL) { + SET_ERRNO(-(long)ret); + ret = MAP_FAILED; + } + return ret; +} + +static __attribute__((unused)) +int sys_munmap(void *addr, size_t length) +{ + return my_syscall2(__NR_munmap, addr, 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; +} /* * int mount(const char *source, const char *target, -- cgit From 5a18d07ce3006dbcb3c4cfc7bf1c094a5da19540 Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Tue, 29 Mar 2022 17:17:34 +0700 Subject: tools/nolibc/types: Implement `offsetof()` and `container_of()` macro Implement `offsetof()` and `container_of()` macro. The first use case of these macros is for `malloc()`, `realloc()` and `free()`. Acked-by: Willy Tarreau Signed-off-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/types.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index 357e60ad38a8..959997034e55 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -191,4 +191,15 @@ struct stat { #define major(dev) ((unsigned int)(((dev) >> 8) & 0xfff)) #define minor(dev) ((unsigned int)(((dev) & 0xff)) +#ifndef offsetof +#define offsetof(TYPE, FIELD) ((size_t) &((TYPE *)0)->FIELD) +#endif + +#ifndef container_of +#define container_of(PTR, TYPE, FIELD) ({ \ + __typeof__(((TYPE *)0)->FIELD) *__FIELD_PTR = (PTR); \ + (TYPE *)((char *) __FIELD_PTR - offsetof(TYPE, FIELD)); \ +}) +#endif + #endif /* _NOLIBC_TYPES_H */ -- cgit From 0e0ff638400be8f497a35b51a4751fd823f6bd6a Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Tue, 29 Mar 2022 17:17:35 +0700 Subject: tools/nolibc/stdlib: Implement `malloc()`, `calloc()`, `realloc()` and `free()` Implement basic dynamic allocator functions. These functions are currently only available on architectures that have nolibc mmap() syscall implemented. These are not a super-fast memory allocator, but at least they can satisfy basic needs for having heap without libc. Cc: David Laight Acked-by: Willy Tarreau Signed-off-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdlib.h | 81 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 8a07e263f0d0..8fd32eaf8037 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -11,7 +11,12 @@ #include "arch.h" #include "types.h" #include "sys.h" +#include "string.h" +struct nolibc_heap { + size_t len; + char user_p[] __attribute__((__aligned__)); +}; /* Buffer used to store int-to-ASCII conversions. Will only be implemented if * any of the related functions is implemented. The area is large enough to @@ -60,6 +65,18 @@ int atoi(const char *s) return atol(s); } +static __attribute__((unused)) +void free(void *ptr) +{ + struct nolibc_heap *heap; + + if (!ptr) + return; + + heap = container_of(ptr, struct nolibc_heap, user_p); + munmap(heap, heap->len); +} + /* getenv() tries to find the environment variable named in the * environment array pointed to by global variable "environ" which must be * declared as a char **, and must be terminated by a NULL (it is recommended @@ -91,6 +108,70 @@ char *getenv(const char *name) return _getenv(name, environ); } +static __attribute__((unused)) +void *malloc(size_t len) +{ + struct nolibc_heap *heap; + + /* Always allocate memory with size multiple of 4096. */ + len = sizeof(*heap) + len; + len = (len + 4095UL) & -4096UL; + heap = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, + -1, 0); + if (__builtin_expect(heap == MAP_FAILED, 0)) + return NULL; + + heap->len = len; + return heap->user_p; +} + +static __attribute__((unused)) +void *calloc(size_t size, size_t nmemb) +{ + void *orig; + size_t res = 0; + + if (__builtin_expect(__builtin_mul_overflow(nmemb, size, &res), 0)) { + SET_ERRNO(ENOMEM); + return NULL; + } + + /* + * No need to zero the heap, the MAP_ANONYMOUS in malloc() + * already does it. + */ + return malloc(res); +} + +static __attribute__((unused)) +void *realloc(void *old_ptr, size_t new_size) +{ + struct nolibc_heap *heap; + size_t user_p_len; + void *ret; + + if (!old_ptr) + return malloc(new_size); + + heap = container_of(old_ptr, struct nolibc_heap, user_p); + user_p_len = heap->len - sizeof(*heap); + /* + * Don't realloc() if @user_p_len >= @new_size, this block of + * memory is still enough to handle the @new_size. Just return + * the same pointer. + */ + if (user_p_len >= new_size) + return old_ptr; + + ret = malloc(new_size); + if (__builtin_expect(!ret, 0)) + return NULL; + + memcpy(ret, heap->user_p, heap->len); + munmap(heap, heap->len); + return ret; +} + /* Converts the unsigned long integer to its hex representation into * buffer , which must be long enough to store the number and the * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The -- cgit From b26823c19a12d9a06207ad3051e3d1059a9e1005 Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Tue, 29 Mar 2022 17:17:36 +0700 Subject: tools/nolibc/string: Implement `strnlen()` size_t strnlen(const char *str, size_t maxlen); The strnlen() function returns the number of bytes in the string pointed to by sstr, excluding the terminating null byte ('\0'), but at most maxlen. In doing this, strnlen() looks only at the first maxlen characters in the string pointed to by str and never beyond str[maxlen-1]. The first use case of this function is for determining the memory allocation size in the strndup() function. Link: https://lore.kernel.org/lkml/CAOG64qMpEMh+EkOfjNdAoueC+uQyT2Uv3689_sOr37-JxdJf4g@mail.gmail.com Suggested-by: Alviro Iskandar Setiawan Acked-by: Willy Tarreau Signed-off-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index 75a453870498..f43d52a44d09 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -147,6 +147,15 @@ size_t nolibc_strlen(const char *str) #define strlen(str) nolibc_strlen((str)) #endif +static __attribute__((unused)) +size_t strnlen(const char *str, size_t maxlen) +{ + size_t len; + + for (len = 0; (len < maxlen) && str[len]; len++); + return len; +} + static __attribute__((unused)) size_t strlcat(char *dst, const char *src, size_t size) { -- cgit From 11dbdaeff41d9ec9376476889651fac4838bff99 Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Tue, 29 Mar 2022 17:17:37 +0700 Subject: tools/nolibc/string: Implement `strdup()` and `strndup()` These functions are currently only available on architectures that have my_syscall6() macro implemented. Since these functions use malloc(), malloc() uses mmap(), mmap() depends on my_syscall6() macro. On architectures that don't support my_syscall6(), these function will always return NULL with errno set to ENOSYS. Acked-by: Willy Tarreau Signed-off-by: Ammar Faizi Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'tools/include') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index f43d52a44d09..bef35bee9c44 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -9,6 +9,8 @@ #include "std.h" +static void *malloc(size_t len); + /* * As much as possible, please keep functions alphabetically sorted. */ @@ -156,6 +158,36 @@ size_t strnlen(const char *str, size_t maxlen) return len; } +static __attribute__((unused)) +char *strdup(const char *str) +{ + size_t len; + char *ret; + + len = strlen(str); + ret = malloc(len + 1); + if (__builtin_expect(ret != NULL, 1)) + memcpy(ret, str, len + 1); + + return ret; +} + +static __attribute__((unused)) +char *strndup(const char *str, size_t maxlen) +{ + size_t len; + char *ret; + + len = strnlen(str, maxlen); + ret = malloc(len + 1); + if (__builtin_expect(ret != NULL, 1)) { + memcpy(ret, str, len); + ret[len] = '\0'; + } + + return ret; +} + static __attribute__((unused)) size_t strlcat(char *dst, const char *src, size_t size) { -- cgit From 03f16cd020eb8bb2eb837e2090086f296a9fa91d Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Mon, 18 Apr 2022 09:50:36 -0700 Subject: objtool: Add CONFIG_OBJTOOL Now that stack validation is an optional feature of objtool, add CONFIG_OBJTOOL and replace most usages of CONFIG_STACK_VALIDATION with it. CONFIG_STACK_VALIDATION can now be considered to be frame-pointer specific. CONFIG_UNWINDER_ORC is already inherently valid for live patching, so no need to "validate" it. Signed-off-by: Josh Poimboeuf Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Miroslav Benes Link: https://lkml.kernel.org/r/939bf3d85604b2a126412bf11af6e3bd3b872bcb.1650300597.git.jpoimboe@redhat.com --- Makefile | 2 +- arch/Kconfig | 8 ++++++-- arch/x86/Kconfig | 18 +++++++++++------- arch/x86/Kconfig.debug | 2 +- arch/x86/include/asm/jump_label.h | 6 +++--- arch/x86/kernel/alternative.c | 6 +++--- include/linux/compiler.h | 6 +++--- include/linux/instrumentation.h | 6 +++--- include/linux/objtool.h | 6 +++--- kernel/trace/Kconfig | 1 + lib/Kconfig.debug | 20 +++++++++++--------- lib/Kconfig.kcsan | 3 ++- lib/Kconfig.ubsan | 2 +- scripts/Makefile.build | 4 ++-- scripts/link-vmlinux.sh | 32 ++++++++++++++++++-------------- scripts/package/builddeb | 2 +- tools/include/linux/objtool.h | 6 +++--- 17 files changed, 73 insertions(+), 57 deletions(-) (limited to 'tools/include') diff --git a/Makefile b/Makefile index fa5112a0ec1b..250707647359 100644 --- a/Makefile +++ b/Makefile @@ -1302,7 +1302,7 @@ install: sub_make_done := # --------------------------------------------------------------------------- # Tools -ifdef CONFIG_STACK_VALIDATION +ifdef CONFIG_OBJTOOL prepare: tools/objtool endif diff --git a/arch/Kconfig b/arch/Kconfig index 29b0167c088b..04cdef16db24 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1028,11 +1028,14 @@ config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT depends on MMU select ARCH_HAS_ELF_RANDOMIZE +config HAVE_OBJTOOL + bool + config HAVE_STACK_VALIDATION bool help - Architecture supports the 'objtool check' host tool command, which - performs compile-time stack metadata validation. + Architecture supports objtool compile-time frame pointer rule + validation. config HAVE_RELIABLE_STACKTRACE bool @@ -1302,6 +1305,7 @@ config HAVE_STATIC_CALL config HAVE_STATIC_CALL_INLINE bool depends on HAVE_STATIC_CALL + select OBJTOOL config HAVE_PREEMPT_DYNAMIC bool diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4bed3abf444d..43e26ee1611e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -188,7 +188,7 @@ config X86 select HAVE_CONTEXT_TRACKING if X86_64 select HAVE_CONTEXT_TRACKING_OFFSTACK if HAVE_CONTEXT_TRACKING select HAVE_C_RECORDMCOUNT - select HAVE_OBJTOOL_MCOUNT if STACK_VALIDATION + select HAVE_OBJTOOL_MCOUNT if HAVE_OBJTOOL select HAVE_BUILDTIME_MCOUNT_SORT select HAVE_DEBUG_KMEMLEAK select HAVE_DMA_CONTIGUOUS @@ -231,6 +231,7 @@ config X86 select HAVE_MOVE_PMD select HAVE_MOVE_PUD select HAVE_NMI + select HAVE_OBJTOOL if X86_64 select HAVE_OPTPROBES select HAVE_PCSPKR_PLATFORM select HAVE_PERF_EVENTS @@ -239,17 +240,17 @@ config X86 select HAVE_PCI select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP - select MMU_GATHER_RCU_TABLE_FREE if PARAVIRT + select MMU_GATHER_RCU_TABLE_FREE if PARAVIRT select HAVE_POSIX_CPU_TIMERS_TASK_WORK select HAVE_REGS_AND_STACK_ACCESS_API - select HAVE_RELIABLE_STACKTRACE if X86_64 && (UNWINDER_FRAME_POINTER || UNWINDER_ORC) && STACK_VALIDATION + select HAVE_RELIABLE_STACKTRACE if UNWINDER_ORC || STACK_VALIDATION select HAVE_FUNCTION_ARG_ACCESS_API select HAVE_SETUP_PER_CPU_AREA select HAVE_SOFTIRQ_ON_OWN_STACK select HAVE_STACKPROTECTOR if CC_HAS_SANE_STACKPROTECTOR - select HAVE_STACK_VALIDATION if X86_64 + select HAVE_STACK_VALIDATION if HAVE_OBJTOOL select HAVE_STATIC_CALL - select HAVE_STATIC_CALL_INLINE if HAVE_STACK_VALIDATION + select HAVE_STATIC_CALL_INLINE if HAVE_OBJTOOL select HAVE_PREEMPT_DYNAMIC_CALL select HAVE_RSEQ select HAVE_SYSCALL_TRACEPOINTS @@ -268,7 +269,6 @@ config X86 select RTC_MC146818_LIB select SPARSE_IRQ select SRCU - select STACK_VALIDATION if HAVE_STACK_VALIDATION && (HAVE_STATIC_CALL_INLINE || RETPOLINE) select SYSCTL_EXCEPTION_TRACE select THREAD_INFO_IN_TASK select TRACE_IRQFLAGS_SUPPORT @@ -459,6 +459,7 @@ config GOLDFISH config RETPOLINE bool "Avoid speculative indirect branches in kernel" + select OBJTOOL if HAVE_OBJTOOL default y help Compile kernel with the retpoline compiler options to guard against @@ -472,6 +473,7 @@ config CC_HAS_SLS config SLS bool "Mitigate Straight-Line-Speculation" depends on CC_HAS_SLS && X86_64 + select OBJTOOL if HAVE_OBJTOOL default n help Compile the kernel with straight-line-speculation options to guard @@ -1819,6 +1821,7 @@ config ARCH_RANDOM config X86_SMAP def_bool y prompt "Supervisor Mode Access Prevention" if EXPERT + select OBJTOOL if HAVE_OBJTOOL help Supervisor Mode Access Prevention (SMAP) is a security feature in newer Intel processors. There is a small @@ -1855,9 +1858,10 @@ config CC_HAS_IBT config X86_KERNEL_IBT prompt "Indirect Branch Tracking" bool - depends on X86_64 && CC_HAS_IBT && STACK_VALIDATION + depends on X86_64 && CC_HAS_IBT && HAVE_OBJTOOL # https://github.com/llvm/llvm-project/commit/9d7001eba9c4cb311e03cd8cdc231f9e579f2d0f depends on !LD_IS_LLD || LLD_VERSION >= 140000 + select OBJTOOL help Build the kernel with support for Indirect Branch Tracking, a hardware support course-grain forward-edge Control Flow Integrity diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index d3a6f74a94bd..d872a7522e55 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -237,7 +237,7 @@ choice config UNWINDER_ORC bool "ORC unwinder" depends on X86_64 - select STACK_VALIDATION + select OBJTOOL help This option enables the ORC (Oops Rewind Capability) unwinder for unwinding kernel stack traces. It uses a custom data format which is diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index 0449b125d27f..3ce0e67c579c 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -20,7 +20,7 @@ _ASM_PTR "%c0 + %c1 - .\n\t" \ ".popsection \n\t" -#ifdef CONFIG_STACK_VALIDATION +#ifdef CONFIG_OBJTOOL static __always_inline bool arch_static_branch(struct static_key *key, bool branch) { @@ -34,7 +34,7 @@ l_yes: return true; } -#else +#else /* !CONFIG_OBJTOOL */ static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) { @@ -48,7 +48,7 @@ l_yes: return true; } -#endif /* STACK_VALIDATION */ +#endif /* CONFIG_OBJTOOL */ static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch) { diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index d374cb3cf024..3c66073e7645 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -338,7 +338,7 @@ next: } } -#if defined(CONFIG_RETPOLINE) && defined(CONFIG_STACK_VALIDATION) +#if defined(CONFIG_RETPOLINE) && defined(CONFIG_OBJTOOL) /* * CALL/JMP *%\reg @@ -507,11 +507,11 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) } } -#else /* !RETPOLINES || !CONFIG_STACK_VALIDATION */ +#else /* !CONFIG_RETPOLINE || !CONFIG_OBJTOOL */ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) { } -#endif /* CONFIG_RETPOLINE && CONFIG_STACK_VALIDATION */ +#endif /* CONFIG_RETPOLINE && CONFIG_OBJTOOL */ #ifdef CONFIG_X86_KERNEL_IBT diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 219aa5ddbc73..01ce94b58b42 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -109,7 +109,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, #endif /* Unreachable code */ -#ifdef CONFIG_STACK_VALIDATION +#ifdef CONFIG_OBJTOOL /* * These macros help objtool understand GCC code flow for unreachable code. * The __COUNTER__ based labels are a hack to make each instance of the macros @@ -128,10 +128,10 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, /* Annotate a C jump table to allow objtool to follow the code flow */ #define __annotate_jump_table __section(".rodata..c_jump_table") -#else +#else /* !CONFIG_OBJTOOL */ #define annotate_unreachable() #define __annotate_jump_table -#endif +#endif /* CONFIG_OBJTOOL */ #ifndef unreachable # define unreachable() do { \ diff --git a/include/linux/instrumentation.h b/include/linux/instrumentation.h index 24359b4a9605..9111a3704072 100644 --- a/include/linux/instrumentation.h +++ b/include/linux/instrumentation.h @@ -2,7 +2,7 @@ #ifndef __LINUX_INSTRUMENTATION_H #define __LINUX_INSTRUMENTATION_H -#if defined(CONFIG_DEBUG_ENTRY) && defined(CONFIG_STACK_VALIDATION) +#ifdef CONFIG_VMLINUX_VALIDATION #include @@ -53,9 +53,9 @@ ".popsection\n\t" : : "i" (c)); \ }) #define instrumentation_end() __instrumentation_end(__COUNTER__) -#else +#else /* !CONFIG_VMLINUX_VALIDATION */ # define instrumentation_begin() do { } while(0) # define instrumentation_end() do { } while(0) -#endif +#endif /* CONFIG_VMLINUX_VALIDATION */ #endif /* __LINUX_INSTRUMENTATION_H */ diff --git a/include/linux/objtool.h b/include/linux/objtool.h index 586d35720f13..977d90ba642d 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -38,7 +38,7 @@ struct unwind_hint { #define UNWIND_HINT_TYPE_REGS_PARTIAL 2 #define UNWIND_HINT_TYPE_FUNC 3 -#ifdef CONFIG_STACK_VALIDATION +#ifdef CONFIG_OBJTOOL #ifndef __ASSEMBLY__ @@ -157,7 +157,7 @@ struct unwind_hint { #endif /* __ASSEMBLY__ */ -#else /* !CONFIG_STACK_VALIDATION */ +#else /* !CONFIG_OBJTOOL */ #ifndef __ASSEMBLY__ @@ -179,6 +179,6 @@ struct unwind_hint { .endm #endif -#endif /* CONFIG_STACK_VALIDATION */ +#endif /* CONFIG_OBJTOOL */ #endif /* _LINUX_OBJTOOL_H */ diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 2c43e327a619..2956bc277150 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -728,6 +728,7 @@ config FTRACE_MCOUNT_USE_OBJTOOL depends on !FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY depends on !FTRACE_MCOUNT_USE_CC depends on FTRACE_MCOUNT_RECORD + select OBJTOOL config FTRACE_MCOUNT_USE_RECORDMCOUNT def_bool y diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 075cd25363ac..c0e4e47f3ce3 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -485,24 +485,25 @@ config FRAME_POINTER larger and slower, but it gives very useful debugging information in case of kernel bugs. (precise oopses/stacktraces/warnings) +config OBJTOOL + bool + config STACK_VALIDATION bool "Compile-time stack metadata validation" - depends on HAVE_STACK_VALIDATION + depends on HAVE_STACK_VALIDATION && UNWINDER_FRAME_POINTER + select OBJTOOL default n help - Add compile-time checks to validate stack metadata, including frame - pointers (if CONFIG_FRAME_POINTER is enabled). This helps ensure - that runtime stack traces are more reliable. - - This is also a prerequisite for generation of ORC unwind data, which - is needed for CONFIG_UNWINDER_ORC. + Validate frame pointer rules at compile-time. This helps ensure that + runtime stack traces are more reliable. For more information, see tools/objtool/Documentation/stack-validation.txt. config VMLINUX_VALIDATION bool - depends on STACK_VALIDATION && DEBUG_ENTRY + depends on HAVE_OBJTOOL && DEBUG_ENTRY + select OBJTOOL default y config VMLINUX_MAP @@ -2035,10 +2036,11 @@ config KCOV bool "Code coverage for fuzzing" depends on ARCH_HAS_KCOV depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS - depends on !ARCH_WANTS_NO_INSTR || STACK_VALIDATION || \ + depends on !ARCH_WANTS_NO_INSTR || HAVE_OBJTOOL || \ GCC_VERSION >= 120000 || CLANG_VERSION >= 130000 select DEBUG_FS select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC + select OBJTOOL if HAVE_OBJTOOL help KCOV exposes kernel code coverage information in a form suitable for coverage-guided fuzzing (randomized testing). diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan index de022445fbba..901c3b509aca 100644 --- a/lib/Kconfig.kcsan +++ b/lib/Kconfig.kcsan @@ -187,7 +187,8 @@ config KCSAN_WEAK_MEMORY # We can either let objtool nop __tsan_func_{entry,exit}() and builtin # atomics instrumentation in .noinstr.text, or use a compiler that can # implement __no_kcsan to really remove all instrumentation. - depends on STACK_VALIDATION || CC_IS_GCC || CLANG_VERSION >= 140000 + depends on HAVE_OBJTOOL || CC_IS_GCC || CLANG_VERSION >= 140000 + select OBJTOOL if HAVE_OBJTOOL help Enable support for modeling a subset of weak memory, which allows detecting a subset of data races due to missing memory barriers. diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan index f3c57ed51838..c4fe15d38b60 100644 --- a/lib/Kconfig.ubsan +++ b/lib/Kconfig.ubsan @@ -94,7 +94,7 @@ config UBSAN_UNREACHABLE bool "Perform checking for unreachable code" # objtool already handles unreachable checking and gets angry about # seeing UBSan instrumentation located in unreachable places. - depends on !STACK_VALIDATION + depends on !(OBJTOOL && (STACK_VALIDATION || UNWINDER_ORC || X86_SMAP)) depends on $(cc-option,-fsanitize=unreachable) help This option enables -fsanitize=unreachable which checks for control diff --git a/scripts/Makefile.build b/scripts/Makefile.build index d5e15ae29156..0f73e02b7cf1 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -222,7 +222,7 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), $(sub_cmd_record_mcount)) endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT -ifdef CONFIG_STACK_VALIDATION +ifdef CONFIG_OBJTOOL objtool := $(objtree)/tools/objtool/objtool @@ -241,7 +241,7 @@ objtool_args = \ cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd) -endif # CONFIG_STACK_VALIDATION +endif # CONFIG_OBJTOOL ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 0140bfa32c0c..5101a7fbfaaf 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -108,8 +108,11 @@ objtool_link() local objtoolcmd; local objtoolopt; - if is_enabled CONFIG_STACK_VALIDATION && \ - ( is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT ); then + if ! is_enabled CONFIG_OBJTOOL; then + return; + fi + + if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then # Don't perform vmlinux validation unless explicitly requested, # but run objtool on vmlinux.o now that we have an object file. @@ -126,10 +129,23 @@ objtool_link() objtoolopt="${objtoolopt} --orc" fi + if is_enabled CONFIG_RETPOLINE; then + objtoolopt="${objtoolopt} --retpoline" + fi + + if is_enabled CONFIG_SLS; then + objtoolopt="${objtoolopt} --sls" + fi + if is_enabled CONFIG_STACK_VALIDATION; then objtoolopt="${objtoolopt} --stackval" fi + if is_enabled CONFIG_X86_SMAP; then + objtoolopt="${objtoolopt} --uaccess" + fi + + objtoolopt="${objtoolopt} --lto" fi @@ -139,18 +155,6 @@ objtool_link() if [ -n "${objtoolopt}" ]; then - if is_enabled CONFIG_RETPOLINE; then - objtoolopt="${objtoolopt} --retpoline" - fi - - if is_enabled CONFIG_SLS; then - objtoolopt="${objtoolopt} --sls" - fi - - if is_enabled CONFIG_X86_SMAP; then - objtoolopt="${objtoolopt} --uaccess" - fi - if ! is_enabled CONFIG_FRAME_POINTER; then objtoolopt="${objtoolopt} --no-fp" fi diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 91a502bb97e8..67cd420dcf89 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -67,7 +67,7 @@ deploy_kernel_headers () { ) > debian/hdrsrcfiles { - if is_enabled CONFIG_STACK_VALIDATION; then + if is_enabled CONFIG_OBJTOOL; then echo tools/objtool/objtool fi diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h index 586d35720f13..977d90ba642d 100644 --- a/tools/include/linux/objtool.h +++ b/tools/include/linux/objtool.h @@ -38,7 +38,7 @@ struct unwind_hint { #define UNWIND_HINT_TYPE_REGS_PARTIAL 2 #define UNWIND_HINT_TYPE_FUNC 3 -#ifdef CONFIG_STACK_VALIDATION +#ifdef CONFIG_OBJTOOL #ifndef __ASSEMBLY__ @@ -157,7 +157,7 @@ struct unwind_hint { #endif /* __ASSEMBLY__ */ -#else /* !CONFIG_STACK_VALIDATION */ +#else /* !CONFIG_OBJTOOL */ #ifndef __ASSEMBLY__ @@ -179,6 +179,6 @@ struct unwind_hint { .endm #endif -#endif /* CONFIG_STACK_VALIDATION */ +#endif /* CONFIG_OBJTOOL */ #endif /* _LINUX_OBJTOOL_H */ -- cgit From b9663a6ff8289a095d56d9a3a3f9c185a7b7b0d7 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Fri, 22 Apr 2022 13:20:21 -0400 Subject: tools: Add kmem_cache_alloc_lru() Turn kmem_cache_alloc() into a wrapper around kmem_cache_alloc_lru(). Fixes: 9bbdc0f32409 ("xarray: use kmem_cache_alloc_lru to allocate xa_node") Signed-off-by: Matthew Wilcox (Oracle) Reported-by: Liam R. Howlett Reported-by: Li Wang --- tools/include/linux/slab.h | 8 +++++++- tools/testing/radix-tree/linux.c | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/tools/include/linux/slab.h b/tools/include/linux/slab.h index f41d8a0eb1a4..0616409513eb 100644 --- a/tools/include/linux/slab.h +++ b/tools/include/linux/slab.h @@ -28,7 +28,13 @@ static inline void *kzalloc(size_t size, gfp_t gfp) return kmalloc(size, gfp | __GFP_ZERO); } -void *kmem_cache_alloc(struct kmem_cache *cachep, int flags); +struct list_lru; + +void *kmem_cache_alloc_lru(struct kmem_cache *cachep, struct list_lru *, int flags); +static inline void *kmem_cache_alloc(struct kmem_cache *cachep, int flags) +{ + return kmem_cache_alloc_lru(cachep, NULL, flags); +} void kmem_cache_free(struct kmem_cache *cachep, void *objp); struct kmem_cache *kmem_cache_create(const char *name, unsigned int size, diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c index 81539f543954..d5c1bcba86fe 100644 --- a/tools/testing/radix-tree/linux.c +++ b/tools/testing/radix-tree/linux.c @@ -25,7 +25,8 @@ struct kmem_cache { void (*ctor)(void *); }; -void *kmem_cache_alloc(struct kmem_cache *cachep, int gfp) +void *kmem_cache_alloc_lru(struct kmem_cache *cachep, struct list_lru *lru, + int gfp) { void *p; -- cgit From c0a5a21c25f37c9fd7b36072f9968cdff1e4aa13 Mon Sep 17 00:00:00 2001 From: Kumar Kartikeya Dwivedi Date: Mon, 25 Apr 2022 03:18:51 +0530 Subject: bpf: Allow storing referenced kptr in map Extending the code in previous commits, introduce referenced kptr support, which needs to be tagged using 'kptr_ref' tag instead. Unlike unreferenced kptr, referenced kptr have a lot more restrictions. In addition to the type matching, only a newly introduced bpf_kptr_xchg helper is allowed to modify the map value at that offset. This transfers the referenced pointer being stored into the map, releasing the references state for the program, and returning the old value and creating new reference state for the returned pointer. Similar to unreferenced pointer case, return value for this case will also be PTR_TO_BTF_ID_OR_NULL. The reference for the returned pointer must either be eventually released by calling the corresponding release function, otherwise it must be transferred into another map. It is also allowed to call bpf_kptr_xchg with a NULL pointer, to clear the value, and obtain the old value if any. BPF_LDX, BPF_STX, and BPF_ST cannot access referenced kptr. A future commit will permit using BPF_LDX for such pointers, but attempt at making it safe, since the lifetime of object won't be guaranteed. There are valid reasons to enforce the restriction of permitting only bpf_kptr_xchg to operate on referenced kptr. The pointer value must be consistent in face of concurrent modification, and any prior values contained in the map must also be released before a new one is moved into the map. To ensure proper transfer of this ownership, bpf_kptr_xchg returns the old value, which the verifier would require the user to either free or move into another map, and releases the reference held for the pointer being moved in. In the future, direct BPF_XCHG instruction may also be permitted to work like bpf_kptr_xchg helper. Note that process_kptr_func doesn't have to call check_helper_mem_access, since we already disallow rdonly/wronly flags for map, which is what check_map_access_type checks, and we already ensure the PTR_TO_MAP_VALUE refers to kptr by obtaining its off_desc, so check_map_access is also not required. Signed-off-by: Kumar Kartikeya Dwivedi Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20220424214901.2743946-4-memxor@gmail.com --- include/linux/bpf.h | 8 ++++ include/uapi/linux/bpf.h | 12 ++++++ kernel/bpf/btf.c | 10 ++++- kernel/bpf/helpers.c | 24 +++++++++++ kernel/bpf/verifier.c | 98 ++++++++++++++++++++++++++++++++++++------ tools/include/uapi/linux/bpf.h | 12 ++++++ 6 files changed, 151 insertions(+), 13 deletions(-) (limited to 'tools/include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 492edd2c5713..24310837bafc 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -160,8 +160,14 @@ enum { BPF_MAP_VALUE_OFF_MAX = 8, }; +enum bpf_kptr_type { + BPF_KPTR_UNREF, + BPF_KPTR_REF, +}; + struct bpf_map_value_off_desc { u32 offset; + enum bpf_kptr_type type; struct { struct btf *btf; u32 btf_id; @@ -418,6 +424,7 @@ enum bpf_arg_type { ARG_PTR_TO_STACK, /* pointer to stack */ ARG_PTR_TO_CONST_STR, /* pointer to a null terminated read-only string */ ARG_PTR_TO_TIMER, /* pointer to bpf_timer */ + ARG_PTR_TO_KPTR, /* pointer to referenced kptr */ __BPF_ARG_TYPE_MAX, /* Extended arg_types. */ @@ -427,6 +434,7 @@ enum bpf_arg_type { ARG_PTR_TO_SOCKET_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_SOCKET, ARG_PTR_TO_ALLOC_MEM_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_ALLOC_MEM, ARG_PTR_TO_STACK_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_STACK, + ARG_PTR_TO_BTF_ID_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_BTF_ID, /* This must be the last entry. Its purpose is to ensure the enum is * wide enough to hold the higher bits reserved for bpf_type_flag. diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index d14b10b85e51..444fe6f1cf35 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5143,6 +5143,17 @@ union bpf_attr { * The **hash_algo** is returned on success, * **-EOPNOTSUP** if the hash calculation failed or **-EINVAL** if * invalid arguments are passed. + * + * void *bpf_kptr_xchg(void *map_value, void *ptr) + * Description + * Exchange kptr at pointer *map_value* with *ptr*, and return the + * old value. *ptr* can be NULL, otherwise it must be a referenced + * pointer which will be released when this helper is called. + * Return + * The old value of kptr (which can be NULL). The returned pointer + * if not NULL, is a reference which must be released using its + * corresponding release function, or moved into a BPF map before + * program exit. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5339,6 +5350,7 @@ union bpf_attr { FN(copy_from_user_task), \ FN(skb_set_tstamp), \ FN(ima_file_hash), \ + FN(kptr_xchg), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index f0287342204f..4138c51728dd 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -3177,6 +3177,7 @@ enum { struct btf_field_info { u32 type_id; u32 off; + enum bpf_kptr_type type; }; static int btf_find_struct(const struct btf *btf, const struct btf_type *t, @@ -3193,6 +3194,7 @@ static int btf_find_struct(const struct btf *btf, const struct btf_type *t, static int btf_find_kptr(const struct btf *btf, const struct btf_type *t, u32 off, int sz, struct btf_field_info *info) { + enum bpf_kptr_type type; u32 res_id; /* For PTR, sz is always == 8 */ @@ -3205,7 +3207,11 @@ static int btf_find_kptr(const struct btf *btf, const struct btf_type *t, /* Reject extra tags */ if (btf_type_is_type_tag(btf_type_by_id(btf, t->type))) return -EINVAL; - if (strcmp("kptr", __btf_name_by_offset(btf, t->name_off))) + if (!strcmp("kptr", __btf_name_by_offset(btf, t->name_off))) + type = BPF_KPTR_UNREF; + else if (!strcmp("kptr_ref", __btf_name_by_offset(btf, t->name_off))) + type = BPF_KPTR_REF; + else return -EINVAL; /* Get the base type */ @@ -3216,6 +3222,7 @@ static int btf_find_kptr(const struct btf *btf, const struct btf_type *t, info->type_id = res_id; info->off = off; + info->type = type; return BTF_FIELD_FOUND; } @@ -3420,6 +3427,7 @@ struct bpf_map_value_off *btf_parse_kptrs(const struct btf *btf, } tab->off[i].offset = info_arr[i].off; + tab->off[i].type = info_arr[i].type; tab->off[i].kptr.btf_id = id; tab->off[i].kptr.btf = kernel_btf; } diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 315053ef6a75..3e709fed5306 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1374,6 +1374,28 @@ out: kfree(t); } +BPF_CALL_2(bpf_kptr_xchg, void *, map_value, void *, ptr) +{ + unsigned long *kptr = map_value; + + return xchg(kptr, (unsigned long)ptr); +} + +/* Unlike other PTR_TO_BTF_ID helpers the btf_id in bpf_kptr_xchg() + * helper is determined dynamically by the verifier. + */ +#define BPF_PTR_POISON ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA)) + +const struct bpf_func_proto bpf_kptr_xchg_proto = { + .func = bpf_kptr_xchg, + .gpl_only = false, + .ret_type = RET_PTR_TO_BTF_ID_OR_NULL, + .ret_btf_id = BPF_PTR_POISON, + .arg1_type = ARG_PTR_TO_KPTR, + .arg2_type = ARG_PTR_TO_BTF_ID_OR_NULL | OBJ_RELEASE, + .arg2_btf_id = BPF_PTR_POISON, +}; + const struct bpf_func_proto bpf_get_current_task_proto __weak; const struct bpf_func_proto bpf_get_current_task_btf_proto __weak; const struct bpf_func_proto bpf_probe_read_user_proto __weak; @@ -1452,6 +1474,8 @@ bpf_base_func_proto(enum bpf_func_id func_id) return &bpf_timer_start_proto; case BPF_FUNC_timer_cancel: return &bpf_timer_cancel_proto; + case BPF_FUNC_kptr_xchg: + return &bpf_kptr_xchg_proto; default: break; } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5426bab7f02c..c9ee44efed89 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -258,6 +258,7 @@ struct bpf_call_arg_meta { struct btf *ret_btf; u32 ret_btf_id; u32 subprogno; + struct bpf_map_value_off_desc *kptr_off_desc; }; struct btf *btf_vmlinux; @@ -489,7 +490,8 @@ static bool is_acquire_function(enum bpf_func_id func_id, if (func_id == BPF_FUNC_sk_lookup_tcp || func_id == BPF_FUNC_sk_lookup_udp || func_id == BPF_FUNC_skc_lookup_tcp || - func_id == BPF_FUNC_ringbuf_reserve) + func_id == BPF_FUNC_ringbuf_reserve || + func_id == BPF_FUNC_kptr_xchg) return true; if (func_id == BPF_FUNC_map_lookup_elem && @@ -3514,6 +3516,12 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, /* We need to verify reg->type and reg->btf, before accessing reg->btf */ reg_name = kernel_type_name(reg->btf, reg->btf_id); + /* For ref_ptr case, release function check should ensure we get one + * referenced PTR_TO_BTF_ID, and that its fixed offset is 0. For the + * normal store of unreferenced kptr, we must ensure var_off is zero. + * Since ref_ptr cannot be accessed directly by BPF insns, checks for + * reg->off and reg->ref_obj_id are not needed here. + */ if (__check_ptr_off_reg(env, reg, regno, true)) return -EACCES; @@ -3569,6 +3577,12 @@ static int check_map_kptr_access(struct bpf_verifier_env *env, u32 regno, return -EACCES; } + /* We cannot directly access kptr_ref */ + if (off_desc->type == BPF_KPTR_REF) { + verbose(env, "accessing referenced kptr disallowed\n"); + return -EACCES; + } + if (class == BPF_LDX) { val_reg = reg_state(env, value_regno); /* We can simply mark the value_regno receiving the pointer @@ -5293,6 +5307,53 @@ static int process_timer_func(struct bpf_verifier_env *env, int regno, return 0; } +static int process_kptr_func(struct bpf_verifier_env *env, int regno, + struct bpf_call_arg_meta *meta) +{ + struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; + struct bpf_map_value_off_desc *off_desc; + struct bpf_map *map_ptr = reg->map_ptr; + u32 kptr_off; + int ret; + + if (!tnum_is_const(reg->var_off)) { + verbose(env, + "R%d doesn't have constant offset. kptr has to be at the constant offset\n", + regno); + return -EINVAL; + } + if (!map_ptr->btf) { + verbose(env, "map '%s' has to have BTF in order to use bpf_kptr_xchg\n", + map_ptr->name); + return -EINVAL; + } + if (!map_value_has_kptrs(map_ptr)) { + ret = PTR_ERR(map_ptr->kptr_off_tab); + if (ret == -E2BIG) + verbose(env, "map '%s' has more than %d kptr\n", map_ptr->name, + BPF_MAP_VALUE_OFF_MAX); + else if (ret == -EEXIST) + verbose(env, "map '%s' has repeating kptr BTF tags\n", map_ptr->name); + else + verbose(env, "map '%s' has no valid kptr\n", map_ptr->name); + return -EINVAL; + } + + meta->map_ptr = map_ptr; + kptr_off = reg->off + reg->var_off.value; + off_desc = bpf_map_kptr_off_contains(map_ptr, kptr_off); + if (!off_desc) { + verbose(env, "off=%d doesn't point to kptr\n", kptr_off); + return -EACCES; + } + if (off_desc->type != BPF_KPTR_REF) { + verbose(env, "off=%d kptr isn't referenced kptr\n", kptr_off); + return -EACCES; + } + meta->kptr_off_desc = off_desc; + return 0; +} + static bool arg_type_is_mem_ptr(enum bpf_arg_type type) { return base_type(type) == ARG_PTR_TO_MEM || @@ -5433,6 +5494,7 @@ static const struct bpf_reg_types func_ptr_types = { .types = { PTR_TO_FUNC } }; static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK } }; static const struct bpf_reg_types const_str_ptr_types = { .types = { PTR_TO_MAP_VALUE } }; static const struct bpf_reg_types timer_types = { .types = { PTR_TO_MAP_VALUE } }; +static const struct bpf_reg_types kptr_types = { .types = { PTR_TO_MAP_VALUE } }; static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_PTR_TO_MAP_KEY] = &map_key_value_types, @@ -5460,11 +5522,13 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_PTR_TO_STACK] = &stack_ptr_types, [ARG_PTR_TO_CONST_STR] = &const_str_ptr_types, [ARG_PTR_TO_TIMER] = &timer_types, + [ARG_PTR_TO_KPTR] = &kptr_types, }; static int check_reg_type(struct bpf_verifier_env *env, u32 regno, enum bpf_arg_type arg_type, - const u32 *arg_btf_id) + const u32 *arg_btf_id, + struct bpf_call_arg_meta *meta) { struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; enum bpf_reg_type expected, type = reg->type; @@ -5517,8 +5581,11 @@ found: arg_btf_id = compatible->btf_id; } - if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id, reg->off, - btf_vmlinux, *arg_btf_id)) { + if (meta->func_id == BPF_FUNC_kptr_xchg) { + if (map_kptr_match_type(env, meta->kptr_off_desc, reg, regno)) + return -EACCES; + } else if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id, reg->off, + btf_vmlinux, *arg_btf_id)) { verbose(env, "R%d is of type %s but %s is expected\n", regno, kernel_type_name(reg->btf, reg->btf_id), kernel_type_name(btf_vmlinux, *arg_btf_id)); @@ -5625,7 +5692,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, */ goto skip_type_check; - err = check_reg_type(env, regno, arg_type, fn->arg_btf_id[arg]); + err = check_reg_type(env, regno, arg_type, fn->arg_btf_id[arg], meta); if (err) return err; @@ -5801,6 +5868,9 @@ skip_type_check: verbose(env, "string is not zero-terminated\n"); return -EINVAL; } + } else if (arg_type == ARG_PTR_TO_KPTR) { + if (process_kptr_func(env, regno, meta)) + return -EACCES; } return err; @@ -6143,10 +6213,10 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn) int i; for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) { - if (fn->arg_type[i] == ARG_PTR_TO_BTF_ID && !fn->arg_btf_id[i]) + if (base_type(fn->arg_type[i]) == ARG_PTR_TO_BTF_ID && !fn->arg_btf_id[i]) return false; - if (fn->arg_type[i] != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i]) + if (base_type(fn->arg_type[i]) != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i]) return false; } @@ -7012,21 +7082,25 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn regs[BPF_REG_0].btf_id = meta.ret_btf_id; } } else if (base_type(ret_type) == RET_PTR_TO_BTF_ID) { + struct btf *ret_btf; int ret_btf_id; mark_reg_known_zero(env, regs, BPF_REG_0); regs[BPF_REG_0].type = PTR_TO_BTF_ID | ret_flag; - ret_btf_id = *fn->ret_btf_id; + if (func_id == BPF_FUNC_kptr_xchg) { + ret_btf = meta.kptr_off_desc->kptr.btf; + ret_btf_id = meta.kptr_off_desc->kptr.btf_id; + } else { + ret_btf = btf_vmlinux; + ret_btf_id = *fn->ret_btf_id; + } if (ret_btf_id == 0) { verbose(env, "invalid return type %u of func %s#%d\n", base_type(ret_type), func_id_name(func_id), func_id); return -EINVAL; } - /* current BPF helper definitions are only coming from - * built-in code with type IDs from vmlinux BTF - */ - regs[BPF_REG_0].btf = btf_vmlinux; + regs[BPF_REG_0].btf = ret_btf; regs[BPF_REG_0].btf_id = ret_btf_id; } else { verbose(env, "unknown return type %u of func %s#%d\n", diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index d14b10b85e51..444fe6f1cf35 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5143,6 +5143,17 @@ union bpf_attr { * The **hash_algo** is returned on success, * **-EOPNOTSUP** if the hash calculation failed or **-EINVAL** if * invalid arguments are passed. + * + * void *bpf_kptr_xchg(void *map_value, void *ptr) + * Description + * Exchange kptr at pointer *map_value* with *ptr*, and return the + * old value. *ptr* can be NULL, otherwise it must be a referenced + * pointer which will be released when this helper is called. + * Return + * The old value of kptr (which can be NULL). The returned pointer + * if not NULL, is a reference which must be released using its + * corresponding release function, or moved into a BPF map before + * program exit. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5339,6 +5350,7 @@ union bpf_attr { FN(copy_from_user_task), \ FN(skb_set_tstamp), \ FN(ima_file_hash), \ + FN(kptr_xchg), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From 9f79b8b7233942e9c4b071f1f331f17e7282bbfa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 5 Apr 2022 15:12:55 +0800 Subject: uapi: simplify __ARCH_FLOCK{,64}_PAD a little Don't bother to define the symbols empty, just don't use them. That makes the intent a little more clear. Remove the unused HAVE_ARCH_STRUCT_FLOCK64 define and merge the 32-bit mips struct flock into the generic one. Add a new __ARCH_FLOCK_EXTRA_SYSID macro following the style of __ARCH_FLOCK_PAD to avoid having a separate definition just for one architecture. Signed-off-by: Christoph Hellwig Signed-off-by: Guo Ren Reviewed-by: Arnd Bergmann Tested-by: Heiko Stuebner Link: https://lore.kernel.org/r/20220405071314.3225832-2-guoren@kernel.org Signed-off-by: Palmer Dabbelt --- arch/mips/include/uapi/asm/fcntl.h | 26 +++----------------------- include/uapi/asm-generic/fcntl.h | 19 +++++++------------ tools/include/uapi/asm-generic/fcntl.h | 19 +++++++------------ 3 files changed, 17 insertions(+), 47 deletions(-) (limited to 'tools/include') diff --git a/arch/mips/include/uapi/asm/fcntl.h b/arch/mips/include/uapi/asm/fcntl.h index 42e13dead543..9e44ac810db9 100644 --- a/arch/mips/include/uapi/asm/fcntl.h +++ b/arch/mips/include/uapi/asm/fcntl.h @@ -50,30 +50,10 @@ #define F_SETLKW64 35 #endif -/* - * The flavours of struct flock. "struct flock" is the ABI compliant - * variant. Finally struct flock64 is the LFS variant of struct flock. As - * a historic accident and inconsistence with the ABI definition it doesn't - * contain all the same fields as struct flock. - */ - #if _MIPS_SIM != _MIPS_SIM_ABI64 - -#include - -struct flock { - short l_type; - short l_whence; - __kernel_off_t l_start; - __kernel_off_t l_len; - long l_sysid; - __kernel_pid_t l_pid; - long pad[4]; -}; - -#define HAVE_ARCH_STRUCT_FLOCK - -#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ +#define __ARCH_FLOCK_EXTRA_SYSID long l_sysid; +#define __ARCH_FLOCK_PAD long pad[4]; +#endif #include diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index ecd0f5bdfc1d..77aa9f2ff98d 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -192,25 +192,19 @@ struct f_owner_ex { #define F_LINUX_SPECIFIC_BASE 1024 -#ifndef HAVE_ARCH_STRUCT_FLOCK -#ifndef __ARCH_FLOCK_PAD -#define __ARCH_FLOCK_PAD -#endif - struct flock { short l_type; short l_whence; __kernel_off_t l_start; __kernel_off_t l_len; __kernel_pid_t l_pid; - __ARCH_FLOCK_PAD -}; +#ifdef __ARCH_FLOCK_EXTRA_SYSID + __ARCH_FLOCK_EXTRA_SYSID #endif - -#ifndef HAVE_ARCH_STRUCT_FLOCK64 -#ifndef __ARCH_FLOCK64_PAD -#define __ARCH_FLOCK64_PAD +#ifdef __ARCH_FLOCK_PAD + __ARCH_FLOCK_PAD #endif +}; struct flock64 { short l_type; @@ -218,8 +212,9 @@ struct flock64 { __kernel_loff_t l_start; __kernel_loff_t l_len; __kernel_pid_t l_pid; +#ifdef __ARCH_FLOCK64_PAD __ARCH_FLOCK64_PAD -}; #endif +}; #endif /* _ASM_GENERIC_FCNTL_H */ diff --git a/tools/include/uapi/asm-generic/fcntl.h b/tools/include/uapi/asm-generic/fcntl.h index ac190958c981..99bc9b15ce2b 100644 --- a/tools/include/uapi/asm-generic/fcntl.h +++ b/tools/include/uapi/asm-generic/fcntl.h @@ -187,25 +187,19 @@ struct f_owner_ex { #define F_LINUX_SPECIFIC_BASE 1024 -#ifndef HAVE_ARCH_STRUCT_FLOCK -#ifndef __ARCH_FLOCK_PAD -#define __ARCH_FLOCK_PAD -#endif - struct flock { short l_type; short l_whence; __kernel_off_t l_start; __kernel_off_t l_len; __kernel_pid_t l_pid; - __ARCH_FLOCK_PAD -}; +#ifdef __ARCH_FLOCK_EXTRA_SYSID + __ARCH_FLOCK_EXTRA_SYSID #endif - -#ifndef HAVE_ARCH_STRUCT_FLOCK64 -#ifndef __ARCH_FLOCK64_PAD -#define __ARCH_FLOCK64_PAD +#ifdef __ARCH_FLOCK_PAD + __ARCH_FLOCK_PAD #endif +}; struct flock64 { short l_type; @@ -213,8 +207,9 @@ struct flock64 { __kernel_loff_t l_start; __kernel_loff_t l_len; __kernel_pid_t l_pid; +#ifdef __ARCH_FLOCK64_PAD __ARCH_FLOCK64_PAD -}; #endif +}; #endif /* _ASM_GENERIC_FCNTL_H */ -- cgit From 306f7cc1e9061313c46d19e9bdffc819880794c1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 5 Apr 2022 15:12:56 +0800 Subject: uapi: always define F_GETLK64/F_SETLK64/F_SETLKW64 in fcntl.h The F_GETLK64/F_SETLK64/F_SETLKW64 fcntl opcodes are only implemented for the 32-bit syscall APIs, but are also needed for compat handling on 64-bit kernels. Consolidate them in unistd.h instead of definining the internal compat definitions in compat.h, which is rather error prone (e.g. parisc gets the values wrong currently). Note that before this change they were never visible to userspace due to the fact that CONFIG_64BIT is only set for kernel builds. Signed-off-by: Christoph Hellwig Signed-off-by: Guo Ren Reviewed-by: Arnd Bergmann Tested-by: Heiko Stuebner Link: https://lore.kernel.org/r/20220405071314.3225832-3-guoren@kernel.org Signed-off-by: Palmer Dabbelt --- arch/arm64/include/asm/compat.h | 4 ---- arch/mips/include/asm/compat.h | 4 ---- arch/mips/include/uapi/asm/fcntl.h | 4 ++-- arch/powerpc/include/asm/compat.h | 4 ---- arch/s390/include/asm/compat.h | 4 ---- arch/sparc/include/asm/compat.h | 4 ---- arch/x86/include/asm/compat.h | 4 ---- include/uapi/asm-generic/fcntl.h | 4 ++-- tools/include/uapi/asm-generic/fcntl.h | 2 -- 9 files changed, 4 insertions(+), 30 deletions(-) (limited to 'tools/include') diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index eaa6ca062d89..276328765408 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -73,10 +73,6 @@ struct compat_flock { compat_pid_t l_pid; }; -#define F_GETLK64 12 /* using 'struct flock64' */ -#define F_SETLK64 13 -#define F_SETLKW64 14 - struct compat_flock64 { short l_type; short l_whence; diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h index bbb3bc5a42fd..6a350c1f70d7 100644 --- a/arch/mips/include/asm/compat.h +++ b/arch/mips/include/asm/compat.h @@ -65,10 +65,6 @@ struct compat_flock { s32 pad[4]; }; -#define F_GETLK64 33 -#define F_SETLK64 34 -#define F_SETLKW64 35 - struct compat_flock64 { short l_type; short l_whence; diff --git a/arch/mips/include/uapi/asm/fcntl.h b/arch/mips/include/uapi/asm/fcntl.h index 9e44ac810db9..0369a38e3d4f 100644 --- a/arch/mips/include/uapi/asm/fcntl.h +++ b/arch/mips/include/uapi/asm/fcntl.h @@ -44,11 +44,11 @@ #define F_SETOWN 24 /* for sockets. */ #define F_GETOWN 23 /* for sockets. */ -#ifndef __mips64 +#if __BITS_PER_LONG == 32 || defined(__KERNEL__) #define F_GETLK64 33 /* using 'struct flock64' */ #define F_SETLK64 34 #define F_SETLKW64 35 -#endif +#endif /* __BITS_PER_LONG == 32 || defined(__KERNEL__) */ #if _MIPS_SIM != _MIPS_SIM_ABI64 #define __ARCH_FLOCK_EXTRA_SYSID long l_sysid; diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index 7afc96fb6524..83d8f70779cb 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -52,10 +52,6 @@ struct compat_flock { compat_pid_t l_pid; }; -#define F_GETLK64 12 /* using 'struct flock64' */ -#define F_SETLK64 13 -#define F_SETLKW64 14 - struct compat_flock64 { short l_type; short l_whence; diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index cdc7ae72529d..0f14b3188b1b 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -110,10 +110,6 @@ struct compat_flock { compat_pid_t l_pid; }; -#define F_GETLK64 12 -#define F_SETLK64 13 -#define F_SETLKW64 14 - struct compat_flock64 { short l_type; short l_whence; diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h index bd949fcf9d63..108078751bb5 100644 --- a/arch/sparc/include/asm/compat.h +++ b/arch/sparc/include/asm/compat.h @@ -84,10 +84,6 @@ struct compat_flock { short __unused; }; -#define F_GETLK64 12 -#define F_SETLK64 13 -#define F_SETLKW64 14 - struct compat_flock64 { short l_type; short l_whence; diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index 7516e4199b3c..8d19a212f4f2 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -58,10 +58,6 @@ struct compat_flock { compat_pid_t l_pid; }; -#define F_GETLK64 12 /* using 'struct flock64' */ -#define F_SETLK64 13 -#define F_SETLKW64 14 - /* * IA32 uses 4 byte alignment for 64 bit quantities, * so we need to pack this structure. diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 77aa9f2ff98d..f13d37b60775 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -116,13 +116,13 @@ #define F_GETSIG 11 /* for sockets. */ #endif -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG == 32 || defined(__KERNEL__) #ifndef F_GETLK64 #define F_GETLK64 12 /* using 'struct flock64' */ #define F_SETLK64 13 #define F_SETLKW64 14 #endif -#endif +#endif /* __BITS_PER_LONG == 32 || defined(__KERNEL__) */ #ifndef F_SETOWN_EX #define F_SETOWN_EX 15 diff --git a/tools/include/uapi/asm-generic/fcntl.h b/tools/include/uapi/asm-generic/fcntl.h index 99bc9b15ce2b..0197042b7dfb 100644 --- a/tools/include/uapi/asm-generic/fcntl.h +++ b/tools/include/uapi/asm-generic/fcntl.h @@ -115,13 +115,11 @@ #define F_GETSIG 11 /* for sockets. */ #endif -#ifndef CONFIG_64BIT #ifndef F_GETLK64 #define F_GETLK64 12 /* using 'struct flock64' */ #define F_SETLK64 13 #define F_SETLKW64 14 #endif -#endif #ifndef F_SETOWN_EX #define F_SETOWN_EX 15 -- cgit From c86d2cad193a5c7f9b92467955bb7fb6642b9e80 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 5 Apr 2022 15:13:01 +0800 Subject: syscalls: compat: Fix the missing part for __SYSCALL_COMPAT Make "uapi asm unistd.h" could be used for architectures' COMPAT mode. The __SYSCALL_COMPAT is first used in riscv. Signed-off-by: Guo Ren Signed-off-by: Guo Ren Reviewed-by: Arnd Bergmann Reviewed-by: Christoph Hellwig Tested-by: Heiko Stuebner Link: https://lore.kernel.org/r/20220405071314.3225832-8-guoren@kernel.org Signed-off-by: Palmer Dabbelt --- include/uapi/asm-generic/unistd.h | 4 ++-- tools/include/uapi/asm-generic/unistd.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/include') diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 1c48b0ae3ba3..45fa180cc56a 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -383,7 +383,7 @@ __SYSCALL(__NR_syslog, sys_syslog) /* kernel/ptrace.c */ #define __NR_ptrace 117 -__SYSCALL(__NR_ptrace, sys_ptrace) +__SC_COMP(__NR_ptrace, sys_ptrace, compat_sys_ptrace) /* kernel/sched/core.c */ #define __NR_sched_setparam 118 @@ -779,7 +779,7 @@ __SYSCALL(__NR_rseq, sys_rseq) #define __NR_kexec_file_load 294 __SYSCALL(__NR_kexec_file_load, sys_kexec_file_load) /* 295 through 402 are unassigned to sync up with generic numbers, don't use */ -#if __BITS_PER_LONG == 32 +#if defined(__SYSCALL_COMPAT) || __BITS_PER_LONG == 32 #define __NR_clock_gettime64 403 __SYSCALL(__NR_clock_gettime64, sys_clock_gettime) #define __NR_clock_settime64 404 diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index 1c48b0ae3ba3..45fa180cc56a 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h @@ -383,7 +383,7 @@ __SYSCALL(__NR_syslog, sys_syslog) /* kernel/ptrace.c */ #define __NR_ptrace 117 -__SYSCALL(__NR_ptrace, sys_ptrace) +__SC_COMP(__NR_ptrace, sys_ptrace, compat_sys_ptrace) /* kernel/sched/core.c */ #define __NR_sched_setparam 118 @@ -779,7 +779,7 @@ __SYSCALL(__NR_rseq, sys_rseq) #define __NR_kexec_file_load 294 __SYSCALL(__NR_kexec_file_load, sys_kexec_file_load) /* 295 through 402 are unassigned to sync up with generic numbers, don't use */ -#if __BITS_PER_LONG == 32 +#if defined(__SYSCALL_COMPAT) || __BITS_PER_LONG == 32 #define __NR_clock_gettime64 403 __SYSCALL(__NR_clock_gettime64, sys_clock_gettime) #define __NR_clock_settime64 404 -- cgit From 6fd1d51cfa253b5ee7dae18d7cf1df830e9b6137 Mon Sep 17 00:00:00 2001 From: Erin MacNeil Date: Wed, 27 Apr 2022 16:02:37 -0400 Subject: net: SO_RCVMARK socket option for SO_MARK with recvmsg() Adding a new socket option, SO_RCVMARK, to indicate that SO_MARK should be included in the ancillary data returned by recvmsg(). Renamed the sock_recv_ts_and_drops() function to sock_recv_cmsgs(). Signed-off-by: Erin MacNeil Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Acked-by: Marc Kleine-Budde Link: https://lore.kernel.org/r/20220427200259.2564-1-lnx.erin@gmail.com Signed-off-by: Jakub Kicinski --- arch/alpha/include/uapi/asm/socket.h | 2 ++ arch/mips/include/uapi/asm/socket.h | 2 ++ arch/parisc/include/uapi/asm/socket.h | 2 ++ arch/sparc/include/uapi/asm/socket.h | 1 + include/net/sock.h | 18 ++++++++++-------- include/uapi/asm-generic/socket.h | 2 ++ net/atm/common.c | 2 +- net/bluetooth/af_bluetooth.c | 4 ++-- net/can/bcm.c | 2 +- net/can/j1939/socket.c | 2 +- net/can/raw.c | 2 +- net/core/sock.c | 7 +++++++ net/ieee802154/socket.c | 4 ++-- net/ipv4/raw.c | 2 +- net/ipv4/udp.c | 2 +- net/ipv6/raw.c | 2 +- net/ipv6/udp.c | 2 +- net/key/af_key.c | 2 +- net/mctp/af_mctp.c | 2 +- net/packet/af_packet.c | 2 +- net/sctp/socket.c | 2 +- net/socket.c | 15 ++++++++++++--- tools/include/uapi/asm-generic/socket.h | 2 ++ 23 files changed, 56 insertions(+), 27 deletions(-) (limited to 'tools/include') diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h index 7d81535893af..739891b94136 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -135,6 +135,8 @@ #define SO_TXREHASH 74 +#define SO_RCVMARK 75 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h index 1d55e57b8466..18f3d95ecfec 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -146,6 +146,8 @@ #define SO_TXREHASH 74 +#define SO_RCVMARK 75 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h index 654061e0964e..f486d3dfb6bb 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -127,6 +127,8 @@ #define SO_TXREHASH 0x4048 +#define SO_RCVMARK 0x4049 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h index 666f81e617ea..2fda57a3ea86 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -128,6 +128,7 @@ #define SO_TXREHASH 0x0053 +#define SO_RCVMARK 0x0054 #if !defined(__KERNEL__) diff --git a/include/net/sock.h b/include/net/sock.h index f9f8ecae0f8d..663041b92c21 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -893,6 +893,7 @@ enum sock_flags { SOCK_TXTIME, SOCK_XDP, /* XDP is attached */ SOCK_TSTAMP_NEW, /* Indicates 64 bit timestamps always */ + SOCK_RCVMARK, /* Receive SO_MARK ancillary data with packet */ }; #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) @@ -2647,20 +2648,21 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) __sock_recv_wifi_status(msg, sk, skb); } -void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb); +void __sock_recv_cmsgs(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb); #define SK_DEFAULT_STAMP (-1L * NSEC_PER_SEC) -static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb) +static inline void sock_recv_cmsgs(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb) { -#define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL) | \ - (1UL << SOCK_RCVTSTAMP)) +#define FLAGS_RECV_CMSGS ((1UL << SOCK_RXQ_OVFL) | \ + (1UL << SOCK_RCVTSTAMP) | \ + (1UL << SOCK_RCVMARK)) #define TSFLAGS_ANY (SOF_TIMESTAMPING_SOFTWARE | \ SOF_TIMESTAMPING_RAW_HARDWARE) - if (sk->sk_flags & FLAGS_TS_OR_DROPS || sk->sk_tsflags & TSFLAGS_ANY) - __sock_recv_ts_and_drops(msg, sk, skb); + if (sk->sk_flags & FLAGS_RECV_CMSGS || sk->sk_tsflags & TSFLAGS_ANY) + __sock_recv_cmsgs(msg, sk, skb); else if (unlikely(sock_flag(sk, SOCK_TIMESTAMP))) sock_write_timestamp(sk, skb->tstamp); else if (unlikely(sk->sk_stamp == SK_DEFAULT_STAMP)) diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h index 467ca2f28760..638230899e98 100644 --- a/include/uapi/asm-generic/socket.h +++ b/include/uapi/asm-generic/socket.h @@ -130,6 +130,8 @@ #define SO_TXREHASH 74 +#define SO_RCVMARK 75 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) diff --git a/net/atm/common.c b/net/atm/common.c index d0c8ab7ff8f6..f7019df41c3e 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -553,7 +553,7 @@ int vcc_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, error = skb_copy_datagram_msg(skb, 0, msg, copied); if (error) return error; - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (!(flags & MSG_PEEK)) { pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc), diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 62705734343b..b506409bb498 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -280,7 +280,7 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, skb_reset_transport_header(skb); err = skb_copy_datagram_msg(skb, 0, msg, copied); if (err == 0) { - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (msg->msg_name && bt_sk(sk)->skb_msg_name) bt_sk(sk)->skb_msg_name(skb, msg->msg_name, @@ -384,7 +384,7 @@ int bt_sock_stream_recvmsg(struct socket *sock, struct msghdr *msg, copied += chunk; size -= chunk; - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (!(flags & MSG_PEEK)) { int skb_len = skb_headlen(skb); diff --git a/net/can/bcm.c b/net/can/bcm.c index 64c07e650bb4..65ee1b784a30 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1647,7 +1647,7 @@ static int bcm_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, return err; } - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (msg->msg_name) { __sockaddr_check_size(BCM_MIN_NAMELEN); diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index 0bb4fd3f6264..f5ecfdcf57b2 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -841,7 +841,7 @@ static int j1939_sk_recvmsg(struct socket *sock, struct msghdr *msg, paddr->can_addr.j1939.pgn = skcb->addr.pgn; } - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); msg->msg_flags |= skcb->msg_flags; skb_free_datagram(sk, skb); diff --git a/net/can/raw.c b/net/can/raw.c index 0cf728dcff36..b7dbb57557f3 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -866,7 +866,7 @@ static int raw_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, return err; } - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (msg->msg_name) { __sockaddr_check_size(RAW_MIN_NAMELEN); diff --git a/net/core/sock.c b/net/core/sock.c index a0f3989de3d6..770408fd935f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1311,6 +1311,9 @@ set_sndbuf: __sock_set_mark(sk, val); break; + case SO_RCVMARK: + sock_valbool_flag(sk, SOCK_RCVMARK, valbool); + break; case SO_RXQ_OVFL: sock_valbool_flag(sk, SOCK_RXQ_OVFL, valbool); @@ -1737,6 +1740,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = sk->sk_mark; break; + case SO_RCVMARK: + v.val = sock_flag(sk, SOCK_RCVMARK); + break; + case SO_RXQ_OVFL: v.val = sock_flag(sk, SOCK_RXQ_OVFL); break; diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c index f24852814fa3..718fb77bb372 100644 --- a/net/ieee802154/socket.c +++ b/net/ieee802154/socket.c @@ -328,7 +328,7 @@ static int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, if (err) goto done; - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (flags & MSG_TRUNC) copied = skb->len; @@ -718,7 +718,7 @@ static int dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, if (err) goto done; - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (saddr) { /* Clear the implicit padding in struct sockaddr_ieee802154 diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 4056b0da85ea..bbd717805b10 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -783,7 +783,7 @@ static int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, if (err) goto done; - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); /* Copy the address. */ if (sin) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index aa8545ca6964..9d5071c79c95 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1909,7 +1909,7 @@ try_again: UDP_INC_STATS(sock_net(sk), UDP_MIB_INDATAGRAMS, is_udplite); - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); /* Copy the address. */ if (sin) { diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 0d7c13d33d1a..3b7cbd522b54 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -512,7 +512,7 @@ static int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, *addr_len = sizeof(*sin6); } - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (np->rxopt.all) ip6_datagram_recv_ctl(sk, msg, skb); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 688af6f809fe..3fc97d4621ac 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -391,7 +391,7 @@ try_again: if (!peeking) SNMP_INC_STATS(mib, UDP_MIB_INDATAGRAMS); - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); /* Copy the address. */ if (msg->msg_name) { diff --git a/net/key/af_key.c b/net/key/af_key.c index d09ec26b1081..175a162eec58 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3711,7 +3711,7 @@ static int pfkey_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, if (err) goto out_free; - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); err = (flags & MSG_TRUNC) ? skb->len : copied; diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c index 221863afc4b1..c2fc2a7b2528 100644 --- a/net/mctp/af_mctp.c +++ b/net/mctp/af_mctp.c @@ -238,7 +238,7 @@ static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, if (rc < 0) goto out_free; - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (addr) { struct mctp_skb_cb *cb = mctp_cb(skb); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index fd31334cf688..677f9cfa9660 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3477,7 +3477,7 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, sll->sll_protocol = skb->protocol; } - sock_recv_ts_and_drops(msg, sk, skb); + sock_recv_cmsgs(msg, sk, skb); if (msg->msg_name) { const size_t max_len = min(sizeof(skb->cb), diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 3e3fe923bed5..6d37d2dfb3da 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2128,7 +2128,7 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, head_skb = event->chunk->head_skb; else head_skb = skb; - sock_recv_ts_and_drops(msg, sk, head_skb); + sock_recv_cmsgs(msg, sk, head_skb); if (sctp_ulpevent_is_notification(event)) { msg->msg_flags |= MSG_NOTIFICATION; sp->pf->event_msgname(event, msg->msg_name, addr_len); diff --git a/net/socket.c b/net/socket.c index 6887840682bb..f0c39c874665 100644 --- a/net/socket.c +++ b/net/socket.c @@ -930,13 +930,22 @@ static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, sizeof(__u32), &SOCK_SKB_CB(skb)->dropcount); } -void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb) +static void sock_recv_mark(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb) +{ + if (sock_flag(sk, SOCK_RCVMARK) && skb) + put_cmsg(msg, SOL_SOCKET, SO_MARK, sizeof(__u32), + &skb->mark); +} + +void __sock_recv_cmsgs(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb) { sock_recv_timestamp(msg, sk, skb); sock_recv_drops(msg, sk, skb); + sock_recv_mark(msg, sk, skb); } -EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops); +EXPORT_SYMBOL_GPL(__sock_recv_cmsgs); INDIRECT_CALLABLE_DECLARE(int inet_recvmsg(struct socket *, struct msghdr *, size_t, int)); diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h index 77f7c1638eb1..8756df13be50 100644 --- a/tools/include/uapi/asm-generic/socket.h +++ b/tools/include/uapi/asm-generic/socket.h @@ -119,6 +119,8 @@ #define SO_DETACH_REUSEPORT_BPF 68 +#define SO_RCVMARK 75 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) -- cgit From ea733263949646700977feeb662a92703f514351 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Mon, 2 May 2022 23:38:51 +0000 Subject: tools: Import ARM SMCCC definitions Import the standard SMCCC definitions from include/linux/arm-smccc.h. Signed-off-by: Raghavendra Rao Ananta Reviewed-by: Gavin Shan Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220502233853.1233742-8-rananta@google.com --- tools/include/linux/arm-smccc.h | 193 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 tools/include/linux/arm-smccc.h (limited to 'tools/include') diff --git a/tools/include/linux/arm-smccc.h b/tools/include/linux/arm-smccc.h new file mode 100644 index 000000000000..63ce9bebccd3 --- /dev/null +++ b/tools/include/linux/arm-smccc.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015, Linaro Limited + */ +#ifndef __LINUX_ARM_SMCCC_H +#define __LINUX_ARM_SMCCC_H + +#include + +/* + * This file provides common defines for ARM SMC Calling Convention as + * specified in + * https://developer.arm.com/docs/den0028/latest + * + * This code is up-to-date with version DEN 0028 C + */ + +#define ARM_SMCCC_STD_CALL _AC(0,U) +#define ARM_SMCCC_FAST_CALL _AC(1,U) +#define ARM_SMCCC_TYPE_SHIFT 31 + +#define ARM_SMCCC_SMC_32 0 +#define ARM_SMCCC_SMC_64 1 +#define ARM_SMCCC_CALL_CONV_SHIFT 30 + +#define ARM_SMCCC_OWNER_MASK 0x3F +#define ARM_SMCCC_OWNER_SHIFT 24 + +#define ARM_SMCCC_FUNC_MASK 0xFFFF + +#define ARM_SMCCC_IS_FAST_CALL(smc_val) \ + ((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT)) +#define ARM_SMCCC_IS_64(smc_val) \ + ((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT)) +#define ARM_SMCCC_FUNC_NUM(smc_val) ((smc_val) & ARM_SMCCC_FUNC_MASK) +#define ARM_SMCCC_OWNER_NUM(smc_val) \ + (((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK) + +#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \ + (((type) << ARM_SMCCC_TYPE_SHIFT) | \ + ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \ + (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \ + ((func_num) & ARM_SMCCC_FUNC_MASK)) + +#define ARM_SMCCC_OWNER_ARCH 0 +#define ARM_SMCCC_OWNER_CPU 1 +#define ARM_SMCCC_OWNER_SIP 2 +#define ARM_SMCCC_OWNER_OEM 3 +#define ARM_SMCCC_OWNER_STANDARD 4 +#define ARM_SMCCC_OWNER_STANDARD_HYP 5 +#define ARM_SMCCC_OWNER_VENDOR_HYP 6 +#define ARM_SMCCC_OWNER_TRUSTED_APP 48 +#define ARM_SMCCC_OWNER_TRUSTED_APP_END 49 +#define ARM_SMCCC_OWNER_TRUSTED_OS 50 +#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63 + +#define ARM_SMCCC_FUNC_QUERY_CALL_UID 0xff01 + +#define ARM_SMCCC_QUIRK_NONE 0 +#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */ + +#define ARM_SMCCC_VERSION_1_0 0x10000 +#define ARM_SMCCC_VERSION_1_1 0x10001 +#define ARM_SMCCC_VERSION_1_2 0x10002 +#define ARM_SMCCC_VERSION_1_3 0x10003 + +#define ARM_SMCCC_1_3_SVE_HINT 0x10000 + +#define ARM_SMCCC_VERSION_FUNC_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 0) + +#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 1) + +#define ARM_SMCCC_ARCH_SOC_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 2) + +#define ARM_SMCCC_ARCH_WORKAROUND_1 \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 0x8000) + +#define ARM_SMCCC_ARCH_WORKAROUND_2 \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 0x7fff) + +#define ARM_SMCCC_ARCH_WORKAROUND_3 \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 0x3fff) + +#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_VENDOR_HYP, \ + ARM_SMCCC_FUNC_QUERY_CALL_UID) + +/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */ +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 0xb66fb428U +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 0xe911c52eU +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2 0x564bcaa9U +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3 0x743a004dU + +/* KVM "vendor specific" services */ +#define ARM_SMCCC_KVM_FUNC_FEATURES 0 +#define ARM_SMCCC_KVM_FUNC_PTP 1 +#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127 +#define ARM_SMCCC_KVM_NUM_FUNCS 128 + +#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_VENDOR_HYP, \ + ARM_SMCCC_KVM_FUNC_FEATURES) + +#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED 1 + +/* + * ptp_kvm is a feature used for time sync between vm and host. + * ptp_kvm module in guest kernel will get service from host using + * this hypercall ID. + */ +#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_VENDOR_HYP, \ + ARM_SMCCC_KVM_FUNC_PTP) + +/* ptp_kvm counter type ID */ +#define KVM_PTP_VIRT_COUNTER 0 +#define KVM_PTP_PHYS_COUNTER 1 + +/* Paravirtualised time calls (defined by ARM DEN0057A) */ +#define ARM_SMCCC_HV_PV_TIME_FEATURES \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_STANDARD_HYP, \ + 0x20) + +#define ARM_SMCCC_HV_PV_TIME_ST \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_STANDARD_HYP, \ + 0x21) + +/* TRNG entropy source calls (defined by ARM DEN0098) */ +#define ARM_SMCCC_TRNG_VERSION \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_STANDARD, \ + 0x50) + +#define ARM_SMCCC_TRNG_FEATURES \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_STANDARD, \ + 0x51) + +#define ARM_SMCCC_TRNG_GET_UUID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_STANDARD, \ + 0x52) + +#define ARM_SMCCC_TRNG_RND32 \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_STANDARD, \ + 0x53) + +#define ARM_SMCCC_TRNG_RND64 \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_STANDARD, \ + 0x53) + +/* + * Return codes defined in ARM DEN 0070A + * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C + */ +#define SMCCC_RET_SUCCESS 0 +#define SMCCC_RET_NOT_SUPPORTED -1 +#define SMCCC_RET_NOT_REQUIRED -2 +#define SMCCC_RET_INVALID_PARAMETER -3 + +#endif /*__LINUX_ARM_SMCCC_H*/ -- cgit From e2ef115813c34ea5380ac5b4879f515070150210 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 6 May 2022 14:14:37 +0200 Subject: objtool: Fix STACK_FRAME_NON_STANDARD reloc type STACK_FRAME_NON_STANDARD results in inconsistent relocation types depending on .c or .S usage: Relocation section '.rela.discard.func_stack_frame_non_standard' at offset 0x3c01090 contains 5 entries: Offset Info Type Symbol's Value Symbol's Name + Addend 0000000000000000 00020c2200000002 R_X86_64_PC32 0000000000047b40 do_suspend_lowlevel + 0 0000000000000008 0002461e00000001 R_X86_64_64 00000000000480a0 machine_real_restart + 0 0000000000000010 0000001400000001 R_X86_64_64 0000000000000000 .rodata + b3d4 0000000000000018 0002444600000002 R_X86_64_PC32 00000000000678a0 __efi64_thunk + 0 0000000000000020 0002659d00000001 R_X86_64_64 0000000000113160 __crash_kexec + 0 Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Borislav Petkov Link: https://lore.kernel.org/r/20220506121631.508692613@infradead.org --- include/linux/objtool.h | 4 +++- tools/include/linux/objtool.h | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/include/linux/objtool.h b/include/linux/objtool.h index 586d35720f13..b9c1474a571e 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -40,6 +40,8 @@ struct unwind_hint { #ifdef CONFIG_STACK_VALIDATION +#include + #ifndef __ASSEMBLY__ #define UNWIND_HINT(sp_reg, sp_offset, type, end) \ @@ -137,7 +139,7 @@ struct unwind_hint { .macro STACK_FRAME_NON_STANDARD func:req .pushsection .discard.func_stack_frame_non_standard, "aw" - .long \func - . + _ASM_PTR \func .popsection .endm diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h index 586d35720f13..b9c1474a571e 100644 --- a/tools/include/linux/objtool.h +++ b/tools/include/linux/objtool.h @@ -40,6 +40,8 @@ struct unwind_hint { #ifdef CONFIG_STACK_VALIDATION +#include + #ifndef __ASSEMBLY__ #define UNWIND_HINT(sp_reg, sp_offset, type, end) \ @@ -137,7 +139,7 @@ struct unwind_hint { .macro STACK_FRAME_NON_STANDARD func:req .pushsection .discard.func_stack_frame_non_standard, "aw" - .long \func - . + _ASM_PTR \func .popsection .endm -- cgit From 474e76c4075c10461c4373d932a083e25d6adf3c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 9 May 2021 09:39:02 -0300 Subject: tools headers UAPI: Sync linux/kvm.h with the kernel sources To pick the changes in: d495f942f40aa412 ("KVM: fix bad user ABI for KVM_EXIT_SYSTEM_EVENT") That just rebuilds perf, as these patches don't add any new KVM ioctl to be harvested for the the 'perf trace' ioctl syscall argument beautifiers. This is also by now used by tools/testing/selftests/kvm/, a simple test build succeeded. This silences this perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/kvm.h' differs from latest version at 'include/uapi/linux/kvm.h' diff -u tools/include/uapi/linux/kvm.h include/uapi/linux/kvm.h Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paolo Bonzini Link: http://lore.kernel.org/lkml/YnE5BIweGmCkpOTN@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/kvm.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 91a6fe4e02c0..6a184d260c7f 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -445,7 +445,13 @@ struct kvm_run { #define KVM_SYSTEM_EVENT_RESET 2 #define KVM_SYSTEM_EVENT_CRASH 3 __u32 type; - __u64 flags; + __u32 ndata; + union { +#ifndef __KERNEL__ + __u64 flags; +#endif + __u64 data[16]; + }; } system_event; /* KVM_EXIT_S390_STSI */ struct { @@ -1144,6 +1150,8 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_S390_MEM_OP_EXTENSION 211 #define KVM_CAP_PMU_CAPABILITY 212 #define KVM_CAP_DISABLE_QUIRKS2 213 +/* #define KVM_CAP_VM_TSC_CONTROL 214 */ +#define KVM_CAP_SYSTEM_EVENT_DATA 215 #ifdef KVM_CAP_IRQ_ROUTING -- cgit From 26101f5ab6bdf30ac25c8e578e0b4873e7849e0c Mon Sep 17 00:00:00 2001 From: Kaixi Fan Date: Sat, 30 Apr 2022 15:48:42 +0800 Subject: bpf: Add source ip in "struct bpf_tunnel_key" Add tunnel source ip field in "struct bpf_tunnel_key". Add related code to set and get tunnel source field. Signed-off-by: Kaixi Fan Link: https://lore.kernel.org/r/20220430074844.69214-2-fankaixi.li@bytedance.com Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 4 ++++ net/core/filter.c | 9 +++++++++ tools/include/uapi/linux/bpf.h | 4 ++++ 3 files changed, 17 insertions(+) (limited to 'tools/include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 444fe6f1cf35..95a3d1ff6255 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5604,6 +5604,10 @@ struct bpf_tunnel_key { __u8 tunnel_ttl; __u16 tunnel_ext; /* Padding, future use. */ __u32 tunnel_label; + union { + __u32 local_ipv4; + __u32 local_ipv6[4]; + }; }; /* user accessible mirror of in-kernel xfrm_state. diff --git a/net/core/filter.c b/net/core/filter.c index b741b9f7e6a9..fe0da529d00f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4498,6 +4498,7 @@ BPF_CALL_4(bpf_skb_get_tunnel_key, struct sk_buff *, skb, struct bpf_tunnel_key if (unlikely(size != sizeof(struct bpf_tunnel_key))) { err = -EINVAL; switch (size) { + case offsetof(struct bpf_tunnel_key, local_ipv6[0]): case offsetof(struct bpf_tunnel_key, tunnel_label): case offsetof(struct bpf_tunnel_key, tunnel_ext): goto set_compat; @@ -4523,10 +4524,14 @@ set_compat: if (flags & BPF_F_TUNINFO_IPV6) { memcpy(to->remote_ipv6, &info->key.u.ipv6.src, sizeof(to->remote_ipv6)); + memcpy(to->local_ipv6, &info->key.u.ipv6.dst, + sizeof(to->local_ipv6)); to->tunnel_label = be32_to_cpu(info->key.label); } else { to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src); memset(&to->remote_ipv6[1], 0, sizeof(__u32) * 3); + to->local_ipv4 = be32_to_cpu(info->key.u.ipv4.dst); + memset(&to->local_ipv6[1], 0, sizeof(__u32) * 3); to->tunnel_label = 0; } @@ -4597,6 +4602,7 @@ BPF_CALL_4(bpf_skb_set_tunnel_key, struct sk_buff *, skb, return -EINVAL; if (unlikely(size != sizeof(struct bpf_tunnel_key))) { switch (size) { + case offsetof(struct bpf_tunnel_key, local_ipv6[0]): case offsetof(struct bpf_tunnel_key, tunnel_label): case offsetof(struct bpf_tunnel_key, tunnel_ext): case offsetof(struct bpf_tunnel_key, remote_ipv6[1]): @@ -4639,10 +4645,13 @@ BPF_CALL_4(bpf_skb_set_tunnel_key, struct sk_buff *, skb, info->mode |= IP_TUNNEL_INFO_IPV6; memcpy(&info->key.u.ipv6.dst, from->remote_ipv6, sizeof(from->remote_ipv6)); + memcpy(&info->key.u.ipv6.src, from->local_ipv6, + sizeof(from->local_ipv6)); info->key.label = cpu_to_be32(from->tunnel_label) & IPV6_FLOWLABEL_MASK; } else { info->key.u.ipv4.dst = cpu_to_be32(from->remote_ipv4); + info->key.u.ipv4.src = cpu_to_be32(from->local_ipv4); } return 0; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 444fe6f1cf35..95a3d1ff6255 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5604,6 +5604,10 @@ struct bpf_tunnel_key { __u8 tunnel_ttl; __u16 tunnel_ext; /* Padding, future use. */ __u32 tunnel_label; + union { + __u32 local_ipv4; + __u32 local_ipv6[4]; + }; }; /* user accessible mirror of in-kernel xfrm_state. -- cgit From f7e0beaf39d3868dc700d4954b26cf8443c5d423 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Tue, 10 May 2022 13:59:19 -0700 Subject: bpf, x86: Generate trampolines from bpf_tramp_links Replace struct bpf_tramp_progs with struct bpf_tramp_links to collect struct bpf_tramp_link(s) for a trampoline. struct bpf_tramp_link extends bpf_link to act as a linked list node. arch_prepare_bpf_trampoline() accepts a struct bpf_tramp_links to collects all bpf_tramp_link(s) that a trampoline should call. Change BPF trampoline and bpf_struct_ops to pass bpf_tramp_links instead of bpf_tramp_progs. Signed-off-by: Kui-Feng Lee Signed-off-by: Alexei Starovoitov Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20220510205923.3206889-2-kuifeng@fb.com --- arch/x86/net/bpf_jit_comp.c | 36 +++++++++++---------- include/linux/bpf.h | 36 ++++++++++++++------- include/linux/bpf_types.h | 1 + include/uapi/linux/bpf.h | 1 + kernel/bpf/bpf_struct_ops.c | 71 +++++++++++++++++++++++++++------------- kernel/bpf/syscall.c | 23 +++++-------- kernel/bpf/trampoline.c | 73 ++++++++++++++++++++++++------------------ net/bpf/bpf_dummy_struct_ops.c | 24 +++++++++++--- tools/bpf/bpftool/link.c | 1 + tools/include/uapi/linux/bpf.h | 1 + 10 files changed, 164 insertions(+), 103 deletions(-) (limited to 'tools/include') diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 16b6efacf7c6..38eb43159230 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -1762,10 +1762,12 @@ static void restore_regs(const struct btf_func_model *m, u8 **prog, int nr_args, } static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, - struct bpf_prog *p, int stack_size, bool save_ret) + struct bpf_tramp_link *l, int stack_size, + bool save_ret) { u8 *prog = *pprog; u8 *jmp_insn; + struct bpf_prog *p = l->link.prog; /* arg1: mov rdi, progs[i] */ emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32, (u32) (long) p); @@ -1850,14 +1852,14 @@ static int emit_cond_near_jump(u8 **pprog, void *func, void *ip, u8 jmp_cond) } static int invoke_bpf(const struct btf_func_model *m, u8 **pprog, - struct bpf_tramp_progs *tp, int stack_size, + struct bpf_tramp_links *tl, int stack_size, bool save_ret) { int i; u8 *prog = *pprog; - for (i = 0; i < tp->nr_progs; i++) { - if (invoke_bpf_prog(m, &prog, tp->progs[i], stack_size, + for (i = 0; i < tl->nr_links; i++) { + if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, save_ret)) return -EINVAL; } @@ -1866,7 +1868,7 @@ static int invoke_bpf(const struct btf_func_model *m, u8 **pprog, } static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog, - struct bpf_tramp_progs *tp, int stack_size, + struct bpf_tramp_links *tl, int stack_size, u8 **branches) { u8 *prog = *pprog; @@ -1877,8 +1879,8 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog, */ emit_mov_imm32(&prog, false, BPF_REG_0, 0); emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8); - for (i = 0; i < tp->nr_progs; i++) { - if (invoke_bpf_prog(m, &prog, tp->progs[i], stack_size, true)) + for (i = 0; i < tl->nr_links; i++) { + if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, true)) return -EINVAL; /* mod_ret prog stored return value into [rbp - 8]. Emit: @@ -1980,14 +1982,14 @@ static bool is_valid_bpf_tramp_flags(unsigned int flags) */ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, const struct btf_func_model *m, u32 flags, - struct bpf_tramp_progs *tprogs, + struct bpf_tramp_links *tlinks, void *orig_call) { int ret, i, nr_args = m->nr_args; int regs_off, ip_off, args_off, stack_size = nr_args * 8; - struct bpf_tramp_progs *fentry = &tprogs[BPF_TRAMP_FENTRY]; - struct bpf_tramp_progs *fexit = &tprogs[BPF_TRAMP_FEXIT]; - struct bpf_tramp_progs *fmod_ret = &tprogs[BPF_TRAMP_MODIFY_RETURN]; + struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; + struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT]; + struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN]; u8 **branches = NULL; u8 *prog; bool save_ret; @@ -2078,13 +2080,13 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i } } - if (fentry->nr_progs) + if (fentry->nr_links) if (invoke_bpf(m, &prog, fentry, regs_off, flags & BPF_TRAMP_F_RET_FENTRY_RET)) return -EINVAL; - if (fmod_ret->nr_progs) { - branches = kcalloc(fmod_ret->nr_progs, sizeof(u8 *), + if (fmod_ret->nr_links) { + branches = kcalloc(fmod_ret->nr_links, sizeof(u8 *), GFP_KERNEL); if (!branches) return -ENOMEM; @@ -2111,7 +2113,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i prog += X86_PATCH_SIZE; } - if (fmod_ret->nr_progs) { + if (fmod_ret->nr_links) { /* From Intel 64 and IA-32 Architectures Optimization * Reference Manual, 3.4.1.4 Code Alignment, Assembly/Compiler * Coding Rule 11: All branch targets should be 16-byte @@ -2121,12 +2123,12 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i /* Update the branches saved in invoke_bpf_mod_ret with the * aligned address of do_fexit. */ - for (i = 0; i < fmod_ret->nr_progs; i++) + for (i = 0; i < fmod_ret->nr_links; i++) emit_cond_near_jump(&branches[i], prog, branches[i], X86_JNE); } - if (fexit->nr_progs) + if (fexit->nr_links) if (invoke_bpf(m, &prog, fexit, regs_off, false)) { ret = -EINVAL; goto cleanup; diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 551b7198ae8a..75e0110a65e1 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -723,11 +723,11 @@ struct btf_func_model { /* Each call __bpf_prog_enter + call bpf_func + call __bpf_prog_exit is ~50 * bytes on x86. Pick a number to fit into BPF_IMAGE_SIZE / 2 */ -#define BPF_MAX_TRAMP_PROGS 38 +#define BPF_MAX_TRAMP_LINKS 38 -struct bpf_tramp_progs { - struct bpf_prog *progs[BPF_MAX_TRAMP_PROGS]; - int nr_progs; +struct bpf_tramp_links { + struct bpf_tramp_link *links[BPF_MAX_TRAMP_LINKS]; + int nr_links; }; /* Different use cases for BPF trampoline: @@ -753,7 +753,7 @@ struct bpf_tramp_progs { struct bpf_tramp_image; int arch_prepare_bpf_trampoline(struct bpf_tramp_image *tr, void *image, void *image_end, const struct btf_func_model *m, u32 flags, - struct bpf_tramp_progs *tprogs, + struct bpf_tramp_links *tlinks, void *orig_call); /* these two functions are called from generated trampoline */ u64 notrace __bpf_prog_enter(struct bpf_prog *prog); @@ -852,9 +852,10 @@ static __always_inline __nocfi unsigned int bpf_dispatcher_nop_func( { return bpf_func(ctx, insnsi); } + #ifdef CONFIG_BPF_JIT -int bpf_trampoline_link_prog(struct bpf_prog *prog, struct bpf_trampoline *tr); -int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr); +int bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr); +int bpf_trampoline_unlink_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr); struct bpf_trampoline *bpf_trampoline_get(u64 key, struct bpf_attach_target_info *tgt_info); void bpf_trampoline_put(struct bpf_trampoline *tr); @@ -905,12 +906,12 @@ int bpf_jit_charge_modmem(u32 size); void bpf_jit_uncharge_modmem(u32 size); bool bpf_prog_has_trampoline(const struct bpf_prog *prog); #else -static inline int bpf_trampoline_link_prog(struct bpf_prog *prog, +static inline int bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr) { return -ENOTSUPP; } -static inline int bpf_trampoline_unlink_prog(struct bpf_prog *prog, +static inline int bpf_trampoline_unlink_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr) { return -ENOTSUPP; @@ -1009,7 +1010,6 @@ struct bpf_prog_aux { bool tail_call_reachable; bool xdp_has_frags; bool use_bpf_prog_pack; - struct hlist_node tramp_hlist; /* BTF_KIND_FUNC_PROTO for valid attach_btf_id */ const struct btf_type *attach_func_proto; /* function name for valid attach_btf_id */ @@ -1096,6 +1096,18 @@ struct bpf_link_ops { struct bpf_link_info *info); }; +struct bpf_tramp_link { + struct bpf_link link; + struct hlist_node tramp_hlist; +}; + +struct bpf_tracing_link { + struct bpf_tramp_link link; + enum bpf_attach_type attach_type; + struct bpf_trampoline *trampoline; + struct bpf_prog *tgt_prog; +}; + struct bpf_link_primer { struct bpf_link *link; struct file *file; @@ -1133,8 +1145,8 @@ bool bpf_struct_ops_get(const void *kdata); void bpf_struct_ops_put(const void *kdata); int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key, void *value); -int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_progs *tprogs, - struct bpf_prog *prog, +int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks, + struct bpf_tramp_link *link, const struct btf_func_model *model, void *image, void *image_end); static inline bool bpf_try_module_get(const void *data, struct module *owner) diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index 3e24ad0c4b3c..2b9112b80171 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -141,3 +141,4 @@ BPF_LINK_TYPE(BPF_LINK_TYPE_XDP, xdp) BPF_LINK_TYPE(BPF_LINK_TYPE_PERF_EVENT, perf) #endif BPF_LINK_TYPE(BPF_LINK_TYPE_KPROBE_MULTI, kprobe_multi) +BPF_LINK_TYPE(BPF_LINK_TYPE_STRUCT_OPS, struct_ops) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 95a3d1ff6255..3d032ea1b6a3 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1013,6 +1013,7 @@ enum bpf_link_type { BPF_LINK_TYPE_XDP = 6, BPF_LINK_TYPE_PERF_EVENT = 7, BPF_LINK_TYPE_KPROBE_MULTI = 8, + BPF_LINK_TYPE_STRUCT_OPS = 9, MAX_BPF_LINK_TYPE, }; diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 3a0103ad97bc..d9a3c9207240 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -33,15 +33,15 @@ struct bpf_struct_ops_map { const struct bpf_struct_ops *st_ops; /* protect map_update */ struct mutex lock; - /* progs has all the bpf_prog that is populated + /* link has all the bpf_links that is populated * to the func ptr of the kernel's struct * (in kvalue.data). */ - struct bpf_prog **progs; + struct bpf_link **links; /* image is a page that has all the trampolines * that stores the func args before calling the bpf_prog. * A PAGE_SIZE "image" is enough to store all trampoline for - * "progs[]". + * "links[]". */ void *image; /* uvalue->data stores the kernel struct @@ -283,9 +283,9 @@ static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map) u32 i; for (i = 0; i < btf_type_vlen(t); i++) { - if (st_map->progs[i]) { - bpf_prog_put(st_map->progs[i]); - st_map->progs[i] = NULL; + if (st_map->links[i]) { + bpf_link_put(st_map->links[i]); + st_map->links[i] = NULL; } } } @@ -316,18 +316,34 @@ static int check_zero_holes(const struct btf_type *t, void *data) return 0; } -int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_progs *tprogs, - struct bpf_prog *prog, +static void bpf_struct_ops_link_release(struct bpf_link *link) +{ +} + +static void bpf_struct_ops_link_dealloc(struct bpf_link *link) +{ + struct bpf_tramp_link *tlink = container_of(link, struct bpf_tramp_link, link); + + kfree(tlink); +} + +const struct bpf_link_ops bpf_struct_ops_link_lops = { + .release = bpf_struct_ops_link_release, + .dealloc = bpf_struct_ops_link_dealloc, +}; + +int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks, + struct bpf_tramp_link *link, const struct btf_func_model *model, void *image, void *image_end) { u32 flags; - tprogs[BPF_TRAMP_FENTRY].progs[0] = prog; - tprogs[BPF_TRAMP_FENTRY].nr_progs = 1; + tlinks[BPF_TRAMP_FENTRY].links[0] = link; + tlinks[BPF_TRAMP_FENTRY].nr_links = 1; flags = model->ret_size > 0 ? BPF_TRAMP_F_RET_FENTRY_RET : 0; return arch_prepare_bpf_trampoline(NULL, image, image_end, - model, flags, tprogs, NULL); + model, flags, tlinks, NULL); } static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, @@ -338,7 +354,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, struct bpf_struct_ops_value *uvalue, *kvalue; const struct btf_member *member; const struct btf_type *t = st_ops->type; - struct bpf_tramp_progs *tprogs = NULL; + struct bpf_tramp_links *tlinks = NULL; void *udata, *kdata; int prog_fd, err = 0; void *image, *image_end; @@ -362,8 +378,8 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, if (uvalue->state || refcount_read(&uvalue->refcnt)) return -EINVAL; - tprogs = kcalloc(BPF_TRAMP_MAX, sizeof(*tprogs), GFP_KERNEL); - if (!tprogs) + tlinks = kcalloc(BPF_TRAMP_MAX, sizeof(*tlinks), GFP_KERNEL); + if (!tlinks) return -ENOMEM; uvalue = (struct bpf_struct_ops_value *)st_map->uvalue; @@ -386,6 +402,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, for_each_member(i, t, member) { const struct btf_type *mtype, *ptype; struct bpf_prog *prog; + struct bpf_tramp_link *link; u32 moff; moff = __btf_member_bit_offset(t, member) / 8; @@ -439,16 +456,26 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key, err = PTR_ERR(prog); goto reset_unlock; } - st_map->progs[i] = prog; if (prog->type != BPF_PROG_TYPE_STRUCT_OPS || prog->aux->attach_btf_id != st_ops->type_id || prog->expected_attach_type != i) { + bpf_prog_put(prog); err = -EINVAL; goto reset_unlock; } - err = bpf_struct_ops_prepare_trampoline(tprogs, prog, + link = kzalloc(sizeof(*link), GFP_USER); + if (!link) { + bpf_prog_put(prog); + err = -ENOMEM; + goto reset_unlock; + } + bpf_link_init(&link->link, BPF_LINK_TYPE_STRUCT_OPS, + &bpf_struct_ops_link_lops, prog); + st_map->links[i] = &link->link; + + err = bpf_struct_ops_prepare_trampoline(tlinks, link, &st_ops->func_models[i], image, image_end); if (err < 0) @@ -491,7 +518,7 @@ reset_unlock: memset(uvalue, 0, map->value_size); memset(kvalue, 0, map->value_size); unlock: - kfree(tprogs); + kfree(tlinks); mutex_unlock(&st_map->lock); return err; } @@ -546,9 +573,9 @@ static void bpf_struct_ops_map_free(struct bpf_map *map) { struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map; - if (st_map->progs) + if (st_map->links) bpf_struct_ops_map_put_progs(st_map); - bpf_map_area_free(st_map->progs); + bpf_map_area_free(st_map->links); bpf_jit_free_exec(st_map->image); bpf_map_area_free(st_map->uvalue); bpf_map_area_free(st_map); @@ -597,11 +624,11 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) map = &st_map->map; st_map->uvalue = bpf_map_area_alloc(vt->size, NUMA_NO_NODE); - st_map->progs = - bpf_map_area_alloc(btf_type_vlen(t) * sizeof(struct bpf_prog *), + st_map->links = + bpf_map_area_alloc(btf_type_vlen(t) * sizeof(struct bpf_links *), NUMA_NO_NODE); st_map->image = bpf_jit_alloc_exec(PAGE_SIZE); - if (!st_map->uvalue || !st_map->progs || !st_map->image) { + if (!st_map->uvalue || !st_map->links || !st_map->image) { bpf_struct_ops_map_free(map); return ERR_PTR(-ENOMEM); } diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 50164d324eaf..2dc582773344 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2864,19 +2864,12 @@ struct bpf_link *bpf_link_get_from_fd(u32 ufd) } EXPORT_SYMBOL(bpf_link_get_from_fd); -struct bpf_tracing_link { - struct bpf_link link; - enum bpf_attach_type attach_type; - struct bpf_trampoline *trampoline; - struct bpf_prog *tgt_prog; -}; - static void bpf_tracing_link_release(struct bpf_link *link) { struct bpf_tracing_link *tr_link = - container_of(link, struct bpf_tracing_link, link); + container_of(link, struct bpf_tracing_link, link.link); - WARN_ON_ONCE(bpf_trampoline_unlink_prog(link->prog, + WARN_ON_ONCE(bpf_trampoline_unlink_prog(&tr_link->link, tr_link->trampoline)); bpf_trampoline_put(tr_link->trampoline); @@ -2889,7 +2882,7 @@ static void bpf_tracing_link_release(struct bpf_link *link) static void bpf_tracing_link_dealloc(struct bpf_link *link) { struct bpf_tracing_link *tr_link = - container_of(link, struct bpf_tracing_link, link); + container_of(link, struct bpf_tracing_link, link.link); kfree(tr_link); } @@ -2898,7 +2891,7 @@ static void bpf_tracing_link_show_fdinfo(const struct bpf_link *link, struct seq_file *seq) { struct bpf_tracing_link *tr_link = - container_of(link, struct bpf_tracing_link, link); + container_of(link, struct bpf_tracing_link, link.link); seq_printf(seq, "attach_type:\t%d\n", @@ -2909,7 +2902,7 @@ static int bpf_tracing_link_fill_link_info(const struct bpf_link *link, struct bpf_link_info *info) { struct bpf_tracing_link *tr_link = - container_of(link, struct bpf_tracing_link, link); + container_of(link, struct bpf_tracing_link, link.link); info->tracing.attach_type = tr_link->attach_type; bpf_trampoline_unpack_key(tr_link->trampoline->key, @@ -2990,7 +2983,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog, err = -ENOMEM; goto out_put_prog; } - bpf_link_init(&link->link, BPF_LINK_TYPE_TRACING, + bpf_link_init(&link->link.link, BPF_LINK_TYPE_TRACING, &bpf_tracing_link_lops, prog); link->attach_type = prog->expected_attach_type; @@ -3060,11 +3053,11 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog, tgt_prog = prog->aux->dst_prog; } - err = bpf_link_prime(&link->link, &link_primer); + err = bpf_link_prime(&link->link.link, &link_primer); if (err) goto out_unlock; - err = bpf_trampoline_link_prog(prog, tr); + err = bpf_trampoline_link_prog(&link->link, tr); if (err) { bpf_link_cleanup(&link_primer); link = NULL; diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index ada97751ae1b..d5e6bc5517cb 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -168,30 +168,30 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr) return ret; } -static struct bpf_tramp_progs * +static struct bpf_tramp_links * bpf_trampoline_get_progs(const struct bpf_trampoline *tr, int *total, bool *ip_arg) { - const struct bpf_prog_aux *aux; - struct bpf_tramp_progs *tprogs; - struct bpf_prog **progs; + struct bpf_tramp_link *link; + struct bpf_tramp_links *tlinks; + struct bpf_tramp_link **links; int kind; *total = 0; - tprogs = kcalloc(BPF_TRAMP_MAX, sizeof(*tprogs), GFP_KERNEL); - if (!tprogs) + tlinks = kcalloc(BPF_TRAMP_MAX, sizeof(*tlinks), GFP_KERNEL); + if (!tlinks) return ERR_PTR(-ENOMEM); for (kind = 0; kind < BPF_TRAMP_MAX; kind++) { - tprogs[kind].nr_progs = tr->progs_cnt[kind]; + tlinks[kind].nr_links = tr->progs_cnt[kind]; *total += tr->progs_cnt[kind]; - progs = tprogs[kind].progs; + links = tlinks[kind].links; - hlist_for_each_entry(aux, &tr->progs_hlist[kind], tramp_hlist) { - *ip_arg |= aux->prog->call_get_func_ip; - *progs++ = aux->prog; + hlist_for_each_entry(link, &tr->progs_hlist[kind], tramp_hlist) { + *ip_arg |= link->link.prog->call_get_func_ip; + *links++ = link; } } - return tprogs; + return tlinks; } static void __bpf_tramp_image_put_deferred(struct work_struct *work) @@ -330,14 +330,14 @@ out: static int bpf_trampoline_update(struct bpf_trampoline *tr) { struct bpf_tramp_image *im; - struct bpf_tramp_progs *tprogs; + struct bpf_tramp_links *tlinks; u32 flags = BPF_TRAMP_F_RESTORE_REGS; bool ip_arg = false; int err, total; - tprogs = bpf_trampoline_get_progs(tr, &total, &ip_arg); - if (IS_ERR(tprogs)) - return PTR_ERR(tprogs); + tlinks = bpf_trampoline_get_progs(tr, &total, &ip_arg); + if (IS_ERR(tlinks)) + return PTR_ERR(tlinks); if (total == 0) { err = unregister_fentry(tr, tr->cur_image->image); @@ -353,15 +353,15 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr) goto out; } - if (tprogs[BPF_TRAMP_FEXIT].nr_progs || - tprogs[BPF_TRAMP_MODIFY_RETURN].nr_progs) + if (tlinks[BPF_TRAMP_FEXIT].nr_links || + tlinks[BPF_TRAMP_MODIFY_RETURN].nr_links) flags = BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_SKIP_FRAME; if (ip_arg) flags |= BPF_TRAMP_F_IP_ARG; err = arch_prepare_bpf_trampoline(im, im->image, im->image + PAGE_SIZE, - &tr->func.model, flags, tprogs, + &tr->func.model, flags, tlinks, tr->func.addr); if (err < 0) goto out; @@ -381,7 +381,7 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr) tr->cur_image = im; tr->selector++; out: - kfree(tprogs); + kfree(tlinks); return err; } @@ -407,13 +407,14 @@ static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog) } } -int bpf_trampoline_link_prog(struct bpf_prog *prog, struct bpf_trampoline *tr) +int bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr) { enum bpf_tramp_prog_type kind; + struct bpf_tramp_link *link_exiting; int err = 0; int cnt; - kind = bpf_attach_type_to_tramp(prog); + kind = bpf_attach_type_to_tramp(link->link.prog); mutex_lock(&tr->mutex); if (tr->extension_prog) { /* cannot attach fentry/fexit if extension prog is attached. @@ -429,25 +430,33 @@ int bpf_trampoline_link_prog(struct bpf_prog *prog, struct bpf_trampoline *tr) err = -EBUSY; goto out; } - tr->extension_prog = prog; + tr->extension_prog = link->link.prog; err = bpf_arch_text_poke(tr->func.addr, BPF_MOD_JUMP, NULL, - prog->bpf_func); + link->link.prog->bpf_func); goto out; } - if (cnt >= BPF_MAX_TRAMP_PROGS) { + if (cnt >= BPF_MAX_TRAMP_LINKS) { err = -E2BIG; goto out; } - if (!hlist_unhashed(&prog->aux->tramp_hlist)) { + if (!hlist_unhashed(&link->tramp_hlist)) { /* prog already linked */ err = -EBUSY; goto out; } - hlist_add_head(&prog->aux->tramp_hlist, &tr->progs_hlist[kind]); + hlist_for_each_entry(link_exiting, &tr->progs_hlist[kind], tramp_hlist) { + if (link_exiting->link.prog != link->link.prog) + continue; + /* prog already linked */ + err = -EBUSY; + goto out; + } + + hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]); tr->progs_cnt[kind]++; err = bpf_trampoline_update(tr); if (err) { - hlist_del_init(&prog->aux->tramp_hlist); + hlist_del_init(&link->tramp_hlist); tr->progs_cnt[kind]--; } out: @@ -456,12 +465,12 @@ out: } /* bpf_trampoline_unlink_prog() should never fail. */ -int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr) +int bpf_trampoline_unlink_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr) { enum bpf_tramp_prog_type kind; int err; - kind = bpf_attach_type_to_tramp(prog); + kind = bpf_attach_type_to_tramp(link->link.prog); mutex_lock(&tr->mutex); if (kind == BPF_TRAMP_REPLACE) { WARN_ON_ONCE(!tr->extension_prog); @@ -470,7 +479,7 @@ int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr) tr->extension_prog = NULL; goto out; } - hlist_del_init(&prog->aux->tramp_hlist); + hlist_del_init(&link->tramp_hlist); tr->progs_cnt[kind]--; err = bpf_trampoline_update(tr); out: @@ -635,7 +644,7 @@ void notrace __bpf_tramp_exit(struct bpf_tramp_image *tr) int __weak arch_prepare_bpf_trampoline(struct bpf_tramp_image *tr, void *image, void *image_end, const struct btf_func_model *m, u32 flags, - struct bpf_tramp_progs *tprogs, + struct bpf_tramp_links *tlinks, void *orig_call) { return -ENOTSUPP; diff --git a/net/bpf/bpf_dummy_struct_ops.c b/net/bpf/bpf_dummy_struct_ops.c index d0e54e30658a..e78dadfc5829 100644 --- a/net/bpf/bpf_dummy_struct_ops.c +++ b/net/bpf/bpf_dummy_struct_ops.c @@ -72,13 +72,16 @@ static int dummy_ops_call_op(void *image, struct bpf_dummy_ops_test_args *args) args->args[3], args->args[4]); } +extern const struct bpf_link_ops bpf_struct_ops_link_lops; + int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, union bpf_attr __user *uattr) { const struct bpf_struct_ops *st_ops = &bpf_bpf_dummy_ops; const struct btf_type *func_proto; struct bpf_dummy_ops_test_args *args; - struct bpf_tramp_progs *tprogs; + struct bpf_tramp_links *tlinks; + struct bpf_tramp_link *link = NULL; void *image = NULL; unsigned int op_idx; int prog_ret; @@ -92,8 +95,8 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, if (IS_ERR(args)) return PTR_ERR(args); - tprogs = kcalloc(BPF_TRAMP_MAX, sizeof(*tprogs), GFP_KERNEL); - if (!tprogs) { + tlinks = kcalloc(BPF_TRAMP_MAX, sizeof(*tlinks), GFP_KERNEL); + if (!tlinks) { err = -ENOMEM; goto out; } @@ -105,8 +108,17 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, } set_vm_flush_reset_perms(image); + link = kzalloc(sizeof(*link), GFP_USER); + if (!link) { + err = -ENOMEM; + goto out; + } + /* prog doesn't take the ownership of the reference from caller */ + bpf_prog_inc(prog); + bpf_link_init(&link->link, BPF_LINK_TYPE_STRUCT_OPS, &bpf_struct_ops_link_lops, prog); + op_idx = prog->expected_attach_type; - err = bpf_struct_ops_prepare_trampoline(tprogs, prog, + err = bpf_struct_ops_prepare_trampoline(tlinks, link, &st_ops->func_models[op_idx], image, image + PAGE_SIZE); if (err < 0) @@ -124,7 +136,9 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr, out: kfree(args); bpf_jit_free_exec(image); - kfree(tprogs); + if (link) + bpf_link_put(&link->link); + kfree(tlinks); return err; } diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index 8fb0116f9136..6353a789322b 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -23,6 +23,7 @@ static const char * const link_type_name[] = { [BPF_LINK_TYPE_XDP] = "xdp", [BPF_LINK_TYPE_PERF_EVENT] = "perf_event", [BPF_LINK_TYPE_KPROBE_MULTI] = "kprobe_multi", + [BPF_LINK_TYPE_STRUCT_OPS] = "struct_ops", }; static struct hashmap *link_table; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 95a3d1ff6255..3d032ea1b6a3 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1013,6 +1013,7 @@ enum bpf_link_type { BPF_LINK_TYPE_XDP = 6, BPF_LINK_TYPE_PERF_EVENT = 7, BPF_LINK_TYPE_KPROBE_MULTI = 8, + BPF_LINK_TYPE_STRUCT_OPS = 9, MAX_BPF_LINK_TYPE, }; -- cgit From 2fcc82411e74e5e6aba336561cf56fb899bfae4e Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Tue, 10 May 2022 13:59:21 -0700 Subject: bpf, x86: Attach a cookie to fentry/fexit/fmod_ret/lsm. Pass a cookie along with BPF_LINK_CREATE requests. Add a bpf_cookie field to struct bpf_tracing_link to attach a cookie. The cookie of a bpf_tracing_link is available by calling bpf_get_attach_cookie when running the BPF program of the attached link. The value of a cookie will be set at bpf_tramp_run_ctx by the trampoline of the link. Signed-off-by: Kui-Feng Lee Signed-off-by: Alexei Starovoitov Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20220510205923.3206889-4-kuifeng@fb.com --- arch/x86/net/bpf_jit_comp.c | 5 +++-- include/linux/bpf.h | 1 + include/uapi/linux/bpf.h | 9 +++++++++ kernel/bpf/bpf_lsm.c | 17 +++++++++++++++++ kernel/bpf/syscall.c | 12 ++++++++---- kernel/bpf/trampoline.c | 7 +++++-- kernel/trace/bpf_trace.c | 17 +++++++++++++++++ tools/include/uapi/linux/bpf.h | 9 +++++++++ 8 files changed, 69 insertions(+), 8 deletions(-) (limited to 'tools/include') diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 1fbc5cf1c7a7..a2b6d197c226 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -1769,9 +1769,10 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, u8 *jmp_insn; int ctx_cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie); struct bpf_prog *p = l->link.prog; + u64 cookie = l->cookie; - /* mov rdi, 0 */ - emit_mov_imm64(&prog, BPF_REG_1, 0, 0); + /* mov rdi, cookie */ + emit_mov_imm64(&prog, BPF_REG_1, (long) cookie >> 32, (u32) (long) cookie); /* Prepare struct bpf_tramp_run_ctx. * diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 256fb802e580..aba7ded56436 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1102,6 +1102,7 @@ struct bpf_link_ops { struct bpf_tramp_link { struct bpf_link link; struct hlist_node tramp_hlist; + u64 cookie; }; struct bpf_tracing_link { diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 3d032ea1b6a3..bc7f89948f54 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1490,6 +1490,15 @@ union bpf_attr { __aligned_u64 addrs; __aligned_u64 cookies; } kprobe_multi; + struct { + /* this is overlaid with the target_btf_id above. */ + __u32 target_btf_id; + /* black box user-provided value passed through + * to BPF program at the execution time and + * accessible through bpf_get_attach_cookie() BPF helper + */ + __u64 cookie; + } tracing; }; } link_create; diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index 064eccba641d..c1351df9f7ee 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -117,6 +117,21 @@ static const struct bpf_func_proto bpf_ima_file_hash_proto = { .allowed = bpf_ima_inode_hash_allowed, }; +BPF_CALL_1(bpf_get_attach_cookie, void *, ctx) +{ + struct bpf_trace_run_ctx *run_ctx; + + run_ctx = container_of(current->bpf_ctx, struct bpf_trace_run_ctx, run_ctx); + return run_ctx->bpf_cookie; +} + +static const struct bpf_func_proto bpf_get_attach_cookie_proto = { + .func = bpf_get_attach_cookie, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +}; + static const struct bpf_func_proto * bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -141,6 +156,8 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return prog->aux->sleepable ? &bpf_ima_inode_hash_proto : NULL; case BPF_FUNC_ima_file_hash: return prog->aux->sleepable ? &bpf_ima_file_hash_proto : NULL; + case BPF_FUNC_get_attach_cookie: + return bpf_prog_has_trampoline(prog) ? &bpf_get_attach_cookie_proto : NULL; default: return tracing_prog_func_proto(func_id, prog); } diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index d48165fccf49..72e53489165d 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2921,7 +2921,8 @@ static const struct bpf_link_ops bpf_tracing_link_lops = { static int bpf_tracing_prog_attach(struct bpf_prog *prog, int tgt_prog_fd, - u32 btf_id) + u32 btf_id, + u64 bpf_cookie) { struct bpf_link_primer link_primer; struct bpf_prog *tgt_prog = NULL; @@ -2986,6 +2987,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog, bpf_link_init(&link->link.link, BPF_LINK_TYPE_TRACING, &bpf_tracing_link_lops, prog); link->attach_type = prog->expected_attach_type; + link->link.cookie = bpf_cookie; mutex_lock(&prog->aux->dst_mutex); @@ -3271,7 +3273,7 @@ static int bpf_raw_tp_link_attach(struct bpf_prog *prog, tp_name = prog->aux->attach_func_name; break; } - return bpf_tracing_prog_attach(prog, 0, 0); + return bpf_tracing_prog_attach(prog, 0, 0, 0); case BPF_PROG_TYPE_RAW_TRACEPOINT: case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: if (strncpy_from_user(buf, user_tp_name, sizeof(buf) - 1) < 0) @@ -4524,7 +4526,8 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr) case BPF_PROG_TYPE_EXT: ret = bpf_tracing_prog_attach(prog, attr->link_create.target_fd, - attr->link_create.target_btf_id); + attr->link_create.target_btf_id, + attr->link_create.tracing.cookie); break; case BPF_PROG_TYPE_LSM: case BPF_PROG_TYPE_TRACING: @@ -4539,7 +4542,8 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr) else ret = bpf_tracing_prog_attach(prog, attr->link_create.target_fd, - attr->link_create.target_btf_id); + attr->link_create.target_btf_id, + attr->link_create.tracing.cookie); break; case BPF_PROG_TYPE_FLOW_DISSECTOR: case BPF_PROG_TYPE_SK_LOOKUP: diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index baf1b65d523e..0e9b3aefc34a 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -30,9 +30,12 @@ static DEFINE_MUTEX(trampoline_mutex); bool bpf_prog_has_trampoline(const struct bpf_prog *prog) { enum bpf_attach_type eatype = prog->expected_attach_type; + enum bpf_prog_type ptype = prog->type; - return eatype == BPF_TRACE_FENTRY || eatype == BPF_TRACE_FEXIT || - eatype == BPF_MODIFY_RETURN; + return (ptype == BPF_PROG_TYPE_TRACING && + (eatype == BPF_TRACE_FENTRY || eatype == BPF_TRACE_FEXIT || + eatype == BPF_MODIFY_RETURN)) || + (ptype == BPF_PROG_TYPE_LSM && eatype == BPF_LSM_MAC); } void *bpf_jit_alloc_exec_page(void) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 7fd11c17558d..2eaac094caf8 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1091,6 +1091,21 @@ static const struct bpf_func_proto bpf_get_attach_cookie_proto_pe = { .arg1_type = ARG_PTR_TO_CTX, }; +BPF_CALL_1(bpf_get_attach_cookie_tracing, void *, ctx) +{ + struct bpf_trace_run_ctx *run_ctx; + + run_ctx = container_of(current->bpf_ctx, struct bpf_trace_run_ctx, run_ctx); + return run_ctx->bpf_cookie; +} + +static const struct bpf_func_proto bpf_get_attach_cookie_proto_tracing = { + .func = bpf_get_attach_cookie_tracing, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +}; + BPF_CALL_3(bpf_get_branch_snapshot, void *, buf, u32, size, u64, flags) { #ifndef CONFIG_X86 @@ -1719,6 +1734,8 @@ tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return bpf_prog_has_trampoline(prog) ? &bpf_get_func_ret_proto : NULL; case BPF_FUNC_get_func_arg_cnt: return bpf_prog_has_trampoline(prog) ? &bpf_get_func_arg_cnt_proto : NULL; + case BPF_FUNC_get_attach_cookie: + return bpf_prog_has_trampoline(prog) ? &bpf_get_attach_cookie_proto_tracing : NULL; default: fn = raw_tp_prog_func_proto(func_id, prog); if (!fn && prog->expected_attach_type == BPF_TRACE_ITER) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 3d032ea1b6a3..bc7f89948f54 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1490,6 +1490,15 @@ union bpf_attr { __aligned_u64 addrs; __aligned_u64 cookies; } kprobe_multi; + struct { + /* this is overlaid with the target_btf_id above. */ + __u32 target_btf_id; + /* black box user-provided value passed through + * to BPF program at the execution time and + * accessible through bpf_get_attach_cookie() BPF helper + */ + __u64 cookie; + } tracing; }; } link_create; -- cgit From 07343110b293456d30393e89b86c4dee1ac051c8 Mon Sep 17 00:00:00 2001 From: Feng Zhou Date: Wed, 11 May 2022 17:38:53 +0800 Subject: bpf: add bpf_map_lookup_percpu_elem for percpu map Add new ebpf helpers bpf_map_lookup_percpu_elem. The implementation method is relatively simple, refer to the implementation method of map_lookup_elem of percpu map, increase the parameters of cpu, and obtain it according to the specified cpu. Signed-off-by: Feng Zhou Link: https://lore.kernel.org/r/20220511093854.411-2-zhoufeng.zf@bytedance.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 2 ++ include/uapi/linux/bpf.h | 9 +++++++++ kernel/bpf/arraymap.c | 15 +++++++++++++++ kernel/bpf/core.c | 1 + kernel/bpf/hashtab.c | 32 ++++++++++++++++++++++++++++++++ kernel/bpf/helpers.c | 18 ++++++++++++++++++ kernel/bpf/verifier.c | 17 +++++++++++++++-- kernel/trace/bpf_trace.c | 2 ++ tools/include/uapi/linux/bpf.h | 9 +++++++++ 9 files changed, 103 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 3ded8711457f..5061ccd8b2dc 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -89,6 +89,7 @@ struct bpf_map_ops { int (*map_push_elem)(struct bpf_map *map, void *value, u64 flags); int (*map_pop_elem)(struct bpf_map *map, void *value); int (*map_peek_elem)(struct bpf_map *map, void *value); + void *(*map_lookup_percpu_elem)(struct bpf_map *map, void *key, u32 cpu); /* funcs called by prog_array and perf_event_array map */ void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file, @@ -2184,6 +2185,7 @@ extern const struct bpf_func_proto bpf_map_delete_elem_proto; extern const struct bpf_func_proto bpf_map_push_elem_proto; extern const struct bpf_func_proto bpf_map_pop_elem_proto; extern const struct bpf_func_proto bpf_map_peek_elem_proto; +extern const struct bpf_func_proto bpf_map_lookup_percpu_elem_proto; extern const struct bpf_func_proto bpf_get_prandom_u32_proto; extern const struct bpf_func_proto bpf_get_smp_processor_id_proto; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index bc7f89948f54..0210f85131b3 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5164,6 +5164,14 @@ union bpf_attr { * if not NULL, is a reference which must be released using its * corresponding release function, or moved into a BPF map before * program exit. + * + * void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu) + * Description + * Perform a lookup in *percpu map* for an entry associated to + * *key* on *cpu*. + * Return + * Map value associated to *key* on *cpu*, or **NULL** if no entry + * was found or *cpu* is invalid. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5361,6 +5369,7 @@ union bpf_attr { FN(skb_set_tstamp), \ FN(ima_file_hash), \ FN(kptr_xchg), \ + FN(map_lookup_percpu_elem), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 724613da6576..fe40d3b9458f 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -243,6 +243,20 @@ static void *percpu_array_map_lookup_elem(struct bpf_map *map, void *key) return this_cpu_ptr(array->pptrs[index & array->index_mask]); } +static void *percpu_array_map_lookup_percpu_elem(struct bpf_map *map, void *key, u32 cpu) +{ + struct bpf_array *array = container_of(map, struct bpf_array, map); + u32 index = *(u32 *)key; + + if (cpu >= nr_cpu_ids) + return NULL; + + if (unlikely(index >= array->map.max_entries)) + return NULL; + + return per_cpu_ptr(array->pptrs[index & array->index_mask], cpu); +} + int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value) { struct bpf_array *array = container_of(map, struct bpf_array, map); @@ -725,6 +739,7 @@ const struct bpf_map_ops percpu_array_map_ops = { .map_lookup_elem = percpu_array_map_lookup_elem, .map_update_elem = array_map_update_elem, .map_delete_elem = array_map_delete_elem, + .map_lookup_percpu_elem = percpu_array_map_lookup_percpu_elem, .map_seq_show_elem = percpu_array_map_seq_show_elem, .map_check_btf = array_map_check_btf, .map_lookup_batch = generic_map_lookup_batch, diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 13e9dbeeedf3..76f68d0a7ae8 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -2619,6 +2619,7 @@ const struct bpf_func_proto bpf_map_delete_elem_proto __weak; const struct bpf_func_proto bpf_map_push_elem_proto __weak; const struct bpf_func_proto bpf_map_pop_elem_proto __weak; const struct bpf_func_proto bpf_map_peek_elem_proto __weak; +const struct bpf_func_proto bpf_map_lookup_percpu_elem_proto __weak; const struct bpf_func_proto bpf_spin_lock_proto __weak; const struct bpf_func_proto bpf_spin_unlock_proto __weak; const struct bpf_func_proto bpf_jiffies64_proto __weak; diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index 705841279d16..17fb69c0e0dc 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -2199,6 +2199,20 @@ static void *htab_percpu_map_lookup_elem(struct bpf_map *map, void *key) return NULL; } +static void *htab_percpu_map_lookup_percpu_elem(struct bpf_map *map, void *key, u32 cpu) +{ + struct htab_elem *l; + + if (cpu >= nr_cpu_ids) + return NULL; + + l = __htab_map_lookup_elem(map, key); + if (l) + return per_cpu_ptr(htab_elem_get_ptr(l, map->key_size), cpu); + else + return NULL; +} + static void *htab_lru_percpu_map_lookup_elem(struct bpf_map *map, void *key) { struct htab_elem *l = __htab_map_lookup_elem(map, key); @@ -2211,6 +2225,22 @@ static void *htab_lru_percpu_map_lookup_elem(struct bpf_map *map, void *key) return NULL; } +static void *htab_lru_percpu_map_lookup_percpu_elem(struct bpf_map *map, void *key, u32 cpu) +{ + struct htab_elem *l; + + if (cpu >= nr_cpu_ids) + return NULL; + + l = __htab_map_lookup_elem(map, key); + if (l) { + bpf_lru_node_set_ref(&l->lru_node); + return per_cpu_ptr(htab_elem_get_ptr(l, map->key_size), cpu); + } + + return NULL; +} + int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value) { struct htab_elem *l; @@ -2300,6 +2330,7 @@ const struct bpf_map_ops htab_percpu_map_ops = { .map_lookup_and_delete_elem = htab_percpu_map_lookup_and_delete_elem, .map_update_elem = htab_percpu_map_update_elem, .map_delete_elem = htab_map_delete_elem, + .map_lookup_percpu_elem = htab_percpu_map_lookup_percpu_elem, .map_seq_show_elem = htab_percpu_map_seq_show_elem, .map_set_for_each_callback_args = map_set_for_each_callback_args, .map_for_each_callback = bpf_for_each_hash_elem, @@ -2318,6 +2349,7 @@ const struct bpf_map_ops htab_lru_percpu_map_ops = { .map_lookup_and_delete_elem = htab_lru_percpu_map_lookup_and_delete_elem, .map_update_elem = htab_lru_percpu_map_update_elem, .map_delete_elem = htab_lru_map_delete_elem, + .map_lookup_percpu_elem = htab_lru_percpu_map_lookup_percpu_elem, .map_seq_show_elem = htab_percpu_map_seq_show_elem, .map_set_for_each_callback_args = map_set_for_each_callback_args, .map_for_each_callback = bpf_for_each_hash_elem, diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 3e709fed5306..d5f104a39092 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -119,6 +119,22 @@ const struct bpf_func_proto bpf_map_peek_elem_proto = { .arg2_type = ARG_PTR_TO_UNINIT_MAP_VALUE, }; +BPF_CALL_3(bpf_map_lookup_percpu_elem, struct bpf_map *, map, void *, key, u32, cpu) +{ + WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); + return (unsigned long) map->ops->map_lookup_percpu_elem(map, key, cpu); +} + +const struct bpf_func_proto bpf_map_lookup_percpu_elem_proto = { + .func = bpf_map_lookup_percpu_elem, + .gpl_only = false, + .pkt_access = true, + .ret_type = RET_PTR_TO_MAP_VALUE_OR_NULL, + .arg1_type = ARG_CONST_MAP_PTR, + .arg2_type = ARG_PTR_TO_MAP_KEY, + .arg3_type = ARG_ANYTHING, +}; + const struct bpf_func_proto bpf_get_prandom_u32_proto = { .func = bpf_user_rnd_u32, .gpl_only = false, @@ -1420,6 +1436,8 @@ bpf_base_func_proto(enum bpf_func_id func_id) return &bpf_map_pop_elem_proto; case BPF_FUNC_map_peek_elem: return &bpf_map_peek_elem_proto; + case BPF_FUNC_map_lookup_percpu_elem: + return &bpf_map_lookup_percpu_elem_proto; case BPF_FUNC_get_prandom_u32: return &bpf_get_prandom_u32_proto; case BPF_FUNC_get_smp_processor_id: diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c27fee73a2cb..05c1b6656824 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6137,6 +6137,12 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, map->map_type != BPF_MAP_TYPE_BLOOM_FILTER) goto error; break; + case BPF_FUNC_map_lookup_percpu_elem: + if (map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY && + map->map_type != BPF_MAP_TYPE_PERCPU_HASH && + map->map_type != BPF_MAP_TYPE_LRU_PERCPU_HASH) + goto error; + break; case BPF_FUNC_sk_storage_get: case BPF_FUNC_sk_storage_delete: if (map->map_type != BPF_MAP_TYPE_SK_STORAGE) @@ -6750,7 +6756,8 @@ record_func_map(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, func_id != BPF_FUNC_map_pop_elem && func_id != BPF_FUNC_map_peek_elem && func_id != BPF_FUNC_for_each_map_elem && - func_id != BPF_FUNC_redirect_map) + func_id != BPF_FUNC_redirect_map && + func_id != BPF_FUNC_map_lookup_percpu_elem) return 0; if (map == NULL) { @@ -13810,7 +13817,8 @@ static int do_misc_fixups(struct bpf_verifier_env *env) insn->imm == BPF_FUNC_map_pop_elem || insn->imm == BPF_FUNC_map_peek_elem || insn->imm == BPF_FUNC_redirect_map || - insn->imm == BPF_FUNC_for_each_map_elem)) { + insn->imm == BPF_FUNC_for_each_map_elem || + insn->imm == BPF_FUNC_map_lookup_percpu_elem)) { aux = &env->insn_aux_data[i + delta]; if (bpf_map_ptr_poisoned(aux)) goto patch_call_imm; @@ -13859,6 +13867,8 @@ static int do_misc_fixups(struct bpf_verifier_env *env) bpf_callback_t callback_fn, void *callback_ctx, u64 flags))NULL)); + BUILD_BUG_ON(!__same_type(ops->map_lookup_percpu_elem, + (void *(*)(struct bpf_map *map, void *key, u32 cpu))NULL)); patch_map_ops_generic: switch (insn->imm) { @@ -13886,6 +13896,9 @@ patch_map_ops_generic: case BPF_FUNC_for_each_map_elem: insn->imm = BPF_CALL_IMM(ops->map_for_each_callback); continue; + case BPF_FUNC_map_lookup_percpu_elem: + insn->imm = BPF_CALL_IMM(ops->map_lookup_percpu_elem); + continue; } goto patch_call_imm; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 2eaac094caf8..7141ca8a1c2d 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1197,6 +1197,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_map_pop_elem_proto; case BPF_FUNC_map_peek_elem: return &bpf_map_peek_elem_proto; + case BPF_FUNC_map_lookup_percpu_elem: + return &bpf_map_lookup_percpu_elem_proto; case BPF_FUNC_ktime_get_ns: return &bpf_ktime_get_ns_proto; case BPF_FUNC_ktime_get_boot_ns: diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index bc7f89948f54..0210f85131b3 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5164,6 +5164,14 @@ union bpf_attr { * if not NULL, is a reference which must be released using its * corresponding release function, or moved into a BPF map before * program exit. + * + * void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu) + * Description + * Perform a lookup in *percpu map* for an entry associated to + * *key* on *cpu*. + * Return + * Map value associated to *key* on *cpu*, or **NULL** if no entry + * was found or *cpu* is invalid. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5361,6 +5369,7 @@ union bpf_attr { FN(skb_set_tstamp), \ FN(ima_file_hash), \ FN(kptr_xchg), \ + FN(map_lookup_percpu_elem), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From 89527be8d8d672773eeaec910118a6e84fb597e3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 13 May 2022 11:33:56 -0700 Subject: net: add IFLA_TSO_{MAX_SIZE|SEGS} attributes New netlink attributes IFLA_TSO_MAX_SIZE and IFLA_TSO_MAX_SEGS are used to report to user-space the device TSO limits. ip -d link sh dev eth1 ... tso_max_size 65536 tso_max_segs 65535 Signed-off-by: Eric Dumazet Acked-by: Alexander Duyck Signed-off-by: David S. Miller --- include/uapi/linux/if_link.h | 2 ++ net/core/rtnetlink.c | 6 ++++++ tools/include/uapi/linux/if_link.h | 2 ++ 3 files changed, 10 insertions(+) (limited to 'tools/include') diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index d1e600816b82..5f58dcfe2787 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -368,6 +368,8 @@ enum { IFLA_PARENT_DEV_NAME, IFLA_PARENT_DEV_BUS_NAME, IFLA_GRO_MAX_SIZE, + IFLA_TSO_MAX_SIZE, + IFLA_TSO_MAX_SEGS, __IFLA_MAX }; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index bdc891326102..f35cc21298ac 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1064,6 +1064,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, + nla_total_size(4) /* IFLA_GSO_MAX_SEGS */ + nla_total_size(4) /* IFLA_GSO_MAX_SIZE */ + nla_total_size(4) /* IFLA_GRO_MAX_SIZE */ + + nla_total_size(4) /* IFLA_TSO_MAX_SIZE */ + + nla_total_size(4) /* IFLA_TSO_MAX_SEGS */ + nla_total_size(1) /* IFLA_OPERSTATE */ + nla_total_size(1) /* IFLA_LINKMODE */ + nla_total_size(4) /* IFLA_CARRIER_CHANGES */ @@ -1769,6 +1771,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, nla_put_u32(skb, IFLA_GSO_MAX_SEGS, dev->gso_max_segs) || nla_put_u32(skb, IFLA_GSO_MAX_SIZE, dev->gso_max_size) || nla_put_u32(skb, IFLA_GRO_MAX_SIZE, dev->gro_max_size) || + nla_put_u32(skb, IFLA_TSO_MAX_SIZE, dev->tso_max_size) || + nla_put_u32(skb, IFLA_TSO_MAX_SEGS, dev->tso_max_segs) || #ifdef CONFIG_RPS nla_put_u32(skb, IFLA_NUM_RX_QUEUES, dev->num_rx_queues) || #endif @@ -1922,6 +1926,8 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_NEW_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 1), [IFLA_PARENT_DEV_NAME] = { .type = NLA_NUL_STRING }, [IFLA_GRO_MAX_SIZE] = { .type = NLA_U32 }, + [IFLA_TSO_MAX_SIZE] = { .type = NLA_REJECT }, + [IFLA_TSO_MAX_SEGS] = { .type = NLA_REJECT }, }; static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index e1ba2d51b717..b339bf2196ca 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -348,6 +348,8 @@ enum { IFLA_PARENT_DEV_NAME, IFLA_PARENT_DEV_BUS_NAME, IFLA_GRO_MAX_SIZE, + IFLA_TSO_MAX_SIZE, + IFLA_TSO_MAX_SEGS, __IFLA_MAX }; -- cgit From 3bc253c2e652cf5f12cd8c00d80d8ec55d67d1a7 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 19 May 2022 16:30:10 -0700 Subject: bpf: Add bpf_skc_to_mptcp_sock_proto This patch implements a new struct bpf_func_proto, named bpf_skc_to_mptcp_sock_proto. Define a new bpf_id BTF_SOCK_TYPE_MPTCP, and a new helper bpf_skc_to_mptcp_sock(), which invokes another new helper bpf_mptcp_sock_from_subflow() in net/mptcp/bpf.c to get struct mptcp_sock from a given subflow socket. v2: Emit BTF type, add func_id checks in verifier.c and bpf_trace.c, remove build check for CONFIG_BPF_JIT v5: Drop EXPORT_SYMBOL (Martin) Co-developed-by: Nicolas Rybowski Co-developed-by: Matthieu Baerts Signed-off-by: Nicolas Rybowski Signed-off-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20220519233016.105670-2-mathew.j.martineau@linux.intel.com --- include/linux/bpf.h | 1 + include/linux/btf_ids.h | 3 ++- include/net/mptcp.h | 6 ++++++ include/uapi/linux/bpf.h | 7 +++++++ kernel/bpf/verifier.c | 1 + kernel/trace/bpf_trace.c | 2 ++ net/core/filter.c | 18 ++++++++++++++++++ net/mptcp/Makefile | 2 ++ net/mptcp/bpf.c | 21 +++++++++++++++++++++ scripts/bpf_doc.py | 2 ++ tools/include/uapi/linux/bpf.h | 7 +++++++ 11 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 net/mptcp/bpf.c (limited to 'tools/include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index c107392b0ba7..a3ef078401cf 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2231,6 +2231,7 @@ extern const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto; extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto; extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto; extern const struct bpf_func_proto bpf_skc_to_unix_sock_proto; +extern const struct bpf_func_proto bpf_skc_to_mptcp_sock_proto; extern const struct bpf_func_proto bpf_copy_from_user_proto; extern const struct bpf_func_proto bpf_snprintf_btf_proto; extern const struct bpf_func_proto bpf_snprintf_proto; diff --git a/include/linux/btf_ids.h b/include/linux/btf_ids.h index bc5d9cc34e4c..335a19092368 100644 --- a/include/linux/btf_ids.h +++ b/include/linux/btf_ids.h @@ -178,7 +178,8 @@ extern struct btf_id_set name; BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP6, tcp6_sock) \ BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP, udp_sock) \ BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP6, udp6_sock) \ - BTF_SOCK_TYPE(BTF_SOCK_TYPE_UNIX, unix_sock) + BTF_SOCK_TYPE(BTF_SOCK_TYPE_UNIX, unix_sock) \ + BTF_SOCK_TYPE(BTF_SOCK_TYPE_MPTCP, mptcp_sock) enum { #define BTF_SOCK_TYPE(name, str) name, diff --git a/include/net/mptcp.h b/include/net/mptcp.h index 8b1afd6f5cc4..2ba09de955c7 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -284,4 +284,10 @@ static inline int mptcpv6_init(void) { return 0; } static inline void mptcpv6_handle_mapped(struct sock *sk, bool mapped) { } #endif +#if defined(CONFIG_MPTCP) && defined(CONFIG_BPF_SYSCALL) +struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk); +#else +static inline struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk) { return NULL; } +#endif + #endif /* __NET_MPTCP_H */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 0210f85131b3..56688bee20d9 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5172,6 +5172,12 @@ union bpf_attr { * Return * Map value associated to *key* on *cpu*, or **NULL** if no entry * was found or *cpu* is invalid. + * + * struct mptcp_sock *bpf_skc_to_mptcp_sock(void *sk) + * Description + * Dynamically cast a *sk* pointer to a *mptcp_sock* pointer. + * Return + * *sk* if casting is valid, or **NULL** otherwise. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5370,6 +5376,7 @@ union bpf_attr { FN(ima_file_hash), \ FN(kptr_xchg), \ FN(map_lookup_percpu_elem), \ + FN(skc_to_mptcp_sock), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9b59581026f8..14e8c17d3d8d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -509,6 +509,7 @@ static bool is_ptr_cast_function(enum bpf_func_id func_id) func_id == BPF_FUNC_skc_to_tcp_sock || func_id == BPF_FUNC_skc_to_tcp6_sock || func_id == BPF_FUNC_skc_to_udp6_sock || + func_id == BPF_FUNC_skc_to_mptcp_sock || func_id == BPF_FUNC_skc_to_tcp_timewait_sock || func_id == BPF_FUNC_skc_to_tcp_request_sock; } diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 7141ca8a1c2d..10b157a6d73e 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1705,6 +1705,8 @@ tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_skc_to_udp6_sock_proto; case BPF_FUNC_skc_to_unix_sock: return &bpf_skc_to_unix_sock_proto; + case BPF_FUNC_skc_to_mptcp_sock: + return &bpf_skc_to_mptcp_sock_proto; case BPF_FUNC_sk_storage_get: return &bpf_sk_storage_get_tracing_proto; case BPF_FUNC_sk_storage_delete: diff --git a/net/core/filter.c b/net/core/filter.c index fe0da529d00f..5af58eb48587 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -78,6 +78,7 @@ #include #include #include +#include static const struct bpf_func_proto * bpf_sk_base_func_proto(enum bpf_func_id func_id); @@ -11281,6 +11282,20 @@ const struct bpf_func_proto bpf_skc_to_unix_sock_proto = { .ret_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_UNIX], }; +BPF_CALL_1(bpf_skc_to_mptcp_sock, struct sock *, sk) +{ + BTF_TYPE_EMIT(struct mptcp_sock); + return (unsigned long)bpf_mptcp_sock_from_subflow(sk); +} + +const struct bpf_func_proto bpf_skc_to_mptcp_sock_proto = { + .func = bpf_skc_to_mptcp_sock, + .gpl_only = false, + .ret_type = RET_PTR_TO_BTF_ID_OR_NULL, + .arg1_type = ARG_PTR_TO_SOCK_COMMON, + .ret_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_MPTCP], +}; + BPF_CALL_1(bpf_sock_from_file, struct file *, file) { return (unsigned long)sock_from_file(file); @@ -11323,6 +11338,9 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id) case BPF_FUNC_skc_to_unix_sock: func = &bpf_skc_to_unix_sock_proto; break; + case BPF_FUNC_skc_to_mptcp_sock: + func = &bpf_skc_to_mptcp_sock_proto; + break; case BPF_FUNC_ktime_get_coarse_ns: return &bpf_ktime_get_coarse_ns_proto; default: diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile index e54daceac58b..99dddf08ca73 100644 --- a/net/mptcp/Makefile +++ b/net/mptcp/Makefile @@ -10,3 +10,5 @@ obj-$(CONFIG_INET_MPTCP_DIAG) += mptcp_diag.o mptcp_crypto_test-objs := crypto_test.o mptcp_token_test-objs := token_test.o obj-$(CONFIG_MPTCP_KUNIT_TEST) += mptcp_crypto_test.o mptcp_token_test.o + +obj-$(CONFIG_BPF_SYSCALL) += bpf.o diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c new file mode 100644 index 000000000000..5a0a84ad94af --- /dev/null +++ b/net/mptcp/bpf.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Multipath TCP + * + * Copyright (c) 2020, Tessares SA. + * Copyright (c) 2022, SUSE. + * + * Author: Nicolas Rybowski + */ + +#define pr_fmt(fmt) "MPTCP: " fmt + +#include +#include "protocol.h" + +struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk) +{ + if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk)) + return mptcp_sk(mptcp_subflow_ctx(sk)->conn); + + return NULL; +} diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index 096625242475..d5452f7eb996 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -633,6 +633,7 @@ class PrinterHelpers(Printer): 'struct socket', 'struct file', 'struct bpf_timer', + 'struct mptcp_sock', ] known_types = { '...', @@ -682,6 +683,7 @@ class PrinterHelpers(Printer): 'struct socket', 'struct file', 'struct bpf_timer', + 'struct mptcp_sock', } mapped_types = { 'u8': '__u8', diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 0210f85131b3..56688bee20d9 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5172,6 +5172,12 @@ union bpf_attr { * Return * Map value associated to *key* on *cpu*, or **NULL** if no entry * was found or *cpu* is invalid. + * + * struct mptcp_sock *bpf_skc_to_mptcp_sock(void *sk) + * Description + * Dynamically cast a *sk* pointer to a *mptcp_sock* pointer. + * Return + * *sk* if casting is valid, or **NULL** otherwise. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5370,6 +5376,7 @@ union bpf_attr { FN(ima_file_hash), \ FN(kptr_xchg), \ FN(map_lookup_percpu_elem), \ + FN(skc_to_mptcp_sock), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From 97e03f521050c092919591e668107b3d69c5f426 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Mon, 23 May 2022 14:07:07 -0700 Subject: bpf: Add verifier support for dynptrs This patch adds the bulk of the verifier work for supporting dynamic pointers (dynptrs) in bpf. A bpf_dynptr is opaque to the bpf program. It is a 16-byte structure defined internally as: struct bpf_dynptr_kern { void *data; u32 size; u32 offset; } __aligned(8); The upper 8 bits of *size* is reserved (it contains extra metadata about read-only status and dynptr type). Consequently, a dynptr only supports memory less than 16 MB. There are different types of dynptrs (eg malloc, ringbuf, ...). In this patchset, the most basic one, dynptrs to a bpf program's local memory, is added. For now only local memory that is of reg type PTR_TO_MAP_VALUE is supported. In the verifier, dynptr state information will be tracked in stack slots. When the program passes in an uninitialized dynptr (ARG_PTR_TO_DYNPTR | MEM_UNINIT), the stack slots corresponding to the frame pointer where the dynptr resides at are marked STACK_DYNPTR. For helper functions that take in initialized dynptrs (eg bpf_dynptr_read + bpf_dynptr_write which are added later in this patchset), the verifier enforces that the dynptr has been initialized properly by checking that their corresponding stack slots have been marked as STACK_DYNPTR. The 6th patch in this patchset adds test cases that the verifier should successfully reject, such as for example attempting to use a dynptr after doing a direct write into it inside the bpf program. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Acked-by: David Vernet Link: https://lore.kernel.org/bpf/20220523210712.3641569-2-joannelkoong@gmail.com --- include/linux/bpf.h | 28 ++++++ include/linux/bpf_verifier.h | 18 ++++ include/uapi/linux/bpf.h | 5 ++ kernel/bpf/verifier.c | 188 ++++++++++++++++++++++++++++++++++++++++- scripts/bpf_doc.py | 2 + tools/include/uapi/linux/bpf.h | 5 ++ 6 files changed, 243 insertions(+), 3 deletions(-) (limited to 'tools/include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index a9b1875212f6..b26c8176b9e0 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -392,10 +392,15 @@ enum bpf_type_flag { MEM_UNINIT = BIT(7 + BPF_BASE_TYPE_BITS), + /* DYNPTR points to memory local to the bpf program. */ + DYNPTR_TYPE_LOCAL = BIT(8 + BPF_BASE_TYPE_BITS), + __BPF_TYPE_FLAG_MAX, __BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1, }; +#define DYNPTR_TYPE_FLAG_MASK DYNPTR_TYPE_LOCAL + /* Max number of base types. */ #define BPF_BASE_TYPE_LIMIT (1UL << BPF_BASE_TYPE_BITS) @@ -438,6 +443,7 @@ enum bpf_arg_type { ARG_PTR_TO_CONST_STR, /* pointer to a null terminated read-only string */ ARG_PTR_TO_TIMER, /* pointer to bpf_timer */ ARG_PTR_TO_KPTR, /* pointer to referenced kptr */ + ARG_PTR_TO_DYNPTR, /* pointer to bpf_dynptr. See bpf_type_flag for dynptr type */ __BPF_ARG_TYPE_MAX, /* Extended arg_types. */ @@ -2376,4 +2382,26 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, u32 **bin_buf, u32 num_args); void bpf_bprintf_cleanup(void); +/* the implementation of the opaque uapi struct bpf_dynptr */ +struct bpf_dynptr_kern { + void *data; + /* Size represents the number of usable bytes of dynptr data. + * If for example the offset is at 4 for a local dynptr whose data is + * of type u64, the number of usable bytes is 4. + * + * The upper 8 bits are reserved. It is as follows: + * Bits 0 - 23 = size + * Bits 24 - 30 = dynptr type + * Bit 31 = whether dynptr is read-only + */ + u32 size; + u32 offset; +} __aligned(8); + +enum bpf_dynptr_type { + BPF_DYNPTR_TYPE_INVALID, + /* Points to memory that is local to the bpf program */ + BPF_DYNPTR_TYPE_LOCAL, +}; + #endif /* _LINUX_BPF_H */ diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 1f1e7f2ea967..af5b2135215e 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -72,6 +72,18 @@ struct bpf_reg_state { u32 mem_size; /* for PTR_TO_MEM | PTR_TO_MEM_OR_NULL */ + /* For dynptr stack slots */ + struct { + enum bpf_dynptr_type type; + /* A dynptr is 16 bytes so it takes up 2 stack slots. + * We need to track which slot is the first slot + * to protect against cases where the user may try to + * pass in an address starting at the second slot of the + * dynptr. + */ + bool first_slot; + } dynptr; + /* Max size from any of the above. */ struct { unsigned long raw1; @@ -174,9 +186,15 @@ enum bpf_stack_slot_type { STACK_SPILL, /* register spilled into stack */ STACK_MISC, /* BPF program wrote some data into this slot */ STACK_ZERO, /* BPF program wrote constant zero */ + /* A dynptr is stored in this stack slot. The type of dynptr + * is stored in bpf_stack_state->spilled_ptr.dynptr.type + */ + STACK_DYNPTR, }; #define BPF_REG_SIZE 8 /* size of eBPF register in bytes */ +#define BPF_DYNPTR_SIZE sizeof(struct bpf_dynptr_kern) +#define BPF_DYNPTR_NR_SLOTS (BPF_DYNPTR_SIZE / BPF_REG_SIZE) struct bpf_stack_state { struct bpf_reg_state spilled_ptr; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 56688bee20d9..610944cb3389 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -6528,6 +6528,11 @@ struct bpf_timer { __u64 :64; } __attribute__((aligned(8))); +struct bpf_dynptr { + __u64 :64; + __u64 :64; +} __attribute__((aligned(8))); + struct bpf_sysctl { __u32 write; /* Sysctl is being read (= 0) or written (= 1). * Allows 1,2,4-byte read, but no write. diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 45153cbc2bd6..1fd0b81c3fec 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -259,6 +259,7 @@ struct bpf_call_arg_meta { u32 ret_btf_id; u32 subprogno; struct bpf_map_value_off_desc *kptr_off_desc; + u8 uninit_dynptr_regno; }; struct btf *btf_vmlinux; @@ -581,6 +582,7 @@ static char slot_type_char[] = { [STACK_SPILL] = 'r', [STACK_MISC] = 'm', [STACK_ZERO] = '0', + [STACK_DYNPTR] = 'd', }; static void print_liveness(struct bpf_verifier_env *env, @@ -596,6 +598,25 @@ static void print_liveness(struct bpf_verifier_env *env, verbose(env, "D"); } +static int get_spi(s32 off) +{ + return (-off - 1) / BPF_REG_SIZE; +} + +static bool is_spi_bounds_valid(struct bpf_func_state *state, int spi, int nr_slots) +{ + int allocated_slots = state->allocated_stack / BPF_REG_SIZE; + + /* We need to check that slots between [spi - nr_slots + 1, spi] are + * within [0, allocated_stack). + * + * Please note that the spi grows downwards. For example, a dynptr + * takes the size of two stack slots; the first slot will be at + * spi and the second slot will be at spi - 1. + */ + return spi - nr_slots + 1 >= 0 && spi < allocated_slots; +} + static struct bpf_func_state *func(struct bpf_verifier_env *env, const struct bpf_reg_state *reg) { @@ -647,6 +668,108 @@ static void mark_verifier_state_scratched(struct bpf_verifier_env *env) env->scratched_stack_slots = ~0ULL; } +static enum bpf_dynptr_type arg_to_dynptr_type(enum bpf_arg_type arg_type) +{ + switch (arg_type & DYNPTR_TYPE_FLAG_MASK) { + case DYNPTR_TYPE_LOCAL: + return BPF_DYNPTR_TYPE_LOCAL; + default: + return BPF_DYNPTR_TYPE_INVALID; + } +} + +static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg, + enum bpf_arg_type arg_type, int insn_idx) +{ + struct bpf_func_state *state = func(env, reg); + enum bpf_dynptr_type type; + int spi, i; + + spi = get_spi(reg->off); + + if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) + return -EINVAL; + + for (i = 0; i < BPF_REG_SIZE; i++) { + state->stack[spi].slot_type[i] = STACK_DYNPTR; + state->stack[spi - 1].slot_type[i] = STACK_DYNPTR; + } + + type = arg_to_dynptr_type(arg_type); + if (type == BPF_DYNPTR_TYPE_INVALID) + return -EINVAL; + + state->stack[spi].spilled_ptr.dynptr.first_slot = true; + state->stack[spi].spilled_ptr.dynptr.type = type; + state->stack[spi - 1].spilled_ptr.dynptr.type = type; + + return 0; +} + +static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +{ + struct bpf_func_state *state = func(env, reg); + int spi, i; + + spi = get_spi(reg->off); + + if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) + return -EINVAL; + + for (i = 0; i < BPF_REG_SIZE; i++) { + state->stack[spi].slot_type[i] = STACK_INVALID; + state->stack[spi - 1].slot_type[i] = STACK_INVALID; + } + + state->stack[spi].spilled_ptr.dynptr.first_slot = false; + state->stack[spi].spilled_ptr.dynptr.type = 0; + state->stack[spi - 1].spilled_ptr.dynptr.type = 0; + + return 0; +} + +static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +{ + struct bpf_func_state *state = func(env, reg); + int spi = get_spi(reg->off); + int i; + + if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) + return true; + + for (i = 0; i < BPF_REG_SIZE; i++) { + if (state->stack[spi].slot_type[i] == STACK_DYNPTR || + state->stack[spi - 1].slot_type[i] == STACK_DYNPTR) + return false; + } + + return true; +} + +static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg, + enum bpf_arg_type arg_type) +{ + struct bpf_func_state *state = func(env, reg); + int spi = get_spi(reg->off); + int i; + + if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS) || + !state->stack[spi].spilled_ptr.dynptr.first_slot) + return false; + + for (i = 0; i < BPF_REG_SIZE; i++) { + if (state->stack[spi].slot_type[i] != STACK_DYNPTR || + state->stack[spi - 1].slot_type[i] != STACK_DYNPTR) + return false; + } + + /* ARG_PTR_TO_DYNPTR takes any type of dynptr */ + if (arg_type == ARG_PTR_TO_DYNPTR) + return true; + + return state->stack[spi].spilled_ptr.dynptr.type == arg_to_dynptr_type(arg_type); +} + /* The reg state of a pointer or a bounded scalar was saved when * it was spilled to the stack. */ @@ -5400,6 +5523,11 @@ static bool arg_type_is_release(enum bpf_arg_type type) return type & OBJ_RELEASE; } +static bool arg_type_is_dynptr(enum bpf_arg_type type) +{ + return base_type(type) == ARG_PTR_TO_DYNPTR; +} + static int int_ptr_type_to_size(enum bpf_arg_type type) { if (type == ARG_PTR_TO_INT) @@ -5539,6 +5667,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_PTR_TO_CONST_STR] = &const_str_ptr_types, [ARG_PTR_TO_TIMER] = &timer_types, [ARG_PTR_TO_KPTR] = &kptr_types, + [ARG_PTR_TO_DYNPTR] = &stack_ptr_types, }; static int check_reg_type(struct bpf_verifier_env *env, u32 regno, @@ -5628,8 +5757,13 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env, bool fixed_off_ok = false; switch ((u32)type) { - case SCALAR_VALUE: /* Pointer types where reg offset is explicitly allowed: */ + case PTR_TO_STACK: + if (arg_type_is_dynptr(arg_type) && reg->off % BPF_REG_SIZE) { + verbose(env, "cannot pass in dynptr at an offset\n"); + return -EINVAL; + } + fallthrough; case PTR_TO_PACKET: case PTR_TO_PACKET_META: case PTR_TO_MAP_KEY: @@ -5639,7 +5773,7 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env, case PTR_TO_MEM | MEM_ALLOC: case PTR_TO_BUF: case PTR_TO_BUF | MEM_RDONLY: - case PTR_TO_STACK: + case SCALAR_VALUE: /* Some of the argument types nevertheless require a * zero register offset. */ @@ -5837,6 +5971,36 @@ skip_type_check: bool zero_size_allowed = (arg_type == ARG_CONST_SIZE_OR_ZERO); err = check_mem_size_reg(env, reg, regno, zero_size_allowed, meta); + } else if (arg_type_is_dynptr(arg_type)) { + if (arg_type & MEM_UNINIT) { + if (!is_dynptr_reg_valid_uninit(env, reg)) { + verbose(env, "Dynptr has to be an uninitialized dynptr\n"); + return -EINVAL; + } + + /* We only support one dynptr being uninitialized at the moment, + * which is sufficient for the helper functions we have right now. + */ + if (meta->uninit_dynptr_regno) { + verbose(env, "verifier internal error: multiple uninitialized dynptr args\n"); + return -EFAULT; + } + + meta->uninit_dynptr_regno = regno; + } else if (!is_dynptr_reg_valid_init(env, reg, arg_type)) { + const char *err_extra = ""; + + switch (arg_type & DYNPTR_TYPE_FLAG_MASK) { + case DYNPTR_TYPE_LOCAL: + err_extra = "local "; + break; + default: + break; + } + verbose(env, "Expected an initialized %sdynptr as arg #%d\n", + err_extra, arg + 1); + return -EINVAL; + } } else if (arg_type_is_alloc_size(arg_type)) { if (!tnum_is_const(reg->var_off)) { verbose(env, "R%d is not a known constant'\n", @@ -6970,9 +7134,27 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn regs = cur_regs(env); + if (meta.uninit_dynptr_regno) { + /* we write BPF_DW bits (8 bytes) at a time */ + for (i = 0; i < BPF_DYNPTR_SIZE; i += 8) { + err = check_mem_access(env, insn_idx, meta.uninit_dynptr_regno, + i, BPF_DW, BPF_WRITE, -1, false); + if (err) + return err; + } + + err = mark_stack_slots_dynptr(env, ®s[meta.uninit_dynptr_regno], + fn->arg_type[meta.uninit_dynptr_regno - BPF_REG_1], + insn_idx); + if (err) + return err; + } + if (meta.release_regno) { err = -EINVAL; - if (meta.ref_obj_id) + if (arg_type_is_dynptr(fn->arg_type[meta.release_regno - BPF_REG_1])) + err = unmark_stack_slots_dynptr(env, ®s[meta.release_regno]); + else if (meta.ref_obj_id) err = release_reference(env, meta.ref_obj_id); /* meta.ref_obj_id can only be 0 if register that is meant to be * released is NULL, which must be > R0. diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index d5452f7eb996..855b937e7585 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -634,6 +634,7 @@ class PrinterHelpers(Printer): 'struct file', 'struct bpf_timer', 'struct mptcp_sock', + 'struct bpf_dynptr', ] known_types = { '...', @@ -684,6 +685,7 @@ class PrinterHelpers(Printer): 'struct file', 'struct bpf_timer', 'struct mptcp_sock', + 'struct bpf_dynptr', } mapped_types = { 'u8': '__u8', diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 56688bee20d9..610944cb3389 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -6528,6 +6528,11 @@ struct bpf_timer { __u64 :64; } __attribute__((aligned(8))); +struct bpf_dynptr { + __u64 :64; + __u64 :64; +} __attribute__((aligned(8))); + struct bpf_sysctl { __u32 write; /* Sysctl is being read (= 0) or written (= 1). * Allows 1,2,4-byte read, but no write. -- cgit From 263ae152e96253f40c2c276faad8629e096b3bad Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Mon, 23 May 2022 14:07:08 -0700 Subject: bpf: Add bpf_dynptr_from_mem for local dynptrs This patch adds a new api bpf_dynptr_from_mem: long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr); which initializes a dynptr to point to a bpf program's local memory. For now only local memory that is of reg type PTR_TO_MAP_VALUE is supported. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20220523210712.3641569-3-joannelkoong@gmail.com --- include/uapi/linux/bpf.h | 12 ++++++++ kernel/bpf/helpers.c | 65 ++++++++++++++++++++++++++++++++++++++++++ kernel/bpf/verifier.c | 6 ++++ tools/include/uapi/linux/bpf.h | 12 ++++++++ 4 files changed, 95 insertions(+) (limited to 'tools/include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 610944cb3389..9be3644457dd 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5178,6 +5178,17 @@ union bpf_attr { * Dynamically cast a *sk* pointer to a *mptcp_sock* pointer. * Return * *sk* if casting is valid, or **NULL** otherwise. + * + * long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr) + * Description + * Get a dynptr to local memory *data*. + * + * *data* must be a ptr to a map value. + * The maximum *size* supported is DYNPTR_MAX_SIZE. + * *flags* is currently unused. + * Return + * 0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE, + * -EINVAL if flags is not 0. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5377,6 +5388,7 @@ union bpf_attr { FN(kptr_xchg), \ FN(map_lookup_percpu_elem), \ FN(skc_to_mptcp_sock), \ + FN(dynptr_from_mem), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index bad96131a510..d3e935c2e25e 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1412,6 +1412,69 @@ const struct bpf_func_proto bpf_kptr_xchg_proto = { .arg2_btf_id = BPF_PTR_POISON, }; +/* Since the upper 8 bits of dynptr->size is reserved, the + * maximum supported size is 2^24 - 1. + */ +#define DYNPTR_MAX_SIZE ((1UL << 24) - 1) +#define DYNPTR_TYPE_SHIFT 28 + +static void bpf_dynptr_set_type(struct bpf_dynptr_kern *ptr, enum bpf_dynptr_type type) +{ + ptr->size |= type << DYNPTR_TYPE_SHIFT; +} + +static int bpf_dynptr_check_size(u32 size) +{ + return size > DYNPTR_MAX_SIZE ? -E2BIG : 0; +} + +static void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data, + enum bpf_dynptr_type type, u32 offset, u32 size) +{ + ptr->data = data; + ptr->offset = offset; + ptr->size = size; + bpf_dynptr_set_type(ptr, type); +} + +static void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr) +{ + memset(ptr, 0, sizeof(*ptr)); +} + +BPF_CALL_4(bpf_dynptr_from_mem, void *, data, u32, size, u64, flags, struct bpf_dynptr_kern *, ptr) +{ + int err; + + err = bpf_dynptr_check_size(size); + if (err) + goto error; + + /* flags is currently unsupported */ + if (flags) { + err = -EINVAL; + goto error; + } + + bpf_dynptr_init(ptr, data, BPF_DYNPTR_TYPE_LOCAL, 0, size); + + return 0; + +error: + bpf_dynptr_set_null(ptr); + return err; +} + +const struct bpf_func_proto bpf_dynptr_from_mem_proto = { + .func = bpf_dynptr_from_mem, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_UNINIT_MEM, + .arg2_type = ARG_CONST_SIZE_OR_ZERO, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT, +}; + const struct bpf_func_proto bpf_get_current_task_proto __weak; const struct bpf_func_proto bpf_get_current_task_btf_proto __weak; const struct bpf_func_proto bpf_probe_read_user_proto __weak; @@ -1466,6 +1529,8 @@ bpf_base_func_proto(enum bpf_func_id func_id) return &bpf_loop_proto; case BPF_FUNC_strncmp: return &bpf_strncmp_proto; + case BPF_FUNC_dynptr_from_mem: + return &bpf_dynptr_from_mem_proto; default: break; } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 1fd0b81c3fec..b657d46f886e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -7204,6 +7204,12 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, set_loop_callback_state); break; + case BPF_FUNC_dynptr_from_mem: + if (regs[BPF_REG_1].type != PTR_TO_MAP_VALUE) { + verbose(env, "Unsupported reg type %s for bpf_dynptr_from_mem data\n", + reg_type_str(env, regs[BPF_REG_1].type)); + return -EACCES; + } } if (err) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 610944cb3389..9be3644457dd 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5178,6 +5178,17 @@ union bpf_attr { * Dynamically cast a *sk* pointer to a *mptcp_sock* pointer. * Return * *sk* if casting is valid, or **NULL** otherwise. + * + * long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr) + * Description + * Get a dynptr to local memory *data*. + * + * *data* must be a ptr to a map value. + * The maximum *size* supported is DYNPTR_MAX_SIZE. + * *flags* is currently unused. + * Return + * 0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE, + * -EINVAL if flags is not 0. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5377,6 +5388,7 @@ union bpf_attr { FN(kptr_xchg), \ FN(map_lookup_percpu_elem), \ FN(skc_to_mptcp_sock), \ + FN(dynptr_from_mem), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From bc34dee65a65e9c920c420005b8a43f2a721a458 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Mon, 23 May 2022 14:07:09 -0700 Subject: bpf: Dynptr support for ring buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, our only way of writing dynamically-sized data into a ring buffer is through bpf_ringbuf_output but this incurs an extra memcpy cost. bpf_ringbuf_reserve + bpf_ringbuf_commit avoids this extra memcpy, but it can only safely support reservation sizes that are statically known since the verifier cannot guarantee that the bpf program won’t access memory outside the reserved space. The bpf_dynptr abstraction allows for dynamically-sized ring buffer reservations without the extra memcpy. There are 3 new APIs: long bpf_ringbuf_reserve_dynptr(void *ringbuf, u32 size, u64 flags, struct bpf_dynptr *ptr); void bpf_ringbuf_submit_dynptr(struct bpf_dynptr *ptr, u64 flags); void bpf_ringbuf_discard_dynptr(struct bpf_dynptr *ptr, u64 flags); These closely follow the functionalities of the original ringbuf APIs. For example, all ringbuffer dynptrs that have been reserved must be either submitted or discarded before the program exits. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Acked-by: David Vernet Link: https://lore.kernel.org/bpf/20220523210712.3641569-4-joannelkoong@gmail.com --- include/linux/bpf.h | 15 +++++++- include/linux/bpf_verifier.h | 2 ++ include/uapi/linux/bpf.h | 35 +++++++++++++++++++ kernel/bpf/helpers.c | 14 +++++--- kernel/bpf/ringbuf.c | 78 ++++++++++++++++++++++++++++++++++++++++++ kernel/bpf/verifier.c | 52 ++++++++++++++++++++++++++-- tools/include/uapi/linux/bpf.h | 35 +++++++++++++++++++ 7 files changed, 223 insertions(+), 8 deletions(-) (limited to 'tools/include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index b26c8176b9e0..c72321b6f306 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -395,11 +395,14 @@ enum bpf_type_flag { /* DYNPTR points to memory local to the bpf program. */ DYNPTR_TYPE_LOCAL = BIT(8 + BPF_BASE_TYPE_BITS), + /* DYNPTR points to a ringbuf record. */ + DYNPTR_TYPE_RINGBUF = BIT(9 + BPF_BASE_TYPE_BITS), + __BPF_TYPE_FLAG_MAX, __BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1, }; -#define DYNPTR_TYPE_FLAG_MASK DYNPTR_TYPE_LOCAL +#define DYNPTR_TYPE_FLAG_MASK (DYNPTR_TYPE_LOCAL | DYNPTR_TYPE_RINGBUF) /* Max number of base types. */ #define BPF_BASE_TYPE_LIMIT (1UL << BPF_BASE_TYPE_BITS) @@ -2231,6 +2234,9 @@ extern const struct bpf_func_proto bpf_ringbuf_reserve_proto; extern const struct bpf_func_proto bpf_ringbuf_submit_proto; extern const struct bpf_func_proto bpf_ringbuf_discard_proto; extern const struct bpf_func_proto bpf_ringbuf_query_proto; +extern const struct bpf_func_proto bpf_ringbuf_reserve_dynptr_proto; +extern const struct bpf_func_proto bpf_ringbuf_submit_dynptr_proto; +extern const struct bpf_func_proto bpf_ringbuf_discard_dynptr_proto; extern const struct bpf_func_proto bpf_skc_to_tcp6_sock_proto; extern const struct bpf_func_proto bpf_skc_to_tcp_sock_proto; extern const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto; @@ -2402,6 +2408,13 @@ enum bpf_dynptr_type { BPF_DYNPTR_TYPE_INVALID, /* Points to memory that is local to the bpf program */ BPF_DYNPTR_TYPE_LOCAL, + /* Underlying data is a ringbuf record */ + BPF_DYNPTR_TYPE_RINGBUF, }; +void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data, + enum bpf_dynptr_type type, u32 offset, u32 size); +void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr); +int bpf_dynptr_check_size(u32 size); + #endif /* _LINUX_BPF_H */ diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index af5b2135215e..e8439f6cbe57 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -100,6 +100,8 @@ struct bpf_reg_state { * for the purpose of tracking that it's freed. * For PTR_TO_SOCKET this is used to share which pointers retain the * same reference to the socket, to determine proper reference freeing. + * For stack slots that are dynptrs, this is used to track references to + * the dynptr to determine proper reference freeing. */ u32 id; /* PTR_TO_SOCKET and PTR_TO_TCP_SOCK could be a ptr returned diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 9be3644457dd..081a55540aa5 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5189,6 +5189,38 @@ union bpf_attr { * Return * 0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE, * -EINVAL if flags is not 0. + * + * long bpf_ringbuf_reserve_dynptr(void *ringbuf, u32 size, u64 flags, struct bpf_dynptr *ptr) + * Description + * Reserve *size* bytes of payload in a ring buffer *ringbuf* + * through the dynptr interface. *flags* must be 0. + * + * Please note that a corresponding bpf_ringbuf_submit_dynptr or + * bpf_ringbuf_discard_dynptr must be called on *ptr*, even if the + * reservation fails. This is enforced by the verifier. + * Return + * 0 on success, or a negative error in case of failure. + * + * void bpf_ringbuf_submit_dynptr(struct bpf_dynptr *ptr, u64 flags) + * Description + * Submit reserved ring buffer sample, pointed to by *data*, + * through the dynptr interface. This is a no-op if the dynptr is + * invalid/null. + * + * For more information on *flags*, please see + * 'bpf_ringbuf_submit'. + * Return + * Nothing. Always succeeds. + * + * void bpf_ringbuf_discard_dynptr(struct bpf_dynptr *ptr, u64 flags) + * Description + * Discard reserved ring buffer sample through the dynptr + * interface. This is a no-op if the dynptr is invalid/null. + * + * For more information on *flags*, please see + * 'bpf_ringbuf_discard'. + * Return + * Nothing. Always succeeds. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5389,6 +5421,9 @@ union bpf_attr { FN(map_lookup_percpu_elem), \ FN(skc_to_mptcp_sock), \ FN(dynptr_from_mem), \ + FN(ringbuf_reserve_dynptr), \ + FN(ringbuf_submit_dynptr), \ + FN(ringbuf_discard_dynptr), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index d3e935c2e25e..abb08999ff56 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1423,13 +1423,13 @@ static void bpf_dynptr_set_type(struct bpf_dynptr_kern *ptr, enum bpf_dynptr_typ ptr->size |= type << DYNPTR_TYPE_SHIFT; } -static int bpf_dynptr_check_size(u32 size) +int bpf_dynptr_check_size(u32 size) { return size > DYNPTR_MAX_SIZE ? -E2BIG : 0; } -static void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data, - enum bpf_dynptr_type type, u32 offset, u32 size) +void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data, + enum bpf_dynptr_type type, u32 offset, u32 size) { ptr->data = data; ptr->offset = offset; @@ -1437,7 +1437,7 @@ static void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data, bpf_dynptr_set_type(ptr, type); } -static void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr) +void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr) { memset(ptr, 0, sizeof(*ptr)); } @@ -1523,6 +1523,12 @@ bpf_base_func_proto(enum bpf_func_id func_id) return &bpf_ringbuf_discard_proto; case BPF_FUNC_ringbuf_query: return &bpf_ringbuf_query_proto; + case BPF_FUNC_ringbuf_reserve_dynptr: + return &bpf_ringbuf_reserve_dynptr_proto; + case BPF_FUNC_ringbuf_submit_dynptr: + return &bpf_ringbuf_submit_dynptr_proto; + case BPF_FUNC_ringbuf_discard_dynptr: + return &bpf_ringbuf_discard_dynptr_proto; case BPF_FUNC_for_each_map_elem: return &bpf_for_each_map_elem_proto; case BPF_FUNC_loop: diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c index 311264ab80c4..ded4faeca192 100644 --- a/kernel/bpf/ringbuf.c +++ b/kernel/bpf/ringbuf.c @@ -475,3 +475,81 @@ const struct bpf_func_proto bpf_ringbuf_query_proto = { .arg1_type = ARG_CONST_MAP_PTR, .arg2_type = ARG_ANYTHING, }; + +BPF_CALL_4(bpf_ringbuf_reserve_dynptr, struct bpf_map *, map, u32, size, u64, flags, + struct bpf_dynptr_kern *, ptr) +{ + struct bpf_ringbuf_map *rb_map; + void *sample; + int err; + + if (unlikely(flags)) { + bpf_dynptr_set_null(ptr); + return -EINVAL; + } + + err = bpf_dynptr_check_size(size); + if (err) { + bpf_dynptr_set_null(ptr); + return err; + } + + rb_map = container_of(map, struct bpf_ringbuf_map, map); + + sample = __bpf_ringbuf_reserve(rb_map->rb, size); + if (!sample) { + bpf_dynptr_set_null(ptr); + return -EINVAL; + } + + bpf_dynptr_init(ptr, sample, BPF_DYNPTR_TYPE_RINGBUF, 0, size); + + return 0; +} + +const struct bpf_func_proto bpf_ringbuf_reserve_dynptr_proto = { + .func = bpf_ringbuf_reserve_dynptr, + .ret_type = RET_INTEGER, + .arg1_type = ARG_CONST_MAP_PTR, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT, +}; + +BPF_CALL_2(bpf_ringbuf_submit_dynptr, struct bpf_dynptr_kern *, ptr, u64, flags) +{ + if (!ptr->data) + return 0; + + bpf_ringbuf_commit(ptr->data, flags, false /* discard */); + + bpf_dynptr_set_null(ptr); + + return 0; +} + +const struct bpf_func_proto bpf_ringbuf_submit_dynptr_proto = { + .func = bpf_ringbuf_submit_dynptr, + .ret_type = RET_VOID, + .arg1_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | OBJ_RELEASE, + .arg2_type = ARG_ANYTHING, +}; + +BPF_CALL_2(bpf_ringbuf_discard_dynptr, struct bpf_dynptr_kern *, ptr, u64, flags) +{ + if (!ptr->data) + return 0; + + bpf_ringbuf_commit(ptr->data, flags, true /* discard */); + + bpf_dynptr_set_null(ptr); + + return 0; +} + +const struct bpf_func_proto bpf_ringbuf_discard_dynptr_proto = { + .func = bpf_ringbuf_discard_dynptr, + .ret_type = RET_VOID, + .arg1_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | OBJ_RELEASE, + .arg2_type = ARG_ANYTHING, +}; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b657d46f886e..8be140351966 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -187,6 +187,9 @@ struct bpf_verifier_stack_elem { POISON_POINTER_DELTA)) #define BPF_MAP_PTR(X) ((struct bpf_map *)((X) & ~BPF_MAP_PTR_UNPRIV)) +static int acquire_reference_state(struct bpf_verifier_env *env, int insn_idx); +static int release_reference(struct bpf_verifier_env *env, int ref_obj_id); + static bool bpf_map_ptr_poisoned(const struct bpf_insn_aux_data *aux) { return BPF_MAP_PTR(aux->map_ptr_state) == BPF_MAP_PTR_POISON; @@ -673,17 +676,24 @@ static enum bpf_dynptr_type arg_to_dynptr_type(enum bpf_arg_type arg_type) switch (arg_type & DYNPTR_TYPE_FLAG_MASK) { case DYNPTR_TYPE_LOCAL: return BPF_DYNPTR_TYPE_LOCAL; + case DYNPTR_TYPE_RINGBUF: + return BPF_DYNPTR_TYPE_RINGBUF; default: return BPF_DYNPTR_TYPE_INVALID; } } +static bool dynptr_type_refcounted(enum bpf_dynptr_type type) +{ + return type == BPF_DYNPTR_TYPE_RINGBUF; +} + static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg, enum bpf_arg_type arg_type, int insn_idx) { struct bpf_func_state *state = func(env, reg); enum bpf_dynptr_type type; - int spi, i; + int spi, i, id; spi = get_spi(reg->off); @@ -703,6 +713,16 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_ state->stack[spi].spilled_ptr.dynptr.type = type; state->stack[spi - 1].spilled_ptr.dynptr.type = type; + if (dynptr_type_refcounted(type)) { + /* The id is used to track proper releasing */ + id = acquire_reference_state(env, insn_idx); + if (id < 0) + return id; + + state->stack[spi].spilled_ptr.id = id; + state->stack[spi - 1].spilled_ptr.id = id; + } + return 0; } @@ -721,6 +741,13 @@ static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_re state->stack[spi - 1].slot_type[i] = STACK_INVALID; } + /* Invalidate any slices associated with this dynptr */ + if (dynptr_type_refcounted(state->stack[spi].spilled_ptr.dynptr.type)) { + release_reference(env, state->stack[spi].spilled_ptr.id); + state->stack[spi].spilled_ptr.id = 0; + state->stack[spi - 1].spilled_ptr.id = 0; + } + state->stack[spi].spilled_ptr.dynptr.first_slot = false; state->stack[spi].spilled_ptr.dynptr.type = 0; state->stack[spi - 1].spilled_ptr.dynptr.type = 0; @@ -5859,7 +5886,16 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, skip_type_check: if (arg_type_is_release(arg_type)) { - if (!reg->ref_obj_id && !register_is_null(reg)) { + if (arg_type_is_dynptr(arg_type)) { + struct bpf_func_state *state = func(env, reg); + int spi = get_spi(reg->off); + + if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS) || + !state->stack[spi].spilled_ptr.id) { + verbose(env, "arg %d is an unacquired reference\n", regno); + return -EINVAL; + } + } else if (!reg->ref_obj_id && !register_is_null(reg)) { verbose(env, "R%d must be referenced when passed to release function\n", regno); return -EINVAL; @@ -5994,9 +6030,13 @@ skip_type_check: case DYNPTR_TYPE_LOCAL: err_extra = "local "; break; + case DYNPTR_TYPE_RINGBUF: + err_extra = "ringbuf "; + break; default: break; } + verbose(env, "Expected an initialized %sdynptr as arg #%d\n", err_extra, arg + 1); return -EINVAL; @@ -6122,7 +6162,10 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, case BPF_MAP_TYPE_RINGBUF: if (func_id != BPF_FUNC_ringbuf_output && func_id != BPF_FUNC_ringbuf_reserve && - func_id != BPF_FUNC_ringbuf_query) + func_id != BPF_FUNC_ringbuf_query && + func_id != BPF_FUNC_ringbuf_reserve_dynptr && + func_id != BPF_FUNC_ringbuf_submit_dynptr && + func_id != BPF_FUNC_ringbuf_discard_dynptr) goto error; break; case BPF_MAP_TYPE_STACK_TRACE: @@ -6238,6 +6281,9 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, case BPF_FUNC_ringbuf_output: case BPF_FUNC_ringbuf_reserve: case BPF_FUNC_ringbuf_query: + case BPF_FUNC_ringbuf_reserve_dynptr: + case BPF_FUNC_ringbuf_submit_dynptr: + case BPF_FUNC_ringbuf_discard_dynptr: if (map->map_type != BPF_MAP_TYPE_RINGBUF) goto error; break; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 9be3644457dd..081a55540aa5 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5189,6 +5189,38 @@ union bpf_attr { * Return * 0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE, * -EINVAL if flags is not 0. + * + * long bpf_ringbuf_reserve_dynptr(void *ringbuf, u32 size, u64 flags, struct bpf_dynptr *ptr) + * Description + * Reserve *size* bytes of payload in a ring buffer *ringbuf* + * through the dynptr interface. *flags* must be 0. + * + * Please note that a corresponding bpf_ringbuf_submit_dynptr or + * bpf_ringbuf_discard_dynptr must be called on *ptr*, even if the + * reservation fails. This is enforced by the verifier. + * Return + * 0 on success, or a negative error in case of failure. + * + * void bpf_ringbuf_submit_dynptr(struct bpf_dynptr *ptr, u64 flags) + * Description + * Submit reserved ring buffer sample, pointed to by *data*, + * through the dynptr interface. This is a no-op if the dynptr is + * invalid/null. + * + * For more information on *flags*, please see + * 'bpf_ringbuf_submit'. + * Return + * Nothing. Always succeeds. + * + * void bpf_ringbuf_discard_dynptr(struct bpf_dynptr *ptr, u64 flags) + * Description + * Discard reserved ring buffer sample through the dynptr + * interface. This is a no-op if the dynptr is invalid/null. + * + * For more information on *flags*, please see + * 'bpf_ringbuf_discard'. + * Return + * Nothing. Always succeeds. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5389,6 +5421,9 @@ union bpf_attr { FN(map_lookup_percpu_elem), \ FN(skc_to_mptcp_sock), \ FN(dynptr_from_mem), \ + FN(ringbuf_reserve_dynptr), \ + FN(ringbuf_submit_dynptr), \ + FN(ringbuf_discard_dynptr), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From 13bbbfbea7598ea9f8d9c3d73bf053bb57f9c4b2 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Mon, 23 May 2022 14:07:10 -0700 Subject: bpf: Add bpf_dynptr_read and bpf_dynptr_write This patch adds two helper functions, bpf_dynptr_read and bpf_dynptr_write: long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset); long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len); The dynptr passed into these functions must be valid dynptrs that have been initialized. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20220523210712.3641569-5-joannelkoong@gmail.com --- include/uapi/linux/bpf.h | 19 ++++++++++ kernel/bpf/helpers.c | 78 ++++++++++++++++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 19 ++++++++++ 3 files changed, 116 insertions(+) (limited to 'tools/include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 081a55540aa5..efe2505650e6 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5221,6 +5221,23 @@ union bpf_attr { * 'bpf_ringbuf_discard'. * Return * Nothing. Always succeeds. + * + * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset) + * Description + * Read *len* bytes from *src* into *dst*, starting from *offset* + * into *src*. + * Return + * 0 on success, -E2BIG if *offset* + *len* exceeds the length + * of *src*'s data, -EINVAL if *src* is an invalid dynptr. + * + * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len) + * Description + * Write *len* bytes from *src* into *dst*, starting from *offset* + * into *dst*. + * Return + * 0 on success, -E2BIG if *offset* + *len* exceeds the length + * of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst* + * is a read-only dynptr. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5424,6 +5441,8 @@ union bpf_attr { FN(ringbuf_reserve_dynptr), \ FN(ringbuf_submit_dynptr), \ FN(ringbuf_discard_dynptr), \ + FN(dynptr_read), \ + FN(dynptr_write), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index abb08999ff56..8cef3fb0d143 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1417,12 +1417,24 @@ const struct bpf_func_proto bpf_kptr_xchg_proto = { */ #define DYNPTR_MAX_SIZE ((1UL << 24) - 1) #define DYNPTR_TYPE_SHIFT 28 +#define DYNPTR_SIZE_MASK 0xFFFFFF +#define DYNPTR_RDONLY_BIT BIT(31) + +static bool bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr) +{ + return ptr->size & DYNPTR_RDONLY_BIT; +} static void bpf_dynptr_set_type(struct bpf_dynptr_kern *ptr, enum bpf_dynptr_type type) { ptr->size |= type << DYNPTR_TYPE_SHIFT; } +static u32 bpf_dynptr_get_size(struct bpf_dynptr_kern *ptr) +{ + return ptr->size & DYNPTR_SIZE_MASK; +} + int bpf_dynptr_check_size(u32 size) { return size > DYNPTR_MAX_SIZE ? -E2BIG : 0; @@ -1442,6 +1454,16 @@ void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr) memset(ptr, 0, sizeof(*ptr)); } +static int bpf_dynptr_check_off_len(struct bpf_dynptr_kern *ptr, u32 offset, u32 len) +{ + u32 size = bpf_dynptr_get_size(ptr); + + if (len > size || offset > size - len) + return -E2BIG; + + return 0; +} + BPF_CALL_4(bpf_dynptr_from_mem, void *, data, u32, size, u64, flags, struct bpf_dynptr_kern *, ptr) { int err; @@ -1475,6 +1497,58 @@ const struct bpf_func_proto bpf_dynptr_from_mem_proto = { .arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT, }; +BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src, u32, offset) +{ + int err; + + if (!src->data) + return -EINVAL; + + err = bpf_dynptr_check_off_len(src, offset, len); + if (err) + return err; + + memcpy(dst, src->data + src->offset + offset, len); + + return 0; +} + +const struct bpf_func_proto bpf_dynptr_read_proto = { + .func = bpf_dynptr_read, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_UNINIT_MEM, + .arg2_type = ARG_CONST_SIZE_OR_ZERO, + .arg3_type = ARG_PTR_TO_DYNPTR, + .arg4_type = ARG_ANYTHING, +}; + +BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src, u32, len) +{ + int err; + + if (!dst->data || bpf_dynptr_is_rdonly(dst)) + return -EINVAL; + + err = bpf_dynptr_check_off_len(dst, offset, len); + if (err) + return err; + + memcpy(dst->data + dst->offset + offset, src, len); + + return 0; +} + +const struct bpf_func_proto bpf_dynptr_write_proto = { + .func = bpf_dynptr_write, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_DYNPTR, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg4_type = ARG_CONST_SIZE_OR_ZERO, +}; + const struct bpf_func_proto bpf_get_current_task_proto __weak; const struct bpf_func_proto bpf_get_current_task_btf_proto __weak; const struct bpf_func_proto bpf_probe_read_user_proto __weak; @@ -1537,6 +1611,10 @@ bpf_base_func_proto(enum bpf_func_id func_id) return &bpf_strncmp_proto; case BPF_FUNC_dynptr_from_mem: return &bpf_dynptr_from_mem_proto; + case BPF_FUNC_dynptr_read: + return &bpf_dynptr_read_proto; + case BPF_FUNC_dynptr_write: + return &bpf_dynptr_write_proto; default: break; } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 081a55540aa5..efe2505650e6 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5221,6 +5221,23 @@ union bpf_attr { * 'bpf_ringbuf_discard'. * Return * Nothing. Always succeeds. + * + * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset) + * Description + * Read *len* bytes from *src* into *dst*, starting from *offset* + * into *src*. + * Return + * 0 on success, -E2BIG if *offset* + *len* exceeds the length + * of *src*'s data, -EINVAL if *src* is an invalid dynptr. + * + * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len) + * Description + * Write *len* bytes from *src* into *dst*, starting from *offset* + * into *dst*. + * Return + * 0 on success, -E2BIG if *offset* + *len* exceeds the length + * of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst* + * is a read-only dynptr. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5424,6 +5441,8 @@ union bpf_attr { FN(ringbuf_reserve_dynptr), \ FN(ringbuf_submit_dynptr), \ FN(ringbuf_discard_dynptr), \ + FN(dynptr_read), \ + FN(dynptr_write), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From 34d4ef5775f776ec4b0d53a02d588bf3195cada6 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Mon, 23 May 2022 14:07:11 -0700 Subject: bpf: Add dynptr data slices This patch adds a new helper function void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len); which returns a pointer to the underlying data of a dynptr. *len* must be a statically known value. The bpf program may access the returned data slice as a normal buffer (eg can do direct reads and writes), since the verifier associates the length with the returned pointer, and enforces that no out of bounds accesses occur. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20220523210712.3641569-6-joannelkoong@gmail.com --- include/linux/bpf.h | 1 + include/uapi/linux/bpf.h | 12 ++++++++++++ kernel/bpf/helpers.c | 28 ++++++++++++++++++++++++++++ kernel/bpf/verifier.c | 23 +++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 12 ++++++++++++ 5 files changed, 76 insertions(+) (limited to 'tools/include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index c72321b6f306..a7080c86fa76 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -488,6 +488,7 @@ enum bpf_return_type { RET_PTR_TO_TCP_SOCK_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_TCP_SOCK, RET_PTR_TO_SOCK_COMMON_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_SOCK_COMMON, RET_PTR_TO_ALLOC_MEM_OR_NULL = PTR_MAYBE_NULL | MEM_ALLOC | RET_PTR_TO_ALLOC_MEM, + RET_PTR_TO_DYNPTR_MEM_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_ALLOC_MEM, RET_PTR_TO_BTF_ID_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_BTF_ID, /* This must be the last entry. Its purpose is to ensure the enum is diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index efe2505650e6..f4009dbdf62d 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5238,6 +5238,17 @@ union bpf_attr { * 0 on success, -E2BIG if *offset* + *len* exceeds the length * of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst* * is a read-only dynptr. + * + * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len) + * Description + * Get a pointer to the underlying dynptr data. + * + * *len* must be a statically known value. The returned data slice + * is invalidated whenever the dynptr is invalidated. + * Return + * Pointer to the underlying dynptr data, NULL if the dynptr is + * read-only, if the dynptr is invalid, or if the offset and length + * is out of bounds. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5443,6 +5454,7 @@ union bpf_attr { FN(ringbuf_discard_dynptr), \ FN(dynptr_read), \ FN(dynptr_write), \ + FN(dynptr_data), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 8cef3fb0d143..225806a02efb 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1549,6 +1549,32 @@ const struct bpf_func_proto bpf_dynptr_write_proto = { .arg4_type = ARG_CONST_SIZE_OR_ZERO, }; +BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len) +{ + int err; + + if (!ptr->data) + return 0; + + err = bpf_dynptr_check_off_len(ptr, offset, len); + if (err) + return 0; + + if (bpf_dynptr_is_rdonly(ptr)) + return 0; + + return (unsigned long)(ptr->data + ptr->offset + offset); +} + +const struct bpf_func_proto bpf_dynptr_data_proto = { + .func = bpf_dynptr_data, + .gpl_only = false, + .ret_type = RET_PTR_TO_DYNPTR_MEM_OR_NULL, + .arg1_type = ARG_PTR_TO_DYNPTR, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_CONST_ALLOC_SIZE_OR_ZERO, +}; + const struct bpf_func_proto bpf_get_current_task_proto __weak; const struct bpf_func_proto bpf_get_current_task_btf_proto __weak; const struct bpf_func_proto bpf_probe_read_user_proto __weak; @@ -1615,6 +1641,8 @@ bpf_base_func_proto(enum bpf_func_id func_id) return &bpf_dynptr_read_proto; case BPF_FUNC_dynptr_write: return &bpf_dynptr_write_proto; + case BPF_FUNC_dynptr_data: + return &bpf_dynptr_data_proto; default: break; } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 8be140351966..aedac2ac02b9 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -5832,6 +5832,14 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env, return __check_ptr_off_reg(env, reg, regno, fixed_off_ok); } +static u32 stack_slot_get_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +{ + struct bpf_func_state *state = func(env, reg); + int spi = get_spi(reg->off); + + return state->stack[spi].spilled_ptr.id; +} + static int check_func_arg(struct bpf_verifier_env *env, u32 arg, struct bpf_call_arg_meta *meta, const struct bpf_func_proto *fn) @@ -7384,6 +7392,21 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn regs[BPF_REG_0].id = id; /* For release_reference() */ regs[BPF_REG_0].ref_obj_id = id; + } else if (func_id == BPF_FUNC_dynptr_data) { + int dynptr_id = 0, i; + + /* Find the id of the dynptr we're acquiring a reference to */ + for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) { + if (arg_type_is_dynptr(fn->arg_type[i])) { + if (dynptr_id) { + verbose(env, "verifier internal error: multiple dynptr args in func\n"); + return -EFAULT; + } + dynptr_id = stack_slot_get_id(env, ®s[BPF_REG_1 + i]); + } + } + /* For release_reference() */ + regs[BPF_REG_0].ref_obj_id = dynptr_id; } do_refine_retval_range(regs, fn->ret_type, func_id, &meta); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index efe2505650e6..f4009dbdf62d 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5238,6 +5238,17 @@ union bpf_attr { * 0 on success, -E2BIG if *offset* + *len* exceeds the length * of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst* * is a read-only dynptr. + * + * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len) + * Description + * Get a pointer to the underlying dynptr data. + * + * *len* must be a statically known value. The returned data slice + * is invalidated whenever the dynptr is invalidated. + * Return + * Pointer to the underlying dynptr data, NULL if the dynptr is + * read-only, if the dynptr is invalid, or if the offset and length + * is out of bounds. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5443,6 +5454,7 @@ union bpf_attr { FN(ringbuf_discard_dynptr), \ FN(dynptr_read), \ FN(dynptr_write), \ + FN(dynptr_data), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit From b738c106f7355e318ca47a3b981688efe1bc12fb Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Tue, 31 May 2022 18:04:11 +0800 Subject: LoongArch: Add other common headers Add some other common headers for basic LoongArch support. Reviewed-by: WANG Xuerui Reviewed-by: Jiaxun Yang Signed-off-by: Huacai Chen --- arch/loongarch/include/asm/asm-prototypes.h | 7 + arch/loongarch/include/asm/asm.h | 191 +++++++++++++++++ arch/loongarch/include/asm/asmmacro.h | 289 ++++++++++++++++++++++++++ arch/loongarch/include/asm/clocksource.h | 12 ++ arch/loongarch/include/asm/compiler.h | 15 ++ arch/loongarch/include/asm/inst.h | 117 +++++++++++ arch/loongarch/include/asm/linkage.h | 36 ++++ arch/loongarch/include/asm/perf_event.h | 10 + arch/loongarch/include/asm/prefetch.h | 29 +++ arch/loongarch/include/asm/serial.h | 11 + arch/loongarch/include/asm/time.h | 50 +++++ arch/loongarch/include/asm/timex.h | 33 +++ arch/loongarch/include/asm/topology.h | 15 ++ arch/loongarch/include/asm/types.h | 19 ++ arch/loongarch/include/uapi/asm/bitsperlong.h | 9 + arch/loongarch/include/uapi/asm/byteorder.h | 13 ++ arch/loongarch/include/uapi/asm/reg.h | 59 ++++++ tools/include/uapi/asm/bitsperlong.h | 2 + 18 files changed, 917 insertions(+) create mode 100644 arch/loongarch/include/asm/asm-prototypes.h create mode 100644 arch/loongarch/include/asm/asm.h create mode 100644 arch/loongarch/include/asm/asmmacro.h create mode 100644 arch/loongarch/include/asm/clocksource.h create mode 100644 arch/loongarch/include/asm/compiler.h create mode 100644 arch/loongarch/include/asm/inst.h create mode 100644 arch/loongarch/include/asm/linkage.h create mode 100644 arch/loongarch/include/asm/perf_event.h create mode 100644 arch/loongarch/include/asm/prefetch.h create mode 100644 arch/loongarch/include/asm/serial.h create mode 100644 arch/loongarch/include/asm/time.h create mode 100644 arch/loongarch/include/asm/timex.h create mode 100644 arch/loongarch/include/asm/topology.h create mode 100644 arch/loongarch/include/asm/types.h create mode 100644 arch/loongarch/include/uapi/asm/bitsperlong.h create mode 100644 arch/loongarch/include/uapi/asm/byteorder.h create mode 100644 arch/loongarch/include/uapi/asm/reg.h (limited to 'tools/include') diff --git a/arch/loongarch/include/asm/asm-prototypes.h b/arch/loongarch/include/asm/asm-prototypes.h new file mode 100644 index 000000000000..ed06d3997420 --- /dev/null +++ b/arch/loongarch/include/asm/asm-prototypes.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include +#include +#include +#include +#include diff --git a/arch/loongarch/include/asm/asm.h b/arch/loongarch/include/asm/asm.h new file mode 100644 index 000000000000..40eea6aa469e --- /dev/null +++ b/arch/loongarch/include/asm/asm.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Some useful macros for LoongArch assembler code + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1995, 1996, 1997, 1999, 2001 by Ralf Baechle + * Copyright (C) 1999 by Silicon Graphics, Inc. + * Copyright (C) 2001 MIPS Technologies, Inc. + * Copyright (C) 2002 Maciej W. Rozycki + */ +#ifndef __ASM_ASM_H +#define __ASM_ASM_H + +/* LoongArch pref instruction. */ +#ifdef CONFIG_CPU_HAS_PREFETCH + +#define PREF(hint, addr, offs) \ + preld hint, addr, offs; \ + +#define PREFX(hint, addr, index) \ + preldx hint, addr, index; \ + +#else /* !CONFIG_CPU_HAS_PREFETCH */ + +#define PREF(hint, addr, offs) +#define PREFX(hint, addr, index) + +#endif /* !CONFIG_CPU_HAS_PREFETCH */ + +/* + * Stack alignment + */ +#define STACK_ALIGN ~(0xf) + +/* + * Macros to handle different pointer/register sizes for 32/64-bit code + */ + +/* + * Size of a register + */ +#ifndef __loongarch64 +#define SZREG 4 +#else +#define SZREG 8 +#endif + +/* + * Use the following macros in assemblercode to load/store registers, + * pointers etc. + */ +#if (SZREG == 4) +#define REG_L ld.w +#define REG_S st.w +#define REG_ADD add.w +#define REG_SUB sub.w +#else /* SZREG == 8 */ +#define REG_L ld.d +#define REG_S st.d +#define REG_ADD add.d +#define REG_SUB sub.d +#endif + +/* + * How to add/sub/load/store/shift C int variables. + */ +#if (__SIZEOF_INT__ == 4) +#define INT_ADD add.w +#define INT_ADDI addi.w +#define INT_SUB sub.w +#define INT_L ld.w +#define INT_S st.w +#define INT_SLL slli.w +#define INT_SLLV sll.w +#define INT_SRL srli.w +#define INT_SRLV srl.w +#define INT_SRA srai.w +#define INT_SRAV sra.w +#endif + +#if (__SIZEOF_INT__ == 8) +#define INT_ADD add.d +#define INT_ADDI addi.d +#define INT_SUB sub.d +#define INT_L ld.d +#define INT_S st.d +#define INT_SLL slli.d +#define INT_SLLV sll.d +#define INT_SRL srli.d +#define INT_SRLV srl.d +#define INT_SRA srai.d +#define INT_SRAV sra.d +#endif + +/* + * How to add/sub/load/store/shift C long variables. + */ +#if (__SIZEOF_LONG__ == 4) +#define LONG_ADD add.w +#define LONG_ADDI addi.w +#define LONG_SUB sub.w +#define LONG_L ld.w +#define LONG_S st.w +#define LONG_SLL slli.w +#define LONG_SLLV sll.w +#define LONG_SRL srli.w +#define LONG_SRLV srl.w +#define LONG_SRA srai.w +#define LONG_SRAV sra.w + +#ifdef __ASSEMBLY__ +#define LONG .word +#endif +#define LONGSIZE 4 +#define LONGMASK 3 +#define LONGLOG 2 +#endif + +#if (__SIZEOF_LONG__ == 8) +#define LONG_ADD add.d +#define LONG_ADDI addi.d +#define LONG_SUB sub.d +#define LONG_L ld.d +#define LONG_S st.d +#define LONG_SLL slli.d +#define LONG_SLLV sll.d +#define LONG_SRL srli.d +#define LONG_SRLV srl.d +#define LONG_SRA srai.d +#define LONG_SRAV sra.d + +#ifdef __ASSEMBLY__ +#define LONG .dword +#endif +#define LONGSIZE 8 +#define LONGMASK 7 +#define LONGLOG 3 +#endif + +/* + * How to add/sub/load/store/shift pointers. + */ +#if (__SIZEOF_POINTER__ == 4) +#define PTR_ADD add.w +#define PTR_ADDI addi.w +#define PTR_SUB sub.w +#define PTR_L ld.w +#define PTR_S st.w +#define PTR_LI li.w +#define PTR_SLL slli.w +#define PTR_SLLV sll.w +#define PTR_SRL srli.w +#define PTR_SRLV srl.w +#define PTR_SRA srai.w +#define PTR_SRAV sra.w + +#define PTR_SCALESHIFT 2 + +#ifdef __ASSEMBLY__ +#define PTR .word +#endif +#define PTRSIZE 4 +#define PTRLOG 2 +#endif + +#if (__SIZEOF_POINTER__ == 8) +#define PTR_ADD add.d +#define PTR_ADDI addi.d +#define PTR_SUB sub.d +#define PTR_L ld.d +#define PTR_S st.d +#define PTR_LI li.d +#define PTR_SLL slli.d +#define PTR_SLLV sll.d +#define PTR_SRL srli.d +#define PTR_SRLV srl.d +#define PTR_SRA srai.d +#define PTR_SRAV sra.d + +#define PTR_SCALESHIFT 3 + +#ifdef __ASSEMBLY__ +#define PTR .dword +#endif +#define PTRSIZE 8 +#define PTRLOG 3 +#endif + +#endif /* __ASM_ASM_H */ diff --git a/arch/loongarch/include/asm/asmmacro.h b/arch/loongarch/include/asm/asmmacro.h new file mode 100644 index 000000000000..a1a04083bd67 --- /dev/null +++ b/arch/loongarch/include/asm/asmmacro.h @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_ASMMACRO_H +#define _ASM_ASMMACRO_H + +#include +#include +#include +#include + + .macro parse_v var val + \var = \val + .endm + + .macro parse_r var r + \var = -1 + .ifc \r, $r0 + \var = 0 + .endif + .ifc \r, $r1 + \var = 1 + .endif + .ifc \r, $r2 + \var = 2 + .endif + .ifc \r, $r3 + \var = 3 + .endif + .ifc \r, $r4 + \var = 4 + .endif + .ifc \r, $r5 + \var = 5 + .endif + .ifc \r, $r6 + \var = 6 + .endif + .ifc \r, $r7 + \var = 7 + .endif + .ifc \r, $r8 + \var = 8 + .endif + .ifc \r, $r9 + \var = 9 + .endif + .ifc \r, $r10 + \var = 10 + .endif + .ifc \r, $r11 + \var = 11 + .endif + .ifc \r, $r12 + \var = 12 + .endif + .ifc \r, $r13 + \var = 13 + .endif + .ifc \r, $r14 + \var = 14 + .endif + .ifc \r, $r15 + \var = 15 + .endif + .ifc \r, $r16 + \var = 16 + .endif + .ifc \r, $r17 + \var = 17 + .endif + .ifc \r, $r18 + \var = 18 + .endif + .ifc \r, $r19 + \var = 19 + .endif + .ifc \r, $r20 + \var = 20 + .endif + .ifc \r, $r21 + \var = 21 + .endif + .ifc \r, $r22 + \var = 22 + .endif + .ifc \r, $r23 + \var = 23 + .endif + .ifc \r, $r24 + \var = 24 + .endif + .ifc \r, $r25 + \var = 25 + .endif + .ifc \r, $r26 + \var = 26 + .endif + .ifc \r, $r27 + \var = 27 + .endif + .ifc \r, $r28 + \var = 28 + .endif + .ifc \r, $r29 + \var = 29 + .endif + .ifc \r, $r30 + \var = 30 + .endif + .ifc \r, $r31 + \var = 31 + .endif + .iflt \var + .error "Unable to parse register name \r" + .endif + .endm + + .macro cpu_save_nonscratch thread + stptr.d s0, \thread, THREAD_REG23 + stptr.d s1, \thread, THREAD_REG24 + stptr.d s2, \thread, THREAD_REG25 + stptr.d s3, \thread, THREAD_REG26 + stptr.d s4, \thread, THREAD_REG27 + stptr.d s5, \thread, THREAD_REG28 + stptr.d s6, \thread, THREAD_REG29 + stptr.d s7, \thread, THREAD_REG30 + stptr.d s8, \thread, THREAD_REG31 + stptr.d sp, \thread, THREAD_REG03 + stptr.d fp, \thread, THREAD_REG22 + .endm + + .macro cpu_restore_nonscratch thread + ldptr.d s0, \thread, THREAD_REG23 + ldptr.d s1, \thread, THREAD_REG24 + ldptr.d s2, \thread, THREAD_REG25 + ldptr.d s3, \thread, THREAD_REG26 + ldptr.d s4, \thread, THREAD_REG27 + ldptr.d s5, \thread, THREAD_REG28 + ldptr.d s6, \thread, THREAD_REG29 + ldptr.d s7, \thread, THREAD_REG30 + ldptr.d s8, \thread, THREAD_REG31 + ldptr.d ra, \thread, THREAD_REG01 + ldptr.d sp, \thread, THREAD_REG03 + ldptr.d fp, \thread, THREAD_REG22 + .endm + + .macro fpu_save_csr thread tmp + movfcsr2gr \tmp, fcsr0 + stptr.w \tmp, \thread, THREAD_FCSR + .endm + + .macro fpu_restore_csr thread tmp + ldptr.w \tmp, \thread, THREAD_FCSR + movgr2fcsr fcsr0, \tmp + .endm + + .macro fpu_save_cc thread tmp0 tmp1 + movcf2gr \tmp0, $fcc0 + move \tmp1, \tmp0 + movcf2gr \tmp0, $fcc1 + bstrins.d \tmp1, \tmp0, 15, 8 + movcf2gr \tmp0, $fcc2 + bstrins.d \tmp1, \tmp0, 23, 16 + movcf2gr \tmp0, $fcc3 + bstrins.d \tmp1, \tmp0, 31, 24 + movcf2gr \tmp0, $fcc4 + bstrins.d \tmp1, \tmp0, 39, 32 + movcf2gr \tmp0, $fcc5 + bstrins.d \tmp1, \tmp0, 47, 40 + movcf2gr \tmp0, $fcc6 + bstrins.d \tmp1, \tmp0, 55, 48 + movcf2gr \tmp0, $fcc7 + bstrins.d \tmp1, \tmp0, 63, 56 + stptr.d \tmp1, \thread, THREAD_FCC + .endm + + .macro fpu_restore_cc thread tmp0 tmp1 + ldptr.d \tmp0, \thread, THREAD_FCC + bstrpick.d \tmp1, \tmp0, 7, 0 + movgr2cf $fcc0, \tmp1 + bstrpick.d \tmp1, \tmp0, 15, 8 + movgr2cf $fcc1, \tmp1 + bstrpick.d \tmp1, \tmp0, 23, 16 + movgr2cf $fcc2, \tmp1 + bstrpick.d \tmp1, \tmp0, 31, 24 + movgr2cf $fcc3, \tmp1 + bstrpick.d \tmp1, \tmp0, 39, 32 + movgr2cf $fcc4, \tmp1 + bstrpick.d \tmp1, \tmp0, 47, 40 + movgr2cf $fcc5, \tmp1 + bstrpick.d \tmp1, \tmp0, 55, 48 + movgr2cf $fcc6, \tmp1 + bstrpick.d \tmp1, \tmp0, 63, 56 + movgr2cf $fcc7, \tmp1 + .endm + + .macro fpu_save_double thread tmp + li.w \tmp, THREAD_FPR0 + PTR_ADD \tmp, \tmp, \thread + fst.d $f0, \tmp, THREAD_FPR0 - THREAD_FPR0 + fst.d $f1, \tmp, THREAD_FPR1 - THREAD_FPR0 + fst.d $f2, \tmp, THREAD_FPR2 - THREAD_FPR0 + fst.d $f3, \tmp, THREAD_FPR3 - THREAD_FPR0 + fst.d $f4, \tmp, THREAD_FPR4 - THREAD_FPR0 + fst.d $f5, \tmp, THREAD_FPR5 - THREAD_FPR0 + fst.d $f6, \tmp, THREAD_FPR6 - THREAD_FPR0 + fst.d $f7, \tmp, THREAD_FPR7 - THREAD_FPR0 + fst.d $f8, \tmp, THREAD_FPR8 - THREAD_FPR0 + fst.d $f9, \tmp, THREAD_FPR9 - THREAD_FPR0 + fst.d $f10, \tmp, THREAD_FPR10 - THREAD_FPR0 + fst.d $f11, \tmp, THREAD_FPR11 - THREAD_FPR0 + fst.d $f12, \tmp, THREAD_FPR12 - THREAD_FPR0 + fst.d $f13, \tmp, THREAD_FPR13 - THREAD_FPR0 + fst.d $f14, \tmp, THREAD_FPR14 - THREAD_FPR0 + fst.d $f15, \tmp, THREAD_FPR15 - THREAD_FPR0 + fst.d $f16, \tmp, THREAD_FPR16 - THREAD_FPR0 + fst.d $f17, \tmp, THREAD_FPR17 - THREAD_FPR0 + fst.d $f18, \tmp, THREAD_FPR18 - THREAD_FPR0 + fst.d $f19, \tmp, THREAD_FPR19 - THREAD_FPR0 + fst.d $f20, \tmp, THREAD_FPR20 - THREAD_FPR0 + fst.d $f21, \tmp, THREAD_FPR21 - THREAD_FPR0 + fst.d $f22, \tmp, THREAD_FPR22 - THREAD_FPR0 + fst.d $f23, \tmp, THREAD_FPR23 - THREAD_FPR0 + fst.d $f24, \tmp, THREAD_FPR24 - THREAD_FPR0 + fst.d $f25, \tmp, THREAD_FPR25 - THREAD_FPR0 + fst.d $f26, \tmp, THREAD_FPR26 - THREAD_FPR0 + fst.d $f27, \tmp, THREAD_FPR27 - THREAD_FPR0 + fst.d $f28, \tmp, THREAD_FPR28 - THREAD_FPR0 + fst.d $f29, \tmp, THREAD_FPR29 - THREAD_FPR0 + fst.d $f30, \tmp, THREAD_FPR30 - THREAD_FPR0 + fst.d $f31, \tmp, THREAD_FPR31 - THREAD_FPR0 + .endm + + .macro fpu_restore_double thread tmp + li.w \tmp, THREAD_FPR0 + PTR_ADD \tmp, \tmp, \thread + fld.d $f0, \tmp, THREAD_FPR0 - THREAD_FPR0 + fld.d $f1, \tmp, THREAD_FPR1 - THREAD_FPR0 + fld.d $f2, \tmp, THREAD_FPR2 - THREAD_FPR0 + fld.d $f3, \tmp, THREAD_FPR3 - THREAD_FPR0 + fld.d $f4, \tmp, THREAD_FPR4 - THREAD_FPR0 + fld.d $f5, \tmp, THREAD_FPR5 - THREAD_FPR0 + fld.d $f6, \tmp, THREAD_FPR6 - THREAD_FPR0 + fld.d $f7, \tmp, THREAD_FPR7 - THREAD_FPR0 + fld.d $f8, \tmp, THREAD_FPR8 - THREAD_FPR0 + fld.d $f9, \tmp, THREAD_FPR9 - THREAD_FPR0 + fld.d $f10, \tmp, THREAD_FPR10 - THREAD_FPR0 + fld.d $f11, \tmp, THREAD_FPR11 - THREAD_FPR0 + fld.d $f12, \tmp, THREAD_FPR12 - THREAD_FPR0 + fld.d $f13, \tmp, THREAD_FPR13 - THREAD_FPR0 + fld.d $f14, \tmp, THREAD_FPR14 - THREAD_FPR0 + fld.d $f15, \tmp, THREAD_FPR15 - THREAD_FPR0 + fld.d $f16, \tmp, THREAD_FPR16 - THREAD_FPR0 + fld.d $f17, \tmp, THREAD_FPR17 - THREAD_FPR0 + fld.d $f18, \tmp, THREAD_FPR18 - THREAD_FPR0 + fld.d $f19, \tmp, THREAD_FPR19 - THREAD_FPR0 + fld.d $f20, \tmp, THREAD_FPR20 - THREAD_FPR0 + fld.d $f21, \tmp, THREAD_FPR21 - THREAD_FPR0 + fld.d $f22, \tmp, THREAD_FPR22 - THREAD_FPR0 + fld.d $f23, \tmp, THREAD_FPR23 - THREAD_FPR0 + fld.d $f24, \tmp, THREAD_FPR24 - THREAD_FPR0 + fld.d $f25, \tmp, THREAD_FPR25 - THREAD_FPR0 + fld.d $f26, \tmp, THREAD_FPR26 - THREAD_FPR0 + fld.d $f27, \tmp, THREAD_FPR27 - THREAD_FPR0 + fld.d $f28, \tmp, THREAD_FPR28 - THREAD_FPR0 + fld.d $f29, \tmp, THREAD_FPR29 - THREAD_FPR0 + fld.d $f30, \tmp, THREAD_FPR30 - THREAD_FPR0 + fld.d $f31, \tmp, THREAD_FPR31 - THREAD_FPR0 + .endm + +.macro not dst src + nor \dst, \src, zero +.endm + +.macro bgt r0 r1 label + blt \r1, \r0, \label +.endm + +.macro bltz r0 label + blt \r0, zero, \label +.endm + +.macro bgez r0 label + bge \r0, zero, \label +.endm + +#endif /* _ASM_ASMMACRO_H */ diff --git a/arch/loongarch/include/asm/clocksource.h b/arch/loongarch/include/asm/clocksource.h new file mode 100644 index 000000000000..58e64aa05d26 --- /dev/null +++ b/arch/loongarch/include/asm/clocksource.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_CLOCKSOURCE_H +#define __ASM_CLOCKSOURCE_H + +#include + +#endif /* __ASM_CLOCKSOURCE_H */ diff --git a/arch/loongarch/include/asm/compiler.h b/arch/loongarch/include/asm/compiler.h new file mode 100644 index 000000000000..657cebe70ace --- /dev/null +++ b/arch/loongarch/include/asm/compiler.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_COMPILER_H +#define _ASM_COMPILER_H + +#define GCC_OFF_SMALL_ASM() "ZC" + +#define LOONGARCH_ISA_LEVEL "loongarch" +#define LOONGARCH_ISA_ARCH_LEVEL "arch=loongarch" +#define LOONGARCH_ISA_LEVEL_RAW loongarch +#define LOONGARCH_ISA_ARCH_LEVEL_RAW LOONGARCH_ISA_LEVEL_RAW + +#endif /* _ASM_COMPILER_H */ diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h new file mode 100644 index 000000000000..575d1bb66ffb --- /dev/null +++ b/arch/loongarch/include/asm/inst.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_INST_H +#define _ASM_INST_H + +#include +#include + +#define ADDR_IMMMASK_LU52ID 0xFFF0000000000000 +#define ADDR_IMMMASK_LU32ID 0x000FFFFF00000000 +#define ADDR_IMMMASK_ADDU16ID 0x00000000FFFF0000 + +#define ADDR_IMMSHIFT_LU52ID 52 +#define ADDR_IMMSHIFT_LU32ID 32 +#define ADDR_IMMSHIFT_ADDU16ID 16 + +#define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN) + +enum reg1i20_op { + lu12iw_op = 0x0a, + lu32id_op = 0x0b, +}; + +enum reg2i12_op { + lu52id_op = 0x0c, +}; + +enum reg2i16_op { + jirl_op = 0x13, +}; + +struct reg0i26_format { + unsigned int immediate_h : 10; + unsigned int immediate_l : 16; + unsigned int opcode : 6; +}; + +struct reg1i20_format { + unsigned int rd : 5; + unsigned int immediate : 20; + unsigned int opcode : 7; +}; + +struct reg1i21_format { + unsigned int immediate_h : 5; + unsigned int rj : 5; + unsigned int immediate_l : 16; + unsigned int opcode : 6; +}; + +struct reg2i12_format { + unsigned int rd : 5; + unsigned int rj : 5; + unsigned int immediate : 12; + unsigned int opcode : 10; +}; + +struct reg2i16_format { + unsigned int rd : 5; + unsigned int rj : 5; + unsigned int immediate : 16; + unsigned int opcode : 6; +}; + +union loongarch_instruction { + unsigned int word; + struct reg0i26_format reg0i26_format; + struct reg1i20_format reg1i20_format; + struct reg1i21_format reg1i21_format; + struct reg2i12_format reg2i12_format; + struct reg2i16_format reg2i16_format; +}; + +#define LOONGARCH_INSN_SIZE sizeof(union loongarch_instruction) + +enum loongarch_gpr { + LOONGARCH_GPR_ZERO = 0, + LOONGARCH_GPR_RA = 1, + LOONGARCH_GPR_TP = 2, + LOONGARCH_GPR_SP = 3, + LOONGARCH_GPR_A0 = 4, /* Reused as V0 for return value */ + LOONGARCH_GPR_A1, /* Reused as V1 for return value */ + LOONGARCH_GPR_A2, + LOONGARCH_GPR_A3, + LOONGARCH_GPR_A4, + LOONGARCH_GPR_A5, + LOONGARCH_GPR_A6, + LOONGARCH_GPR_A7, + LOONGARCH_GPR_T0 = 12, + LOONGARCH_GPR_T1, + LOONGARCH_GPR_T2, + LOONGARCH_GPR_T3, + LOONGARCH_GPR_T4, + LOONGARCH_GPR_T5, + LOONGARCH_GPR_T6, + LOONGARCH_GPR_T7, + LOONGARCH_GPR_T8, + LOONGARCH_GPR_FP = 22, + LOONGARCH_GPR_S0 = 23, + LOONGARCH_GPR_S1, + LOONGARCH_GPR_S2, + LOONGARCH_GPR_S3, + LOONGARCH_GPR_S4, + LOONGARCH_GPR_S5, + LOONGARCH_GPR_S6, + LOONGARCH_GPR_S7, + LOONGARCH_GPR_S8, + LOONGARCH_GPR_MAX +}; + +u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm); +u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm); +u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest); + +#endif /* _ASM_INST_H */ diff --git a/arch/loongarch/include/asm/linkage.h b/arch/loongarch/include/asm/linkage.h new file mode 100644 index 000000000000..81b0c4cfbf4f --- /dev/null +++ b/arch/loongarch/include/asm/linkage.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +#define __ALIGN .align 2 +#define __ALIGN_STR __stringify(__ALIGN) + +#define SYM_FUNC_START(name) \ + SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) \ + .cfi_startproc; + +#define SYM_FUNC_START_NOALIGN(name) \ + SYM_START(name, SYM_L_GLOBAL, SYM_A_NONE) \ + .cfi_startproc; + +#define SYM_FUNC_START_LOCAL(name) \ + SYM_START(name, SYM_L_LOCAL, SYM_A_ALIGN) \ + .cfi_startproc; + +#define SYM_FUNC_START_LOCAL_NOALIGN(name) \ + SYM_START(name, SYM_L_LOCAL, SYM_A_NONE) \ + .cfi_startproc; + +#define SYM_FUNC_START_WEAK(name) \ + SYM_START(name, SYM_L_WEAK, SYM_A_ALIGN) \ + .cfi_startproc; + +#define SYM_FUNC_START_WEAK_NOALIGN(name) \ + SYM_START(name, SYM_L_WEAK, SYM_A_NONE) \ + .cfi_startproc; + +#define SYM_FUNC_END(name) \ + .cfi_endproc; \ + SYM_END(name, SYM_T_FUNC) + +#endif diff --git a/arch/loongarch/include/asm/perf_event.h b/arch/loongarch/include/asm/perf_event.h new file mode 100644 index 000000000000..dcb3b17053a8 --- /dev/null +++ b/arch/loongarch/include/asm/perf_event.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __LOONGARCH_PERF_EVENT_H__ +#define __LOONGARCH_PERF_EVENT_H__ +/* Nothing to show here; the file is required by linux/perf_event.h. */ +#endif /* __LOONGARCH_PERF_EVENT_H__ */ diff --git a/arch/loongarch/include/asm/prefetch.h b/arch/loongarch/include/asm/prefetch.h new file mode 100644 index 000000000000..1672262a5e2e --- /dev/null +++ b/arch/loongarch/include/asm/prefetch.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_PREFETCH_H +#define __ASM_PREFETCH_H + +#define Pref_Load 0 +#define Pref_Store 8 + +#ifdef __ASSEMBLY__ + + .macro __pref hint addr +#ifdef CONFIG_CPU_HAS_PREFETCH + preld \hint, \addr, 0 +#endif + .endm + + .macro pref_load addr + __pref Pref_Load, \addr + .endm + + .macro pref_store addr + __pref Pref_Store, \addr + .endm + +#endif + +#endif /* __ASM_PREFETCH_H */ diff --git a/arch/loongarch/include/asm/serial.h b/arch/loongarch/include/asm/serial.h new file mode 100644 index 000000000000..3fb550eb9115 --- /dev/null +++ b/arch/loongarch/include/asm/serial.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM__SERIAL_H +#define __ASM__SERIAL_H + +#define BASE_BAUD 0 +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#endif /* __ASM__SERIAL_H */ diff --git a/arch/loongarch/include/asm/time.h b/arch/loongarch/include/asm/time.h new file mode 100644 index 000000000000..2eae219301d0 --- /dev/null +++ b/arch/loongarch/include/asm/time.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_TIME_H +#define _ASM_TIME_H + +#include +#include +#include + +extern u64 cpu_clock_freq; +extern u64 const_clock_freq; + +extern void sync_counter(void); + +static inline unsigned int calc_const_freq(void) +{ + unsigned int res; + unsigned int base_freq; + unsigned int cfm, cfd; + + res = read_cpucfg(LOONGARCH_CPUCFG2); + if (!(res & CPUCFG2_LLFTP)) + return 0; + + base_freq = read_cpucfg(LOONGARCH_CPUCFG4); + res = read_cpucfg(LOONGARCH_CPUCFG5); + cfm = res & 0xffff; + cfd = (res >> 16) & 0xffff; + + if (!base_freq || !cfm || !cfd) + return 0; + + return (base_freq * cfm / cfd); +} + +/* + * Initialize the calling CPU's timer interrupt as clockevent device + */ +extern int constant_clockevent_init(void); +extern int constant_clocksource_init(void); + +static inline void clockevent_set_clock(struct clock_event_device *cd, + unsigned int clock) +{ + clockevents_calc_mult_shift(cd, clock, 4); +} + +#endif /* _ASM_TIME_H */ diff --git a/arch/loongarch/include/asm/timex.h b/arch/loongarch/include/asm/timex.h new file mode 100644 index 000000000000..d3ed99a4fdbd --- /dev/null +++ b/arch/loongarch/include/asm/timex.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_TIMEX_H +#define _ASM_TIMEX_H + +#ifdef __KERNEL__ + +#include + +#include +#include + +/* + * Standard way to access the cycle counter. + * Currently only used on SMP for scheduling. + * + * We know that all SMP capable CPUs have cycle counters. + */ + +typedef unsigned long cycles_t; + +#define get_cycles get_cycles + +static inline cycles_t get_cycles(void) +{ + return drdtime(); +} + +#endif /* __KERNEL__ */ + +#endif /* _ASM_TIMEX_H */ diff --git a/arch/loongarch/include/asm/topology.h b/arch/loongarch/include/asm/topology.h new file mode 100644 index 000000000000..9ac71a25207a --- /dev/null +++ b/arch/loongarch/include/asm/topology.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_TOPOLOGY_H +#define __ASM_TOPOLOGY_H + +#include + +#define cpu_logical_map(cpu) 0 + +#include + +static inline void arch_fix_phys_package_id(int num, u32 slot) { } +#endif /* __ASM_TOPOLOGY_H */ diff --git a/arch/loongarch/include/asm/types.h b/arch/loongarch/include/asm/types.h new file mode 100644 index 000000000000..baf15a0dcf8b --- /dev/null +++ b/arch/loongarch/include/asm/types.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_TYPES_H +#define _ASM_TYPES_H + +#include +#include + +#ifdef __ASSEMBLY__ +#define _ULCAST_ +#define _U64CAST_ +#else +#define _ULCAST_ (unsigned long) +#define _U64CAST_ (u64) +#endif + +#endif /* _ASM_TYPES_H */ diff --git a/arch/loongarch/include/uapi/asm/bitsperlong.h b/arch/loongarch/include/uapi/asm/bitsperlong.h new file mode 100644 index 000000000000..00b4ba1e5cdf --- /dev/null +++ b/arch/loongarch/include/uapi/asm/bitsperlong.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __ASM_LOONGARCH_BITSPERLONG_H +#define __ASM_LOONGARCH_BITSPERLONG_H + +#define __BITS_PER_LONG (__SIZEOF_LONG__ * 8) + +#include + +#endif /* __ASM_LOONGARCH_BITSPERLONG_H */ diff --git a/arch/loongarch/include/uapi/asm/byteorder.h b/arch/loongarch/include/uapi/asm/byteorder.h new file mode 100644 index 000000000000..b1722d890deb --- /dev/null +++ b/arch/loongarch/include/uapi/asm/byteorder.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Author: Hanlu Li + * Huacai Chen + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_BYTEORDER_H +#define _ASM_BYTEORDER_H + +#include + +#endif /* _ASM_BYTEORDER_H */ diff --git a/arch/loongarch/include/uapi/asm/reg.h b/arch/loongarch/include/uapi/asm/reg.h new file mode 100644 index 000000000000..90ad910c60eb --- /dev/null +++ b/arch/loongarch/include/uapi/asm/reg.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Various register offset definitions for debuggers, core file + * examiners and whatnot. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __UAPI_ASM_LOONGARCH_REG_H +#define __UAPI_ASM_LOONGARCH_REG_H + +#define LOONGARCH_EF_R0 0 +#define LOONGARCH_EF_R1 1 +#define LOONGARCH_EF_R2 2 +#define LOONGARCH_EF_R3 3 +#define LOONGARCH_EF_R4 4 +#define LOONGARCH_EF_R5 5 +#define LOONGARCH_EF_R6 6 +#define LOONGARCH_EF_R7 7 +#define LOONGARCH_EF_R8 8 +#define LOONGARCH_EF_R9 9 +#define LOONGARCH_EF_R10 10 +#define LOONGARCH_EF_R11 11 +#define LOONGARCH_EF_R12 12 +#define LOONGARCH_EF_R13 13 +#define LOONGARCH_EF_R14 14 +#define LOONGARCH_EF_R15 15 +#define LOONGARCH_EF_R16 16 +#define LOONGARCH_EF_R17 17 +#define LOONGARCH_EF_R18 18 +#define LOONGARCH_EF_R19 19 +#define LOONGARCH_EF_R20 20 +#define LOONGARCH_EF_R21 21 +#define LOONGARCH_EF_R22 22 +#define LOONGARCH_EF_R23 23 +#define LOONGARCH_EF_R24 24 +#define LOONGARCH_EF_R25 25 +#define LOONGARCH_EF_R26 26 +#define LOONGARCH_EF_R27 27 +#define LOONGARCH_EF_R28 28 +#define LOONGARCH_EF_R29 29 +#define LOONGARCH_EF_R30 30 +#define LOONGARCH_EF_R31 31 + +/* + * Saved special registers + */ +#define LOONGARCH_EF_ORIG_A0 32 +#define LOONGARCH_EF_CSR_ERA 33 +#define LOONGARCH_EF_CSR_BADV 34 +#define LOONGARCH_EF_CSR_CRMD 35 +#define LOONGARCH_EF_CSR_PRMD 36 +#define LOONGARCH_EF_CSR_EUEN 37 +#define LOONGARCH_EF_CSR_ECFG 38 +#define LOONGARCH_EF_CSR_ESTAT 39 + +#define LOONGARCH_EF_SIZE 320 /* size in bytes */ + +#endif /* __UAPI_ASM_LOONGARCH_REG_H */ diff --git a/tools/include/uapi/asm/bitsperlong.h b/tools/include/uapi/asm/bitsperlong.h index edba4d93e9e6..da5206517158 100644 --- a/tools/include/uapi/asm/bitsperlong.h +++ b/tools/include/uapi/asm/bitsperlong.h @@ -17,6 +17,8 @@ #include "../../../arch/riscv/include/uapi/asm/bitsperlong.h" #elif defined(__alpha__) #include "../../../arch/alpha/include/uapi/asm/bitsperlong.h" +#elif defined(__loongarch__) +#include "../../../arch/loongarch/include/uapi/asm/bitsperlong.h" #else #include #endif -- cgit From 005f17007f47495dbbb659aa5db7e581065d16e7 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 18 May 2022 13:52:22 -0700 Subject: bitmap: Fix return values to be unsigned Both nodemask and bitmap routines had mixed return values that provided potentially signed return values that could never happen. This was leading to the compiler getting confusing about the range of possible return values (it was thinking things could be negative where they could not be). In preparation for fixing nodemask, fix all the bitmap routines that should be returning unsigned (or bool) values. Cc: Yury Norov Cc: Rasmus Villemoes Cc: Christophe de Dinechin Cc: Alexey Dobriyan Cc: Andy Shevchenko Cc: Andrew Morton Cc: Zhen Lei Signed-off-by: Kees Cook Signed-off-by: Yury Norov --- include/linux/bitmap.h | 25 +++++++++++++------------ lib/bitmap.c | 30 +++++++++++++++--------------- tools/include/linux/bitmap.h | 17 +++++++++-------- tools/lib/bitmap.c | 20 ++++++++++---------- 4 files changed, 47 insertions(+), 45 deletions(-) (limited to 'tools/include') diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 71147b7d721b..2e6cd5681040 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -134,8 +134,8 @@ unsigned long *devm_bitmap_zalloc(struct device *dev, * lib/bitmap.c provides these functions: */ -int __bitmap_equal(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); +bool __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); bool __pure __bitmap_or_equal(const unsigned long *src1, const unsigned long *src2, const unsigned long *src3, @@ -159,10 +159,10 @@ int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, void __bitmap_replace(unsigned long *dst, const unsigned long *old, const unsigned long *new, const unsigned long *mask, unsigned int nbits); -int __bitmap_intersects(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); -int __bitmap_subset(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); +bool __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); +bool __bitmap_subset(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits); void __bitmap_set(unsigned long *map, unsigned int start, int len); void __bitmap_clear(unsigned long *map, unsigned int start, int len); @@ -353,8 +353,8 @@ static inline void bitmap_complement(unsigned long *dst, const unsigned long *sr #endif #define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1) -static inline int bitmap_equal(const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) +static inline bool bitmap_equal(const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) { if (small_const_nbits(nbits)) return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); @@ -384,8 +384,9 @@ static inline bool bitmap_or_equal(const unsigned long *src1, return !(((*src1 | *src2) ^ *src3) & BITMAP_LAST_WORD_MASK(nbits)); } -static inline int bitmap_intersects(const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) +static inline bool bitmap_intersects(const unsigned long *src1, + const unsigned long *src2, + unsigned int nbits) { if (small_const_nbits(nbits)) return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0; @@ -393,8 +394,8 @@ static inline int bitmap_intersects(const unsigned long *src1, return __bitmap_intersects(src1, src2, nbits); } -static inline int bitmap_subset(const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) +static inline bool bitmap_subset(const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) { if (small_const_nbits(nbits)) return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits)); diff --git a/lib/bitmap.c b/lib/bitmap.c index 4061a5dd2bc6..b18e31ea6e66 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -45,19 +45,19 @@ * for the best explanations of this ordering. */ -int __bitmap_equal(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) +bool __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) { unsigned int k, lim = bits/BITS_PER_LONG; for (k = 0; k < lim; ++k) if (bitmap1[k] != bitmap2[k]) - return 0; + return false; if (bits % BITS_PER_LONG) if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) - return 0; + return false; - return 1; + return true; } EXPORT_SYMBOL(__bitmap_equal); @@ -303,33 +303,33 @@ void __bitmap_replace(unsigned long *dst, } EXPORT_SYMBOL(__bitmap_replace); -int __bitmap_intersects(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) +bool __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) { unsigned int k, lim = bits/BITS_PER_LONG; for (k = 0; k < lim; ++k) if (bitmap1[k] & bitmap2[k]) - return 1; + return true; if (bits % BITS_PER_LONG) if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) - return 1; - return 0; + return true; + return false; } EXPORT_SYMBOL(__bitmap_intersects); -int __bitmap_subset(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) +bool __bitmap_subset(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) { unsigned int k, lim = bits/BITS_PER_LONG; for (k = 0; k < lim; ++k) if (bitmap1[k] & ~bitmap2[k]) - return 0; + return false; if (bits % BITS_PER_LONG) if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) - return 0; - return 1; + return false; + return true; } EXPORT_SYMBOL(__bitmap_subset); diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h index ea97804d04d4..afdf93bebaaf 100644 --- a/tools/include/linux/bitmap.h +++ b/tools/include/linux/bitmap.h @@ -16,11 +16,11 @@ void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, const unsigned long *bitmap2, int bits); int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, const unsigned long *bitmap2, unsigned int bits); -int __bitmap_equal(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits); +bool __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits); void bitmap_clear(unsigned long *map, unsigned int start, int len); -int __bitmap_intersects(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits); +bool __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits); #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1))) @@ -162,8 +162,8 @@ static inline int bitmap_and(unsigned long *dst, const unsigned long *src1, #define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1) #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) -static inline int bitmap_equal(const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) +static inline bool bitmap_equal(const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) { if (small_const_nbits(nbits)) return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); @@ -173,8 +173,9 @@ static inline int bitmap_equal(const unsigned long *src1, return __bitmap_equal(src1, src2, nbits); } -static inline int bitmap_intersects(const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) +static inline bool bitmap_intersects(const unsigned long *src1, + const unsigned long *src2, + unsigned int nbits) { if (small_const_nbits(nbits)) return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0; diff --git a/tools/lib/bitmap.c b/tools/lib/bitmap.c index db466ef7be9d..354f8cdc0880 100644 --- a/tools/lib/bitmap.c +++ b/tools/lib/bitmap.c @@ -72,31 +72,31 @@ int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, return result != 0; } -int __bitmap_equal(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) +bool __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) { unsigned int k, lim = bits/BITS_PER_LONG; for (k = 0; k < lim; ++k) if (bitmap1[k] != bitmap2[k]) - return 0; + return false; if (bits % BITS_PER_LONG) if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) - return 0; + return false; - return 1; + return true; } -int __bitmap_intersects(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) +bool __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) { unsigned int k, lim = bits/BITS_PER_LONG; for (k = 0; k < lim; ++k) if (bitmap1[k] & bitmap2[k]) - return 1; + return true; if (bits % BITS_PER_LONG) if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) - return 1; - return 0; + return true; + return false; } -- cgit From 7b6c7a877cc616bc7dc9cd39646fe454acbed48b Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 3 Jun 2022 08:04:44 -0700 Subject: x86/ftrace: Remove OBJECT_FILES_NON_STANDARD usage The file-wide OBJECT_FILES_NON_STANDARD annotation is used with CONFIG_FRAME_POINTER to tell objtool to skip the entire file when frame pointers are enabled. However that annotation is now deprecated because it doesn't work with IBT, where objtool runs on vmlinux.o instead of individual translation units. Instead, use more fine-grained function-specific annotations: - The 'save_mcount_regs' macro does funny things with the frame pointer. Use STACK_FRAME_NON_STANDARD_FP to tell objtool to ignore the functions using it. - The return_to_handler() "function" isn't actually a callable function. Instead of being called, it's returned to. The real return address isn't on the stack, so unwinding is already doomed no matter which unwinder is used. So just remove the STT_FUNC annotation, telling objtool to ignore it. That also removes the implicit ANNOTATE_NOENDBR, which now needs to be made explicit. Fixes the following warning: vmlinux.o: warning: objtool: __fentry__+0x16: return with modified stack frame Fixes: ed53a0d97192 ("x86/alternative: Use .ibt_endbr_seal to seal indirect calls") Reported-by: kernel test robot Signed-off-by: Josh Poimboeuf Link: https://lore.kernel.org/r/b7a7a42fe306aca37826043dac89e113a1acdbac.1654268610.git.jpoimboe@kernel.org --- arch/x86/kernel/Makefile | 4 ---- arch/x86/kernel/ftrace_64.S | 11 ++++++++--- include/linux/objtool.h | 6 ++++++ tools/include/linux/objtool.h | 6 ++++++ 4 files changed, 20 insertions(+), 7 deletions(-) (limited to 'tools/include') diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 03364dc40d8d..4c8b6ae802ac 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -36,10 +36,6 @@ KCSAN_SANITIZE := n OBJECT_FILES_NON_STANDARD_test_nx.o := y -ifdef CONFIG_FRAME_POINTER -OBJECT_FILES_NON_STANDARD_ftrace_$(BITS).o := y -endif - # If instrumentation of this dir is enabled, boot hangs during first second. # Probably could be more selective here, but note that files related to irqs, # boot, dumpstack/stacktrace, etc are either non-interesting or can lead to diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S index 4ec13608d3c6..dfeb227de561 100644 --- a/arch/x86/kernel/ftrace_64.S +++ b/arch/x86/kernel/ftrace_64.S @@ -175,6 +175,7 @@ SYM_INNER_LABEL(ftrace_caller_end, SYM_L_GLOBAL) jmp ftrace_epilogue SYM_FUNC_END(ftrace_caller); +STACK_FRAME_NON_STANDARD_FP(ftrace_caller) SYM_FUNC_START(ftrace_epilogue) /* @@ -282,6 +283,7 @@ SYM_INNER_LABEL(ftrace_regs_caller_end, SYM_L_GLOBAL) jmp ftrace_epilogue SYM_FUNC_END(ftrace_regs_caller) +STACK_FRAME_NON_STANDARD_FP(ftrace_regs_caller) #else /* ! CONFIG_DYNAMIC_FTRACE */ @@ -311,10 +313,14 @@ trace: jmp ftrace_stub SYM_FUNC_END(__fentry__) EXPORT_SYMBOL(__fentry__) +STACK_FRAME_NON_STANDARD_FP(__fentry__) + #endif /* CONFIG_DYNAMIC_FTRACE */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER -SYM_FUNC_START(return_to_handler) +SYM_CODE_START(return_to_handler) + UNWIND_HINT_EMPTY + ANNOTATE_NOENDBR subq $16, %rsp /* Save the return values */ @@ -339,7 +345,6 @@ SYM_FUNC_START(return_to_handler) int3 .Ldo_rop: mov %rdi, (%rsp) - UNWIND_HINT_FUNC RET -SYM_FUNC_END(return_to_handler) +SYM_CODE_END(return_to_handler) #endif diff --git a/include/linux/objtool.h b/include/linux/objtool.h index 6491fa8fba6d..15b940ec1eac 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -143,6 +143,12 @@ struct unwind_hint { .popsection .endm +.macro STACK_FRAME_NON_STANDARD_FP func:req +#ifdef CONFIG_FRAME_POINTER + STACK_FRAME_NON_STANDARD \func +#endif +.endm + .macro ANNOTATE_NOENDBR .Lhere_\@: .pushsection .discard.noendbr diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h index 6491fa8fba6d..15b940ec1eac 100644 --- a/tools/include/linux/objtool.h +++ b/tools/include/linux/objtool.h @@ -143,6 +143,12 @@ struct unwind_hint { .popsection .endm +.macro STACK_FRAME_NON_STANDARD_FP func:req +#ifdef CONFIG_FRAME_POINTER + STACK_FRAME_NON_STANDARD \func +#endif +.endm + .macro ANNOTATE_NOENDBR .Lhere_\@: .pushsection .discard.noendbr -- cgit From 140cd9ec8fdddc0e2d1684e6b69bcd05efbc9549 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 11 Feb 2021 12:50:52 -0300 Subject: tools headers UAPI: Sync linux/prctl.h with the kernel sources To pick the changes in: 9e4ab6c891094720 ("arm64/sme: Implement vector length configuration prctl()s") That don't result in any changes in tooling: $ tools/perf/trace/beauty/prctl_option.sh > before $ cp include/uapi/linux/prctl.h tools/include/uapi/linux/prctl.h $ tools/perf/trace/beauty/prctl_option.sh > after $ diff -u before after $ Just silences this perf tools build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/prctl.h' differs from latest version at 'include/uapi/linux/prctl.h' diff -u tools/include/uapi/linux/prctl.h include/uapi/linux/prctl.h Cc: Catalin Marinas Cc: Mark Brown Link: http://lore.kernel.org/lkml/Yq81we+XFOqlBWyu@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/prctl.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/prctl.h b/tools/include/uapi/linux/prctl.h index e998764f0262..a5e06dcbba13 100644 --- a/tools/include/uapi/linux/prctl.h +++ b/tools/include/uapi/linux/prctl.h @@ -272,6 +272,15 @@ struct prctl_mm_map { # define PR_SCHED_CORE_SCOPE_THREAD_GROUP 1 # define PR_SCHED_CORE_SCOPE_PROCESS_GROUP 2 +/* arm64 Scalable Matrix Extension controls */ +/* Flag values must be in sync with SVE versions */ +#define PR_SME_SET_VL 63 /* set task vector length */ +# define PR_SME_SET_VL_ONEXEC (1 << 18) /* defer effect until exec */ +#define PR_SME_GET_VL 64 /* get task vector length */ +/* Bits common to PR_SME_SET_VL and PR_SME_GET_VL */ +# define PR_SME_VL_LEN_MASK 0xffff +# define PR_SME_VL_INHERIT (1 << 17) /* inherit across exec */ + #define PR_SET_VMA 0x53564d41 # define PR_SET_VMA_ANON_NAME 0 -- cgit From 0fdd435cb4f873b5602913db4f2ba497a5443daf Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 13 Nov 2021 11:08:31 -0300 Subject: tools headers UAPI: Sync drm/i915_drm.h with the kernel sources To pick up the changes in: ecf8eca51f33dbfd ("drm/i915/xehp: Add compute engine ABI") 991b4de3275728fd ("drm/i915/uapi: Add kerneldoc for engine class enum") c94fde8f516610b0 ("drm/i915/uapi: Add DRM_I915_QUERY_GEOMETRY_SUBSLICES") 1c671ad753dbbf5f ("drm/i915/doc: Link query items to their uapi structs") a2e5402691e23269 ("drm/i915/doc: Convert perf UAPI comments to kerneldoc") 462ac1cdf4d7acf1 ("drm/i915/doc: Convert drm_i915_query_topology_info comment to kerneldoc") 034d47b25b2ce627 ("drm/i915/uapi: Document DRM_I915_QUERY_HWCONFIG_BLOB") 78e1fb3112c0ac44 ("drm/i915/uapi: Add query for hwconfig blob") That don't add any new ioctl, so no changes in tooling. This silences this perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/drm/i915_drm.h' differs from latest version at 'include/uapi/drm/i915_drm.h' diff -u tools/include/uapi/drm/i915_drm.h include/uapi/drm/i915_drm.h Cc: John Harrison Cc: Matt Atwood Cc: Matt Roper Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Link: http://lore.kernel.org/lkml/YrDi4ALYjv9Mdocq@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/drm/i915_drm.h | 353 +++++++++++++++++++++++++++++--------- 1 file changed, 272 insertions(+), 81 deletions(-) (limited to 'tools/include') diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index 05c3642aaece..a2def7b27009 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h @@ -154,25 +154,77 @@ enum i915_mocs_table_index { I915_MOCS_CACHED, }; -/* +/** + * enum drm_i915_gem_engine_class - uapi engine type enumeration + * * Different engines serve different roles, and there may be more than one - * engine serving each role. enum drm_i915_gem_engine_class provides a - * classification of the role of the engine, which may be used when requesting - * operations to be performed on a certain subset of engines, or for providing - * information about that group. + * engine serving each role. This enum provides a classification of the role + * of the engine, which may be used when requesting operations to be performed + * on a certain subset of engines, or for providing information about that + * group. */ enum drm_i915_gem_engine_class { + /** + * @I915_ENGINE_CLASS_RENDER: + * + * Render engines support instructions used for 3D, Compute (GPGPU), + * and programmable media workloads. These instructions fetch data and + * dispatch individual work items to threads that operate in parallel. + * The threads run small programs (called "kernels" or "shaders") on + * the GPU's execution units (EUs). + */ I915_ENGINE_CLASS_RENDER = 0, + + /** + * @I915_ENGINE_CLASS_COPY: + * + * Copy engines (also referred to as "blitters") support instructions + * that move blocks of data from one location in memory to another, + * or that fill a specified location of memory with fixed data. + * Copy engines can perform pre-defined logical or bitwise operations + * on the source, destination, or pattern data. + */ I915_ENGINE_CLASS_COPY = 1, + + /** + * @I915_ENGINE_CLASS_VIDEO: + * + * Video engines (also referred to as "bit stream decode" (BSD) or + * "vdbox") support instructions that perform fixed-function media + * decode and encode. + */ I915_ENGINE_CLASS_VIDEO = 2, + + /** + * @I915_ENGINE_CLASS_VIDEO_ENHANCE: + * + * Video enhancement engines (also referred to as "vebox") support + * instructions related to image enhancement. + */ I915_ENGINE_CLASS_VIDEO_ENHANCE = 3, - /* should be kept compact */ + /** + * @I915_ENGINE_CLASS_COMPUTE: + * + * Compute engines support a subset of the instructions available + * on render engines: compute engines support Compute (GPGPU) and + * programmable media workloads, but do not support the 3D pipeline. + */ + I915_ENGINE_CLASS_COMPUTE = 4, + + /* Values in this enum should be kept compact. */ + /** + * @I915_ENGINE_CLASS_INVALID: + * + * Placeholder value to represent an invalid engine class assignment. + */ I915_ENGINE_CLASS_INVALID = -1 }; -/* +/** + * struct i915_engine_class_instance - Engine class/instance identifier + * * There may be more than one engine fulfilling any role within the system. * Each engine of a class is given a unique instance number and therefore * any engine can be specified by its class:instance tuplet. APIs that allow @@ -180,10 +232,21 @@ enum drm_i915_gem_engine_class { * for this identification. */ struct i915_engine_class_instance { - __u16 engine_class; /* see enum drm_i915_gem_engine_class */ - __u16 engine_instance; + /** + * @engine_class: + * + * Engine class from enum drm_i915_gem_engine_class + */ + __u16 engine_class; #define I915_ENGINE_CLASS_INVALID_NONE -1 #define I915_ENGINE_CLASS_INVALID_VIRTUAL -2 + + /** + * @engine_instance: + * + * Engine instance. + */ + __u16 engine_instance; }; /** @@ -2657,24 +2720,65 @@ enum drm_i915_perf_record_type { DRM_I915_PERF_RECORD_MAX /* non-ABI */ }; -/* +/** + * struct drm_i915_perf_oa_config + * * Structure to upload perf dynamic configuration into the kernel. */ struct drm_i915_perf_oa_config { - /** String formatted like "%08x-%04x-%04x-%04x-%012x" */ + /** + * @uuid: + * + * String formatted like "%\08x-%\04x-%\04x-%\04x-%\012x" + */ char uuid[36]; + /** + * @n_mux_regs: + * + * Number of mux regs in &mux_regs_ptr. + */ __u32 n_mux_regs; + + /** + * @n_boolean_regs: + * + * Number of boolean regs in &boolean_regs_ptr. + */ __u32 n_boolean_regs; + + /** + * @n_flex_regs: + * + * Number of flex regs in &flex_regs_ptr. + */ __u32 n_flex_regs; - /* - * These fields are pointers to tuples of u32 values (register address, - * value). For example the expected length of the buffer pointed by - * mux_regs_ptr is (2 * sizeof(u32) * n_mux_regs). + /** + * @mux_regs_ptr: + * + * Pointer to tuples of u32 values (register address, value) for mux + * registers. Expected length of buffer is (2 * sizeof(u32) * + * &n_mux_regs). */ __u64 mux_regs_ptr; + + /** + * @boolean_regs_ptr: + * + * Pointer to tuples of u32 values (register address, value) for mux + * registers. Expected length of buffer is (2 * sizeof(u32) * + * &n_boolean_regs). + */ __u64 boolean_regs_ptr; + + /** + * @flex_regs_ptr: + * + * Pointer to tuples of u32 values (register address, value) for mux + * registers. Expected length of buffer is (2 * sizeof(u32) * + * &n_flex_regs). + */ __u64 flex_regs_ptr; }; @@ -2685,12 +2789,24 @@ struct drm_i915_perf_oa_config { * @data_ptr is also depends on the specific @query_id. */ struct drm_i915_query_item { - /** @query_id: The id for this query */ + /** + * @query_id: + * + * The id for this query. Currently accepted query IDs are: + * - %DRM_I915_QUERY_TOPOLOGY_INFO (see struct drm_i915_query_topology_info) + * - %DRM_I915_QUERY_ENGINE_INFO (see struct drm_i915_engine_info) + * - %DRM_I915_QUERY_PERF_CONFIG (see struct drm_i915_query_perf_config) + * - %DRM_I915_QUERY_MEMORY_REGIONS (see struct drm_i915_query_memory_regions) + * - %DRM_I915_QUERY_HWCONFIG_BLOB (see `GuC HWCONFIG blob uAPI`) + * - %DRM_I915_QUERY_GEOMETRY_SUBSLICES (see struct drm_i915_query_topology_info) + */ __u64 query_id; -#define DRM_I915_QUERY_TOPOLOGY_INFO 1 -#define DRM_I915_QUERY_ENGINE_INFO 2 -#define DRM_I915_QUERY_PERF_CONFIG 3 -#define DRM_I915_QUERY_MEMORY_REGIONS 4 +#define DRM_I915_QUERY_TOPOLOGY_INFO 1 +#define DRM_I915_QUERY_ENGINE_INFO 2 +#define DRM_I915_QUERY_PERF_CONFIG 3 +#define DRM_I915_QUERY_MEMORY_REGIONS 4 +#define DRM_I915_QUERY_HWCONFIG_BLOB 5 +#define DRM_I915_QUERY_GEOMETRY_SUBSLICES 6 /* Must be kept compact -- no holes and well documented */ /** @@ -2706,14 +2822,17 @@ struct drm_i915_query_item { /** * @flags: * - * When query_id == DRM_I915_QUERY_TOPOLOGY_INFO, must be 0. + * When &query_id == %DRM_I915_QUERY_TOPOLOGY_INFO, must be 0. * - * When query_id == DRM_I915_QUERY_PERF_CONFIG, must be one of the + * When &query_id == %DRM_I915_QUERY_PERF_CONFIG, must be one of the * following: * - * - DRM_I915_QUERY_PERF_CONFIG_LIST - * - DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID - * - DRM_I915_QUERY_PERF_CONFIG_FOR_UUID + * - %DRM_I915_QUERY_PERF_CONFIG_LIST + * - %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID + * - %DRM_I915_QUERY_PERF_CONFIG_FOR_UUID + * + * When &query_id == %DRM_I915_QUERY_GEOMETRY_SUBSLICES must contain + * a struct i915_engine_class_instance that references a render engine. */ __u32 flags; #define DRM_I915_QUERY_PERF_CONFIG_LIST 1 @@ -2771,66 +2890,112 @@ struct drm_i915_query { __u64 items_ptr; }; -/* - * Data written by the kernel with query DRM_I915_QUERY_TOPOLOGY_INFO : - * - * data: contains the 3 pieces of information : - * - * - the slice mask with one bit per slice telling whether a slice is - * available. The availability of slice X can be queried with the following - * formula : - * - * (data[X / 8] >> (X % 8)) & 1 - * - * - the subslice mask for each slice with one bit per subslice telling - * whether a subslice is available. Gen12 has dual-subslices, which are - * similar to two gen11 subslices. For gen12, this array represents dual- - * subslices. The availability of subslice Y in slice X can be queried - * with the following formula : - * - * (data[subslice_offset + - * X * subslice_stride + - * Y / 8] >> (Y % 8)) & 1 - * - * - the EU mask for each subslice in each slice with one bit per EU telling - * whether an EU is available. The availability of EU Z in subslice Y in - * slice X can be queried with the following formula : +/** + * struct drm_i915_query_topology_info * - * (data[eu_offset + - * (X * max_subslices + Y) * eu_stride + - * Z / 8] >> (Z % 8)) & 1 + * Describes slice/subslice/EU information queried by + * %DRM_I915_QUERY_TOPOLOGY_INFO */ struct drm_i915_query_topology_info { - /* + /** + * @flags: + * * Unused for now. Must be cleared to zero. */ __u16 flags; + /** + * @max_slices: + * + * The number of bits used to express the slice mask. + */ __u16 max_slices; + + /** + * @max_subslices: + * + * The number of bits used to express the subslice mask. + */ __u16 max_subslices; + + /** + * @max_eus_per_subslice: + * + * The number of bits in the EU mask that correspond to a single + * subslice's EUs. + */ __u16 max_eus_per_subslice; - /* + /** + * @subslice_offset: + * * Offset in data[] at which the subslice masks are stored. */ __u16 subslice_offset; - /* + /** + * @subslice_stride: + * * Stride at which each of the subslice masks for each slice are * stored. */ __u16 subslice_stride; - /* + /** + * @eu_offset: + * * Offset in data[] at which the EU masks are stored. */ __u16 eu_offset; - /* + /** + * @eu_stride: + * * Stride at which each of the EU masks for each subslice are stored. */ __u16 eu_stride; + /** + * @data: + * + * Contains 3 pieces of information : + * + * - The slice mask with one bit per slice telling whether a slice is + * available. The availability of slice X can be queried with the + * following formula : + * + * .. code:: c + * + * (data[X / 8] >> (X % 8)) & 1 + * + * Starting with Xe_HP platforms, Intel hardware no longer has + * traditional slices so i915 will always report a single slice + * (hardcoded slicemask = 0x1) which contains all of the platform's + * subslices. I.e., the mask here does not reflect any of the newer + * hardware concepts such as "gslices" or "cslices" since userspace + * is capable of inferring those from the subslice mask. + * + * - The subslice mask for each slice with one bit per subslice telling + * whether a subslice is available. Starting with Gen12 we use the + * term "subslice" to refer to what the hardware documentation + * describes as a "dual-subslices." The availability of subslice Y + * in slice X can be queried with the following formula : + * + * .. code:: c + * + * (data[subslice_offset + X * subslice_stride + Y / 8] >> (Y % 8)) & 1 + * + * - The EU mask for each subslice in each slice, with one bit per EU + * telling whether an EU is available. The availability of EU Z in + * subslice Y in slice X can be queried with the following formula : + * + * .. code:: c + * + * (data[eu_offset + + * (X * max_subslices + Y) * eu_stride + + * Z / 8 + * ] >> (Z % 8)) & 1 + */ __u8 data[]; }; @@ -2951,52 +3116,68 @@ struct drm_i915_query_engine_info { struct drm_i915_engine_info engines[]; }; -/* - * Data written by the kernel with query DRM_I915_QUERY_PERF_CONFIG. +/** + * struct drm_i915_query_perf_config + * + * Data written by the kernel with query %DRM_I915_QUERY_PERF_CONFIG and + * %DRM_I915_QUERY_GEOMETRY_SUBSLICES. */ struct drm_i915_query_perf_config { union { - /* - * When query_item.flags == DRM_I915_QUERY_PERF_CONFIG_LIST, i915 sets - * this fields to the number of configurations available. + /** + * @n_configs: + * + * When &drm_i915_query_item.flags == + * %DRM_I915_QUERY_PERF_CONFIG_LIST, i915 sets this fields to + * the number of configurations available. */ __u64 n_configs; - /* - * When query_id == DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID, - * i915 will use the value in this field as configuration - * identifier to decide what data to write into config_ptr. + /** + * @config: + * + * When &drm_i915_query_item.flags == + * %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID, i915 will use the + * value in this field as configuration identifier to decide + * what data to write into config_ptr. */ __u64 config; - /* - * When query_id == DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID, - * i915 will use the value in this field as configuration - * identifier to decide what data to write into config_ptr. + /** + * @uuid: + * + * When &drm_i915_query_item.flags == + * %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID, i915 will use the + * value in this field as configuration identifier to decide + * what data to write into config_ptr. * * String formatted like "%08x-%04x-%04x-%04x-%012x" */ char uuid[36]; }; - /* + /** + * @flags: + * * Unused for now. Must be cleared to zero. */ __u32 flags; - /* - * When query_item.flags == DRM_I915_QUERY_PERF_CONFIG_LIST, i915 will - * write an array of __u64 of configuration identifiers. + /** + * @data: * - * When query_item.flags == DRM_I915_QUERY_PERF_CONFIG_DATA, i915 will - * write a struct drm_i915_perf_oa_config. If the following fields of - * drm_i915_perf_oa_config are set not set to 0, i915 will write into - * the associated pointers the values of submitted when the + * When &drm_i915_query_item.flags == %DRM_I915_QUERY_PERF_CONFIG_LIST, + * i915 will write an array of __u64 of configuration identifiers. + * + * When &drm_i915_query_item.flags == %DRM_I915_QUERY_PERF_CONFIG_DATA, + * i915 will write a struct drm_i915_perf_oa_config. If the following + * fields of struct drm_i915_perf_oa_config are not set to 0, i915 will + * write into the associated pointers the values of submitted when the * configuration was created : * - * - n_mux_regs - * - n_boolean_regs - * - n_flex_regs + * - &drm_i915_perf_oa_config.n_mux_regs + * - &drm_i915_perf_oa_config.n_boolean_regs + * - &drm_i915_perf_oa_config.n_flex_regs */ __u8 data[]; }; @@ -3134,6 +3315,16 @@ struct drm_i915_query_memory_regions { struct drm_i915_memory_region_info regions[]; }; +/** + * DOC: GuC HWCONFIG blob uAPI + * + * The GuC produces a blob with information about the current device. + * i915 reads this blob from GuC and makes it available via this uAPI. + * + * The format and meaning of the blob content are documented in the + * Programmer's Reference Manual. + */ + /** * struct drm_i915_gem_create_ext - Existing gem_create behaviour, with added * extension support using struct i915_user_extension. -- cgit From e2213a2dc63e1b2941728a9a938c2196548e980f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 14 Apr 2020 09:12:55 -0300 Subject: tools include UAPI: Sync linux/vhost.h with the kernel sources To get the changes in: 84d7c8fd3aade2fe ("vhost-vdpa: introduce uAPI to set group ASID") 2d1fcb7758e49fd9 ("vhost-vdpa: uAPI to get virtqueue group id") a0c95f201170bd55 ("vhost-vdpa: introduce uAPI to get the number of address spaces") 3ace88bd37436abc ("vhost-vdpa: introduce uAPI to get the number of virtqueue groups") 175d493c3c3e09a3 ("vhost: move the backend feature bits to vhost_types.h") Silencing this perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/vhost.h' differs from latest version at 'include/uapi/linux/vhost.h' diff -u tools/include/uapi/linux/vhost.h include/uapi/linux/vhost.h To pick up these changes and support them: $ tools/perf/trace/beauty/vhost_virtio_ioctl.sh > before $ cp include/uapi/linux/vhost.h tools/include/uapi/linux/vhost.h $ tools/perf/trace/beauty/vhost_virtio_ioctl.sh > after $ diff -u before after --- before 2022-06-26 12:04:35.982003781 -0300 +++ after 2022-06-26 12:04:43.819972476 -0300 @@ -28,6 +28,7 @@ [0x74] = "VDPA_SET_CONFIG", [0x75] = "VDPA_SET_VRING_ENABLE", [0x77] = "VDPA_SET_CONFIG_CALL", + [0x7C] = "VDPA_SET_GROUP_ASID", }; static const char *vhost_virtio_ioctl_read_cmds[] = { [0x00] = "GET_FEATURES", @@ -39,5 +40,8 @@ [0x76] = "VDPA_GET_VRING_NUM", [0x78] = "VDPA_GET_IOVA_RANGE", [0x79] = "VDPA_GET_CONFIG_SIZE", + [0x7A] = "VDPA_GET_AS_NUM", + [0x7B] = "VDPA_GET_VRING_GROUP", [0x80] = "VDPA_GET_VQS_COUNT", + [0x81] = "VDPA_GET_GROUP_NUM", }; $ Cc: Adrian Hunter Cc: Gautam Dawar Cc: Jiri Olsa Cc: Michael S. Tsirkin Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/Yrh3xMYbfeAD0MFL@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/vhost.h | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/vhost.h b/tools/include/uapi/linux/vhost.h index 5d99e7c242a2..cab645d4a645 100644 --- a/tools/include/uapi/linux/vhost.h +++ b/tools/include/uapi/linux/vhost.h @@ -89,11 +89,6 @@ /* Set or get vhost backend capability */ -/* Use message type V2 */ -#define VHOST_BACKEND_F_IOTLB_MSG_V2 0x1 -/* IOTLB can accept batching hints */ -#define VHOST_BACKEND_F_IOTLB_BATCH 0x2 - #define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64) #define VHOST_GET_BACKEND_FEATURES _IOR(VHOST_VIRTIO, 0x26, __u64) @@ -150,11 +145,30 @@ /* Get the valid iova range */ #define VHOST_VDPA_GET_IOVA_RANGE _IOR(VHOST_VIRTIO, 0x78, \ struct vhost_vdpa_iova_range) - /* Get the config size */ #define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32) /* Get the count of all virtqueues */ #define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) +/* Get the number of virtqueue groups. */ +#define VHOST_VDPA_GET_GROUP_NUM _IOR(VHOST_VIRTIO, 0x81, __u32) + +/* Get the number of address spaces. */ +#define VHOST_VDPA_GET_AS_NUM _IOR(VHOST_VIRTIO, 0x7A, unsigned int) + +/* Get the group for a virtqueue: read index, write group in num, + * The virtqueue index is stored in the index field of + * vhost_vring_state. The group for this specific virtqueue is + * returned via num field of vhost_vring_state. + */ +#define VHOST_VDPA_GET_VRING_GROUP _IOWR(VHOST_VIRTIO, 0x7B, \ + struct vhost_vring_state) +/* Set the ASID for a virtqueue group. The group index is stored in + * the index field of vhost_vring_state, the ASID associated with this + * group is stored at num field of vhost_vring_state. + */ +#define VHOST_VDPA_SET_GROUP_ASID _IOW(VHOST_VIRTIO, 0x7C, \ + struct vhost_vring_state) + #endif -- cgit From 7fe718fb8f3f543da1f04ca08bf652dd2afb55f8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 9 May 2021 09:39:02 -0300 Subject: tools headers UAPI: Sync linux/kvm.h with the kernel sources To pick the changes in: bfbab44568779e16 ("KVM: arm64: Implement PSCI SYSTEM_SUSPEND") 7b33a09d036ffd9a ("KVM: arm64: Add support for userspace to suspend a vCPU") ffbb61d09fc56c85 ("KVM: x86: Accept KVM_[GS]ET_TSC_KHZ as a VM ioctl.") 661a20fab7d156cf ("KVM: x86/xen: Advertise and document KVM_XEN_HVM_CONFIG_EVTCHN_SEND") fde0451be8fb3208 ("KVM: x86/xen: Support per-vCPU event channel upcall via local APIC") 28d1629f751c4a5f ("KVM: x86/xen: Kernel acceleration for XENVER_version") 536395260582be74 ("KVM: x86/xen: handle PV timers oneshot mode") 942c2490c23f2800 ("KVM: x86/xen: Add KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID") 2fd6df2f2b47d430 ("KVM: x86/xen: intercept EVTCHNOP_send from guests") 35025735a79eaa89 ("KVM: x86/xen: Support direct injection of event channel events") That automatically adds support for this new ioctl: $ tools/perf/trace/beauty/kvm_ioctl.sh > before $ cp include/uapi/linux/kvm.h tools/include/uapi/linux/kvm.h $ tools/perf/trace/beauty/kvm_ioctl.sh > after $ diff -u before after --- before 2022-06-28 12:13:07.281150509 -0300 +++ after 2022-06-28 12:13:16.423392896 -0300 @@ -98,6 +98,7 @@ [0xcc] = "GET_SREGS2", [0xcd] = "SET_SREGS2", [0xce] = "GET_STATS_FD", + [0xd0] = "XEN_HVM_EVTCHN_SEND", [0xe0] = "CREATE_DEVICE", [0xe1] = "SET_DEVICE_ATTR", [0xe2] = "GET_DEVICE_ATTR", $ This silences these perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/kvm.h' differs from latest version at 'include/uapi/linux/kvm.h' diff -u tools/include/uapi/linux/kvm.h include/uapi/linux/kvm.h Cc: Adrian Hunter Cc: David Woodhouse Cc: Ian Rogers Cc: Jiri Olsa Cc: Joao Martins Cc: Marc Zyngier Cc: Namhyung Kim Cc: Oliver Upton Cc: Paolo Bonzini Link: http://lore.kernel.org/lkml/Yrs4RE+qfgTaWdAt@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/kvm.h | 54 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) (limited to 'tools/include') diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 6a184d260c7f..5088bd9f1922 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -444,6 +444,9 @@ struct kvm_run { #define KVM_SYSTEM_EVENT_SHUTDOWN 1 #define KVM_SYSTEM_EVENT_RESET 2 #define KVM_SYSTEM_EVENT_CRASH 3 +#define KVM_SYSTEM_EVENT_WAKEUP 4 +#define KVM_SYSTEM_EVENT_SUSPEND 5 +#define KVM_SYSTEM_EVENT_SEV_TERM 6 __u32 type; __u32 ndata; union { @@ -646,6 +649,7 @@ struct kvm_vapic_addr { #define KVM_MP_STATE_OPERATING 7 #define KVM_MP_STATE_LOAD 8 #define KVM_MP_STATE_AP_RESET_HOLD 9 +#define KVM_MP_STATE_SUSPENDED 10 struct kvm_mp_state { __u32 mp_state; @@ -1150,8 +1154,9 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_S390_MEM_OP_EXTENSION 211 #define KVM_CAP_PMU_CAPABILITY 212 #define KVM_CAP_DISABLE_QUIRKS2 213 -/* #define KVM_CAP_VM_TSC_CONTROL 214 */ +#define KVM_CAP_VM_TSC_CONTROL 214 #define KVM_CAP_SYSTEM_EVENT_DATA 215 +#define KVM_CAP_ARM_SYSTEM_SUSPEND 216 #ifdef KVM_CAP_IRQ_ROUTING @@ -1240,6 +1245,7 @@ struct kvm_x86_mce { #define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2) #define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3) #define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4) +#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5) struct kvm_xen_hvm_config { __u32 flags; @@ -1478,7 +1484,8 @@ struct kvm_s390_ucas_mapping { #define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2) /* Available with KVM_CAP_PPC_GET_PVINFO */ #define KVM_PPC_GET_PVINFO _IOW(KVMIO, 0xa1, struct kvm_ppc_pvinfo) -/* Available with KVM_CAP_TSC_CONTROL */ +/* Available with KVM_CAP_TSC_CONTROL for a vCPU, or with +* KVM_CAP_VM_TSC_CONTROL to set defaults for a VM */ #define KVM_SET_TSC_KHZ _IO(KVMIO, 0xa2) #define KVM_GET_TSC_KHZ _IO(KVMIO, 0xa3) /* Available with KVM_CAP_PCI_2_3 */ @@ -1694,6 +1701,32 @@ struct kvm_xen_hvm_attr { struct { __u64 gfn; } shared_info; + struct { + __u32 send_port; + __u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */ + __u32 flags; +#define KVM_XEN_EVTCHN_DEASSIGN (1 << 0) +#define KVM_XEN_EVTCHN_UPDATE (1 << 1) +#define KVM_XEN_EVTCHN_RESET (1 << 2) + /* + * Events sent by the guest are either looped back to + * the guest itself (potentially on a different port#) + * or signalled via an eventfd. + */ + union { + struct { + __u32 port; + __u32 vcpu; + __u32 priority; + } port; + struct { + __u32 port; /* Zero for eventfd */ + __s32 fd; + } eventfd; + __u32 padding[4]; + } deliver; + } evtchn; + __u32 xen_version; __u64 pad[8]; } u; }; @@ -1702,11 +1735,17 @@ struct kvm_xen_hvm_attr { #define KVM_XEN_ATTR_TYPE_LONG_MODE 0x0 #define KVM_XEN_ATTR_TYPE_SHARED_INFO 0x1 #define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR 0x2 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ +#define KVM_XEN_ATTR_TYPE_EVTCHN 0x3 +#define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4 /* Per-vCPU Xen attributes */ #define KVM_XEN_VCPU_GET_ATTR _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr) #define KVM_XEN_VCPU_SET_ATTR _IOW(KVMIO, 0xcb, struct kvm_xen_vcpu_attr) +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ +#define KVM_XEN_HVM_EVTCHN_SEND _IOW(KVMIO, 0xd0, struct kvm_irq_routing_xen_evtchn) + #define KVM_GET_SREGS2 _IOR(KVMIO, 0xcc, struct kvm_sregs2) #define KVM_SET_SREGS2 _IOW(KVMIO, 0xcd, struct kvm_sregs2) @@ -1724,6 +1763,13 @@ struct kvm_xen_vcpu_attr { __u64 time_blocked; __u64 time_offline; } runstate; + __u32 vcpu_id; + struct { + __u32 port; + __u32 priority; + __u64 expires_ns; + } timer; + __u8 vector; } u; }; @@ -1734,6 +1780,10 @@ struct kvm_xen_vcpu_attr { #define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT 0x3 #define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA 0x4 #define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 0x5 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ +#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID 0x6 +#define KVM_XEN_VCPU_ATTR_TYPE_TIMER 0x7 +#define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR 0x8 /* Secure Encrypted Virtualization command */ enum sev_cmd_id { -- cgit