Skip to content

Commit

Permalink
[S390] Improve address space mode selection.
Browse files Browse the repository at this point in the history
Introduce user_mode to replace the two variables switch_amode and
s390_noexec. There are three valid combinations of the old values:
  1) switch_amode == 0 && s390_noexec == 0
  2) switch_amode == 1 && s390_noexec == 0
  3) switch_amode == 1 && s390_noexec == 1
They get replaced by
  1) user_mode == HOME_SPACE_MODE
  2) user_mode == PRIMARY_SPACE_MODE
  3) user_mode == SECONDARY_SPACE_MODE
The new kernel parameter user_mode=[primary,secondary,home] lets
you choose the address space mode the user space processes should
use. In addition the CONFIG_S390_SWITCH_AMODE config option
is removed.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Martin Schwidefsky authored and Martin Schwidefsky committed Dec 7, 2009
1 parent 61365e1 commit b11b533
Show file tree
Hide file tree
Showing 11 changed files with 38 additions and 58 deletions.
15 changes: 0 additions & 15 deletions arch/s390/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -220,23 +220,8 @@ config AUDIT_ARCH
bool
default y

config S390_SWITCH_AMODE
bool "Switch kernel/user addressing modes"
help
This option allows to switch the addressing modes of kernel and user
space. The kernel parameter switch_amode=on will enable this feature,
default is disabled. Enabling this (via kernel parameter) on machines
earlier than IBM System z9-109 EC/BC will reduce system performance.

Note that this option will also be selected by selecting the execute
protection option below. Enabling the execute protection via the
noexec kernel parameter will also switch the addressing modes,
independent of the switch_amode kernel parameter.


config S390_EXEC_PROTECT
bool "Data execute protection"
select S390_SWITCH_AMODE
help
This option allows to enable a buffer overflow protection for user
space programs and it also selects the addressing mode option above.
Expand Down
1 change: 0 additions & 1 deletion arch/s390/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ CONFIG_HOTPLUG_CPU=y
CONFIG_COMPAT=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_AUDIT_ARCH=y
CONFIG_S390_SWITCH_AMODE=y
CONFIG_S390_EXEC_PROTECT=y

#
Expand Down
4 changes: 2 additions & 2 deletions arch/s390/include/asm/mmu_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ static inline int init_new_context(struct task_struct *tsk,
mm->context.has_pgste = 1;
mm->context.alloc_pgste = 1;
} else {
mm->context.noexec = s390_noexec;
mm->context.noexec = (user_mode == SECONDARY_SPACE_MODE);
mm->context.has_pgste = 0;
mm->context.alloc_pgste = 0;
}
Expand All @@ -58,7 +58,7 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
pgd_t *pgd = mm->pgd;

S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
if (switch_amode) {
if (user_mode != HOME_SPACE_MODE) {
/* Load primary space page table origin. */
pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd;
S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd);
Expand Down
3 changes: 2 additions & 1 deletion arch/s390/include/asm/pgalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
spin_lock_init(&mm->context.list_lock);
INIT_LIST_HEAD(&mm->context.crst_list);
INIT_LIST_HEAD(&mm->context.pgtable_list);
return (pgd_t *) crst_table_alloc(mm, s390_noexec);
return (pgd_t *)
crst_table_alloc(mm, user_mode == SECONDARY_SPACE_MODE);
}
#define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd)

Expand Down
17 changes: 6 additions & 11 deletions arch/s390/include/asm/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,12 @@ extern unsigned long memory_end;

void detect_memory_layout(struct mem_chunk chunk[]);

#ifdef CONFIG_S390_SWITCH_AMODE
extern unsigned int switch_amode;
#else
#define switch_amode (0)
#endif

#ifdef CONFIG_S390_EXEC_PROTECT
extern unsigned int s390_noexec;
#else
#define s390_noexec (0)
#endif
#define PRIMARY_SPACE_MODE 0
#define ACCESS_REGISTER_MODE 1
#define SECONDARY_SPACE_MODE 2
#define HOME_SPACE_MODE 3

extern unsigned int user_mode;

/*
* Machine features detected in head.S
Expand Down
36 changes: 20 additions & 16 deletions arch/s390/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,8 @@ static int __init early_parse_mem(char *p)
}
early_param("mem", early_parse_mem);

#ifdef CONFIG_S390_SWITCH_AMODE
unsigned int switch_amode = 0;
EXPORT_SYMBOL_GPL(switch_amode);
unsigned int user_mode = HOME_SPACE_MODE;
EXPORT_SYMBOL_GPL(user_mode);

static int set_amode_and_uaccess(unsigned long user_amode,
unsigned long user32_amode)
Expand Down Expand Up @@ -340,48 +339,53 @@ static int set_amode_and_uaccess(unsigned long user_amode,
*/
static int __init early_parse_switch_amode(char *p)
{
switch_amode = 1;
if (user_mode != SECONDARY_SPACE_MODE)
user_mode = PRIMARY_SPACE_MODE;
return 0;
}
early_param("switch_amode", early_parse_switch_amode);

#else /* CONFIG_S390_SWITCH_AMODE */
static inline int set_amode_and_uaccess(unsigned long user_amode,
unsigned long user32_amode)
static int __init early_parse_user_mode(char *p)
{
if (p && strcmp(p, "primary") == 0)
user_mode = PRIMARY_SPACE_MODE;
#ifdef CONFIG_S390_EXEC_PROTECT
else if (p && strcmp(p, "secondary") == 0)
user_mode = SECONDARY_SPACE_MODE;
#endif
else if (!p || strcmp(p, "home") == 0)
user_mode = HOME_SPACE_MODE;
else
return 1;
return 0;
}
#endif /* CONFIG_S390_SWITCH_AMODE */
early_param("user_mode", early_parse_user_mode);

#ifdef CONFIG_S390_EXEC_PROTECT
unsigned int s390_noexec = 0;
EXPORT_SYMBOL_GPL(s390_noexec);

/*
* Enable execute protection?
*/
static int __init early_parse_noexec(char *p)
{
if (!strncmp(p, "off", 3))
return 0;
switch_amode = 1;
s390_noexec = 1;
user_mode = SECONDARY_SPACE_MODE;
return 0;
}
early_param("noexec", early_parse_noexec);
#endif /* CONFIG_S390_EXEC_PROTECT */

static void setup_addressing_mode(void)
{
if (s390_noexec) {
if (user_mode == SECONDARY_SPACE_MODE) {
if (set_amode_and_uaccess(PSW_ASC_SECONDARY,
PSW32_ASC_SECONDARY))
pr_info("Execute protection active, "
"mvcos available\n");
else
pr_info("Execute protection active, "
"mvcos not available\n");
} else if (switch_amode) {
} else if (user_mode == PRIMARY_SPACE_MODE) {
if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY))
pr_info("Address spaces switched, "
"mvcos available\n");
Expand Down Expand Up @@ -411,7 +415,7 @@ setup_lowcore(void)
lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
lc->restart_psw.addr =
PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
if (switch_amode)
if (user_mode != HOME_SPACE_MODE)
lc->restart_psw.mask |= PSW_ASC_HOME;
lc->external_new_psw.mask = psw_kernel_bits;
lc->external_new_psw.addr =
Expand Down
9 changes: 5 additions & 4 deletions arch/s390/kernel/vdso.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ static void vdso_init_data(struct vdso_data *vd)
unsigned int facility_list;

facility_list = stfl();
vd->ectg_available = switch_amode && (facility_list & 1);
vd->ectg_available =
user_mode != HOME_SPACE_MODE && (facility_list & 1);
}

#ifdef CONFIG_64BIT
Expand Down Expand Up @@ -114,7 +115,7 @@ int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore)

lowcore->vdso_per_cpu_data = __LC_PASTE;

if (!switch_amode || !vdso_enabled)
if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
return 0;

segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER);
Expand Down Expand Up @@ -160,7 +161,7 @@ void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore)
unsigned long segment_table, page_table, page_frame;
u32 *psal, *aste;

if (!switch_amode || !vdso_enabled)
if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
return;

psal = (u32 *)(addr_t) lowcore->paste[4];
Expand All @@ -184,7 +185,7 @@ static void __vdso_init_cr5(void *dummy)

static void vdso_init_cr5(void)
{
if (switch_amode && vdso_enabled)
if (user_mode != HOME_SPACE_MODE && vdso_enabled)
on_each_cpu(__vdso_init_cr5, NULL, 1);
}
#endif /* CONFIG_64BIT */
Expand Down
1 change: 0 additions & 1 deletion arch/s390/kvm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ config KVM
depends on HAVE_KVM && EXPERIMENTAL
select PREEMPT_NOTIFIERS
select ANON_INODES
select S390_SWITCH_AMODE
---help---
Support hosting paravirtualized guest machines using the SIE
virtualization capability on the mainframe. This should work
Expand Down
4 changes: 0 additions & 4 deletions arch/s390/lib/uaccess_mvcos.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ static size_t clear_user_mvcos(size_t size, void __user *to)
return size;
}

#ifdef CONFIG_S390_SWITCH_AMODE
static size_t strnlen_user_mvcos(size_t count, const char __user *src)
{
char buf[256];
Expand Down Expand Up @@ -200,7 +199,6 @@ static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
} while ((len_str == len) && (done < count));
return done;
}
#endif /* CONFIG_S390_SWITCH_AMODE */

struct uaccess_ops uaccess_mvcos = {
.copy_from_user = copy_from_user_mvcos_check,
Expand All @@ -215,7 +213,6 @@ struct uaccess_ops uaccess_mvcos = {
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
};

#ifdef CONFIG_S390_SWITCH_AMODE
struct uaccess_ops uaccess_mvcos_switch = {
.copy_from_user = copy_from_user_mvcos,
.copy_from_user_small = copy_from_user_mvcos,
Expand All @@ -228,4 +225,3 @@ struct uaccess_ops uaccess_mvcos_switch = {
.futex_atomic_op = futex_atomic_op_pt,
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
};
#endif
4 changes: 2 additions & 2 deletions arch/s390/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ static inline int user_space_fault(unsigned long trans_exc_code)
if (trans_exc_code == 2)
/* Access via secondary space, set_fs setting decides */
return current->thread.mm_segment.ar4;
if (!switch_amode)
if (user_mode == HOME_SPACE_MODE)
/* User space if the access has been done via home space. */
return trans_exc_code == 3;
/*
Expand Down Expand Up @@ -168,7 +168,7 @@ static void do_no_context(struct pt_regs *regs, unsigned long error_code,
* terminate things with extreme prejudice.
*/
address = trans_exc_code & __FAIL_ADDR_MASK;
if (user_space_fault(trans_exc_code) == 0)
if (!user_space_fault(trans_exc_code))
printk(KERN_ALERT "Unable to handle kernel pointer dereference"
" at virtual kernel address %p\n", (void *)address);
else
Expand Down
2 changes: 1 addition & 1 deletion arch/s390/mm/pgtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ int s390_enable_sie(void)
struct mm_struct *mm, *old_mm;

/* Do we have switched amode? If no, we cannot do sie */
if (!switch_amode)
if (user_mode == HOME_SPACE_MODE)
return -EINVAL;

/* Do we have pgstes? if yes, we are done */
Expand Down

0 comments on commit b11b533

Please sign in to comment.