Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/s390/kernel/os_info.c
38184 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* OS info memory interface
4
*
5
* Copyright IBM Corp. 2012
6
* Author(s): Michael Holzheu <[email protected]>
7
*/
8
9
#define pr_fmt(fmt) "os_info: " fmt
10
11
#include <linux/crash_dump.h>
12
#include <linux/kernel.h>
13
#include <linux/slab.h>
14
#include <asm/checksum.h>
15
#include <asm/abs_lowcore.h>
16
#include <asm/os_info.h>
17
#include <asm/physmem_info.h>
18
#include <asm/maccess.h>
19
#include <asm/asm-offsets.h>
20
#include <asm/sections.h>
21
#include <asm/ipl.h>
22
23
/*
24
* OS info structure has to be page aligned
25
*/
26
static struct os_info os_info __page_aligned_data;
27
28
/*
29
* Compute checksum over OS info structure
30
*/
31
u32 os_info_csum(struct os_info *os_info)
32
{
33
int size = sizeof(*os_info) - offsetof(struct os_info, version_major);
34
return (__force u32)cksm(&os_info->version_major, size, 0);
35
}
36
37
/*
38
* Add crashkernel info to OS info and update checksum
39
*/
40
void os_info_crashkernel_add(unsigned long base, unsigned long size)
41
{
42
os_info.crashkernel_addr = (u64)(unsigned long)base;
43
os_info.crashkernel_size = (u64)(unsigned long)size;
44
os_info.csum = os_info_csum(&os_info);
45
}
46
47
/*
48
* Add OS info data entry and update checksum
49
*/
50
void os_info_entry_add_data(int nr, void *ptr, u64 size)
51
{
52
os_info.entry[nr].addr = __pa(ptr);
53
os_info.entry[nr].size = size;
54
os_info.entry[nr].csum = (__force u32)cksm(ptr, size, 0);
55
os_info.csum = os_info_csum(&os_info);
56
}
57
58
/*
59
* Add OS info value entry and update checksum
60
*/
61
void os_info_entry_add_val(int nr, u64 value)
62
{
63
os_info.entry[nr].val = value;
64
os_info.entry[nr].size = 0;
65
os_info.entry[nr].csum = 0;
66
os_info.csum = os_info_csum(&os_info);
67
}
68
69
/*
70
* Initialize OS info structure and set lowcore pointer
71
*/
72
void __init os_info_init(void)
73
{
74
struct lowcore *abs_lc;
75
76
BUILD_BUG_ON(sizeof(struct os_info) != PAGE_SIZE);
77
os_info.version_major = OS_INFO_VERSION_MAJOR;
78
os_info.version_minor = OS_INFO_VERSION_MINOR;
79
os_info.magic = OS_INFO_MAGIC;
80
os_info_entry_add_val(OS_INFO_IDENTITY_BASE, __identity_base);
81
os_info_entry_add_val(OS_INFO_KASLR_OFFSET, kaslr_offset());
82
os_info_entry_add_val(OS_INFO_KASLR_OFF_PHYS, __kaslr_offset_phys);
83
os_info_entry_add_val(OS_INFO_VMEMMAP, (unsigned long)vmemmap);
84
os_info_entry_add_val(OS_INFO_AMODE31_START, AMODE31_START);
85
os_info_entry_add_val(OS_INFO_AMODE31_END, AMODE31_END);
86
os_info_entry_add_val(OS_INFO_IMAGE_START, (unsigned long)_stext);
87
os_info_entry_add_val(OS_INFO_IMAGE_END, (unsigned long)_end);
88
os_info_entry_add_val(OS_INFO_IMAGE_PHYS, __pa_symbol(_stext));
89
os_info.csum = os_info_csum(&os_info);
90
abs_lc = get_abs_lowcore();
91
abs_lc->os_info = __pa(&os_info);
92
put_abs_lowcore(abs_lc);
93
}
94
95
#ifdef CONFIG_CRASH_DUMP
96
97
static struct os_info *os_info_old;
98
99
/*
100
* Allocate and copy OS info entry from oldmem
101
*/
102
static void os_info_old_alloc(int nr, int align)
103
{
104
unsigned long addr, size = 0;
105
char *buf, *buf_align, *msg;
106
u32 csum;
107
108
addr = os_info_old->entry[nr].addr;
109
if (!addr) {
110
msg = "not available";
111
goto fail;
112
}
113
size = os_info_old->entry[nr].size;
114
buf = kmalloc(size + align - 1, GFP_KERNEL);
115
if (!buf) {
116
msg = "alloc failed";
117
goto fail;
118
}
119
buf_align = PTR_ALIGN(buf, align);
120
if (copy_oldmem_kernel(buf_align, addr, size)) {
121
msg = "copy failed";
122
goto fail_free;
123
}
124
csum = (__force u32)cksm(buf_align, size, 0);
125
if (csum != os_info_old->entry[nr].csum) {
126
msg = "checksum failed";
127
goto fail_free;
128
}
129
os_info_old->entry[nr].addr = (u64)(unsigned long)buf_align;
130
msg = "copied";
131
goto out;
132
fail_free:
133
kfree(buf);
134
fail:
135
os_info_old->entry[nr].addr = 0;
136
out:
137
pr_info("entry %i: %s (addr=0x%lx size=%lu)\n",
138
nr, msg, addr, size);
139
}
140
141
/*
142
* Initialize os info and os info entries from oldmem
143
*/
144
static void os_info_old_init(void)
145
{
146
static int os_info_init;
147
unsigned long addr;
148
149
if (os_info_init)
150
return;
151
if (!oldmem_data.start && !is_ipl_type_dump())
152
goto fail;
153
if (copy_oldmem_kernel(&addr, __LC_OS_INFO, sizeof(addr)))
154
goto fail;
155
if (addr == 0 || addr % PAGE_SIZE)
156
goto fail;
157
os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL);
158
if (!os_info_old)
159
goto fail;
160
if (copy_oldmem_kernel(os_info_old, addr, sizeof(*os_info_old)))
161
goto fail_free;
162
if (os_info_old->magic != OS_INFO_MAGIC)
163
goto fail_free;
164
if (os_info_old->csum != os_info_csum(os_info_old))
165
goto fail_free;
166
if (os_info_old->version_major > OS_INFO_VERSION_MAJOR)
167
goto fail_free;
168
os_info_old_alloc(OS_INFO_VMCOREINFO, 1);
169
os_info_old_alloc(OS_INFO_REIPL_BLOCK, 1);
170
pr_info("crashkernel: addr=0x%lx size=%lu\n",
171
(unsigned long) os_info_old->crashkernel_addr,
172
(unsigned long) os_info_old->crashkernel_size);
173
os_info_init = 1;
174
return;
175
fail_free:
176
kfree(os_info_old);
177
fail:
178
os_info_init = 1;
179
os_info_old = NULL;
180
}
181
182
/*
183
* Return pointer to os info entry and its size
184
*/
185
void *os_info_old_entry(int nr, unsigned long *size)
186
{
187
os_info_old_init();
188
189
if (!os_info_old)
190
return NULL;
191
if (!os_info_old->entry[nr].addr)
192
return NULL;
193
*size = (unsigned long) os_info_old->entry[nr].size;
194
return (void *)(unsigned long)os_info_old->entry[nr].addr;
195
}
196
#endif
197
198