1b2d24b97SGerald Schaefer // SPDX-License-Identifier: GPL-2.0
2b2d24b97SGerald Schaefer /*
3b2d24b97SGerald Schaefer * Copyright IBM Corp. 2019
4b2d24b97SGerald Schaefer */
5ca5999fdSMike Rapoport #include <linux/pgtable.h>
68c37cb7dSVasily Gorbik #include <asm/physmem_info.h>
7b2d24b97SGerald Schaefer #include <asm/cpacf.h>
8b2d24b97SGerald Schaefer #include <asm/timex.h>
9b2d24b97SGerald Schaefer #include <asm/sclp.h>
100c4ec024SVasily Gorbik #include <asm/kasan.h>
11edd4a866SHeiko Carstens #include "decompressor.h"
12868202ceSVasily Gorbik #include "boot.h"
13b2d24b97SGerald Schaefer
14b2d24b97SGerald Schaefer #define PRNG_MODE_TDES 1
15b2d24b97SGerald Schaefer #define PRNG_MODE_SHA512 2
16b2d24b97SGerald Schaefer #define PRNG_MODE_TRNG 3
17b2d24b97SGerald Schaefer
18b2d24b97SGerald Schaefer struct prno_parm {
19b2d24b97SGerald Schaefer u32 res;
20b2d24b97SGerald Schaefer u32 reseed_counter;
21b2d24b97SGerald Schaefer u64 stream_bytes;
22b2d24b97SGerald Schaefer u8 V[112];
23b2d24b97SGerald Schaefer u8 C[112];
24b2d24b97SGerald Schaefer };
25b2d24b97SGerald Schaefer
26b2d24b97SGerald Schaefer struct prng_parm {
27b2d24b97SGerald Schaefer u8 parm_block[32];
28b2d24b97SGerald Schaefer u32 reseed_counter;
29b2d24b97SGerald Schaefer u64 byte_counter;
30b2d24b97SGerald Schaefer };
31b2d24b97SGerald Schaefer
check_prng(void)32b2d24b97SGerald Schaefer static int check_prng(void)
33b2d24b97SGerald Schaefer {
34b2d24b97SGerald Schaefer if (!cpacf_query_func(CPACF_KMC, CPACF_KMC_PRNG)) {
35b2d24b97SGerald Schaefer sclp_early_printk("KASLR disabled: CPU has no PRNG\n");
36b2d24b97SGerald Schaefer return 0;
37b2d24b97SGerald Schaefer }
38b2d24b97SGerald Schaefer if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG))
39b2d24b97SGerald Schaefer return PRNG_MODE_TRNG;
40b2d24b97SGerald Schaefer if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN))
41b2d24b97SGerald Schaefer return PRNG_MODE_SHA512;
42b2d24b97SGerald Schaefer else
43b2d24b97SGerald Schaefer return PRNG_MODE_TDES;
44b2d24b97SGerald Schaefer }
45b2d24b97SGerald Schaefer
get_random(unsigned long limit,unsigned long * value)4607a699bcSVasily Gorbik static int get_random(unsigned long limit, unsigned long *value)
47b2d24b97SGerald Schaefer {
48b2d24b97SGerald Schaefer struct prng_parm prng = {
49b2d24b97SGerald Schaefer /* initial parameter block for tdes mode, copied from libica */
50b2d24b97SGerald Schaefer .parm_block = {
51b2d24b97SGerald Schaefer 0x0F, 0x2B, 0x8E, 0x63, 0x8C, 0x8E, 0xD2, 0x52,
52b2d24b97SGerald Schaefer 0x64, 0xB7, 0xA0, 0x7B, 0x75, 0x28, 0xB8, 0xF4,
53b2d24b97SGerald Schaefer 0x75, 0x5F, 0xD2, 0xA6, 0x8D, 0x97, 0x11, 0xFF,
54b2d24b97SGerald Schaefer 0x49, 0xD8, 0x23, 0xF3, 0x7E, 0x21, 0xEC, 0xA0
55b2d24b97SGerald Schaefer },
56b2d24b97SGerald Schaefer };
57b2d24b97SGerald Schaefer unsigned long seed, random;
58b2d24b97SGerald Schaefer struct prno_parm prno;
59b2d24b97SGerald Schaefer __u64 entropy[4];
60b2d24b97SGerald Schaefer int mode, i;
61b2d24b97SGerald Schaefer
62b2d24b97SGerald Schaefer mode = check_prng();
63b2d24b97SGerald Schaefer seed = get_tod_clock_fast();
64b2d24b97SGerald Schaefer switch (mode) {
65b2d24b97SGerald Schaefer case PRNG_MODE_TRNG:
66b2d24b97SGerald Schaefer cpacf_trng(NULL, 0, (u8 *) &random, sizeof(random));
67b2d24b97SGerald Schaefer break;
68b2d24b97SGerald Schaefer case PRNG_MODE_SHA512:
69b2d24b97SGerald Schaefer cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, &prno, NULL, 0,
70b2d24b97SGerald Schaefer (u8 *) &seed, sizeof(seed));
71b2d24b97SGerald Schaefer cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, &prno, (u8 *) &random,
72b2d24b97SGerald Schaefer sizeof(random), NULL, 0);
73b2d24b97SGerald Schaefer break;
74b2d24b97SGerald Schaefer case PRNG_MODE_TDES:
75b2d24b97SGerald Schaefer /* add entropy */
76b2d24b97SGerald Schaefer *(unsigned long *) prng.parm_block ^= seed;
77b2d24b97SGerald Schaefer for (i = 0; i < 16; i++) {
78b2d24b97SGerald Schaefer cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block,
79788d6715SNathan Chancellor (u8 *) entropy, (u8 *) entropy,
80b2d24b97SGerald Schaefer sizeof(entropy));
81b2d24b97SGerald Schaefer memcpy(prng.parm_block, entropy, sizeof(entropy));
82b2d24b97SGerald Schaefer }
83b2d24b97SGerald Schaefer random = seed;
84b2d24b97SGerald Schaefer cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block, (u8 *) &random,
85b2d24b97SGerald Schaefer (u8 *) &random, sizeof(random));
86b2d24b97SGerald Schaefer break;
87b2d24b97SGerald Schaefer default:
8807a699bcSVasily Gorbik return -1;
89b2d24b97SGerald Schaefer }
9007a699bcSVasily Gorbik *value = random % limit;
9107a699bcSVasily Gorbik return 0;
92b2d24b97SGerald Schaefer }
93b2d24b97SGerald Schaefer
sort_reserved_ranges(struct reserved_range * res,unsigned long size)94*6e259bc5SVasily Gorbik static void sort_reserved_ranges(struct reserved_range *res, unsigned long size)
955c46f276SVasily Gorbik {
96*6e259bc5SVasily Gorbik struct reserved_range tmp;
97*6e259bc5SVasily Gorbik int i, j;
985c46f276SVasily Gorbik
99*6e259bc5SVasily Gorbik for (i = 1; i < size; i++) {
100*6e259bc5SVasily Gorbik tmp = res[i];
101*6e259bc5SVasily Gorbik for (j = i - 1; j >= 0 && res[j].start > tmp.start; j--)
102*6e259bc5SVasily Gorbik res[j + 1] = res[j];
103*6e259bc5SVasily Gorbik res[j + 1] = tmp;
104*6e259bc5SVasily Gorbik }
105*6e259bc5SVasily Gorbik }
106*6e259bc5SVasily Gorbik
iterate_valid_positions(unsigned long size,unsigned long align,unsigned long _min,unsigned long _max,struct reserved_range * res,size_t res_count,bool pos_count,unsigned long find_pos)107*6e259bc5SVasily Gorbik static unsigned long iterate_valid_positions(unsigned long size, unsigned long align,
108*6e259bc5SVasily Gorbik unsigned long _min, unsigned long _max,
109*6e259bc5SVasily Gorbik struct reserved_range *res, size_t res_count,
110*6e259bc5SVasily Gorbik bool pos_count, unsigned long find_pos)
111*6e259bc5SVasily Gorbik {
112*6e259bc5SVasily Gorbik unsigned long start, end, tmp_end, range_pos, pos = 0;
113*6e259bc5SVasily Gorbik struct reserved_range *res_end = res + res_count;
114*6e259bc5SVasily Gorbik struct reserved_range *skip_res;
115*6e259bc5SVasily Gorbik int i;
116*6e259bc5SVasily Gorbik
117*6e259bc5SVasily Gorbik align = max(align, 8UL);
118*6e259bc5SVasily Gorbik _min = round_up(_min, align);
119*6e259bc5SVasily Gorbik for_each_physmem_usable_range(i, &start, &end) {
120*6e259bc5SVasily Gorbik if (_min >= end)
121*6e259bc5SVasily Gorbik continue;
122*6e259bc5SVasily Gorbik start = round_up(start, align);
123*6e259bc5SVasily Gorbik if (start >= _max)
124*6e259bc5SVasily Gorbik break;
125*6e259bc5SVasily Gorbik start = max(_min, start);
126*6e259bc5SVasily Gorbik end = min(_max, end);
127*6e259bc5SVasily Gorbik
128*6e259bc5SVasily Gorbik while (start + size <= end) {
129*6e259bc5SVasily Gorbik /* skip reserved ranges below the start */
130*6e259bc5SVasily Gorbik while (res && res->end <= start) {
131*6e259bc5SVasily Gorbik res++;
132*6e259bc5SVasily Gorbik if (res >= res_end)
133*6e259bc5SVasily Gorbik res = NULL;
134*6e259bc5SVasily Gorbik }
135*6e259bc5SVasily Gorbik skip_res = NULL;
136*6e259bc5SVasily Gorbik tmp_end = end;
137*6e259bc5SVasily Gorbik /* has intersecting reserved range */
138*6e259bc5SVasily Gorbik if (res && res->start < end) {
139*6e259bc5SVasily Gorbik skip_res = res;
140*6e259bc5SVasily Gorbik tmp_end = res->start;
141*6e259bc5SVasily Gorbik }
142*6e259bc5SVasily Gorbik if (start + size <= tmp_end) {
143*6e259bc5SVasily Gorbik range_pos = (tmp_end - start - size) / align + 1;
144*6e259bc5SVasily Gorbik if (pos_count) {
145*6e259bc5SVasily Gorbik pos += range_pos;
146*6e259bc5SVasily Gorbik } else {
147*6e259bc5SVasily Gorbik if (range_pos >= find_pos)
148*6e259bc5SVasily Gorbik return start + (find_pos - 1) * align;
149*6e259bc5SVasily Gorbik find_pos -= range_pos;
150*6e259bc5SVasily Gorbik }
151*6e259bc5SVasily Gorbik }
152*6e259bc5SVasily Gorbik if (!skip_res)
153*6e259bc5SVasily Gorbik break;
154*6e259bc5SVasily Gorbik start = round_up(skip_res->end, align);
155*6e259bc5SVasily Gorbik }
156*6e259bc5SVasily Gorbik }
157*6e259bc5SVasily Gorbik
158*6e259bc5SVasily Gorbik return pos_count ? pos : 0;
159*6e259bc5SVasily Gorbik }
160*6e259bc5SVasily Gorbik
161*6e259bc5SVasily Gorbik /*
162*6e259bc5SVasily Gorbik * Two types of decompressor memory allocations/reserves are considered
163*6e259bc5SVasily Gorbik * differently.
164*6e259bc5SVasily Gorbik *
165*6e259bc5SVasily Gorbik * "Static" or "single" allocations are done via physmem_alloc_range() and
166*6e259bc5SVasily Gorbik * physmem_reserve(), and they are listed in physmem_info.reserved[]. Each
167*6e259bc5SVasily Gorbik * type of "static" allocation can only have one allocation per type and
168*6e259bc5SVasily Gorbik * cannot have chains.
169*6e259bc5SVasily Gorbik *
170*6e259bc5SVasily Gorbik * On the other hand, "dynamic" or "repetitive" allocations are done via
171*6e259bc5SVasily Gorbik * physmem_alloc_top_down(). These allocations are tightly packed together
172*6e259bc5SVasily Gorbik * top down from the end of online memory. physmem_alloc_pos represents
173*6e259bc5SVasily Gorbik * current position where those allocations start.
174*6e259bc5SVasily Gorbik *
175*6e259bc5SVasily Gorbik * Functions randomize_within_range() and iterate_valid_positions()
176*6e259bc5SVasily Gorbik * only consider "dynamic" allocations by never looking above
177*6e259bc5SVasily Gorbik * physmem_alloc_pos. "Static" allocations, however, are explicitly
178*6e259bc5SVasily Gorbik * considered by checking the "res" (reserves) array. The first
179*6e259bc5SVasily Gorbik * reserved_range of a "dynamic" allocation may also be checked along the
180*6e259bc5SVasily Gorbik * way, but it will always be above the maximum value anyway.
181*6e259bc5SVasily Gorbik */
randomize_within_range(unsigned long size,unsigned long align,unsigned long min,unsigned long max)182*6e259bc5SVasily Gorbik unsigned long randomize_within_range(unsigned long size, unsigned long align,
183*6e259bc5SVasily Gorbik unsigned long min, unsigned long max)
184*6e259bc5SVasily Gorbik {
185*6e259bc5SVasily Gorbik struct reserved_range res[RR_MAX];
186*6e259bc5SVasily Gorbik unsigned long max_pos, pos;
187*6e259bc5SVasily Gorbik
188*6e259bc5SVasily Gorbik memcpy(res, physmem_info.reserved, sizeof(res));
189*6e259bc5SVasily Gorbik sort_reserved_ranges(res, ARRAY_SIZE(res));
190*6e259bc5SVasily Gorbik max = min(max, get_physmem_alloc_pos());
191*6e259bc5SVasily Gorbik
192*6e259bc5SVasily Gorbik max_pos = iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), true, 0);
193*6e259bc5SVasily Gorbik if (!max_pos)
1945c46f276SVasily Gorbik return 0;
195*6e259bc5SVasily Gorbik if (get_random(max_pos, &pos))
196*6e259bc5SVasily Gorbik return 0;
197*6e259bc5SVasily Gorbik return iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), false, pos + 1);
198b2d24b97SGerald Schaefer }
199