powerpc/vdso: Add a page for non-time data

The page containing VDSO time data is swapped with the one containing
TIME namespace data when a process uses a non-root time namespace.
For other data like powerpc specific data and RNG data, it means
tracking whether time namespace is the root one or not to know which
page to use.

Simplify the logic behind by moving time data out of first data page
so that the first data page which contains everything else always
remains the first page. Time data is in the second or third page
depending on selected time namespace.

While we are playing with get_datapage macro, directly take into
account the data offset inside the macro instead of adding that offset
afterwards.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://patch.msgid.link/0557d3ec898c1d0ea2fc59fa8757618e524c5d94.1727858295.git.christophe.leroy@csgroup.eu
This commit is contained in:
Christophe Leroy 2024-10-02 10:39:28 +02:00 committed by Michael Ellerman
parent 8cf0b93919
commit c39b1dcf05
8 changed files with 25 additions and 33 deletions

View file

@ -82,8 +82,9 @@ struct vdso_arch_data {
__u32 syscall_map[SYSCALL_MAP_SIZE]; /* Map of syscalls */
__u32 compat_syscall_map[SYSCALL_MAP_SIZE]; /* Map of compat syscalls */
struct vdso_data data[CS_BASES];
struct vdso_rng_data rng_data;
struct vdso_data data[CS_BASES] __aligned(1 << CONFIG_PAGE_SHIFT);
};
#else /* CONFIG_PPC64 */
@ -95,8 +96,9 @@ struct vdso_arch_data {
__u64 tb_ticks_per_sec; /* Timebase tics / sec 0x38 */
__u32 syscall_map[SYSCALL_MAP_SIZE]; /* Map of syscalls */
__u32 compat_syscall_map[0]; /* No compat syscalls on PPC32 */
struct vdso_data data[CS_BASES];
struct vdso_rng_data rng_data;
struct vdso_data data[CS_BASES] __aligned(1 << CONFIG_PAGE_SHIFT);
};
#endif /* CONFIG_PPC64 */
@ -105,29 +107,17 @@ extern struct vdso_arch_data *vdso_data;
#else /* __ASSEMBLY__ */
.macro get_datapage ptr
.macro get_datapage ptr offset=0
bcl 20, 31, .+4
999:
mflr \ptr
addis \ptr, \ptr, (_vdso_datapage - 999b)@ha
addi \ptr, \ptr, (_vdso_datapage - 999b)@l
addis \ptr, \ptr, (_vdso_datapage - 999b + \offset)@ha
addi \ptr, \ptr, (_vdso_datapage - 999b + \offset)@l
.endm
#include <asm/asm-offsets.h>
#include <asm/page.h>
.macro get_realdatapage ptr scratch
get_datapage \ptr
#ifdef CONFIG_TIME_NS
lwz \scratch, VDSO_CLOCKMODE_OFFSET(\ptr)
xoris \scratch, \scratch, VDSO_CLOCKMODE_TIMENS@h
xori \scratch, \scratch, VDSO_CLOCKMODE_TIMENS@l
cntlzw \scratch, \scratch
rlwinm \scratch, \scratch, PAGE_SHIFT - 5, 1 << PAGE_SHIFT
add \ptr, \ptr, \scratch
#endif
.endm
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */

View file

@ -48,12 +48,13 @@ long sys_ni_syscall(void);
*/
static union {
struct vdso_arch_data data;
u8 page[PAGE_SIZE];
u8 page[2 * PAGE_SIZE];
} vdso_data_store __page_aligned_data;
struct vdso_arch_data *vdso_data = &vdso_data_store.data;
enum vvar_pages {
VVAR_DATA_PAGE_OFFSET,
VVAR_BASE_PAGE_OFFSET,
VVAR_TIME_PAGE_OFFSET,
VVAR_TIMENS_PAGE_OFFSET,
VVAR_NR_PAGES,
};
@ -119,7 +120,7 @@ static struct vm_special_mapping vdso64_spec __ro_after_init = {
#ifdef CONFIG_TIME_NS
struct vdso_data *arch_get_vdso_data(void *vvar_page)
{
return ((struct vdso_arch_data *)vvar_page)->data;
return vvar_page;
}
/*
@ -153,11 +154,14 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
unsigned long pfn;
switch (vmf->pgoff) {
case VVAR_DATA_PAGE_OFFSET:
case VVAR_BASE_PAGE_OFFSET:
pfn = virt_to_pfn(vdso_data);
break;
case VVAR_TIME_PAGE_OFFSET:
if (timens_page)
pfn = page_to_pfn(timens_page);
else
pfn = virt_to_pfn(vdso_data);
pfn = virt_to_pfn(vdso_data->data);
break;
#ifdef CONFIG_TIME_NS
case VVAR_TIMENS_PAGE_OFFSET:
@ -170,7 +174,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
*/
if (!timens_page)
return VM_FAULT_SIGBUS;
pfn = virt_to_pfn(vdso_data);
pfn = virt_to_pfn(vdso_data->data);
break;
#endif /* CONFIG_TIME_NS */
default:

View file

@ -30,7 +30,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
#ifdef CONFIG_PPC64
mflr r12
.cfi_register lr,r12
get_realdatapage r10, r11
get_datapage r10
mtlr r12
.cfi_restore lr
#endif

View file

@ -28,7 +28,7 @@ V_FUNCTION_BEGIN(__kernel_get_syscall_map)
mflr r12
.cfi_register lr,r12
mr. r4,r3
get_realdatapage r3, r11
get_datapage r3
mtlr r12
#ifdef __powerpc64__
addi r3,r3,CFG_SYSCALL_MAP64
@ -52,7 +52,7 @@ V_FUNCTION_BEGIN(__kernel_get_tbfreq)
.cfi_startproc
mflr r12
.cfi_register lr,r12
get_realdatapage r3, r11
get_datapage r3
#ifndef __powerpc64__
lwz r4,(CFG_TB_TICKS_PER_SEC + 4)(r3)
#endif

View file

@ -31,8 +31,7 @@
PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1)
.cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT
#endif
get_realdatapage r8, r11
addi r8, r8, VDSO_RNG_DATA_OFFSET
get_datapage r8 VDSO_RNG_DATA_OFFSET
bl CFUNC(DOTSYM(\funct))
PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
#ifdef __powerpc64__

View file

@ -32,11 +32,10 @@
PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1)
.cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT
#endif
get_datapage r5
.ifeq \call_time
addi r5, r5, VDSO_DATA_OFFSET
get_datapage r5 VDSO_DATA_OFFSET
.else
addi r4, r5, VDSO_DATA_OFFSET
get_datapage r4 VDSO_DATA_OFFSET
.endif
bl CFUNC(DOTSYM(\funct))
PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)

View file

@ -16,7 +16,7 @@ OUTPUT_ARCH(powerpc:common)
SECTIONS
{
PROVIDE(_vdso_datapage = . - 2 * PAGE_SIZE);
PROVIDE(_vdso_datapage = . - 3 * PAGE_SIZE);
. = SIZEOF_HEADERS;
.hash : { *(.hash) } :text

View file

@ -16,7 +16,7 @@ OUTPUT_ARCH(powerpc:common64)
SECTIONS
{
PROVIDE(_vdso_datapage = . - 2 * PAGE_SIZE);
PROVIDE(_vdso_datapage = . - 3 * PAGE_SIZE);
. = SIZEOF_HEADERS;
.hash : { *(.hash) } :text