summaryrefslogtreecommitdiff
path: root/kexec/crashdump-xen.c
blob: aa096e646fe6a092eef83cda2fd2f07940f5b9a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#define _GNU_SOURCE
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "kexec.h"
#include "crashdump.h"

struct crash_note_info {
	unsigned long base;
	unsigned long length;
};

int xen_phys_cpus = 0;
struct crash_note_info *xen_phys_notes;

int xen_present(void)
{
	struct stat buf;

	return stat("/proc/xen", &buf) == 0;
}

static int xen_crash_note_callback(void *data, int nr,
				   char *str,
				   unsigned long base,
				   unsigned long length)
{
	struct crash_note_info *note = xen_phys_notes + nr;

	note->base = base;
	note->length = length;

	return 0;
}

int xen_get_nr_phys_cpus(void)
{
	char *match = "Crash note\n";
	int cpus, n;

	if (xen_phys_cpus)
		return xen_phys_cpus;

	if ((cpus = kexec_iomem_for_each_line(match, NULL, NULL))) {
		n = sizeof(struct crash_note_info) * cpus;
		xen_phys_notes = malloc(n);
		if (xen_phys_notes) {
			memset(xen_phys_notes, 0, n);
			kexec_iomem_for_each_line(match,
						  xen_crash_note_callback,
						  NULL);
		}

		xen_phys_cpus = cpus;
	}

	return cpus;
}

int xen_get_note(int cpu, uint64_t *addr, uint64_t *len)
{
	struct crash_note_info *note;

	if (xen_phys_cpus <= 0)
		return -1;

	note = xen_phys_notes + cpu;

	*addr = note->base;
	*len = note->length;

	return 0;
}