Skip to content

Commit f0f6db9

Browse files
hcahcaVasily Gorbik
authored andcommitted
s390/alternatives: Add debug functionality
Similar to x86 and loongarch add a "debug-alternative" command line parameter, which allows for alternative debugging. The parameter itself comes with architecture specific semantics: "debug-alternative" -> print debug message for every single alternative "debug-alternative=0;2" -> print debug message for all alternatives with type 0 and 2 "debug-alternative=0:0-7" -> print debug message for all alternatives with type 0 which have a facility number within the range of 0-7 "debug-alternative=0:!8;1" -> print debug message for all alternatives with type 0, for all facility numbers, except facility 8, and in addition print all alternatives with type 1 A defconfig build currently results in a kernel with more than 20.000 alternatives, where the majority is for the niai alternative (spinlocks), and the relocated lowcore alternative. The following kernel command like options limit alternative debug output, and enable dynamic debug messages: debug-alternative=0:!49;1:!0 earlyprintk bootdebug ignore_loglevel loglevel=8 dyndbg="file alternative.c +p" This results in output like this: alt: [0/ 11] 0000021b9ce8680c: c0f400000089 -> c00400000000 alt: [0/ 64] 0000021b9ce87e60: c0f400000043 -> c00400000000 alt: [0/133] 0000021b9ce88c56: c0f400000027 -> c00400000000 alt: [0/ 74] 0000021b9ce89410: c0f40000002a -> c00400000000 alt: [0/ 40] 0000021b9dc3720a: 47000000 -> b280d398 alt: [0/193] 0000021b9dc37306: 47000000 -> b201d2b0 alt: [0/193] 0000021b9dc37354: c00400000000 -> d20720c0d2b0 alt: [1/ 5] 0000038d720d7bf2: c0f400000016 -> c00400000000 With [<alternative type>/<alternative data>] <address> oldcode -> newcode Alternative data depends on the alternative type: for type 0 (ALT_TYPE_FACILITY) data is the facility. For type 1 (ALT_TYPE_FEATURE) data is the corresponding machine feature. Acked-by: Vasily Gorbik <[email protected]> Signed-off-by: Heiko Carstens <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]>
1 parent 66ec751 commit f0f6db9

File tree

5 files changed

+190
-5
lines changed

5 files changed

+190
-5
lines changed

arch/s390/boot/alternative.c

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,138 @@
11
// SPDX-License-Identifier: GPL-2.0
2+
#define boot_fmt(fmt) "alt: " fmt
3+
#include "boot.h"
4+
5+
#define a_debug boot_debug
26

37
#include "../kernel/alternative.c"
8+
9+
static void alt_debug_all(int type)
10+
{
11+
int i;
12+
13+
switch (type) {
14+
case ALT_TYPE_FACILITY:
15+
for (i = 0; i < ARRAY_SIZE(alt_debug.facilities); i++)
16+
alt_debug.facilities[i] = -1UL;
17+
break;
18+
case ALT_TYPE_FEATURE:
19+
for (i = 0; i < ARRAY_SIZE(alt_debug.mfeatures); i++)
20+
alt_debug.mfeatures[i] = -1UL;
21+
break;
22+
case ALT_TYPE_SPEC:
23+
alt_debug.spec = 1;
24+
break;
25+
}
26+
}
27+
28+
static void alt_debug_modify(int type, unsigned int nr, bool clear)
29+
{
30+
switch (type) {
31+
case ALT_TYPE_FACILITY:
32+
if (clear)
33+
__clear_facility(nr, alt_debug.facilities);
34+
else
35+
__set_facility(nr, alt_debug.facilities);
36+
break;
37+
case ALT_TYPE_FEATURE:
38+
if (clear)
39+
__clear_machine_feature(nr, alt_debug.mfeatures);
40+
else
41+
__set_machine_feature(nr, alt_debug.mfeatures);
42+
break;
43+
}
44+
}
45+
46+
static char *alt_debug_parse(int type, char *str)
47+
{
48+
unsigned long val, endval;
49+
char *endp;
50+
bool clear;
51+
int i;
52+
53+
if (*str == ':') {
54+
str++;
55+
} else {
56+
alt_debug_all(type);
57+
return str;
58+
}
59+
clear = false;
60+
if (*str == '!') {
61+
alt_debug_all(type);
62+
clear = true;
63+
str++;
64+
}
65+
while (*str) {
66+
val = simple_strtoull(str, &endp, 0);
67+
if (str == endp)
68+
break;
69+
str = endp;
70+
if (*str == '-') {
71+
str++;
72+
endval = simple_strtoull(str, &endp, 0);
73+
if (str == endp)
74+
break;
75+
str = endp;
76+
while (val <= endval) {
77+
alt_debug_modify(type, val, clear);
78+
val++;
79+
}
80+
} else {
81+
alt_debug_modify(type, val, clear);
82+
}
83+
if (*str != ',')
84+
break;
85+
str++;
86+
}
87+
return str;
88+
}
89+
90+
/*
91+
* Use debug-alternative command line parameter for debugging:
92+
* "debug-alternative"
93+
* -> print debug message for every single alternative
94+
*
95+
* "debug-alternative=0;2"
96+
* -> print debug message for all alternatives with type 0 and 2
97+
*
98+
* "debug-alternative=0:0-7"
99+
* -> print debug message for all alternatives with type 0 and with
100+
* facility numbers within the range of 0-7
101+
* (if type 0 is ALT_TYPE_FACILITY)
102+
*
103+
* "debug-alternative=0:!8;1"
104+
* -> print debug message for all alternatives with type 0, for all
105+
* facility number, except facility 8, and in addition print all
106+
* alternatives with type 1
107+
*/
108+
void alt_debug_setup(char *str)
109+
{
110+
unsigned long type;
111+
char *endp;
112+
int i;
113+
114+
if (!str) {
115+
alt_debug_all(ALT_TYPE_FACILITY);
116+
alt_debug_all(ALT_TYPE_FEATURE);
117+
alt_debug_all(ALT_TYPE_SPEC);
118+
return;
119+
}
120+
while (*str) {
121+
type = simple_strtoull(str, &endp, 0);
122+
if (str == endp)
123+
break;
124+
str = endp;
125+
switch (type) {
126+
case ALT_TYPE_FACILITY:
127+
case ALT_TYPE_FEATURE:
128+
str = alt_debug_parse(type, str);
129+
break;
130+
case ALT_TYPE_SPEC:
131+
alt_debug_all(ALT_TYPE_SPEC);
132+
break;
133+
}
134+
if (*str != ';')
135+
break;
136+
str++;
137+
}
138+
}

arch/s390/boot/boot.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ void parse_boot_command_line(void);
6464
void verify_facilities(void);
6565
void print_missing_facilities(void);
6666
void sclp_early_setup_buffer(void);
67+
void alt_debug_setup(char *str);
6768
void print_pgm_check_info(void);
6869
unsigned long randomize_within_range(unsigned long size, unsigned long align,
6970
unsigned long min, unsigned long max);

arch/s390/boot/ipl_parm.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ void parse_boot_command_line(void)
296296
if (!strcmp(param, "facilities") && val)
297297
modify_fac_list(val);
298298

299+
if (!strcmp(param, "debug-alternative"))
300+
alt_debug_setup(val);
301+
299302
if (!strcmp(param, "nokaslr"))
300303
__kaslr_enabled = 0;
301304

arch/s390/kernel/alternative.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,90 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3+
#ifndef pr_fmt
4+
#define pr_fmt(fmt) "alt: " fmt
5+
#endif
6+
37
#include <linux/uaccess.h>
8+
#include <linux/printk.h>
49
#include <asm/nospec-branch.h>
510
#include <asm/abs_lowcore.h>
611
#include <asm/alternative.h>
712
#include <asm/facility.h>
813
#include <asm/sections.h>
914
#include <asm/machine.h>
1015

16+
#ifndef a_debug
17+
#define a_debug pr_debug
18+
#endif
19+
20+
#ifndef __kernel_va
21+
#define __kernel_va(x) (void *)(x)
22+
#endif
23+
1124
unsigned long __bootdata_preserved(machine_features[1]);
1225

26+
struct alt_debug {
27+
unsigned long facilities[MAX_FACILITY_BIT / BITS_PER_LONG];
28+
unsigned long mfeatures[MAX_MFEATURE_BIT / BITS_PER_LONG];
29+
int spec;
30+
};
31+
32+
static struct alt_debug __bootdata_preserved(alt_debug);
33+
34+
static void alternative_dump(u8 *old, u8 *new, unsigned int len, unsigned int type, unsigned int data)
35+
{
36+
char oinsn[33], ninsn[33];
37+
unsigned long kptr;
38+
unsigned int pos;
39+
40+
for (pos = 0; pos < len && 2 * pos < sizeof(oinsn) - 3; pos++)
41+
hex_byte_pack(&oinsn[2 * pos], old[pos]);
42+
oinsn[2 * pos] = 0;
43+
for (pos = 0; pos < len && 2 * pos < sizeof(ninsn) - 3; pos++)
44+
hex_byte_pack(&ninsn[2 * pos], new[pos]);
45+
ninsn[2 * pos] = 0;
46+
kptr = (unsigned long)__kernel_va(old);
47+
a_debug("[%d/%3d] %016lx: %s -> %s\n", type, data, kptr, oinsn, ninsn);
48+
}
49+
1350
void __apply_alternatives(struct alt_instr *start, struct alt_instr *end, unsigned int ctx)
1451
{
15-
u8 *instr, *replacement;
52+
struct alt_debug *d;
1653
struct alt_instr *a;
17-
bool replace;
54+
bool debug, replace;
55+
u8 *old, *new;
1856

1957
/*
2058
* The scan order should be from start to end. A later scanned
2159
* alternative code can overwrite previously scanned alternative code.
2260
*/
61+
d = &alt_debug;
2362
for (a = start; a < end; a++) {
2463
if (!(a->ctx & ctx))
2564
continue;
2665
switch (a->type) {
2766
case ALT_TYPE_FACILITY:
2867
replace = test_facility(a->data);
68+
debug = __test_facility(a->data, d->facilities);
2969
break;
3070
case ALT_TYPE_FEATURE:
3171
replace = test_machine_feature(a->data);
72+
debug = __test_machine_feature(a->data, d->mfeatures);
3273
break;
3374
case ALT_TYPE_SPEC:
3475
replace = nobp_enabled();
76+
debug = d->spec;
3577
break;
3678
default:
3779
replace = false;
80+
debug = false;
3881
}
3982
if (!replace)
4083
continue;
41-
instr = (u8 *)&a->instr_offset + a->instr_offset;
42-
replacement = (u8 *)&a->repl_offset + a->repl_offset;
43-
s390_kernel_write(instr, replacement, a->instrlen);
84+
old = (u8 *)&a->instr_offset + a->instr_offset;
85+
new = (u8 *)&a->repl_offset + a->repl_offset;
86+
if (debug)
87+
alternative_dump(old, new, a->instrlen, a->type, a->data);
88+
s390_kernel_write(old, new, a->instrlen);
4489
}
4590
}

arch/s390/kernel/early.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ decompressor_handled_param(nokaslr);
5555
decompressor_handled_param(cmma);
5656
decompressor_handled_param(relocate_lowcore);
5757
decompressor_handled_param(bootdebug);
58+
__decompressor_handled_param(debug_alternative, debug-alternative);
5859
#if IS_ENABLED(CONFIG_KVM)
5960
decompressor_handled_param(prot_virt);
6061
#endif

0 commit comments

Comments
 (0)