Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/s390/kernel/crash_dump.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* S390 kdump implementation
4
*
5
* Copyright IBM Corp. 2011
6
* Author(s): Michael Holzheu <[email protected]>
7
*/
8
9
#include <linux/crash_dump.h>
10
#include <linux/export.h>
11
#include <asm/lowcore.h>
12
#include <linux/kernel.h>
13
#include <linux/init.h>
14
#include <linux/mm.h>
15
#include <linux/gfp.h>
16
#include <linux/slab.h>
17
#include <linux/memblock.h>
18
#include <linux/elf.h>
19
#include <linux/uio.h>
20
#include <asm/asm-offsets.h>
21
#include <asm/os_info.h>
22
#include <asm/elf.h>
23
#include <asm/ipl.h>
24
#include <asm/sclp.h>
25
#include <asm/maccess.h>
26
#include <asm/fpu.h>
27
28
#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
29
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
30
#define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))
31
32
static struct memblock_region oldmem_region;
33
34
static struct memblock_type oldmem_type = {
35
.cnt = 1,
36
.max = 1,
37
.total_size = 0,
38
.regions = &oldmem_region,
39
.name = "oldmem",
40
};
41
42
struct save_area {
43
struct list_head list;
44
u64 psw[2];
45
u64 ctrs[16];
46
u64 gprs[16];
47
u32 acrs[16];
48
u64 fprs[16];
49
u32 fpc;
50
u32 prefix;
51
u32 todpreg;
52
u64 timer;
53
u64 todcmp;
54
u64 vxrs_low[16];
55
__vector128 vxrs_high[16];
56
};
57
58
static LIST_HEAD(dump_save_areas);
59
60
/*
61
* Allocate a save area
62
*/
63
struct save_area * __init save_area_alloc(bool is_boot_cpu)
64
{
65
struct save_area *sa;
66
67
sa = memblock_alloc_or_panic(sizeof(*sa), 8);
68
69
if (is_boot_cpu)
70
list_add(&sa->list, &dump_save_areas);
71
else
72
list_add_tail(&sa->list, &dump_save_areas);
73
return sa;
74
}
75
76
/*
77
* Return the address of the save area for the boot CPU
78
*/
79
struct save_area * __init save_area_boot_cpu(void)
80
{
81
return list_first_entry_or_null(&dump_save_areas, struct save_area, list);
82
}
83
84
/*
85
* Copy CPU registers into the save area
86
*/
87
void __init save_area_add_regs(struct save_area *sa, void *regs)
88
{
89
struct lowcore *lc;
90
91
lc = (struct lowcore *)(regs - __LC_FPREGS_SAVE_AREA);
92
memcpy(&sa->psw, &lc->psw_save_area, sizeof(sa->psw));
93
memcpy(&sa->ctrs, &lc->cregs_save_area, sizeof(sa->ctrs));
94
memcpy(&sa->gprs, &lc->gpregs_save_area, sizeof(sa->gprs));
95
memcpy(&sa->acrs, &lc->access_regs_save_area, sizeof(sa->acrs));
96
memcpy(&sa->fprs, &lc->floating_pt_save_area, sizeof(sa->fprs));
97
memcpy(&sa->fpc, &lc->fpt_creg_save_area, sizeof(sa->fpc));
98
memcpy(&sa->prefix, &lc->prefixreg_save_area, sizeof(sa->prefix));
99
memcpy(&sa->todpreg, &lc->tod_progreg_save_area, sizeof(sa->todpreg));
100
memcpy(&sa->timer, &lc->cpu_timer_save_area, sizeof(sa->timer));
101
memcpy(&sa->todcmp, &lc->clock_comp_save_area, sizeof(sa->todcmp));
102
}
103
104
/*
105
* Copy vector registers into the save area
106
*/
107
void __init save_area_add_vxrs(struct save_area *sa, __vector128 *vxrs)
108
{
109
int i;
110
111
/* Copy lower halves of vector registers 0-15 */
112
for (i = 0; i < 16; i++)
113
sa->vxrs_low[i] = vxrs[i].low;
114
/* Copy vector registers 16-31 */
115
memcpy(sa->vxrs_high, vxrs + 16, 16 * sizeof(__vector128));
116
}
117
118
static size_t copy_oldmem_iter(struct iov_iter *iter, unsigned long src, size_t count)
119
{
120
size_t len, copied, res = 0;
121
122
while (count) {
123
if (!oldmem_data.start && src < sclp.hsa_size) {
124
/* Copy from zfcp/nvme dump HSA area */
125
len = min(count, sclp.hsa_size - src);
126
copied = memcpy_hsa_iter(iter, src, len);
127
} else {
128
/* Check for swapped kdump oldmem areas */
129
if (oldmem_data.start && src - oldmem_data.start < oldmem_data.size) {
130
src -= oldmem_data.start;
131
len = min(count, oldmem_data.size - src);
132
} else if (oldmem_data.start && src < oldmem_data.size) {
133
len = min(count, oldmem_data.size - src);
134
src += oldmem_data.start;
135
} else {
136
len = count;
137
}
138
copied = memcpy_real_iter(iter, src, len);
139
}
140
count -= copied;
141
src += copied;
142
res += copied;
143
if (copied < len)
144
break;
145
}
146
return res;
147
}
148
149
int copy_oldmem_kernel(void *dst, unsigned long src, size_t count)
150
{
151
struct iov_iter iter;
152
struct kvec kvec;
153
154
kvec.iov_base = dst;
155
kvec.iov_len = count;
156
iov_iter_kvec(&iter, ITER_DEST, &kvec, 1, count);
157
if (copy_oldmem_iter(&iter, src, count) < count)
158
return -EFAULT;
159
return 0;
160
}
161
162
/*
163
* Copy one page from "oldmem"
164
*/
165
ssize_t copy_oldmem_page(struct iov_iter *iter, unsigned long pfn, size_t csize,
166
unsigned long offset)
167
{
168
unsigned long src;
169
170
src = pfn_to_phys(pfn) + offset;
171
return copy_oldmem_iter(iter, src, csize);
172
}
173
174
/*
175
* Remap "oldmem" for kdump
176
*
177
* For the kdump reserved memory this functions performs a swap operation:
178
* [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
179
*/
180
static int remap_oldmem_pfn_range_kdump(struct vm_area_struct *vma,
181
unsigned long from, unsigned long pfn,
182
unsigned long size, pgprot_t prot)
183
{
184
unsigned long size_old;
185
int rc;
186
187
if (pfn < oldmem_data.size >> PAGE_SHIFT) {
188
size_old = min(size, oldmem_data.size - (pfn << PAGE_SHIFT));
189
rc = remap_pfn_range(vma, from,
190
pfn + (oldmem_data.start >> PAGE_SHIFT),
191
size_old, prot);
192
if (rc || size == size_old)
193
return rc;
194
size -= size_old;
195
from += size_old;
196
pfn += size_old >> PAGE_SHIFT;
197
}
198
return remap_pfn_range(vma, from, pfn, size, prot);
199
}
200
201
/*
202
* Remap "oldmem" for zfcp/nvme dump
203
*
204
* We only map available memory above HSA size. Memory below HSA size
205
* is read on demand using the copy_oldmem_page() function.
206
*/
207
static int remap_oldmem_pfn_range_zfcpdump(struct vm_area_struct *vma,
208
unsigned long from,
209
unsigned long pfn,
210
unsigned long size, pgprot_t prot)
211
{
212
unsigned long hsa_end = sclp.hsa_size;
213
unsigned long size_hsa;
214
215
if (pfn < hsa_end >> PAGE_SHIFT) {
216
size_hsa = min(size, hsa_end - (pfn << PAGE_SHIFT));
217
if (size == size_hsa)
218
return 0;
219
size -= size_hsa;
220
from += size_hsa;
221
pfn += size_hsa >> PAGE_SHIFT;
222
}
223
return remap_pfn_range(vma, from, pfn, size, prot);
224
}
225
226
/*
227
* Remap "oldmem" for kdump or zfcp/nvme dump
228
*/
229
int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
230
unsigned long pfn, unsigned long size, pgprot_t prot)
231
{
232
if (oldmem_data.start)
233
return remap_oldmem_pfn_range_kdump(vma, from, pfn, size, prot);
234
else
235
return remap_oldmem_pfn_range_zfcpdump(vma, from, pfn, size,
236
prot);
237
}
238
239
/*
240
* Return true only when in a kdump or stand-alone kdump environment.
241
* Note that /proc/vmcore might also be available in "standard zfcp/nvme dump"
242
* environments, where this function returns false; see dump_available().
243
*/
244
bool is_kdump_kernel(void)
245
{
246
return oldmem_data.start;
247
}
248
EXPORT_SYMBOL_GPL(is_kdump_kernel);
249
250
/*
251
* Initialize ELF note
252
*/
253
static void *nt_init_name(void *buf, Elf64_Word type, void *desc, int d_len,
254
const char *name)
255
{
256
Elf64_Nhdr *note;
257
u64 len;
258
259
note = (Elf64_Nhdr *)buf;
260
note->n_namesz = strlen(name) + 1;
261
note->n_descsz = d_len;
262
note->n_type = type;
263
len = sizeof(Elf64_Nhdr);
264
265
memcpy(buf + len, name, note->n_namesz);
266
len = roundup(len + note->n_namesz, 4);
267
268
memcpy(buf + len, desc, note->n_descsz);
269
len = roundup(len + note->n_descsz, 4);
270
271
return PTR_ADD(buf, len);
272
}
273
274
#define nt_init(buf, type, desc) \
275
nt_init_name(buf, NT_ ## type, &(desc), sizeof(desc), NN_ ## type)
276
277
/*
278
* Calculate the size of ELF note
279
*/
280
static size_t nt_size_name(int d_len, const char *name)
281
{
282
size_t size;
283
284
size = sizeof(Elf64_Nhdr);
285
size += roundup(strlen(name) + 1, 4);
286
size += roundup(d_len, 4);
287
288
return size;
289
}
290
291
#define nt_size(type, desc) nt_size_name(sizeof(desc), NN_ ## type)
292
293
/*
294
* Fill ELF notes for one CPU with save area registers
295
*/
296
static void *fill_cpu_elf_notes(void *ptr, int cpu, struct save_area *sa)
297
{
298
struct elf_prstatus nt_prstatus;
299
elf_fpregset_t nt_fpregset;
300
301
/* Prepare prstatus note */
302
memset(&nt_prstatus, 0, sizeof(nt_prstatus));
303
memcpy(&nt_prstatus.pr_reg.gprs, sa->gprs, sizeof(sa->gprs));
304
memcpy(&nt_prstatus.pr_reg.psw, sa->psw, sizeof(sa->psw));
305
memcpy(&nt_prstatus.pr_reg.acrs, sa->acrs, sizeof(sa->acrs));
306
nt_prstatus.common.pr_pid = cpu;
307
/* Prepare fpregset (floating point) note */
308
memset(&nt_fpregset, 0, sizeof(nt_fpregset));
309
memcpy(&nt_fpregset.fpc, &sa->fpc, sizeof(sa->fpc));
310
memcpy(&nt_fpregset.fprs, &sa->fprs, sizeof(sa->fprs));
311
/* Create ELF notes for the CPU */
312
ptr = nt_init(ptr, PRSTATUS, nt_prstatus);
313
ptr = nt_init(ptr, PRFPREG, nt_fpregset);
314
ptr = nt_init(ptr, S390_TIMER, sa->timer);
315
ptr = nt_init(ptr, S390_TODCMP, sa->todcmp);
316
ptr = nt_init(ptr, S390_TODPREG, sa->todpreg);
317
ptr = nt_init(ptr, S390_CTRS, sa->ctrs);
318
ptr = nt_init(ptr, S390_PREFIX, sa->prefix);
319
if (cpu_has_vx()) {
320
ptr = nt_init(ptr, S390_VXRS_HIGH, sa->vxrs_high);
321
ptr = nt_init(ptr, S390_VXRS_LOW, sa->vxrs_low);
322
}
323
return ptr;
324
}
325
326
/*
327
* Calculate size of ELF notes per cpu
328
*/
329
static size_t get_cpu_elf_notes_size(void)
330
{
331
struct save_area *sa = NULL;
332
size_t size;
333
334
size = nt_size(PRSTATUS, struct elf_prstatus);
335
size += nt_size(PRFPREG, elf_fpregset_t);
336
size += nt_size(S390_TIMER, sa->timer);
337
size += nt_size(S390_TODCMP, sa->todcmp);
338
size += nt_size(S390_TODPREG, sa->todpreg);
339
size += nt_size(S390_CTRS, sa->ctrs);
340
size += nt_size(S390_PREFIX, sa->prefix);
341
if (cpu_has_vx()) {
342
size += nt_size(S390_VXRS_HIGH, sa->vxrs_high);
343
size += nt_size(S390_VXRS_LOW, sa->vxrs_low);
344
}
345
346
return size;
347
}
348
349
/*
350
* Initialize prpsinfo note (new kernel)
351
*/
352
static void *nt_prpsinfo(void *ptr)
353
{
354
struct elf_prpsinfo prpsinfo;
355
356
memset(&prpsinfo, 0, sizeof(prpsinfo));
357
prpsinfo.pr_sname = 'R';
358
strscpy(prpsinfo.pr_fname, "vmlinux");
359
return nt_init(ptr, PRPSINFO, prpsinfo);
360
}
361
362
/*
363
* Get vmcoreinfo using lowcore->vmcore_info (new kernel)
364
*/
365
static void *get_vmcoreinfo_old(unsigned long *size)
366
{
367
char nt_name[11], *vmcoreinfo;
368
unsigned long addr;
369
Elf64_Nhdr note;
370
371
if (copy_oldmem_kernel(&addr, __LC_VMCORE_INFO, sizeof(addr)))
372
return NULL;
373
memset(nt_name, 0, sizeof(nt_name));
374
if (copy_oldmem_kernel(&note, addr, sizeof(note)))
375
return NULL;
376
if (copy_oldmem_kernel(nt_name, addr + sizeof(note),
377
sizeof(nt_name) - 1))
378
return NULL;
379
if (strcmp(nt_name, VMCOREINFO_NOTE_NAME) != 0)
380
return NULL;
381
vmcoreinfo = kzalloc(note.n_descsz, GFP_KERNEL);
382
if (!vmcoreinfo)
383
return NULL;
384
if (copy_oldmem_kernel(vmcoreinfo, addr + 24, note.n_descsz)) {
385
kfree(vmcoreinfo);
386
return NULL;
387
}
388
*size = note.n_descsz;
389
return vmcoreinfo;
390
}
391
392
/*
393
* Initialize vmcoreinfo note (new kernel)
394
*/
395
static void *nt_vmcoreinfo(void *ptr)
396
{
397
const char *name = VMCOREINFO_NOTE_NAME;
398
unsigned long size;
399
void *vmcoreinfo;
400
401
vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size);
402
if (vmcoreinfo)
403
return nt_init_name(ptr, 0, vmcoreinfo, size, name);
404
405
vmcoreinfo = get_vmcoreinfo_old(&size);
406
if (!vmcoreinfo)
407
return ptr;
408
ptr = nt_init_name(ptr, 0, vmcoreinfo, size, name);
409
kfree(vmcoreinfo);
410
return ptr;
411
}
412
413
static size_t nt_vmcoreinfo_size(void)
414
{
415
const char *name = VMCOREINFO_NOTE_NAME;
416
unsigned long size;
417
void *vmcoreinfo;
418
419
vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size);
420
if (vmcoreinfo)
421
return nt_size_name(size, name);
422
423
vmcoreinfo = get_vmcoreinfo_old(&size);
424
if (!vmcoreinfo)
425
return 0;
426
427
kfree(vmcoreinfo);
428
return nt_size_name(size, name);
429
}
430
431
/*
432
* Initialize final note (needed for /proc/vmcore code)
433
*/
434
static void *nt_final(void *ptr)
435
{
436
Elf64_Nhdr *note;
437
438
note = (Elf64_Nhdr *) ptr;
439
note->n_namesz = 0;
440
note->n_descsz = 0;
441
note->n_type = 0;
442
return PTR_ADD(ptr, sizeof(Elf64_Nhdr));
443
}
444
445
/*
446
* Initialize ELF header (new kernel)
447
*/
448
static void *ehdr_init(Elf64_Ehdr *ehdr, int phdr_count)
449
{
450
memset(ehdr, 0, sizeof(*ehdr));
451
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
452
ehdr->e_ident[EI_CLASS] = ELFCLASS64;
453
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
454
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
455
memset(ehdr->e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD);
456
ehdr->e_type = ET_CORE;
457
ehdr->e_machine = EM_S390;
458
ehdr->e_version = EV_CURRENT;
459
ehdr->e_phoff = sizeof(Elf64_Ehdr);
460
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
461
ehdr->e_phentsize = sizeof(Elf64_Phdr);
462
/* Number of PT_LOAD program headers plus PT_NOTE program header */
463
ehdr->e_phnum = phdr_count + 1;
464
return ehdr + 1;
465
}
466
467
/*
468
* Return CPU count for ELF header (new kernel)
469
*/
470
static int get_cpu_cnt(void)
471
{
472
struct save_area *sa;
473
int cpus = 0;
474
475
list_for_each_entry(sa, &dump_save_areas, list)
476
if (sa->prefix != 0)
477
cpus++;
478
return cpus;
479
}
480
481
/*
482
* Return memory chunk count for ELF header (new kernel)
483
*/
484
static int get_mem_chunk_cnt(void)
485
{
486
int cnt = 0;
487
u64 idx;
488
489
for_each_physmem_range(idx, &oldmem_type, NULL, NULL)
490
cnt++;
491
return cnt;
492
}
493
494
static void fill_ptload(Elf64_Phdr *phdr, unsigned long paddr,
495
unsigned long vaddr, unsigned long size)
496
{
497
phdr->p_type = PT_LOAD;
498
phdr->p_vaddr = vaddr;
499
phdr->p_offset = paddr;
500
phdr->p_paddr = paddr;
501
phdr->p_filesz = size;
502
phdr->p_memsz = size;
503
phdr->p_flags = PF_R | PF_W | PF_X;
504
phdr->p_align = PAGE_SIZE;
505
}
506
507
/*
508
* Initialize ELF loads (new kernel)
509
*/
510
static void loads_init(Elf64_Phdr *phdr, bool os_info_has_vm)
511
{
512
unsigned long old_identity_base = 0;
513
phys_addr_t start, end;
514
u64 idx;
515
516
if (os_info_has_vm)
517
old_identity_base = os_info_old_value(OS_INFO_IDENTITY_BASE);
518
for_each_physmem_range(idx, &oldmem_type, &start, &end) {
519
fill_ptload(phdr, start, old_identity_base + start,
520
end - start);
521
phdr++;
522
}
523
}
524
525
static bool os_info_has_vm(void)
526
{
527
return os_info_old_value(OS_INFO_KASLR_OFFSET);
528
}
529
530
#ifdef CONFIG_PROC_VMCORE_DEVICE_RAM
531
/*
532
* Fill PT_LOAD for a physical memory range owned by a device and detected by
533
* its device driver.
534
*/
535
void elfcorehdr_fill_device_ram_ptload_elf64(Elf64_Phdr *phdr,
536
unsigned long long paddr, unsigned long long size)
537
{
538
unsigned long old_identity_base = 0;
539
540
if (os_info_has_vm())
541
old_identity_base = os_info_old_value(OS_INFO_IDENTITY_BASE);
542
fill_ptload(phdr, paddr, old_identity_base + paddr, size);
543
}
544
#endif
545
546
/*
547
* Prepare PT_LOAD type program header for kernel image region
548
*/
549
static void text_init(Elf64_Phdr *phdr)
550
{
551
unsigned long start_phys = os_info_old_value(OS_INFO_IMAGE_PHYS);
552
unsigned long start = os_info_old_value(OS_INFO_IMAGE_START);
553
unsigned long end = os_info_old_value(OS_INFO_IMAGE_END);
554
555
phdr->p_type = PT_LOAD;
556
phdr->p_vaddr = start;
557
phdr->p_filesz = end - start;
558
phdr->p_memsz = end - start;
559
phdr->p_offset = start_phys;
560
phdr->p_paddr = start_phys;
561
phdr->p_flags = PF_R | PF_W | PF_X;
562
phdr->p_align = PAGE_SIZE;
563
}
564
565
/*
566
* Initialize notes (new kernel)
567
*/
568
static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
569
{
570
struct save_area *sa;
571
void *ptr_start = ptr;
572
int cpu;
573
574
ptr = nt_prpsinfo(ptr);
575
576
cpu = 1;
577
list_for_each_entry(sa, &dump_save_areas, list)
578
if (sa->prefix != 0)
579
ptr = fill_cpu_elf_notes(ptr, cpu++, sa);
580
ptr = nt_vmcoreinfo(ptr);
581
ptr = nt_final(ptr);
582
memset(phdr, 0, sizeof(*phdr));
583
phdr->p_type = PT_NOTE;
584
phdr->p_offset = notes_offset;
585
phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start);
586
phdr->p_memsz = phdr->p_filesz;
587
return ptr;
588
}
589
590
static size_t get_elfcorehdr_size(int phdr_count)
591
{
592
size_t size;
593
594
size = sizeof(Elf64_Ehdr);
595
/* PT_NOTES */
596
size += sizeof(Elf64_Phdr);
597
/* nt_prpsinfo */
598
size += nt_size(PRPSINFO, struct elf_prpsinfo);
599
/* regsets */
600
size += get_cpu_cnt() * get_cpu_elf_notes_size();
601
/* nt_vmcoreinfo */
602
size += nt_vmcoreinfo_size();
603
/* nt_final */
604
size += sizeof(Elf64_Nhdr);
605
/* PT_LOADS */
606
size += phdr_count * sizeof(Elf64_Phdr);
607
608
return size;
609
}
610
611
/*
612
* Create ELF core header (new kernel)
613
*/
614
int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
615
{
616
Elf64_Phdr *phdr_notes, *phdr_loads, *phdr_text;
617
int mem_chunk_cnt, phdr_text_cnt;
618
size_t alloc_size;
619
void *ptr, *hdr;
620
u64 hdr_off;
621
622
/* If we are not in kdump or zfcp/nvme dump mode return */
623
if (!oldmem_data.start && !is_ipl_type_dump())
624
return 0;
625
/* If we cannot get HSA size for zfcp/nvme dump return error */
626
if (is_ipl_type_dump() && !sclp.hsa_size)
627
return -ENODEV;
628
629
/* For kdump, exclude previous crashkernel memory */
630
if (oldmem_data.start) {
631
oldmem_region.base = oldmem_data.start;
632
oldmem_region.size = oldmem_data.size;
633
oldmem_type.total_size = oldmem_data.size;
634
}
635
636
mem_chunk_cnt = get_mem_chunk_cnt();
637
phdr_text_cnt = os_info_has_vm() ? 1 : 0;
638
639
alloc_size = get_elfcorehdr_size(mem_chunk_cnt + phdr_text_cnt);
640
641
hdr = kzalloc(alloc_size, GFP_KERNEL);
642
643
/*
644
* Without elfcorehdr /proc/vmcore cannot be created. Thus creating
645
* a dump with this crash kernel will fail. Panic now to allow other
646
* dump mechanisms to take over.
647
*/
648
if (!hdr)
649
panic("s390 kdump allocating elfcorehdr failed");
650
651
/* Init elf header */
652
phdr_notes = ehdr_init(hdr, mem_chunk_cnt + phdr_text_cnt);
653
/* Init program headers */
654
if (phdr_text_cnt) {
655
phdr_text = phdr_notes + 1;
656
phdr_loads = phdr_text + 1;
657
} else {
658
phdr_loads = phdr_notes + 1;
659
}
660
ptr = PTR_ADD(phdr_loads, sizeof(Elf64_Phdr) * mem_chunk_cnt);
661
/* Init notes */
662
hdr_off = PTR_DIFF(ptr, hdr);
663
ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off);
664
/* Init kernel text program header */
665
if (phdr_text_cnt)
666
text_init(phdr_text);
667
/* Init loads */
668
loads_init(phdr_loads, phdr_text_cnt);
669
/* Finalize program headers */
670
hdr_off = PTR_DIFF(ptr, hdr);
671
*addr = (unsigned long long) hdr;
672
*size = (unsigned long long) hdr_off;
673
BUG_ON(elfcorehdr_size > alloc_size);
674
return 0;
675
}
676
677
/*
678
* Free ELF core header (new kernel)
679
*/
680
void elfcorehdr_free(unsigned long long addr)
681
{
682
kfree((void *)(unsigned long)addr);
683
}
684
685
/*
686
* Read from ELF header
687
*/
688
ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
689
{
690
void *src = (void *)(unsigned long)*ppos;
691
692
memcpy(buf, src, count);
693
*ppos += count;
694
return count;
695
}
696
697
/*
698
* Read from ELF notes data
699
*/
700
ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
701
{
702
void *src = (void *)(unsigned long)*ppos;
703
704
memcpy(buf, src, count);
705
*ppos += count;
706
return count;
707
}
708
709