diff options
Diffstat (limited to '5.4/01_all_backport-5.6-alsa-timespec64-p6.patch')
-rw-r--r-- | 5.4/01_all_backport-5.6-alsa-timespec64-p6.patch | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/5.4/01_all_backport-5.6-alsa-timespec64-p6.patch b/5.4/01_all_backport-5.6-alsa-timespec64-p6.patch new file mode 100644 index 0000000..0f7ed72 --- /dev/null +++ b/5.4/01_all_backport-5.6-alsa-timespec64-p6.patch @@ -0,0 +1,248 @@ +From 80fe7430c7085951d1246d83f638cc17e6c0be36 Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann <arnd@arndb.de> +Date: Tue, 24 Apr 2018 20:06:15 +0800 +Subject: [PATCH] ALSA: add new 32-bit layout for snd_pcm_mmap_status/control + +The snd_pcm_mmap_status and snd_pcm_mmap_control interfaces are one of the +trickiest areas to get right when moving to 64-bit time_t in user space. + +The snd_pcm_mmap_status structure layout is incompatible with user space +that uses a 64-bit time_t, so we need a new layout for it. Since the +SNDRV_PCM_IOCTL_SYNC_PTR ioctl combines it with snd_pcm_mmap_control +into snd_pcm_sync_ptr, we need to change those two as well. + +Both structures are also exported via an mmap() operation on certain +architectures, and this suffers from incompatibility between 32-bit +and 64-bit user space. As we have to change both structures anyway, +this is a good opportunity to fix the mmap() problem as well, so let's +standardize on the existing 64-bit layout of the structure where possible. + +The downside is that we lose mmap() support for existing 32-bit x86 and +powerpc applications, adding that would introduce very noticeable runtime +overhead and complexity. My assumption here is that not too many people +will miss the removed feature, given that: + +- Almost all x86 and powerpc users these days are on 64-bit kernels, +the majority of today's 32-bit users are on architectures that never +supported mmap (ARM, MIPS, ...). +- It never worked in compat mode (it was intentionally disabled there) +- The application already needs to work with a fallback to +SNDRV_PCM_IOCTL_SYNC_PTR, which will keep working with both the old +and new structure layout. + +Both the ioctl() and mmap() based interfaces are changed at the same +time, as they are based on the same structures. Unlike other interfaces, +we change the uapi header to export both the traditional structure and +a version that is portable between 32-bit and 64-bit user space code +and that corresponds to the existing 64-bit layout. We further check the +__USE_TIME_BITS64 macro that will be defined by future C library versions +whenever we use the new time_t definition, so any existing user space +source code will not see any changes until it gets rebuilt against a new +C library. However, the new structures are all visible in addition to the +old ones, allowing applications to explicitly request the new structures. + +In order to detect the difference between the old snd_pcm_mmap_status and +the new __snd_pcm_mmap_status64 structure from the ioctl command number, +we rely on one quirk in the structure definition: snd_pcm_mmap_status +must be aligned to alignof(time_t), which leads the compiler to insert +four bytes of padding in struct snd_pcm_sync_ptr after 'flags' and a +corresponding change in the size of snd_pcm_sync_ptr itself. On x86-32 +(and only there), the compiler doesn't use 64-bit alignment in structure, +so I'm adding an explicit pad in the structure that has no effect on the +existing 64-bit architectures but ensures that the layout matches for x86. + +The snd_pcm_uframes_t type compatibility requires another hack: we can't +easily make that 64 bit wide, so I leave the type as 'unsigned long', +but add padding before and after it, to ensure that the data is properly +aligned to the respective 64-bit field in the in-kernel structure. + +For the SNDRV_PCM_MMAP_OFFSET_STATUS/CONTROL constants that are used +as the virtual file offset in the mmap() function, we also have to +introduce new constants that depend on hte __USE_TIME_BITS64 macro: +The existing macros are renamed to SNDRV_PCM_MMAP_OFFSET_STATUS_OLD +and SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD, they continue to work fine on +64-bit architectures, but stop working on native 32-bit user space. +The replacement _NEW constants are now used by default for user space +built with __USE_TIME_BITS64, those now work on all new kernels for x86, +ppc and alpha (32 and 64 bit, native and compat). It might be a good idea +for a future alsa-lib to support both the _OLD and _NEW macros and use +the corresponding structures directly. Unmodified alsa-lib source code +will retain the current behavior, so it will no longer be able to use +mmap() for the status/control structures on 32-bit systems, until either +the C library gets updated to 64-bit time_t or alsa-lib gets updated to +support both mmap() layouts. + +Co-developed-with: Baolin Wang <baolin.wang@linaro.org> +Signed-off-by: Baolin Wang <baolin.wang@linaro.org> +Signed-off-by: Arnd Bergmann <arnd@arndb.de> +--- + include/uapi/sound/asound.h | 110 ++++++++++++++++++++++++++++++++---- + +--- a/include/uapi/sound/asound.h ++++ b/include/uapi/sound/asound.h +@@ -35,6 +35,8 @@ + #include <time.h> + #endif + ++#include <asm/byteorder.h> ++ + /* + * protocol version + */ +@@ -301,7 +303,9 @@ typedef int __bitwise snd_pcm_subformat_t; + #define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ + #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ + +- ++#if (__BITS_PER_LONG == 32 && defined(__USE_TIME_BITS64)) || defined __KERNEL__ ++#define __SND_STRUCT_TIME64 ++#endif + + typedef int __bitwise snd_pcm_state_t; + #define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ +@@ -317,8 +321,17 @@ typedef int __bitwise snd_pcm_state_t; + + enum { + SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, +- SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, +- SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, ++ SNDRV_PCM_MMAP_OFFSET_STATUS_OLD = 0x80000000, ++ SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD = 0x81000000, ++ SNDRV_PCM_MMAP_OFFSET_STATUS_NEW = 0x82000000, ++ SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW = 0x83000000, ++#ifdef __SND_STRUCT_TIME64 ++ SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_NEW, ++ SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW, ++#else ++ SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_OLD, ++ SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD, ++#endif + }; + + union snd_pcm_sync_id { +@@ -480,16 +493,46 @@ struct snd_pcm_status { + }; + #endif + +-struct snd_pcm_mmap_status { ++/* ++ * For mmap operations, we need the 64-bit layout, both for compat mode, ++ * and for y2038 compatibility. For 64-bit applications, the two definitions ++ * are identical, so we keep the traditional version. ++ */ ++#ifdef __SND_STRUCT_TIME64 ++#define __snd_pcm_mmap_status64 snd_pcm_mmap_status ++#define __snd_pcm_mmap_control64 snd_pcm_mmap_control ++#define __snd_pcm_sync_ptr64 snd_pcm_sync_ptr ++#ifdef __KERNEL__ ++#define __snd_timespec64 __kernel_timespec ++#else ++#define __snd_timespec64 timespec ++#endif ++struct __snd_timespec { ++ __s32 tv_sec; ++ __s32 tv_nsec; ++}; ++#else ++#define __snd_pcm_mmap_status snd_pcm_mmap_status ++#define __snd_pcm_mmap_control snd_pcm_mmap_control ++#define __snd_pcm_sync_ptr snd_pcm_sync_ptr ++#define __snd_timespec timespec ++struct __snd_timespec64 { ++ __s64 tv_sec; ++ __s64 tv_nsec; ++}; ++ ++#endif ++ ++struct __snd_pcm_mmap_status { + snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */ + int pad1; /* Needed for 64 bit alignment */ + snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ +- struct timespec tstamp; /* Timestamp */ ++ struct __snd_timespec tstamp; /* Timestamp */ + snd_pcm_state_t suspended_state; /* RO: suspended stream state */ +- struct timespec audio_tstamp; /* from sample counter or wall clock */ ++ struct __snd_timespec audio_tstamp; /* from sample counter or wall clock */ + }; + +-struct snd_pcm_mmap_control { ++struct __snd_pcm_mmap_control { + snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ + snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ + }; +@@ -498,14 +541,59 @@ struct snd_pcm_mmap_control { + #define SNDRV_PCM_SYNC_PTR_APPL (1<<1) /* get appl_ptr from driver (r/w op) */ + #define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) /* get avail_min from driver */ + +-struct snd_pcm_sync_ptr { ++struct __snd_pcm_sync_ptr { + unsigned int flags; + union { +- struct snd_pcm_mmap_status status; ++ struct __snd_pcm_mmap_status status; ++ unsigned char reserved[64]; ++ } s; ++ union { ++ struct __snd_pcm_mmap_control control; ++ unsigned char reserved[64]; ++ } c; ++}; ++ ++#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN) ++typedef char __pad_before_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)]; ++typedef char __pad_after_uframe[0]; ++#endif ++ ++#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) ++typedef char __pad_before_uframe[0]; ++typedef char __pad_after_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)]; ++#endif ++ ++struct __snd_pcm_mmap_status64 { ++ __s32 state; /* RO: state - SNDRV_PCM_STATE_XXXX */ ++ __u32 pad1; /* Needed for 64 bit alignment */ ++ __pad_before_uframe __pad1; ++ snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ ++ __pad_after_uframe __pad2; ++ struct __snd_timespec64 tstamp; /* Timestamp */ ++ __s32 suspended_state; /* RO: suspended stream state */ ++ __u32 pad3; /* Needed for 64 bit alignment */ ++ struct __snd_timespec64 audio_tstamp; /* sample counter or wall clock */ ++}; ++ ++struct __snd_pcm_mmap_control64 { ++ __pad_before_uframe __pad1; ++ snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ ++ __pad_before_uframe __pad2; ++ ++ __pad_before_uframe __pad3; ++ snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ ++ __pad_after_uframe __pad4; ++}; ++ ++struct __snd_pcm_sync_ptr64 { ++ __u32 flags; ++ __u32 pad1; ++ union { ++ struct __snd_pcm_mmap_status64 status; + unsigned char reserved[64]; + } s; + union { +- struct snd_pcm_mmap_control control; ++ struct __snd_pcm_mmap_control64 control; + unsigned char reserved[64]; + } c; + }; +@@ -590,6 +678,8 @@ enum { + #define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status) + #define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) + #define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) ++#define __SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct __snd_pcm_sync_ptr) ++#define __SNDRV_PCM_IOCTL_SYNC_PTR64 _IOWR('A', 0x23, struct __snd_pcm_sync_ptr64) + #define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) + #define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) + #define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) +-- +2.26.2 + |