Commit 14bc84ce authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Martin Schwidefsky:
 "One additional new feature for 4.1, a new PRNG based on SHA-512 for
  the zcrypt driver.

  Two memory management related changes, the page table reallocation for
  KVM is removed, and with file ptes gone the encoding of page table
  entries is improved.

  And three bug fixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/zcrypt: Introduce new SHA-512 based Pseudo Random Generator.
  s390/mm: change swap pte encoding and pgtable cleanup
  s390/mm: correct transfer of dirty & young bits in __pmd_to_pte
  s390/bpf: add dependency to z196 features
  s390/3215: free memory in error path
  s390/kvm: remove delayed reallocation of page tables for KVM
  kexec: allocate the kexec control page with KEXEC_CONTROL_MEMORY_GFP
parents 2decb268 57127645
...@@ -115,7 +115,7 @@ config S390 ...@@ -115,7 +115,7 @@ config S390
select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_TRANSPARENT_HUGEPAGE select HAVE_ARCH_TRANSPARENT_HUGEPAGE
select HAVE_BPF_JIT if PACK_STACK && HAVE_MARCH_Z9_109_FEATURES select HAVE_BPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
select HAVE_CMPXCHG_DOUBLE select HAVE_CMPXCHG_DOUBLE
select HAVE_CMPXCHG_LOCAL select HAVE_CMPXCHG_LOCAL
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
......
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
* *
* Support for s390 cryptographic instructions. * Support for s390 cryptographic instructions.
* *
* Copyright IBM Corp. 2003, 2007 * Copyright IBM Corp. 2003, 2015
* Author(s): Thomas Spatzier * Author(s): Thomas Spatzier
* Jan Glauber (jan.glauber@de.ibm.com) * Jan Glauber (jan.glauber@de.ibm.com)
* Harald Freudenberger (freude@de.ibm.com)
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free * under the terms of the GNU General Public License as published by the Free
...@@ -28,15 +29,17 @@ ...@@ -28,15 +29,17 @@
#define CRYPT_S390_MSA 0x1 #define CRYPT_S390_MSA 0x1
#define CRYPT_S390_MSA3 0x2 #define CRYPT_S390_MSA3 0x2
#define CRYPT_S390_MSA4 0x4 #define CRYPT_S390_MSA4 0x4
#define CRYPT_S390_MSA5 0x8
/* s390 cryptographic operations */ /* s390 cryptographic operations */
enum crypt_s390_operations { enum crypt_s390_operations {
CRYPT_S390_KM = 0x0100, CRYPT_S390_KM = 0x0100,
CRYPT_S390_KMC = 0x0200, CRYPT_S390_KMC = 0x0200,
CRYPT_S390_KIMD = 0x0300, CRYPT_S390_KIMD = 0x0300,
CRYPT_S390_KLMD = 0x0400, CRYPT_S390_KLMD = 0x0400,
CRYPT_S390_KMAC = 0x0500, CRYPT_S390_KMAC = 0x0500,
CRYPT_S390_KMCTR = 0x0600 CRYPT_S390_KMCTR = 0x0600,
CRYPT_S390_PPNO = 0x0700
}; };
/* /*
...@@ -138,6 +141,16 @@ enum crypt_s390_kmac_func { ...@@ -138,6 +141,16 @@ enum crypt_s390_kmac_func {
KMAC_TDEA_192 = CRYPT_S390_KMAC | 3 KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
}; };
/*
* function codes for PPNO (PERFORM PSEUDORANDOM NUMBER
* OPERATION) instruction
*/
enum crypt_s390_ppno_func {
PPNO_QUERY = CRYPT_S390_PPNO | 0,
PPNO_SHA512_DRNG_GEN = CRYPT_S390_PPNO | 3,
PPNO_SHA512_DRNG_SEED = CRYPT_S390_PPNO | 0x83
};
/** /**
* crypt_s390_km: * crypt_s390_km:
* @func: the function code passed to KM; see crypt_s390_km_func * @func: the function code passed to KM; see crypt_s390_km_func
...@@ -162,11 +175,11 @@ static inline int crypt_s390_km(long func, void *param, ...@@ -162,11 +175,11 @@ static inline int crypt_s390_km(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */ "0: .insn rre,0xb92e0000,%3,%1\n" /* KM opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
...@@ -198,11 +211,11 @@ static inline int crypt_s390_kmc(long func, void *param, ...@@ -198,11 +211,11 @@ static inline int crypt_s390_kmc(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */ "0: .insn rre,0xb92f0000,%3,%1\n" /* KMC opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
...@@ -233,11 +246,11 @@ static inline int crypt_s390_kimd(long func, void *param, ...@@ -233,11 +246,11 @@ static inline int crypt_s390_kimd(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */ "0: .insn rre,0xb93e0000,%1,%1\n" /* KIMD opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len) : "=d" (ret), "+a" (__src), "+d" (__src_len)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
...@@ -267,11 +280,11 @@ static inline int crypt_s390_klmd(long func, void *param, ...@@ -267,11 +280,11 @@ static inline int crypt_s390_klmd(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */ "0: .insn rre,0xb93f0000,%1,%1\n" /* KLMD opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len) : "=d" (ret), "+a" (__src), "+d" (__src_len)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
...@@ -302,11 +315,11 @@ static inline int crypt_s390_kmac(long func, void *param, ...@@ -302,11 +315,11 @@ static inline int crypt_s390_kmac(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */ "0: .insn rre,0xb91e0000,%1,%1\n" /* KLAC opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len) : "=d" (ret), "+a" (__src), "+d" (__src_len)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
...@@ -340,11 +353,11 @@ static inline int crypt_s390_kmctr(long func, void *param, u8 *dest, ...@@ -340,11 +353,11 @@ static inline int crypt_s390_kmctr(long func, void *param, u8 *dest,
int ret = -1; int ret = -1;
asm volatile( asm volatile(
"0: .insn rrf,0xb92d0000,%3,%1,%4,0 \n" /* KMCTR opcode */ "0: .insn rrf,0xb92d0000,%3,%1,%4,0\n" /* KMCTR opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "+d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest), : "+d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest),
"+a" (__ctr) "+a" (__ctr)
: "d" (__func), "a" (__param) : "cc", "memory"); : "d" (__func), "a" (__param) : "cc", "memory");
...@@ -353,6 +366,47 @@ static inline int crypt_s390_kmctr(long func, void *param, u8 *dest, ...@@ -353,6 +366,47 @@ static inline int crypt_s390_kmctr(long func, void *param, u8 *dest,
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
} }
/**
* crypt_s390_ppno:
* @func: the function code passed to PPNO; see crypt_s390_ppno_func
* @param: address of parameter block; see POP for details on each func
* @dest: address of destination memory area
* @dest_len: size of destination memory area in bytes
* @seed: address of seed data
* @seed_len: size of seed data in bytes
*
* Executes the PPNO (PERFORM PSEUDORANDOM NUMBER OPERATION)
* operation of the CPU.
*
* Returns -1 for failure, 0 for the query func, number of random
* bytes stored in dest buffer for generate function
*/
static inline int crypt_s390_ppno(long func, void *param,
u8 *dest, long dest_len,
const u8 *seed, long seed_len)
{
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
register void *__param asm("1") = param; /* param block (240 bytes) */
register u8 *__dest asm("2") = dest; /* buf for recv random bytes */
register long __dest_len asm("3") = dest_len; /* requested random bytes */
register const u8 *__seed asm("4") = seed; /* buf with seed data */
register long __seed_len asm("5") = seed_len; /* bytes in seed buf */
int ret = -1;
asm volatile (
"0: .insn rre,0xb93c0000,%1,%5\n" /* PPNO opcode */
"1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n"
"2:\n"
EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "+d" (ret), "+a"(__dest), "+d"(__dest_len)
: "d"(__func), "a"(__param), "a"(__seed), "d"(__seed_len)
: "cc", "memory");
if (ret < 0)
return ret;
return (func & CRYPT_S390_FUNC_MASK) ? dest_len - __dest_len : 0;
}
/** /**
* crypt_s390_func_available: * crypt_s390_func_available:
* @func: the function code of the specific function; 0 if op in general * @func: the function code of the specific function; 0 if op in general
...@@ -373,6 +427,9 @@ static inline int crypt_s390_func_available(int func, ...@@ -373,6 +427,9 @@ static inline int crypt_s390_func_available(int func,
return 0; return 0;
if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77)) if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77))
return 0; return 0;
if (facility_mask & CRYPT_S390_MSA5 && !test_facility(57))
return 0;
switch (func & CRYPT_S390_OP_MASK) { switch (func & CRYPT_S390_OP_MASK) {
case CRYPT_S390_KM: case CRYPT_S390_KM:
ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0); ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
...@@ -390,8 +447,12 @@ static inline int crypt_s390_func_available(int func, ...@@ -390,8 +447,12 @@ static inline int crypt_s390_func_available(int func,
ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
break; break;
case CRYPT_S390_KMCTR: case CRYPT_S390_KMCTR:
ret = crypt_s390_kmctr(KMCTR_QUERY, &status, NULL, NULL, 0, ret = crypt_s390_kmctr(KMCTR_QUERY, &status,
NULL); NULL, NULL, 0, NULL);
break;
case CRYPT_S390_PPNO:
ret = crypt_s390_ppno(PPNO_QUERY, &status,
NULL, 0, NULL, 0);
break; break;
default: default:
return 0; return 0;
...@@ -419,15 +480,14 @@ static inline int crypt_s390_pcc(long func, void *param) ...@@ -419,15 +480,14 @@ static inline int crypt_s390_pcc(long func, void *param)
int ret = -1; int ret = -1;
asm volatile( asm volatile(
"0: .insn rre,0xb92c0000,0,0 \n" /* PCC opcode */ "0: .insn rre,0xb92c0000,0,0\n" /* PCC opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "+d" (ret) : "+d" (ret)
: "d" (__func), "a" (__param) : "cc", "memory"); : "d" (__func), "a" (__param) : "cc", "memory");
return ret; return ret;
} }
#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */ #endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */
This diff is collapsed.
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
/* Not more than 2GB */ /* Not more than 2GB */
#define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31) #define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31)
/* Allocate control page with GFP_DMA */
#define KEXEC_CONTROL_MEMORY_GFP GFP_DMA
/* Maximum address we can use for the crash control pages */ /* Maximum address we can use for the crash control pages */
#define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL) #define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL)
......
...@@ -14,7 +14,9 @@ typedef struct { ...@@ -14,7 +14,9 @@ typedef struct {
unsigned long asce_bits; unsigned long asce_bits;
unsigned long asce_limit; unsigned long asce_limit;
unsigned long vdso_base; unsigned long vdso_base;
/* The mmu context has extended page tables. */ /* The mmu context allocates 4K page tables. */
unsigned int alloc_pgste:1;
/* The mmu context uses extended page tables. */
unsigned int has_pgste:1; unsigned int has_pgste:1;
/* The mmu context uses storage keys. */ /* The mmu context uses storage keys. */
unsigned int use_skey:1; unsigned int use_skey:1;
......
...@@ -20,8 +20,11 @@ static inline int init_new_context(struct task_struct *tsk, ...@@ -20,8 +20,11 @@ static inline int init_new_context(struct task_struct *tsk,
mm->context.flush_mm = 0; mm->context.flush_mm = 0;
mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
mm->context.asce_bits |= _ASCE_TYPE_REGION3; mm->context.asce_bits |= _ASCE_TYPE_REGION3;
#ifdef CONFIG_PGSTE
mm->context.alloc_pgste = page_table_allocate_pgste;
mm->context.has_pgste = 0; mm->context.has_pgste = 0;
mm->context.use_skey = 0; mm->context.use_skey = 0;
#endif
mm->context.asce_limit = STACK_TOP_MAX; mm->context.asce_limit = STACK_TOP_MAX;
crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm)); crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
return 0; return 0;
......
...@@ -21,6 +21,7 @@ void crst_table_free(struct mm_struct *, unsigned long *); ...@@ -21,6 +21,7 @@ void crst_table_free(struct mm_struct *, unsigned long *);
unsigned long *page_table_alloc(struct mm_struct *); unsigned long *page_table_alloc(struct mm_struct *);
void page_table_free(struct mm_struct *, unsigned long *); void page_table_free(struct mm_struct *, unsigned long *);
void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long); void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long);
extern int page_table_allocate_pgste;
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned long key, bool nq); unsigned long key, bool nq);
......
This diff is collapsed.
...@@ -14,20 +14,23 @@ static inline pmd_t __pte_to_pmd(pte_t pte) ...@@ -14,20 +14,23 @@ static inline pmd_t __pte_to_pmd(pte_t pte)
/* /*
* Convert encoding pte bits pmd bits * Convert encoding pte bits pmd bits
* .IR...wrdytp dy..R...I...wr * lIR.uswrdy.p dy..R...I...wr
* empty .10...000000 -> 00..0...1...00 * empty 010.000000.0 -> 00..0...1...00
* prot-none, clean, old .11...000001 -> 00..1...1...00 * prot-none, clean, old 111.000000.1 -> 00..1...1...00
* prot-none, clean, young .11...000101 -> 01..1...1...00 * prot-none, clean, young 111.000001.1 -> 01..1...1...00
* prot-none, dirty, old .10...001001 -> 10..1...1...00 * prot-none, dirty, old 111.000010.1 -> 10..1...1...00
* prot-none, dirty, young .10...001101 -> 11..1...1...00 * prot-none, dirty, young 111.000011.1 -> 11..1...1...00
* read-only, clean, old .11...010001 -> 00..1...1...01 * read-only, clean, old 111.000100.1 -> 00..1...1...01
* read-only, clean, young .01...010101 -> 01..1...0...01 * read-only, clean, young 101.000101.1 -> 01..1...0...01
* read-only, dirty, old .11...011001 -> 10..1...1...01 * read-only, dirty, old 111.000110.1 -> 10..1...1...01
* read-only, dirty, young .01...011101 -> 11..1...0...01 * read-only, dirty, young 101.000111.1 -> 11..1...0...01
* read-write, clean, old .11...110001 -> 00..0...1...11 * read-write, clean, old 111.001100.1 -> 00..1...1...11
* read-write, clean, young .01...110101 -> 01..0...0...11 * read-write, clean, young 101.001101.1 -> 01..1...0...11
* read-write, dirty, old .10...111001 -> 10..0...1...11 * read-write, dirty, old 110.001110.1 -> 10..0...1...11
* read-write, dirty, young .00...111101 -> 11..0...0...11 * read-write, dirty, young 100.001111.1 -> 11..0...0...11
* HW-bits: R read-only, I invalid
* SW-bits: p present, y young, d dirty, r read, w write, s special,
* u unused, l large
*/ */
if (pte_present(pte)) { if (pte_present(pte)) {
pmd_val(pmd) = pte_val(pte) & PAGE_MASK; pmd_val(pmd) = pte_val(pte) & PAGE_MASK;
...@@ -48,20 +51,23 @@ static inline pte_t __pmd_to_pte(pmd_t pmd) ...@@ -48,20 +51,23 @@ static inline pte_t __pmd_to_pte(pmd_t pmd)
/* /*
* Convert encoding pmd bits pte bits * Convert encoding pmd bits pte bits
* dy..R...I...wr .IR...wrdytp * dy..R...I...wr lIR.uswrdy.p
* empty 00..0...1...00 -> .10...001100 * empty 00..0...1...00 -> 010.000000.0
* prot-none, clean, old 00..0...1...00 -> .10...000001 * prot-none, clean, old 00..1...1...00 -> 111.000000.1
* prot-none, clean, young 01..0...1...00 -> .10...000101 * prot-none, clean, young 01..1...1...00 -> 111.000001.1
* prot-none, dirty, old 10..0...1...00 -> .10...001001 * prot-none, dirty, old 10..1...1...00 -> 111.000010.1
* prot-none, dirty, young 11..0...1...00 -> .10...001101 * prot-none, dirty, young 11..1...1...00 -> 111.000011.1
* read-only, clean, old 00..1...1...01 -> .11...010001 * read-only, clean, old 00..1...1...01 -> 111.000100.1
* read-only, clean, young 01..1...1...01 -> .11...010101 * read-only, clean, young 01..1...0...01 -> 101.000101.1
* read-only, dirty, old 10..1...1...01 -> .11...011001 * read-only, dirty, old 10..1...1...01 -> 111.000110.1
* read-only, dirty, young 11..1...1...01 -> .11...011101 * read-only, dirty, young 11..1...0...01 -> 101.000111.1
* read-write, clean, old 00..0...1...11 -> .10...110001 * read-write, clean, old 00..1...1...11 -> 111.001100.1
* read-write, clean, young 01..0...1...11 -> .10...110101 * read-write, clean, young 01..1...0...11 -> 101.001101.1
* read-write, dirty, old 10..0...1...11 -> .10...111001 * read-write, dirty, old 10..0...1...11 -> 110.001110.1
* read-write, dirty, young 11..0...1...11 -> .10...111101 * read-write, dirty, young 11..0...0...11 -> 100.001111.1
* HW-bits: R read-only, I invalid
* SW-bits: p present, y young, d dirty, r read, w write, s special,
* u unused, l large
*/ */
if (pmd_present(pmd)) { if (pmd_present(pmd)) {
pte_val(pte) = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN_LARGE; pte_val(pte) = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN_LARGE;
...@@ -70,8 +76,8 @@ static inline pte_t __pmd_to_pte(pmd_t pmd) ...@@ -70,8 +76,8 @@ static inline pte_t __pmd_to_pte(pmd_t pmd)
pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) << 4; pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) << 4;
pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) << 5; pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) << 5;
pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT); pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT);
pmd_val(pmd) |= (pte_val(pte) & _PAGE_DIRTY) << 10; pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) >> 10;
pmd_val(pmd) |= (pte_val(pte) & _PAGE_YOUNG) << 10; pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) >> 10;
} else } else
pte_val(pte) = _PAGE_INVALID; pte_val(pte) = _PAGE_INVALID;
return pte; return pte;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/swapops.h> #include <linux/swapops.h>
#include <linux/sysctl.h>
#include <linux/ksm.h> #include <linux/ksm.h>
#include <linux/mman.h> #include <linux/mman.h>
...@@ -920,6 +921,40 @@ unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr) ...@@ -920,6 +921,40 @@ unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr)
} }
EXPORT_SYMBOL(get_guest_storage_key); EXPORT_SYMBOL(get_guest_storage_key);
static int page_table_allocate_pgste_min = 0;
static int page_table_allocate_pgste_max = 1;
int page_table_allocate_pgste = 0;
EXPORT_SYMBOL(page_table_allocate_pgste);
static struct ctl_table page_table_sysctl[] = {
{
.procname = "allocate_pgste",
.data = &page_table_allocate_pgste,
.maxlen = sizeof(int),
.mode = S_IRUGO | S_IWUSR,
.proc_handler = proc_dointvec,
.extra1 = &page_table_allocate_pgste_min,
.extra2 = &page_table_allocate_pgste_max,
},
{ }
};
static struct ctl_table page_table_sysctl_dir[] = {
{
.procname = "vm",
.maxlen = 0,
.mode = 0555,
.child = page_table_sysctl,
},
{ }
};
static int __init page_table_register_sysctl(void)
{
return register_sysctl_table(page_table_sysctl_dir) ? 0 : -ENOMEM;
}
__initcall(page_table_register_sysctl);
#else /* CONFIG_PGSTE */ #else /* CONFIG_PGSTE */
static inline int page_table_with_pgste(struct page *page) static inline int page_table_with_pgste(struct page *page)
...@@ -963,7 +998,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) ...@@ -963,7 +998,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
struct page *uninitialized_var(page); struct page *uninitialized_var(page);
unsigned int mask, bit; unsigned int mask, bit;
if (mm_has_pgste(mm)) if (mm_alloc_pgste(mm))
return page_table_alloc_pgste(mm); return page_table_alloc_pgste(mm);
/* Allocate fragments of a 4K page as 1K/2K page table */ /* Allocate fragments of a 4K page as 1K/2K page table */
spin_lock_bh(&mm->context.list_lock); spin_lock_bh(&mm->context.list_lock);
...@@ -1165,116 +1200,25 @@ static inline void thp_split_mm(struct mm_struct *mm) ...@@ -1165,116 +1200,25 @@ static inline void thp_split_mm(struct mm_struct *mm)
} }
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
static unsigned long page_table_realloc_pmd(struct mmu_gather *tlb,
struct mm_struct *mm, pud_t *pud,
unsigned long addr, unsigned long end)
{
unsigned long next, *table, *new;
struct page *page;
spinlock_t *ptl;
pmd_t *pmd;
pmd = pmd_offset(pud, addr);
do {
next = pmd_addr_end(addr, end);
again:
if (pmd_none_or_clear_bad(pmd))
continue;
table = (unsigned long *) pmd_deref(*pmd);
page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
if (page_table_with_pgste(page))
continue;
/* Allocate new page table with pgstes */
new = page_table_alloc_pgste(mm);
if (!new)
return -ENOMEM;
ptl = pmd_lock(mm, pmd);
if (likely((unsigned long *) pmd_deref(*pmd) == table)) {
/* Nuke pmd entry pointing to the "short" page table */
pmdp_flush_lazy(mm, addr, pmd);
pmd_clear(pmd);
/* Copy ptes from old table to new table */
memcpy(new, table, PAGE_SIZE/2);
clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
/* Establish new table */
pmd_populate(mm, pmd, (pte_t *) new);
/* Free old table with rcu, there might be a walker! */
page_table_free_rcu(tlb, table, addr);
new = NULL;
}
spin_unlock(ptl);
if (new) {
page_table_free_pgste(new);
goto again;
}
} while (pmd++, addr = next, addr != end);
return addr;
}
static unsigned long page_table_realloc_pud(struct mmu_gather *tlb,
struct mm_struct *mm, pgd_t *pgd,
unsigned long addr, unsigned long end)
{
unsigned long next;
pud_t *pud;
pud = pud_offset(pgd, addr);
do {
next = pud_addr_end(addr, end);
if (pud_none_or_clear_bad(pud))
continue;
next = page_table_realloc_pmd(tlb, mm, pud, addr, next);
if (unlikely(IS_ERR_VALUE(next)))
return next;
} while (pud++, addr = next, addr != end);
return addr;
}
static unsigned long page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
unsigned long addr, unsigned long end)
{
unsigned long next;
pgd_t *pgd;
pgd = pgd_offset(mm, addr);
do {
next = pgd_addr_end(addr, end);
if (pgd_none_or_clear_bad(pgd))
continue;
next = page_table_realloc_pud(tlb, mm, pgd, addr, next);
if (unlikely(IS_ERR_VALUE(next)))
return next;
} while (pgd++, addr = next, addr != end);
return 0;
}
/* /*
* switch on pgstes for its userspace process (for kvm) * switch on pgstes for its userspace process (for kvm)
*/ */
int s390_enable_sie(void) int s390_enable_sie(void)
{ {
struct task_struct *tsk = current; struct mm_struct *mm = current->mm;
struct mm_struct *mm = tsk->mm;
struct mmu_gather tlb;
/* Do we have pgstes? if yes, we are done */ /* Do we have pgstes? if yes, we are done */
if (mm_has_pgste(tsk->mm)) if (mm_has_pgste(mm))
return 0; return 0;
/* Fail if the page tables are 2K */
if (!mm_alloc_pgste(mm))
return -EINVAL;
down_write(&mm->mmap_sem); down_write(&mm->mmap_sem);
mm->context.has_pgste = 1;
/* split thp mappings and disable thp for future mappings */ /* split thp mappings and disable thp for future mappings */
thp_split_mm(mm); thp_split_mm(mm);
/* Reallocate the page tables with pgstes */
tlb_gather_mmu(&tlb, mm, 0, TASK_SIZE);
if (!page_table_realloc(&tlb, mm, 0, TASK_SIZE))
mm->context.has_pgste = 1;
tlb_finish_mmu(&tlb, 0, TASK_SIZE);
up_write(&mm->mmap_sem); up_write(&mm->mmap_sem);
return mm->context.has_pgste ? 0 : -ENOMEM; return 0;
} }
EXPORT_SYMBOL_GPL(s390_enable_sie); EXPORT_SYMBOL_GPL(s390_enable_sie);
......
...@@ -667,6 +667,8 @@ static struct raw3215_info *raw3215_alloc_info(void) ...@@ -667,6 +667,8 @@ static struct raw3215_info *raw3215_alloc_info(void)
info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA); info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
if (!info->buffer || !info->inbuf) { if (!info->buffer || !info->inbuf) {
kfree(info->inbuf);
kfree(info->buffer);
kfree(info); kfree(info);
return NULL; return NULL;
} }
......
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
#error KEXEC_CONTROL_MEMORY_LIMIT not defined #error KEXEC_CONTROL_MEMORY_LIMIT not defined
#endif #endif
#ifndef KEXEC_CONTROL_MEMORY_GFP
#define KEXEC_CONTROL_MEMORY_GFP GFP_KERNEL
#endif
#ifndef KEXEC_CONTROL_PAGE_SIZE #ifndef KEXEC_CONTROL_PAGE_SIZE
#error KEXEC_CONTROL_PAGE_SIZE not defined #error KEXEC_CONTROL_PAGE_SIZE not defined
#endif #endif
......
...@@ -707,7 +707,7 @@ static struct page *kimage_alloc_normal_control_pages(struct kimage *image, ...@@ -707,7 +707,7 @@ static struct page *kimage_alloc_normal_control_pages(struct kimage *image,
do { do {
unsigned long pfn, epfn, addr, eaddr; unsigned long pfn, epfn, addr, eaddr;
pages = kimage_alloc_pages(GFP_KERNEL, order); pages = kimage_alloc_pages(KEXEC_CONTROL_MEMORY_GFP, order);
if (!pages) if (!pages)
break; break;
pfn = page_to_pfn(pages); pfn = page_to_pfn(pages);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment