diff options
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/dis.c | 123 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 12 | ||||
-rw-r--r-- | arch/s390/kernel/guarded_storage.c | 7 | ||||
-rw-r--r-- | arch/s390/kernel/perf_cpum_sf.c | 5 | ||||
-rw-r--r-- | arch/s390/kernel/process.c | 17 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 142 | ||||
-rw-r--r-- | arch/s390/kernel/runtime_instr.c | 42 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 14 | ||||
-rw-r--r-- | arch/s390/kernel/topology.c | 191 |
11 files changed, 465 insertions, 92 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 1fefb7f9216f..7b742ffac7d3 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -33,6 +33,8 @@ AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH) AFLAGS_head.o += -march=z900 endif +CFLAGS_als.o += -D__NO_FORTIFY + # # Passing null pointers is ok for smp code, since we access the lowcore here. # diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index f7e82302a71e..94e96a7bd6d8 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -78,6 +78,7 @@ enum { U8_8, /* 8 bit unsigned value starting at 8 */ U8_16, /* 8 bit unsigned value starting at 16 */ U8_24, /* 8 bit unsigned value starting at 24 */ + U8_28, /* 8 bit unsigned value starting at 28 */ U8_32, /* 8 bit unsigned value starting at 32 */ I8_8, /* 8 bit signed value starting at 8 */ I8_16, /* 8 bit signed value starting at 16 */ @@ -113,7 +114,7 @@ enum { INSTR_MII_UPI, INSTR_RIE_R0IU, INSTR_RIE_R0UU, INSTR_RIE_RRP, INSTR_RIE_RRPU, INSTR_RIE_RRUUU, INSTR_RIE_RUPI, INSTR_RIE_RUPU, INSTR_RIE_RRI0, - INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, INSTR_RIL_UP, + INSTR_RIE_RUI0, INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, INSTR_RIL_UP, INSTR_RIS_R0RDU, INSTR_RIS_R0UU, INSTR_RIS_RURDI, INSTR_RIS_RURDU, INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP, INSTR_RRE_00, INSTR_RRE_0R, INSTR_RRE_AA, INSTR_RRE_AR, INSTR_RRE_F0, @@ -130,7 +131,7 @@ enum { INSTR_RSI_RRP, INSTR_RSL_LRDFU, INSTR_RSL_R0RD, INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD, - INSTR_RSY_RDRM, INSTR_RSY_RMRD, + INSTR_RSY_RURD2, INSTR_RSY_RDRM, INSTR_RSY_RMRD, INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD, INSTR_RS_RURD, INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM, @@ -157,6 +158,10 @@ enum { INSTR_VRS_RVRDM, INSTR_VRV_VVRDM, INSTR_VRV_VWRDM, INSTR_VRX_VRRDM, INSTR_VRX_VRRD0, + INSTR_VSI_URDV, INSTR_VRS_RRDV, INSTR_VRI_V0UU2, INSTR_VRR_RV0U, + INSTR_VRI_VR0UU, INSTR_VRI_VVUUU2, INSTR_VRR_0V, INSTR_VRI_VVV0UU2, + INSTR_VRR_0VV0U, INSTR_VRR_VVV, INSTR_VRR_VVVU0UV, + INSTR_VRR_VVVUU0V, INSTR_VRR_VVV0UUU, }; static const struct s390_operand operands[] = @@ -207,6 +212,7 @@ static const struct s390_operand operands[] = [U8_8] = { 8, 8, 0 }, [U8_16] = { 8, 16, 0 }, [U8_24] = { 8, 24, 0 }, + [U8_28] = { 8, 28, 0 }, [U8_32] = { 8, 32, 0 }, [J12_12] = { 12, 12, OPERAND_PCREL }, [I8_8] = { 8, 8, OPERAND_SIGNED }, @@ -241,6 +247,7 @@ static const unsigned char formats[][7] = { [INSTR_RIE_RRPU] = { 0xff, R_8,R_12,U4_32,J16_16,0,0 }, [INSTR_RIE_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, [INSTR_RIE_RRUUU] = { 0xff, R_8,R_12,U8_16,U8_24,U8_32,0 }, + [INSTR_RIE_RUI0] = { 0xff, R_8,I16_16,U4_12,0,0,0 }, [INSTR_RIE_RUPI] = { 0xff, R_8,I8_32,U4_12,J16_16,0,0 }, [INSTR_RIE_RUPU] = { 0xff, R_8,U8_32,U4_12,J16_16,0,0 }, [INSTR_RIL_RI] = { 0x0f, R_8,I32_16,0,0,0,0 }, @@ -295,7 +302,7 @@ static const unsigned char formats[][7] = { [INSTR_RSE_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, [INSTR_RSE_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, [INSTR_RSI_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, - [INSTR_RSL_LRDFU] = { 0xff, F_32,D_20,L4_8,B_16,U4_36,0 }, + [INSTR_RSL_LRDFU] = { 0xff, F_32,D_20,L8_8,B_16,U4_36,0 }, [INSTR_RSL_R0RD] = { 0xff, D_20,L4_8,B_16,0,0,0 }, [INSTR_RSY_AARD] = { 0xff, A_8,A_12,D20_20,B_16,0,0 }, [INSTR_RSY_CCRD] = { 0xff, C_8,C_12,D20_20,B_16,0,0 }, @@ -303,6 +310,7 @@ static const unsigned char formats[][7] = { [INSTR_RSY_RMRD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 }, [INSTR_RSY_RRRD] = { 0xff, R_8,R_12,D20_20,B_16,0,0 }, [INSTR_RSY_RURD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 }, + [INSTR_RSY_RURD2] = { 0xff, R_8,D20_20,B_16,U4_12,0,0 }, [INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 }, [INSTR_RS_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, [INSTR_RS_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, @@ -366,6 +374,19 @@ static const unsigned char formats[][7] = { [INSTR_VRV_VWRDM] = { 0xff, V_8,D_20,W_12,B_16,M_32,0 }, [INSTR_VRX_VRRDM] = { 0xff, V_8,D_20,X_12,B_16,M_32,0 }, [INSTR_VRX_VRRD0] = { 0xff, V_8,D_20,X_12,B_16,0,0 }, + [INSTR_VRI_V0UU2] = {0xff, V_8,U16_16,U4_32,0,0,0 }, + [INSTR_VRI_VR0UU] = {0xff, V_8,V_12,U8_28,U8_16,U4_24,0 }, + [INSTR_VRI_VVUUU2]= {0xff, V_8,V_12,U8_28,U8_16,U4_24,0 }, + [INSTR_VRI_VVV0UU2]= {0xff, V_8,V_12,V_16,U8_28,U4_24,0 }, + [INSTR_VRR_0VV0U] = {0xff, V_12,V_16,U4_24,0,0,0 }, + [INSTR_VRR_0V] = {0xff, V_12,0,0,0,0,0 }, + [INSTR_VRR_RV0U] = {0xff, R_8,V_12,U4_24,0,0,0 }, + [INSTR_VRR_VVV0UUU]= {0xff, V_8,V_12,V_16,U4_32,U4_28,U4_24 }, + [INSTR_VRR_VVVU0UV]= {0xff, V_8,V_12,V_16,V_32,U4_28,U4_20 }, + [INSTR_VRR_VVVUU0V]= {0xff, V_8,V_12,V_16,V_32,U4_20,U4_24 }, + [INSTR_VRR_VVV] = {0xff, V_8,V_12,V_16,0,0,0 }, + [INSTR_VRS_RRDV] = {0xff, V_32,R_12,D_20,B_16,0,0 }, + [INSTR_VSI_URDV] = {0xff, V_32,D_20,B_16,U8_8,0,0 }, }; enum { @@ -425,6 +446,10 @@ enum { LONG_INSN_LLGFRL, LONG_INSN_LLGHRL, LONG_INSN_LLGTAT, + LONG_INSN_LLZRGF, + LONG_INSN_LOCFHR, + LONG_INSN_LOCGHI, + LONG_INSN_LOCHHI, LONG_INSN_POPCNT, LONG_INSN_RIEMIT, LONG_INSN_RINEXT, @@ -433,6 +458,7 @@ enum { LONG_INSN_RISBLG, LONG_INSN_SLHHHR, LONG_INSN_SLHHLR, + LONG_INSN_STOCFH, LONG_INSN_TABORT, LONG_INSN_TBEGIN, LONG_INSN_TBEGINC, @@ -445,7 +471,11 @@ enum { LONG_INSN_VESRAV, LONG_INSN_VESRLV, LONG_INSN_VSBCBI, - LONG_INSN_STCCTM + LONG_INSN_STCCTM, + LONG_INSN_MSGRKC, + LONG_INSN_LLGFSG, + LONG_INSN_VSTRLR, + LONG_INSN_VBPERM, }; static char *long_insn_name[] = { @@ -505,6 +535,7 @@ static char *long_insn_name[] = { [LONG_INSN_LLGFRL] = "llgfrl", [LONG_INSN_LLGHRL] = "llghrl", [LONG_INSN_LLGTAT] = "llgtat", + [LONG_INSN_LLZRGF] = "llzrgf", [LONG_INSN_POPCNT] = "popcnt", [LONG_INSN_RIEMIT] = "riemit", [LONG_INSN_RINEXT] = "rinext", @@ -526,6 +557,14 @@ static char *long_insn_name[] = { [LONG_INSN_VESRLV] = "vesrlv", [LONG_INSN_VSBCBI] = "vsbcbi", [LONG_INSN_STCCTM] = "stcctm", + [LONG_INSN_LOCFHR] = "locfhr", + [LONG_INSN_LOCGHI] = "locghi", + [LONG_INSN_LOCHHI] = "lochhi", + [LONG_INSN_STOCFH] = "stocfh", + [LONG_INSN_MSGRKC] = "msgrkc", + [LONG_INSN_LLGFSG] = "llgfsg", + [LONG_INSN_VSTRLR] = "vstrlr", + [LONG_INSN_VBPERM] = "vbperm", }; static struct s390_insn opcode[] = { @@ -865,6 +904,7 @@ static struct s390_insn opcode_b2[] = { { "msr", 0x52, INSTR_RRE_RR }, { "mvpg", 0x54, INSTR_RRE_RR }, { "mvst", 0x55, INSTR_RRE_RR }, + { "sthyi", 0x56, INSTR_RRE_RR }, { "cuse", 0x57, INSTR_RRE_RR }, { "bsg", 0x58, INSTR_RRE_RR }, { "bsa", 0x5a, INSTR_RRE_RR }, @@ -1054,12 +1094,6 @@ static struct s390_insn opcode_b3[] = { { "fidr", 0x7f, INSTR_RRE_FF }, { "sfpc", 0x84, INSTR_RRE_RR_OPT }, { "efpc", 0x8c, INSTR_RRE_RR_OPT }, - { "cefbr", 0x94, INSTR_RRE_RF }, - { "cdfbr", 0x95, INSTR_RRE_RF }, - { "cxfbr", 0x96, INSTR_RRE_RF }, - { "cfebr", 0x98, INSTR_RRF_U0RF }, - { "cfdbr", 0x99, INSTR_RRF_U0RF }, - { "cfxbr", 0x9a, INSTR_RRF_U0RF }, { "cefr", 0xb4, INSTR_RRE_FR }, { "cdfr", 0xb5, INSTR_RRE_FR }, { "cxfr", 0xb6, INSTR_RRE_FR }, @@ -1104,8 +1138,10 @@ static struct s390_insn opcode_b9[] = { { "sturg", 0x25, INSTR_RRE_RR }, { "lbr", 0x26, INSTR_RRE_RR }, { "lhr", 0x27, INSTR_RRE_RR }, + { "kma", 0x29, INSTR_RRF_R0RR }, { "cgfr", 0x30, INSTR_RRE_RR }, { "clgfr", 0x31, INSTR_RRE_RR }, + { "ppno", 0x3c, INSTR_RRE_RR }, { "cfdtr", 0x41, INSTR_RRF_UURF }, { { 0, LONG_INSN_CLGDTR }, 0x42, INSTR_RRF_UURF }, { { 0, LONG_INSN_CLFDTR }, 0x43, INSTR_RRF_UURF }, @@ -1165,6 +1201,7 @@ static struct s390_insn opcode_b9[] = { { { 0, LONG_INSN_SLHHLR }, 0xdb, INSTR_RRF_R0RR2 }, { "chlr", 0xdd, INSTR_RRE_RR }, { "clhlr", 0xdf, INSTR_RRE_RR }, + { { 0, LONG_INSN_LOCFHR }, 0xe0, INSTR_RRF_U0RR }, { { 0, LONG_INSN_POPCNT }, 0xe1, INSTR_RRE_RR }, { "locgr", 0xe2, INSTR_RRF_M0RR }, { "ngrk", 0xe4, INSTR_RRF_R0RR2 }, @@ -1174,6 +1211,8 @@ static struct s390_insn opcode_b9[] = { { "sgrk", 0xe9, INSTR_RRF_R0RR2 }, { "algrk", 0xea, INSTR_RRF_R0RR2 }, { "slgrk", 0xeb, INSTR_RRF_R0RR2 }, + { "mgrk", 0xec, INSTR_RRF_R0RR2 }, + { { 0, LONG_INSN_MSGRKC }, 0xed, INSTR_RRF_R0RR2 }, { "locr", 0xf2, INSTR_RRF_M0RR }, { "nrk", 0xf4, INSTR_RRF_R0RR2 }, { "ork", 0xf6, INSTR_RRF_R0RR2 }, @@ -1182,6 +1221,7 @@ static struct s390_insn opcode_b9[] = { { "srk", 0xf9, INSTR_RRF_R0RR2 }, { "alrk", 0xfa, INSTR_RRF_R0RR2 }, { "slrk", 0xfb, INSTR_RRF_R0RR2 }, + { "msrkc", 0xfd, INSTR_RRF_R0RR2 }, { "kmac", 0x1e, INSTR_RRE_RR }, { "lrvr", 0x1f, INSTR_RRE_RR }, { "km", 0x2e, INSTR_RRE_RR }, @@ -1314,6 +1354,7 @@ static struct s390_insn opcode_e3[] = { { "stg", 0x24, INSTR_RXY_RRRD }, { "ntstg", 0x25, INSTR_RXY_RRRD }, { "cvdy", 0x26, INSTR_RXY_RRRD }, + { "lzrg", 0x2a, INSTR_RXY_RRRD }, { "cvdg", 0x2e, INSTR_RXY_RRRD }, { "strvg", 0x2f, INSTR_RXY_RRRD }, { "cgf", 0x30, INSTR_RXY_RRRD }, @@ -1321,10 +1362,21 @@ static struct s390_insn opcode_e3[] = { { "ltgf", 0x32, INSTR_RXY_RRRD }, { "cgh", 0x34, INSTR_RXY_RRRD }, { "pfd", 0x36, INSTR_RXY_URRD }, + { "agh", 0x38, INSTR_RXY_RRRD }, + { "sgh", 0x39, INSTR_RXY_RRRD }, + { { 0, LONG_INSN_LLZRGF }, 0x3a, INSTR_RXY_RRRD }, + { "lzrf", 0x3b, INSTR_RXY_RRRD }, + { "mgh", 0x3c, INSTR_RXY_RRRD }, { "strvh", 0x3f, INSTR_RXY_RRRD }, { "bctg", 0x46, INSTR_RXY_RRRD }, + { "bic", 0x47, INSTR_RXY_URRD }, + { { 0, LONG_INSN_LLGFSG }, 0x48, INSTR_RXY_RRRD }, + { "stgsc", 0x49, INSTR_RXY_RRRD }, + { "lgg", 0x4c, INSTR_RXY_RRRD }, + { "lgsc", 0x4d, INSTR_RXY_RRRD }, { "sty", 0x50, INSTR_RXY_RRRD }, { "msy", 0x51, INSTR_RXY_RRRD }, + { "msc", 0x53, INSTR_RXY_RRRD }, { "ny", 0x54, INSTR_RXY_RRRD }, { "cly", 0x55, INSTR_RXY_RRRD }, { "oy", 0x56, INSTR_RXY_RRRD }, @@ -1351,6 +1403,8 @@ static struct s390_insn opcode_e3[] = { { "ng", 0x80, INSTR_RXY_RRRD }, { "og", 0x81, INSTR_RXY_RRRD }, { "xg", 0x82, INSTR_RXY_RRRD }, + { "msgc", 0x83, INSTR_RXY_RRRD }, + { "mg", 0x84, INSTR_RXY_RRRD }, { "lgat", 0x85, INSTR_RXY_RRRD }, { "mlg", 0x86, INSTR_RXY_RRRD }, { "dlg", 0x87, INSTR_RXY_RRRD }, @@ -1408,6 +1462,32 @@ static struct s390_insn opcode_e5[] = { { "", 0, INSTR_INVALID } }; +static struct s390_insn opcode_e6[] = { + { "vpkz", 0x34, INSTR_VSI_URDV }, + { "vlrl", 0x35, INSTR_VSI_URDV }, + { "vlrlr", 0x37, INSTR_VRS_RRDV }, + { "vupkz", 0x3c, INSTR_VSI_URDV }, + { "vstrl", 0x3d, INSTR_VSI_URDV }, + { {0 , LONG_INSN_VSTRLR }, 0x3f, INSTR_VRS_RRDV }, + { "vlip", 0x49, INSTR_VRI_V0UU2 }, + { "vcvb", 0x50, INSTR_VRR_RV0U }, + { "vcvbg", 0x52, INSTR_VRR_RV0U }, + { "vcvd", 0x58, INSTR_VRI_VR0UU }, + { "vsrp", 0x59, INSTR_VRI_VVUUU2 }, + { "vcvdg", 0x5a, INSTR_VRI_VR0UU }, + { "vpsop", 0x5b, INSTR_VRI_VVUUU2 }, + { "vtp", 0x5f, INSTR_VRR_0V }, + { "vap", 0x71, INSTR_VRI_VVV0UU2 }, + { "vsp", 0x73, INSTR_VRI_VVV0UU2 }, + { "vcp", 0x77, INSTR_VRR_0VV0U }, + { "vmp", 0x78, INSTR_VRI_VVV0UU2 }, + { "vmsp", 0x79, INSTR_VRI_VVV0UU2 }, + { "vdp", 0x7a, INSTR_VRI_VVV0UU2 }, + { "vrp", 0x7b, INSTR_VRI_VVV0UU2 }, + { "vsdp", 0x7e, INSTR_VRI_VVV0UU2 }, + { "", 0, INSTR_INVALID } +}; + static struct s390_insn opcode_e7[] = { { "lcbb", 0x27, INSTR_RXE_RRRDM }, { "vgef", 0x13, INSTR_VRV_VVRDM }, @@ -1548,6 +1628,16 @@ static struct s390_insn opcode_e7[] = { { "vfsq", 0xce, INSTR_VRR_VV000MM }, { "vfs", 0xe2, INSTR_VRR_VVV00MM }, { "vftci", 0x4a, INSTR_VRI_VVIMM }, + { "vnx", 0x6c, INSTR_VRR_VVV }, + { "vnn", 0x6e, INSTR_VRR_VVV }, + { "voc", 0x6f, INSTR_VRR_VVV }, + { { 0, LONG_INSN_VBPERM }, 0x85, INSTR_VRR_VVV }, + { "vfnms", 0x9e, INSTR_VRR_VVVU0UV }, + { "vfnma", 0x9f, INSTR_VRR_VVVU0UV }, + { "vmsl", 0xb8, INSTR_VRR_VVVUU0V }, + { "vfmin", 0xee, INSTR_VRR_VVV0UUU }, + { "vfmax", 0xef, INSTR_VRR_VVV0UUU }, + { "", 0, INSTR_INVALID } }; static struct s390_insn opcode_eb[] = { @@ -1599,6 +1689,8 @@ static struct s390_insn opcode_eb[] = { { "slak", 0xdd, INSTR_RSY_RRRD }, { "srlk", 0xde, INSTR_RSY_RRRD }, { "sllk", 0xdf, INSTR_RSY_RRRD }, + { "locfh", 0xe0, INSTR_RSY_RURD2 }, + { { 0, LONG_INSN_STOCFH }, 0xe1, INSTR_RSY_RURD2 }, { "locg", 0xe2, INSTR_RSY_RDRM }, { "stocg", 0xe3, INSTR_RSY_RDRM }, { "lang", 0xe4, INSTR_RSY_RRRD }, @@ -1624,8 +1716,11 @@ static struct s390_insn opcode_eb[] = { }; static struct s390_insn opcode_ec[] = { + { "lochi", 0x42, INSTR_RIE_RUI0 }, { "brxhg", 0x44, INSTR_RIE_RRP }, { "brxlg", 0x45, INSTR_RIE_RRP }, + { { 0, LONG_INSN_LOCGHI }, 0x46, INSTR_RIE_RUI0 }, + { { 0, LONG_INSN_LOCHHI }, 0x4e, INSTR_RIE_RUI0 }, { { 0, LONG_INSN_RISBLG }, 0x51, INSTR_RIE_RRUUU }, { "rnsbg", 0x54, INSTR_RIE_RRUUU }, { "risbg", 0x55, INSTR_RIE_RRUUU }, @@ -1721,6 +1816,10 @@ static struct s390_insn opcode_ed[] = { { "mee", 0x37, INSTR_RXE_FRRD }, { "mad", 0x3e, INSTR_RXF_FRRDF }, { "msd", 0x3f, INSTR_RXF_FRRDF }, + { "cdpt", 0xae, INSTR_RSL_LRDFU }, + { "cxpt", 0xaf, INSTR_RSL_LRDFU }, + { "cpdt", 0xac, INSTR_RSL_LRDFU }, + { "cpxt", 0xad, INSTR_RSL_LRDFU }, { "", 0, INSTR_INVALID } }; @@ -1828,6 +1927,10 @@ struct s390_insn *find_insn(unsigned char *code) case 0xe5: table = opcode_e5; break; + case 0xe6: + table = opcode_e6; + opfrag = code[5]; + break; case 0xe7: table = opcode_e7; opfrag = code[5]; diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index ca8cd80e8feb..60181caf8e8a 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -404,18 +404,6 @@ static inline void save_vector_registers(void) #endif } -static int __init topology_setup(char *str) -{ - bool enabled; - int rc; - - rc = kstrtobool(str, &enabled); - if (!rc && !enabled) - S390_lowcore.machine_flags &= ~MACHINE_FLAG_TOPOLOGY; - return rc; -} -early_param("topology", topology_setup); - static int __init disable_vector_extension(char *str) { S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; diff --git a/arch/s390/kernel/guarded_storage.c b/arch/s390/kernel/guarded_storage.c index 6f064745c3b1..65b0eca2128c 100644 --- a/arch/s390/kernel/guarded_storage.c +++ b/arch/s390/kernel/guarded_storage.c @@ -11,11 +11,10 @@ #include <asm/guarded_storage.h> #include "entry.h" -void exit_thread_gs(void) +void guarded_storage_release(struct task_struct *tsk) { - kfree(current->thread.gs_cb); - kfree(current->thread.gs_bc_cb); - current->thread.gs_cb = current->thread.gs_bc_cb = NULL; + kfree(tsk->thread.gs_cb); + kfree(tsk->thread.gs_bc_cb); } static int gs_enable(void) diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index c1bf75ffb875..bd4bbf61aaf3 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -823,9 +823,8 @@ static int cpumsf_pmu_event_init(struct perf_event *event) } /* Check online status of the CPU to which the event is pinned */ - if ((unsigned int)event->cpu >= nr_cpumask_bits || - (event->cpu >= 0 && !cpu_online(event->cpu))) - return -ENODEV; + if (event->cpu >= 0 && !cpu_online(event->cpu)) + return -ENODEV; /* Force reset of idle/hv excludes regardless of what the * user requested. diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index bb32b8618bf6..080c851dd9a5 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -43,27 +43,14 @@ asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); extern void kernel_thread_starter(void); -/* - * Free current thread data structures etc.. - */ -void exit_thread(struct task_struct *tsk) -{ - if (tsk == current) { - exit_thread_runtime_instr(); - exit_thread_gs(); - } -} - void flush_thread(void) { } -void release_thread(struct task_struct *dead_task) -{ -} - void arch_release_task_struct(struct task_struct *tsk) { + runtime_instr_release(tsk); + guarded_storage_release(tsk); } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 252ed61a128b..ea711f141bb8 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -30,6 +30,9 @@ #include <linux/uaccess.h> #include <asm/unistd.h> #include <asm/switch_to.h> +#include <asm/runtime_instr.h> +#include <asm/facility.h> + #include "entry.h" #ifdef CONFIG_COMPAT @@ -1171,26 +1174,37 @@ static int s390_gs_cb_set(struct task_struct *target, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - struct gs_cb *data = target->thread.gs_cb; + struct gs_cb gs_cb = { }, *data = NULL; int rc; if (!MACHINE_HAS_GS) return -ENODEV; - if (!data) { + if (!target->thread.gs_cb) { data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->gsd = 25; - target->thread.gs_cb = data; - if (target == current) - __ctl_set_bit(2, 4); - } else if (target == current) { - save_gs_cb(data); } + if (!target->thread.gs_cb) + gs_cb.gsd = 25; + else if (target == current) + save_gs_cb(&gs_cb); + else + gs_cb = *target->thread.gs_cb; rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - data, 0, sizeof(struct gs_cb)); - if (target == current) - restore_gs_cb(data); + &gs_cb, 0, sizeof(gs_cb)); + if (rc) { + kfree(data); + return -EFAULT; + } + preempt_disable(); + if (!target->thread.gs_cb) + target->thread.gs_cb = data; + *target->thread.gs_cb = gs_cb; + if (target == current) { + __ctl_set_bit(2, 4); + restore_gs_cb(target->thread.gs_cb); + } + preempt_enable(); return rc; } @@ -1228,6 +1242,96 @@ static int s390_gs_bc_set(struct task_struct *target, data, 0, sizeof(struct gs_cb)); } +static bool is_ri_cb_valid(struct runtime_instr_cb *cb) +{ + return (cb->rca & 0x1f) == 0 && + (cb->roa & 0xfff) == 0 && + (cb->rla & 0xfff) == 0xfff && + cb->s == 1 && + cb->k == 1 && + cb->h == 0 && + cb->reserved1 == 0 && + cb->ps == 1 && + cb->qs == 0 && + cb->pc == 1 && + cb->qc == 0 && + cb->reserved2 == 0 && + cb->key == PAGE_DEFAULT_KEY && + cb->reserved3 == 0 && + cb->reserved4 == 0 && + cb->reserved5 == 0 && + cb->reserved6 == 0 && + cb->reserved7 == 0 && + cb->reserved8 == 0 && + cb->rla >= cb->roa && + cb->rca >= cb->roa && + cb->rca <= cb->rla+1 && + cb->m < 3; +} + +static int s390_runtime_instr_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + struct runtime_instr_cb *data = target->thread.ri_cb; + + if (!test_facility(64)) + return -ENODEV; + if (!data) + return -ENODATA; + + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, + data, 0, sizeof(struct runtime_instr_cb)); +} + +static int s390_runtime_instr_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct runtime_instr_cb ri_cb = { }, *data = NULL; + int rc; + + if (!test_facility(64)) + return -ENODEV; + + if (!target->thread.ri_cb) { + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + } + + if (target->thread.ri_cb) { + if (target == current) + store_runtime_instr_cb(&ri_cb); + else + ri_cb = *target->thread.ri_cb; + } + + rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &ri_cb, 0, sizeof(struct runtime_instr_cb)); + if (rc) { + kfree(data); + return -EFAULT; + } + + if (!is_ri_cb_valid(&ri_cb)) { + kfree(data); + return -EINVAL; + } + + preempt_disable(); + if (!target->thread.ri_cb) + target->thread.ri_cb = data; + *target->thread.ri_cb = ri_cb; + if (target == current) + load_runtime_instr_cb(target->thread.ri_cb); + preempt_enable(); + + return 0; +} + static const struct user_regset s390_regsets[] = { { .core_note_type = NT_PRSTATUS, @@ -1301,6 +1405,14 @@ static const struct user_regset s390_regsets[] = { .get = s390_gs_bc_get, .set = s390_gs_bc_set, }, + { + .core_note_type = NT_S390_RI_CB, + .n = sizeof(struct runtime_instr_cb) / sizeof(__u64), + .size = sizeof(__u64), + .align = sizeof(__u64), + .get = s390_runtime_instr_get, + .set = s390_runtime_instr_set, + }, }; static const struct user_regset_view user_s390_view = { @@ -1537,6 +1649,14 @@ static const struct user_regset s390_compat_regsets[] = { .get = s390_gs_cb_get, .set = s390_gs_cb_set, }, + { + .core_note_type = NT_S390_RI_CB, + .n = sizeof(struct runtime_instr_cb) / sizeof(__u64), + .size = sizeof(__u64), + .align = sizeof(__u64), + .get = s390_runtime_instr_get, + .set = s390_runtime_instr_set, + }, }; static const struct user_regset_view user_s390_compat_view = { diff --git a/arch/s390/kernel/runtime_instr.c b/arch/s390/kernel/runtime_instr.c index 429d3a782f1c..8ae851cfea6c 100644 --- a/arch/s390/kernel/runtime_instr.c +++ b/arch/s390/kernel/runtime_instr.c @@ -20,11 +20,24 @@ /* empty control block to disable RI by loading it */ struct runtime_instr_cb runtime_instr_empty_cb; +void runtime_instr_release(struct task_struct *tsk) +{ + kfree(tsk->thread.ri_cb); +} + static void disable_runtime_instr(void) { - struct pt_regs *regs = task_pt_regs(current); + struct task_struct *task = current; + struct pt_regs *regs; + if (!task->thread.ri_cb) + return; + regs = task_pt_regs(task); + preempt_disable(); load_runtime_instr_cb(&runtime_instr_empty_cb); + kfree(task->thread.ri_cb); + task->thread.ri_cb = NULL; + preempt_enable(); /* * Make sure the RI bit is deleted from the PSW. If the user did not @@ -36,24 +49,13 @@ static void disable_runtime_instr(void) static void init_runtime_instr_cb(struct runtime_instr_cb *cb) { - cb->buf_limit = 0xfff; - cb->pstate = 1; - cb->pstate_set_buf = 1; - cb->pstate_sample = 1; - cb->pstate_collect = 1; + cb->rla = 0xfff; + cb->s = 1; + cb->k = 1; + cb->ps = 1; + cb->pc = 1; cb->key = PAGE_DEFAULT_KEY; - cb->valid = 1; -} - -void exit_thread_runtime_instr(void) -{ - struct task_struct *task = current; - - if (!task->thread.ri_cb) - return; - disable_runtime_instr(); - kfree(task->thread.ri_cb); - task->thread.ri_cb = NULL; + cb->v = 1; } SYSCALL_DEFINE1(s390_runtime_instr, int, command) @@ -64,9 +66,7 @@ SYSCALL_DEFINE1(s390_runtime_instr, int, command) return -EOPNOTSUPP; if (command == S390_RUNTIME_INSTR_STOP) { - preempt_disable(); - exit_thread_runtime_instr(); - preempt_enable(); + disable_runtime_instr(); return 0; } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 164a1e16b53e..b2c9af9b88d5 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -380,6 +380,8 @@ static void __init setup_lowcore(void) #ifdef CONFIG_SMP lc->spinlock_lockval = arch_spin_lockval(0); + lc->spinlock_index = 0; + arch_spin_lock_setup(0); #endif set_prefix((u32)(unsigned long) lc); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 1cee6753d47a..cc04b74fbb84 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -226,6 +226,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) lc->mcesad = mcesa_origin | mcesa_bits; lc->cpu_nr = cpu; lc->spinlock_lockval = arch_spin_lockval(cpu); + lc->spinlock_index = 0; if (vdso_alloc_per_cpu(lc)) goto out; lowcore_ptr[cpu] = lc; @@ -273,6 +274,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) cpumask_set_cpu(cpu, mm_cpumask(&init_mm)); lc->cpu_nr = cpu; lc->spinlock_lockval = arch_spin_lockval(cpu); + lc->spinlock_index = 0; lc->percpu_offset = __per_cpu_offset[cpu]; lc->kernel_asce = S390_lowcore.kernel_asce; lc->machine_flags = S390_lowcore.machine_flags; @@ -281,6 +283,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) save_access_regs((unsigned int *) lc->access_regs_save_area); memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, MAX_FACILITY_BIT/8); + arch_spin_lock_setup(cpu); } static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk) @@ -800,6 +803,8 @@ void __init smp_detect_cpus(void) */ static void smp_start_secondary(void *cpuvoid) { + int cpu = smp_processor_id(); + S390_lowcore.last_update_clock = get_tod_clock(); S390_lowcore.restart_stack = (unsigned long) restart_stack; S390_lowcore.restart_fn = (unsigned long) do_restart; @@ -813,8 +818,12 @@ static void smp_start_secondary(void *cpuvoid) init_cpu_timer(); vtime_init(); pfault_init(); - notify_cpu_starting(smp_processor_id()); - set_cpu_online(smp_processor_id(), true); + notify_cpu_starting(cpu); + if (topology_cpu_dedicated(cpu)) + set_cpu_flag(CIF_DEDICATED_CPU); + else + clear_cpu_flag(CIF_DEDICATED_CPU); + set_cpu_online(cpu, true); inc_irq_stat(CPU_RST); local_irq_enable(); cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); @@ -961,6 +970,7 @@ void __init smp_setup_processor_id(void) pcpu_devices[0].address = stap(); S390_lowcore.cpu_nr = 0; S390_lowcore.spinlock_lockval = arch_spin_lockval(0); + S390_lowcore.spinlock_index = 0; } /* diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index bb47c92476f0..d49940fb43b1 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -8,6 +8,8 @@ #include <linux/workqueue.h> #include <linux/bootmem.h> +#include <linux/uaccess.h> +#include <linux/sysctl.h> #include <linux/cpuset.h> #include <linux/device.h> #include <linux/export.h> @@ -29,12 +31,20 @@ #define PTF_VERTICAL (1UL) #define PTF_CHECK (2UL) +enum { + TOPOLOGY_MODE_HW, + TOPOLOGY_MODE_SINGLE, + TOPOLOGY_MODE_PACKAGE, + TOPOLOGY_MODE_UNINITIALIZED +}; + struct mask_info { struct mask_info *next; unsigned char id; cpumask_t mask; }; +static int topology_mode = TOPOLOGY_MODE_UNINITIALIZED; static void set_topology_timer(void); static void topology_work_fn(struct work_struct *work); static struct sysinfo_15_1_x *tl_info; @@ -59,11 +69,26 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) cpumask_t mask; cpumask_copy(&mask, cpumask_of(cpu)); - if (!MACHINE_HAS_TOPOLOGY) - return mask; - for (; info; info = info->next) { - if (cpumask_test_cpu(cpu, &info->mask)) - return info->mask; + switch (topology_mode) { + case TOPOLOGY_MODE_HW: + while (info) { + if (cpumask_test_cpu(cpu, &info->mask)) { + mask = info->mask; + break; + } + info = info->next; + } + if (cpumask_empty(&mask)) + cpumask_copy(&mask, cpumask_of(cpu)); + break; + case TOPOLOGY_MODE_PACKAGE: + cpumask_copy(&mask, cpu_present_mask); + break; + default: + /* fallthrough */ + case TOPOLOGY_MODE_SINGLE: + cpumask_copy(&mask, cpumask_of(cpu)); + break; } return mask; } @@ -74,7 +99,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu) int i; cpumask_copy(&mask, cpumask_of(cpu)); - if (!MACHINE_HAS_TOPOLOGY) + if (topology_mode != TOPOLOGY_MODE_HW) return mask; cpu -= cpu % (smp_cpu_mtid + 1); for (i = 0; i <= smp_cpu_mtid; i++) @@ -108,6 +133,7 @@ static void add_cpus_to_mask(struct topology_core *tl_core, topo->socket_id = socket->id; topo->core_id = rcore; topo->thread_id = lcpu + i; + topo->dedicated = tl_core->d; cpumask_set_cpu(lcpu + i, &drawer->mask); cpumask_set_cpu(lcpu + i, &book->mask); cpumask_set_cpu(lcpu + i, &socket->mask); @@ -184,10 +210,8 @@ static void topology_update_polarization_simple(void) { int cpu; - mutex_lock(&smp_cpu_state_mutex); for_each_possible_cpu(cpu) smp_cpu_set_polarization(cpu, POLARIZATION_HRZ); - mutex_unlock(&smp_cpu_state_mutex); } static int ptf(unsigned long fc) @@ -223,7 +247,7 @@ int topology_set_cpu_management(int fc) static void update_cpu_masks(void) { struct cpu_topology_s390 *topo; - int cpu; + int cpu, id; for_each_possible_cpu(cpu) { topo = &cpu_topology[cpu]; @@ -231,12 +255,13 @@ static void update_cpu_masks(void) topo->core_mask = cpu_group_map(&socket_info, cpu); topo->book_mask = cpu_group_map(&book_info, cpu); topo->drawer_mask = cpu_group_map(&drawer_info, cpu); - if (!MACHINE_HAS_TOPOLOGY) { + if (topology_mode != TOPOLOGY_MODE_HW) { + id = topology_mode == TOPOLOGY_MODE_PACKAGE ? 0 : cpu; topo->thread_id = cpu; topo->core_id = cpu; - topo->socket_id = cpu; - topo->book_id = cpu; - topo->drawer_id = cpu; + topo->socket_id = id; + topo->book_id = id; + topo->drawer_id = id; if (cpu_present(cpu)) cpumask_set_cpu(cpu, &cpus_with_topology); } @@ -249,11 +274,20 @@ void store_topology(struct sysinfo_15_1_x *info) stsi(info, 15, 1, topology_mnest_limit()); } +static void __arch_update_dedicated_flag(void *arg) +{ + if (topology_cpu_dedicated(smp_processor_id())) + set_cpu_flag(CIF_DEDICATED_CPU); + else + clear_cpu_flag(CIF_DEDICATED_CPU); +} + static int __arch_update_cpu_topology(void) { struct sysinfo_15_1_x *info = tl_info; int rc = 0; + mutex_lock(&smp_cpu_state_mutex); cpumask_clear(&cpus_with_topology); if (MACHINE_HAS_TOPOLOGY) { rc = 1; @@ -263,6 +297,7 @@ static int __arch_update_cpu_topology(void) update_cpu_masks(); if (!MACHINE_HAS_TOPOLOGY) topology_update_polarization_simple(); + mutex_unlock(&smp_cpu_state_mutex); return rc; } @@ -272,6 +307,7 @@ int arch_update_cpu_topology(void) int cpu, rc; rc = __arch_update_cpu_topology(); + on_each_cpu(__arch_update_dedicated_flag, NULL, 0); for_each_online_cpu(cpu) { dev = get_cpu_device(cpu); kobject_uevent(&dev->kobj, KOBJ_CHANGE); @@ -289,6 +325,11 @@ void topology_schedule_update(void) schedule_work(&topology_work); } +static void topology_flush_work(void) +{ + flush_work(&topology_work); +} + static void topology_timer_fn(unsigned long ignored) { if (ptf(PTF_CHECK)) @@ -404,9 +445,39 @@ static struct attribute_group topology_cpu_attr_group = { .attrs = topology_cpu_attrs, }; +static ssize_t cpu_dedicated_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int cpu = dev->id; + ssize_t count; + + mutex_lock(&smp_cpu_state_mutex); + count = sprintf(buf, "%d\n", topology_cpu_dedicated(cpu)); + mutex_unlock(&smp_cpu_state_mutex); + return count; +} +static DEVICE_ATTR(dedicated, 0444, cpu_dedicated_show, NULL); + +static struct attribute *topology_extra_cpu_attrs[] = { + &dev_attr_dedicated.attr, + NULL, +}; + +static struct attribute_group topology_extra_cpu_attr_group = { + .attrs = topology_extra_cpu_attrs, +}; + int topology_cpu_init(struct cpu *cpu) { - return sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group); + int rc; + + rc = sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group); + if (rc || !MACHINE_HAS_TOPOLOGY) + return rc; + rc = sysfs_create_group(&cpu->dev.kobj, &topology_extra_cpu_attr_group); + if (rc) + sysfs_remove_group(&cpu->dev.kobj, &topology_cpu_attr_group); + return rc; } static const struct cpumask *cpu_thread_mask(int cpu) @@ -459,6 +530,12 @@ void __init topology_init_early(void) struct sysinfo_15_1_x *info; set_sched_topology(s390_topology); + if (topology_mode == TOPOLOGY_MODE_UNINITIALIZED) { + if (MACHINE_HAS_TOPOLOGY) + topology_mode = TOPOLOGY_MODE_HW; + else + topology_mode = TOPOLOGY_MODE_SINGLE; + } if (!MACHINE_HAS_TOPOLOGY) goto out; tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE); @@ -472,7 +549,92 @@ void __init topology_init_early(void) alloc_masks(info, &drawer_info, 3); out: __arch_update_cpu_topology(); + __arch_update_dedicated_flag(NULL); +} + +static inline int topology_get_mode(int enabled) +{ + if (!enabled) + return TOPOLOGY_MODE_SINGLE; + return MACHINE_HAS_TOPOLOGY ? TOPOLOGY_MODE_HW : TOPOLOGY_MODE_PACKAGE; +} + +static inline int topology_is_enabled(void) +{ + return topology_mode != TOPOLOGY_MODE_SINGLE; +} + +static int __init topology_setup(char *str) +{ + bool enabled; + int rc; + + rc = kstrtobool(str, &enabled); + if (rc) + return rc; + topology_mode = topology_get_mode(enabled); + return 0; } +early_param("topology", topology_setup); + +static int topology_ctl_handler(struct ctl_table *ctl, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + unsigned int len; + int new_mode; + char buf[2]; + + if (!*lenp || *ppos) { + *lenp = 0; + return 0; + } + if (!write) { + strncpy(buf, topology_is_enabled() ? "1\n" : "0\n", + ARRAY_SIZE(buf)); + len = strnlen(buf, ARRAY_SIZE(buf)); + if (len > *lenp) + len = *lenp; + if (copy_to_user(buffer, buf, len)) + return -EFAULT; + goto out; + } + len = *lenp; + if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) + return -EFAULT; + if (buf[0] != '0' && buf[0] != '1') + return -EINVAL; + mutex_lock(&smp_cpu_state_mutex); + new_mode = topology_get_mode(buf[0] == '1'); + if (topology_mode != new_mode) { + topology_mode = new_mode; + topology_schedule_update(); + } + mutex_unlock(&smp_cpu_state_mutex); + topology_flush_work(); +out: + *lenp = len; + *ppos += len; + return 0; +} + +static struct ctl_table topology_ctl_table[] = { + { + .procname = "topology", + .mode = 0644, + .proc_handler = topology_ctl_handler, + }, + { }, +}; + +static struct ctl_table topology_dir_table[] = { + { + .procname = "s390", + .maxlen = 0, + .mode = 0555, + .child = topology_ctl_table, + }, + { }, +}; static int __init topology_init(void) { @@ -480,6 +642,7 @@ static int __init topology_init(void) set_topology_timer(); else topology_update_polarization_simple(); + register_sysctl_table(topology_dir_table); return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching); } device_initcall(topology_init); |