Skip to content

Commit

Permalink
evl: add support for compat mode
Browse files Browse the repository at this point in the history
Compat mode (CONFIG_COMPAT) allows application binaries built for a
32bit architecture to issue system calls to a 64bit kernel which
implements such compatibility support.

This work builds on the y2038 sanitization which eliminated the
remaining assumptions about the size of native long integers in the
same move.  Although these changes enable armv7 binaries to call an
armv8 kernel, most of them are architecture-independent, and follow
this pattern:

- .compat_ioctl and .compat_oob_ioctl handlers are added to all file
  operations structs, pointing at compat_ptr_ioctl()
  compat_ptr_oob_ioctl() respectively.

- all pointers passed by applications within ioctl() argument structs
  are conveyed as generic 64bit values.

These changes mandate upgrading the ABI revision to Freescale#20.

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
  • Loading branch information
pgerum authored and ldts committed Jun 22, 2023
1 parent 34f0bbb commit 9e123d4
Show file tree
Hide file tree
Showing 25 changed files with 329 additions and 227 deletions.
47 changes: 28 additions & 19 deletions arch/arm/include/asm/evl/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,34 @@
#include <asm/unistd.h>
#include <asm/ptrace.h>
#include <asm/syscall.h>
#include <uapi/asm/dovetail.h>
#include <uapi/asm-generic/dovetail.h>

#define raw_put_user(src, dst) __put_user(src, dst)
#define raw_get_user(dst, src) __get_user(dst, src)

#define is_oob_syscall(__regs) ((__regs)->ARM_r7 == __ARM_NR_dovetail)
#define oob_syscall_nr(__regs) ((__regs)->ARM_ORIG_r0)

#define oob_retval(__regs) ((__regs)->ARM_r0)
#define oob_arg1(__regs) ((__regs)->ARM_r1)
#define oob_arg2(__regs) ((__regs)->ARM_r2)
#define oob_arg3(__regs) ((__regs)->ARM_r3)
#define oob_arg4(__regs) ((__regs)->ARM_r4)
#define oob_arg5(__regs) ((__regs)->ARM_r5)

/*
* Fetch and test inband syscall number (valid only if
* !is_oob_syscall(__regs)).
*/
#define inband_syscall_nr(__regs, __nr) \
({ \
*(__nr) = (__regs)->ARM_r7; \
*(__nr) < NR_syscalls || *(__nr) >= __ARM_NR_BASE; \
})
#define oob_arg1(__regs) ((__regs)->ARM_r0)
#define oob_arg2(__regs) ((__regs)->ARM_r1)
#define oob_arg3(__regs) ((__regs)->ARM_r2)
#define oob_arg4(__regs) ((__regs)->ARM_r3)
#define oob_arg5(__regs) ((__regs)->ARM_r4)

static inline bool is_oob_syscall(struct pt_regs *regs)
{
return !!(regs->ARM_r7 & __OOB_SYSCALL_BIT);
}

static inline unsigned int oob_syscall_nr(struct pt_regs *regs)
{
return regs->ARM_r7 & ~__OOB_SYSCALL_BIT;
}

static inline
bool inband_syscall_nr(struct pt_regs *regs, unsigned int *nr)
{
*nr = regs->ARM_r7;
return *nr < NR_syscalls || *nr >= __ARM_NR_BASE;
}

static inline void
set_oob_error(struct pt_regs *regs, int err)
Expand All @@ -43,4 +47,9 @@ void set_oob_retval(struct pt_regs *regs, long ret)
oob_retval(regs) = ret;
}

static inline bool is_compat_oob_call(void)
{
return false;
}

#endif /* !_EVL_ARM_ASM_SYSCALL_H */
53 changes: 35 additions & 18 deletions arch/arm64/include/asm/evl/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,58 @@
#include <linux/uaccess.h>
#include <asm/unistd.h>
#include <asm/ptrace.h>
#include <uapi/asm/evl/syscall.h>
#include <uapi/asm-generic/dovetail.h>

#define raw_put_user(src, dst) __put_user(src, dst)
#define raw_get_user(dst, src) __get_user(dst, src)

#define is_oob_syscall(__regs) ((__regs)->syscallno & __EVL_SYSCALL_BIT)
#define oob_syscall_nr(__regs) ((__regs)->syscallno & ~__EVL_SYSCALL_BIT)

#define oob_retval(__regs) ((__regs)->regs[0])
#define oob_arg1(__regs) ((__regs)->regs[0])
#define oob_arg2(__regs) ((__regs)->regs[1])
#define oob_arg3(__regs) ((__regs)->regs[2])
#define oob_arg4(__regs) ((__regs)->regs[3])
#define oob_arg5(__regs) ((__regs)->regs[4])

/*
* Fetch and test inband syscall number (valid only if
* !is_oob_syscall(__regs)).
*/
#define inband_syscall_nr(__regs, __nr) \
({ \
*(__nr) = oob_syscall_nr(__regs); \
!is_oob_syscall(__regs); \
})

static inline void
set_oob_error(struct pt_regs *regs, int err)
#define __ARM_NR_BASE_compat 0xf0000

static inline bool is_oob_syscall(const struct pt_regs *regs)
{
return !!(regs->syscallno & __OOB_SYSCALL_BIT);
}

static inline unsigned int oob_syscall_nr(const struct pt_regs *regs)
{
return regs->syscallno & ~__OOB_SYSCALL_BIT;
}

static inline bool
inband_syscall_nr(struct pt_regs *regs, unsigned int *nr)
{
*nr = oob_syscall_nr(regs);

return !is_oob_syscall(regs);
}

static inline void set_oob_error(struct pt_regs *regs, int err)
{
oob_retval(regs) = err;
}

static inline
void set_oob_retval(struct pt_regs *regs, long ret)
static inline void set_oob_retval(struct pt_regs *regs, long ret)
{
oob_retval(regs) = ret;
}

#ifdef CONFIG_COMPAT
static inline bool is_compat_oob_call(void)
{
return is_compat_task();
}
#else
static inline bool is_compat_oob_call(void)
{
return false;
}
#endif

#endif /* !_EVL_ARM64_ASM_SYSCALL_H */
7 changes: 0 additions & 7 deletions arch/arm64/include/uapi/asm/evl/syscall.h

This file was deleted.

43 changes: 25 additions & 18 deletions arch/x86/include/asm/evl/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,48 @@
#include <linux/uaccess.h>
#include <asm/unistd.h>
#include <asm/ptrace.h>
#include <uapi/asm/evl/syscall.h>
#include <uapi/asm-generic/dovetail.h>

#define raw_put_user(src, dst) __put_user(src, dst)
#define raw_get_user(dst, src) __get_user(dst, src)

#define is_oob_syscall(__regs) ((__regs)->orig_ax & __EVL_SYSCALL_BIT)
#define oob_syscall_nr(__regs) ((__regs)->orig_ax & ~__EVL_SYSCALL_BIT)

#define oob_retval(__regs) ((__regs)->ax)
#define oob_arg1(__regs) ((__regs)->di)
#define oob_arg2(__regs) ((__regs)->si)
#define oob_arg3(__regs) ((__regs)->dx)
#define oob_arg4(__regs) ((__regs)->r10)
#define oob_arg5(__regs) ((__regs)->r8)

/*
* Fetch and test inband syscall number (valid only if
* !is_oob_syscall(__regs)).
*/
#define inband_syscall_nr(__regs, __nr) \
({ \
*(__nr) = oob_syscall_nr(__regs); \
!is_oob_syscall(__regs); \
})

static inline void
set_oob_error(struct pt_regs *regs, int err)
static inline bool is_oob_syscall(const struct pt_regs *regs)
{
oob_retval(regs) = err;
return !!(regs->orig_ax & __OOB_SYSCALL_BIT);
}

static inline unsigned int oob_syscall_nr(const struct pt_regs *regs)
{
return regs->orig_ax & ~__OOB_SYSCALL_BIT;
}

static inline
void set_oob_retval(struct pt_regs *regs, long ret)
bool inband_syscall_nr(struct pt_regs *regs, unsigned int *nr)
{
*nr = oob_syscall_nr(regs);
return !is_oob_syscall(regs);
}

static inline void set_oob_error(struct pt_regs *regs, int err)
{
oob_retval(regs) = err;
}

static inline void set_oob_retval(struct pt_regs *regs, long ret)
{
oob_retval(regs) = ret;
}

static inline bool is_compat_oob_call(void)
{
return in_ia32_syscall();
}

#endif /* !_EVL_X86_ASM_SYSCALL_H */
7 changes: 0 additions & 7 deletions arch/x86/include/uapi/asm/evl/syscall.h

This file was deleted.

4 changes: 4 additions & 0 deletions drivers/evl/hectic.c
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,10 @@ static const struct file_operations hectic_fops = {
.release = hectic_release,
.unlocked_ioctl = hectic_ioctl,
.oob_ioctl = hectic_oob_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_ptr_ioctl,
.compat_oob_ioctl = compat_ptr_oob_ioctl,
#endif
};

static dev_t hectic_devt;
Expand Down
15 changes: 10 additions & 5 deletions drivers/evl/latmus.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/uaccess.h>
#include <evl/file.h>
#include <evl/flag.h>
#include <evl/clock.h>
#include <evl/thread.h>
#include <evl/xbuf.h>
#include <evl/uaccess.h>
#include <uapi/evl/devices/latmus.h>
#include <trace/events/evl.h>

Expand Down Expand Up @@ -779,7 +779,7 @@ static int run_tuning(struct latmus_runner *runner,

gravity = runner->get_gravity(runner);

if (raw_copy_to_user(result->data, &gravity, sizeof(gravity)))
if (raw_copy_to_user_ptr64(result->data_ptr, &gravity, sizeof(gravity)))
return -EFAULT;

return 0;
Expand Down Expand Up @@ -817,7 +817,7 @@ static int run_measurement(struct latmus_runner *runner,
if (result->len != sizeof(mr))
return -EINVAL;

if (raw_copy_from_user(&mr, result->data, sizeof(mr)))
if (raw_copy_from_user_ptr64(&mr, result->data_ptr, sizeof(mr)))
return -EFAULT;

ret = measure_continously(runner);
Expand All @@ -833,15 +833,16 @@ static int run_measurement(struct latmus_runner *runner,
last.sum_lat = state->sum;
last.overruns = state->overruns;
last.samples = state->cur_samples;
if (raw_copy_to_user(mr.last, &last, sizeof(last)))
if (raw_copy_to_user_ptr64(mr.last_ptr, &last, sizeof(last)))
return -EFAULT;

if (runner->histogram) {
len = runner->hcells * sizeof(s32);
if (len > mr.len)
len = result->len;
if (len > 0 &&
raw_copy_to_user(mr.histogram, runner->histogram, len))
raw_copy_to_user_ptr64(mr.histogram_ptr,
runner->histogram, len))
return -EFAULT;
}

Expand Down Expand Up @@ -1020,6 +1021,10 @@ static const struct file_operations latmus_fops = {
.release = latmus_release,
.unlocked_ioctl = latmus_ioctl,
.oob_ioctl = latmus_oob_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_ptr_ioctl,
.compat_oob_ioctl = compat_ptr_oob_ioctl,
#endif
};

static dev_t latmus_devt;
Expand Down
27 changes: 27 additions & 0 deletions include/evl/uaccess.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2020 Philippe Gerum <rpm@xenomai.org>
*/

#ifndef _EVL_UACCESS_H
#define _EVL_UACCESS_H

#include <linux/uaccess.h>

static inline unsigned long __must_check
raw_copy_from_user_ptr64(void *to, u64 from_ptr, unsigned long n)
{
return raw_copy_from_user(to, (void *)(long)from_ptr, n);
}

static inline unsigned long __must_check
raw_copy_to_user_ptr64(u64 to, const void *from, unsigned long n)
{
return raw_copy_to_user((void *)(long)to, from, n);
}

#define evl_ptrval64(__ptr) ((u64)(long)(__ptr))
#define evl_valptr64(__ptrval, __type) ((__type *)(long)(__ptrval))

#endif /* !_EVL_UACCESS_H */
4 changes: 2 additions & 2 deletions include/uapi/evl/clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
#define EVL_CLKIOC_NEW_TIMER _IO(EVL_CLOCK_IOCBASE, 5)

struct evl_timerfd_setreq {
struct __evl_itimerspec *value;
struct __evl_itimerspec *ovalue;
__u64 value_ptr; /* (struct __evl_itimerspec *value) */
__u64 ovalue_ptr; /* (struct __evl_itimerspec *ovalue) */
};

#define EVL_TIMERFD_IOCBASE 't'
Expand Down
6 changes: 3 additions & 3 deletions include/uapi/evl/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
#include <uapi/evl/sched.h>

/* Earliest ABI level we support. */
#define EVL_ABI_BASE 19
#define EVL_ABI_BASE 20
/*
* Current/latest ABI level we support. We may decouple the base and
* current ABI levels by providing backward compatibility from the
* latter to the former. CAUTION: a litteral value is required for the
* current ABI definition (scripts reading this may be naive).
*/
#define EVL_ABI_LEVEL 19
#define EVL_ABI_LEVEL 20

#define EVL_CONTROL_DEV "/dev/evl/control"

Expand All @@ -31,7 +31,7 @@ struct evl_core_info {

struct evl_cpu_state {
__u32 cpu;
__u32 *state;
__u64 state_ptr; /* (__u32 *state) */
};

#define EVL_CONTROL_IOCBASE 'C'
Expand Down
6 changes: 3 additions & 3 deletions include/uapi/evl/devices/latmus.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ struct latmus_measurement {
};

struct latmus_measurement_result {
struct latmus_measurement *last;
__s32 *histogram;
__u64 last_ptr; /* (struct latmus_measurement *last) */
__u64 histogram_ptr; /* (__s32 *histogram) */
__u32 len;
};

struct latmus_result {
void *data;
__u64 data_ptr; /* (void *data) */
__u32 len;
};

Expand Down
4 changes: 2 additions & 2 deletions include/uapi/evl/factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ struct evl_element_ids {
};

struct evl_clone_req {
const char *name;
void *attrs;
__u64 name_ptr; /* (const char *name) */
__u64 attrs_ptr; /* (void *attrs) */
struct evl_element_ids eids;
};

Expand Down
2 changes: 1 addition & 1 deletion include/uapi/evl/monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct evl_monitor_state {
};

struct evl_monitor_waitreq {
struct __evl_timespec *timeout;
__u64 timeout_ptr; /* (struct __evl_timespec *timeout) */
__s32 gatefd;
__s32 status;
__s32 value;
Expand Down
Loading

0 comments on commit 9e123d4

Please sign in to comment.