]> Git Repo - J-linux.git/blob - arch/s390/kernel/os_info.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / arch / s390 / kernel / os_info.c
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 KMSG_COMPONENT "os_info"
10 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
12 #include <linux/crash_dump.h>
13 #include <linux/kernel.h>
14 #include <linux/slab.h>
15 #include <asm/checksum.h>
16 #include <asm/abs_lowcore.h>
17 #include <asm/os_info.h>
18 #include <asm/physmem_info.h>
19 #include <asm/maccess.h>
20 #include <asm/asm-offsets.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
This page took 0.036932 seconds and 4 git commands to generate.