diff options
-rw-r--r-- | kexec/Makefile | 1 | ||||
-rw-r--r-- | kexec/kexec-iomem.c | 101 | ||||
-rw-r--r-- | kexec/kexec.h | 10 |
3 files changed, 112 insertions, 0 deletions
diff --git a/kexec/Makefile b/kexec/Makefile index 000c1bb..4ff1bdf 100644 --- a/kexec/Makefile +++ b/kexec/Makefile @@ -16,6 +16,7 @@ KEXEC_C_SRCS+= kexec/kexec-elf-exec.c KEXEC_C_SRCS+= kexec/kexec-elf-core.c KEXEC_C_SRCS+= kexec/kexec-elf-rel.c KEXEC_C_SRCS+= kexec/kexec-elf-boot.c +KEXEC_C_SRCS+= kexec/kexec-iomem.c KEXEC_C_SRCS+= kexec/crashdump.c KEXEC_C_GENERATED_SRCS+= $(PURGATORY_HEX_C) KEXEC_S_SRCS:= diff --git a/kexec/kexec-iomem.c b/kexec/kexec-iomem.c new file mode 100644 index 0000000..6ae4fe4 --- /dev/null +++ b/kexec/kexec-iomem.c @@ -0,0 +1,101 @@ +#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" + +/* + * kexec_iomem_for_each_line() + * + * Iterate over each line in /proc/iomem. If match is NULL or if the line + * matches with our match-pattern then call the callback if non-NULL. + * Return the number of lines matched. + */ + +int kexec_iomem_for_each_line(char *match, + int (*callback)(void *data, + int nr, + char *str, + unsigned long base, + unsigned long length), + void *data) +{ + const char iomem[]= "/proc/iomem"; + char line[MAX_LINE]; + FILE *fp; + unsigned long long start, end, size; + char *str; + int consumed; + int count; + int nr = 0; + + fp = fopen(iomem, "r"); + if (!fp) + die("Cannot open /proc/iomem"); + + while(fgets(line, sizeof(line), fp) != 0) { + count = sscanf(line, "%Lx-%Lx : %n", &start, &end, &consumed); + if (count != 2) + continue; + str = line + consumed; + size = end - start + 1; + if (!match || memcmp(str, match, strlen(match)) == 0) { + if (callback + && callback(data, nr, str, start, size) < 0) { + break; + } + nr++; + } + } + + fclose(fp); + + return nr; +} + +static int kexec_iomem_single_callback(void *data, int nr, + char *str, + unsigned long base, + unsigned long length) +{ + struct memory_range *range = data; + + if (nr == 0) { + range->start = base; + range->end = base + length - 1; + } + + return 0; +} + +int parse_iomem_single(char *str, uint64_t *start, uint64_t *end) +{ + struct memory_range range; + int ret; + + memset(&range, 0, sizeof(range)); + + ret = kexec_iomem_for_each_line(str, kexec_iomem_single_callback, + &range); + + if (ret == 1) { + if (start) + *start = range.start; + if (end) + *end = range.end; + + ret = 0; + } + else + ret = -1; + + return ret; +} diff --git a/kexec/kexec.h b/kexec/kexec.h index 890dbb0..8fd3edb 100644 --- a/kexec/kexec.h +++ b/kexec/kexec.h @@ -201,6 +201,16 @@ int arch_compat_trampoline(struct kexec_info *info); void arch_update_purgatory(struct kexec_info *info); int is_crashkernel_mem_reserved(void); +int kexec_iomem_for_each_line(char *match, + int (*callback)(void *data, + int nr, + char *str, + unsigned long base, + unsigned long length), + void *data); +int parse_iomem_single(char *str, uint64_t *start, uint64_t *end); + + #define MAX_LINE 160 #ifdef DEBUG |