diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 11:11:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 11:11:13 -0500 |
commit | 72f318897e50c29b91efd1ed24515a93c138a2ba (patch) | |
tree | 7e7ef8138d5afacd1be4655e4458dc4cee432d1e /arch/s390 | |
parent | a0e86bd4252519321b0d102dc4ed90557aa7bee9 (diff) | |
parent | 2fa1d4fce599809e6bd7d95756709a5faef30710 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (31 commits)
[S390] disassembler: mark exception causing instructions
[S390] Enable exception traces by default
[S390] return address of compat signals
[S390] sysctl: get rid of dead declaration
[S390] dasd: fix fixpoint divide exception in define_extent
[S390] dasd: add sanity check to detect path connection error
[S390] qdio: fix kernel panic for zfcp 31-bit
[S390] Add s390x description to Documentation/kdump/kdump.txt
[S390] Add VMCOREINFO_SYMBOL(high_memory) to vmcoreinfo
[S390] dasd: fix expiration handling for recovery requests
[S390] outstanding interrupts vs. smp_send_stop
[S390] ipc: call generic sys_ipc demultiplexer
[S390] zcrypt: Fix error return codes.
[S390] zcrypt: Rework length parameter checking.
[S390] cleanup trap handling
[S390] Remove Kerntypes leftovers
[S390] topology: increase poll frequency if change is anticipated
[S390] entry[64].S improvements
[S390] make arch/s390 subdirectories depend on config option
[S390] kvm: move cmf host id constant out of lowcore
...
Fix up conflicts in arch/s390/kernel/{smp.c,topology.c} due to the
sysdev removal clashing with "topology: get rid of ifdefs" which moved
some of that code around.
Diffstat (limited to 'arch/s390')
40 files changed, 1626 insertions, 1840 deletions
diff --git a/arch/s390/Kbuild b/arch/s390/Kbuild index ae4b01060edd..9858476fa0fe 100644 --- a/arch/s390/Kbuild +++ b/arch/s390/Kbuild | |||
@@ -1,6 +1,7 @@ | |||
1 | obj-y += kernel/ | 1 | obj-y += kernel/ |
2 | obj-y += mm/ | 2 | obj-y += mm/ |
3 | obj-y += crypto/ | 3 | obj-$(CONFIG_KVM) += kvm/ |
4 | obj-y += appldata/ | 4 | obj-$(CONFIG_CRYPTO_HW) += crypto/ |
5 | obj-y += hypfs/ | 5 | obj-$(CONFIG_S390_HYPFS_FS) += hypfs/ |
6 | obj-y += kvm/ | 6 | obj-$(CONFIG_APPLDATA_BASE) += appldata/ |
7 | obj-$(CONFIG_MATHEMU) += math-emu/ | ||
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 28d183c42751..d1727584230a 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -193,18 +193,13 @@ config HOTPLUG_CPU | |||
193 | Say N if you want to disable CPU hotplug. | 193 | Say N if you want to disable CPU hotplug. |
194 | 194 | ||
195 | config SCHED_MC | 195 | config SCHED_MC |
196 | def_bool y | 196 | def_bool n |
197 | prompt "Multi-core scheduler support" | ||
198 | depends on SMP | ||
199 | help | ||
200 | Multi-core scheduler support improves the CPU scheduler's decision | ||
201 | making when dealing with multi-core CPU chips at a cost of slightly | ||
202 | increased overhead in some places. | ||
203 | 197 | ||
204 | config SCHED_BOOK | 198 | config SCHED_BOOK |
205 | def_bool y | 199 | def_bool y |
206 | prompt "Book scheduler support" | 200 | prompt "Book scheduler support" |
207 | depends on SMP && SCHED_MC | 201 | depends on SMP |
202 | select SCHED_MC | ||
208 | help | 203 | help |
209 | Book scheduler support improves the CPU scheduler's decision making | 204 | Book scheduler support improves the CPU scheduler's decision making |
210 | when dealing with machines that have several books. | 205 | when dealing with machines that have several books. |
diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 27a0b5df5ead..e9f353341693 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile | |||
@@ -99,7 +99,6 @@ core-y += arch/s390/ | |||
99 | 99 | ||
100 | libs-y += arch/s390/lib/ | 100 | libs-y += arch/s390/lib/ |
101 | drivers-y += drivers/s390/ | 101 | drivers-y += drivers/s390/ |
102 | drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/ | ||
103 | 102 | ||
104 | # must be linked after kernel | 103 | # must be linked after kernel |
105 | drivers-$(CONFIG_OPROFILE) += arch/s390/oprofile/ | 104 | drivers-$(CONFIG_OPROFILE) += arch/s390/oprofile/ |
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile index 635d677d3281..f2737a005afc 100644 --- a/arch/s390/boot/Makefile +++ b/arch/s390/boot/Makefile | |||
@@ -23,4 +23,4 @@ $(obj)/compressed/vmlinux: FORCE | |||
23 | 23 | ||
24 | install: $(CONFIGURE) $(obj)/image | 24 | install: $(CONFIGURE) $(obj)/image |
25 | sh -x $(srctree)/$(obj)/install.sh $(KERNELRELEASE) $(obj)/image \ | 25 | sh -x $(srctree)/$(obj)/install.sh $(KERNELRELEASE) $(obj)/image \ |
26 | System.map Kerntypes "$(INSTALL_PATH)" | 26 | System.map "$(INSTALL_PATH)" |
diff --git a/arch/s390/include/asm/kdebug.h b/arch/s390/include/asm/kdebug.h index 40db27cd6e60..5c1abd47612a 100644 --- a/arch/s390/include/asm/kdebug.h +++ b/arch/s390/include/asm/kdebug.h | |||
@@ -22,6 +22,6 @@ enum die_val { | |||
22 | DIE_NMI_IPI, | 22 | DIE_NMI_IPI, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | extern void die(const char *, struct pt_regs *, long); | 25 | extern void die(struct pt_regs *, const char *); |
26 | 26 | ||
27 | #endif | 27 | #endif |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 9e13c7d56cc1..707f2306725b 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
@@ -97,47 +97,52 @@ struct _lowcore { | |||
97 | __u32 gpregs_save_area[16]; /* 0x0180 */ | 97 | __u32 gpregs_save_area[16]; /* 0x0180 */ |
98 | __u32 cregs_save_area[16]; /* 0x01c0 */ | 98 | __u32 cregs_save_area[16]; /* 0x01c0 */ |
99 | 99 | ||
100 | /* Save areas. */ | ||
101 | __u32 save_area_sync[8]; /* 0x0200 */ | ||
102 | __u32 save_area_async[8]; /* 0x0220 */ | ||
103 | __u32 save_area_restart[1]; /* 0x0240 */ | ||
104 | __u8 pad_0x0244[0x0248-0x0244]; /* 0x0244 */ | ||
105 | |||
100 | /* Return psws. */ | 106 | /* Return psws. */ |
101 | __u32 save_area[16]; /* 0x0200 */ | 107 | psw_t return_psw; /* 0x0248 */ |
102 | psw_t return_psw; /* 0x0240 */ | 108 | psw_t return_mcck_psw; /* 0x0250 */ |
103 | psw_t return_mcck_psw; /* 0x0248 */ | ||
104 | 109 | ||
105 | /* CPU time accounting values */ | 110 | /* CPU time accounting values */ |
106 | __u64 sync_enter_timer; /* 0x0250 */ | 111 | __u64 sync_enter_timer; /* 0x0258 */ |
107 | __u64 async_enter_timer; /* 0x0258 */ | 112 | __u64 async_enter_timer; /* 0x0260 */ |
108 | __u64 mcck_enter_timer; /* 0x0260 */ | 113 | __u64 mcck_enter_timer; /* 0x0268 */ |
109 | __u64 exit_timer; /* 0x0268 */ | 114 | __u64 exit_timer; /* 0x0270 */ |
110 | __u64 user_timer; /* 0x0270 */ | 115 | __u64 user_timer; /* 0x0278 */ |
111 | __u64 system_timer; /* 0x0278 */ | 116 | __u64 system_timer; /* 0x0280 */ |
112 | __u64 steal_timer; /* 0x0280 */ | 117 | __u64 steal_timer; /* 0x0288 */ |
113 | __u64 last_update_timer; /* 0x0288 */ | 118 | __u64 last_update_timer; /* 0x0290 */ |
114 | __u64 last_update_clock; /* 0x0290 */ | 119 | __u64 last_update_clock; /* 0x0298 */ |
115 | 120 | ||
116 | /* Current process. */ | 121 | /* Current process. */ |
117 | __u32 current_task; /* 0x0298 */ | 122 | __u32 current_task; /* 0x02a0 */ |
118 | __u32 thread_info; /* 0x029c */ | 123 | __u32 thread_info; /* 0x02a4 */ |
119 | __u32 kernel_stack; /* 0x02a0 */ | 124 | __u32 kernel_stack; /* 0x02a8 */ |
120 | 125 | ||
121 | /* Interrupt and panic stack. */ | 126 | /* Interrupt and panic stack. */ |
122 | __u32 async_stack; /* 0x02a4 */ | 127 | __u32 async_stack; /* 0x02ac */ |
123 | __u32 panic_stack; /* 0x02a8 */ | 128 | __u32 panic_stack; /* 0x02b0 */ |
124 | 129 | ||
125 | /* Address space pointer. */ | 130 | /* Address space pointer. */ |
126 | __u32 kernel_asce; /* 0x02ac */ | 131 | __u32 kernel_asce; /* 0x02b4 */ |
127 | __u32 user_asce; /* 0x02b0 */ | 132 | __u32 user_asce; /* 0x02b8 */ |
128 | __u32 current_pid; /* 0x02b4 */ | 133 | __u32 current_pid; /* 0x02bc */ |
129 | 134 | ||
130 | /* SMP info area */ | 135 | /* SMP info area */ |
131 | __u32 cpu_nr; /* 0x02b8 */ | 136 | __u32 cpu_nr; /* 0x02c0 */ |
132 | __u32 softirq_pending; /* 0x02bc */ | 137 | __u32 softirq_pending; /* 0x02c4 */ |
133 | __u32 percpu_offset; /* 0x02c0 */ | 138 | __u32 percpu_offset; /* 0x02c8 */ |
134 | __u32 ext_call_fast; /* 0x02c4 */ | 139 | __u32 ext_call_fast; /* 0x02cc */ |
135 | __u64 int_clock; /* 0x02c8 */ | 140 | __u64 int_clock; /* 0x02d0 */ |
136 | __u64 mcck_clock; /* 0x02d0 */ | 141 | __u64 mcck_clock; /* 0x02d8 */ |
137 | __u64 clock_comparator; /* 0x02d8 */ | 142 | __u64 clock_comparator; /* 0x02e0 */ |
138 | __u32 machine_flags; /* 0x02e0 */ | 143 | __u32 machine_flags; /* 0x02e8 */ |
139 | __u32 ftrace_func; /* 0x02e4 */ | 144 | __u32 ftrace_func; /* 0x02ec */ |
140 | __u8 pad_0x02e8[0x0300-0x02e8]; /* 0x02e8 */ | 145 | __u8 pad_0x02f8[0x0300-0x02f0]; /* 0x02f0 */ |
141 | 146 | ||
142 | /* Interrupt response block */ | 147 | /* Interrupt response block */ |
143 | __u8 irb[64]; /* 0x0300 */ | 148 | __u8 irb[64]; /* 0x0300 */ |
@@ -229,57 +234,62 @@ struct _lowcore { | |||
229 | psw_t mcck_new_psw; /* 0x01e0 */ | 234 | psw_t mcck_new_psw; /* 0x01e0 */ |
230 | psw_t io_new_psw; /* 0x01f0 */ | 235 | psw_t io_new_psw; /* 0x01f0 */ |
231 | 236 | ||
232 | /* Entry/exit save area & return psws. */ | 237 | /* Save areas. */ |
233 | __u64 save_area[16]; /* 0x0200 */ | 238 | __u64 save_area_sync[8]; /* 0x0200 */ |
234 | psw_t return_psw; /* 0x0280 */ | 239 | __u64 save_area_async[8]; /* 0x0240 */ |
235 | psw_t return_mcck_psw; /* 0x0290 */ | 240 | __u64 save_area_restart[1]; /* 0x0280 */ |
241 | __u8 pad_0x0288[0x0290-0x0288]; /* 0x0288 */ | ||
242 | |||
243 | /* Return psws. */ | ||
244 | psw_t return_psw; /* 0x0290 */ | ||
245 | psw_t return_mcck_psw; /* 0x02a0 */ | ||
236 | 246 | ||
237 | /* CPU accounting and timing values. */ | 247 | /* CPU accounting and timing values. */ |
238 | __u64 sync_enter_timer; /* 0x02a0 */ | 248 | __u64 sync_enter_timer; /* 0x02b0 */ |
239 | __u64 async_enter_timer; /* 0x02a8 */ | 249 | __u64 async_enter_timer; /* 0x02b8 */ |
240 | __u64 mcck_enter_timer; /* 0x02b0 */ | 250 | __u64 mcck_enter_timer; /* 0x02c0 */ |
241 | __u64 exit_timer; /* 0x02b8 */ | 251 | __u64 exit_timer; /* 0x02c8 */ |
242 | __u64 user_timer; /* 0x02c0 */ | 252 | __u64 user_timer; /* 0x02d0 */ |
243 | __u64 system_timer; /* 0x02c8 */ | 253 | __u64 system_timer; /* 0x02d8 */ |
244 | __u64 steal_timer; /* 0x02d0 */ | 254 | __u64 steal_timer; /* 0x02e0 */ |
245 | __u64 last_update_timer; /* 0x02d8 */ | 255 | __u64 last_update_timer; /* 0x02e8 */ |
246 | __u64 last_update_clock; /* 0x02e0 */ | 256 | __u64 last_update_clock; /* 0x02f0 */ |
247 | 257 | ||
248 | /* Current process. */ | 258 | /* Current process. */ |
249 | __u64 current_task; /* 0x02e8 */ | 259 | __u64 current_task; /* 0x02f8 */ |
250 | __u64 thread_info; /* 0x02f0 */ | 260 | __u64 thread_info; /* 0x0300 */ |
251 | __u64 kernel_stack; /* 0x02f8 */ | 261 | __u64 kernel_stack; /* 0x0308 */ |
252 | 262 | ||
253 | /* Interrupt and panic stack. */ | 263 | /* Interrupt and panic stack. */ |
254 | __u64 async_stack; /* 0x0300 */ | 264 | __u64 async_stack; /* 0x0310 */ |
255 | __u64 panic_stack; /* 0x0308 */ | 265 | __u64 panic_stack; /* 0x0318 */ |
256 | 266 | ||
257 | /* Address space pointer. */ | 267 | /* Address space pointer. */ |
258 | __u64 kernel_asce; /* 0x0310 */ | 268 | __u64 kernel_asce; /* 0x0320 */ |
259 | __u64 user_asce; /* 0x0318 */ | 269 | __u64 user_asce; /* 0x0328 */ |
260 | __u64 current_pid; /* 0x0320 */ | 270 | __u64 current_pid; /* 0x0330 */ |
261 | 271 | ||
262 | /* SMP info area */ | 272 | /* SMP info area */ |
263 | __u32 cpu_nr; /* 0x0328 */ | 273 | __u32 cpu_nr; /* 0x0338 */ |
264 | __u32 softirq_pending; /* 0x032c */ | 274 | __u32 softirq_pending; /* 0x033c */ |
265 | __u64 percpu_offset; /* 0x0330 */ | 275 | __u64 percpu_offset; /* 0x0340 */ |
266 | __u64 ext_call_fast; /* 0x0338 */ | 276 | __u64 ext_call_fast; /* 0x0348 */ |
267 | __u64 int_clock; /* 0x0340 */ | 277 | __u64 int_clock; /* 0x0350 */ |
268 | __u64 mcck_clock; /* 0x0348 */ | 278 | __u64 mcck_clock; /* 0x0358 */ |
269 | __u64 clock_comparator; /* 0x0350 */ | 279 | __u64 clock_comparator; /* 0x0360 */ |
270 | __u64 vdso_per_cpu_data; /* 0x0358 */ | 280 | __u64 vdso_per_cpu_data; /* 0x0368 */ |
271 | __u64 machine_flags; /* 0x0360 */ | 281 | __u64 machine_flags; /* 0x0370 */ |
272 | __u64 ftrace_func; /* 0x0368 */ | 282 | __u64 ftrace_func; /* 0x0378 */ |
273 | __u64 gmap; /* 0x0370 */ | 283 | __u64 gmap; /* 0x0380 */ |
274 | __u64 cmf_hpp; /* 0x0378 */ | 284 | __u8 pad_0x0388[0x0400-0x0388]; /* 0x0388 */ |
275 | 285 | ||
276 | /* Interrupt response block. */ | 286 | /* Interrupt response block. */ |
277 | __u8 irb[64]; /* 0x0380 */ | 287 | __u8 irb[64]; /* 0x0400 */ |
278 | 288 | ||
279 | /* Per cpu primary space access list */ | 289 | /* Per cpu primary space access list */ |
280 | __u32 paste[16]; /* 0x03c0 */ | 290 | __u32 paste[16]; /* 0x0440 */ |
281 | 291 | ||
282 | __u8 pad_0x0400[0x0e00-0x0400]; /* 0x0400 */ | 292 | __u8 pad_0x0480[0x0e00-0x0480]; /* 0x0480 */ |
283 | 293 | ||
284 | /* | 294 | /* |
285 | * 0xe00 contains the address of the IPL Parameter Information | 295 | * 0xe00 contains the address of the IPL Parameter Information |
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 4f289ff0b7fe..011358c1b18e 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -128,28 +128,11 @@ static inline int is_zero_pfn(unsigned long pfn) | |||
128 | * effect, this also makes sure that 64 bit module code cannot be used | 128 | * effect, this also makes sure that 64 bit module code cannot be used |
129 | * as system call address. | 129 | * as system call address. |
130 | */ | 130 | */ |
131 | |||
132 | extern unsigned long VMALLOC_START; | 131 | extern unsigned long VMALLOC_START; |
132 | extern unsigned long VMALLOC_END; | ||
133 | extern struct page *vmemmap; | ||
133 | 134 | ||
134 | #ifndef __s390x__ | 135 | #define VMEM_MAX_PHYS ((unsigned long) vmemmap) |
135 | #define VMALLOC_SIZE (96UL << 20) | ||
136 | #define VMALLOC_END 0x7e000000UL | ||
137 | #define VMEM_MAP_END 0x80000000UL | ||
138 | #else /* __s390x__ */ | ||
139 | #define VMALLOC_SIZE (128UL << 30) | ||
140 | #define VMALLOC_END 0x3e000000000UL | ||
141 | #define VMEM_MAP_END 0x40000000000UL | ||
142 | #endif /* __s390x__ */ | ||
143 | |||
144 | /* | ||
145 | * VMEM_MAX_PHYS is the highest physical address that can be added to the 1:1 | ||
146 | * mapping. This needs to be calculated at compile time since the size of the | ||
147 | * VMEM_MAP is static but the size of struct page can change. | ||
148 | */ | ||
149 | #define VMEM_MAX_PAGES ((VMEM_MAP_END - VMALLOC_END) / sizeof(struct page)) | ||
150 | #define VMEM_MAX_PFN min(VMALLOC_START >> PAGE_SHIFT, VMEM_MAX_PAGES) | ||
151 | #define VMEM_MAX_PHYS ((VMEM_MAX_PFN << PAGE_SHIFT) & ~((16 << 20) - 1)) | ||
152 | #define vmemmap ((struct page *) VMALLOC_END) | ||
153 | 136 | ||
154 | /* | 137 | /* |
155 | * A 31 bit pagetable entry of S390 has following format: | 138 | * A 31 bit pagetable entry of S390 has following format: |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 5f33d37d032c..27272f6a14c2 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -80,8 +80,6 @@ struct thread_struct { | |||
80 | unsigned int acrs[NUM_ACRS]; | 80 | unsigned int acrs[NUM_ACRS]; |
81 | unsigned long ksp; /* kernel stack pointer */ | 81 | unsigned long ksp; /* kernel stack pointer */ |
82 | mm_segment_t mm_segment; | 82 | mm_segment_t mm_segment; |
83 | unsigned long prot_addr; /* address of protection-excep. */ | ||
84 | unsigned int trap_no; | ||
85 | unsigned long gmap_addr; /* address of last gmap fault. */ | 83 | unsigned long gmap_addr; /* address of last gmap fault. */ |
86 | struct per_regs per_user; /* User specified PER registers */ | 84 | struct per_regs per_user; /* User specified PER registers */ |
87 | struct per_event per_event; /* Cause of the last PER trap */ | 85 | struct per_event per_event; /* Cause of the last PER trap */ |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index a65846340d51..56da355678f4 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
@@ -324,7 +324,8 @@ struct pt_regs | |||
324 | psw_t psw; | 324 | psw_t psw; |
325 | unsigned long gprs[NUM_GPRS]; | 325 | unsigned long gprs[NUM_GPRS]; |
326 | unsigned long orig_gpr2; | 326 | unsigned long orig_gpr2; |
327 | unsigned int svc_code; | 327 | unsigned int int_code; |
328 | unsigned long int_parm_long; | ||
328 | }; | 329 | }; |
329 | 330 | ||
330 | /* | 331 | /* |
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index e63d13dd3bf5..d75c8e78f7e3 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h | |||
@@ -352,7 +352,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, | |||
352 | * @no_output_qs: number of output queues | 352 | * @no_output_qs: number of output queues |
353 | * @input_handler: handler to be called for input queues | 353 | * @input_handler: handler to be called for input queues |
354 | * @output_handler: handler to be called for output queues | 354 | * @output_handler: handler to be called for output queues |
355 | * @queue_start_poll: polling handlers (one per input queue or NULL) | 355 | * @queue_start_poll_array: polling handlers (one per input queue or NULL) |
356 | * @int_parm: interruption parameter | 356 | * @int_parm: interruption parameter |
357 | * @input_sbal_addr_array: address of no_input_qs * 128 pointers | 357 | * @input_sbal_addr_array: address of no_input_qs * 128 pointers |
358 | * @output_sbal_addr_array: address of no_output_qs * 128 pointers | 358 | * @output_sbal_addr_array: address of no_output_qs * 128 pointers |
@@ -372,7 +372,8 @@ struct qdio_initialize { | |||
372 | unsigned int no_output_qs; | 372 | unsigned int no_output_qs; |
373 | qdio_handler_t *input_handler; | 373 | qdio_handler_t *input_handler; |
374 | qdio_handler_t *output_handler; | 374 | qdio_handler_t *output_handler; |
375 | void (**queue_start_poll) (struct ccw_device *, int, unsigned long); | 375 | void (**queue_start_poll_array) (struct ccw_device *, int, |
376 | unsigned long); | ||
376 | int scan_threshold; | 377 | int scan_threshold; |
377 | unsigned long int_parm; | 378 | unsigned long int_parm; |
378 | void **input_sbal_addr_array; | 379 | void **input_sbal_addr_array; |
diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h index e3bffd4e2d66..7040b8567cd0 100644 --- a/arch/s390/include/asm/sigp.h +++ b/arch/s390/include/asm/sigp.h | |||
@@ -56,6 +56,7 @@ enum { | |||
56 | ec_schedule = 0, | 56 | ec_schedule = 0, |
57 | ec_call_function, | 57 | ec_call_function, |
58 | ec_call_function_single, | 58 | ec_call_function_single, |
59 | ec_stop_cpu, | ||
59 | }; | 60 | }; |
60 | 61 | ||
61 | /* | 62 | /* |
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index ab47a69fdf07..c32e9123b40c 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h | |||
@@ -23,7 +23,6 @@ extern void __cpu_die (unsigned int cpu); | |||
23 | extern int __cpu_up (unsigned int cpu); | 23 | extern int __cpu_up (unsigned int cpu); |
24 | 24 | ||
25 | extern struct mutex smp_cpu_state_mutex; | 25 | extern struct mutex smp_cpu_state_mutex; |
26 | extern int smp_cpu_polarization[]; | ||
27 | 26 | ||
28 | extern void arch_send_call_function_single_ipi(int cpu); | 27 | extern void arch_send_call_function_single_ipi(int cpu); |
29 | extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); | 28 | extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); |
diff --git a/arch/s390/include/asm/sparsemem.h b/arch/s390/include/asm/sparsemem.h index 545d219e6a2d..0fb34027d3f6 100644 --- a/arch/s390/include/asm/sparsemem.h +++ b/arch/s390/include/asm/sparsemem.h | |||
@@ -4,8 +4,8 @@ | |||
4 | #ifdef CONFIG_64BIT | 4 | #ifdef CONFIG_64BIT |
5 | 5 | ||
6 | #define SECTION_SIZE_BITS 28 | 6 | #define SECTION_SIZE_BITS 28 |
7 | #define MAX_PHYSADDR_BITS 42 | 7 | #define MAX_PHYSADDR_BITS 46 |
8 | #define MAX_PHYSMEM_BITS 42 | 8 | #define MAX_PHYSMEM_BITS 46 |
9 | 9 | ||
10 | #else | 10 | #else |
11 | 11 | ||
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index b239ff53b189..fb214dd9b7e0 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h | |||
@@ -27,7 +27,7 @@ static inline long syscall_get_nr(struct task_struct *task, | |||
27 | struct pt_regs *regs) | 27 | struct pt_regs *regs) |
28 | { | 28 | { |
29 | return test_tsk_thread_flag(task, TIF_SYSCALL) ? | 29 | return test_tsk_thread_flag(task, TIF_SYSCALL) ? |
30 | (regs->svc_code & 0xffff) : -1; | 30 | (regs->int_code & 0xffff) : -1; |
31 | } | 31 | } |
32 | 32 | ||
33 | static inline void syscall_rollback(struct task_struct *task, | 33 | static inline void syscall_rollback(struct task_struct *task, |
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index ef573c1d71a7..d73cc6b60000 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h | |||
@@ -20,8 +20,6 @@ | |||
20 | 20 | ||
21 | struct task_struct; | 21 | struct task_struct; |
22 | 22 | ||
23 | extern int sysctl_userprocess_debug; | ||
24 | |||
25 | extern struct task_struct *__switch_to(void *, void *); | 23 | extern struct task_struct *__switch_to(void *, void *); |
26 | extern void update_per_regs(struct task_struct *task); | 24 | extern void update_per_regs(struct task_struct *task); |
27 | 25 | ||
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index 005d77d8ae2a..0837de80c351 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h | |||
@@ -4,6 +4,10 @@ | |||
4 | #include <linux/cpumask.h> | 4 | #include <linux/cpumask.h> |
5 | #include <asm/sysinfo.h> | 5 | #include <asm/sysinfo.h> |
6 | 6 | ||
7 | struct cpu; | ||
8 | |||
9 | #ifdef CONFIG_SCHED_BOOK | ||
10 | |||
7 | extern unsigned char cpu_core_id[NR_CPUS]; | 11 | extern unsigned char cpu_core_id[NR_CPUS]; |
8 | extern cpumask_t cpu_core_map[NR_CPUS]; | 12 | extern cpumask_t cpu_core_map[NR_CPUS]; |
9 | 13 | ||
@@ -16,8 +20,6 @@ static inline const struct cpumask *cpu_coregroup_mask(int cpu) | |||
16 | #define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) | 20 | #define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) |
17 | #define mc_capable() (1) | 21 | #define mc_capable() (1) |
18 | 22 | ||
19 | #ifdef CONFIG_SCHED_BOOK | ||
20 | |||
21 | extern unsigned char cpu_book_id[NR_CPUS]; | 23 | extern unsigned char cpu_book_id[NR_CPUS]; |
22 | extern cpumask_t cpu_book_map[NR_CPUS]; | 24 | extern cpumask_t cpu_book_map[NR_CPUS]; |
23 | 25 | ||
@@ -29,19 +31,45 @@ static inline const struct cpumask *cpu_book_mask(int cpu) | |||
29 | #define topology_book_id(cpu) (cpu_book_id[cpu]) | 31 | #define topology_book_id(cpu) (cpu_book_id[cpu]) |
30 | #define topology_book_cpumask(cpu) (&cpu_book_map[cpu]) | 32 | #define topology_book_cpumask(cpu) (&cpu_book_map[cpu]) |
31 | 33 | ||
32 | #endif /* CONFIG_SCHED_BOOK */ | 34 | int topology_cpu_init(struct cpu *); |
33 | |||
34 | int topology_set_cpu_management(int fc); | 35 | int topology_set_cpu_management(int fc); |
35 | void topology_schedule_update(void); | 36 | void topology_schedule_update(void); |
36 | void store_topology(struct sysinfo_15_1_x *info); | 37 | void store_topology(struct sysinfo_15_1_x *info); |
38 | void topology_expect_change(void); | ||
39 | |||
40 | #else /* CONFIG_SCHED_BOOK */ | ||
41 | |||
42 | static inline void topology_schedule_update(void) { } | ||
43 | static inline int topology_cpu_init(struct cpu *cpu) { return 0; } | ||
44 | static inline void topology_expect_change(void) { } | ||
37 | 45 | ||
38 | #define POLARIZATION_UNKNWN (-1) | 46 | #endif /* CONFIG_SCHED_BOOK */ |
47 | |||
48 | #define POLARIZATION_UNKNOWN (-1) | ||
39 | #define POLARIZATION_HRZ (0) | 49 | #define POLARIZATION_HRZ (0) |
40 | #define POLARIZATION_VL (1) | 50 | #define POLARIZATION_VL (1) |
41 | #define POLARIZATION_VM (2) | 51 | #define POLARIZATION_VM (2) |
42 | #define POLARIZATION_VH (3) | 52 | #define POLARIZATION_VH (3) |
43 | 53 | ||
44 | #ifdef CONFIG_SMP | 54 | extern int cpu_polarization[]; |
55 | |||
56 | static inline void cpu_set_polarization(int cpu, int val) | ||
57 | { | ||
58 | #ifdef CONFIG_SCHED_BOOK | ||
59 | cpu_polarization[cpu] = val; | ||
60 | #endif | ||
61 | } | ||
62 | |||
63 | static inline int cpu_read_polarization(int cpu) | ||
64 | { | ||
65 | #ifdef CONFIG_SCHED_BOOK | ||
66 | return cpu_polarization[cpu]; | ||
67 | #else | ||
68 | return POLARIZATION_HRZ; | ||
69 | #endif | ||
70 | } | ||
71 | |||
72 | #ifdef CONFIG_SCHED_BOOK | ||
45 | void s390_init_cpu_topology(void); | 73 | void s390_init_cpu_topology(void); |
46 | #else | 74 | #else |
47 | static inline void s390_init_cpu_topology(void) | 75 | static inline void s390_init_cpu_topology(void) |
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index 58de4c91c333..8a8008fe7b8f 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h | |||
@@ -398,6 +398,7 @@ | |||
398 | #define __ARCH_WANT_SYS_SIGNAL | 398 | #define __ARCH_WANT_SYS_SIGNAL |
399 | #define __ARCH_WANT_SYS_UTIME | 399 | #define __ARCH_WANT_SYS_UTIME |
400 | #define __ARCH_WANT_SYS_SOCKETCALL | 400 | #define __ARCH_WANT_SYS_SOCKETCALL |
401 | #define __ARCH_WANT_SYS_IPC | ||
401 | #define __ARCH_WANT_SYS_FADVISE64 | 402 | #define __ARCH_WANT_SYS_FADVISE64 |
402 | #define __ARCH_WANT_SYS_GETPGRP | 403 | #define __ARCH_WANT_SYS_GETPGRP |
403 | #define __ARCH_WANT_SYS_LLSEEK | 404 | #define __ARCH_WANT_SYS_LLSEEK |
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index dd4f07640919..7d9ec924e7e7 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -32,7 +32,8 @@ extra-y += head.o init_task.o vmlinux.lds | |||
32 | extra-y += $(if $(CONFIG_64BIT),head64.o,head31.o) | 32 | extra-y += $(if $(CONFIG_64BIT),head64.o,head31.o) |
33 | 33 | ||
34 | obj-$(CONFIG_MODULES) += s390_ksyms.o module.o | 34 | obj-$(CONFIG_MODULES) += s390_ksyms.o module.o |
35 | obj-$(CONFIG_SMP) += smp.o topology.o | 35 | obj-$(CONFIG_SMP) += smp.o |
36 | obj-$(CONFIG_SCHED_BOOK) += topology.o | ||
36 | obj-$(CONFIG_SMP) += $(if $(CONFIG_64BIT),switch_cpu64.o, \ | 37 | obj-$(CONFIG_SMP) += $(if $(CONFIG_64BIT),switch_cpu64.o, \ |
37 | switch_cpu.o) | 38 | switch_cpu.o) |
38 | obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o | 39 | obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 751318765e2e..6e6a72e66d60 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -45,7 +45,8 @@ int main(void) | |||
45 | DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); | 45 | DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); |
46 | DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); | 46 | DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); |
47 | DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); | 47 | DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); |
48 | DEFINE(__PT_SVC_CODE, offsetof(struct pt_regs, svc_code)); | 48 | DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code)); |
49 | DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long)); | ||
49 | DEFINE(__PT_SIZE, sizeof(struct pt_regs)); | 50 | DEFINE(__PT_SIZE, sizeof(struct pt_regs)); |
50 | BLANK(); | 51 | BLANK(); |
51 | DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain)); | 52 | DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain)); |
@@ -108,7 +109,9 @@ int main(void) | |||
108 | DEFINE(__LC_PGM_NEW_PSW, offsetof(struct _lowcore, program_new_psw)); | 109 | DEFINE(__LC_PGM_NEW_PSW, offsetof(struct _lowcore, program_new_psw)); |
109 | DEFINE(__LC_MCK_NEW_PSW, offsetof(struct _lowcore, mcck_new_psw)); | 110 | DEFINE(__LC_MCK_NEW_PSW, offsetof(struct _lowcore, mcck_new_psw)); |
110 | DEFINE(__LC_IO_NEW_PSW, offsetof(struct _lowcore, io_new_psw)); | 111 | DEFINE(__LC_IO_NEW_PSW, offsetof(struct _lowcore, io_new_psw)); |
111 | DEFINE(__LC_SAVE_AREA, offsetof(struct _lowcore, save_area)); | 112 | DEFINE(__LC_SAVE_AREA_SYNC, offsetof(struct _lowcore, save_area_sync)); |
113 | DEFINE(__LC_SAVE_AREA_ASYNC, offsetof(struct _lowcore, save_area_async)); | ||
114 | DEFINE(__LC_SAVE_AREA_RESTART, offsetof(struct _lowcore, save_area_restart)); | ||
112 | DEFINE(__LC_RETURN_PSW, offsetof(struct _lowcore, return_psw)); | 115 | DEFINE(__LC_RETURN_PSW, offsetof(struct _lowcore, return_psw)); |
113 | DEFINE(__LC_RETURN_MCCK_PSW, offsetof(struct _lowcore, return_mcck_psw)); | 116 | DEFINE(__LC_RETURN_MCCK_PSW, offsetof(struct _lowcore, return_mcck_psw)); |
114 | DEFINE(__LC_SYNC_ENTER_TIMER, offsetof(struct _lowcore, sync_enter_timer)); | 117 | DEFINE(__LC_SYNC_ENTER_TIMER, offsetof(struct _lowcore, sync_enter_timer)); |
@@ -150,7 +153,6 @@ int main(void) | |||
150 | DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr)); | 153 | DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr)); |
151 | DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data)); | 154 | DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data)); |
152 | DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap)); | 155 | DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap)); |
153 | DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp)); | ||
154 | DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce)); | 156 | DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce)); |
155 | #endif /* CONFIG_32BIT */ | 157 | #endif /* CONFIG_32BIT */ |
156 | return 0; | 158 | return 0; |
diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S index f8828d38fa6e..3aa4d00aaf50 100644 --- a/arch/s390/kernel/base.S +++ b/arch/s390/kernel/base.S | |||
@@ -33,7 +33,7 @@ s390_base_mcck_handler_fn: | |||
33 | .previous | 33 | .previous |
34 | 34 | ||
35 | ENTRY(s390_base_ext_handler) | 35 | ENTRY(s390_base_ext_handler) |
36 | stmg %r0,%r15,__LC_SAVE_AREA | 36 | stmg %r0,%r15,__LC_SAVE_AREA_ASYNC |
37 | basr %r13,0 | 37 | basr %r13,0 |
38 | 0: aghi %r15,-STACK_FRAME_OVERHEAD | 38 | 0: aghi %r15,-STACK_FRAME_OVERHEAD |
39 | larl %r1,s390_base_ext_handler_fn | 39 | larl %r1,s390_base_ext_handler_fn |
@@ -41,7 +41,7 @@ ENTRY(s390_base_ext_handler) | |||
41 | ltgr %r1,%r1 | 41 | ltgr %r1,%r1 |
42 | jz 1f | 42 | jz 1f |
43 | basr %r14,%r1 | 43 | basr %r14,%r1 |
44 | 1: lmg %r0,%r15,__LC_SAVE_AREA | 44 | 1: lmg %r0,%r15,__LC_SAVE_AREA_ASYNC |
45 | ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit | 45 | ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit |
46 | lpswe __LC_EXT_OLD_PSW | 46 | lpswe __LC_EXT_OLD_PSW |
47 | 47 | ||
@@ -53,7 +53,7 @@ s390_base_ext_handler_fn: | |||
53 | .previous | 53 | .previous |
54 | 54 | ||
55 | ENTRY(s390_base_pgm_handler) | 55 | ENTRY(s390_base_pgm_handler) |
56 | stmg %r0,%r15,__LC_SAVE_AREA | 56 | stmg %r0,%r15,__LC_SAVE_AREA_SYNC |
57 | basr %r13,0 | 57 | basr %r13,0 |
58 | 0: aghi %r15,-STACK_FRAME_OVERHEAD | 58 | 0: aghi %r15,-STACK_FRAME_OVERHEAD |
59 | larl %r1,s390_base_pgm_handler_fn | 59 | larl %r1,s390_base_pgm_handler_fn |
@@ -61,7 +61,7 @@ ENTRY(s390_base_pgm_handler) | |||
61 | ltgr %r1,%r1 | 61 | ltgr %r1,%r1 |
62 | jz 1f | 62 | jz 1f |
63 | basr %r14,%r1 | 63 | basr %r14,%r1 |
64 | lmg %r0,%r15,__LC_SAVE_AREA | 64 | lmg %r0,%r15,__LC_SAVE_AREA_SYNC |
65 | lpswe __LC_PGM_OLD_PSW | 65 | lpswe __LC_PGM_OLD_PSW |
66 | 1: lpswe disabled_wait_psw-0b(%r13) | 66 | 1: lpswe disabled_wait_psw-0b(%r13) |
67 | 67 | ||
@@ -142,7 +142,7 @@ s390_base_mcck_handler_fn: | |||
142 | .previous | 142 | .previous |
143 | 143 | ||
144 | ENTRY(s390_base_ext_handler) | 144 | ENTRY(s390_base_ext_handler) |
145 | stm %r0,%r15,__LC_SAVE_AREA | 145 | stm %r0,%r15,__LC_SAVE_AREA_ASYNC |
146 | basr %r13,0 | 146 | basr %r13,0 |
147 | 0: ahi %r15,-STACK_FRAME_OVERHEAD | 147 | 0: ahi %r15,-STACK_FRAME_OVERHEAD |
148 | l %r1,2f-0b(%r13) | 148 | l %r1,2f-0b(%r13) |
@@ -150,7 +150,7 @@ ENTRY(s390_base_ext_handler) | |||
150 | ltr %r1,%r1 | 150 | ltr %r1,%r1 |
151 | jz 1f | 151 | jz 1f |
152 | basr %r14,%r1 | 152 | basr %r14,%r1 |
153 | 1: lm %r0,%r15,__LC_SAVE_AREA | 153 | 1: lm %r0,%r15,__LC_SAVE_AREA_ASYNC |
154 | ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit | 154 | ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit |
155 | lpsw __LC_EXT_OLD_PSW | 155 | lpsw __LC_EXT_OLD_PSW |
156 | 156 | ||
@@ -164,7 +164,7 @@ s390_base_ext_handler_fn: | |||
164 | .previous | 164 | .previous |
165 | 165 | ||
166 | ENTRY(s390_base_pgm_handler) | 166 | ENTRY(s390_base_pgm_handler) |
167 | stm %r0,%r15,__LC_SAVE_AREA | 167 | stm %r0,%r15,__LC_SAVE_AREA_SYNC |
168 | basr %r13,0 | 168 | basr %r13,0 |
169 | 0: ahi %r15,-STACK_FRAME_OVERHEAD | 169 | 0: ahi %r15,-STACK_FRAME_OVERHEAD |
170 | l %r1,2f-0b(%r13) | 170 | l %r1,2f-0b(%r13) |
@@ -172,7 +172,7 @@ ENTRY(s390_base_pgm_handler) | |||
172 | ltr %r1,%r1 | 172 | ltr %r1,%r1 |
173 | jz 1f | 173 | jz 1f |
174 | basr %r14,%r1 | 174 | basr %r14,%r1 |
175 | lm %r0,%r15,__LC_SAVE_AREA | 175 | lm %r0,%r15,__LC_SAVE_AREA_SYNC |
176 | lpsw __LC_PGM_OLD_PSW | 176 | lpsw __LC_PGM_OLD_PSW |
177 | 177 | ||
178 | 1: lpsw disabled_wait_psw-0b(%r13) | 178 | 1: lpsw disabled_wait_psw-0b(%r13) |
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 84a982898448..ab64bdbab2ae 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c | |||
@@ -278,9 +278,6 @@ asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr) | |||
278 | { | 278 | { |
279 | if (call >> 16) /* hack for backward compatibility */ | 279 | if (call >> 16) /* hack for backward compatibility */ |
280 | return -EINVAL; | 280 | return -EINVAL; |
281 | |||
282 | call &= 0xffff; | ||
283 | |||
284 | switch (call) { | 281 | switch (call) { |
285 | case SEMTIMEDOP: | 282 | case SEMTIMEDOP: |
286 | return compat_sys_semtimedop(first, compat_ptr(ptr), | 283 | return compat_sys_semtimedop(first, compat_ptr(ptr), |
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 4f68c81d3ffa..6fe78c2f95d9 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c | |||
@@ -501,8 +501,12 @@ static int setup_frame32(int sig, struct k_sigaction *ka, | |||
501 | 501 | ||
502 | /* We forgot to include these in the sigcontext. | 502 | /* We forgot to include these in the sigcontext. |
503 | To avoid breaking binary compatibility, they are passed as args. */ | 503 | To avoid breaking binary compatibility, they are passed as args. */ |
504 | regs->gprs[4] = current->thread.trap_no; | 504 | if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || |
505 | regs->gprs[5] = current->thread.prot_addr; | 505 | sig == SIGTRAP || sig == SIGFPE) { |
506 | /* set extra registers only for synchronous signals */ | ||
507 | regs->gprs[4] = regs->int_code & 127; | ||
508 | regs->gprs[5] = regs->int_parm_long; | ||
509 | } | ||
506 | 510 | ||
507 | /* Place signal number on stack to allow backtrace from handler. */ | 511 | /* Place signal number on stack to allow backtrace from handler. */ |
508 | if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo)) | 512 | if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo)) |
@@ -544,9 +548,9 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
544 | /* Set up to return from userspace. If provided, use a stub | 548 | /* Set up to return from userspace. If provided, use a stub |
545 | already in userspace. */ | 549 | already in userspace. */ |
546 | if (ka->sa.sa_flags & SA_RESTORER) { | 550 | if (ka->sa.sa_flags & SA_RESTORER) { |
547 | regs->gprs[14] = (__u64) ka->sa.sa_restorer; | 551 | regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE; |
548 | } else { | 552 | } else { |
549 | regs->gprs[14] = (__u64) frame->retcode; | 553 | regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE; |
550 | err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, | 554 | err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, |
551 | (u16 __force __user *)(frame->retcode)); | 555 | (u16 __force __user *)(frame->retcode)); |
552 | } | 556 | } |
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index 45df6d456aa1..e2f847599c8e 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c | |||
@@ -1578,10 +1578,15 @@ void show_code(struct pt_regs *regs) | |||
1578 | ptr += sprintf(ptr, "%s Code:", mode); | 1578 | ptr += sprintf(ptr, "%s Code:", mode); |
1579 | hops = 0; | 1579 | hops = 0; |
1580 | while (start < end && hops < 8) { | 1580 | while (start < end && hops < 8) { |
1581 | *ptr++ = (start == 32) ? '>' : ' '; | 1581 | opsize = insn_length(code[start]); |
1582 | if (start + opsize == 32) | ||
1583 | *ptr++ = '#'; | ||
1584 | else if (start == 32) | ||
1585 | *ptr++ = '>'; | ||
1586 | else | ||
1587 | *ptr++ = ' '; | ||
1582 | addr = regs->psw.addr + start - 32; | 1588 | addr = regs->psw.addr + start - 32; |
1583 | ptr += sprintf(ptr, ONELONG, addr); | 1589 | ptr += sprintf(ptr, ONELONG, addr); |
1584 | opsize = insn_length(code[start]); | ||
1585 | if (start + opsize >= end) | 1590 | if (start + opsize >= end) |
1586 | break; | 1591 | break; |
1587 | for (i = 0; i < opsize; i++) | 1592 | for (i = 0; i < opsize; i++) |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index c9ffe0025197..52098d6dfaa7 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -434,18 +434,22 @@ static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t)) | |||
434 | } | 434 | } |
435 | } | 435 | } |
436 | 436 | ||
437 | static void __init setup_boot_command_line(void) | 437 | static inline int has_ebcdic_char(const char *str) |
438 | { | 438 | { |
439 | int i; | 439 | int i; |
440 | 440 | ||
441 | /* convert arch command line to ascii */ | 441 | for (i = 0; str[i]; i++) |
442 | for (i = 0; i < ARCH_COMMAND_LINE_SIZE; i++) | 442 | if (str[i] & 0x80) |
443 | if (COMMAND_LINE[i] & 0x80) | 443 | return 1; |
444 | break; | 444 | return 0; |
445 | if (i < ARCH_COMMAND_LINE_SIZE) | 445 | } |
446 | EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); | ||
447 | COMMAND_LINE[ARCH_COMMAND_LINE_SIZE-1] = 0; | ||
448 | 446 | ||
447 | static void __init setup_boot_command_line(void) | ||
448 | { | ||
449 | COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0; | ||
450 | /* convert arch command line to ascii if necessary */ | ||
451 | if (has_ebcdic_char(COMMAND_LINE)) | ||
452 | EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); | ||
449 | /* copy arch command line */ | 453 | /* copy arch command line */ |
450 | strlcpy(boot_command_line, strstrip(COMMAND_LINE), | 454 | strlcpy(boot_command_line, strstrip(COMMAND_LINE), |
451 | ARCH_COMMAND_LINE_SIZE); | 455 | ARCH_COMMAND_LINE_SIZE); |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index b13157057e02..3705700ed374 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -19,32 +19,22 @@ | |||
19 | #include <asm/unistd.h> | 19 | #include <asm/unistd.h> |
20 | #include <asm/page.h> | 20 | #include <asm/page.h> |
21 | 21 | ||
22 | /* | 22 | __PT_R0 = __PT_GPRS |
23 | * Stack layout for the system_call stack entry. | 23 | __PT_R1 = __PT_GPRS + 4 |
24 | * The first few entries are identical to the user_regs_struct. | 24 | __PT_R2 = __PT_GPRS + 8 |
25 | */ | 25 | __PT_R3 = __PT_GPRS + 12 |
26 | SP_PTREGS = STACK_FRAME_OVERHEAD | 26 | __PT_R4 = __PT_GPRS + 16 |
27 | SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS | 27 | __PT_R5 = __PT_GPRS + 20 |
28 | SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW | 28 | __PT_R6 = __PT_GPRS + 24 |
29 | SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS | 29 | __PT_R7 = __PT_GPRS + 28 |
30 | SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4 | 30 | __PT_R8 = __PT_GPRS + 32 |
31 | SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8 | 31 | __PT_R9 = __PT_GPRS + 36 |
32 | SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 12 | 32 | __PT_R10 = __PT_GPRS + 40 |
33 | SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16 | 33 | __PT_R11 = __PT_GPRS + 44 |
34 | SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 20 | 34 | __PT_R12 = __PT_GPRS + 48 |
35 | SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24 | 35 | __PT_R13 = __PT_GPRS + 524 |
36 | SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 28 | 36 | __PT_R14 = __PT_GPRS + 56 |
37 | SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32 | 37 | __PT_R15 = __PT_GPRS + 60 |
38 | SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 36 | ||
39 | SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40 | ||
40 | SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 44 | ||
41 | SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48 | ||
42 | SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52 | ||
43 | SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56 | ||
44 | SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60 | ||
45 | SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 | ||
46 | SP_SVC_CODE = STACK_FRAME_OVERHEAD + __PT_SVC_CODE | ||
47 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE | ||
48 | 38 | ||
49 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ | 39 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ |
50 | _TIF_MCCK_PENDING | _TIF_PER_TRAP ) | 40 | _TIF_MCCK_PENDING | _TIF_PER_TRAP ) |
@@ -58,133 +48,91 @@ STACK_SIZE = 1 << STACK_SHIFT | |||
58 | 48 | ||
59 | #define BASED(name) name-system_call(%r13) | 49 | #define BASED(name) name-system_call(%r13) |
60 | 50 | ||
61 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
62 | .macro TRACE_IRQS_ON | 51 | .macro TRACE_IRQS_ON |
52 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
63 | basr %r2,%r0 | 53 | basr %r2,%r0 |
64 | l %r1,BASED(.Ltrace_irq_on_caller) | 54 | l %r1,BASED(.Lhardirqs_on) |
65 | basr %r14,%r1 | 55 | basr %r14,%r1 # call trace_hardirqs_on_caller |
56 | #endif | ||
66 | .endm | 57 | .endm |
67 | 58 | ||
68 | .macro TRACE_IRQS_OFF | 59 | .macro TRACE_IRQS_OFF |
60 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
69 | basr %r2,%r0 | 61 | basr %r2,%r0 |
70 | l %r1,BASED(.Ltrace_irq_off_caller) | 62 | l %r1,BASED(.Lhardirqs_off) |
71 | basr %r14,%r1 | 63 | basr %r14,%r1 # call trace_hardirqs_off_caller |
72 | .endm | ||
73 | #else | ||
74 | #define TRACE_IRQS_ON | ||
75 | #define TRACE_IRQS_OFF | ||
76 | #endif | 64 | #endif |
65 | .endm | ||
77 | 66 | ||
78 | #ifdef CONFIG_LOCKDEP | ||
79 | .macro LOCKDEP_SYS_EXIT | 67 | .macro LOCKDEP_SYS_EXIT |
80 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 68 | #ifdef CONFIG_LOCKDEP |
81 | jz 0f | 69 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
70 | jz .+10 | ||
82 | l %r1,BASED(.Llockdep_sys_exit) | 71 | l %r1,BASED(.Llockdep_sys_exit) |
83 | basr %r14,%r1 | 72 | basr %r14,%r1 # call lockdep_sys_exit |
84 | 0: | ||
85 | .endm | ||
86 | #else | ||
87 | #define LOCKDEP_SYS_EXIT | ||
88 | #endif | 73 | #endif |
89 | |||
90 | /* | ||
91 | * Register usage in interrupt handlers: | ||
92 | * R9 - pointer to current task structure | ||
93 | * R13 - pointer to literal pool | ||
94 | * R14 - return register for function calls | ||
95 | * R15 - kernel stack pointer | ||
96 | */ | ||
97 | |||
98 | .macro UPDATE_VTIME lc_from,lc_to,lc_sum | ||
99 | lm %r10,%r11,\lc_from | ||
100 | sl %r10,\lc_to | ||
101 | sl %r11,\lc_to+4 | ||
102 | bc 3,BASED(0f) | ||
103 | sl %r10,BASED(.Lc_1) | ||
104 | 0: al %r10,\lc_sum | ||
105 | al %r11,\lc_sum+4 | ||
106 | bc 12,BASED(1f) | ||
107 | al %r10,BASED(.Lc_1) | ||
108 | 1: stm %r10,%r11,\lc_sum | ||
109 | .endm | ||
110 | |||
111 | .macro SAVE_ALL_SVC psworg,savearea | ||
112 | stm %r12,%r15,\savearea | ||
113 | l %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13 | ||
114 | l %r15,__LC_KERNEL_STACK # problem state -> load ksp | ||
115 | s %r15,BASED(.Lc_spsize) # make room for registers & psw | ||
116 | .endm | ||
117 | |||
118 | .macro SAVE_ALL_BASE savearea | ||
119 | stm %r12,%r15,\savearea | ||
120 | l %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13 | ||
121 | .endm | 74 | .endm |
122 | 75 | ||
123 | .macro SAVE_ALL_PGM psworg,savearea | 76 | .macro CHECK_STACK stacksize,savearea |
124 | tm \psworg+1,0x01 # test problem state bit | ||
125 | #ifdef CONFIG_CHECK_STACK | 77 | #ifdef CONFIG_CHECK_STACK |
126 | bnz BASED(1f) | 78 | tml %r15,\stacksize - CONFIG_STACK_GUARD |
127 | tml %r15,STACK_SIZE - CONFIG_STACK_GUARD | 79 | la %r14,\savearea |
128 | bnz BASED(2f) | 80 | jz stack_overflow |
129 | la %r12,\psworg | ||
130 | b BASED(stack_overflow) | ||
131 | #else | ||
132 | bz BASED(2f) | ||
133 | #endif | 81 | #endif |
134 | 1: l %r15,__LC_KERNEL_STACK # problem state -> load ksp | ||
135 | 2: s %r15,BASED(.Lc_spsize) # make room for registers & psw | ||
136 | .endm | 82 | .endm |
137 | 83 | ||
138 | .macro SAVE_ALL_ASYNC psworg,savearea | 84 | .macro SWITCH_ASYNC savearea,stack,shift |
139 | stm %r12,%r15,\savearea | 85 | tmh %r8,0x0001 # interrupting from user ? |
140 | l %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13 | 86 | jnz 1f |
141 | la %r12,\psworg | 87 | lr %r14,%r9 |
142 | tm \psworg+1,0x01 # test problem state bit | 88 | sl %r14,BASED(.Lcritical_start) |
143 | bnz BASED(1f) # from user -> load async stack | 89 | cl %r14,BASED(.Lcritical_length) |
144 | clc \psworg+4(4),BASED(.Lcritical_end) | 90 | jhe 0f |
145 | bhe BASED(0f) | 91 | la %r11,\savearea # inside critical section, do cleanup |
146 | clc \psworg+4(4),BASED(.Lcritical_start) | 92 | bras %r14,cleanup_critical |
147 | bl BASED(0f) | 93 | tmh %r8,0x0001 # retest problem state after cleanup |
148 | l %r14,BASED(.Lcleanup_critical) | 94 | jnz 1f |
149 | basr %r14,%r14 | 95 | 0: l %r14,\stack # are we already on the target stack? |
150 | tm 1(%r12),0x01 # retest problem state after cleanup | ||
151 | bnz BASED(1f) | ||
152 | 0: l %r14,__LC_ASYNC_STACK # are we already on the async stack ? | ||
153 | slr %r14,%r15 | 96 | slr %r14,%r15 |
154 | sra %r14,STACK_SHIFT | 97 | sra %r14,\shift |
155 | #ifdef CONFIG_CHECK_STACK | 98 | jnz 1f |
156 | bnz BASED(1f) | 99 | CHECK_STACK 1<<\shift,\savearea |
157 | tml %r15,STACK_SIZE - CONFIG_STACK_GUARD | 100 | j 2f |
158 | bnz BASED(2f) | 101 | 1: l %r15,\stack # load target stack |
159 | b BASED(stack_overflow) | 102 | 2: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
160 | #else | 103 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
161 | bz BASED(2f) | ||
162 | #endif | ||
163 | 1: l %r15,__LC_ASYNC_STACK | ||
164 | 2: s %r15,BASED(.Lc_spsize) # make room for registers & psw | ||
165 | .endm | 104 | .endm |
166 | 105 | ||
167 | .macro CREATE_STACK_FRAME savearea | 106 | .macro ADD64 high,low,timer |
168 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 107 | al \high,\timer |
169 | st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 | 108 | al \low,\timer+4 |
170 | mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack | 109 | brc 12,.+8 |
171 | stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack | 110 | ahi \high,1 |
172 | .endm | 111 | .endm |
173 | 112 | ||
174 | .macro RESTORE_ALL psworg,sync | 113 | .macro SUB64 high,low,timer |
175 | mvc \psworg(8),SP_PSW(%r15) # move user PSW to lowcore | 114 | sl \high,\timer |
176 | .if !\sync | 115 | sl \low,\timer+4 |
177 | ni \psworg+1,0xfd # clear wait state bit | 116 | brc 3,.+8 |
178 | .endif | 117 | ahi \high,-1 |
179 | lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user | 118 | .endm |
180 | stpt __LC_EXIT_TIMER | 119 | |
181 | lpsw \psworg # back to caller | 120 | .macro UPDATE_VTIME high,low,enter_timer |
121 | lm \high,\low,__LC_EXIT_TIMER | ||
122 | SUB64 \high,\low,\enter_timer | ||
123 | ADD64 \high,\low,__LC_USER_TIMER | ||
124 | stm \high,\low,__LC_USER_TIMER | ||
125 | lm \high,\low,__LC_LAST_UPDATE_TIMER | ||
126 | SUB64 \high,\low,__LC_EXIT_TIMER | ||
127 | ADD64 \high,\low,__LC_SYSTEM_TIMER | ||
128 | stm \high,\low,__LC_SYSTEM_TIMER | ||
129 | mvc __LC_LAST_UPDATE_TIMER(8),\enter_timer | ||
182 | .endm | 130 | .endm |
183 | 131 | ||
184 | .macro REENABLE_IRQS | 132 | .macro REENABLE_IRQS |
185 | mvc __SF_EMPTY(1,%r15),SP_PSW(%r15) | 133 | st %r8,__LC_RETURN_PSW |
186 | ni __SF_EMPTY(%r15),0xbf | 134 | ni __LC_RETURN_PSW,0xbf |
187 | ssm __SF_EMPTY(%r15) | 135 | ssm __LC_RETURN_PSW |
188 | .endm | 136 | .endm |
189 | 137 | ||
190 | .section .kprobes.text, "ax" | 138 | .section .kprobes.text, "ax" |
@@ -197,14 +145,13 @@ STACK_SIZE = 1 << STACK_SHIFT | |||
197 | * gpr2 = prev | 145 | * gpr2 = prev |
198 | */ | 146 | */ |
199 | ENTRY(__switch_to) | 147 | ENTRY(__switch_to) |
200 | basr %r1,0 | 148 | l %r4,__THREAD_info(%r2) # get thread_info of prev |
201 | 0: l %r4,__THREAD_info(%r2) # get thread_info of prev | ||
202 | l %r5,__THREAD_info(%r3) # get thread_info of next | 149 | l %r5,__THREAD_info(%r3) # get thread_info of next |
203 | tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending? | 150 | tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending? |
204 | bz 1f-0b(%r1) | 151 | jz 0f |
205 | ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev | 152 | ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev |
206 | oi __TI_flags+3(%r5),_TIF_MCCK_PENDING # set it in next | 153 | oi __TI_flags+3(%r5),_TIF_MCCK_PENDING # set it in next |
207 | 1: stm %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task | 154 | 0: stm %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task |
208 | st %r15,__THREAD_ksp(%r2) # store kernel stack of prev | 155 | st %r15,__THREAD_ksp(%r2) # store kernel stack of prev |
209 | l %r15,__THREAD_ksp(%r3) # load kernel stack of next | 156 | l %r15,__THREAD_ksp(%r3) # load kernel stack of next |
210 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 | 157 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 |
@@ -224,48 +171,55 @@ __critical_start: | |||
224 | 171 | ||
225 | ENTRY(system_call) | 172 | ENTRY(system_call) |
226 | stpt __LC_SYNC_ENTER_TIMER | 173 | stpt __LC_SYNC_ENTER_TIMER |
227 | sysc_saveall: | 174 | sysc_stm: |
228 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 175 | stm %r8,%r15,__LC_SAVE_AREA_SYNC |
229 | CREATE_STACK_FRAME __LC_SAVE_AREA | 176 | l %r12,__LC_THREAD_INFO |
230 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 177 | l %r13,__LC_SVC_NEW_PSW+4 |
231 | mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW | 178 | sysc_per: |
232 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC | 179 | l %r15,__LC_KERNEL_STACK |
233 | oi __TI_flags+3(%r12),_TIF_SYSCALL | 180 | ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
181 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs | ||
234 | sysc_vtime: | 182 | sysc_vtime: |
235 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 183 | UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER |
236 | sysc_stime: | 184 | stm %r0,%r7,__PT_R0(%r11) |
237 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 185 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC |
238 | sysc_update: | 186 | mvc __PT_PSW(8,%r11),__LC_SVC_OLD_PSW |
239 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 187 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC |
240 | sysc_do_svc: | 188 | sysc_do_svc: |
241 | xr %r7,%r7 | 189 | oi __TI_flags+3(%r12),_TIF_SYSCALL |
242 | icm %r7,3,SP_SVC_CODE+2(%r15)# load svc number and test for svc 0 | 190 | lh %r8,__PT_INT_CODE+2(%r11) |
243 | bnz BASED(sysc_nr_ok) # svc number > 0 | 191 | sla %r8,2 # shift and test for svc0 |
192 | jnz sysc_nr_ok | ||
244 | # svc 0: system call number in %r1 | 193 | # svc 0: system call number in %r1 |
245 | cl %r1,BASED(.Lnr_syscalls) | 194 | cl %r1,BASED(.Lnr_syscalls) |
246 | bnl BASED(sysc_nr_ok) | 195 | jnl sysc_nr_ok |
247 | sth %r1,SP_SVC_CODE+2(%r15) | 196 | sth %r1,__PT_INT_CODE+2(%r11) |
248 | lr %r7,%r1 # copy svc number to %r7 | 197 | lr %r8,%r1 |
198 | sla %r8,2 | ||
249 | sysc_nr_ok: | 199 | sysc_nr_ok: |
250 | sll %r7,2 # svc number *4 | 200 | l %r10,BASED(.Lsys_call_table) # 31 bit system call table |
251 | l %r10,BASED(.Lsysc_table) | 201 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
202 | st %r2,__PT_ORIG_GPR2(%r11) | ||
203 | st %r7,STACK_FRAME_OVERHEAD(%r15) | ||
204 | l %r9,0(%r8,%r10) # get system call addr. | ||
252 | tm __TI_flags+2(%r12),_TIF_TRACE >> 8 | 205 | tm __TI_flags+2(%r12),_TIF_TRACE >> 8 |
253 | mvc SP_ARGS(4,%r15),SP_R7(%r15) | 206 | jnz sysc_tracesys |
254 | l %r8,0(%r7,%r10) # get system call addr. | 207 | basr %r14,%r9 # call sys_xxxx |
255 | bnz BASED(sysc_tracesys) | 208 | st %r2,__PT_R2(%r11) # store return value |
256 | basr %r14,%r8 # call sys_xxxx | ||
257 | st %r2,SP_R2(%r15) # store return value (change R2 on stack) | ||
258 | 209 | ||
259 | sysc_return: | 210 | sysc_return: |
260 | LOCKDEP_SYS_EXIT | 211 | LOCKDEP_SYS_EXIT |
261 | sysc_tif: | 212 | sysc_tif: |
262 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 213 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
263 | bno BASED(sysc_restore) | 214 | jno sysc_restore |
264 | tm __TI_flags+3(%r12),_TIF_WORK_SVC | 215 | tm __TI_flags+3(%r12),_TIF_WORK_SVC |
265 | bnz BASED(sysc_work) # there is work to do (signals etc.) | 216 | jnz sysc_work # check for work |
266 | ni __TI_flags+3(%r12),255-_TIF_SYSCALL | 217 | ni __TI_flags+3(%r12),255-_TIF_SYSCALL |
267 | sysc_restore: | 218 | sysc_restore: |
268 | RESTORE_ALL __LC_RETURN_PSW,1 | 219 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) |
220 | stpt __LC_EXIT_TIMER | ||
221 | lm %r0,%r15,__PT_R0(%r11) | ||
222 | lpsw __LC_RETURN_PSW | ||
269 | sysc_done: | 223 | sysc_done: |
270 | 224 | ||
271 | # | 225 | # |
@@ -273,16 +227,16 @@ sysc_done: | |||
273 | # | 227 | # |
274 | sysc_work: | 228 | sysc_work: |
275 | tm __TI_flags+3(%r12),_TIF_MCCK_PENDING | 229 | tm __TI_flags+3(%r12),_TIF_MCCK_PENDING |
276 | bo BASED(sysc_mcck_pending) | 230 | jo sysc_mcck_pending |
277 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED | 231 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED |
278 | bo BASED(sysc_reschedule) | 232 | jo sysc_reschedule |
279 | tm __TI_flags+3(%r12),_TIF_SIGPENDING | 233 | tm __TI_flags+3(%r12),_TIF_SIGPENDING |
280 | bo BASED(sysc_sigpending) | 234 | jo sysc_sigpending |
281 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME | 235 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME |
282 | bo BASED(sysc_notify_resume) | 236 | jo sysc_notify_resume |
283 | tm __TI_flags+3(%r12),_TIF_PER_TRAP | 237 | tm __TI_flags+3(%r12),_TIF_PER_TRAP |
284 | bo BASED(sysc_singlestep) | 238 | jo sysc_singlestep |
285 | b BASED(sysc_return) # beware of critical section cleanup | 239 | j sysc_return # beware of critical section cleanup |
286 | 240 | ||
287 | # | 241 | # |
288 | # _TIF_NEED_RESCHED is set, call schedule | 242 | # _TIF_NEED_RESCHED is set, call schedule |
@@ -290,13 +244,13 @@ sysc_work: | |||
290 | sysc_reschedule: | 244 | sysc_reschedule: |
291 | l %r1,BASED(.Lschedule) | 245 | l %r1,BASED(.Lschedule) |
292 | la %r14,BASED(sysc_return) | 246 | la %r14,BASED(sysc_return) |
293 | br %r1 # call scheduler | 247 | br %r1 # call schedule |
294 | 248 | ||
295 | # | 249 | # |
296 | # _TIF_MCCK_PENDING is set, call handler | 250 | # _TIF_MCCK_PENDING is set, call handler |
297 | # | 251 | # |
298 | sysc_mcck_pending: | 252 | sysc_mcck_pending: |
299 | l %r1,BASED(.Ls390_handle_mcck) | 253 | l %r1,BASED(.Lhandle_mcck) |
300 | la %r14,BASED(sysc_return) | 254 | la %r14,BASED(sysc_return) |
301 | br %r1 # TIF bit will be cleared by handler | 255 | br %r1 # TIF bit will be cleared by handler |
302 | 256 | ||
@@ -305,23 +259,24 @@ sysc_mcck_pending: | |||
305 | # | 259 | # |
306 | sysc_sigpending: | 260 | sysc_sigpending: |
307 | ni __TI_flags+3(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP | 261 | ni __TI_flags+3(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP |
308 | la %r2,SP_PTREGS(%r15) # load pt_regs | 262 | lr %r2,%r11 # pass pointer to pt_regs |
309 | l %r1,BASED(.Ldo_signal) | 263 | l %r1,BASED(.Ldo_signal) |
310 | basr %r14,%r1 # call do_signal | 264 | basr %r14,%r1 # call do_signal |
311 | tm __TI_flags+3(%r12),_TIF_SYSCALL | 265 | tm __TI_flags+3(%r12),_TIF_SYSCALL |
312 | bno BASED(sysc_return) | 266 | jno sysc_return |
313 | lm %r2,%r6,SP_R2(%r15) # load svc arguments | 267 | lm %r2,%r7,__PT_R2(%r11) # load svc arguments |
314 | xr %r7,%r7 # svc 0 returns -ENOSYS | 268 | xr %r8,%r8 # svc 0 returns -ENOSYS |
315 | clc SP_SVC_CODE+2(2,%r15),BASED(.Lnr_syscalls+2) | 269 | clc __PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2) |
316 | bnl BASED(sysc_nr_ok) # invalid svc number -> do svc 0 | 270 | jnl sysc_nr_ok # invalid svc number -> do svc 0 |
317 | icm %r7,3,SP_SVC_CODE+2(%r15)# load new svc number | 271 | lh %r8,__PT_INT_CODE+2(%r11) # load new svc number |
318 | b BASED(sysc_nr_ok) # restart svc | 272 | sla %r8,2 |
273 | j sysc_nr_ok # restart svc | ||
319 | 274 | ||
320 | # | 275 | # |
321 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | 276 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume |
322 | # | 277 | # |
323 | sysc_notify_resume: | 278 | sysc_notify_resume: |
324 | la %r2,SP_PTREGS(%r15) # load pt_regs | 279 | lr %r2,%r11 # pass pointer to pt_regs |
325 | l %r1,BASED(.Ldo_notify_resume) | 280 | l %r1,BASED(.Ldo_notify_resume) |
326 | la %r14,BASED(sysc_return) | 281 | la %r14,BASED(sysc_return) |
327 | br %r1 # call do_notify_resume | 282 | br %r1 # call do_notify_resume |
@@ -331,56 +286,57 @@ sysc_notify_resume: | |||
331 | # | 286 | # |
332 | sysc_singlestep: | 287 | sysc_singlestep: |
333 | ni __TI_flags+3(%r12),255-(_TIF_SYSCALL | _TIF_PER_TRAP) | 288 | ni __TI_flags+3(%r12),255-(_TIF_SYSCALL | _TIF_PER_TRAP) |
334 | la %r2,SP_PTREGS(%r15) # address of register-save area | 289 | lr %r2,%r11 # pass pointer to pt_regs |
335 | l %r1,BASED(.Lhandle_per) # load adr. of per handler | 290 | l %r1,BASED(.Ldo_per_trap) |
336 | la %r14,BASED(sysc_return) # load adr. of system return | 291 | la %r14,BASED(sysc_return) |
337 | br %r1 # branch to do_per_trap | 292 | br %r1 # call do_per_trap |
338 | 293 | ||
339 | # | 294 | # |
340 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before | 295 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before |
341 | # and after the system call | 296 | # and after the system call |
342 | # | 297 | # |
343 | sysc_tracesys: | 298 | sysc_tracesys: |
344 | l %r1,BASED(.Ltrace_entry) | 299 | l %r1,BASED(.Ltrace_enter) |
345 | la %r2,SP_PTREGS(%r15) # load pt_regs | 300 | lr %r2,%r11 # pass pointer to pt_regs |
346 | la %r3,0 | 301 | la %r3,0 |
347 | xr %r0,%r0 | 302 | xr %r0,%r0 |
348 | icm %r0,3,SP_SVC_CODE(%r15) | 303 | icm %r0,3,__PT_INT_CODE+2(%r11) |
349 | st %r0,SP_R2(%r15) | 304 | st %r0,__PT_R2(%r11) |
350 | basr %r14,%r1 | 305 | basr %r14,%r1 # call do_syscall_trace_enter |
351 | cl %r2,BASED(.Lnr_syscalls) | 306 | cl %r2,BASED(.Lnr_syscalls) |
352 | bnl BASED(sysc_tracenogo) | 307 | jnl sysc_tracenogo |
353 | lr %r7,%r2 | 308 | lr %r8,%r2 |
354 | sll %r7,2 # svc number *4 | 309 | sll %r8,2 |
355 | l %r8,0(%r7,%r10) | 310 | l %r9,0(%r8,%r10) |
356 | sysc_tracego: | 311 | sysc_tracego: |
357 | lm %r3,%r6,SP_R3(%r15) | 312 | lm %r3,%r7,__PT_R3(%r11) |
358 | mvc SP_ARGS(4,%r15),SP_R7(%r15) | 313 | st %r7,STACK_FRAME_OVERHEAD(%r15) |
359 | l %r2,SP_ORIG_R2(%r15) | 314 | l %r2,__PT_ORIG_GPR2(%r11) |
360 | basr %r14,%r8 # call sys_xxx | 315 | basr %r14,%r9 # call sys_xxx |
361 | st %r2,SP_R2(%r15) # store return value | 316 | st %r2,__PT_R2(%r11) # store return value |
362 | sysc_tracenogo: | 317 | sysc_tracenogo: |
363 | tm __TI_flags+2(%r12),_TIF_TRACE >> 8 | 318 | tm __TI_flags+2(%r12),_TIF_TRACE >> 8 |
364 | bz BASED(sysc_return) | 319 | jz sysc_return |
365 | l %r1,BASED(.Ltrace_exit) | 320 | l %r1,BASED(.Ltrace_exit) |
366 | la %r2,SP_PTREGS(%r15) # load pt_regs | 321 | lr %r2,%r11 # pass pointer to pt_regs |
367 | la %r14,BASED(sysc_return) | 322 | la %r14,BASED(sysc_return) |
368 | br %r1 | 323 | br %r1 # call do_syscall_trace_exit |
369 | 324 | ||
370 | # | 325 | # |
371 | # a new process exits the kernel with ret_from_fork | 326 | # a new process exits the kernel with ret_from_fork |
372 | # | 327 | # |
373 | ENTRY(ret_from_fork) | 328 | ENTRY(ret_from_fork) |
329 | la %r11,STACK_FRAME_OVERHEAD(%r15) | ||
330 | l %r12,__LC_THREAD_INFO | ||
374 | l %r13,__LC_SVC_NEW_PSW+4 | 331 | l %r13,__LC_SVC_NEW_PSW+4 |
375 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 332 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? |
376 | tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? | 333 | jo 0f |
377 | bo BASED(0f) | 334 | st %r15,__PT_R15(%r11) # store stack pointer for new kthread |
378 | st %r15,SP_R15(%r15) # store stack pointer for new kthread | 335 | 0: l %r1,BASED(.Lschedule_tail) |
379 | 0: l %r1,BASED(.Lschedtail) | 336 | basr %r14,%r1 # call schedule_tail |
380 | basr %r14,%r1 | ||
381 | TRACE_IRQS_ON | 337 | TRACE_IRQS_ON |
382 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 338 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
383 | b BASED(sysc_tracenogo) | 339 | j sysc_tracenogo |
384 | 340 | ||
385 | # | 341 | # |
386 | # kernel_execve function needs to deal with pt_regs that is not | 342 | # kernel_execve function needs to deal with pt_regs that is not |
@@ -390,153 +346,98 @@ ENTRY(kernel_execve) | |||
390 | stm %r12,%r15,48(%r15) | 346 | stm %r12,%r15,48(%r15) |
391 | lr %r14,%r15 | 347 | lr %r14,%r15 |
392 | l %r13,__LC_SVC_NEW_PSW+4 | 348 | l %r13,__LC_SVC_NEW_PSW+4 |
393 | s %r15,BASED(.Lc_spsize) | 349 | ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
394 | st %r14,__SF_BACKCHAIN(%r15) | 350 | st %r14,__SF_BACKCHAIN(%r15) |
395 | la %r12,SP_PTREGS(%r15) | 351 | la %r12,STACK_FRAME_OVERHEAD(%r15) |
396 | xc 0(__PT_SIZE,%r12),0(%r12) | 352 | xc 0(__PT_SIZE,%r12),0(%r12) |
397 | l %r1,BASED(.Ldo_execve) | 353 | l %r1,BASED(.Ldo_execve) |
398 | lr %r5,%r12 | 354 | lr %r5,%r12 |
399 | basr %r14,%r1 | 355 | basr %r14,%r1 # call do_execve |
400 | ltr %r2,%r2 | 356 | ltr %r2,%r2 |
401 | be BASED(0f) | 357 | je 0f |
402 | a %r15,BASED(.Lc_spsize) | 358 | ahi %r15,(STACK_FRAME_OVERHEAD + __PT_SIZE) |
403 | lm %r12,%r15,48(%r15) | 359 | lm %r12,%r15,48(%r15) |
404 | br %r14 | 360 | br %r14 |
405 | # execve succeeded. | 361 | # execve succeeded. |
406 | 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts | 362 | 0: ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
407 | l %r15,__LC_KERNEL_STACK # load ksp | 363 | l %r15,__LC_KERNEL_STACK # load ksp |
408 | s %r15,BASED(.Lc_spsize) # make room for registers & psw | 364 | ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
409 | mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs | 365 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
366 | mvc 0(__PT_SIZE,%r11),0(%r12) # copy pt_regs | ||
410 | l %r12,__LC_THREAD_INFO | 367 | l %r12,__LC_THREAD_INFO |
411 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 368 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
412 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 369 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
413 | l %r1,BASED(.Lexecve_tail) | 370 | l %r1,BASED(.Lexecve_tail) |
414 | basr %r14,%r1 | 371 | basr %r14,%r1 # call execve_tail |
415 | b BASED(sysc_return) | 372 | j sysc_return |
416 | 373 | ||
417 | /* | 374 | /* |
418 | * Program check handler routine | 375 | * Program check handler routine |
419 | */ | 376 | */ |
420 | 377 | ||
421 | ENTRY(pgm_check_handler) | 378 | ENTRY(pgm_check_handler) |
422 | /* | ||
423 | * First we need to check for a special case: | ||
424 | * Single stepping an instruction that disables the PER event mask will | ||
425 | * cause a PER event AFTER the mask has been set. Example: SVC or LPSW. | ||
426 | * For a single stepped SVC the program check handler gets control after | ||
427 | * the SVC new PSW has been loaded. But we want to execute the SVC first and | ||
428 | * then handle the PER event. Therefore we update the SVC old PSW to point | ||
429 | * to the pgm_check_handler and branch to the SVC handler after we checked | ||
430 | * if we have to load the kernel stack register. | ||
431 | * For every other possible cause for PER event without the PER mask set | ||
432 | * we just ignore the PER event (FIXME: is there anything we have to do | ||
433 | * for LPSW?). | ||
434 | */ | ||
435 | stpt __LC_SYNC_ENTER_TIMER | 379 | stpt __LC_SYNC_ENTER_TIMER |
436 | SAVE_ALL_BASE __LC_SAVE_AREA | 380 | stm %r8,%r15,__LC_SAVE_AREA_SYNC |
437 | tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception | 381 | l %r12,__LC_THREAD_INFO |
438 | bnz BASED(pgm_per) # got per exception -> special case | 382 | l %r13,__LC_SVC_NEW_PSW+4 |
439 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA | 383 | lm %r8,%r9,__LC_PGM_OLD_PSW |
440 | CREATE_STACK_FRAME __LC_SAVE_AREA | 384 | tmh %r8,0x0001 # test problem state bit |
441 | mvc SP_PSW(8,%r15),__LC_PGM_OLD_PSW | 385 | jnz 1f # -> fault in user space |
442 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 386 | tmh %r8,0x4000 # PER bit set in old PSW ? |
443 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 387 | jnz 0f # -> enabled, can't be a double fault |
444 | bz BASED(pgm_no_vtime) | 388 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
445 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 389 | jnz pgm_svcper # -> single stepped svc |
446 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 390 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC |
447 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 391 | j 2f |
448 | pgm_no_vtime: | 392 | 1: UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER |
449 | l %r3,__LC_PGM_ILC # load program interruption code | 393 | l %r15,__LC_KERNEL_STACK |
450 | l %r4,__LC_TRANS_EXC_CODE | 394 | 2: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
451 | REENABLE_IRQS | 395 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
452 | la %r8,0x7f | 396 | stm %r0,%r7,__PT_R0(%r11) |
453 | nr %r8,%r3 | 397 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC |
454 | sll %r8,2 | 398 | stm %r8,%r9,__PT_PSW(%r11) |
455 | l %r1,BASED(.Ljump_table) | 399 | mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC |
456 | l %r1,0(%r8,%r1) # load address of handler routine | 400 | mvc __PT_INT_PARM_LONG(4,%r11),__LC_TRANS_EXC_CODE |
457 | la %r2,SP_PTREGS(%r15) # address of register-save area | 401 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
458 | basr %r14,%r1 # branch to interrupt-handler | 402 | jz 0f |
459 | pgm_exit: | ||
460 | b BASED(sysc_return) | ||
461 | |||
462 | # | ||
463 | # handle per exception | ||
464 | # | ||
465 | pgm_per: | ||
466 | tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on | ||
467 | bnz BASED(pgm_per_std) # ok, normal per event from user space | ||
468 | # ok its one of the special cases, now we need to find out which one | ||
469 | clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW | ||
470 | be BASED(pgm_svcper) | ||
471 | # no interesting special case, ignore PER event | ||
472 | lm %r12,%r15,__LC_SAVE_AREA | ||
473 | lpsw 0x28 | ||
474 | |||
475 | # | ||
476 | # Normal per exception | ||
477 | # | ||
478 | pgm_per_std: | ||
479 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA | ||
480 | CREATE_STACK_FRAME __LC_SAVE_AREA | ||
481 | mvc SP_PSW(8,%r15),__LC_PGM_OLD_PSW | ||
482 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
483 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | ||
484 | bz BASED(pgm_no_vtime2) | ||
485 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | ||
486 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | ||
487 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | ||
488 | pgm_no_vtime2: | ||
489 | l %r1,__TI_task(%r12) | 403 | l %r1,__TI_task(%r12) |
490 | tm SP_PSW+1(%r15),0x01 # kernel per event ? | 404 | tmh %r8,0x0001 # kernel per event ? |
491 | bz BASED(kernel_per) | 405 | jz pgm_kprobe |
492 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE | 406 | oi __TI_flags+3(%r12),_TIF_PER_TRAP |
493 | mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS | 407 | mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS |
408 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE | ||
494 | mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID | 409 | mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID |
495 | oi __TI_flags+3(%r12),_TIF_PER_TRAP # set TIF_PER_TRAP | 410 | 0: REENABLE_IRQS |
496 | l %r3,__LC_PGM_ILC # load program interruption code | 411 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
497 | l %r4,__LC_TRANS_EXC_CODE | ||
498 | REENABLE_IRQS | ||
499 | la %r8,0x7f | ||
500 | nr %r8,%r3 # clear per-event-bit and ilc | ||
501 | be BASED(pgm_exit2) # only per or per+check ? | ||
502 | sll %r8,2 | ||
503 | l %r1,BASED(.Ljump_table) | 412 | l %r1,BASED(.Ljump_table) |
504 | l %r1,0(%r8,%r1) # load address of handler routine | 413 | la %r10,0x7f |
505 | la %r2,SP_PTREGS(%r15) # address of register-save area | 414 | n %r10,__PT_INT_CODE(%r11) |
415 | je sysc_return | ||
416 | sll %r10,2 | ||
417 | l %r1,0(%r10,%r1) # load address of handler routine | ||
418 | lr %r2,%r11 # pass pointer to pt_regs | ||
506 | basr %r14,%r1 # branch to interrupt-handler | 419 | basr %r14,%r1 # branch to interrupt-handler |
507 | pgm_exit2: | 420 | j sysc_return |
508 | b BASED(sysc_return) | ||
509 | 421 | ||
510 | # | 422 | # |
511 | # it was a single stepped SVC that is causing all the trouble | 423 | # PER event in supervisor state, must be kprobes |
512 | # | 424 | # |
513 | pgm_svcper: | 425 | pgm_kprobe: |
514 | SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 426 | REENABLE_IRQS |
515 | CREATE_STACK_FRAME __LC_SAVE_AREA | 427 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
516 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 428 | l %r1,BASED(.Ldo_per_trap) |
517 | mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW | 429 | lr %r2,%r11 # pass pointer to pt_regs |
518 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC | 430 | basr %r14,%r1 # call do_per_trap |
519 | oi __TI_flags+3(%r12),(_TIF_SYSCALL | _TIF_PER_TRAP) | 431 | j sysc_return |
520 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | ||
521 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | ||
522 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | ||
523 | l %r8,__TI_task(%r12) | ||
524 | mvc __THREAD_per_cause(2,%r8),__LC_PER_CAUSE | ||
525 | mvc __THREAD_per_address(4,%r8),__LC_PER_ADDRESS | ||
526 | mvc __THREAD_per_paid(1,%r8),__LC_PER_PAID | ||
527 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | ||
528 | lm %r2,%r6,SP_R2(%r15) # load svc arguments | ||
529 | b BASED(sysc_do_svc) | ||
530 | 432 | ||
531 | # | 433 | # |
532 | # per was called from kernel, must be kprobes | 434 | # single stepped system call |
533 | # | 435 | # |
534 | kernel_per: | 436 | pgm_svcper: |
535 | REENABLE_IRQS | 437 | oi __TI_flags+3(%r12),_TIF_PER_TRAP |
536 | la %r2,SP_PTREGS(%r15) # address of register-save area | 438 | mvc __LC_RETURN_PSW(4),__LC_SVC_NEW_PSW |
537 | l %r1,BASED(.Lhandle_per) # load adr. of per handler | 439 | mvc __LC_RETURN_PSW+4(4),BASED(.Lsysc_per) |
538 | basr %r14,%r1 # branch to do_single_step | 440 | lpsw __LC_RETURN_PSW # branch to sysc_per and enable irqs |
539 | b BASED(pgm_exit) | ||
540 | 441 | ||
541 | /* | 442 | /* |
542 | * IO interrupt handler routine | 443 | * IO interrupt handler routine |
@@ -545,28 +446,35 @@ kernel_per: | |||
545 | ENTRY(io_int_handler) | 446 | ENTRY(io_int_handler) |
546 | stck __LC_INT_CLOCK | 447 | stck __LC_INT_CLOCK |
547 | stpt __LC_ASYNC_ENTER_TIMER | 448 | stpt __LC_ASYNC_ENTER_TIMER |
548 | SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+16 | 449 | stm %r8,%r15,__LC_SAVE_AREA_ASYNC |
549 | CREATE_STACK_FRAME __LC_SAVE_AREA+16 | 450 | l %r12,__LC_THREAD_INFO |
550 | mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack | 451 | l %r13,__LC_SVC_NEW_PSW+4 |
551 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 452 | lm %r8,%r9,__LC_IO_OLD_PSW |
552 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 453 | tmh %r8,0x0001 # interrupting from user ? |
553 | bz BASED(io_no_vtime) | 454 | jz io_skip |
554 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 455 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER |
555 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 456 | io_skip: |
556 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 457 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
557 | io_no_vtime: | 458 | stm %r0,%r7,__PT_R0(%r11) |
459 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC | ||
460 | stm %r8,%r9,__PT_PSW(%r11) | ||
558 | TRACE_IRQS_OFF | 461 | TRACE_IRQS_OFF |
559 | l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ | 462 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
560 | la %r2,SP_PTREGS(%r15) # address of register-save area | 463 | l %r1,BASED(.Ldo_IRQ) |
561 | basr %r14,%r1 # branch to standard irq handler | 464 | lr %r2,%r11 # pass pointer to pt_regs |
465 | basr %r14,%r1 # call do_IRQ | ||
562 | io_return: | 466 | io_return: |
563 | LOCKDEP_SYS_EXIT | 467 | LOCKDEP_SYS_EXIT |
564 | TRACE_IRQS_ON | 468 | TRACE_IRQS_ON |
565 | io_tif: | 469 | io_tif: |
566 | tm __TI_flags+3(%r12),_TIF_WORK_INT | 470 | tm __TI_flags+3(%r12),_TIF_WORK_INT |
567 | bnz BASED(io_work) # there is work to do (signals etc.) | 471 | jnz io_work # there is work to do (signals etc.) |
568 | io_restore: | 472 | io_restore: |
569 | RESTORE_ALL __LC_RETURN_PSW,0 | 473 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) |
474 | ni __LC_RETURN_PSW+1,0xfd # clean wait state bit | ||
475 | stpt __LC_EXIT_TIMER | ||
476 | lm %r0,%r15,__PT_R0(%r11) | ||
477 | lpsw __LC_RETURN_PSW | ||
570 | io_done: | 478 | io_done: |
571 | 479 | ||
572 | # | 480 | # |
@@ -577,28 +485,29 @@ io_done: | |||
577 | # Before any work can be done, a switch to the kernel stack is required. | 485 | # Before any work can be done, a switch to the kernel stack is required. |
578 | # | 486 | # |
579 | io_work: | 487 | io_work: |
580 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 488 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
581 | bo BASED(io_work_user) # yes -> do resched & signal | 489 | jo io_work_user # yes -> do resched & signal |
582 | #ifdef CONFIG_PREEMPT | 490 | #ifdef CONFIG_PREEMPT |
583 | # check for preemptive scheduling | 491 | # check for preemptive scheduling |
584 | icm %r0,15,__TI_precount(%r12) | 492 | icm %r0,15,__TI_precount(%r12) |
585 | bnz BASED(io_restore) # preemption disabled | 493 | jnz io_restore # preemption disabled |
586 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED | 494 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED |
587 | bno BASED(io_restore) | 495 | jno io_restore |
588 | # switch to kernel stack | 496 | # switch to kernel stack |
589 | l %r1,SP_R15(%r15) | 497 | l %r1,__PT_R15(%r11) |
590 | s %r1,BASED(.Lc_spsize) | 498 | ahi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
591 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 499 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
592 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 500 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) |
501 | la %r11,STACK_FRAME_OVERHEAD(%r1) | ||
593 | lr %r15,%r1 | 502 | lr %r15,%r1 |
594 | # TRACE_IRQS_ON already done at io_return, call | 503 | # TRACE_IRQS_ON already done at io_return, call |
595 | # TRACE_IRQS_OFF to keep things symmetrical | 504 | # TRACE_IRQS_OFF to keep things symmetrical |
596 | TRACE_IRQS_OFF | 505 | TRACE_IRQS_OFF |
597 | l %r1,BASED(.Lpreempt_schedule_irq) | 506 | l %r1,BASED(.Lpreempt_irq) |
598 | basr %r14,%r1 # call preempt_schedule_irq | 507 | basr %r14,%r1 # call preempt_schedule_irq |
599 | b BASED(io_return) | 508 | j io_return |
600 | #else | 509 | #else |
601 | b BASED(io_restore) | 510 | j io_restore |
602 | #endif | 511 | #endif |
603 | 512 | ||
604 | # | 513 | # |
@@ -606,9 +515,10 @@ io_work: | |||
606 | # | 515 | # |
607 | io_work_user: | 516 | io_work_user: |
608 | l %r1,__LC_KERNEL_STACK | 517 | l %r1,__LC_KERNEL_STACK |
609 | s %r1,BASED(.Lc_spsize) | 518 | ahi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
610 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 519 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
611 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 520 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) |
521 | la %r11,STACK_FRAME_OVERHEAD(%r1) | ||
612 | lr %r15,%r1 | 522 | lr %r15,%r1 |
613 | 523 | ||
614 | # | 524 | # |
@@ -618,24 +528,24 @@ io_work_user: | |||
618 | # | 528 | # |
619 | io_work_tif: | 529 | io_work_tif: |
620 | tm __TI_flags+3(%r12),_TIF_MCCK_PENDING | 530 | tm __TI_flags+3(%r12),_TIF_MCCK_PENDING |
621 | bo BASED(io_mcck_pending) | 531 | jo io_mcck_pending |
622 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED | 532 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED |
623 | bo BASED(io_reschedule) | 533 | jo io_reschedule |
624 | tm __TI_flags+3(%r12),_TIF_SIGPENDING | 534 | tm __TI_flags+3(%r12),_TIF_SIGPENDING |
625 | bo BASED(io_sigpending) | 535 | jo io_sigpending |
626 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME | 536 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME |
627 | bo BASED(io_notify_resume) | 537 | jo io_notify_resume |
628 | b BASED(io_return) # beware of critical section cleanup | 538 | j io_return # beware of critical section cleanup |
629 | 539 | ||
630 | # | 540 | # |
631 | # _TIF_MCCK_PENDING is set, call handler | 541 | # _TIF_MCCK_PENDING is set, call handler |
632 | # | 542 | # |
633 | io_mcck_pending: | 543 | io_mcck_pending: |
634 | # TRACE_IRQS_ON already done at io_return | 544 | # TRACE_IRQS_ON already done at io_return |
635 | l %r1,BASED(.Ls390_handle_mcck) | 545 | l %r1,BASED(.Lhandle_mcck) |
636 | basr %r14,%r1 # TIF bit will be cleared by handler | 546 | basr %r14,%r1 # TIF bit will be cleared by handler |
637 | TRACE_IRQS_OFF | 547 | TRACE_IRQS_OFF |
638 | b BASED(io_return) | 548 | j io_return |
639 | 549 | ||
640 | # | 550 | # |
641 | # _TIF_NEED_RESCHED is set, call schedule | 551 | # _TIF_NEED_RESCHED is set, call schedule |
@@ -643,37 +553,37 @@ io_mcck_pending: | |||
643 | io_reschedule: | 553 | io_reschedule: |
644 | # TRACE_IRQS_ON already done at io_return | 554 | # TRACE_IRQS_ON already done at io_return |
645 | l %r1,BASED(.Lschedule) | 555 | l %r1,BASED(.Lschedule) |
646 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 556 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
647 | basr %r14,%r1 # call scheduler | 557 | basr %r14,%r1 # call scheduler |
648 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 558 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
649 | TRACE_IRQS_OFF | 559 | TRACE_IRQS_OFF |
650 | b BASED(io_return) | 560 | j io_return |
651 | 561 | ||
652 | # | 562 | # |
653 | # _TIF_SIGPENDING is set, call do_signal | 563 | # _TIF_SIGPENDING is set, call do_signal |
654 | # | 564 | # |
655 | io_sigpending: | 565 | io_sigpending: |
656 | # TRACE_IRQS_ON already done at io_return | 566 | # TRACE_IRQS_ON already done at io_return |
657 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | ||
658 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
659 | l %r1,BASED(.Ldo_signal) | 567 | l %r1,BASED(.Ldo_signal) |
568 | ssm __LC_SVC_NEW_PSW # reenable interrupts | ||
569 | lr %r2,%r11 # pass pointer to pt_regs | ||
660 | basr %r14,%r1 # call do_signal | 570 | basr %r14,%r1 # call do_signal |
661 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 571 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
662 | TRACE_IRQS_OFF | 572 | TRACE_IRQS_OFF |
663 | b BASED(io_return) | 573 | j io_return |
664 | 574 | ||
665 | # | 575 | # |
666 | # _TIF_SIGPENDING is set, call do_signal | 576 | # _TIF_SIGPENDING is set, call do_signal |
667 | # | 577 | # |
668 | io_notify_resume: | 578 | io_notify_resume: |
669 | # TRACE_IRQS_ON already done at io_return | 579 | # TRACE_IRQS_ON already done at io_return |
670 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | ||
671 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
672 | l %r1,BASED(.Ldo_notify_resume) | 580 | l %r1,BASED(.Ldo_notify_resume) |
673 | basr %r14,%r1 # call do_signal | 581 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
674 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 582 | lr %r2,%r11 # pass pointer to pt_regs |
583 | basr %r14,%r1 # call do_notify_resume | ||
584 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | ||
675 | TRACE_IRQS_OFF | 585 | TRACE_IRQS_OFF |
676 | b BASED(io_return) | 586 | j io_return |
677 | 587 | ||
678 | /* | 588 | /* |
679 | * External interrupt handler routine | 589 | * External interrupt handler routine |
@@ -682,23 +592,25 @@ io_notify_resume: | |||
682 | ENTRY(ext_int_handler) | 592 | ENTRY(ext_int_handler) |
683 | stck __LC_INT_CLOCK | 593 | stck __LC_INT_CLOCK |
684 | stpt __LC_ASYNC_ENTER_TIMER | 594 | stpt __LC_ASYNC_ENTER_TIMER |
685 | SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16 | 595 | stm %r8,%r15,__LC_SAVE_AREA_ASYNC |
686 | CREATE_STACK_FRAME __LC_SAVE_AREA+16 | 596 | l %r12,__LC_THREAD_INFO |
687 | mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack | 597 | l %r13,__LC_SVC_NEW_PSW+4 |
688 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 598 | lm %r8,%r9,__LC_EXT_OLD_PSW |
689 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 599 | tmh %r8,0x0001 # interrupting from user ? |
690 | bz BASED(ext_no_vtime) | 600 | jz ext_skip |
691 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 601 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER |
692 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 602 | ext_skip: |
693 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 603 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
694 | ext_no_vtime: | 604 | stm %r0,%r7,__PT_R0(%r11) |
605 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC | ||
606 | stm %r8,%r9,__PT_PSW(%r11) | ||
695 | TRACE_IRQS_OFF | 607 | TRACE_IRQS_OFF |
696 | la %r2,SP_PTREGS(%r15) # address of register-save area | 608 | lr %r2,%r11 # pass pointer to pt_regs |
697 | l %r3,__LC_CPU_ADDRESS # get cpu address + interruption code | 609 | l %r3,__LC_CPU_ADDRESS # get cpu address + interruption code |
698 | l %r4,__LC_EXT_PARAMS # get external parameters | 610 | l %r4,__LC_EXT_PARAMS # get external parameters |
699 | l %r1,BASED(.Ldo_extint) | 611 | l %r1,BASED(.Ldo_extint) |
700 | basr %r14,%r1 | 612 | basr %r14,%r1 # call do_extint |
701 | b BASED(io_return) | 613 | j io_return |
702 | 614 | ||
703 | __critical_end: | 615 | __critical_end: |
704 | 616 | ||
@@ -710,82 +622,74 @@ ENTRY(mcck_int_handler) | |||
710 | stck __LC_MCCK_CLOCK | 622 | stck __LC_MCCK_CLOCK |
711 | spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer | 623 | spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer |
712 | lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs | 624 | lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs |
713 | SAVE_ALL_BASE __LC_SAVE_AREA+32 | 625 | l %r12,__LC_THREAD_INFO |
714 | la %r12,__LC_MCK_OLD_PSW | 626 | l %r13,__LC_SVC_NEW_PSW+4 |
627 | lm %r8,%r9,__LC_MCK_OLD_PSW | ||
715 | tm __LC_MCCK_CODE,0x80 # system damage? | 628 | tm __LC_MCCK_CODE,0x80 # system damage? |
716 | bo BASED(mcck_int_main) # yes -> rest of mcck code invalid | 629 | jo mcck_panic # yes -> rest of mcck code invalid |
717 | mvc __LC_MCCK_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA | 630 | la %r14,__LC_CPU_TIMER_SAVE_AREA |
631 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | ||
718 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | 632 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? |
719 | bo BASED(1f) | 633 | jo 3f |
720 | la %r14,__LC_SYNC_ENTER_TIMER | 634 | la %r14,__LC_SYNC_ENTER_TIMER |
721 | clc 0(8,%r14),__LC_ASYNC_ENTER_TIMER | 635 | clc 0(8,%r14),__LC_ASYNC_ENTER_TIMER |
722 | bl BASED(0f) | 636 | jl 0f |
723 | la %r14,__LC_ASYNC_ENTER_TIMER | 637 | la %r14,__LC_ASYNC_ENTER_TIMER |
724 | 0: clc 0(8,%r14),__LC_EXIT_TIMER | 638 | 0: clc 0(8,%r14),__LC_EXIT_TIMER |
725 | bl BASED(0f) | 639 | jl 1f |
726 | la %r14,__LC_EXIT_TIMER | 640 | la %r14,__LC_EXIT_TIMER |
727 | 0: clc 0(8,%r14),__LC_LAST_UPDATE_TIMER | 641 | 1: clc 0(8,%r14),__LC_LAST_UPDATE_TIMER |
728 | bl BASED(0f) | 642 | jl 2f |
729 | la %r14,__LC_LAST_UPDATE_TIMER | 643 | la %r14,__LC_LAST_UPDATE_TIMER |
730 | 0: spt 0(%r14) | 644 | 2: spt 0(%r14) |
731 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 645 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
732 | 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 646 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? |
733 | bno BASED(mcck_int_main) # no -> skip cleanup critical | 647 | jno mcck_panic # no -> skip cleanup critical |
734 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit | 648 | tm %r8,0x0001 # interrupting from user ? |
735 | bnz BASED(mcck_int_main) # from user -> load async stack | 649 | jz mcck_skip |
736 | clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_end) | 650 | UPDATE_VTIME %r14,%r15,__LC_MCCK_ENTER_TIMER |
737 | bhe BASED(mcck_int_main) | 651 | mcck_skip: |
738 | clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_start) | 652 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+32,__LC_PANIC_STACK,PAGE_SHIFT |
739 | bl BASED(mcck_int_main) | 653 | mvc __PT_R0(64,%r11),__LC_GPREGS_SAVE_AREA |
740 | l %r14,BASED(.Lcleanup_critical) | 654 | stm %r8,%r9,__PT_PSW(%r11) |
741 | basr %r14,%r14 | 655 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
742 | mcck_int_main: | 656 | l %r1,BASED(.Ldo_machine_check) |
743 | l %r14,__LC_PANIC_STACK # are we already on the panic stack? | 657 | lr %r2,%r11 # pass pointer to pt_regs |
744 | slr %r14,%r15 | 658 | basr %r14,%r1 # call s390_do_machine_check |
745 | sra %r14,PAGE_SHIFT | 659 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
746 | be BASED(0f) | 660 | jno mcck_return |
747 | l %r15,__LC_PANIC_STACK # load panic stack | ||
748 | 0: s %r15,BASED(.Lc_spsize) # make room for registers & psw | ||
749 | CREATE_STACK_FRAME __LC_SAVE_AREA+32 | ||
750 | mvc SP_PSW(8,%r15),0(%r12) | ||
751 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
752 | tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? | ||
753 | bno BASED(mcck_no_vtime) # no -> skip cleanup critical | ||
754 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | ||
755 | bz BASED(mcck_no_vtime) | ||
756 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER | ||
757 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | ||
758 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
759 | mcck_no_vtime: | ||
760 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
761 | l %r1,BASED(.Ls390_mcck) | ||
762 | basr %r14,%r1 # call machine check handler | ||
763 | tm SP_PSW+1(%r15),0x01 # returning to user ? | ||
764 | bno BASED(mcck_return) | ||
765 | l %r1,__LC_KERNEL_STACK # switch to kernel stack | 661 | l %r1,__LC_KERNEL_STACK # switch to kernel stack |
766 | s %r1,BASED(.Lc_spsize) | 662 | ahi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
767 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 663 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
768 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 664 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) |
665 | la %r11,STACK_FRAME_OVERHEAD(%r15) | ||
769 | lr %r15,%r1 | 666 | lr %r15,%r1 |
770 | stosm __SF_EMPTY(%r15),0x04 # turn dat on | 667 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off |
771 | tm __TI_flags+3(%r12),_TIF_MCCK_PENDING | 668 | tm __TI_flags+3(%r12),_TIF_MCCK_PENDING |
772 | bno BASED(mcck_return) | 669 | jno mcck_return |
773 | TRACE_IRQS_OFF | 670 | TRACE_IRQS_OFF |
774 | l %r1,BASED(.Ls390_handle_mcck) | 671 | l %r1,BASED(.Lhandle_mcck) |
775 | basr %r14,%r1 # call machine check handler | 672 | basr %r14,%r1 # call s390_handle_mcck |
776 | TRACE_IRQS_ON | 673 | TRACE_IRQS_ON |
777 | mcck_return: | 674 | mcck_return: |
778 | mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW | 675 | mvc __LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW |
779 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit | 676 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit |
780 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? | 677 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? |
781 | bno BASED(0f) | 678 | jno 0f |
782 | lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 | 679 | lm %r0,%r15,__PT_R0(%r11) |
783 | stpt __LC_EXIT_TIMER | 680 | stpt __LC_EXIT_TIMER |
784 | lpsw __LC_RETURN_MCCK_PSW # back to caller | 681 | lpsw __LC_RETURN_MCCK_PSW |
785 | 0: lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 | 682 | 0: lm %r0,%r15,__PT_R0(%r11) |
786 | lpsw __LC_RETURN_MCCK_PSW # back to caller | 683 | lpsw __LC_RETURN_MCCK_PSW |
787 | 684 | ||
788 | RESTORE_ALL __LC_RETURN_MCCK_PSW,0 | 685 | mcck_panic: |
686 | l %r14,__LC_PANIC_STACK | ||
687 | slr %r14,%r15 | ||
688 | sra %r14,PAGE_SHIFT | ||
689 | jz 0f | ||
690 | l %r15,__LC_PANIC_STACK | ||
691 | 0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | ||
692 | j mcck_skip | ||
789 | 693 | ||
790 | /* | 694 | /* |
791 | * Restart interruption handler, kick starter for additional CPUs | 695 | * Restart interruption handler, kick starter for additional CPUs |
@@ -799,18 +703,18 @@ restart_base: | |||
799 | stck __LC_LAST_UPDATE_CLOCK | 703 | stck __LC_LAST_UPDATE_CLOCK |
800 | mvc __LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1) | 704 | mvc __LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1) |
801 | mvc __LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1) | 705 | mvc __LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1) |
802 | l %r15,__LC_SAVE_AREA+60 # load ksp | 706 | l %r15,__LC_GPREGS_SAVE_AREA+60 # load ksp |
803 | lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs | 707 | lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs |
804 | lam %a0,%a15,__LC_AREGS_SAVE_AREA | 708 | lam %a0,%a15,__LC_AREGS_SAVE_AREA |
805 | lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone | 709 | lm %r6,%r15,__SF_GPRS(%r15)# load registers from clone |
806 | l %r1,__LC_THREAD_INFO | 710 | l %r1,__LC_THREAD_INFO |
807 | mvc __LC_USER_TIMER(8),__TI_user_timer(%r1) | 711 | mvc __LC_USER_TIMER(8),__TI_user_timer(%r1) |
808 | mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1) | 712 | mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1) |
809 | xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER | 713 | xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER |
810 | stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on | 714 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off |
811 | basr %r14,0 | 715 | basr %r14,0 |
812 | l %r14,restart_addr-.(%r14) | 716 | l %r14,restart_addr-.(%r14) |
813 | basr %r14,%r14 # branch to start_secondary | 717 | basr %r14,%r14 # call start_secondary |
814 | restart_addr: | 718 | restart_addr: |
815 | .long start_secondary | 719 | .long start_secondary |
816 | .align 8 | 720 | .align 8 |
@@ -835,19 +739,19 @@ restart_go: | |||
835 | # PSW restart interrupt handler | 739 | # PSW restart interrupt handler |
836 | # | 740 | # |
837 | ENTRY(psw_restart_int_handler) | 741 | ENTRY(psw_restart_int_handler) |
838 | st %r15,__LC_SAVE_AREA+48(%r0) # save r15 | 742 | st %r15,__LC_SAVE_AREA_RESTART |
839 | basr %r15,0 | 743 | basr %r15,0 |
840 | 0: l %r15,.Lrestart_stack-0b(%r15) # load restart stack | 744 | 0: l %r15,.Lrestart_stack-0b(%r15) # load restart stack |
841 | l %r15,0(%r15) | 745 | l %r15,0(%r15) |
842 | ahi %r15,-SP_SIZE # make room for pt_regs | 746 | ahi %r15,-__PT_SIZE # create pt_regs on stack |
843 | stm %r0,%r14,SP_R0(%r15) # store gprs %r0-%r14 to stack | 747 | stm %r0,%r14,__PT_R0(%r15) |
844 | mvc SP_R15(4,%r15),__LC_SAVE_AREA+48(%r0)# store saved %r15 to stack | 748 | mvc __PT_R15(4,%r15),__LC_SAVE_AREA_RESTART |
845 | mvc SP_PSW(8,%r15),__LC_RST_OLD_PSW(%r0) # store restart old psw | 749 | mvc __PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw |
846 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # set backchain to 0 | 750 | ahi %r15,-STACK_FRAME_OVERHEAD |
751 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | ||
847 | basr %r14,0 | 752 | basr %r14,0 |
848 | 1: l %r14,.Ldo_restart-1b(%r14) | 753 | 1: l %r14,.Ldo_restart-1b(%r14) |
849 | basr %r14,%r14 | 754 | basr %r14,%r14 |
850 | |||
851 | basr %r14,0 # load disabled wait PSW if | 755 | basr %r14,0 # load disabled wait PSW if |
852 | 2: lpsw restart_psw_crash-2b(%r14) # do_restart returns | 756 | 2: lpsw restart_psw_crash-2b(%r14) # do_restart returns |
853 | .align 4 | 757 | .align 4 |
@@ -869,215 +773,174 @@ restart_psw_crash: | |||
869 | */ | 773 | */ |
870 | stack_overflow: | 774 | stack_overflow: |
871 | l %r15,__LC_PANIC_STACK # change to panic stack | 775 | l %r15,__LC_PANIC_STACK # change to panic stack |
872 | sl %r15,BASED(.Lc_spsize) | 776 | ahi %r15,-__PT_SIZE # create pt_regs |
873 | mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack | 777 | stm %r0,%r7,__PT_R0(%r15) |
874 | stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack | 778 | stm %r8,%r9,__PT_PSW(%r15) |
875 | la %r1,__LC_SAVE_AREA | 779 | mvc __PT_R8(32,%r11),0(%r14) |
876 | ch %r12,BASED(.L0x020) # old psw addr == __LC_SVC_OLD_PSW ? | 780 | lr %r15,%r11 |
877 | be BASED(0f) | 781 | ahi %r15,-STACK_FRAME_OVERHEAD |
878 | ch %r12,BASED(.L0x028) # old psw addr == __LC_PGM_OLD_PSW ? | 782 | l %r1,BASED(1f) |
879 | be BASED(0f) | 783 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
880 | la %r1,__LC_SAVE_AREA+16 | 784 | lr %r2,%r11 # pass pointer to pt_regs |
881 | 0: mvc SP_R12(16,%r15),0(%r1) # move %r12-%r15 to stack | 785 | br %r1 # branch to kernel_stack_overflow |
882 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain | ||
883 | l %r1,BASED(1f) # branch to kernel_stack_overflow | ||
884 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
885 | br %r1 | ||
886 | 1: .long kernel_stack_overflow | 786 | 1: .long kernel_stack_overflow |
887 | #endif | 787 | #endif |
888 | 788 | ||
889 | cleanup_table_system_call: | 789 | cleanup_table: |
890 | .long system_call + 0x80000000, sysc_do_svc + 0x80000000 | 790 | .long system_call + 0x80000000 |
891 | cleanup_table_sysc_tif: | 791 | .long sysc_do_svc + 0x80000000 |
892 | .long sysc_tif + 0x80000000, sysc_restore + 0x80000000 | 792 | .long sysc_tif + 0x80000000 |
893 | cleanup_table_sysc_restore: | 793 | .long sysc_restore + 0x80000000 |
894 | .long sysc_restore + 0x80000000, sysc_done + 0x80000000 | 794 | .long sysc_done + 0x80000000 |
895 | cleanup_table_io_tif: | 795 | .long io_tif + 0x80000000 |
896 | .long io_tif + 0x80000000, io_restore + 0x80000000 | 796 | .long io_restore + 0x80000000 |
897 | cleanup_table_io_restore: | 797 | .long io_done + 0x80000000 |
898 | .long io_restore + 0x80000000, io_done + 0x80000000 | ||
899 | 798 | ||
900 | cleanup_critical: | 799 | cleanup_critical: |
901 | clc 4(4,%r12),BASED(cleanup_table_system_call) | 800 | cl %r9,BASED(cleanup_table) # system_call |
902 | bl BASED(0f) | 801 | jl 0f |
903 | clc 4(4,%r12),BASED(cleanup_table_system_call+4) | 802 | cl %r9,BASED(cleanup_table+4) # sysc_do_svc |
904 | bl BASED(cleanup_system_call) | 803 | jl cleanup_system_call |
905 | 0: | 804 | cl %r9,BASED(cleanup_table+8) # sysc_tif |
906 | clc 4(4,%r12),BASED(cleanup_table_sysc_tif) | 805 | jl 0f |
907 | bl BASED(0f) | 806 | cl %r9,BASED(cleanup_table+12) # sysc_restore |
908 | clc 4(4,%r12),BASED(cleanup_table_sysc_tif+4) | 807 | jl cleanup_sysc_tif |
909 | bl BASED(cleanup_sysc_tif) | 808 | cl %r9,BASED(cleanup_table+16) # sysc_done |
910 | 0: | 809 | jl cleanup_sysc_restore |
911 | clc 4(4,%r12),BASED(cleanup_table_sysc_restore) | 810 | cl %r9,BASED(cleanup_table+20) # io_tif |
912 | bl BASED(0f) | 811 | jl 0f |
913 | clc 4(4,%r12),BASED(cleanup_table_sysc_restore+4) | 812 | cl %r9,BASED(cleanup_table+24) # io_restore |
914 | bl BASED(cleanup_sysc_restore) | 813 | jl cleanup_io_tif |
915 | 0: | 814 | cl %r9,BASED(cleanup_table+28) # io_done |
916 | clc 4(4,%r12),BASED(cleanup_table_io_tif) | 815 | jl cleanup_io_restore |
917 | bl BASED(0f) | 816 | 0: br %r14 |
918 | clc 4(4,%r12),BASED(cleanup_table_io_tif+4) | ||
919 | bl BASED(cleanup_io_tif) | ||
920 | 0: | ||
921 | clc 4(4,%r12),BASED(cleanup_table_io_restore) | ||
922 | bl BASED(0f) | ||
923 | clc 4(4,%r12),BASED(cleanup_table_io_restore+4) | ||
924 | bl BASED(cleanup_io_restore) | ||
925 | 0: | ||
926 | br %r14 | ||
927 | 817 | ||
928 | cleanup_system_call: | 818 | cleanup_system_call: |
929 | mvc __LC_RETURN_PSW(8),0(%r12) | 819 | # check if stpt has been executed |
930 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4) | 820 | cl %r9,BASED(cleanup_system_call_insn) |
931 | bh BASED(0f) | 821 | jh 0f |
932 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
933 | c %r12,BASED(.Lmck_old_psw) | ||
934 | be BASED(0f) | ||
935 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER | 822 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER |
936 | 0: c %r12,BASED(.Lmck_old_psw) | 823 | chi %r11,__LC_SAVE_AREA_ASYNC |
937 | la %r12,__LC_SAVE_AREA+32 | 824 | je 0f |
938 | be BASED(0f) | 825 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER |
939 | la %r12,__LC_SAVE_AREA+16 | 826 | 0: # check if stm has been executed |
940 | 0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) | 827 | cl %r9,BASED(cleanup_system_call_insn+4) |
941 | bhe BASED(cleanup_vtime) | 828 | jh 0f |
942 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn) | 829 | mvc __LC_SAVE_AREA_SYNC(32),0(%r11) |
943 | bh BASED(0f) | 830 | 0: # set up saved registers r12, and r13 |
944 | mvc __LC_SAVE_AREA(16),0(%r12) | 831 | st %r12,16(%r11) # r12 thread-info pointer |
945 | 0: st %r13,4(%r12) | 832 | st %r13,20(%r11) # r13 literal-pool pointer |
946 | l %r15,__LC_KERNEL_STACK # problem state -> load ksp | 833 | # check if the user time calculation has been done |
947 | s %r15,BASED(.Lc_spsize) # make room for registers & psw | 834 | cl %r9,BASED(cleanup_system_call_insn+8) |
948 | st %r15,12(%r12) | 835 | jh 0f |
949 | CREATE_STACK_FRAME __LC_SAVE_AREA | 836 | l %r10,__LC_EXIT_TIMER |
950 | mvc 0(4,%r12),__LC_THREAD_INFO | 837 | l %r15,__LC_EXIT_TIMER+4 |
951 | l %r12,__LC_THREAD_INFO | 838 | SUB64 %r10,%r15,__LC_SYNC_ENTER_TIMER |
952 | mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW | 839 | ADD64 %r10,%r15,__LC_USER_TIMER |
953 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC | 840 | st %r10,__LC_USER_TIMER |
954 | oi __TI_flags+3(%r12),_TIF_SYSCALL | 841 | st %r15,__LC_USER_TIMER+4 |
955 | cleanup_vtime: | 842 | 0: # check if the system time calculation has been done |
956 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12) | 843 | cl %r9,BASED(cleanup_system_call_insn+12) |
957 | bhe BASED(cleanup_stime) | 844 | jh 0f |
958 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 845 | l %r10,__LC_LAST_UPDATE_TIMER |
959 | cleanup_stime: | 846 | l %r15,__LC_LAST_UPDATE_TIMER+4 |
960 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+16) | 847 | SUB64 %r10,%r15,__LC_EXIT_TIMER |
961 | bh BASED(cleanup_update) | 848 | ADD64 %r10,%r15,__LC_SYSTEM_TIMER |
962 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 849 | st %r10,__LC_SYSTEM_TIMER |
963 | cleanup_update: | 850 | st %r15,__LC_SYSTEM_TIMER+4 |
851 | 0: # update accounting time stamp | ||
964 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 852 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
965 | mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_system_call+4) | 853 | # set up saved register 11 |
966 | la %r12,__LC_RETURN_PSW | 854 | l %r15,__LC_KERNEL_STACK |
855 | ahi %r15,-__PT_SIZE | ||
856 | st %r15,12(%r11) # r11 pt_regs pointer | ||
857 | # fill pt_regs | ||
858 | mvc __PT_R8(32,%r15),__LC_SAVE_AREA_SYNC | ||
859 | stm %r0,%r7,__PT_R0(%r15) | ||
860 | mvc __PT_PSW(8,%r15),__LC_SVC_OLD_PSW | ||
861 | mvc __PT_INT_CODE(4,%r15),__LC_SVC_ILC | ||
862 | # setup saved register 15 | ||
863 | ahi %r15,-STACK_FRAME_OVERHEAD | ||
864 | st %r15,28(%r11) # r15 stack pointer | ||
865 | # set new psw address and exit | ||
866 | l %r9,BASED(cleanup_table+4) # sysc_do_svc + 0x80000000 | ||
967 | br %r14 | 867 | br %r14 |
968 | cleanup_system_call_insn: | 868 | cleanup_system_call_insn: |
969 | .long sysc_saveall + 0x80000000 | ||
970 | .long system_call + 0x80000000 | 869 | .long system_call + 0x80000000 |
971 | .long sysc_vtime + 0x80000000 | 870 | .long sysc_stm + 0x80000000 |
972 | .long sysc_stime + 0x80000000 | 871 | .long sysc_vtime + 0x80000000 + 36 |
973 | .long sysc_update + 0x80000000 | 872 | .long sysc_vtime + 0x80000000 + 76 |
974 | 873 | ||
975 | cleanup_sysc_tif: | 874 | cleanup_sysc_tif: |
976 | mvc __LC_RETURN_PSW(4),0(%r12) | 875 | l %r9,BASED(cleanup_table+8) # sysc_tif + 0x80000000 |
977 | mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_sysc_tif) | ||
978 | la %r12,__LC_RETURN_PSW | ||
979 | br %r14 | 876 | br %r14 |
980 | 877 | ||
981 | cleanup_sysc_restore: | 878 | cleanup_sysc_restore: |
982 | clc 4(4,%r12),BASED(cleanup_sysc_restore_insn) | 879 | cl %r9,BASED(cleanup_sysc_restore_insn) |
983 | be BASED(2f) | 880 | jhe 0f |
984 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER | 881 | l %r9,12(%r11) # get saved pointer to pt_regs |
985 | c %r12,BASED(.Lmck_old_psw) | 882 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) |
986 | be BASED(0f) | 883 | mvc 0(32,%r11),__PT_R8(%r9) |
987 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | 884 | lm %r0,%r7,__PT_R0(%r9) |
988 | 0: clc 4(4,%r12),BASED(cleanup_sysc_restore_insn+4) | 885 | 0: lm %r8,%r9,__LC_RETURN_PSW |
989 | be BASED(2f) | ||
990 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) | ||
991 | c %r12,BASED(.Lmck_old_psw) | ||
992 | la %r12,__LC_SAVE_AREA+32 | ||
993 | be BASED(1f) | ||
994 | la %r12,__LC_SAVE_AREA+16 | ||
995 | 1: mvc 0(16,%r12),SP_R12(%r15) | ||
996 | lm %r0,%r11,SP_R0(%r15) | ||
997 | l %r15,SP_R15(%r15) | ||
998 | 2: la %r12,__LC_RETURN_PSW | ||
999 | br %r14 | 886 | br %r14 |
1000 | cleanup_sysc_restore_insn: | 887 | cleanup_sysc_restore_insn: |
1001 | .long sysc_done - 4 + 0x80000000 | 888 | .long sysc_done - 4 + 0x80000000 |
1002 | .long sysc_done - 8 + 0x80000000 | ||
1003 | 889 | ||
1004 | cleanup_io_tif: | 890 | cleanup_io_tif: |
1005 | mvc __LC_RETURN_PSW(4),0(%r12) | 891 | l %r9,BASED(cleanup_table+20) # io_tif + 0x80000000 |
1006 | mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_io_tif) | ||
1007 | la %r12,__LC_RETURN_PSW | ||
1008 | br %r14 | 892 | br %r14 |
1009 | 893 | ||
1010 | cleanup_io_restore: | 894 | cleanup_io_restore: |
1011 | clc 4(4,%r12),BASED(cleanup_io_restore_insn) | 895 | cl %r9,BASED(cleanup_io_restore_insn) |
1012 | be BASED(1f) | 896 | jhe 0f |
1013 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER | 897 | l %r9,12(%r11) # get saved r11 pointer to pt_regs |
1014 | clc 4(4,%r12),BASED(cleanup_io_restore_insn+4) | 898 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) |
1015 | be BASED(1f) | 899 | ni __LC_RETURN_PSW+1,0xfd # clear wait state bit |
1016 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) | 900 | mvc 0(32,%r11),__PT_R8(%r9) |
1017 | mvc __LC_SAVE_AREA+32(16),SP_R12(%r15) | 901 | lm %r0,%r7,__PT_R0(%r9) |
1018 | lm %r0,%r11,SP_R0(%r15) | 902 | 0: lm %r8,%r9,__LC_RETURN_PSW |
1019 | l %r15,SP_R15(%r15) | ||
1020 | 1: la %r12,__LC_RETURN_PSW | ||
1021 | br %r14 | 903 | br %r14 |
1022 | cleanup_io_restore_insn: | 904 | cleanup_io_restore_insn: |
1023 | .long io_done - 4 + 0x80000000 | 905 | .long io_done - 4 + 0x80000000 |
1024 | .long io_done - 8 + 0x80000000 | ||
1025 | 906 | ||
1026 | /* | 907 | /* |
1027 | * Integer constants | 908 | * Integer constants |
1028 | */ | 909 | */ |
1029 | .align 4 | 910 | .align 4 |
1030 | .Lc_spsize: .long SP_SIZE | 911 | .Lnr_syscalls: .long NR_syscalls |
1031 | .Lc_overhead: .long STACK_FRAME_OVERHEAD | ||
1032 | .Lnr_syscalls: .long NR_syscalls | ||
1033 | .L0x018: .short 0x018 | ||
1034 | .L0x020: .short 0x020 | ||
1035 | .L0x028: .short 0x028 | ||
1036 | .L0x030: .short 0x030 | ||
1037 | .L0x038: .short 0x038 | ||
1038 | .Lc_1: .long 1 | ||
1039 | 912 | ||
1040 | /* | 913 | /* |
1041 | * Symbol constants | 914 | * Symbol constants |
1042 | */ | 915 | */ |
1043 | .Ls390_mcck: .long s390_do_machine_check | 916 | .Ldo_machine_check: .long s390_do_machine_check |
1044 | .Ls390_handle_mcck: | 917 | .Lhandle_mcck: .long s390_handle_mcck |
1045 | .long s390_handle_mcck | 918 | .Ldo_IRQ: .long do_IRQ |
1046 | .Lmck_old_psw: .long __LC_MCK_OLD_PSW | 919 | .Ldo_extint: .long do_extint |
1047 | .Ldo_IRQ: .long do_IRQ | 920 | .Ldo_signal: .long do_signal |
1048 | .Ldo_extint: .long do_extint | 921 | .Ldo_notify_resume: .long do_notify_resume |
1049 | .Ldo_signal: .long do_signal | 922 | .Ldo_per_trap: .long do_per_trap |
1050 | .Ldo_notify_resume: | 923 | .Ldo_execve: .long do_execve |
1051 | .long do_notify_resume | 924 | .Lexecve_tail: .long execve_tail |
1052 | .Lhandle_per: .long do_per_trap | 925 | .Ljump_table: .long pgm_check_table |
1053 | .Ldo_execve: .long do_execve | 926 | .Lschedule: .long schedule |
1054 | .Lexecve_tail: .long execve_tail | ||
1055 | .Ljump_table: .long pgm_check_table | ||
1056 | .Lschedule: .long schedule | ||
1057 | #ifdef CONFIG_PREEMPT | 927 | #ifdef CONFIG_PREEMPT |
1058 | .Lpreempt_schedule_irq: | 928 | .Lpreempt_irq: .long preempt_schedule_irq |
1059 | .long preempt_schedule_irq | ||
1060 | #endif | 929 | #endif |
1061 | .Ltrace_entry: .long do_syscall_trace_enter | 930 | .Ltrace_enter: .long do_syscall_trace_enter |
1062 | .Ltrace_exit: .long do_syscall_trace_exit | 931 | .Ltrace_exit: .long do_syscall_trace_exit |
1063 | .Lschedtail: .long schedule_tail | 932 | .Lschedule_tail: .long schedule_tail |
1064 | .Lsysc_table: .long sys_call_table | 933 | .Lsys_call_table: .long sys_call_table |
934 | .Lsysc_per: .long sysc_per + 0x80000000 | ||
1065 | #ifdef CONFIG_TRACE_IRQFLAGS | 935 | #ifdef CONFIG_TRACE_IRQFLAGS |
1066 | .Ltrace_irq_on_caller: | 936 | .Lhardirqs_on: .long trace_hardirqs_on_caller |
1067 | .long trace_hardirqs_on_caller | 937 | .Lhardirqs_off: .long trace_hardirqs_off_caller |
1068 | .Ltrace_irq_off_caller: | ||
1069 | .long trace_hardirqs_off_caller | ||
1070 | #endif | 938 | #endif |
1071 | #ifdef CONFIG_LOCKDEP | 939 | #ifdef CONFIG_LOCKDEP |
1072 | .Llockdep_sys_exit: | 940 | .Llockdep_sys_exit: .long lockdep_sys_exit |
1073 | .long lockdep_sys_exit | ||
1074 | #endif | 941 | #endif |
1075 | .Lcritical_start: | 942 | .Lcritical_start: .long __critical_start + 0x80000000 |
1076 | .long __critical_start + 0x80000000 | 943 | .Lcritical_length: .long __critical_end - __critical_start |
1077 | .Lcritical_end: | ||
1078 | .long __critical_end + 0x80000000 | ||
1079 | .Lcleanup_critical: | ||
1080 | .long cleanup_critical | ||
1081 | 944 | ||
1082 | .section .rodata, "a" | 945 | .section .rodata, "a" |
1083 | #define SYSCALL(esa,esame,emu) .long esa | 946 | #define SYSCALL(esa,esame,emu) .long esa |
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index ef8fb1d6e8d7..bf538aaf407d 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h | |||
@@ -6,15 +6,15 @@ | |||
6 | #include <asm/ptrace.h> | 6 | #include <asm/ptrace.h> |
7 | 7 | ||
8 | 8 | ||
9 | extern void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long); | 9 | extern void (*pgm_check_table[128])(struct pt_regs *); |
10 | extern void *restart_stack; | 10 | extern void *restart_stack; |
11 | 11 | ||
12 | asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); | 12 | asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); |
13 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs); | 13 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs); |
14 | 14 | ||
15 | void do_protection_exception(struct pt_regs *, long, unsigned long); | 15 | void do_protection_exception(struct pt_regs *regs); |
16 | void do_dat_exception(struct pt_regs *, long, unsigned long); | 16 | void do_dat_exception(struct pt_regs *regs); |
17 | void do_asce_exception(struct pt_regs *, long, unsigned long); | 17 | void do_asce_exception(struct pt_regs *regs); |
18 | 18 | ||
19 | void do_per_trap(struct pt_regs *regs); | 19 | void do_per_trap(struct pt_regs *regs); |
20 | void syscall_trace(struct pt_regs *regs, int entryexit); | 20 | void syscall_trace(struct pt_regs *regs, int entryexit); |
@@ -28,7 +28,7 @@ void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long); | |||
28 | void do_restart(void); | 28 | void do_restart(void); |
29 | int __cpuinit start_secondary(void *cpuvoid); | 29 | int __cpuinit start_secondary(void *cpuvoid); |
30 | void __init startup_init(void); | 30 | void __init startup_init(void); |
31 | void die(const char * str, struct pt_regs * regs, long err); | 31 | void die(struct pt_regs *regs, const char *str); |
32 | 32 | ||
33 | void __init time_init(void); | 33 | void __init time_init(void); |
34 | 34 | ||
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 83a93747e2fd..412a7b8783d7 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -19,32 +19,22 @@ | |||
19 | #include <asm/unistd.h> | 19 | #include <asm/unistd.h> |
20 | #include <asm/page.h> | 20 | #include <asm/page.h> |
21 | 21 | ||
22 | /* | 22 | __PT_R0 = __PT_GPRS |
23 | * Stack layout for the system_call stack entry. | 23 | __PT_R1 = __PT_GPRS + 8 |
24 | * The first few entries are identical to the user_regs_struct. | 24 | __PT_R2 = __PT_GPRS + 16 |
25 | */ | 25 | __PT_R3 = __PT_GPRS + 24 |
26 | SP_PTREGS = STACK_FRAME_OVERHEAD | 26 | __PT_R4 = __PT_GPRS + 32 |
27 | SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS | 27 | __PT_R5 = __PT_GPRS + 40 |
28 | SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW | 28 | __PT_R6 = __PT_GPRS + 48 |
29 | SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS | 29 | __PT_R7 = __PT_GPRS + 56 |
30 | SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8 | 30 | __PT_R8 = __PT_GPRS + 64 |
31 | SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16 | 31 | __PT_R9 = __PT_GPRS + 72 |
32 | SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24 | 32 | __PT_R10 = __PT_GPRS + 80 |
33 | SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32 | 33 | __PT_R11 = __PT_GPRS + 88 |
34 | SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40 | 34 | __PT_R12 = __PT_GPRS + 96 |
35 | SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48 | 35 | __PT_R13 = __PT_GPRS + 104 |
36 | SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56 | 36 | __PT_R14 = __PT_GPRS + 112 |
37 | SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 64 | 37 | __PT_R15 = __PT_GPRS + 120 |
38 | SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 72 | ||
39 | SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 80 | ||
40 | SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 88 | ||
41 | SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 96 | ||
42 | SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104 | ||
43 | SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112 | ||
44 | SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120 | ||
45 | SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 | ||
46 | SP_SVC_CODE = STACK_FRAME_OVERHEAD + __PT_SVC_CODE | ||
47 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE | ||
48 | 38 | ||
49 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER | 39 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER |
50 | STACK_SIZE = 1 << STACK_SHIFT | 40 | STACK_SIZE = 1 << STACK_SHIFT |
@@ -59,154 +49,103 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) | |||
59 | 49 | ||
60 | #define BASED(name) name-system_call(%r13) | 50 | #define BASED(name) name-system_call(%r13) |
61 | 51 | ||
62 | .macro SPP newpp | ||
63 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | ||
64 | tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP | ||
65 | jz .+8 | ||
66 | .insn s,0xb2800000,\newpp | ||
67 | #endif | ||
68 | .endm | ||
69 | |||
70 | .macro HANDLE_SIE_INTERCEPT | ||
71 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | ||
72 | tm __TI_flags+6(%r12),_TIF_SIE>>8 | ||
73 | jz 0f | ||
74 | SPP __LC_CMF_HPP # set host id | ||
75 | clc SP_PSW+8(8,%r15),BASED(.Lsie_loop) | ||
76 | jl 0f | ||
77 | clc SP_PSW+8(8,%r15),BASED(.Lsie_done) | ||
78 | jhe 0f | ||
79 | mvc SP_PSW+8(8,%r15),BASED(.Lsie_loop) | ||
80 | 0: | ||
81 | #endif | ||
82 | .endm | ||
83 | |||
84 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
85 | .macro TRACE_IRQS_ON | 52 | .macro TRACE_IRQS_ON |
53 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
86 | basr %r2,%r0 | 54 | basr %r2,%r0 |
87 | brasl %r14,trace_hardirqs_on_caller | 55 | brasl %r14,trace_hardirqs_on_caller |
56 | #endif | ||
88 | .endm | 57 | .endm |
89 | 58 | ||
90 | .macro TRACE_IRQS_OFF | 59 | .macro TRACE_IRQS_OFF |
60 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
91 | basr %r2,%r0 | 61 | basr %r2,%r0 |
92 | brasl %r14,trace_hardirqs_off_caller | 62 | brasl %r14,trace_hardirqs_off_caller |
93 | .endm | ||
94 | #else | ||
95 | #define TRACE_IRQS_ON | ||
96 | #define TRACE_IRQS_OFF | ||
97 | #endif | 63 | #endif |
64 | .endm | ||
98 | 65 | ||
99 | #ifdef CONFIG_LOCKDEP | ||
100 | .macro LOCKDEP_SYS_EXIT | 66 | .macro LOCKDEP_SYS_EXIT |
101 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 67 | #ifdef CONFIG_LOCKDEP |
102 | jz 0f | 68 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
69 | jz .+10 | ||
103 | brasl %r14,lockdep_sys_exit | 70 | brasl %r14,lockdep_sys_exit |
104 | 0: | ||
105 | .endm | ||
106 | #else | ||
107 | #define LOCKDEP_SYS_EXIT | ||
108 | #endif | 71 | #endif |
109 | |||
110 | .macro UPDATE_VTIME lc_from,lc_to,lc_sum | ||
111 | lg %r10,\lc_from | ||
112 | slg %r10,\lc_to | ||
113 | alg %r10,\lc_sum | ||
114 | stg %r10,\lc_sum | ||
115 | .endm | 72 | .endm |
116 | 73 | ||
117 | /* | 74 | .macro SPP newpp |
118 | * Register usage in interrupt handlers: | 75 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) |
119 | * R9 - pointer to current task structure | 76 | tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP |
120 | * R13 - pointer to literal pool | 77 | jz .+8 |
121 | * R14 - return register for function calls | 78 | .insn s,0xb2800000,\newpp |
122 | * R15 - kernel stack pointer | 79 | #endif |
123 | */ | 80 | .endm |
124 | 81 | ||
125 | .macro SAVE_ALL_SVC psworg,savearea | 82 | .macro HANDLE_SIE_INTERCEPT scratch |
126 | stmg %r11,%r15,\savearea | 83 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) |
127 | lg %r15,__LC_KERNEL_STACK # problem state -> load ksp | 84 | tm __TI_flags+6(%r12),_TIF_SIE>>8 |
128 | aghi %r15,-SP_SIZE # make room for registers & psw | 85 | jz .+42 |
129 | lg %r11,__LC_LAST_BREAK | 86 | tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP |
87 | jz .+8 | ||
88 | .insn s,0xb2800000,BASED(.Lhost_id) # set host id | ||
89 | lgr \scratch,%r9 | ||
90 | slg \scratch,BASED(.Lsie_loop) | ||
91 | clg \scratch,BASED(.Lsie_length) | ||
92 | jhe .+10 | ||
93 | lg %r9,BASED(.Lsie_loop) | ||
94 | #endif | ||
130 | .endm | 95 | .endm |
131 | 96 | ||
132 | .macro SAVE_ALL_PGM psworg,savearea | 97 | .macro CHECK_STACK stacksize,savearea |
133 | stmg %r11,%r15,\savearea | ||
134 | tm \psworg+1,0x01 # test problem state bit | ||
135 | #ifdef CONFIG_CHECK_STACK | 98 | #ifdef CONFIG_CHECK_STACK |
136 | jnz 1f | 99 | tml %r15,\stacksize - CONFIG_STACK_GUARD |
137 | tml %r15,STACK_SIZE - CONFIG_STACK_GUARD | 100 | lghi %r14,\savearea |
138 | jnz 2f | 101 | jz stack_overflow |
139 | la %r12,\psworg | ||
140 | j stack_overflow | ||
141 | #else | ||
142 | jz 2f | ||
143 | #endif | 102 | #endif |
144 | 1: lg %r15,__LC_KERNEL_STACK # problem state -> load ksp | ||
145 | 2: aghi %r15,-SP_SIZE # make room for registers & psw | ||
146 | larl %r13,system_call | ||
147 | lg %r11,__LC_LAST_BREAK | ||
148 | .endm | 103 | .endm |
149 | 104 | ||
150 | .macro SAVE_ALL_ASYNC psworg,savearea | 105 | .macro SWITCH_ASYNC savearea,stack,shift |
151 | stmg %r11,%r15,\savearea | 106 | tmhh %r8,0x0001 # interrupting from user ? |
152 | larl %r13,system_call | 107 | jnz 1f |
153 | lg %r11,__LC_LAST_BREAK | 108 | lgr %r14,%r9 |
154 | la %r12,\psworg | 109 | slg %r14,BASED(.Lcritical_start) |
155 | tm \psworg+1,0x01 # test problem state bit | 110 | clg %r14,BASED(.Lcritical_length) |
156 | jnz 1f # from user -> load kernel stack | ||
157 | clc \psworg+8(8),BASED(.Lcritical_end) | ||
158 | jhe 0f | 111 | jhe 0f |
159 | clc \psworg+8(8),BASED(.Lcritical_start) | 112 | lghi %r11,\savearea # inside critical section, do cleanup |
160 | jl 0f | ||
161 | brasl %r14,cleanup_critical | 113 | brasl %r14,cleanup_critical |
162 | tm 1(%r12),0x01 # retest problem state after cleanup | 114 | tmhh %r8,0x0001 # retest problem state after cleanup |
163 | jnz 1f | 115 | jnz 1f |
164 | 0: lg %r14,__LC_ASYNC_STACK # are we already on the async. stack ? | 116 | 0: lg %r14,\stack # are we already on the target stack? |
165 | slgr %r14,%r15 | 117 | slgr %r14,%r15 |
166 | srag %r14,%r14,STACK_SHIFT | 118 | srag %r14,%r14,\shift |
167 | #ifdef CONFIG_CHECK_STACK | ||
168 | jnz 1f | 119 | jnz 1f |
169 | tml %r15,STACK_SIZE - CONFIG_STACK_GUARD | 120 | CHECK_STACK 1<<\shift,\savearea |
170 | jnz 2f | 121 | j 2f |
171 | j stack_overflow | 122 | 1: lg %r15,\stack # load target stack |
172 | #else | 123 | 2: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
173 | jz 2f | 124 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
174 | #endif | ||
175 | 1: lg %r15,__LC_ASYNC_STACK # load async stack | ||
176 | 2: aghi %r15,-SP_SIZE # make room for registers & psw | ||
177 | .endm | ||
178 | |||
179 | .macro CREATE_STACK_FRAME savearea | ||
180 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | ||
181 | stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 | ||
182 | mvc SP_R11(40,%r15),\savearea # move %r11-%r15 to stack | ||
183 | stmg %r0,%r10,SP_R0(%r15) # store gprs %r0-%r10 to kernel stack | ||
184 | .endm | 125 | .endm |
185 | 126 | ||
186 | .macro RESTORE_ALL psworg,sync | 127 | .macro UPDATE_VTIME scratch,enter_timer |
187 | mvc \psworg(16),SP_PSW(%r15) # move user PSW to lowcore | 128 | lg \scratch,__LC_EXIT_TIMER |
188 | .if !\sync | 129 | slg \scratch,\enter_timer |
189 | ni \psworg+1,0xfd # clear wait state bit | 130 | alg \scratch,__LC_USER_TIMER |
190 | .endif | 131 | stg \scratch,__LC_USER_TIMER |
191 | lg %r14,__LC_VDSO_PER_CPU | 132 | lg \scratch,__LC_LAST_UPDATE_TIMER |
192 | lmg %r0,%r13,SP_R0(%r15) # load gprs 0-13 of user | 133 | slg \scratch,__LC_EXIT_TIMER |
193 | stpt __LC_EXIT_TIMER | 134 | alg \scratch,__LC_SYSTEM_TIMER |
194 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER | 135 | stg \scratch,__LC_SYSTEM_TIMER |
195 | lmg %r14,%r15,SP_R14(%r15) # load grps 14-15 of user | 136 | mvc __LC_LAST_UPDATE_TIMER(8),\enter_timer |
196 | lpswe \psworg # back to caller | ||
197 | .endm | 137 | .endm |
198 | 138 | ||
199 | .macro LAST_BREAK | 139 | .macro LAST_BREAK scratch |
200 | srag %r10,%r11,23 | 140 | srag \scratch,%r10,23 |
201 | jz 0f | 141 | jz .+10 |
202 | stg %r11,__TI_last_break(%r12) | 142 | stg %r10,__TI_last_break(%r12) |
203 | 0: | ||
204 | .endm | 143 | .endm |
205 | 144 | ||
206 | .macro REENABLE_IRQS | 145 | .macro REENABLE_IRQS |
207 | mvc __SF_EMPTY(1,%r15),SP_PSW(%r15) | 146 | stg %r8,__LC_RETURN_PSW |
208 | ni __SF_EMPTY(%r15),0xbf | 147 | ni __LC_RETURN_PSW,0xbf |
209 | ssm __SF_EMPTY(%r15) | 148 | ssm __LC_RETURN_PSW |
210 | .endm | 149 | .endm |
211 | 150 | ||
212 | .section .kprobes.text, "ax" | 151 | .section .kprobes.text, "ax" |
@@ -245,55 +184,66 @@ __critical_start: | |||
245 | 184 | ||
246 | ENTRY(system_call) | 185 | ENTRY(system_call) |
247 | stpt __LC_SYNC_ENTER_TIMER | 186 | stpt __LC_SYNC_ENTER_TIMER |
248 | sysc_saveall: | 187 | sysc_stmg: |
249 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 188 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC |
250 | CREATE_STACK_FRAME __LC_SAVE_AREA | 189 | lg %r10,__LC_LAST_BREAK |
251 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 190 | lg %r12,__LC_THREAD_INFO |
252 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | 191 | larl %r13,system_call |
253 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC | 192 | sysc_per: |
254 | oi __TI_flags+7(%r12),_TIF_SYSCALL | 193 | lg %r15,__LC_KERNEL_STACK |
194 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | ||
195 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs | ||
255 | sysc_vtime: | 196 | sysc_vtime: |
256 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 197 | UPDATE_VTIME %r13,__LC_SYNC_ENTER_TIMER |
257 | sysc_stime: | 198 | LAST_BREAK %r13 |
258 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 199 | stmg %r0,%r7,__PT_R0(%r11) |
259 | sysc_update: | 200 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC |
260 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 201 | mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW |
261 | LAST_BREAK | 202 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC |
262 | sysc_do_svc: | 203 | sysc_do_svc: |
263 | llgh %r7,SP_SVC_CODE+2(%r15) | 204 | oi __TI_flags+7(%r12),_TIF_SYSCALL |
264 | slag %r7,%r7,2 # shift and test for svc 0 | 205 | llgh %r8,__PT_INT_CODE+2(%r11) |
206 | slag %r8,%r8,2 # shift and test for svc 0 | ||
265 | jnz sysc_nr_ok | 207 | jnz sysc_nr_ok |
266 | # svc 0: system call number in %r1 | 208 | # svc 0: system call number in %r1 |
267 | llgfr %r1,%r1 # clear high word in r1 | 209 | llgfr %r1,%r1 # clear high word in r1 |
268 | cghi %r1,NR_syscalls | 210 | cghi %r1,NR_syscalls |
269 | jnl sysc_nr_ok | 211 | jnl sysc_nr_ok |
270 | sth %r1,SP_SVC_CODE+2(%r15) | 212 | sth %r1,__PT_INT_CODE+2(%r11) |
271 | slag %r7,%r1,2 # shift and test for svc 0 | 213 | slag %r8,%r1,2 |
272 | sysc_nr_ok: | 214 | sysc_nr_ok: |
273 | larl %r10,sys_call_table | 215 | larl %r10,sys_call_table # 64 bit system call table |
274 | #ifdef CONFIG_COMPAT | 216 | #ifdef CONFIG_COMPAT |
275 | tm __TI_flags+5(%r12),(_TIF_31BIT>>16) # running in 31 bit mode ? | 217 | tm __TI_flags+5(%r12),(_TIF_31BIT>>16) |
276 | jno sysc_noemu | 218 | jno sysc_noemu |
277 | larl %r10,sys_call_table_emu # use 31 bit emulation system calls | 219 | larl %r10,sys_call_table_emu # 31 bit system call table |
278 | sysc_noemu: | 220 | sysc_noemu: |
279 | #endif | 221 | #endif |
222 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | ||
223 | stg %r2,__PT_ORIG_GPR2(%r11) | ||
224 | stg %r7,STACK_FRAME_OVERHEAD(%r15) | ||
225 | lgf %r9,0(%r8,%r10) # get system call add. | ||
280 | tm __TI_flags+6(%r12),_TIF_TRACE >> 8 | 226 | tm __TI_flags+6(%r12),_TIF_TRACE >> 8 |
281 | mvc SP_ARGS(8,%r15),SP_R7(%r15) | ||
282 | lgf %r8,0(%r7,%r10) # load address of system call routine | ||
283 | jnz sysc_tracesys | 227 | jnz sysc_tracesys |
284 | basr %r14,%r8 # call sys_xxxx | 228 | basr %r14,%r9 # call sys_xxxx |
285 | stg %r2,SP_R2(%r15) # store return value (change R2 on stack) | 229 | stg %r2,__PT_R2(%r11) # store return value |
286 | 230 | ||
287 | sysc_return: | 231 | sysc_return: |
288 | LOCKDEP_SYS_EXIT | 232 | LOCKDEP_SYS_EXIT |
289 | sysc_tif: | 233 | sysc_tif: |
290 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 234 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
291 | jno sysc_restore | 235 | jno sysc_restore |
292 | tm __TI_flags+7(%r12),_TIF_WORK_SVC | 236 | tm __TI_flags+7(%r12),_TIF_WORK_SVC |
293 | jnz sysc_work # there is work to do (signals etc.) | 237 | jnz sysc_work # check for work |
294 | ni __TI_flags+7(%r12),255-_TIF_SYSCALL | 238 | ni __TI_flags+7(%r12),255-_TIF_SYSCALL |
295 | sysc_restore: | 239 | sysc_restore: |
296 | RESTORE_ALL __LC_RETURN_PSW,1 | 240 | lg %r14,__LC_VDSO_PER_CPU |
241 | lmg %r0,%r10,__PT_R0(%r11) | ||
242 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) | ||
243 | stpt __LC_EXIT_TIMER | ||
244 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER | ||
245 | lmg %r11,%r15,__PT_R11(%r11) | ||
246 | lpswe __LC_RETURN_PSW | ||
297 | sysc_done: | 247 | sysc_done: |
298 | 248 | ||
299 | # | 249 | # |
@@ -317,7 +267,7 @@ sysc_work: | |||
317 | # | 267 | # |
318 | sysc_reschedule: | 268 | sysc_reschedule: |
319 | larl %r14,sysc_return | 269 | larl %r14,sysc_return |
320 | jg schedule # return point is sysc_return | 270 | jg schedule |
321 | 271 | ||
322 | # | 272 | # |
323 | # _TIF_MCCK_PENDING is set, call handler | 273 | # _TIF_MCCK_PENDING is set, call handler |
@@ -331,33 +281,33 @@ sysc_mcck_pending: | |||
331 | # | 281 | # |
332 | sysc_sigpending: | 282 | sysc_sigpending: |
333 | ni __TI_flags+7(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP | 283 | ni __TI_flags+7(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP |
334 | la %r2,SP_PTREGS(%r15) # load pt_regs | 284 | lgr %r2,%r11 # pass pointer to pt_regs |
335 | brasl %r14,do_signal # call do_signal | 285 | brasl %r14,do_signal |
336 | tm __TI_flags+7(%r12),_TIF_SYSCALL | 286 | tm __TI_flags+7(%r12),_TIF_SYSCALL |
337 | jno sysc_return | 287 | jno sysc_return |
338 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments | 288 | lmg %r2,%r7,__PT_R2(%r11) # load svc arguments |
339 | lghi %r7,0 # svc 0 returns -ENOSYS | 289 | lghi %r8,0 # svc 0 returns -ENOSYS |
340 | lh %r1,SP_SVC_CODE+2(%r15) # load new svc number | 290 | lh %r1,__PT_INT_CODE+2(%r11) # load new svc number |
341 | cghi %r1,NR_syscalls | 291 | cghi %r1,NR_syscalls |
342 | jnl sysc_nr_ok # invalid svc number -> do svc 0 | 292 | jnl sysc_nr_ok # invalid svc number -> do svc 0 |
343 | slag %r7,%r1,2 | 293 | slag %r8,%r1,2 |
344 | j sysc_nr_ok # restart svc | 294 | j sysc_nr_ok # restart svc |
345 | 295 | ||
346 | # | 296 | # |
347 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | 297 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume |
348 | # | 298 | # |
349 | sysc_notify_resume: | 299 | sysc_notify_resume: |
350 | la %r2,SP_PTREGS(%r15) # load pt_regs | 300 | lgr %r2,%r11 # pass pointer to pt_regs |
351 | larl %r14,sysc_return | 301 | larl %r14,sysc_return |
352 | jg do_notify_resume # call do_notify_resume | 302 | jg do_notify_resume |
353 | 303 | ||
354 | # | 304 | # |
355 | # _TIF_PER_TRAP is set, call do_per_trap | 305 | # _TIF_PER_TRAP is set, call do_per_trap |
356 | # | 306 | # |
357 | sysc_singlestep: | 307 | sysc_singlestep: |
358 | ni __TI_flags+7(%r12),255-(_TIF_SYSCALL | _TIF_PER_TRAP) | 308 | ni __TI_flags+7(%r12),255-(_TIF_SYSCALL | _TIF_PER_TRAP) |
359 | la %r2,SP_PTREGS(%r15) # address of register-save area | 309 | lgr %r2,%r11 # pass pointer to pt_regs |
360 | larl %r14,sysc_return # load adr. of system return | 310 | larl %r14,sysc_return |
361 | jg do_per_trap | 311 | jg do_per_trap |
362 | 312 | ||
363 | # | 313 | # |
@@ -365,41 +315,41 @@ sysc_singlestep: | |||
365 | # and after the system call | 315 | # and after the system call |
366 | # | 316 | # |
367 | sysc_tracesys: | 317 | sysc_tracesys: |
368 | la %r2,SP_PTREGS(%r15) # load pt_regs | 318 | lgr %r2,%r11 # pass pointer to pt_regs |
369 | la %r3,0 | 319 | la %r3,0 |
370 | llgh %r0,SP_SVC_CODE+2(%r15) | 320 | llgh %r0,__PT_INT_CODE+2(%r11) |
371 | stg %r0,SP_R2(%r15) | 321 | stg %r0,__PT_R2(%r11) |
372 | brasl %r14,do_syscall_trace_enter | 322 | brasl %r14,do_syscall_trace_enter |
373 | lghi %r0,NR_syscalls | 323 | lghi %r0,NR_syscalls |
374 | clgr %r0,%r2 | 324 | clgr %r0,%r2 |
375 | jnh sysc_tracenogo | 325 | jnh sysc_tracenogo |
376 | sllg %r7,%r2,2 # svc number *4 | 326 | sllg %r8,%r2,2 |
377 | lgf %r8,0(%r7,%r10) | 327 | lgf %r9,0(%r8,%r10) |
378 | sysc_tracego: | 328 | sysc_tracego: |
379 | lmg %r3,%r6,SP_R3(%r15) | 329 | lmg %r3,%r7,__PT_R3(%r11) |
380 | mvc SP_ARGS(8,%r15),SP_R7(%r15) | 330 | stg %r7,STACK_FRAME_OVERHEAD(%r15) |
381 | lg %r2,SP_ORIG_R2(%r15) | 331 | lg %r2,__PT_ORIG_GPR2(%r11) |
382 | basr %r14,%r8 # call sys_xxx | 332 | basr %r14,%r9 # call sys_xxx |
383 | stg %r2,SP_R2(%r15) # store return value | 333 | stg %r2,__PT_R2(%r11) # store return value |
384 | sysc_tracenogo: | 334 | sysc_tracenogo: |
385 | tm __TI_flags+6(%r12),_TIF_TRACE >> 8 | 335 | tm __TI_flags+6(%r12),_TIF_TRACE >> 8 |
386 | jz sysc_return | 336 | jz sysc_return |
387 | la %r2,SP_PTREGS(%r15) # load pt_regs | 337 | lgr %r2,%r11 # pass pointer to pt_regs |
388 | larl %r14,sysc_return # return point is sysc_return | 338 | larl %r14,sysc_return |
389 | jg do_syscall_trace_exit | 339 | jg do_syscall_trace_exit |
390 | 340 | ||
391 | # | 341 | # |
392 | # a new process exits the kernel with ret_from_fork | 342 | # a new process exits the kernel with ret_from_fork |
393 | # | 343 | # |
394 | ENTRY(ret_from_fork) | 344 | ENTRY(ret_from_fork) |
395 | lg %r13,__LC_SVC_NEW_PSW+8 | 345 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
396 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 346 | lg %r12,__LC_THREAD_INFO |
397 | tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? | 347 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? |
398 | jo 0f | 348 | jo 0f |
399 | stg %r15,SP_R15(%r15) # store stack pointer for new kthread | 349 | stg %r15,__PT_R15(%r11) # store stack pointer for new kthread |
400 | 0: brasl %r14,schedule_tail | 350 | 0: brasl %r14,schedule_tail |
401 | TRACE_IRQS_ON | 351 | TRACE_IRQS_ON |
402 | stosm 24(%r15),0x03 # reenable interrupts | 352 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
403 | j sysc_tracenogo | 353 | j sysc_tracenogo |
404 | 354 | ||
405 | # | 355 | # |
@@ -409,26 +359,26 @@ ENTRY(ret_from_fork) | |||
409 | ENTRY(kernel_execve) | 359 | ENTRY(kernel_execve) |
410 | stmg %r12,%r15,96(%r15) | 360 | stmg %r12,%r15,96(%r15) |
411 | lgr %r14,%r15 | 361 | lgr %r14,%r15 |
412 | aghi %r15,-SP_SIZE | 362 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
413 | stg %r14,__SF_BACKCHAIN(%r15) | 363 | stg %r14,__SF_BACKCHAIN(%r15) |
414 | la %r12,SP_PTREGS(%r15) | 364 | la %r12,STACK_FRAME_OVERHEAD(%r15) |
415 | xc 0(__PT_SIZE,%r12),0(%r12) | 365 | xc 0(__PT_SIZE,%r12),0(%r12) |
416 | lgr %r5,%r12 | 366 | lgr %r5,%r12 |
417 | brasl %r14,do_execve | 367 | brasl %r14,do_execve |
418 | ltgfr %r2,%r2 | 368 | ltgfr %r2,%r2 |
419 | je 0f | 369 | je 0f |
420 | aghi %r15,SP_SIZE | 370 | aghi %r15,(STACK_FRAME_OVERHEAD + __PT_SIZE) |
421 | lmg %r12,%r15,96(%r15) | 371 | lmg %r12,%r15,96(%r15) |
422 | br %r14 | 372 | br %r14 |
423 | # execve succeeded. | 373 | # execve succeeded. |
424 | 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts | 374 | 0: ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
425 | lg %r15,__LC_KERNEL_STACK # load ksp | 375 | lg %r15,__LC_KERNEL_STACK # load ksp |
426 | aghi %r15,-SP_SIZE # make room for registers & psw | 376 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
427 | lg %r13,__LC_SVC_NEW_PSW+8 | 377 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
428 | mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs | 378 | mvc 0(__PT_SIZE,%r11),0(%r12) # copy pt_regs |
429 | lg %r12,__LC_THREAD_INFO | 379 | lg %r12,__LC_THREAD_INFO |
430 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 380 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
431 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 381 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
432 | brasl %r14,execve_tail | 382 | brasl %r14,execve_tail |
433 | j sysc_return | 383 | j sysc_return |
434 | 384 | ||
@@ -437,127 +387,72 @@ ENTRY(kernel_execve) | |||
437 | */ | 387 | */ |
438 | 388 | ||
439 | ENTRY(pgm_check_handler) | 389 | ENTRY(pgm_check_handler) |
440 | /* | ||
441 | * First we need to check for a special case: | ||
442 | * Single stepping an instruction that disables the PER event mask will | ||
443 | * cause a PER event AFTER the mask has been set. Example: SVC or LPSW. | ||
444 | * For a single stepped SVC the program check handler gets control after | ||
445 | * the SVC new PSW has been loaded. But we want to execute the SVC first and | ||
446 | * then handle the PER event. Therefore we update the SVC old PSW to point | ||
447 | * to the pgm_check_handler and branch to the SVC handler after we checked | ||
448 | * if we have to load the kernel stack register. | ||
449 | * For every other possible cause for PER event without the PER mask set | ||
450 | * we just ignore the PER event (FIXME: is there anything we have to do | ||
451 | * for LPSW?). | ||
452 | */ | ||
453 | stpt __LC_SYNC_ENTER_TIMER | 390 | stpt __LC_SYNC_ENTER_TIMER |
454 | tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception | 391 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC |
455 | jnz pgm_per # got per exception -> special case | 392 | lg %r10,__LC_LAST_BREAK |
456 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA | 393 | lg %r12,__LC_THREAD_INFO |
457 | CREATE_STACK_FRAME __LC_SAVE_AREA | 394 | larl %r13,system_call |
458 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW | 395 | lmg %r8,%r9,__LC_PGM_OLD_PSW |
459 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 396 | HANDLE_SIE_INTERCEPT %r14 |
460 | HANDLE_SIE_INTERCEPT | 397 | tmhh %r8,0x0001 # test problem state bit |
461 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 398 | jnz 1f # -> fault in user space |
462 | jz pgm_no_vtime | 399 | tmhh %r8,0x4000 # PER bit set in old PSW ? |
463 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 400 | jnz 0f # -> enabled, can't be a double fault |
464 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 401 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
465 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 402 | jnz pgm_svcper # -> single stepped svc |
466 | LAST_BREAK | 403 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC |
467 | pgm_no_vtime: | 404 | j 2f |
468 | stg %r11,SP_ARGS(%r15) | 405 | 1: UPDATE_VTIME %r14,__LC_SYNC_ENTER_TIMER |
469 | lgf %r3,__LC_PGM_ILC # load program interruption code | 406 | LAST_BREAK %r14 |
470 | lg %r4,__LC_TRANS_EXC_CODE | 407 | lg %r15,__LC_KERNEL_STACK |
471 | REENABLE_IRQS | 408 | 2: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
472 | lghi %r8,0x7f | 409 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
473 | ngr %r8,%r3 | 410 | stmg %r0,%r7,__PT_R0(%r11) |
474 | sll %r8,3 | 411 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC |
475 | larl %r1,pgm_check_table | 412 | stmg %r8,%r9,__PT_PSW(%r11) |
476 | lg %r1,0(%r8,%r1) # load address of handler routine | 413 | mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC |
477 | la %r2,SP_PTREGS(%r15) # address of register-save area | 414 | mvc __PT_INT_PARM_LONG(8,%r11),__LC_TRANS_EXC_CODE |
478 | basr %r14,%r1 # branch to interrupt-handler | 415 | stg %r10,__PT_ARGS(%r11) |
479 | pgm_exit: | 416 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
480 | j sysc_return | 417 | jz 0f |
481 | |||
482 | # | ||
483 | # handle per exception | ||
484 | # | ||
485 | pgm_per: | ||
486 | tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on | ||
487 | jnz pgm_per_std # ok, normal per event from user space | ||
488 | # ok its one of the special cases, now we need to find out which one | ||
489 | clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW | ||
490 | je pgm_svcper | ||
491 | # no interesting special case, ignore PER event | ||
492 | lpswe __LC_PGM_OLD_PSW | ||
493 | |||
494 | # | ||
495 | # Normal per exception | ||
496 | # | ||
497 | pgm_per_std: | ||
498 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA | ||
499 | CREATE_STACK_FRAME __LC_SAVE_AREA | ||
500 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW | ||
501 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
502 | HANDLE_SIE_INTERCEPT | ||
503 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | ||
504 | jz pgm_no_vtime2 | ||
505 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | ||
506 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | ||
507 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | ||
508 | LAST_BREAK | ||
509 | pgm_no_vtime2: | ||
510 | lg %r1,__TI_task(%r12) | 418 | lg %r1,__TI_task(%r12) |
511 | tm SP_PSW+1(%r15),0x01 # kernel per event ? | 419 | tmhh %r8,0x0001 # kernel per event ? |
512 | jz kernel_per | 420 | jz pgm_kprobe |
513 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE | 421 | oi __TI_flags+7(%r12),_TIF_PER_TRAP |
514 | mvc __THREAD_per_address(8,%r1),__LC_PER_ADDRESS | 422 | mvc __THREAD_per_address(8,%r1),__LC_PER_ADDRESS |
423 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE | ||
515 | mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID | 424 | mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID |
516 | oi __TI_flags+7(%r12),_TIF_PER_TRAP # set TIF_PER_TRAP | 425 | 0: REENABLE_IRQS |
517 | lgf %r3,__LC_PGM_ILC # load program interruption code | 426 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
518 | lg %r4,__LC_TRANS_EXC_CODE | ||
519 | REENABLE_IRQS | ||
520 | lghi %r8,0x7f | ||
521 | ngr %r8,%r3 # clear per-event-bit and ilc | ||
522 | je pgm_exit2 | ||
523 | sll %r8,3 | ||
524 | larl %r1,pgm_check_table | 427 | larl %r1,pgm_check_table |
525 | lg %r1,0(%r8,%r1) # load address of handler routine | 428 | llgh %r10,__PT_INT_CODE+2(%r11) |
526 | la %r2,SP_PTREGS(%r15) # address of register-save area | 429 | nill %r10,0x007f |
430 | sll %r10,3 | ||
431 | je sysc_return | ||
432 | lg %r1,0(%r10,%r1) # load address of handler routine | ||
433 | lgr %r2,%r11 # pass pointer to pt_regs | ||
527 | basr %r14,%r1 # branch to interrupt-handler | 434 | basr %r14,%r1 # branch to interrupt-handler |
528 | pgm_exit2: | ||
529 | j sysc_return | 435 | j sysc_return |
530 | 436 | ||
531 | # | 437 | # |
532 | # it was a single stepped SVC that is causing all the trouble | 438 | # PER event in supervisor state, must be kprobes |
533 | # | 439 | # |
534 | pgm_svcper: | 440 | pgm_kprobe: |
535 | SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 441 | REENABLE_IRQS |
536 | CREATE_STACK_FRAME __LC_SAVE_AREA | 442 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
537 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 443 | lgr %r2,%r11 # pass pointer to pt_regs |
538 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | 444 | brasl %r14,do_per_trap |
539 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC | 445 | j sysc_return |
540 | oi __TI_flags+7(%r12),(_TIF_SYSCALL | _TIF_PER_TRAP) | ||
541 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | ||
542 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | ||
543 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | ||
544 | LAST_BREAK | ||
545 | lg %r8,__TI_task(%r12) | ||
546 | mvc __THREAD_per_cause(2,%r8),__LC_PER_CAUSE | ||
547 | mvc __THREAD_per_address(8,%r8),__LC_PER_ADDRESS | ||
548 | mvc __THREAD_per_paid(1,%r8),__LC_PER_PAID | ||
549 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | ||
550 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments | ||
551 | j sysc_do_svc | ||
552 | 446 | ||
553 | # | 447 | # |
554 | # per was called from kernel, must be kprobes | 448 | # single stepped system call |
555 | # | 449 | # |
556 | kernel_per: | 450 | pgm_svcper: |
557 | REENABLE_IRQS | 451 | oi __TI_flags+7(%r12),_TIF_PER_TRAP |
558 | la %r2,SP_PTREGS(%r15) # address of register-save area | 452 | mvc __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW |
559 | brasl %r14,do_per_trap | 453 | larl %r14,sysc_per |
560 | j pgm_exit | 454 | stg %r14,__LC_RETURN_PSW+8 |
455 | lpswe __LC_RETURN_PSW # branch to sysc_per and enable irqs | ||
561 | 456 | ||
562 | /* | 457 | /* |
563 | * IO interrupt handler routine | 458 | * IO interrupt handler routine |
@@ -565,21 +460,25 @@ kernel_per: | |||
565 | ENTRY(io_int_handler) | 460 | ENTRY(io_int_handler) |
566 | stck __LC_INT_CLOCK | 461 | stck __LC_INT_CLOCK |
567 | stpt __LC_ASYNC_ENTER_TIMER | 462 | stpt __LC_ASYNC_ENTER_TIMER |
568 | SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+40 | 463 | stmg %r8,%r15,__LC_SAVE_AREA_ASYNC |
569 | CREATE_STACK_FRAME __LC_SAVE_AREA+40 | 464 | lg %r10,__LC_LAST_BREAK |
570 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack | 465 | lg %r12,__LC_THREAD_INFO |
571 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 466 | larl %r13,system_call |
572 | HANDLE_SIE_INTERCEPT | 467 | lmg %r8,%r9,__LC_IO_OLD_PSW |
573 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 468 | HANDLE_SIE_INTERCEPT %r14 |
574 | jz io_no_vtime | 469 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
575 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 470 | tmhh %r8,0x0001 # interrupting from user? |
576 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 471 | jz io_skip |
577 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 472 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER |
578 | LAST_BREAK | 473 | LAST_BREAK %r14 |
579 | io_no_vtime: | 474 | io_skip: |
475 | stmg %r0,%r7,__PT_R0(%r11) | ||
476 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC | ||
477 | stmg %r8,%r9,__PT_PSW(%r11) | ||
580 | TRACE_IRQS_OFF | 478 | TRACE_IRQS_OFF |
581 | la %r2,SP_PTREGS(%r15) # address of register-save area | 479 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
582 | brasl %r14,do_IRQ # call standard irq handler | 480 | lgr %r2,%r11 # pass pointer to pt_regs |
481 | brasl %r14,do_IRQ | ||
583 | io_return: | 482 | io_return: |
584 | LOCKDEP_SYS_EXIT | 483 | LOCKDEP_SYS_EXIT |
585 | TRACE_IRQS_ON | 484 | TRACE_IRQS_ON |
@@ -587,7 +486,14 @@ io_tif: | |||
587 | tm __TI_flags+7(%r12),_TIF_WORK_INT | 486 | tm __TI_flags+7(%r12),_TIF_WORK_INT |
588 | jnz io_work # there is work to do (signals etc.) | 487 | jnz io_work # there is work to do (signals etc.) |
589 | io_restore: | 488 | io_restore: |
590 | RESTORE_ALL __LC_RETURN_PSW,0 | 489 | lg %r14,__LC_VDSO_PER_CPU |
490 | lmg %r0,%r10,__PT_R0(%r11) | ||
491 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) | ||
492 | ni __LC_RETURN_PSW+1,0xfd # clear wait state bit | ||
493 | stpt __LC_EXIT_TIMER | ||
494 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER | ||
495 | lmg %r11,%r15,__PT_R11(%r11) | ||
496 | lpswe __LC_RETURN_PSW | ||
591 | io_done: | 497 | io_done: |
592 | 498 | ||
593 | # | 499 | # |
@@ -600,7 +506,7 @@ io_done: | |||
600 | # Before any work can be done, a switch to the kernel stack is required. | 506 | # Before any work can be done, a switch to the kernel stack is required. |
601 | # | 507 | # |
602 | io_work: | 508 | io_work: |
603 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 509 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
604 | jo io_work_user # yes -> do resched & signal | 510 | jo io_work_user # yes -> do resched & signal |
605 | #ifdef CONFIG_PREEMPT | 511 | #ifdef CONFIG_PREEMPT |
606 | # check for preemptive scheduling | 512 | # check for preemptive scheduling |
@@ -609,10 +515,11 @@ io_work: | |||
609 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED | 515 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED |
610 | jno io_restore | 516 | jno io_restore |
611 | # switch to kernel stack | 517 | # switch to kernel stack |
612 | lg %r1,SP_R15(%r15) | 518 | lg %r1,__PT_R15(%r11) |
613 | aghi %r1,-SP_SIZE | 519 | aghi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
614 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 520 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
615 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 521 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) |
522 | la %r11,STACK_FRAME_OVERHEAD(%r1) | ||
616 | lgr %r15,%r1 | 523 | lgr %r15,%r1 |
617 | # TRACE_IRQS_ON already done at io_return, call | 524 | # TRACE_IRQS_ON already done at io_return, call |
618 | # TRACE_IRQS_OFF to keep things symmetrical | 525 | # TRACE_IRQS_OFF to keep things symmetrical |
@@ -628,9 +535,10 @@ io_work: | |||
628 | # | 535 | # |
629 | io_work_user: | 536 | io_work_user: |
630 | lg %r1,__LC_KERNEL_STACK | 537 | lg %r1,__LC_KERNEL_STACK |
631 | aghi %r1,-SP_SIZE | 538 | aghi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
632 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 539 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
633 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 540 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) |
541 | la %r11,STACK_FRAME_OVERHEAD(%r1) | ||
634 | lgr %r15,%r1 | 542 | lgr %r15,%r1 |
635 | 543 | ||
636 | # | 544 | # |
@@ -663,9 +571,9 @@ io_mcck_pending: | |||
663 | # | 571 | # |
664 | io_reschedule: | 572 | io_reschedule: |
665 | # TRACE_IRQS_ON already done at io_return | 573 | # TRACE_IRQS_ON already done at io_return |
666 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 574 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
667 | brasl %r14,schedule # call scheduler | 575 | brasl %r14,schedule # call scheduler |
668 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 576 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
669 | TRACE_IRQS_OFF | 577 | TRACE_IRQS_OFF |
670 | j io_return | 578 | j io_return |
671 | 579 | ||
@@ -674,10 +582,10 @@ io_reschedule: | |||
674 | # | 582 | # |
675 | io_sigpending: | 583 | io_sigpending: |
676 | # TRACE_IRQS_ON already done at io_return | 584 | # TRACE_IRQS_ON already done at io_return |
677 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 585 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
678 | la %r2,SP_PTREGS(%r15) # load pt_regs | 586 | lgr %r2,%r11 # pass pointer to pt_regs |
679 | brasl %r14,do_signal # call do_signal | 587 | brasl %r14,do_signal |
680 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 588 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
681 | TRACE_IRQS_OFF | 589 | TRACE_IRQS_OFF |
682 | j io_return | 590 | j io_return |
683 | 591 | ||
@@ -686,10 +594,10 @@ io_sigpending: | |||
686 | # | 594 | # |
687 | io_notify_resume: | 595 | io_notify_resume: |
688 | # TRACE_IRQS_ON already done at io_return | 596 | # TRACE_IRQS_ON already done at io_return |
689 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 597 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
690 | la %r2,SP_PTREGS(%r15) # load pt_regs | 598 | lgr %r2,%r11 # pass pointer to pt_regs |
691 | brasl %r14,do_notify_resume # call do_notify_resume | 599 | brasl %r14,do_notify_resume |
692 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 600 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
693 | TRACE_IRQS_OFF | 601 | TRACE_IRQS_OFF |
694 | j io_return | 602 | j io_return |
695 | 603 | ||
@@ -699,21 +607,24 @@ io_notify_resume: | |||
699 | ENTRY(ext_int_handler) | 607 | ENTRY(ext_int_handler) |
700 | stck __LC_INT_CLOCK | 608 | stck __LC_INT_CLOCK |
701 | stpt __LC_ASYNC_ENTER_TIMER | 609 | stpt __LC_ASYNC_ENTER_TIMER |
702 | SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+40 | 610 | stmg %r8,%r15,__LC_SAVE_AREA_ASYNC |
703 | CREATE_STACK_FRAME __LC_SAVE_AREA+40 | 611 | lg %r10,__LC_LAST_BREAK |
704 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack | 612 | lg %r12,__LC_THREAD_INFO |
705 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 613 | larl %r13,system_call |
706 | HANDLE_SIE_INTERCEPT | 614 | lmg %r8,%r9,__LC_EXT_OLD_PSW |
707 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 615 | HANDLE_SIE_INTERCEPT %r14 |
708 | jz ext_no_vtime | 616 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
709 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 617 | tmhh %r8,0x0001 # interrupting from user ? |
710 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 618 | jz ext_skip |
711 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 619 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER |
712 | LAST_BREAK | 620 | LAST_BREAK %r14 |
713 | ext_no_vtime: | 621 | ext_skip: |
622 | stmg %r0,%r7,__PT_R0(%r11) | ||
623 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC | ||
624 | stmg %r8,%r9,__PT_PSW(%r11) | ||
714 | TRACE_IRQS_OFF | 625 | TRACE_IRQS_OFF |
715 | lghi %r1,4096 | 626 | lghi %r1,4096 |
716 | la %r2,SP_PTREGS(%r15) # address of register-save area | 627 | lgr %r2,%r11 # pass pointer to pt_regs |
717 | llgf %r3,__LC_CPU_ADDRESS # get cpu address + interruption code | 628 | llgf %r3,__LC_CPU_ADDRESS # get cpu address + interruption code |
718 | llgf %r4,__LC_EXT_PARAMS # get external parameter | 629 | llgf %r4,__LC_EXT_PARAMS # get external parameter |
719 | lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter | 630 | lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter |
@@ -730,81 +641,77 @@ ENTRY(mcck_int_handler) | |||
730 | la %r1,4095 # revalidate r1 | 641 | la %r1,4095 # revalidate r1 |
731 | spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer | 642 | spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer |
732 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs | 643 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs |
733 | stmg %r11,%r15,__LC_SAVE_AREA+80 | 644 | lg %r10,__LC_LAST_BREAK |
645 | lg %r12,__LC_THREAD_INFO | ||
734 | larl %r13,system_call | 646 | larl %r13,system_call |
735 | lg %r11,__LC_LAST_BREAK | 647 | lmg %r8,%r9,__LC_MCK_OLD_PSW |
736 | la %r12,__LC_MCK_OLD_PSW | 648 | HANDLE_SIE_INTERCEPT %r14 |
737 | tm __LC_MCCK_CODE,0x80 # system damage? | 649 | tm __LC_MCCK_CODE,0x80 # system damage? |
738 | jo mcck_int_main # yes -> rest of mcck code invalid | 650 | jo mcck_panic # yes -> rest of mcck code invalid |
739 | la %r14,4095 | 651 | lghi %r14,__LC_CPU_TIMER_SAVE_AREA |
740 | mvc __LC_MCCK_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14) | 652 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
741 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | 653 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? |
742 | jo 1f | 654 | jo 3f |
743 | la %r14,__LC_SYNC_ENTER_TIMER | 655 | la %r14,__LC_SYNC_ENTER_TIMER |
744 | clc 0(8,%r14),__LC_ASYNC_ENTER_TIMER | 656 | clc 0(8,%r14),__LC_ASYNC_ENTER_TIMER |
745 | jl 0f | 657 | jl 0f |
746 | la %r14,__LC_ASYNC_ENTER_TIMER | 658 | la %r14,__LC_ASYNC_ENTER_TIMER |
747 | 0: clc 0(8,%r14),__LC_EXIT_TIMER | 659 | 0: clc 0(8,%r14),__LC_EXIT_TIMER |
748 | jl 0f | 660 | jl 1f |
749 | la %r14,__LC_EXIT_TIMER | 661 | la %r14,__LC_EXIT_TIMER |
750 | 0: clc 0(8,%r14),__LC_LAST_UPDATE_TIMER | 662 | 1: clc 0(8,%r14),__LC_LAST_UPDATE_TIMER |
751 | jl 0f | 663 | jl 2f |
752 | la %r14,__LC_LAST_UPDATE_TIMER | 664 | la %r14,__LC_LAST_UPDATE_TIMER |
753 | 0: spt 0(%r14) | 665 | 2: spt 0(%r14) |
754 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 666 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
755 | 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 667 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? |
756 | jno mcck_int_main # no -> skip cleanup critical | 668 | jno mcck_panic # no -> skip cleanup critical |
757 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit | 669 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_PANIC_STACK,PAGE_SHIFT |
758 | jnz mcck_int_main # from user -> load kernel stack | 670 | tm %r8,0x0001 # interrupting from user ? |
759 | clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end) | 671 | jz mcck_skip |
760 | jhe mcck_int_main | 672 | UPDATE_VTIME %r14,__LC_MCCK_ENTER_TIMER |
761 | clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start) | 673 | LAST_BREAK %r14 |
762 | jl mcck_int_main | 674 | mcck_skip: |
763 | brasl %r14,cleanup_critical | 675 | lghi %r14,__LC_GPREGS_SAVE_AREA |
764 | mcck_int_main: | 676 | mvc __PT_R0(128,%r11),0(%r14) |
765 | lg %r14,__LC_PANIC_STACK # are we already on the panic stack? | 677 | stmg %r8,%r9,__PT_PSW(%r11) |
766 | slgr %r14,%r15 | 678 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
767 | srag %r14,%r14,PAGE_SHIFT | 679 | lgr %r2,%r11 # pass pointer to pt_regs |
768 | jz 0f | ||
769 | lg %r15,__LC_PANIC_STACK # load panic stack | ||
770 | 0: aghi %r15,-SP_SIZE # make room for registers & psw | ||
771 | CREATE_STACK_FRAME __LC_SAVE_AREA+80 | ||
772 | mvc SP_PSW(16,%r15),0(%r12) | ||
773 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
774 | tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? | ||
775 | jno mcck_no_vtime # no -> no timer update | ||
776 | HANDLE_SIE_INTERCEPT | ||
777 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | ||
778 | jz mcck_no_vtime | ||
779 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER | ||
780 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | ||
781 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
782 | LAST_BREAK | ||
783 | mcck_no_vtime: | ||
784 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
785 | brasl %r14,s390_do_machine_check | 680 | brasl %r14,s390_do_machine_check |
786 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 681 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
787 | jno mcck_return | 682 | jno mcck_return |
788 | lg %r1,__LC_KERNEL_STACK # switch to kernel stack | 683 | lg %r1,__LC_KERNEL_STACK # switch to kernel stack |
789 | aghi %r1,-SP_SIZE | 684 | aghi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
790 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 685 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
791 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 686 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) |
687 | la %r11,STACK_FRAME_OVERHEAD(%r1) | ||
792 | lgr %r15,%r1 | 688 | lgr %r15,%r1 |
793 | stosm __SF_EMPTY(%r15),0x04 # turn dat on | 689 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off |
794 | tm __TI_flags+7(%r12),_TIF_MCCK_PENDING | 690 | tm __TI_flags+7(%r12),_TIF_MCCK_PENDING |
795 | jno mcck_return | 691 | jno mcck_return |
796 | TRACE_IRQS_OFF | 692 | TRACE_IRQS_OFF |
797 | brasl %r14,s390_handle_mcck | 693 | brasl %r14,s390_handle_mcck |
798 | TRACE_IRQS_ON | 694 | TRACE_IRQS_ON |
799 | mcck_return: | 695 | mcck_return: |
800 | mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW | 696 | lg %r14,__LC_VDSO_PER_CPU |
697 | lmg %r0,%r10,__PT_R0(%r11) | ||
698 | mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW | ||
801 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit | 699 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit |
802 | lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 | ||
803 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? | 700 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? |
804 | jno 0f | 701 | jno 0f |
805 | stpt __LC_EXIT_TIMER | 702 | stpt __LC_EXIT_TIMER |
806 | 0: lpswe __LC_RETURN_MCCK_PSW # back to caller | 703 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER |
807 | mcck_done: | 704 | 0: lmg %r11,%r15,__PT_R11(%r11) |
705 | lpswe __LC_RETURN_MCCK_PSW | ||
706 | |||
707 | mcck_panic: | ||
708 | lg %r14,__LC_PANIC_STACK | ||
709 | slgr %r14,%r15 | ||
710 | srag %r14,%r14,PAGE_SHIFT | ||
711 | jz 0f | ||
712 | lg %r15,__LC_PANIC_STACK | ||
713 | 0: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | ||
714 | j mcck_skip | ||
808 | 715 | ||
809 | /* | 716 | /* |
810 | * Restart interruption handler, kick starter for additional CPUs | 717 | * Restart interruption handler, kick starter for additional CPUs |
@@ -818,17 +725,18 @@ restart_base: | |||
818 | stck __LC_LAST_UPDATE_CLOCK | 725 | stck __LC_LAST_UPDATE_CLOCK |
819 | mvc __LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1) | 726 | mvc __LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1) |
820 | mvc __LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1) | 727 | mvc __LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1) |
821 | lg %r15,__LC_SAVE_AREA+120 # load ksp | 728 | lghi %r10,__LC_GPREGS_SAVE_AREA |
729 | lg %r15,120(%r10) # load ksp | ||
822 | lghi %r10,__LC_CREGS_SAVE_AREA | 730 | lghi %r10,__LC_CREGS_SAVE_AREA |
823 | lctlg %c0,%c15,0(%r10) # get new ctl regs | 731 | lctlg %c0,%c15,0(%r10) # get new ctl regs |
824 | lghi %r10,__LC_AREGS_SAVE_AREA | 732 | lghi %r10,__LC_AREGS_SAVE_AREA |
825 | lam %a0,%a15,0(%r10) | 733 | lam %a0,%a15,0(%r10) |
826 | lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone | 734 | lmg %r6,%r15,__SF_GPRS(%r15)# load registers from clone |
827 | lg %r1,__LC_THREAD_INFO | 735 | lg %r1,__LC_THREAD_INFO |
828 | mvc __LC_USER_TIMER(8),__TI_user_timer(%r1) | 736 | mvc __LC_USER_TIMER(8),__TI_user_timer(%r1) |
829 | mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1) | 737 | mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1) |
830 | xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER | 738 | xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER |
831 | stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on | 739 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off |
832 | brasl %r14,start_secondary | 740 | brasl %r14,start_secondary |
833 | .align 8 | 741 | .align 8 |
834 | restart_vtime: | 742 | restart_vtime: |
@@ -852,16 +760,16 @@ restart_go: | |||
852 | # PSW restart interrupt handler | 760 | # PSW restart interrupt handler |
853 | # | 761 | # |
854 | ENTRY(psw_restart_int_handler) | 762 | ENTRY(psw_restart_int_handler) |
855 | stg %r15,__LC_SAVE_AREA+120(%r0) # save r15 | 763 | stg %r15,__LC_SAVE_AREA_RESTART |
856 | larl %r15,restart_stack # load restart stack | 764 | larl %r15,restart_stack # load restart stack |
857 | lg %r15,0(%r15) | 765 | lg %r15,0(%r15) |
858 | aghi %r15,-SP_SIZE # make room for pt_regs | 766 | aghi %r15,-__PT_SIZE # create pt_regs on stack |
859 | stmg %r0,%r14,SP_R0(%r15) # store gprs %r0-%r14 to stack | 767 | stmg %r0,%r14,__PT_R0(%r15) |
860 | mvc SP_R15(8,%r15),__LC_SAVE_AREA+120(%r0)# store saved %r15 to stack | 768 | mvc __PT_R15(8,%r15),__LC_SAVE_AREA_RESTART |
861 | mvc SP_PSW(16,%r15),__LC_RST_OLD_PSW(%r0)# store restart old psw | 769 | mvc __PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw |
862 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # set backchain to 0 | 770 | aghi %r15,-STACK_FRAME_OVERHEAD |
771 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | ||
863 | brasl %r14,do_restart | 772 | brasl %r14,do_restart |
864 | |||
865 | larl %r14,restart_psw_crash # load disabled wait PSW if | 773 | larl %r14,restart_psw_crash # load disabled wait PSW if |
866 | lpswe 0(%r14) # do_restart returns | 774 | lpswe 0(%r14) # do_restart returns |
867 | .align 8 | 775 | .align 8 |
@@ -877,172 +785,153 @@ restart_psw_crash: | |||
877 | * Setup a pt_regs so that show_trace can provide a good call trace. | 785 | * Setup a pt_regs so that show_trace can provide a good call trace. |
878 | */ | 786 | */ |
879 | stack_overflow: | 787 | stack_overflow: |
880 | lg %r15,__LC_PANIC_STACK # change to panic stack | 788 | lg %r11,__LC_PANIC_STACK # change to panic stack |
881 | aghi %r15,-SP_SIZE | 789 | aghi %r11,-__PT_SIZE # create pt_regs |
882 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack | 790 | stmg %r0,%r7,__PT_R0(%r11) |
883 | stmg %r0,%r10,SP_R0(%r15) # store gprs %r0-%r10 to kernel stack | 791 | stmg %r8,%r9,__PT_PSW(%r11) |
884 | la %r1,__LC_SAVE_AREA | 792 | mvc __PT_R8(64,%r11),0(%r14) |
885 | chi %r12,__LC_SVC_OLD_PSW | 793 | stg %r10,__PT_ORIG_GPR2(%r11) # store last break to orig_gpr2 |
886 | je 0f | 794 | lgr %r15,%r11 |
887 | chi %r12,__LC_PGM_OLD_PSW | 795 | aghi %r15,-STACK_FRAME_OVERHEAD |
888 | je 0f | 796 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
889 | la %r1,__LC_SAVE_AREA+40 | 797 | lgr %r2,%r11 # pass pointer to pt_regs |
890 | 0: mvc SP_R11(40,%r15),0(%r1) # move %r11-%r15 to stack | ||
891 | mvc SP_ARGS(8,%r15),__LC_LAST_BREAK | ||
892 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain | ||
893 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
894 | jg kernel_stack_overflow | 798 | jg kernel_stack_overflow |
895 | #endif | 799 | #endif |
896 | 800 | ||
897 | cleanup_table_system_call: | 801 | .align 8 |
898 | .quad system_call, sysc_do_svc | 802 | cleanup_table: |
899 | cleanup_table_sysc_tif: | 803 | .quad system_call |
900 | .quad sysc_tif, sysc_restore | 804 | .quad sysc_do_svc |
901 | cleanup_table_sysc_restore: | 805 | .quad sysc_tif |
902 | .quad sysc_restore, sysc_done | 806 | .quad sysc_restore |
903 | cleanup_table_io_tif: | 807 | .quad sysc_done |
904 | .quad io_tif, io_restore | 808 | .quad io_tif |
905 | cleanup_table_io_restore: | 809 | .quad io_restore |
906 | .quad io_restore, io_done | 810 | .quad io_done |
907 | 811 | ||
908 | cleanup_critical: | 812 | cleanup_critical: |
909 | clc 8(8,%r12),BASED(cleanup_table_system_call) | 813 | clg %r9,BASED(cleanup_table) # system_call |
910 | jl 0f | 814 | jl 0f |
911 | clc 8(8,%r12),BASED(cleanup_table_system_call+8) | 815 | clg %r9,BASED(cleanup_table+8) # sysc_do_svc |
912 | jl cleanup_system_call | 816 | jl cleanup_system_call |
913 | 0: | 817 | clg %r9,BASED(cleanup_table+16) # sysc_tif |
914 | clc 8(8,%r12),BASED(cleanup_table_sysc_tif) | ||
915 | jl 0f | 818 | jl 0f |
916 | clc 8(8,%r12),BASED(cleanup_table_sysc_tif+8) | 819 | clg %r9,BASED(cleanup_table+24) # sysc_restore |
917 | jl cleanup_sysc_tif | 820 | jl cleanup_sysc_tif |
918 | 0: | 821 | clg %r9,BASED(cleanup_table+32) # sysc_done |
919 | clc 8(8,%r12),BASED(cleanup_table_sysc_restore) | ||
920 | jl 0f | ||
921 | clc 8(8,%r12),BASED(cleanup_table_sysc_restore+8) | ||
922 | jl cleanup_sysc_restore | 822 | jl cleanup_sysc_restore |
923 | 0: | 823 | clg %r9,BASED(cleanup_table+40) # io_tif |
924 | clc 8(8,%r12),BASED(cleanup_table_io_tif) | ||
925 | jl 0f | 824 | jl 0f |
926 | clc 8(8,%r12),BASED(cleanup_table_io_tif+8) | 825 | clg %r9,BASED(cleanup_table+48) # io_restore |
927 | jl cleanup_io_tif | 826 | jl cleanup_io_tif |
928 | 0: | 827 | clg %r9,BASED(cleanup_table+56) # io_done |
929 | clc 8(8,%r12),BASED(cleanup_table_io_restore) | ||
930 | jl 0f | ||
931 | clc 8(8,%r12),BASED(cleanup_table_io_restore+8) | ||
932 | jl cleanup_io_restore | 828 | jl cleanup_io_restore |
933 | 0: | 829 | 0: br %r14 |
934 | br %r14 | 830 | |
935 | 831 | ||
936 | cleanup_system_call: | 832 | cleanup_system_call: |
937 | mvc __LC_RETURN_PSW(16),0(%r12) | 833 | # check if stpt has been executed |
938 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8) | 834 | clg %r9,BASED(cleanup_system_call_insn) |
939 | jh 0f | 835 | jh 0f |
940 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
941 | cghi %r12,__LC_MCK_OLD_PSW | ||
942 | je 0f | ||
943 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER | 836 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER |
944 | 0: cghi %r12,__LC_MCK_OLD_PSW | 837 | cghi %r11,__LC_SAVE_AREA_ASYNC |
945 | la %r12,__LC_SAVE_AREA+80 | ||
946 | je 0f | 838 | je 0f |
947 | la %r12,__LC_SAVE_AREA+40 | 839 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER |
948 | 0: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16) | 840 | 0: # check if stmg has been executed |
949 | jhe cleanup_vtime | 841 | clg %r9,BASED(cleanup_system_call_insn+8) |
950 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn) | ||
951 | jh 0f | 842 | jh 0f |
952 | mvc __LC_SAVE_AREA(40),0(%r12) | 843 | mvc __LC_SAVE_AREA_SYNC(64),0(%r11) |
953 | 0: lg %r15,__LC_KERNEL_STACK # problem state -> load ksp | 844 | 0: # check if base register setup + TIF bit load has been done |
954 | aghi %r15,-SP_SIZE # make room for registers & psw | 845 | clg %r9,BASED(cleanup_system_call_insn+16) |
955 | stg %r15,32(%r12) | 846 | jhe 0f |
956 | stg %r11,0(%r12) | 847 | # set up saved registers r10 and r12 |
957 | CREATE_STACK_FRAME __LC_SAVE_AREA | 848 | stg %r10,16(%r11) # r10 last break |
958 | mvc 8(8,%r12),__LC_THREAD_INFO | 849 | stg %r12,32(%r11) # r12 thread-info pointer |
959 | lg %r12,__LC_THREAD_INFO | 850 | 0: # check if the user time update has been done |
960 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | 851 | clg %r9,BASED(cleanup_system_call_insn+24) |
961 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC | 852 | jh 0f |
962 | oi __TI_flags+7(%r12),_TIF_SYSCALL | 853 | lg %r15,__LC_EXIT_TIMER |
963 | cleanup_vtime: | 854 | slg %r15,__LC_SYNC_ENTER_TIMER |
964 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) | 855 | alg %r15,__LC_USER_TIMER |
965 | jhe cleanup_stime | 856 | stg %r15,__LC_USER_TIMER |
966 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 857 | 0: # check if the system time update has been done |
967 | cleanup_stime: | 858 | clg %r9,BASED(cleanup_system_call_insn+32) |
968 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+32) | 859 | jh 0f |
969 | jh cleanup_update | 860 | lg %r15,__LC_LAST_UPDATE_TIMER |
970 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 861 | slg %r15,__LC_EXIT_TIMER |
971 | cleanup_update: | 862 | alg %r15,__LC_SYSTEM_TIMER |
863 | stg %r15,__LC_SYSTEM_TIMER | ||
864 | 0: # update accounting time stamp | ||
972 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 865 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
973 | srag %r12,%r11,23 | 866 | # do LAST_BREAK |
974 | lg %r12,__LC_THREAD_INFO | 867 | lg %r9,16(%r11) |
868 | srag %r9,%r9,23 | ||
975 | jz 0f | 869 | jz 0f |
976 | stg %r11,__TI_last_break(%r12) | 870 | mvc __TI_last_break(8,%r12),16(%r11) |
977 | 0: mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8) | 871 | 0: # set up saved register r11 |
978 | la %r12,__LC_RETURN_PSW | 872 | lg %r15,__LC_KERNEL_STACK |
873 | aghi %r15,-__PT_SIZE | ||
874 | stg %r15,24(%r11) # r11 pt_regs pointer | ||
875 | # fill pt_regs | ||
876 | mvc __PT_R8(64,%r15),__LC_SAVE_AREA_SYNC | ||
877 | stmg %r0,%r7,__PT_R0(%r15) | ||
878 | mvc __PT_PSW(16,%r15),__LC_SVC_OLD_PSW | ||
879 | mvc __PT_INT_CODE(4,%r15),__LC_SVC_ILC | ||
880 | # setup saved register r15 | ||
881 | aghi %r15,-STACK_FRAME_OVERHEAD | ||
882 | stg %r15,56(%r11) # r15 stack pointer | ||
883 | # set new psw address and exit | ||
884 | larl %r9,sysc_do_svc | ||
979 | br %r14 | 885 | br %r14 |
980 | cleanup_system_call_insn: | 886 | cleanup_system_call_insn: |
981 | .quad sysc_saveall | ||
982 | .quad system_call | 887 | .quad system_call |
983 | .quad sysc_vtime | 888 | .quad sysc_stmg |
984 | .quad sysc_stime | 889 | .quad sysc_per |
985 | .quad sysc_update | 890 | .quad sysc_vtime+18 |
891 | .quad sysc_vtime+42 | ||
986 | 892 | ||
987 | cleanup_sysc_tif: | 893 | cleanup_sysc_tif: |
988 | mvc __LC_RETURN_PSW(8),0(%r12) | 894 | larl %r9,sysc_tif |
989 | mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_sysc_tif) | ||
990 | la %r12,__LC_RETURN_PSW | ||
991 | br %r14 | 895 | br %r14 |
992 | 896 | ||
993 | cleanup_sysc_restore: | 897 | cleanup_sysc_restore: |
994 | clc 8(8,%r12),BASED(cleanup_sysc_restore_insn) | 898 | clg %r9,BASED(cleanup_sysc_restore_insn) |
995 | je 2f | ||
996 | clc 8(8,%r12),BASED(cleanup_sysc_restore_insn+8) | ||
997 | jhe 0f | ||
998 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
999 | cghi %r12,__LC_MCK_OLD_PSW | ||
1000 | je 0f | 899 | je 0f |
1001 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | 900 | lg %r9,24(%r11) # get saved pointer to pt_regs |
1002 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | 901 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) |
1003 | cghi %r12,__LC_MCK_OLD_PSW | 902 | mvc 0(64,%r11),__PT_R8(%r9) |
1004 | la %r12,__LC_SAVE_AREA+80 | 903 | lmg %r0,%r7,__PT_R0(%r9) |
1005 | je 1f | 904 | 0: lmg %r8,%r9,__LC_RETURN_PSW |
1006 | la %r12,__LC_SAVE_AREA+40 | ||
1007 | 1: mvc 0(40,%r12),SP_R11(%r15) | ||
1008 | lmg %r0,%r10,SP_R0(%r15) | ||
1009 | lg %r15,SP_R15(%r15) | ||
1010 | 2: la %r12,__LC_RETURN_PSW | ||
1011 | br %r14 | 905 | br %r14 |
1012 | cleanup_sysc_restore_insn: | 906 | cleanup_sysc_restore_insn: |
1013 | .quad sysc_done - 4 | 907 | .quad sysc_done - 4 |
1014 | .quad sysc_done - 16 | ||
1015 | 908 | ||
1016 | cleanup_io_tif: | 909 | cleanup_io_tif: |
1017 | mvc __LC_RETURN_PSW(8),0(%r12) | 910 | larl %r9,io_tif |
1018 | mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_io_tif) | ||
1019 | la %r12,__LC_RETURN_PSW | ||
1020 | br %r14 | 911 | br %r14 |
1021 | 912 | ||
1022 | cleanup_io_restore: | 913 | cleanup_io_restore: |
1023 | clc 8(8,%r12),BASED(cleanup_io_restore_insn) | 914 | clg %r9,BASED(cleanup_io_restore_insn) |
1024 | je 1f | 915 | je 0f |
1025 | clc 8(8,%r12),BASED(cleanup_io_restore_insn+8) | 916 | lg %r9,24(%r11) # get saved r11 pointer to pt_regs |
1026 | jhe 0f | 917 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) |
1027 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER | 918 | ni __LC_RETURN_PSW+1,0xfd # clear wait state bit |
1028 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | 919 | mvc 0(64,%r11),__PT_R8(%r9) |
1029 | mvc __LC_SAVE_AREA+80(40),SP_R11(%r15) | 920 | lmg %r0,%r7,__PT_R0(%r9) |
1030 | lmg %r0,%r10,SP_R0(%r15) | 921 | 0: lmg %r8,%r9,__LC_RETURN_PSW |
1031 | lg %r15,SP_R15(%r15) | ||
1032 | 1: la %r12,__LC_RETURN_PSW | ||
1033 | br %r14 | 922 | br %r14 |
1034 | cleanup_io_restore_insn: | 923 | cleanup_io_restore_insn: |
1035 | .quad io_done - 4 | 924 | .quad io_done - 4 |
1036 | .quad io_done - 16 | ||
1037 | 925 | ||
1038 | /* | 926 | /* |
1039 | * Integer constants | 927 | * Integer constants |
1040 | */ | 928 | */ |
1041 | .align 4 | 929 | .align 8 |
1042 | .Lcritical_start: | 930 | .Lcritical_start: |
1043 | .quad __critical_start | 931 | .quad __critical_start |
1044 | .Lcritical_end: | 932 | .Lcritical_length: |
1045 | .quad __critical_end | 933 | .quad __critical_end - __critical_start |
934 | |||
1046 | 935 | ||
1047 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | 936 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) |
1048 | /* | 937 | /* |
@@ -1054,6 +943,7 @@ ENTRY(sie64a) | |||
1054 | stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers | 943 | stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers |
1055 | stg %r2,__SF_EMPTY(%r15) # save control block pointer | 944 | stg %r2,__SF_EMPTY(%r15) # save control block pointer |
1056 | stg %r3,__SF_EMPTY+8(%r15) # save guest register save area | 945 | stg %r3,__SF_EMPTY+8(%r15) # save guest register save area |
946 | xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0 | ||
1057 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 | 947 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 |
1058 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct | 948 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct |
1059 | oi __TI_flags+6(%r14),_TIF_SIE>>8 | 949 | oi __TI_flags+6(%r14),_TIF_SIE>>8 |
@@ -1070,7 +960,7 @@ sie_gmap: | |||
1070 | SPP __SF_EMPTY(%r15) # set guest id | 960 | SPP __SF_EMPTY(%r15) # set guest id |
1071 | sie 0(%r14) | 961 | sie 0(%r14) |
1072 | sie_done: | 962 | sie_done: |
1073 | SPP __LC_CMF_HPP # set host id | 963 | SPP __SF_EMPTY+16(%r15) # set host id |
1074 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct | 964 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct |
1075 | sie_exit: | 965 | sie_exit: |
1076 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | 966 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce |
@@ -1093,8 +983,10 @@ sie_fault: | |||
1093 | .align 8 | 983 | .align 8 |
1094 | .Lsie_loop: | 984 | .Lsie_loop: |
1095 | .quad sie_loop | 985 | .quad sie_loop |
1096 | .Lsie_done: | 986 | .Lsie_length: |
1097 | .quad sie_done | 987 | .quad sie_done - sie_loop |
988 | .Lhost_id: | ||
989 | .quad 0 | ||
1098 | 990 | ||
1099 | .section __ex_table,"a" | 991 | .section __ex_table,"a" |
1100 | .quad sie_loop,sie_fault | 992 | .quad sie_loop,sie_fault |
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 900068d2bf92..c27a0727f930 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S | |||
@@ -329,8 +329,8 @@ iplstart: | |||
329 | # | 329 | # |
330 | # reset files in VM reader | 330 | # reset files in VM reader |
331 | # | 331 | # |
332 | stidp __LC_SAVE_AREA # store cpuid | 332 | stidp __LC_SAVE_AREA_SYNC # store cpuid |
333 | tm __LC_SAVE_AREA,0xff # running VM ? | 333 | tm __LC_SAVE_AREA_SYNC,0xff# running VM ? |
334 | bno .Lnoreset | 334 | bno .Lnoreset |
335 | la %r2,.Lreset | 335 | la %r2,.Lreset |
336 | lhi %r3,26 | 336 | lhi %r3,26 |
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 3cd0f25ab015..47b168fb29c4 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c | |||
@@ -208,6 +208,7 @@ void machine_kexec_cleanup(struct kimage *image) | |||
208 | void arch_crash_save_vmcoreinfo(void) | 208 | void arch_crash_save_vmcoreinfo(void) |
209 | { | 209 | { |
210 | VMCOREINFO_SYMBOL(lowcore_ptr); | 210 | VMCOREINFO_SYMBOL(lowcore_ptr); |
211 | VMCOREINFO_SYMBOL(high_memory); | ||
211 | VMCOREINFO_LENGTH(lowcore_ptr, NR_CPUS); | 212 | VMCOREINFO_LENGTH(lowcore_ptr, NR_CPUS); |
212 | } | 213 | } |
213 | 214 | ||
diff --git a/arch/s390/kernel/mem_detect.c b/arch/s390/kernel/mem_detect.c index 19b4568f4cee..22d502e885ed 100644 --- a/arch/s390/kernel/mem_detect.c +++ b/arch/s390/kernel/mem_detect.c | |||
@@ -64,70 +64,82 @@ void detect_memory_layout(struct mem_chunk chunk[]) | |||
64 | EXPORT_SYMBOL(detect_memory_layout); | 64 | EXPORT_SYMBOL(detect_memory_layout); |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * Move memory chunks array from index "from" to index "to" | ||
68 | */ | ||
69 | static void mem_chunk_move(struct mem_chunk chunk[], int to, int from) | ||
70 | { | ||
71 | int cnt = MEMORY_CHUNKS - to; | ||
72 | |||
73 | memmove(&chunk[to], &chunk[from], cnt * sizeof(struct mem_chunk)); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Initialize memory chunk | ||
78 | */ | ||
79 | static void mem_chunk_init(struct mem_chunk *chunk, unsigned long addr, | ||
80 | unsigned long size, int type) | ||
81 | { | ||
82 | chunk->type = type; | ||
83 | chunk->addr = addr; | ||
84 | chunk->size = size; | ||
85 | } | ||
86 | |||
87 | /* | ||
67 | * Create memory hole with given address, size, and type | 88 | * Create memory hole with given address, size, and type |
68 | */ | 89 | */ |
69 | void create_mem_hole(struct mem_chunk chunks[], unsigned long addr, | 90 | void create_mem_hole(struct mem_chunk chunk[], unsigned long addr, |
70 | unsigned long size, int type) | 91 | unsigned long size, int type) |
71 | { | 92 | { |
72 | unsigned long start, end, new_size; | 93 | unsigned long lh_start, lh_end, lh_size, ch_start, ch_end, ch_size; |
73 | int i; | 94 | int i, ch_type; |
74 | 95 | ||
75 | for (i = 0; i < MEMORY_CHUNKS; i++) { | 96 | for (i = 0; i < MEMORY_CHUNKS; i++) { |
76 | if (chunks[i].size == 0) | 97 | if (chunk[i].size == 0) |
77 | continue; | ||
78 | if (addr + size < chunks[i].addr) | ||
79 | continue; | ||
80 | if (addr >= chunks[i].addr + chunks[i].size) | ||
81 | continue; | 98 | continue; |
82 | start = max(addr, chunks[i].addr); | 99 | |
83 | end = min(addr + size, chunks[i].addr + chunks[i].size); | 100 | /* Define chunk properties */ |
84 | new_size = end - start; | 101 | ch_start = chunk[i].addr; |
85 | if (new_size == 0) | 102 | ch_size = chunk[i].size; |
86 | continue; | 103 | ch_end = ch_start + ch_size - 1; |
87 | if (start == chunks[i].addr && | 104 | ch_type = chunk[i].type; |
88 | end == chunks[i].addr + chunks[i].size) { | 105 | |
89 | /* Remove chunk */ | 106 | /* Is memory chunk hit by memory hole? */ |
90 | chunks[i].type = type; | 107 | if (addr + size <= ch_start) |
91 | } else if (start == chunks[i].addr) { | 108 | continue; /* No: memory hole in front of chunk */ |
92 | /* Make chunk smaller at start */ | 109 | if (addr > ch_end) |
93 | if (i >= MEMORY_CHUNKS - 1) | 110 | continue; /* No: memory hole after chunk */ |
94 | panic("Unable to create memory hole"); | 111 | |
95 | memmove(&chunks[i + 1], &chunks[i], | 112 | /* Yes: Define local hole properties */ |
96 | sizeof(struct mem_chunk) * | 113 | lh_start = max(addr, chunk[i].addr); |
97 | (MEMORY_CHUNKS - (i + 1))); | 114 | lh_end = min(addr + size - 1, ch_end); |
98 | chunks[i + 1].addr = chunks[i].addr + new_size; | 115 | lh_size = lh_end - lh_start + 1; |
99 | chunks[i + 1].size = chunks[i].size - new_size; | 116 | |
100 | chunks[i].size = new_size; | 117 | if (lh_start == ch_start && lh_end == ch_end) { |
101 | chunks[i].type = type; | 118 | /* Hole covers complete memory chunk */ |
102 | i += 1; | 119 | mem_chunk_init(&chunk[i], lh_start, lh_size, type); |
103 | } else if (end == chunks[i].addr + chunks[i].size) { | 120 | } else if (lh_end == ch_end) { |
104 | /* Make chunk smaller at end */ | 121 | /* Hole starts in memory chunk and convers chunk end */ |
105 | if (i >= MEMORY_CHUNKS - 1) | 122 | mem_chunk_move(chunk, i + 1, i); |
106 | panic("Unable to create memory hole"); | 123 | mem_chunk_init(&chunk[i], ch_start, ch_size - lh_size, |
107 | memmove(&chunks[i + 1], &chunks[i], | 124 | ch_type); |
108 | sizeof(struct mem_chunk) * | 125 | mem_chunk_init(&chunk[i + 1], lh_start, lh_size, type); |
109 | (MEMORY_CHUNKS - (i + 1))); | ||
110 | chunks[i + 1].addr = start; | ||
111 | chunks[i + 1].size = new_size; | ||
112 | chunks[i + 1].type = type; | ||
113 | chunks[i].size -= new_size; | ||
114 | i += 1; | 126 | i += 1; |
127 | } else if (lh_start == ch_start) { | ||
128 | /* Hole ends in memory chunk */ | ||
129 | mem_chunk_move(chunk, i + 1, i); | ||
130 | mem_chunk_init(&chunk[i], lh_start, lh_size, type); | ||
131 | mem_chunk_init(&chunk[i + 1], lh_end + 1, | ||
132 | ch_size - lh_size, ch_type); | ||
133 | break; | ||
115 | } else { | 134 | } else { |
116 | /* Create memory hole */ | 135 | /* Hole splits memory chunk */ |
117 | if (i >= MEMORY_CHUNKS - 2) | 136 | mem_chunk_move(chunk, i + 2, i); |
118 | panic("Unable to create memory hole"); | 137 | mem_chunk_init(&chunk[i], ch_start, |
119 | memmove(&chunks[i + 2], &chunks[i], | 138 | lh_start - ch_start, ch_type); |
120 | sizeof(struct mem_chunk) * | 139 | mem_chunk_init(&chunk[i + 1], lh_start, lh_size, type); |
121 | (MEMORY_CHUNKS - (i + 2))); | 140 | mem_chunk_init(&chunk[i + 2], lh_end + 1, |
122 | chunks[i + 1].addr = addr; | 141 | ch_end - lh_end, ch_type); |
123 | chunks[i + 1].size = size; | 142 | break; |
124 | chunks[i + 1].type = type; | ||
125 | chunks[i + 2].addr = addr + size; | ||
126 | chunks[i + 2].size = | ||
127 | chunks[i].addr + chunks[i].size - (addr + size); | ||
128 | chunks[i + 2].type = chunks[i].type; | ||
129 | chunks[i].size = addr - chunks[i].addr; | ||
130 | i += 2; | ||
131 | } | 143 | } |
132 | } | 144 | } |
133 | } | 145 | } |
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S index 732a793ec53a..36b32658fb24 100644 --- a/arch/s390/kernel/reipl64.S +++ b/arch/s390/kernel/reipl64.S | |||
@@ -17,11 +17,11 @@ | |||
17 | # | 17 | # |
18 | ENTRY(store_status) | 18 | ENTRY(store_status) |
19 | /* Save register one and load save area base */ | 19 | /* Save register one and load save area base */ |
20 | stg %r1,__LC_SAVE_AREA+120(%r0) | 20 | stg %r1,__LC_SAVE_AREA_RESTART |
21 | lghi %r1,SAVE_AREA_BASE | 21 | lghi %r1,SAVE_AREA_BASE |
22 | /* General purpose registers */ | 22 | /* General purpose registers */ |
23 | stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) | 23 | stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) |
24 | lg %r2,__LC_SAVE_AREA+120(%r0) | 24 | lg %r2,__LC_SAVE_AREA_RESTART |
25 | stg %r2,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE+8(%r1) | 25 | stg %r2,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE+8(%r1) |
26 | /* Control registers */ | 26 | /* Control registers */ |
27 | stctg %c0,%c15,__LC_CREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) | 27 | stctg %c0,%c15,__LC_CREGS_SAVE_AREA-SAVE_AREA_BASE(%r1) |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index f11d1b037c50..354de0763eff 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -95,6 +95,15 @@ struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; | |||
95 | int __initdata memory_end_set; | 95 | int __initdata memory_end_set; |
96 | unsigned long __initdata memory_end; | 96 | unsigned long __initdata memory_end; |
97 | 97 | ||
98 | unsigned long VMALLOC_START; | ||
99 | EXPORT_SYMBOL(VMALLOC_START); | ||
100 | |||
101 | unsigned long VMALLOC_END; | ||
102 | EXPORT_SYMBOL(VMALLOC_END); | ||
103 | |||
104 | struct page *vmemmap; | ||
105 | EXPORT_SYMBOL(vmemmap); | ||
106 | |||
98 | /* An array with a pointer to the lowcore of every CPU. */ | 107 | /* An array with a pointer to the lowcore of every CPU. */ |
99 | struct _lowcore *lowcore_ptr[NR_CPUS]; | 108 | struct _lowcore *lowcore_ptr[NR_CPUS]; |
100 | EXPORT_SYMBOL(lowcore_ptr); | 109 | EXPORT_SYMBOL(lowcore_ptr); |
@@ -278,6 +287,15 @@ static int __init early_parse_mem(char *p) | |||
278 | } | 287 | } |
279 | early_param("mem", early_parse_mem); | 288 | early_param("mem", early_parse_mem); |
280 | 289 | ||
290 | static int __init parse_vmalloc(char *arg) | ||
291 | { | ||
292 | if (!arg) | ||
293 | return -EINVAL; | ||
294 | VMALLOC_END = (memparse(arg, &arg) + PAGE_SIZE - 1) & PAGE_MASK; | ||
295 | return 0; | ||
296 | } | ||
297 | early_param("vmalloc", parse_vmalloc); | ||
298 | |||
281 | unsigned int user_mode = HOME_SPACE_MODE; | 299 | unsigned int user_mode = HOME_SPACE_MODE; |
282 | EXPORT_SYMBOL_GPL(user_mode); | 300 | EXPORT_SYMBOL_GPL(user_mode); |
283 | 301 | ||
@@ -383,7 +401,6 @@ setup_lowcore(void) | |||
383 | __ctl_set_bit(14, 29); | 401 | __ctl_set_bit(14, 29); |
384 | } | 402 | } |
385 | #else | 403 | #else |
386 | lc->cmf_hpp = -1ULL; | ||
387 | lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; | 404 | lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; |
388 | #endif | 405 | #endif |
389 | lc->sync_enter_timer = S390_lowcore.sync_enter_timer; | 406 | lc->sync_enter_timer = S390_lowcore.sync_enter_timer; |
@@ -479,8 +496,7 @@ EXPORT_SYMBOL_GPL(real_memory_size); | |||
479 | 496 | ||
480 | static void __init setup_memory_end(void) | 497 | static void __init setup_memory_end(void) |
481 | { | 498 | { |
482 | unsigned long memory_size; | 499 | unsigned long vmax, vmalloc_size, tmp; |
483 | unsigned long max_mem; | ||
484 | int i; | 500 | int i; |
485 | 501 | ||
486 | 502 | ||
@@ -490,12 +506,9 @@ static void __init setup_memory_end(void) | |||
490 | memory_end_set = 1; | 506 | memory_end_set = 1; |
491 | } | 507 | } |
492 | #endif | 508 | #endif |
493 | memory_size = 0; | 509 | real_memory_size = 0; |
494 | memory_end &= PAGE_MASK; | 510 | memory_end &= PAGE_MASK; |
495 | 511 | ||
496 | max_mem = memory_end ? min(VMEM_MAX_PHYS, memory_end) : VMEM_MAX_PHYS; | ||
497 | memory_end = min(max_mem, memory_end); | ||
498 | |||
499 | /* | 512 | /* |
500 | * Make sure all chunks are MAX_ORDER aligned so we don't need the | 513 | * Make sure all chunks are MAX_ORDER aligned so we don't need the |
501 | * extra checks that HOLES_IN_ZONE would require. | 514 | * extra checks that HOLES_IN_ZONE would require. |
@@ -515,23 +528,48 @@ static void __init setup_memory_end(void) | |||
515 | chunk->addr = start; | 528 | chunk->addr = start; |
516 | chunk->size = end - start; | 529 | chunk->size = end - start; |
517 | } | 530 | } |
531 | real_memory_size = max(real_memory_size, | ||
532 | chunk->addr + chunk->size); | ||
518 | } | 533 | } |
519 | 534 | ||
535 | /* Choose kernel address space layout: 2, 3, or 4 levels. */ | ||
536 | #ifdef CONFIG_64BIT | ||
537 | vmalloc_size = VMALLOC_END ?: 128UL << 30; | ||
538 | tmp = (memory_end ?: real_memory_size) / PAGE_SIZE; | ||
539 | tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size; | ||
540 | if (tmp <= (1UL << 42)) | ||
541 | vmax = 1UL << 42; /* 3-level kernel page table */ | ||
542 | else | ||
543 | vmax = 1UL << 53; /* 4-level kernel page table */ | ||
544 | #else | ||
545 | vmalloc_size = VMALLOC_END ?: 96UL << 20; | ||
546 | vmax = 1UL << 31; /* 2-level kernel page table */ | ||
547 | #endif | ||
548 | /* vmalloc area is at the end of the kernel address space. */ | ||
549 | VMALLOC_END = vmax; | ||
550 | VMALLOC_START = vmax - vmalloc_size; | ||
551 | |||
552 | /* Split remaining virtual space between 1:1 mapping & vmemmap array */ | ||
553 | tmp = VMALLOC_START / (PAGE_SIZE + sizeof(struct page)); | ||
554 | tmp = VMALLOC_START - tmp * sizeof(struct page); | ||
555 | tmp &= ~((vmax >> 11) - 1); /* align to page table level */ | ||
556 | tmp = min(tmp, 1UL << MAX_PHYSMEM_BITS); | ||
557 | vmemmap = (struct page *) tmp; | ||
558 | |||
559 | /* Take care that memory_end is set and <= vmemmap */ | ||
560 | memory_end = min(memory_end ?: real_memory_size, tmp); | ||
561 | |||
562 | /* Fixup memory chunk array to fit into 0..memory_end */ | ||
520 | for (i = 0; i < MEMORY_CHUNKS; i++) { | 563 | for (i = 0; i < MEMORY_CHUNKS; i++) { |
521 | struct mem_chunk *chunk = &memory_chunk[i]; | 564 | struct mem_chunk *chunk = &memory_chunk[i]; |
522 | 565 | ||
523 | real_memory_size = max(real_memory_size, | 566 | if (chunk->addr >= memory_end) { |
524 | chunk->addr + chunk->size); | ||
525 | if (chunk->addr >= max_mem) { | ||
526 | memset(chunk, 0, sizeof(*chunk)); | 567 | memset(chunk, 0, sizeof(*chunk)); |
527 | continue; | 568 | continue; |
528 | } | 569 | } |
529 | if (chunk->addr + chunk->size > max_mem) | 570 | if (chunk->addr + chunk->size > memory_end) |
530 | chunk->size = max_mem - chunk->addr; | 571 | chunk->size = memory_end - chunk->addr; |
531 | memory_size = max(memory_size, chunk->addr + chunk->size); | ||
532 | } | 572 | } |
533 | if (!memory_end) | ||
534 | memory_end = memory_size; | ||
535 | } | 573 | } |
536 | 574 | ||
537 | void *restart_stack __attribute__((__section__(".data"))); | 575 | void *restart_stack __attribute__((__section__(".data"))); |
@@ -655,7 +693,6 @@ static int __init verify_crash_base(unsigned long crash_base, | |||
655 | static void __init reserve_kdump_bootmem(unsigned long addr, unsigned long size, | 693 | static void __init reserve_kdump_bootmem(unsigned long addr, unsigned long size, |
656 | int type) | 694 | int type) |
657 | { | 695 | { |
658 | |||
659 | create_mem_hole(memory_chunk, addr, size, type); | 696 | create_mem_hole(memory_chunk, addr, size, type); |
660 | } | 697 | } |
661 | 698 | ||
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 7f6f9f354545..a8ba840294ff 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c | |||
@@ -302,9 +302,13 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
302 | 302 | ||
303 | /* We forgot to include these in the sigcontext. | 303 | /* We forgot to include these in the sigcontext. |
304 | To avoid breaking binary compatibility, they are passed as args. */ | 304 | To avoid breaking binary compatibility, they are passed as args. */ |
305 | regs->gprs[4] = current->thread.trap_no; | 305 | if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || |
306 | regs->gprs[5] = current->thread.prot_addr; | 306 | sig == SIGTRAP || sig == SIGFPE) { |
307 | regs->gprs[6] = task_thread_info(current)->last_break; | 307 | /* set extra registers only for synchronous signals */ |
308 | regs->gprs[4] = regs->int_code & 127; | ||
309 | regs->gprs[5] = regs->int_parm_long; | ||
310 | regs->gprs[6] = task_thread_info(current)->last_break; | ||
311 | } | ||
308 | 312 | ||
309 | /* Place signal number on stack to allow backtrace from handler. */ | 313 | /* Place signal number on stack to allow backtrace from handler. */ |
310 | if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) | 314 | if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) |
@@ -434,13 +438,13 @@ void do_signal(struct pt_regs *regs) | |||
434 | * call information. | 438 | * call information. |
435 | */ | 439 | */ |
436 | current_thread_info()->system_call = | 440 | current_thread_info()->system_call = |
437 | test_thread_flag(TIF_SYSCALL) ? regs->svc_code : 0; | 441 | test_thread_flag(TIF_SYSCALL) ? regs->int_code : 0; |
438 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 442 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
439 | 443 | ||
440 | if (signr > 0) { | 444 | if (signr > 0) { |
441 | /* Whee! Actually deliver the signal. */ | 445 | /* Whee! Actually deliver the signal. */ |
442 | if (current_thread_info()->system_call) { | 446 | if (current_thread_info()->system_call) { |
443 | regs->svc_code = current_thread_info()->system_call; | 447 | regs->int_code = current_thread_info()->system_call; |
444 | /* Check for system call restarting. */ | 448 | /* Check for system call restarting. */ |
445 | switch (regs->gprs[2]) { | 449 | switch (regs->gprs[2]) { |
446 | case -ERESTART_RESTARTBLOCK: | 450 | case -ERESTART_RESTARTBLOCK: |
@@ -457,7 +461,7 @@ void do_signal(struct pt_regs *regs) | |||
457 | regs->gprs[2] = regs->orig_gpr2; | 461 | regs->gprs[2] = regs->orig_gpr2; |
458 | regs->psw.addr = | 462 | regs->psw.addr = |
459 | __rewind_psw(regs->psw, | 463 | __rewind_psw(regs->psw, |
460 | regs->svc_code >> 16); | 464 | regs->int_code >> 16); |
461 | break; | 465 | break; |
462 | } | 466 | } |
463 | } | 467 | } |
@@ -488,11 +492,11 @@ void do_signal(struct pt_regs *regs) | |||
488 | /* No handlers present - check for system call restart */ | 492 | /* No handlers present - check for system call restart */ |
489 | clear_thread_flag(TIF_SYSCALL); | 493 | clear_thread_flag(TIF_SYSCALL); |
490 | if (current_thread_info()->system_call) { | 494 | if (current_thread_info()->system_call) { |
491 | regs->svc_code = current_thread_info()->system_call; | 495 | regs->int_code = current_thread_info()->system_call; |
492 | switch (regs->gprs[2]) { | 496 | switch (regs->gprs[2]) { |
493 | case -ERESTART_RESTARTBLOCK: | 497 | case -ERESTART_RESTARTBLOCK: |
494 | /* Restart with sys_restart_syscall */ | 498 | /* Restart with sys_restart_syscall */ |
495 | regs->svc_code = __NR_restart_syscall; | 499 | regs->int_code = __NR_restart_syscall; |
496 | /* fallthrough */ | 500 | /* fallthrough */ |
497 | case -ERESTARTNOHAND: | 501 | case -ERESTARTNOHAND: |
498 | case -ERESTARTSYS: | 502 | case -ERESTARTSYS: |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 66cca03c0282..2398ce6b15ae 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -69,9 +69,7 @@ enum s390_cpu_state { | |||
69 | }; | 69 | }; |
70 | 70 | ||
71 | DEFINE_MUTEX(smp_cpu_state_mutex); | 71 | DEFINE_MUTEX(smp_cpu_state_mutex); |
72 | int smp_cpu_polarization[NR_CPUS]; | ||
73 | static int smp_cpu_state[NR_CPUS]; | 72 | static int smp_cpu_state[NR_CPUS]; |
74 | static int cpu_management; | ||
75 | 73 | ||
76 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 74 | static DEFINE_PER_CPU(struct cpu, cpu_devices); |
77 | 75 | ||
@@ -149,29 +147,59 @@ void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) | |||
149 | sp -= sizeof(struct pt_regs); | 147 | sp -= sizeof(struct pt_regs); |
150 | regs = (struct pt_regs *) sp; | 148 | regs = (struct pt_regs *) sp; |
151 | memcpy(®s->gprs, ¤t_lc->gpregs_save_area, sizeof(regs->gprs)); | 149 | memcpy(®s->gprs, ¤t_lc->gpregs_save_area, sizeof(regs->gprs)); |
152 | regs->psw = lc->psw_save_area; | 150 | regs->psw = current_lc->psw_save_area; |
153 | sp -= STACK_FRAME_OVERHEAD; | 151 | sp -= STACK_FRAME_OVERHEAD; |
154 | sf = (struct stack_frame *) sp; | 152 | sf = (struct stack_frame *) sp; |
155 | sf->back_chain = regs->gprs[15]; | 153 | sf->back_chain = 0; |
156 | smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]); | 154 | smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]); |
157 | } | 155 | } |
158 | 156 | ||
157 | static void smp_stop_cpu(void) | ||
158 | { | ||
159 | while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) | ||
160 | cpu_relax(); | ||
161 | } | ||
162 | |||
159 | void smp_send_stop(void) | 163 | void smp_send_stop(void) |
160 | { | 164 | { |
161 | int cpu, rc; | 165 | cpumask_t cpumask; |
166 | int cpu; | ||
167 | u64 end; | ||
162 | 168 | ||
163 | /* Disable all interrupts/machine checks */ | 169 | /* Disable all interrupts/machine checks */ |
164 | __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); | 170 | __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); |
165 | trace_hardirqs_off(); | 171 | trace_hardirqs_off(); |
166 | 172 | ||
167 | /* stop all processors */ | 173 | cpumask_copy(&cpumask, cpu_online_mask); |
168 | for_each_online_cpu(cpu) { | 174 | cpumask_clear_cpu(smp_processor_id(), &cpumask); |
169 | if (cpu == smp_processor_id()) | 175 | |
170 | continue; | 176 | if (oops_in_progress) { |
171 | do { | 177 | /* |
172 | rc = sigp(cpu, sigp_stop); | 178 | * Give the other cpus the opportunity to complete |
173 | } while (rc == sigp_busy); | 179 | * outstanding interrupts before stopping them. |
180 | */ | ||
181 | end = get_clock() + (1000000UL << 12); | ||
182 | for_each_cpu(cpu, &cpumask) { | ||
183 | set_bit(ec_stop_cpu, (unsigned long *) | ||
184 | &lowcore_ptr[cpu]->ext_call_fast); | ||
185 | while (sigp(cpu, sigp_emergency_signal) == sigp_busy && | ||
186 | get_clock() < end) | ||
187 | cpu_relax(); | ||
188 | } | ||
189 | while (get_clock() < end) { | ||
190 | for_each_cpu(cpu, &cpumask) | ||
191 | if (cpu_stopped(cpu)) | ||
192 | cpumask_clear_cpu(cpu, &cpumask); | ||
193 | if (cpumask_empty(&cpumask)) | ||
194 | break; | ||
195 | cpu_relax(); | ||
196 | } | ||
197 | } | ||
174 | 198 | ||
199 | /* stop all processors */ | ||
200 | for_each_cpu(cpu, &cpumask) { | ||
201 | while (sigp(cpu, sigp_stop) == sigp_busy) | ||
202 | cpu_relax(); | ||
175 | while (!cpu_stopped(cpu)) | 203 | while (!cpu_stopped(cpu)) |
176 | cpu_relax(); | 204 | cpu_relax(); |
177 | } | 205 | } |
@@ -187,7 +215,7 @@ static void do_ext_call_interrupt(unsigned int ext_int_code, | |||
187 | { | 215 | { |
188 | unsigned long bits; | 216 | unsigned long bits; |
189 | 217 | ||
190 | if (ext_int_code == 0x1202) | 218 | if ((ext_int_code & 0xffff) == 0x1202) |
191 | kstat_cpu(smp_processor_id()).irqs[EXTINT_EXC]++; | 219 | kstat_cpu(smp_processor_id()).irqs[EXTINT_EXC]++; |
192 | else | 220 | else |
193 | kstat_cpu(smp_processor_id()).irqs[EXTINT_EMS]++; | 221 | kstat_cpu(smp_processor_id()).irqs[EXTINT_EMS]++; |
@@ -196,6 +224,9 @@ static void do_ext_call_interrupt(unsigned int ext_int_code, | |||
196 | */ | 224 | */ |
197 | bits = xchg(&S390_lowcore.ext_call_fast, 0); | 225 | bits = xchg(&S390_lowcore.ext_call_fast, 0); |
198 | 226 | ||
227 | if (test_bit(ec_stop_cpu, &bits)) | ||
228 | smp_stop_cpu(); | ||
229 | |||
199 | if (test_bit(ec_schedule, &bits)) | 230 | if (test_bit(ec_schedule, &bits)) |
200 | scheduler_ipi(); | 231 | scheduler_ipi(); |
201 | 232 | ||
@@ -204,6 +235,7 @@ static void do_ext_call_interrupt(unsigned int ext_int_code, | |||
204 | 235 | ||
205 | if (test_bit(ec_call_function_single, &bits)) | 236 | if (test_bit(ec_call_function_single, &bits)) |
206 | generic_smp_call_function_single_interrupt(); | 237 | generic_smp_call_function_single_interrupt(); |
238 | |||
207 | } | 239 | } |
208 | 240 | ||
209 | /* | 241 | /* |
@@ -369,7 +401,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) | |||
369 | if (cpu_known(cpu_id)) | 401 | if (cpu_known(cpu_id)) |
370 | continue; | 402 | continue; |
371 | __cpu_logical_map[logical_cpu] = cpu_id; | 403 | __cpu_logical_map[logical_cpu] = cpu_id; |
372 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | 404 | cpu_set_polarization(logical_cpu, POLARIZATION_UNKNOWN); |
373 | if (!cpu_stopped(logical_cpu)) | 405 | if (!cpu_stopped(logical_cpu)) |
374 | continue; | 406 | continue; |
375 | set_cpu_present(logical_cpu, true); | 407 | set_cpu_present(logical_cpu, true); |
@@ -403,7 +435,7 @@ static int smp_rescan_cpus_sclp(cpumask_t avail) | |||
403 | if (cpu_known(cpu_id)) | 435 | if (cpu_known(cpu_id)) |
404 | continue; | 436 | continue; |
405 | __cpu_logical_map[logical_cpu] = cpu_id; | 437 | __cpu_logical_map[logical_cpu] = cpu_id; |
406 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | 438 | cpu_set_polarization(logical_cpu, POLARIZATION_UNKNOWN); |
407 | set_cpu_present(logical_cpu, true); | 439 | set_cpu_present(logical_cpu, true); |
408 | if (cpu >= info->configured) | 440 | if (cpu >= info->configured) |
409 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; | 441 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; |
@@ -656,7 +688,7 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
656 | - sizeof(struct stack_frame)); | 688 | - sizeof(struct stack_frame)); |
657 | memset(sf, 0, sizeof(struct stack_frame)); | 689 | memset(sf, 0, sizeof(struct stack_frame)); |
658 | sf->gprs[9] = (unsigned long) sf; | 690 | sf->gprs[9] = (unsigned long) sf; |
659 | cpu_lowcore->save_area[15] = (unsigned long) sf; | 691 | cpu_lowcore->gpregs_save_area[15] = (unsigned long) sf; |
660 | __ctl_store(cpu_lowcore->cregs_save_area, 0, 15); | 692 | __ctl_store(cpu_lowcore->cregs_save_area, 0, 15); |
661 | atomic_inc(&init_mm.context.attach_count); | 693 | atomic_inc(&init_mm.context.attach_count); |
662 | asm volatile( | 694 | asm volatile( |
@@ -806,7 +838,7 @@ void __init smp_prepare_boot_cpu(void) | |||
806 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; | 838 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; |
807 | current_set[0] = current; | 839 | current_set[0] = current; |
808 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; | 840 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; |
809 | smp_cpu_polarization[0] = POLARIZATION_UNKNWN; | 841 | cpu_set_polarization(0, POLARIZATION_UNKNOWN); |
810 | } | 842 | } |
811 | 843 | ||
812 | void __init smp_cpus_done(unsigned int max_cpus) | 844 | void __init smp_cpus_done(unsigned int max_cpus) |
@@ -868,7 +900,8 @@ static ssize_t cpu_configure_store(struct device *dev, | |||
868 | rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]); | 900 | rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]); |
869 | if (!rc) { | 901 | if (!rc) { |
870 | smp_cpu_state[cpu] = CPU_STATE_STANDBY; | 902 | smp_cpu_state[cpu] = CPU_STATE_STANDBY; |
871 | smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; | 903 | cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); |
904 | topology_expect_change(); | ||
872 | } | 905 | } |
873 | } | 906 | } |
874 | break; | 907 | break; |
@@ -877,7 +910,8 @@ static ssize_t cpu_configure_store(struct device *dev, | |||
877 | rc = sclp_cpu_configure(__cpu_logical_map[cpu]); | 910 | rc = sclp_cpu_configure(__cpu_logical_map[cpu]); |
878 | if (!rc) { | 911 | if (!rc) { |
879 | smp_cpu_state[cpu] = CPU_STATE_CONFIGURED; | 912 | smp_cpu_state[cpu] = CPU_STATE_CONFIGURED; |
880 | smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; | 913 | cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); |
914 | topology_expect_change(); | ||
881 | } | 915 | } |
882 | } | 916 | } |
883 | break; | 917 | break; |
@@ -892,35 +926,6 @@ out: | |||
892 | static DEVICE_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store); | 926 | static DEVICE_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store); |
893 | #endif /* CONFIG_HOTPLUG_CPU */ | 927 | #endif /* CONFIG_HOTPLUG_CPU */ |
894 | 928 | ||
895 | static ssize_t cpu_polarization_show(struct device *dev, | ||
896 | struct device_attribute *attr, char *buf) | ||
897 | { | ||
898 | int cpu = dev->id; | ||
899 | ssize_t count; | ||
900 | |||
901 | mutex_lock(&smp_cpu_state_mutex); | ||
902 | switch (smp_cpu_polarization[cpu]) { | ||
903 | case POLARIZATION_HRZ: | ||
904 | count = sprintf(buf, "horizontal\n"); | ||
905 | break; | ||
906 | case POLARIZATION_VL: | ||
907 | count = sprintf(buf, "vertical:low\n"); | ||
908 | break; | ||
909 | case POLARIZATION_VM: | ||
910 | count = sprintf(buf, "vertical:medium\n"); | ||
911 | break; | ||
912 | case POLARIZATION_VH: | ||
913 | count = sprintf(buf, "vertical:high\n"); | ||
914 | break; | ||
915 | default: | ||
916 | count = sprintf(buf, "unknown\n"); | ||
917 | break; | ||
918 | } | ||
919 | mutex_unlock(&smp_cpu_state_mutex); | ||
920 | return count; | ||
921 | } | ||
922 | static DEVICE_ATTR(polarization, 0444, cpu_polarization_show, NULL); | ||
923 | |||
924 | static ssize_t show_cpu_address(struct device *dev, | 929 | static ssize_t show_cpu_address(struct device *dev, |
925 | struct device_attribute *attr, char *buf) | 930 | struct device_attribute *attr, char *buf) |
926 | { | 931 | { |
@@ -928,13 +933,11 @@ static ssize_t show_cpu_address(struct device *dev, | |||
928 | } | 933 | } |
929 | static DEVICE_ATTR(address, 0444, show_cpu_address, NULL); | 934 | static DEVICE_ATTR(address, 0444, show_cpu_address, NULL); |
930 | 935 | ||
931 | |||
932 | static struct attribute *cpu_common_attrs[] = { | 936 | static struct attribute *cpu_common_attrs[] = { |
933 | #ifdef CONFIG_HOTPLUG_CPU | 937 | #ifdef CONFIG_HOTPLUG_CPU |
934 | &dev_attr_configure.attr, | 938 | &dev_attr_configure.attr, |
935 | #endif | 939 | #endif |
936 | &dev_attr_address.attr, | 940 | &dev_attr_address.attr, |
937 | &dev_attr_polarization.attr, | ||
938 | NULL, | 941 | NULL, |
939 | }; | 942 | }; |
940 | 943 | ||
@@ -1055,11 +1058,20 @@ static int __devinit smp_add_present_cpu(int cpu) | |||
1055 | rc = sysfs_create_group(&s->kobj, &cpu_common_attr_group); | 1058 | rc = sysfs_create_group(&s->kobj, &cpu_common_attr_group); |
1056 | if (rc) | 1059 | if (rc) |
1057 | goto out_cpu; | 1060 | goto out_cpu; |
1058 | if (!cpu_online(cpu)) | 1061 | if (cpu_online(cpu)) { |
1059 | goto out; | 1062 | rc = sysfs_create_group(&s->kobj, &cpu_online_attr_group); |
1060 | rc = sysfs_create_group(&s->kobj, &cpu_online_attr_group); | 1063 | if (rc) |
1061 | if (!rc) | 1064 | goto out_online; |
1062 | return 0; | 1065 | } |
1066 | rc = topology_cpu_init(c); | ||
1067 | if (rc) | ||
1068 | goto out_topology; | ||
1069 | return 0; | ||
1070 | |||
1071 | out_topology: | ||
1072 | if (cpu_online(cpu)) | ||
1073 | sysfs_remove_group(&s->kobj, &cpu_online_attr_group); | ||
1074 | out_online: | ||
1063 | sysfs_remove_group(&s->kobj, &cpu_common_attr_group); | 1075 | sysfs_remove_group(&s->kobj, &cpu_common_attr_group); |
1064 | out_cpu: | 1076 | out_cpu: |
1065 | #ifdef CONFIG_HOTPLUG_CPU | 1077 | #ifdef CONFIG_HOTPLUG_CPU |
@@ -1111,61 +1123,16 @@ static ssize_t __ref rescan_store(struct device *dev, | |||
1111 | static DEVICE_ATTR(rescan, 0200, NULL, rescan_store); | 1123 | static DEVICE_ATTR(rescan, 0200, NULL, rescan_store); |
1112 | #endif /* CONFIG_HOTPLUG_CPU */ | 1124 | #endif /* CONFIG_HOTPLUG_CPU */ |
1113 | 1125 | ||
1114 | static ssize_t dispatching_show(struct device *dev, | 1126 | static int __init s390_smp_init(void) |
1115 | struct device_attribute *attr, | ||
1116 | char *buf) | ||
1117 | { | ||
1118 | ssize_t count; | ||
1119 | |||
1120 | mutex_lock(&smp_cpu_state_mutex); | ||
1121 | count = sprintf(buf, "%d\n", cpu_management); | ||
1122 | mutex_unlock(&smp_cpu_state_mutex); | ||
1123 | return count; | ||
1124 | } | ||
1125 | |||
1126 | static ssize_t dispatching_store(struct device *dev, | ||
1127 | struct device_attribute *attr, | ||
1128 | const char *buf, | ||
1129 | size_t count) | ||
1130 | { | ||
1131 | int val, rc; | ||
1132 | char delim; | ||
1133 | |||
1134 | if (sscanf(buf, "%d %c", &val, &delim) != 1) | ||
1135 | return -EINVAL; | ||
1136 | if (val != 0 && val != 1) | ||
1137 | return -EINVAL; | ||
1138 | rc = 0; | ||
1139 | get_online_cpus(); | ||
1140 | mutex_lock(&smp_cpu_state_mutex); | ||
1141 | if (cpu_management == val) | ||
1142 | goto out; | ||
1143 | rc = topology_set_cpu_management(val); | ||
1144 | if (!rc) | ||
1145 | cpu_management = val; | ||
1146 | out: | ||
1147 | mutex_unlock(&smp_cpu_state_mutex); | ||
1148 | put_online_cpus(); | ||
1149 | return rc ? rc : count; | ||
1150 | } | ||
1151 | static DEVICE_ATTR(dispatching, 0644, dispatching_show, | ||
1152 | dispatching_store); | ||
1153 | |||
1154 | static int __init topology_init(void) | ||
1155 | { | 1127 | { |
1156 | int cpu; | 1128 | int cpu, rc; |
1157 | int rc; | ||
1158 | 1129 | ||
1159 | register_cpu_notifier(&smp_cpu_nb); | 1130 | register_cpu_notifier(&smp_cpu_nb); |
1160 | |||
1161 | #ifdef CONFIG_HOTPLUG_CPU | 1131 | #ifdef CONFIG_HOTPLUG_CPU |
1162 | rc = device_create_file(cpu_subsys.dev_root, &dev_attr_rescan); | 1132 | rc = device_create_file(cpu_subsys.dev_root, &dev_attr_rescan); |
1163 | if (rc) | 1133 | if (rc) |
1164 | return rc; | 1134 | return rc; |
1165 | #endif | 1135 | #endif |
1166 | rc = device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching); | ||
1167 | if (rc) | ||
1168 | return rc; | ||
1169 | for_each_present_cpu(cpu) { | 1136 | for_each_present_cpu(cpu) { |
1170 | rc = smp_add_present_cpu(cpu); | 1137 | rc = smp_add_present_cpu(cpu); |
1171 | if (rc) | 1138 | if (rc) |
@@ -1173,4 +1140,4 @@ static int __init topology_init(void) | |||
1173 | } | 1140 | } |
1174 | return 0; | 1141 | return 0; |
1175 | } | 1142 | } |
1176 | subsys_initcall(topology_init); | 1143 | subsys_initcall(s390_smp_init); |
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c index 476081440df9..78ea1948ff51 100644 --- a/arch/s390/kernel/sys_s390.c +++ b/arch/s390/kernel/sys_s390.c | |||
@@ -60,74 +60,22 @@ out: | |||
60 | } | 60 | } |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. | 63 | * sys_ipc() is the de-multiplexer for the SysV IPC calls. |
64 | * | ||
65 | * This is really horribly ugly. | ||
66 | */ | 64 | */ |
67 | SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second, | 65 | SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second, |
68 | unsigned long, third, void __user *, ptr) | 66 | unsigned long, third, void __user *, ptr) |
69 | { | 67 | { |
70 | struct ipc_kludge tmp; | 68 | if (call >> 16) |
71 | int ret; | 69 | return -EINVAL; |
72 | 70 | /* The s390 sys_ipc variant has only five parameters instead of six | |
73 | switch (call) { | 71 | * like the generic variant. The only difference is the handling of |
74 | case SEMOP: | 72 | * the SEMTIMEDOP subcall where on s390 the third parameter is used |
75 | return sys_semtimedop(first, (struct sembuf __user *)ptr, | 73 | * as a pointer to a struct timespec where the generic variant uses |
76 | (unsigned)second, NULL); | 74 | * the fifth parameter. |
77 | case SEMTIMEDOP: | 75 | * Therefore we can call the generic variant by simply passing the |
78 | return sys_semtimedop(first, (struct sembuf __user *)ptr, | 76 | * third parameter also as fifth parameter. |
79 | (unsigned)second, | 77 | */ |
80 | (const struct timespec __user *) third); | 78 | return sys_ipc(call, first, second, third, ptr, third); |
81 | case SEMGET: | ||
82 | return sys_semget(first, (int)second, third); | ||
83 | case SEMCTL: { | ||
84 | union semun fourth; | ||
85 | if (!ptr) | ||
86 | return -EINVAL; | ||
87 | if (get_user(fourth.__pad, (void __user * __user *) ptr)) | ||
88 | return -EFAULT; | ||
89 | return sys_semctl(first, (int)second, third, fourth); | ||
90 | } | ||
91 | case MSGSND: | ||
92 | return sys_msgsnd (first, (struct msgbuf __user *) ptr, | ||
93 | (size_t)second, third); | ||
94 | break; | ||
95 | case MSGRCV: | ||
96 | if (!ptr) | ||
97 | return -EINVAL; | ||
98 | if (copy_from_user (&tmp, (struct ipc_kludge __user *) ptr, | ||
99 | sizeof (struct ipc_kludge))) | ||
100 | return -EFAULT; | ||
101 | return sys_msgrcv (first, tmp.msgp, | ||
102 | (size_t)second, tmp.msgtyp, third); | ||
103 | case MSGGET: | ||
104 | return sys_msgget((key_t)first, (int)second); | ||
105 | case MSGCTL: | ||
106 | return sys_msgctl(first, (int)second, | ||
107 | (struct msqid_ds __user *)ptr); | ||
108 | |||
109 | case SHMAT: { | ||
110 | ulong raddr; | ||
111 | ret = do_shmat(first, (char __user *)ptr, | ||
112 | (int)second, &raddr); | ||
113 | if (ret) | ||
114 | return ret; | ||
115 | return put_user (raddr, (ulong __user *) third); | ||
116 | break; | ||
117 | } | ||
118 | case SHMDT: | ||
119 | return sys_shmdt ((char __user *)ptr); | ||
120 | case SHMGET: | ||
121 | return sys_shmget(first, (size_t)second, third); | ||
122 | case SHMCTL: | ||
123 | return sys_shmctl(first, (int)second, | ||
124 | (struct shmid_ds __user *) ptr); | ||
125 | default: | ||
126 | return -ENOSYS; | ||
127 | |||
128 | } | ||
129 | |||
130 | return -EINVAL; | ||
131 | } | 79 | } |
132 | 80 | ||
133 | #ifdef CONFIG_64BIT | 81 | #ifdef CONFIG_64BIT |
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 6e0e29b29a7b..7370a41948ca 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
@@ -1,22 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright IBM Corp. 2007 | 2 | * Copyright IBM Corp. 2007,2011 |
3 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | 3 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #define KMSG_COMPONENT "cpu" | 6 | #define KMSG_COMPONENT "cpu" |
7 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 7 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
8 | 8 | ||
9 | #include <linux/kernel.h> | 9 | #include <linux/workqueue.h> |
10 | #include <linux/mm.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
11 | #include <linux/cpuset.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/init.h> |
16 | #include <linux/delay.h> | ||
16 | #include <linux/cpu.h> | 17 | #include <linux/cpu.h> |
17 | #include <linux/smp.h> | 18 | #include <linux/smp.h> |
18 | #include <linux/cpuset.h> | 19 | #include <linux/mm.h> |
19 | #include <asm/delay.h> | ||
20 | 20 | ||
21 | #define PTF_HORIZONTAL (0UL) | 21 | #define PTF_HORIZONTAL (0UL) |
22 | #define PTF_VERTICAL (1UL) | 22 | #define PTF_VERTICAL (1UL) |
@@ -31,7 +31,6 @@ struct mask_info { | |||
31 | static int topology_enabled = 1; | 31 | static int topology_enabled = 1; |
32 | static void topology_work_fn(struct work_struct *work); | 32 | static void topology_work_fn(struct work_struct *work); |
33 | static struct sysinfo_15_1_x *tl_info; | 33 | static struct sysinfo_15_1_x *tl_info; |
34 | static struct timer_list topology_timer; | ||
35 | static void set_topology_timer(void); | 34 | static void set_topology_timer(void); |
36 | static DECLARE_WORK(topology_work, topology_work_fn); | 35 | static DECLARE_WORK(topology_work, topology_work_fn); |
37 | /* topology_lock protects the core linked list */ | 36 | /* topology_lock protects the core linked list */ |
@@ -41,11 +40,12 @@ static struct mask_info core_info; | |||
41 | cpumask_t cpu_core_map[NR_CPUS]; | 40 | cpumask_t cpu_core_map[NR_CPUS]; |
42 | unsigned char cpu_core_id[NR_CPUS]; | 41 | unsigned char cpu_core_id[NR_CPUS]; |
43 | 42 | ||
44 | #ifdef CONFIG_SCHED_BOOK | ||
45 | static struct mask_info book_info; | 43 | static struct mask_info book_info; |
46 | cpumask_t cpu_book_map[NR_CPUS]; | 44 | cpumask_t cpu_book_map[NR_CPUS]; |
47 | unsigned char cpu_book_id[NR_CPUS]; | 45 | unsigned char cpu_book_id[NR_CPUS]; |
48 | #endif | 46 | |
47 | /* smp_cpu_state_mutex must be held when accessing this array */ | ||
48 | int cpu_polarization[NR_CPUS]; | ||
49 | 49 | ||
50 | static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) | 50 | static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) |
51 | { | 51 | { |
@@ -71,7 +71,7 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) | |||
71 | static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu, | 71 | static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu, |
72 | struct mask_info *book, | 72 | struct mask_info *book, |
73 | struct mask_info *core, | 73 | struct mask_info *core, |
74 | int z10) | 74 | int one_core_per_cpu) |
75 | { | 75 | { |
76 | unsigned int cpu; | 76 | unsigned int cpu; |
77 | 77 | ||
@@ -85,18 +85,16 @@ static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu, | |||
85 | for_each_present_cpu(lcpu) { | 85 | for_each_present_cpu(lcpu) { |
86 | if (cpu_logical_map(lcpu) != rcpu) | 86 | if (cpu_logical_map(lcpu) != rcpu) |
87 | continue; | 87 | continue; |
88 | #ifdef CONFIG_SCHED_BOOK | ||
89 | cpumask_set_cpu(lcpu, &book->mask); | 88 | cpumask_set_cpu(lcpu, &book->mask); |
90 | cpu_book_id[lcpu] = book->id; | 89 | cpu_book_id[lcpu] = book->id; |
91 | #endif | ||
92 | cpumask_set_cpu(lcpu, &core->mask); | 90 | cpumask_set_cpu(lcpu, &core->mask); |
93 | if (z10) { | 91 | if (one_core_per_cpu) { |
94 | cpu_core_id[lcpu] = rcpu; | 92 | cpu_core_id[lcpu] = rcpu; |
95 | core = core->next; | 93 | core = core->next; |
96 | } else { | 94 | } else { |
97 | cpu_core_id[lcpu] = core->id; | 95 | cpu_core_id[lcpu] = core->id; |
98 | } | 96 | } |
99 | smp_cpu_polarization[lcpu] = tl_cpu->pp; | 97 | cpu_set_polarization(lcpu, tl_cpu->pp); |
100 | } | 98 | } |
101 | } | 99 | } |
102 | return core; | 100 | return core; |
@@ -111,13 +109,11 @@ static void clear_masks(void) | |||
111 | cpumask_clear(&info->mask); | 109 | cpumask_clear(&info->mask); |
112 | info = info->next; | 110 | info = info->next; |
113 | } | 111 | } |
114 | #ifdef CONFIG_SCHED_BOOK | ||
115 | info = &book_info; | 112 | info = &book_info; |
116 | while (info) { | 113 | while (info) { |
117 | cpumask_clear(&info->mask); | 114 | cpumask_clear(&info->mask); |
118 | info = info->next; | 115 | info = info->next; |
119 | } | 116 | } |
120 | #endif | ||
121 | } | 117 | } |
122 | 118 | ||
123 | static union topology_entry *next_tle(union topology_entry *tle) | 119 | static union topology_entry *next_tle(union topology_entry *tle) |
@@ -127,66 +123,75 @@ static union topology_entry *next_tle(union topology_entry *tle) | |||
127 | return (union topology_entry *)((struct topology_container *)tle + 1); | 123 | return (union topology_entry *)((struct topology_container *)tle + 1); |
128 | } | 124 | } |
129 | 125 | ||
130 | static void tl_to_cores(struct sysinfo_15_1_x *info) | 126 | static void __tl_to_cores_generic(struct sysinfo_15_1_x *info) |
131 | { | 127 | { |
132 | #ifdef CONFIG_SCHED_BOOK | ||
133 | struct mask_info *book = &book_info; | ||
134 | struct cpuid cpu_id; | ||
135 | #else | ||
136 | struct mask_info *book = NULL; | ||
137 | #endif | ||
138 | struct mask_info *core = &core_info; | 128 | struct mask_info *core = &core_info; |
129 | struct mask_info *book = &book_info; | ||
139 | union topology_entry *tle, *end; | 130 | union topology_entry *tle, *end; |
140 | int z10 = 0; | ||
141 | 131 | ||
142 | #ifdef CONFIG_SCHED_BOOK | ||
143 | get_cpu_id(&cpu_id); | ||
144 | z10 = cpu_id.machine == 0x2097 || cpu_id.machine == 0x2098; | ||
145 | #endif | ||
146 | spin_lock_irq(&topology_lock); | ||
147 | clear_masks(); | ||
148 | tle = info->tle; | 132 | tle = info->tle; |
149 | end = (union topology_entry *)((unsigned long)info + info->length); | 133 | end = (union topology_entry *)((unsigned long)info + info->length); |
150 | while (tle < end) { | 134 | while (tle < end) { |
151 | #ifdef CONFIG_SCHED_BOOK | ||
152 | if (z10) { | ||
153 | switch (tle->nl) { | ||
154 | case 1: | ||
155 | book = book->next; | ||
156 | book->id = tle->container.id; | ||
157 | break; | ||
158 | case 0: | ||
159 | core = add_cpus_to_mask(&tle->cpu, book, core, z10); | ||
160 | break; | ||
161 | default: | ||
162 | clear_masks(); | ||
163 | goto out; | ||
164 | } | ||
165 | tle = next_tle(tle); | ||
166 | continue; | ||
167 | } | ||
168 | #endif | ||
169 | switch (tle->nl) { | 135 | switch (tle->nl) { |
170 | #ifdef CONFIG_SCHED_BOOK | ||
171 | case 2: | 136 | case 2: |
172 | book = book->next; | 137 | book = book->next; |
173 | book->id = tle->container.id; | 138 | book->id = tle->container.id; |
174 | break; | 139 | break; |
175 | #endif | ||
176 | case 1: | 140 | case 1: |
177 | core = core->next; | 141 | core = core->next; |
178 | core->id = tle->container.id; | 142 | core->id = tle->container.id; |
179 | break; | 143 | break; |
180 | case 0: | 144 | case 0: |
181 | add_cpus_to_mask(&tle->cpu, book, core, z10); | 145 | add_cpus_to_mask(&tle->cpu, book, core, 0); |
182 | break; | 146 | break; |
183 | default: | 147 | default: |
184 | clear_masks(); | 148 | clear_masks(); |
185 | goto out; | 149 | return; |
186 | } | 150 | } |
187 | tle = next_tle(tle); | 151 | tle = next_tle(tle); |
188 | } | 152 | } |
189 | out: | 153 | } |
154 | |||
155 | static void __tl_to_cores_z10(struct sysinfo_15_1_x *info) | ||
156 | { | ||
157 | struct mask_info *core = &core_info; | ||
158 | struct mask_info *book = &book_info; | ||
159 | union topology_entry *tle, *end; | ||
160 | |||
161 | tle = info->tle; | ||
162 | end = (union topology_entry *)((unsigned long)info + info->length); | ||
163 | while (tle < end) { | ||
164 | switch (tle->nl) { | ||
165 | case 1: | ||
166 | book = book->next; | ||
167 | book->id = tle->container.id; | ||
168 | break; | ||
169 | case 0: | ||
170 | core = add_cpus_to_mask(&tle->cpu, book, core, 1); | ||
171 | break; | ||
172 | default: | ||
173 | clear_masks(); | ||
174 | return; | ||
175 | } | ||
176 | tle = next_tle(tle); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | static void tl_to_cores(struct sysinfo_15_1_x *info) | ||
181 | { | ||
182 | struct cpuid cpu_id; | ||
183 | |||
184 | get_cpu_id(&cpu_id); | ||
185 | spin_lock_irq(&topology_lock); | ||
186 | clear_masks(); | ||
187 | switch (cpu_id.machine) { | ||
188 | case 0x2097: | ||
189 | case 0x2098: | ||
190 | __tl_to_cores_z10(info); | ||
191 | break; | ||
192 | default: | ||
193 | __tl_to_cores_generic(info); | ||
194 | } | ||
190 | spin_unlock_irq(&topology_lock); | 195 | spin_unlock_irq(&topology_lock); |
191 | } | 196 | } |
192 | 197 | ||
@@ -196,7 +201,7 @@ static void topology_update_polarization_simple(void) | |||
196 | 201 | ||
197 | mutex_lock(&smp_cpu_state_mutex); | 202 | mutex_lock(&smp_cpu_state_mutex); |
198 | for_each_possible_cpu(cpu) | 203 | for_each_possible_cpu(cpu) |
199 | smp_cpu_polarization[cpu] = POLARIZATION_HRZ; | 204 | cpu_set_polarization(cpu, POLARIZATION_HRZ); |
200 | mutex_unlock(&smp_cpu_state_mutex); | 205 | mutex_unlock(&smp_cpu_state_mutex); |
201 | } | 206 | } |
202 | 207 | ||
@@ -215,8 +220,7 @@ static int ptf(unsigned long fc) | |||
215 | 220 | ||
216 | int topology_set_cpu_management(int fc) | 221 | int topology_set_cpu_management(int fc) |
217 | { | 222 | { |
218 | int cpu; | 223 | int cpu, rc; |
219 | int rc; | ||
220 | 224 | ||
221 | if (!MACHINE_HAS_TOPOLOGY) | 225 | if (!MACHINE_HAS_TOPOLOGY) |
222 | return -EOPNOTSUPP; | 226 | return -EOPNOTSUPP; |
@@ -227,7 +231,7 @@ int topology_set_cpu_management(int fc) | |||
227 | if (rc) | 231 | if (rc) |
228 | return -EBUSY; | 232 | return -EBUSY; |
229 | for_each_possible_cpu(cpu) | 233 | for_each_possible_cpu(cpu) |
230 | smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; | 234 | cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); |
231 | return rc; | 235 | return rc; |
232 | } | 236 | } |
233 | 237 | ||
@@ -239,22 +243,18 @@ static void update_cpu_core_map(void) | |||
239 | spin_lock_irqsave(&topology_lock, flags); | 243 | spin_lock_irqsave(&topology_lock, flags); |
240 | for_each_possible_cpu(cpu) { | 244 | for_each_possible_cpu(cpu) { |
241 | cpu_core_map[cpu] = cpu_group_map(&core_info, cpu); | 245 | cpu_core_map[cpu] = cpu_group_map(&core_info, cpu); |
242 | #ifdef CONFIG_SCHED_BOOK | ||
243 | cpu_book_map[cpu] = cpu_group_map(&book_info, cpu); | 246 | cpu_book_map[cpu] = cpu_group_map(&book_info, cpu); |
244 | #endif | ||
245 | } | 247 | } |
246 | spin_unlock_irqrestore(&topology_lock, flags); | 248 | spin_unlock_irqrestore(&topology_lock, flags); |
247 | } | 249 | } |
248 | 250 | ||
249 | void store_topology(struct sysinfo_15_1_x *info) | 251 | void store_topology(struct sysinfo_15_1_x *info) |
250 | { | 252 | { |
251 | #ifdef CONFIG_SCHED_BOOK | ||
252 | int rc; | 253 | int rc; |
253 | 254 | ||
254 | rc = stsi(info, 15, 1, 3); | 255 | rc = stsi(info, 15, 1, 3); |
255 | if (rc != -ENOSYS) | 256 | if (rc != -ENOSYS) |
256 | return; | 257 | return; |
257 | #endif | ||
258 | stsi(info, 15, 1, 2); | 258 | stsi(info, 15, 1, 2); |
259 | } | 259 | } |
260 | 260 | ||
@@ -296,12 +296,30 @@ static void topology_timer_fn(unsigned long ignored) | |||
296 | set_topology_timer(); | 296 | set_topology_timer(); |
297 | } | 297 | } |
298 | 298 | ||
299 | static struct timer_list topology_timer = | ||
300 | TIMER_DEFERRED_INITIALIZER(topology_timer_fn, 0, 0); | ||
301 | |||
302 | static atomic_t topology_poll = ATOMIC_INIT(0); | ||
303 | |||
299 | static void set_topology_timer(void) | 304 | static void set_topology_timer(void) |
300 | { | 305 | { |
301 | topology_timer.function = topology_timer_fn; | 306 | if (atomic_add_unless(&topology_poll, -1, 0)) |
302 | topology_timer.data = 0; | 307 | mod_timer(&topology_timer, jiffies + HZ / 10); |
303 | topology_timer.expires = jiffies + 60 * HZ; | 308 | else |
304 | add_timer(&topology_timer); | 309 | mod_timer(&topology_timer, jiffies + HZ * 60); |
310 | } | ||
311 | |||
312 | void topology_expect_change(void) | ||
313 | { | ||
314 | if (!MACHINE_HAS_TOPOLOGY) | ||
315 | return; | ||
316 | /* This is racy, but it doesn't matter since it is just a heuristic. | ||
317 | * Worst case is that we poll in a higher frequency for a bit longer. | ||
318 | */ | ||
319 | if (atomic_read(&topology_poll) > 60) | ||
320 | return; | ||
321 | atomic_add(60, &topology_poll); | ||
322 | set_topology_timer(); | ||
305 | } | 323 | } |
306 | 324 | ||
307 | static int __init early_parse_topology(char *p) | 325 | static int __init early_parse_topology(char *p) |
@@ -313,23 +331,6 @@ static int __init early_parse_topology(char *p) | |||
313 | } | 331 | } |
314 | early_param("topology", early_parse_topology); | 332 | early_param("topology", early_parse_topology); |
315 | 333 | ||
316 | static int __init init_topology_update(void) | ||
317 | { | ||
318 | int rc; | ||
319 | |||
320 | rc = 0; | ||
321 | if (!MACHINE_HAS_TOPOLOGY) { | ||
322 | topology_update_polarization_simple(); | ||
323 | goto out; | ||
324 | } | ||
325 | init_timer_deferrable(&topology_timer); | ||
326 | set_topology_timer(); | ||
327 | out: | ||
328 | update_cpu_core_map(); | ||
329 | return rc; | ||
330 | } | ||
331 | __initcall(init_topology_update); | ||
332 | |||
333 | static void __init alloc_masks(struct sysinfo_15_1_x *info, | 334 | static void __init alloc_masks(struct sysinfo_15_1_x *info, |
334 | struct mask_info *mask, int offset) | 335 | struct mask_info *mask, int offset) |
335 | { | 336 | { |
@@ -357,10 +358,108 @@ void __init s390_init_cpu_topology(void) | |||
357 | store_topology(info); | 358 | store_topology(info); |
358 | pr_info("The CPU configuration topology of the machine is:"); | 359 | pr_info("The CPU configuration topology of the machine is:"); |
359 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) | 360 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) |
360 | printk(" %d", info->mag[i]); | 361 | printk(KERN_CONT " %d", info->mag[i]); |
361 | printk(" / %d\n", info->mnest); | 362 | printk(KERN_CONT " / %d\n", info->mnest); |
362 | alloc_masks(info, &core_info, 1); | 363 | alloc_masks(info, &core_info, 1); |
363 | #ifdef CONFIG_SCHED_BOOK | ||
364 | alloc_masks(info, &book_info, 2); | 364 | alloc_masks(info, &book_info, 2); |
365 | #endif | ||
366 | } | 365 | } |
366 | |||
367 | static int cpu_management; | ||
368 | |||
369 | static ssize_t dispatching_show(struct device *dev, | ||
370 | struct device_attribute *attr, | ||
371 | char *buf) | ||
372 | { | ||
373 | ssize_t count; | ||
374 | |||
375 | mutex_lock(&smp_cpu_state_mutex); | ||
376 | count = sprintf(buf, "%d\n", cpu_management); | ||
377 | mutex_unlock(&smp_cpu_state_mutex); | ||
378 | return count; | ||
379 | } | ||
380 | |||
381 | static ssize_t dispatching_store(struct device *dev, | ||
382 | struct device_attribute *attr, | ||
383 | const char *buf, | ||
384 | size_t count) | ||
385 | { | ||
386 | int val, rc; | ||
387 | char delim; | ||
388 | |||
389 | if (sscanf(buf, "%d %c", &val, &delim) != 1) | ||
390 | return -EINVAL; | ||
391 | if (val != 0 && val != 1) | ||
392 | return -EINVAL; | ||
393 | rc = 0; | ||
394 | get_online_cpus(); | ||
395 | mutex_lock(&smp_cpu_state_mutex); | ||
396 | if (cpu_management == val) | ||
397 | goto out; | ||
398 | rc = topology_set_cpu_management(val); | ||
399 | if (rc) | ||
400 | goto out; | ||
401 | cpu_management = val; | ||
402 | topology_expect_change(); | ||
403 | out: | ||
404 | mutex_unlock(&smp_cpu_state_mutex); | ||
405 | put_online_cpus(); | ||
406 | return rc ? rc : count; | ||
407 | } | ||
408 | static DEVICE_ATTR(dispatching, 0644, dispatching_show, | ||
409 | dispatching_store); | ||
410 | |||
411 | static ssize_t cpu_polarization_show(struct device *dev, | ||
412 | struct device_attribute *attr, char *buf) | ||
413 | { | ||
414 | int cpu = dev->id; | ||
415 | ssize_t count; | ||
416 | |||
417 | mutex_lock(&smp_cpu_state_mutex); | ||
418 | switch (cpu_read_polarization(cpu)) { | ||
419 | case POLARIZATION_HRZ: | ||
420 | count = sprintf(buf, "horizontal\n"); | ||
421 | break; | ||
422 | case POLARIZATION_VL: | ||
423 | count = sprintf(buf, "vertical:low\n"); | ||
424 | break; | ||
425 | case POLARIZATION_VM: | ||
426 | count = sprintf(buf, "vertical:medium\n"); | ||
427 | break; | ||
428 | case POLARIZATION_VH: | ||
429 | count = sprintf(buf, "vertical:high\n"); | ||
430 | break; | ||
431 | default: | ||
432 | count = sprintf(buf, "unknown\n"); | ||
433 | break; | ||
434 | } | ||
435 | mutex_unlock(&smp_cpu_state_mutex); | ||
436 | return count; | ||
437 | } | ||
438 | static DEVICE_ATTR(polarization, 0444, cpu_polarization_show, NULL); | ||
439 | |||
440 | static struct attribute *topology_cpu_attrs[] = { | ||
441 | &dev_attr_polarization.attr, | ||
442 | NULL, | ||
443 | }; | ||
444 | |||
445 | static struct attribute_group topology_cpu_attr_group = { | ||
446 | .attrs = topology_cpu_attrs, | ||
447 | }; | ||
448 | |||
449 | int topology_cpu_init(struct cpu *cpu) | ||
450 | { | ||
451 | return sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group); | ||
452 | } | ||
453 | |||
454 | static int __init topology_init(void) | ||
455 | { | ||
456 | if (!MACHINE_HAS_TOPOLOGY) { | ||
457 | topology_update_polarization_simple(); | ||
458 | goto out; | ||
459 | } | ||
460 | set_topology_timer(); | ||
461 | out: | ||
462 | update_cpu_core_map(); | ||
463 | return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching); | ||
464 | } | ||
465 | device_initcall(topology_init); | ||
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index a9807dd86276..5ce3750b181f 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -43,9 +43,9 @@ | |||
43 | #include <asm/debug.h> | 43 | #include <asm/debug.h> |
44 | #include "entry.h" | 44 | #include "entry.h" |
45 | 45 | ||
46 | void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long); | 46 | void (*pgm_check_table[128])(struct pt_regs *regs); |
47 | 47 | ||
48 | int show_unhandled_signals; | 48 | int show_unhandled_signals = 1; |
49 | 49 | ||
50 | #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) | 50 | #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) |
51 | 51 | ||
@@ -234,7 +234,7 @@ void show_regs(struct pt_regs *regs) | |||
234 | 234 | ||
235 | static DEFINE_SPINLOCK(die_lock); | 235 | static DEFINE_SPINLOCK(die_lock); |
236 | 236 | ||
237 | void die(const char * str, struct pt_regs * regs, long err) | 237 | void die(struct pt_regs *regs, const char *str) |
238 | { | 238 | { |
239 | static int die_counter; | 239 | static int die_counter; |
240 | 240 | ||
@@ -243,7 +243,7 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
243 | console_verbose(); | 243 | console_verbose(); |
244 | spin_lock_irq(&die_lock); | 244 | spin_lock_irq(&die_lock); |
245 | bust_spinlocks(1); | 245 | bust_spinlocks(1); |
246 | printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); | 246 | printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter); |
247 | #ifdef CONFIG_PREEMPT | 247 | #ifdef CONFIG_PREEMPT |
248 | printk("PREEMPT "); | 248 | printk("PREEMPT "); |
249 | #endif | 249 | #endif |
@@ -254,7 +254,7 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
254 | printk("DEBUG_PAGEALLOC"); | 254 | printk("DEBUG_PAGEALLOC"); |
255 | #endif | 255 | #endif |
256 | printk("\n"); | 256 | printk("\n"); |
257 | notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); | 257 | notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); |
258 | show_regs(regs); | 258 | show_regs(regs); |
259 | bust_spinlocks(0); | 259 | bust_spinlocks(0); |
260 | add_taint(TAINT_DIE); | 260 | add_taint(TAINT_DIE); |
@@ -267,8 +267,7 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
267 | do_exit(SIGSEGV); | 267 | do_exit(SIGSEGV); |
268 | } | 268 | } |
269 | 269 | ||
270 | static void inline report_user_fault(struct pt_regs *regs, long int_code, | 270 | static inline void report_user_fault(struct pt_regs *regs, int signr) |
271 | int signr) | ||
272 | { | 271 | { |
273 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) | 272 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) |
274 | return; | 273 | return; |
@@ -276,7 +275,7 @@ static void inline report_user_fault(struct pt_regs *regs, long int_code, | |||
276 | return; | 275 | return; |
277 | if (!printk_ratelimit()) | 276 | if (!printk_ratelimit()) |
278 | return; | 277 | return; |
279 | printk("User process fault: interruption code 0x%lX ", int_code); | 278 | printk("User process fault: interruption code 0x%X ", regs->int_code); |
280 | print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); | 279 | print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); |
281 | printk("\n"); | 280 | printk("\n"); |
282 | show_regs(regs); | 281 | show_regs(regs); |
@@ -287,19 +286,28 @@ int is_valid_bugaddr(unsigned long addr) | |||
287 | return 1; | 286 | return 1; |
288 | } | 287 | } |
289 | 288 | ||
290 | static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str, | 289 | static inline void __user *get_psw_address(struct pt_regs *regs) |
291 | struct pt_regs *regs, siginfo_t *info) | ||
292 | { | 290 | { |
293 | if (notify_die(DIE_TRAP, str, regs, pgm_int_code, | 291 | return (void __user *) |
294 | pgm_int_code, signr) == NOTIFY_STOP) | 292 | ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); |
293 | } | ||
294 | |||
295 | static void __kprobes do_trap(struct pt_regs *regs, | ||
296 | int si_signo, int si_code, char *str) | ||
297 | { | ||
298 | siginfo_t info; | ||
299 | |||
300 | if (notify_die(DIE_TRAP, str, regs, 0, | ||
301 | regs->int_code, si_signo) == NOTIFY_STOP) | ||
295 | return; | 302 | return; |
296 | 303 | ||
297 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 304 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
298 | struct task_struct *tsk = current; | 305 | info.si_signo = si_signo; |
299 | 306 | info.si_errno = 0; | |
300 | tsk->thread.trap_no = pgm_int_code & 0xffff; | 307 | info.si_code = si_code; |
301 | force_sig_info(signr, info, tsk); | 308 | info.si_addr = get_psw_address(regs); |
302 | report_user_fault(regs, pgm_int_code, signr); | 309 | force_sig_info(si_signo, &info, current); |
310 | report_user_fault(regs, si_signo); | ||
303 | } else { | 311 | } else { |
304 | const struct exception_table_entry *fixup; | 312 | const struct exception_table_entry *fixup; |
305 | fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); | 313 | fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); |
@@ -311,18 +319,11 @@ static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str, | |||
311 | btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs); | 319 | btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs); |
312 | if (btt == BUG_TRAP_TYPE_WARN) | 320 | if (btt == BUG_TRAP_TYPE_WARN) |
313 | return; | 321 | return; |
314 | die(str, regs, pgm_int_code); | 322 | die(regs, str); |
315 | } | 323 | } |
316 | } | 324 | } |
317 | } | 325 | } |
318 | 326 | ||
319 | static inline void __user *get_psw_address(struct pt_regs *regs, | ||
320 | long pgm_int_code) | ||
321 | { | ||
322 | return (void __user *) | ||
323 | ((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN); | ||
324 | } | ||
325 | |||
326 | void __kprobes do_per_trap(struct pt_regs *regs) | 327 | void __kprobes do_per_trap(struct pt_regs *regs) |
327 | { | 328 | { |
328 | siginfo_t info; | 329 | siginfo_t info; |
@@ -339,26 +340,19 @@ void __kprobes do_per_trap(struct pt_regs *regs) | |||
339 | force_sig_info(SIGTRAP, &info, current); | 340 | force_sig_info(SIGTRAP, &info, current); |
340 | } | 341 | } |
341 | 342 | ||
342 | static void default_trap_handler(struct pt_regs *regs, long pgm_int_code, | 343 | static void default_trap_handler(struct pt_regs *regs) |
343 | unsigned long trans_exc_code) | ||
344 | { | 344 | { |
345 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 345 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
346 | report_user_fault(regs, pgm_int_code, SIGSEGV); | 346 | report_user_fault(regs, SIGSEGV); |
347 | do_exit(SIGSEGV); | 347 | do_exit(SIGSEGV); |
348 | } else | 348 | } else |
349 | die("Unknown program exception", regs, pgm_int_code); | 349 | die(regs, "Unknown program exception"); |
350 | } | 350 | } |
351 | 351 | ||
352 | #define DO_ERROR_INFO(name, signr, sicode, str) \ | 352 | #define DO_ERROR_INFO(name, signr, sicode, str) \ |
353 | static void name(struct pt_regs *regs, long pgm_int_code, \ | 353 | static void name(struct pt_regs *regs) \ |
354 | unsigned long trans_exc_code) \ | ||
355 | { \ | 354 | { \ |
356 | siginfo_t info; \ | 355 | do_trap(regs, signr, sicode, str); \ |
357 | info.si_signo = signr; \ | ||
358 | info.si_errno = 0; \ | ||
359 | info.si_code = sicode; \ | ||
360 | info.si_addr = get_psw_address(regs, pgm_int_code); \ | ||
361 | do_trap(pgm_int_code, signr, str, regs, &info); \ | ||
362 | } | 356 | } |
363 | 357 | ||
364 | DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, | 358 | DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, |
@@ -388,42 +382,34 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, | |||
388 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, | 382 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, |
389 | "translation exception") | 383 | "translation exception") |
390 | 384 | ||
391 | static inline void do_fp_trap(struct pt_regs *regs, void __user *location, | 385 | static inline void do_fp_trap(struct pt_regs *regs, int fpc) |
392 | int fpc, long pgm_int_code) | ||
393 | { | 386 | { |
394 | siginfo_t si; | 387 | int si_code = 0; |
395 | |||
396 | si.si_signo = SIGFPE; | ||
397 | si.si_errno = 0; | ||
398 | si.si_addr = location; | ||
399 | si.si_code = 0; | ||
400 | /* FPC[2] is Data Exception Code */ | 388 | /* FPC[2] is Data Exception Code */ |
401 | if ((fpc & 0x00000300) == 0) { | 389 | if ((fpc & 0x00000300) == 0) { |
402 | /* bits 6 and 7 of DXC are 0 iff IEEE exception */ | 390 | /* bits 6 and 7 of DXC are 0 iff IEEE exception */ |
403 | if (fpc & 0x8000) /* invalid fp operation */ | 391 | if (fpc & 0x8000) /* invalid fp operation */ |
404 | si.si_code = FPE_FLTINV; | 392 | si_code = FPE_FLTINV; |
405 | else if (fpc & 0x4000) /* div by 0 */ | 393 | else if (fpc & 0x4000) /* div by 0 */ |
406 | si.si_code = FPE_FLTDIV; | 394 | si_code = FPE_FLTDIV; |
407 | else if (fpc & 0x2000) /* overflow */ | 395 | else if (fpc & 0x2000) /* overflow */ |
408 | si.si_code = FPE_FLTOVF; | 396 | si_code = FPE_FLTOVF; |
409 | else if (fpc & 0x1000) /* underflow */ | 397 | else if (fpc & 0x1000) /* underflow */ |
410 | si.si_code = FPE_FLTUND; | 398 | si_code = FPE_FLTUND; |
411 | else if (fpc & 0x0800) /* inexact */ | 399 | else if (fpc & 0x0800) /* inexact */ |
412 | si.si_code = FPE_FLTRES; | 400 | si_code = FPE_FLTRES; |
413 | } | 401 | } |
414 | do_trap(pgm_int_code, SIGFPE, | 402 | do_trap(regs, SIGFPE, si_code, "floating point exception"); |
415 | "floating point exception", regs, &si); | ||
416 | } | 403 | } |
417 | 404 | ||
418 | static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code, | 405 | static void __kprobes illegal_op(struct pt_regs *regs) |
419 | unsigned long trans_exc_code) | ||
420 | { | 406 | { |
421 | siginfo_t info; | 407 | siginfo_t info; |
422 | __u8 opcode[6]; | 408 | __u8 opcode[6]; |
423 | __u16 __user *location; | 409 | __u16 __user *location; |
424 | int signal = 0; | 410 | int signal = 0; |
425 | 411 | ||
426 | location = get_psw_address(regs, pgm_int_code); | 412 | location = get_psw_address(regs); |
427 | 413 | ||
428 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 414 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
429 | if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) | 415 | if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) |
@@ -467,44 +453,31 @@ static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code, | |||
467 | * If we get an illegal op in kernel mode, send it through the | 453 | * If we get an illegal op in kernel mode, send it through the |
468 | * kprobes notifier. If kprobes doesn't pick it up, SIGILL | 454 | * kprobes notifier. If kprobes doesn't pick it up, SIGILL |
469 | */ | 455 | */ |
470 | if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code, | 456 | if (notify_die(DIE_BPT, "bpt", regs, 0, |
471 | 3, SIGTRAP) != NOTIFY_STOP) | 457 | 3, SIGTRAP) != NOTIFY_STOP) |
472 | signal = SIGILL; | 458 | signal = SIGILL; |
473 | } | 459 | } |
474 | 460 | ||
475 | #ifdef CONFIG_MATHEMU | 461 | #ifdef CONFIG_MATHEMU |
476 | if (signal == SIGFPE) | 462 | if (signal == SIGFPE) |
477 | do_fp_trap(regs, location, | 463 | do_fp_trap(regs, current->thread.fp_regs.fpc); |
478 | current->thread.fp_regs.fpc, pgm_int_code); | 464 | else if (signal == SIGSEGV) |
479 | else if (signal == SIGSEGV) { | 465 | do_trap(regs, signal, SEGV_MAPERR, "user address fault"); |
480 | info.si_signo = signal; | 466 | else |
481 | info.si_errno = 0; | ||
482 | info.si_code = SEGV_MAPERR; | ||
483 | info.si_addr = (void __user *) location; | ||
484 | do_trap(pgm_int_code, signal, | ||
485 | "user address fault", regs, &info); | ||
486 | } else | ||
487 | #endif | 467 | #endif |
488 | if (signal) { | 468 | if (signal) |
489 | info.si_signo = signal; | 469 | do_trap(regs, signal, ILL_ILLOPC, "illegal operation"); |
490 | info.si_errno = 0; | ||
491 | info.si_code = ILL_ILLOPC; | ||
492 | info.si_addr = (void __user *) location; | ||
493 | do_trap(pgm_int_code, signal, | ||
494 | "illegal operation", regs, &info); | ||
495 | } | ||
496 | } | 470 | } |
497 | 471 | ||
498 | 472 | ||
499 | #ifdef CONFIG_MATHEMU | 473 | #ifdef CONFIG_MATHEMU |
500 | void specification_exception(struct pt_regs *regs, long pgm_int_code, | 474 | void specification_exception(struct pt_regs *regs) |
501 | unsigned long trans_exc_code) | ||
502 | { | 475 | { |
503 | __u8 opcode[6]; | 476 | __u8 opcode[6]; |
504 | __u16 __user *location = NULL; | 477 | __u16 __user *location = NULL; |
505 | int signal = 0; | 478 | int signal = 0; |
506 | 479 | ||
507 | location = (__u16 __user *) get_psw_address(regs, pgm_int_code); | 480 | location = (__u16 __user *) get_psw_address(regs); |
508 | 481 | ||
509 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 482 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
510 | get_user(*((__u16 *) opcode), location); | 483 | get_user(*((__u16 *) opcode), location); |
@@ -539,30 +512,21 @@ void specification_exception(struct pt_regs *regs, long pgm_int_code, | |||
539 | signal = SIGILL; | 512 | signal = SIGILL; |
540 | 513 | ||
541 | if (signal == SIGFPE) | 514 | if (signal == SIGFPE) |
542 | do_fp_trap(regs, location, | 515 | do_fp_trap(regs, current->thread.fp_regs.fpc); |
543 | current->thread.fp_regs.fpc, pgm_int_code); | 516 | else if (signal) |
544 | else if (signal) { | 517 | do_trap(regs, signal, ILL_ILLOPN, "specification exception"); |
545 | siginfo_t info; | ||
546 | info.si_signo = signal; | ||
547 | info.si_errno = 0; | ||
548 | info.si_code = ILL_ILLOPN; | ||
549 | info.si_addr = location; | ||
550 | do_trap(pgm_int_code, signal, | ||
551 | "specification exception", regs, &info); | ||
552 | } | ||
553 | } | 518 | } |
554 | #else | 519 | #else |
555 | DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, | 520 | DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, |
556 | "specification exception"); | 521 | "specification exception"); |
557 | #endif | 522 | #endif |
558 | 523 | ||
559 | static void data_exception(struct pt_regs *regs, long pgm_int_code, | 524 | static void data_exception(struct pt_regs *regs) |
560 | unsigned long trans_exc_code) | ||
561 | { | 525 | { |
562 | __u16 __user *location; | 526 | __u16 __user *location; |
563 | int signal = 0; | 527 | int signal = 0; |
564 | 528 | ||
565 | location = get_psw_address(regs, pgm_int_code); | 529 | location = get_psw_address(regs); |
566 | 530 | ||
567 | if (MACHINE_HAS_IEEE) | 531 | if (MACHINE_HAS_IEEE) |
568 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); | 532 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); |
@@ -627,32 +591,18 @@ static void data_exception(struct pt_regs *regs, long pgm_int_code, | |||
627 | else | 591 | else |
628 | signal = SIGILL; | 592 | signal = SIGILL; |
629 | if (signal == SIGFPE) | 593 | if (signal == SIGFPE) |
630 | do_fp_trap(regs, location, | 594 | do_fp_trap(regs, current->thread.fp_regs.fpc); |
631 | current->thread.fp_regs.fpc, pgm_int_code); | 595 | else if (signal) |
632 | else if (signal) { | 596 | do_trap(regs, signal, ILL_ILLOPN, "data exception"); |
633 | siginfo_t info; | ||
634 | info.si_signo = signal; | ||
635 | info.si_errno = 0; | ||
636 | info.si_code = ILL_ILLOPN; | ||
637 | info.si_addr = location; | ||
638 | do_trap(pgm_int_code, signal, "data exception", regs, &info); | ||
639 | } | ||
640 | } | 597 | } |
641 | 598 | ||
642 | static void space_switch_exception(struct pt_regs *regs, long pgm_int_code, | 599 | static void space_switch_exception(struct pt_regs *regs) |
643 | unsigned long trans_exc_code) | ||
644 | { | 600 | { |
645 | siginfo_t info; | ||
646 | |||
647 | /* Set user psw back to home space mode. */ | 601 | /* Set user psw back to home space mode. */ |
648 | if (regs->psw.mask & PSW_MASK_PSTATE) | 602 | if (regs->psw.mask & PSW_MASK_PSTATE) |
649 | regs->psw.mask |= PSW_ASC_HOME; | 603 | regs->psw.mask |= PSW_ASC_HOME; |
650 | /* Send SIGILL. */ | 604 | /* Send SIGILL. */ |
651 | info.si_signo = SIGILL; | 605 | do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event"); |
652 | info.si_errno = 0; | ||
653 | info.si_code = ILL_PRVOPC; | ||
654 | info.si_addr = get_psw_address(regs, pgm_int_code); | ||
655 | do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info); | ||
656 | } | 606 | } |
657 | 607 | ||
658 | void __kprobes kernel_stack_overflow(struct pt_regs * regs) | 608 | void __kprobes kernel_stack_overflow(struct pt_regs * regs) |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index a9a301866b3c..354dd39073ef 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -125,8 +125,7 @@ static inline int user_space_fault(unsigned long trans_exc_code) | |||
125 | return trans_exc_code != 3; | 125 | return trans_exc_code != 3; |
126 | } | 126 | } |
127 | 127 | ||
128 | static inline void report_user_fault(struct pt_regs *regs, long int_code, | 128 | static inline void report_user_fault(struct pt_regs *regs, long signr) |
129 | int signr, unsigned long address) | ||
130 | { | 129 | { |
131 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) | 130 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) |
132 | return; | 131 | return; |
@@ -134,10 +133,12 @@ static inline void report_user_fault(struct pt_regs *regs, long int_code, | |||
134 | return; | 133 | return; |
135 | if (!printk_ratelimit()) | 134 | if (!printk_ratelimit()) |
136 | return; | 135 | return; |
137 | printk("User process fault: interruption code 0x%lX ", int_code); | 136 | printk(KERN_ALERT "User process fault: interruption code 0x%X ", |
137 | regs->int_code); | ||
138 | print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); | 138 | print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); |
139 | printk("\n"); | 139 | printk(KERN_CONT "\n"); |
140 | printk("failing address: %lX\n", address); | 140 | printk(KERN_ALERT "failing address: %lX\n", |
141 | regs->int_parm_long & __FAIL_ADDR_MASK); | ||
141 | show_regs(regs); | 142 | show_regs(regs); |
142 | } | 143 | } |
143 | 144 | ||
@@ -145,24 +146,18 @@ static inline void report_user_fault(struct pt_regs *regs, long int_code, | |||
145 | * Send SIGSEGV to task. This is an external routine | 146 | * Send SIGSEGV to task. This is an external routine |
146 | * to keep the stack usage of do_page_fault small. | 147 | * to keep the stack usage of do_page_fault small. |
147 | */ | 148 | */ |
148 | static noinline void do_sigsegv(struct pt_regs *regs, long int_code, | 149 | static noinline void do_sigsegv(struct pt_regs *regs, int si_code) |
149 | int si_code, unsigned long trans_exc_code) | ||
150 | { | 150 | { |
151 | struct siginfo si; | 151 | struct siginfo si; |
152 | unsigned long address; | ||
153 | 152 | ||
154 | address = trans_exc_code & __FAIL_ADDR_MASK; | 153 | report_user_fault(regs, SIGSEGV); |
155 | current->thread.prot_addr = address; | ||
156 | current->thread.trap_no = int_code; | ||
157 | report_user_fault(regs, int_code, SIGSEGV, address); | ||
158 | si.si_signo = SIGSEGV; | 154 | si.si_signo = SIGSEGV; |
159 | si.si_code = si_code; | 155 | si.si_code = si_code; |
160 | si.si_addr = (void __user *) address; | 156 | si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); |
161 | force_sig_info(SIGSEGV, &si, current); | 157 | force_sig_info(SIGSEGV, &si, current); |
162 | } | 158 | } |
163 | 159 | ||
164 | static noinline void do_no_context(struct pt_regs *regs, long int_code, | 160 | static noinline void do_no_context(struct pt_regs *regs) |
165 | unsigned long trans_exc_code) | ||
166 | { | 161 | { |
167 | const struct exception_table_entry *fixup; | 162 | const struct exception_table_entry *fixup; |
168 | unsigned long address; | 163 | unsigned long address; |
@@ -178,55 +173,48 @@ static noinline void do_no_context(struct pt_regs *regs, long int_code, | |||
178 | * Oops. The kernel tried to access some bad page. We'll have to | 173 | * Oops. The kernel tried to access some bad page. We'll have to |
179 | * terminate things with extreme prejudice. | 174 | * terminate things with extreme prejudice. |
180 | */ | 175 | */ |
181 | address = trans_exc_code & __FAIL_ADDR_MASK; | 176 | address = regs->int_parm_long & __FAIL_ADDR_MASK; |
182 | if (!user_space_fault(trans_exc_code)) | 177 | if (!user_space_fault(regs->int_parm_long)) |
183 | printk(KERN_ALERT "Unable to handle kernel pointer dereference" | 178 | printk(KERN_ALERT "Unable to handle kernel pointer dereference" |
184 | " at virtual kernel address %p\n", (void *)address); | 179 | " at virtual kernel address %p\n", (void *)address); |
185 | else | 180 | else |
186 | printk(KERN_ALERT "Unable to handle kernel paging request" | 181 | printk(KERN_ALERT "Unable to handle kernel paging request" |
187 | " at virtual user address %p\n", (void *)address); | 182 | " at virtual user address %p\n", (void *)address); |
188 | 183 | ||
189 | die("Oops", regs, int_code); | 184 | die(regs, "Oops"); |
190 | do_exit(SIGKILL); | 185 | do_exit(SIGKILL); |
191 | } | 186 | } |
192 | 187 | ||
193 | static noinline void do_low_address(struct pt_regs *regs, long int_code, | 188 | static noinline void do_low_address(struct pt_regs *regs) |
194 | unsigned long trans_exc_code) | ||
195 | { | 189 | { |
196 | /* Low-address protection hit in kernel mode means | 190 | /* Low-address protection hit in kernel mode means |
197 | NULL pointer write access in kernel mode. */ | 191 | NULL pointer write access in kernel mode. */ |
198 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 192 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
199 | /* Low-address protection hit in user mode 'cannot happen'. */ | 193 | /* Low-address protection hit in user mode 'cannot happen'. */ |
200 | die ("Low-address protection", regs, int_code); | 194 | die (regs, "Low-address protection"); |
201 | do_exit(SIGKILL); | 195 | do_exit(SIGKILL); |
202 | } | 196 | } |
203 | 197 | ||
204 | do_no_context(regs, int_code, trans_exc_code); | 198 | do_no_context(regs); |
205 | } | 199 | } |
206 | 200 | ||
207 | static noinline void do_sigbus(struct pt_regs *regs, long int_code, | 201 | static noinline void do_sigbus(struct pt_regs *regs) |
208 | unsigned long trans_exc_code) | ||
209 | { | 202 | { |
210 | struct task_struct *tsk = current; | 203 | struct task_struct *tsk = current; |
211 | unsigned long address; | ||
212 | struct siginfo si; | 204 | struct siginfo si; |
213 | 205 | ||
214 | /* | 206 | /* |
215 | * Send a sigbus, regardless of whether we were in kernel | 207 | * Send a sigbus, regardless of whether we were in kernel |
216 | * or user mode. | 208 | * or user mode. |
217 | */ | 209 | */ |
218 | address = trans_exc_code & __FAIL_ADDR_MASK; | ||
219 | tsk->thread.prot_addr = address; | ||
220 | tsk->thread.trap_no = int_code; | ||
221 | si.si_signo = SIGBUS; | 210 | si.si_signo = SIGBUS; |
222 | si.si_errno = 0; | 211 | si.si_errno = 0; |
223 | si.si_code = BUS_ADRERR; | 212 | si.si_code = BUS_ADRERR; |
224 | si.si_addr = (void __user *) address; | 213 | si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); |
225 | force_sig_info(SIGBUS, &si, tsk); | 214 | force_sig_info(SIGBUS, &si, tsk); |
226 | } | 215 | } |
227 | 216 | ||
228 | static noinline void do_fault_error(struct pt_regs *regs, long int_code, | 217 | static noinline void do_fault_error(struct pt_regs *regs, int fault) |
229 | unsigned long trans_exc_code, int fault) | ||
230 | { | 218 | { |
231 | int si_code; | 219 | int si_code; |
232 | 220 | ||
@@ -238,24 +226,24 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code, | |||
238 | /* User mode accesses just cause a SIGSEGV */ | 226 | /* User mode accesses just cause a SIGSEGV */ |
239 | si_code = (fault == VM_FAULT_BADMAP) ? | 227 | si_code = (fault == VM_FAULT_BADMAP) ? |
240 | SEGV_MAPERR : SEGV_ACCERR; | 228 | SEGV_MAPERR : SEGV_ACCERR; |
241 | do_sigsegv(regs, int_code, si_code, trans_exc_code); | 229 | do_sigsegv(regs, si_code); |
242 | return; | 230 | return; |
243 | } | 231 | } |
244 | case VM_FAULT_BADCONTEXT: | 232 | case VM_FAULT_BADCONTEXT: |
245 | do_no_context(regs, int_code, trans_exc_code); | 233 | do_no_context(regs); |
246 | break; | 234 | break; |
247 | default: /* fault & VM_FAULT_ERROR */ | 235 | default: /* fault & VM_FAULT_ERROR */ |
248 | if (fault & VM_FAULT_OOM) { | 236 | if (fault & VM_FAULT_OOM) { |
249 | if (!(regs->psw.mask & PSW_MASK_PSTATE)) | 237 | if (!(regs->psw.mask & PSW_MASK_PSTATE)) |
250 | do_no_context(regs, int_code, trans_exc_code); | 238 | do_no_context(regs); |
251 | else | 239 | else |
252 | pagefault_out_of_memory(); | 240 | pagefault_out_of_memory(); |
253 | } else if (fault & VM_FAULT_SIGBUS) { | 241 | } else if (fault & VM_FAULT_SIGBUS) { |
254 | /* Kernel mode? Handle exceptions or die */ | 242 | /* Kernel mode? Handle exceptions or die */ |
255 | if (!(regs->psw.mask & PSW_MASK_PSTATE)) | 243 | if (!(regs->psw.mask & PSW_MASK_PSTATE)) |
256 | do_no_context(regs, int_code, trans_exc_code); | 244 | do_no_context(regs); |
257 | else | 245 | else |
258 | do_sigbus(regs, int_code, trans_exc_code); | 246 | do_sigbus(regs); |
259 | } else | 247 | } else |
260 | BUG(); | 248 | BUG(); |
261 | break; | 249 | break; |
@@ -273,12 +261,12 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code, | |||
273 | * 11 Page translation -> Not present (nullification) | 261 | * 11 Page translation -> Not present (nullification) |
274 | * 3b Region third trans. -> Not present (nullification) | 262 | * 3b Region third trans. -> Not present (nullification) |
275 | */ | 263 | */ |
276 | static inline int do_exception(struct pt_regs *regs, int access, | 264 | static inline int do_exception(struct pt_regs *regs, int access) |
277 | unsigned long trans_exc_code) | ||
278 | { | 265 | { |
279 | struct task_struct *tsk; | 266 | struct task_struct *tsk; |
280 | struct mm_struct *mm; | 267 | struct mm_struct *mm; |
281 | struct vm_area_struct *vma; | 268 | struct vm_area_struct *vma; |
269 | unsigned long trans_exc_code; | ||
282 | unsigned long address; | 270 | unsigned long address; |
283 | unsigned int flags; | 271 | unsigned int flags; |
284 | int fault; | 272 | int fault; |
@@ -288,6 +276,7 @@ static inline int do_exception(struct pt_regs *regs, int access, | |||
288 | 276 | ||
289 | tsk = current; | 277 | tsk = current; |
290 | mm = tsk->mm; | 278 | mm = tsk->mm; |
279 | trans_exc_code = regs->int_parm_long; | ||
291 | 280 | ||
292 | /* | 281 | /* |
293 | * Verify that the fault happened in user space, that | 282 | * Verify that the fault happened in user space, that |
@@ -387,45 +376,46 @@ out: | |||
387 | return fault; | 376 | return fault; |
388 | } | 377 | } |
389 | 378 | ||
390 | void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code, | 379 | void __kprobes do_protection_exception(struct pt_regs *regs) |
391 | unsigned long trans_exc_code) | ||
392 | { | 380 | { |
381 | unsigned long trans_exc_code; | ||
393 | int fault; | 382 | int fault; |
394 | 383 | ||
384 | trans_exc_code = regs->int_parm_long; | ||
395 | /* Protection exception is suppressing, decrement psw address. */ | 385 | /* Protection exception is suppressing, decrement psw address. */ |
396 | regs->psw.addr = __rewind_psw(regs->psw, pgm_int_code >> 16); | 386 | regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16); |
397 | /* | 387 | /* |
398 | * Check for low-address protection. This needs to be treated | 388 | * Check for low-address protection. This needs to be treated |
399 | * as a special case because the translation exception code | 389 | * as a special case because the translation exception code |
400 | * field is not guaranteed to contain valid data in this case. | 390 | * field is not guaranteed to contain valid data in this case. |
401 | */ | 391 | */ |
402 | if (unlikely(!(trans_exc_code & 4))) { | 392 | if (unlikely(!(trans_exc_code & 4))) { |
403 | do_low_address(regs, pgm_int_code, trans_exc_code); | 393 | do_low_address(regs); |
404 | return; | 394 | return; |
405 | } | 395 | } |
406 | fault = do_exception(regs, VM_WRITE, trans_exc_code); | 396 | fault = do_exception(regs, VM_WRITE); |
407 | if (unlikely(fault)) | 397 | if (unlikely(fault)) |
408 | do_fault_error(regs, 4, trans_exc_code, fault); | 398 | do_fault_error(regs, fault); |
409 | } | 399 | } |
410 | 400 | ||
411 | void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code, | 401 | void __kprobes do_dat_exception(struct pt_regs *regs) |
412 | unsigned long trans_exc_code) | ||
413 | { | 402 | { |
414 | int access, fault; | 403 | int access, fault; |
415 | 404 | ||
416 | access = VM_READ | VM_EXEC | VM_WRITE; | 405 | access = VM_READ | VM_EXEC | VM_WRITE; |
417 | fault = do_exception(regs, access, trans_exc_code); | 406 | fault = do_exception(regs, access); |
418 | if (unlikely(fault)) | 407 | if (unlikely(fault)) |
419 | do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault); | 408 | do_fault_error(regs, fault); |
420 | } | 409 | } |
421 | 410 | ||
422 | #ifdef CONFIG_64BIT | 411 | #ifdef CONFIG_64BIT |
423 | void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code, | 412 | void __kprobes do_asce_exception(struct pt_regs *regs) |
424 | unsigned long trans_exc_code) | ||
425 | { | 413 | { |
426 | struct mm_struct *mm = current->mm; | 414 | struct mm_struct *mm = current->mm; |
427 | struct vm_area_struct *vma; | 415 | struct vm_area_struct *vma; |
416 | unsigned long trans_exc_code; | ||
428 | 417 | ||
418 | trans_exc_code = regs->int_parm_long; | ||
429 | if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm)) | 419 | if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm)) |
430 | goto no_context; | 420 | goto no_context; |
431 | 421 | ||
@@ -440,12 +430,12 @@ void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code, | |||
440 | 430 | ||
441 | /* User mode accesses just cause a SIGSEGV */ | 431 | /* User mode accesses just cause a SIGSEGV */ |
442 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 432 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
443 | do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code); | 433 | do_sigsegv(regs, SEGV_MAPERR); |
444 | return; | 434 | return; |
445 | } | 435 | } |
446 | 436 | ||
447 | no_context: | 437 | no_context: |
448 | do_no_context(regs, pgm_int_code, trans_exc_code); | 438 | do_no_context(regs); |
449 | } | 439 | } |
450 | #endif | 440 | #endif |
451 | 441 | ||
@@ -459,14 +449,15 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) | |||
459 | regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT; | 449 | regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT; |
460 | regs.psw.addr = (unsigned long) __builtin_return_address(0); | 450 | regs.psw.addr = (unsigned long) __builtin_return_address(0); |
461 | regs.psw.addr |= PSW_ADDR_AMODE; | 451 | regs.psw.addr |= PSW_ADDR_AMODE; |
462 | uaddr &= PAGE_MASK; | 452 | regs.int_code = pgm_int_code; |
453 | regs.int_parm_long = (uaddr & PAGE_MASK) | 2; | ||
463 | access = write ? VM_WRITE : VM_READ; | 454 | access = write ? VM_WRITE : VM_READ; |
464 | fault = do_exception(®s, access, uaddr | 2); | 455 | fault = do_exception(®s, access); |
465 | if (unlikely(fault)) { | 456 | if (unlikely(fault)) { |
466 | if (fault & VM_FAULT_OOM) | 457 | if (fault & VM_FAULT_OOM) |
467 | return -EFAULT; | 458 | return -EFAULT; |
468 | else if (fault & VM_FAULT_SIGBUS) | 459 | else if (fault & VM_FAULT_SIGBUS) |
469 | do_sigbus(®s, pgm_int_code, uaddr); | 460 | do_sigbus(®s); |
470 | } | 461 | } |
471 | return fault ? -EFAULT : 0; | 462 | return fault ? -EFAULT : 0; |
472 | } | 463 | } |
@@ -509,7 +500,7 @@ int pfault_init(void) | |||
509 | .reserved = __PF_RES_FIELD }; | 500 | .reserved = __PF_RES_FIELD }; |
510 | int rc; | 501 | int rc; |
511 | 502 | ||
512 | if (!MACHINE_IS_VM || pfault_disable) | 503 | if (pfault_disable) |
513 | return -1; | 504 | return -1; |
514 | asm volatile( | 505 | asm volatile( |
515 | " diag %1,%0,0x258\n" | 506 | " diag %1,%0,0x258\n" |
@@ -530,7 +521,7 @@ void pfault_fini(void) | |||
530 | .refversn = 2, | 521 | .refversn = 2, |
531 | }; | 522 | }; |
532 | 523 | ||
533 | if (!MACHINE_IS_VM || pfault_disable) | 524 | if (pfault_disable) |
534 | return; | 525 | return; |
535 | asm volatile( | 526 | asm volatile( |
536 | " diag %0,0,0x258\n" | 527 | " diag %0,0,0x258\n" |
@@ -643,8 +634,6 @@ static int __init pfault_irq_init(void) | |||
643 | { | 634 | { |
644 | int rc; | 635 | int rc; |
645 | 636 | ||
646 | if (!MACHINE_IS_VM) | ||
647 | return 0; | ||
648 | rc = register_external_interrupt(0x2603, pfault_interrupt); | 637 | rc = register_external_interrupt(0x2603, pfault_interrupt); |
649 | if (rc) | 638 | if (rc) |
650 | goto out_extint; | 639 | goto out_extint; |
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index d4b9fb4d0042..5d633019d8f3 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c | |||
@@ -93,18 +93,22 @@ static unsigned long setup_zero_pages(void) | |||
93 | void __init paging_init(void) | 93 | void __init paging_init(void) |
94 | { | 94 | { |
95 | unsigned long max_zone_pfns[MAX_NR_ZONES]; | 95 | unsigned long max_zone_pfns[MAX_NR_ZONES]; |
96 | unsigned long pgd_type; | 96 | unsigned long pgd_type, asce_bits; |
97 | 97 | ||
98 | init_mm.pgd = swapper_pg_dir; | 98 | init_mm.pgd = swapper_pg_dir; |
99 | S390_lowcore.kernel_asce = __pa(init_mm.pgd) & PAGE_MASK; | ||
100 | #ifdef CONFIG_64BIT | 99 | #ifdef CONFIG_64BIT |
101 | /* A three level page table (4TB) is enough for the kernel space. */ | 100 | if (VMALLOC_END > (1UL << 42)) { |
102 | S390_lowcore.kernel_asce |= _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH; | 101 | asce_bits = _ASCE_TYPE_REGION2 | _ASCE_TABLE_LENGTH; |
103 | pgd_type = _REGION3_ENTRY_EMPTY; | 102 | pgd_type = _REGION2_ENTRY_EMPTY; |
103 | } else { | ||
104 | asce_bits = _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH; | ||
105 | pgd_type = _REGION3_ENTRY_EMPTY; | ||
106 | } | ||
104 | #else | 107 | #else |
105 | S390_lowcore.kernel_asce |= _ASCE_TABLE_LENGTH; | 108 | asce_bits = _ASCE_TABLE_LENGTH; |
106 | pgd_type = _SEGMENT_ENTRY_EMPTY; | 109 | pgd_type = _SEGMENT_ENTRY_EMPTY; |
107 | #endif | 110 | #endif |
111 | S390_lowcore.kernel_asce = (__pa(init_mm.pgd) & PAGE_MASK) | asce_bits; | ||
108 | clear_table((unsigned long *) init_mm.pgd, pgd_type, | 112 | clear_table((unsigned long *) init_mm.pgd, pgd_type, |
109 | sizeof(unsigned long)*2048); | 113 | sizeof(unsigned long)*2048); |
110 | vmem_map_init(); | 114 | vmem_map_init(); |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 301c84d3b542..9a4d02f64f16 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -33,17 +33,6 @@ | |||
33 | #define FRAG_MASK 0x03 | 33 | #define FRAG_MASK 0x03 |
34 | #endif | 34 | #endif |
35 | 35 | ||
36 | unsigned long VMALLOC_START = VMALLOC_END - VMALLOC_SIZE; | ||
37 | EXPORT_SYMBOL(VMALLOC_START); | ||
38 | |||
39 | static int __init parse_vmalloc(char *arg) | ||
40 | { | ||
41 | if (!arg) | ||
42 | return -EINVAL; | ||
43 | VMALLOC_START = (VMALLOC_END - memparse(arg, &arg)) & PAGE_MASK; | ||
44 | return 0; | ||
45 | } | ||
46 | early_param("vmalloc", parse_vmalloc); | ||
47 | 36 | ||
48 | unsigned long *crst_table_alloc(struct mm_struct *mm) | 37 | unsigned long *crst_table_alloc(struct mm_struct *mm) |
49 | { | 38 | { |
@@ -267,7 +256,10 @@ static int gmap_alloc_table(struct gmap *gmap, | |||
267 | struct page *page; | 256 | struct page *page; |
268 | unsigned long *new; | 257 | unsigned long *new; |
269 | 258 | ||
259 | /* since we dont free the gmap table until gmap_free we can unlock */ | ||
260 | spin_unlock(&gmap->mm->page_table_lock); | ||
270 | page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); | 261 | page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); |
262 | spin_lock(&gmap->mm->page_table_lock); | ||
271 | if (!page) | 263 | if (!page) |
272 | return -ENOMEM; | 264 | return -ENOMEM; |
273 | new = (unsigned long *) page_to_phys(page); | 265 | new = (unsigned long *) page_to_phys(page); |