diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/include/asm/lowcore.h | 9 | ||||
-rw-r--r-- | arch/s390/include/asm/vdso.h | 15 | ||||
-rw-r--r-- | arch/s390/kernel/asm-offsets.c | 5 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 45 | ||||
-rw-r--r-- | arch/s390/kernel/head64.S | 2 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 9 | ||||
-rw-r--r-- | arch/s390/kernel/vdso.c | 123 | ||||
-rw-r--r-- | arch/s390/kernel/vdso64/clock_getres.S | 5 | ||||
-rw-r--r-- | arch/s390/kernel/vdso64/clock_gettime.S | 39 |
10 files changed, 222 insertions, 32 deletions
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index a547817cf1ab..ffdef5fe8587 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
@@ -106,8 +106,10 @@ | |||
106 | #define __LC_IPLDEV 0xDB8 | 106 | #define __LC_IPLDEV 0xDB8 |
107 | #define __LC_CURRENT 0xDD8 | 107 | #define __LC_CURRENT 0xDD8 |
108 | #define __LC_INT_CLOCK 0xDE8 | 108 | #define __LC_INT_CLOCK 0xDE8 |
109 | #define __LC_VDSO_PER_CPU 0xE38 | ||
109 | #endif /* __s390x__ */ | 110 | #endif /* __s390x__ */ |
110 | 111 | ||
112 | #define __LC_PASTE 0xE40 | ||
111 | 113 | ||
112 | #define __LC_PANIC_MAGIC 0xE00 | 114 | #define __LC_PANIC_MAGIC 0xE00 |
113 | #ifndef __s390x__ | 115 | #ifndef __s390x__ |
@@ -381,7 +383,12 @@ struct _lowcore | |||
381 | /* whether the kernel died with panic() or not */ | 383 | /* whether the kernel died with panic() or not */ |
382 | __u32 panic_magic; /* 0xe00 */ | 384 | __u32 panic_magic; /* 0xe00 */ |
383 | 385 | ||
384 | __u8 pad13[0x11b8-0xe04]; /* 0xe04 */ | 386 | /* Per cpu primary space access list */ |
387 | __u8 pad_0xe04[0xe3c-0xe04]; /* 0xe04 */ | ||
388 | __u32 vdso_per_cpu_data; /* 0xe3c */ | ||
389 | __u32 paste[16]; /* 0xe40 */ | ||
390 | |||
391 | __u8 pad13[0x11b8-0xe80]; /* 0xe80 */ | ||
385 | 392 | ||
386 | /* 64 bit extparam used for pfault, diag 250 etc */ | 393 | /* 64 bit extparam used for pfault, diag 250 etc */ |
387 | __u64 ext_params2; /* 0x11B8 */ | 394 | __u64 ext_params2; /* 0x11B8 */ |
diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h index a44f4fe16a35..7bdd7c8ebc91 100644 --- a/arch/s390/include/asm/vdso.h +++ b/arch/s390/include/asm/vdso.h | |||
@@ -12,9 +12,9 @@ | |||
12 | #ifndef __ASSEMBLY__ | 12 | #ifndef __ASSEMBLY__ |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * Note about this structure: | 15 | * Note about the vdso_data and vdso_per_cpu_data structures: |
16 | * | 16 | * |
17 | * NEVER USE THIS IN USERSPACE CODE DIRECTLY. The layout of this | 17 | * NEVER USE THEM IN USERSPACE CODE DIRECTLY. The layout of the |
18 | * structure is supposed to be known only to the function in the vdso | 18 | * structure is supposed to be known only to the function in the vdso |
19 | * itself and may change without notice. | 19 | * itself and may change without notice. |
20 | */ | 20 | */ |
@@ -28,10 +28,21 @@ struct vdso_data { | |||
28 | __u64 wtom_clock_nsec; /* 0x28 */ | 28 | __u64 wtom_clock_nsec; /* 0x28 */ |
29 | __u32 tz_minuteswest; /* Minutes west of Greenwich 0x30 */ | 29 | __u32 tz_minuteswest; /* Minutes west of Greenwich 0x30 */ |
30 | __u32 tz_dsttime; /* Type of dst correction 0x34 */ | 30 | __u32 tz_dsttime; /* Type of dst correction 0x34 */ |
31 | __u32 ectg_available; | ||
32 | }; | ||
33 | |||
34 | struct vdso_per_cpu_data { | ||
35 | __u64 ectg_timer_base; | ||
36 | __u64 ectg_user_time; | ||
31 | }; | 37 | }; |
32 | 38 | ||
33 | extern struct vdso_data *vdso_data; | 39 | extern struct vdso_data *vdso_data; |
34 | 40 | ||
41 | #ifdef CONFIG_64BIT | ||
42 | int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore); | ||
43 | void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore); | ||
44 | #endif | ||
45 | |||
35 | #endif /* __ASSEMBLY__ */ | 46 | #endif /* __ASSEMBLY__ */ |
36 | 47 | ||
37 | #endif /* __KERNEL__ */ | 48 | #endif /* __KERNEL__ */ |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index e641f60bac99..67a60016babb 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -48,6 +48,11 @@ int main(void) | |||
48 | DEFINE(__VDSO_WTOM_SEC, offsetof(struct vdso_data, wtom_clock_sec)); | 48 | DEFINE(__VDSO_WTOM_SEC, offsetof(struct vdso_data, wtom_clock_sec)); |
49 | DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); | 49 | DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); |
50 | DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest)); | 50 | DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest)); |
51 | DEFINE(__VDSO_ECTG_OK, offsetof(struct vdso_data, ectg_available)); | ||
52 | DEFINE(__VDSO_ECTG_BASE, | ||
53 | offsetof(struct vdso_per_cpu_data, ectg_timer_base)); | ||
54 | DEFINE(__VDSO_ECTG_USER, | ||
55 | offsetof(struct vdso_per_cpu_data, ectg_user_time)); | ||
51 | /* constants used by the vdso */ | 56 | /* constants used by the vdso */ |
52 | DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); | 57 | DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); |
53 | DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); | 58 | DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index ae83c195171c..c6fbde13971a 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -177,8 +177,11 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ | |||
177 | .if !\sync | 177 | .if !\sync |
178 | ni \psworg+1,0xfd # clear wait state bit | 178 | ni \psworg+1,0xfd # clear wait state bit |
179 | .endif | 179 | .endif |
180 | lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user | 180 | lg %r14,__LC_VDSO_PER_CPU |
181 | lmg %r0,%r13,SP_R0(%r15) # load gprs 0-13 of user | ||
181 | stpt __LC_EXIT_TIMER | 182 | stpt __LC_EXIT_TIMER |
183 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER | ||
184 | lmg %r14,%r15,SP_R14(%r15) # load grps 14-15 of user | ||
182 | lpswe \psworg # back to caller | 185 | lpswe \psworg # back to caller |
183 | .endm | 186 | .endm |
184 | 187 | ||
@@ -980,23 +983,23 @@ cleanup_sysc_return: | |||
980 | 983 | ||
981 | cleanup_sysc_leave: | 984 | cleanup_sysc_leave: |
982 | clc 8(8,%r12),BASED(cleanup_sysc_leave_insn) | 985 | clc 8(8,%r12),BASED(cleanup_sysc_leave_insn) |
983 | je 2f | 986 | je 3f |
984 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | ||
985 | clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8) | 987 | clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8) |
986 | je 2f | 988 | jhe 0f |
987 | mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | 989 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER |
990 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | ||
988 | cghi %r12,__LC_MCK_OLD_PSW | 991 | cghi %r12,__LC_MCK_OLD_PSW |
989 | jne 0f | 992 | jne 1f |
990 | mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) | 993 | mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) |
991 | j 1f | 994 | j 2f |
992 | 0: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) | 995 | 1: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) |
993 | 1: lmg %r0,%r11,SP_R0(%r15) | 996 | 2: lmg %r0,%r11,SP_R0(%r15) |
994 | lg %r15,SP_R15(%r15) | 997 | lg %r15,SP_R15(%r15) |
995 | 2: la %r12,__LC_RETURN_PSW | 998 | 3: la %r12,__LC_RETURN_PSW |
996 | br %r14 | 999 | br %r14 |
997 | cleanup_sysc_leave_insn: | 1000 | cleanup_sysc_leave_insn: |
998 | .quad sysc_done - 4 | 1001 | .quad sysc_done - 4 |
999 | .quad sysc_done - 8 | 1002 | .quad sysc_done - 16 |
1000 | 1003 | ||
1001 | cleanup_io_return: | 1004 | cleanup_io_return: |
1002 | mvc __LC_RETURN_PSW(8),0(%r12) | 1005 | mvc __LC_RETURN_PSW(8),0(%r12) |
@@ -1006,23 +1009,23 @@ cleanup_io_return: | |||
1006 | 1009 | ||
1007 | cleanup_io_leave: | 1010 | cleanup_io_leave: |
1008 | clc 8(8,%r12),BASED(cleanup_io_leave_insn) | 1011 | clc 8(8,%r12),BASED(cleanup_io_leave_insn) |
1009 | je 2f | 1012 | je 3f |
1010 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | ||
1011 | clc 8(8,%r12),BASED(cleanup_io_leave_insn+8) | 1013 | clc 8(8,%r12),BASED(cleanup_io_leave_insn+8) |
1012 | je 2f | 1014 | jhe 0f |
1013 | mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | 1015 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER |
1016 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | ||
1014 | cghi %r12,__LC_MCK_OLD_PSW | 1017 | cghi %r12,__LC_MCK_OLD_PSW |
1015 | jne 0f | 1018 | jne 1f |
1016 | mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) | 1019 | mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) |
1017 | j 1f | 1020 | j 2f |
1018 | 0: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) | 1021 | 1: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) |
1019 | 1: lmg %r0,%r11,SP_R0(%r15) | 1022 | 2: lmg %r0,%r11,SP_R0(%r15) |
1020 | lg %r15,SP_R15(%r15) | 1023 | lg %r15,SP_R15(%r15) |
1021 | 2: la %r12,__LC_RETURN_PSW | 1024 | 3: la %r12,__LC_RETURN_PSW |
1022 | br %r14 | 1025 | br %r14 |
1023 | cleanup_io_leave_insn: | 1026 | cleanup_io_leave_insn: |
1024 | .quad io_done - 4 | 1027 | .quad io_done - 4 |
1025 | .quad io_done - 8 | 1028 | .quad io_done - 16 |
1026 | 1029 | ||
1027 | /* | 1030 | /* |
1028 | * Integer constants | 1031 | * Integer constants |
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 3ccd36b24b8f..f9f70aa15244 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S | |||
@@ -87,6 +87,8 @@ startup_continue: | |||
87 | lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area | 87 | lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area |
88 | # move IPL device to lowcore | 88 | # move IPL device to lowcore |
89 | mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12) | 89 | mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12) |
90 | lghi %r0,__LC_PASTE | ||
91 | stg %r0,__LC_VDSO_PER_CPU | ||
90 | # | 92 | # |
91 | # Setup stack | 93 | # Setup stack |
92 | # | 94 | # |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index b7a1efd5522c..d825f4950e4e 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -427,6 +427,8 @@ setup_lowcore(void) | |||
427 | /* enable extended save area */ | 427 | /* enable extended save area */ |
428 | __ctl_set_bit(14, 29); | 428 | __ctl_set_bit(14, 29); |
429 | } | 429 | } |
430 | #else | ||
431 | lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; | ||
430 | #endif | 432 | #endif |
431 | set_prefix((u32)(unsigned long) lc); | 433 | set_prefix((u32)(unsigned long) lc); |
432 | } | 434 | } |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 3979a6fc0882..b3461e8f1705 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <asm/lowcore.h> | 47 | #include <asm/lowcore.h> |
48 | #include <asm/sclp.h> | 48 | #include <asm/sclp.h> |
49 | #include <asm/cpu.h> | 49 | #include <asm/cpu.h> |
50 | #include <asm/vdso.h> | ||
50 | #include "entry.h" | 51 | #include "entry.h" |
51 | 52 | ||
52 | /* | 53 | /* |
@@ -506,6 +507,9 @@ static int __cpuinit smp_alloc_lowcore(int cpu) | |||
506 | goto out; | 507 | goto out; |
507 | lowcore->extended_save_area_addr = (u32) save_area; | 508 | lowcore->extended_save_area_addr = (u32) save_area; |
508 | } | 509 | } |
510 | #else | ||
511 | if (vdso_alloc_per_cpu(cpu, lowcore)) | ||
512 | goto out; | ||
509 | #endif | 513 | #endif |
510 | lowcore_ptr[cpu] = lowcore; | 514 | lowcore_ptr[cpu] = lowcore; |
511 | return 0; | 515 | return 0; |
@@ -528,6 +532,8 @@ static void smp_free_lowcore(int cpu) | |||
528 | #ifndef CONFIG_64BIT | 532 | #ifndef CONFIG_64BIT |
529 | if (MACHINE_HAS_IEEE) | 533 | if (MACHINE_HAS_IEEE) |
530 | free_page((unsigned long) lowcore->extended_save_area_addr); | 534 | free_page((unsigned long) lowcore->extended_save_area_addr); |
535 | #else | ||
536 | vdso_free_per_cpu(cpu, lowcore); | ||
531 | #endif | 537 | #endif |
532 | free_page(lowcore->panic_stack - PAGE_SIZE); | 538 | free_page(lowcore->panic_stack - PAGE_SIZE); |
533 | free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER); | 539 | free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER); |
@@ -670,6 +676,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
670 | lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order); | 676 | lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order); |
671 | panic_stack = __get_free_page(GFP_KERNEL); | 677 | panic_stack = __get_free_page(GFP_KERNEL); |
672 | async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); | 678 | async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); |
679 | BUG_ON(!lowcore || !panic_stack || !async_stack); | ||
673 | #ifndef CONFIG_64BIT | 680 | #ifndef CONFIG_64BIT |
674 | if (MACHINE_HAS_IEEE) | 681 | if (MACHINE_HAS_IEEE) |
675 | save_area = get_zeroed_page(GFP_KERNEL); | 682 | save_area = get_zeroed_page(GFP_KERNEL); |
@@ -683,6 +690,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
683 | #ifndef CONFIG_64BIT | 690 | #ifndef CONFIG_64BIT |
684 | if (MACHINE_HAS_IEEE) | 691 | if (MACHINE_HAS_IEEE) |
685 | lowcore->extended_save_area_addr = (u32) save_area; | 692 | lowcore->extended_save_area_addr = (u32) save_area; |
693 | #else | ||
694 | BUG_ON(vdso_alloc_per_cpu(smp_processor_id(), lowcore)); | ||
686 | #endif | 695 | #endif |
687 | set_prefix((u32)(unsigned long) lowcore); | 696 | set_prefix((u32)(unsigned long) lowcore); |
688 | local_mcck_enable(); | 697 | local_mcck_enable(); |
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 10a6ccef4412..25a6a82f1c02 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c | |||
@@ -31,9 +31,6 @@ | |||
31 | #include <asm/sections.h> | 31 | #include <asm/sections.h> |
32 | #include <asm/vdso.h> | 32 | #include <asm/vdso.h> |
33 | 33 | ||
34 | /* Max supported size for symbol names */ | ||
35 | #define MAX_SYMNAME 64 | ||
36 | |||
37 | #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) | 34 | #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) |
38 | extern char vdso32_start, vdso32_end; | 35 | extern char vdso32_start, vdso32_end; |
39 | static void *vdso32_kbase = &vdso32_start; | 36 | static void *vdso32_kbase = &vdso32_start; |
@@ -71,6 +68,119 @@ static union { | |||
71 | struct vdso_data *vdso_data = &vdso_data_store.data; | 68 | struct vdso_data *vdso_data = &vdso_data_store.data; |
72 | 69 | ||
73 | /* | 70 | /* |
71 | * Setup vdso data page. | ||
72 | */ | ||
73 | static void vdso_init_data(struct vdso_data *vd) | ||
74 | { | ||
75 | unsigned int facility_list; | ||
76 | |||
77 | facility_list = stfl(); | ||
78 | vd->ectg_available = switch_amode && (facility_list & 1); | ||
79 | } | ||
80 | |||
81 | #ifdef CONFIG_64BIT | ||
82 | /* | ||
83 | * Setup per cpu vdso data page. | ||
84 | */ | ||
85 | static void vdso_init_per_cpu_data(int cpu, struct vdso_per_cpu_data *vpcd) | ||
86 | { | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Allocate/free per cpu vdso data. | ||
91 | */ | ||
92 | #ifdef CONFIG_64BIT | ||
93 | #define SEGMENT_ORDER 2 | ||
94 | #else | ||
95 | #define SEGMENT_ORDER 1 | ||
96 | #endif | ||
97 | |||
98 | int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore) | ||
99 | { | ||
100 | unsigned long segment_table, page_table, page_frame; | ||
101 | u32 *psal, *aste; | ||
102 | int i; | ||
103 | |||
104 | lowcore->vdso_per_cpu_data = __LC_PASTE; | ||
105 | |||
106 | if (!switch_amode || !vdso_enabled) | ||
107 | return 0; | ||
108 | |||
109 | segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER); | ||
110 | page_table = get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
111 | page_frame = get_zeroed_page(GFP_KERNEL); | ||
112 | if (!segment_table || !page_table || !page_frame) | ||
113 | goto out; | ||
114 | |||
115 | clear_table((unsigned long *) segment_table, _SEGMENT_ENTRY_EMPTY, | ||
116 | PAGE_SIZE << SEGMENT_ORDER); | ||
117 | clear_table((unsigned long *) page_table, _PAGE_TYPE_EMPTY, | ||
118 | 256*sizeof(unsigned long)); | ||
119 | |||
120 | *(unsigned long *) segment_table = _SEGMENT_ENTRY + page_table; | ||
121 | *(unsigned long *) page_table = _PAGE_RO + page_frame; | ||
122 | |||
123 | psal = (u32 *) (page_table + 256*sizeof(unsigned long)); | ||
124 | aste = psal + 32; | ||
125 | |||
126 | for (i = 4; i < 32; i += 4) | ||
127 | psal[i] = 0x80000000; | ||
128 | |||
129 | lowcore->paste[4] = (u32)(addr_t) psal; | ||
130 | psal[0] = 0x20000000; | ||
131 | psal[2] = (u32)(addr_t) aste; | ||
132 | *(unsigned long *) (aste + 2) = segment_table + | ||
133 | _ASCE_TABLE_LENGTH + _ASCE_USER_BITS + _ASCE_TYPE_SEGMENT; | ||
134 | aste[4] = (u32)(addr_t) psal; | ||
135 | lowcore->vdso_per_cpu_data = page_frame; | ||
136 | |||
137 | vdso_init_per_cpu_data(cpu, (struct vdso_per_cpu_data *) page_frame); | ||
138 | return 0; | ||
139 | |||
140 | out: | ||
141 | free_page(page_frame); | ||
142 | free_page(page_table); | ||
143 | free_pages(segment_table, SEGMENT_ORDER); | ||
144 | return -ENOMEM; | ||
145 | } | ||
146 | |||
147 | #ifdef CONFIG_HOTPLUG_CPU | ||
148 | void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore) | ||
149 | { | ||
150 | unsigned long segment_table, page_table, page_frame; | ||
151 | u32 *psal, *aste; | ||
152 | |||
153 | if (!switch_amode || !vdso_enabled) | ||
154 | return; | ||
155 | |||
156 | psal = (u32 *)(addr_t) lowcore->paste[4]; | ||
157 | aste = (u32 *)(addr_t) psal[2]; | ||
158 | segment_table = *(unsigned long *)(aste + 2) & PAGE_MASK; | ||
159 | page_table = *(unsigned long *) segment_table; | ||
160 | page_frame = *(unsigned long *) page_table; | ||
161 | |||
162 | free_page(page_frame); | ||
163 | free_page(page_table); | ||
164 | free_pages(segment_table, SEGMENT_ORDER); | ||
165 | } | ||
166 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
167 | |||
168 | static void __vdso_init_cr5(void *dummy) | ||
169 | { | ||
170 | unsigned long cr5; | ||
171 | |||
172 | cr5 = offsetof(struct _lowcore, paste); | ||
173 | __ctl_load(cr5, 5, 5); | ||
174 | } | ||
175 | |||
176 | static void vdso_init_cr5(void) | ||
177 | { | ||
178 | if (switch_amode && vdso_enabled) | ||
179 | on_each_cpu(__vdso_init_cr5, NULL, 1); | ||
180 | } | ||
181 | #endif /* CONFIG_64BIT */ | ||
182 | |||
183 | /* | ||
74 | * This is called from binfmt_elf, we create the special vma for the | 184 | * This is called from binfmt_elf, we create the special vma for the |
75 | * vDSO and insert it into the mm struct tree | 185 | * vDSO and insert it into the mm struct tree |
76 | */ | 186 | */ |
@@ -172,6 +282,9 @@ static int __init vdso_init(void) | |||
172 | { | 282 | { |
173 | int i; | 283 | int i; |
174 | 284 | ||
285 | if (!vdso_enabled) | ||
286 | return 0; | ||
287 | vdso_init_data(vdso_data); | ||
175 | #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) | 288 | #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) |
176 | /* Calculate the size of the 32 bit vDSO */ | 289 | /* Calculate the size of the 32 bit vDSO */ |
177 | vdso32_pages = ((&vdso32_end - &vdso32_start | 290 | vdso32_pages = ((&vdso32_end - &vdso32_start |
@@ -208,6 +321,10 @@ static int __init vdso_init(void) | |||
208 | } | 321 | } |
209 | vdso64_pagelist[vdso64_pages - 1] = virt_to_page(vdso_data); | 322 | vdso64_pagelist[vdso64_pages - 1] = virt_to_page(vdso_data); |
210 | vdso64_pagelist[vdso64_pages] = NULL; | 323 | vdso64_pagelist[vdso64_pages] = NULL; |
324 | #ifndef CONFIG_SMP | ||
325 | BUG_ON(vdso_alloc_per_cpu(0, S390_lowcore)); | ||
326 | #endif | ||
327 | vdso_init_cr5(); | ||
211 | #endif /* CONFIG_64BIT */ | 328 | #endif /* CONFIG_64BIT */ |
212 | 329 | ||
213 | get_page(virt_to_page(vdso_data)); | 330 | get_page(virt_to_page(vdso_data)); |
diff --git a/arch/s390/kernel/vdso64/clock_getres.S b/arch/s390/kernel/vdso64/clock_getres.S index 488e31a3c0e7..9ce8caafdb4e 100644 --- a/arch/s390/kernel/vdso64/clock_getres.S +++ b/arch/s390/kernel/vdso64/clock_getres.S | |||
@@ -22,7 +22,12 @@ __kernel_clock_getres: | |||
22 | cghi %r2,CLOCK_REALTIME | 22 | cghi %r2,CLOCK_REALTIME |
23 | je 0f | 23 | je 0f |
24 | cghi %r2,CLOCK_MONOTONIC | 24 | cghi %r2,CLOCK_MONOTONIC |
25 | je 0f | ||
26 | cghi %r2,-2 /* CLOCK_THREAD_CPUTIME_ID for this thread */ | ||
25 | jne 2f | 27 | jne 2f |
28 | larl %r5,_vdso_data | ||
29 | icm %r0,15,__LC_ECTG_OK(%r5) | ||
30 | jz 2f | ||
26 | 0: ltgr %r3,%r3 | 31 | 0: ltgr %r3,%r3 |
27 | jz 1f /* res == NULL */ | 32 | jz 1f /* res == NULL */ |
28 | larl %r1,3f | 33 | larl %r1,3f |
diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S index 738a410b7eb2..79dbfee831ec 100644 --- a/arch/s390/kernel/vdso64/clock_gettime.S +++ b/arch/s390/kernel/vdso64/clock_gettime.S | |||
@@ -22,8 +22,10 @@ __kernel_clock_gettime: | |||
22 | larl %r5,_vdso_data | 22 | larl %r5,_vdso_data |
23 | cghi %r2,CLOCK_REALTIME | 23 | cghi %r2,CLOCK_REALTIME |
24 | je 4f | 24 | je 4f |
25 | cghi %r2,-2 /* CLOCK_THREAD_CPUTIME_ID for this thread */ | ||
26 | je 9f | ||
25 | cghi %r2,CLOCK_MONOTONIC | 27 | cghi %r2,CLOCK_MONOTONIC |
26 | jne 9f | 28 | jne 12f |
27 | 29 | ||
28 | /* CLOCK_MONOTONIC */ | 30 | /* CLOCK_MONOTONIC */ |
29 | ltgr %r3,%r3 | 31 | ltgr %r3,%r3 |
@@ -42,7 +44,7 @@ __kernel_clock_gettime: | |||
42 | alg %r0,__VDSO_WTOM_SEC(%r5) | 44 | alg %r0,__VDSO_WTOM_SEC(%r5) |
43 | clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ | 45 | clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ |
44 | jne 0b | 46 | jne 0b |
45 | larl %r5,10f | 47 | larl %r5,13f |
46 | 1: clg %r1,0(%r5) | 48 | 1: clg %r1,0(%r5) |
47 | jl 2f | 49 | jl 2f |
48 | slg %r1,0(%r5) | 50 | slg %r1,0(%r5) |
@@ -68,7 +70,7 @@ __kernel_clock_gettime: | |||
68 | lg %r0,__VDSO_XTIME_SEC(%r5) | 70 | lg %r0,__VDSO_XTIME_SEC(%r5) |
69 | clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ | 71 | clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ |
70 | jne 5b | 72 | jne 5b |
71 | larl %r5,10f | 73 | larl %r5,13f |
72 | 6: clg %r1,0(%r5) | 74 | 6: clg %r1,0(%r5) |
73 | jl 7f | 75 | jl 7f |
74 | slg %r1,0(%r5) | 76 | slg %r1,0(%r5) |
@@ -79,11 +81,38 @@ __kernel_clock_gettime: | |||
79 | 8: lghi %r2,0 | 81 | 8: lghi %r2,0 |
80 | br %r14 | 82 | br %r14 |
81 | 83 | ||
84 | /* CLOCK_THREAD_CPUTIME_ID for this thread */ | ||
85 | 9: icm %r0,15,__VDSO_ECTG_OK(%r5) | ||
86 | jz 12f | ||
87 | ear %r2,%a4 | ||
88 | llilh %r4,0x0100 | ||
89 | sar %a4,%r4 | ||
90 | lghi %r4,0 | ||
91 | sacf 512 /* Magic ectg instruction */ | ||
92 | .insn ssf,0xc80100000000,__VDSO_ECTG_BASE(4),__VDSO_ECTG_USER(4),4 | ||
93 | sacf 0 | ||
94 | sar %a4,%r2 | ||
95 | algr %r1,%r0 /* r1 = cputime as TOD value */ | ||
96 | mghi %r1,1000 /* convert to nanoseconds */ | ||
97 | srlg %r1,%r1,12 /* r1 = cputime in nanosec */ | ||
98 | lgr %r4,%r1 | ||
99 | larl %r5,13f | ||
100 | srlg %r1,%r1,9 /* divide by 1000000000 */ | ||
101 | mlg %r0,8(%r5) | ||
102 | srlg %r0,%r0,11 /* r0 = tv_sec */ | ||
103 | stg %r0,0(%r3) | ||
104 | msg %r0,0(%r5) /* calculate tv_nsec */ | ||
105 | slgr %r4,%r0 /* r4 = tv_nsec */ | ||
106 | stg %r4,8(%r3) | ||
107 | lghi %r2,0 | ||
108 | br %r14 | ||
109 | |||
82 | /* Fallback to system call */ | 110 | /* Fallback to system call */ |
83 | 9: lghi %r1,__NR_clock_gettime | 111 | 12: lghi %r1,__NR_clock_gettime |
84 | svc 0 | 112 | svc 0 |
85 | br %r14 | 113 | br %r14 |
86 | 114 | ||
87 | 10: .quad 1000000000 | 115 | 13: .quad 1000000000 |
116 | 14: .quad 19342813113834067 | ||
88 | .cfi_endproc | 117 | .cfi_endproc |
89 | .size __kernel_clock_gettime,.-__kernel_clock_gettime | 118 | .size __kernel_clock_gettime,.-__kernel_clock_gettime |