summaryrefslogtreecommitdiffstats
path: root/kexec/kexec.h
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/kexec.h')
-rw-r--r--kexec/kexec.h350
1 files changed, 350 insertions, 0 deletions
diff --git a/kexec/kexec.h b/kexec/kexec.h
new file mode 100644
index 0000000..ed3b499
--- /dev/null
+++ b/kexec/kexec.h
@@ -0,0 +1,350 @@
+#ifndef KEXEC_H
+#define KEXEC_H
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#define USE_BSD
+#include <byteswap.h>
+#include <endian.h>
+#define _GNU_SOURCE
+
+#include "kexec-elf.h"
+#include "unused.h"
+
+#ifndef BYTE_ORDER
+#error BYTE_ORDER not defined
+#endif
+
+#ifndef LITTLE_ENDIAN
+#error LITTLE_ENDIAN not defined
+#endif
+
+#ifndef BIG_ENDIAN
+#error BIG_ENDIAN not defined
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define cpu_to_le16(val) (val)
+#define cpu_to_le32(val) (val)
+#define cpu_to_le64(val) (val)
+#define cpu_to_be16(val) bswap_16(val)
+#define cpu_to_be32(val) bswap_32(val)
+#define cpu_to_be64(val) bswap_64(val)
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#define le64_to_cpu(val) (val)
+#define be16_to_cpu(val) bswap_16(val)
+#define be32_to_cpu(val) bswap_32(val)
+#define be64_to_cpu(val) bswap_64(val)
+#elif BYTE_ORDER == BIG_ENDIAN
+#define cpu_to_le16(val) bswap_16(val)
+#define cpu_to_le32(val) bswap_32(val)
+#define cpu_to_le64(val) bswap_64(val)
+#define cpu_to_be16(val) (val)
+#define cpu_to_be32(val) (val)
+#define cpu_to_be64(val) (val)
+#define le16_to_cpu(val) bswap_16(val)
+#define le32_to_cpu(val) bswap_32(val)
+#define le64_to_cpu(val) bswap_64(val)
+#define be16_to_cpu(val) (val)
+#define be32_to_cpu(val) (val)
+#define be64_to_cpu(val) (val)
+#else
+#error unknwon BYTE_ORDER
+#endif
+
+/*
+ * Document some of the reasons why crashdump may fail, so we can give
+ * better error messages
+ */
+#define EFAILED -1 /* default error code */
+#define ENOCRASHKERNEL -2 /* no memory reserved for crashkernel */
+#define EFALLBACK -3 /* fallback to kexec_load(2) may work */
+
+/*
+ * This function doesn't actually exist. The idea is that when someone
+ * uses the macros below with an unsupported size (datatype), the linker
+ * will alert us to the problem via an unresolved reference error.
+ */
+extern unsigned long bad_unaligned_access_length (void);
+
+#define get_unaligned(loc) \
+({ \
+ __typeof__(*(loc)) _v; \
+ size_t size = sizeof(*(loc)); \
+ switch(size) { \
+ case 1: case 2: case 4: case 8: \
+ memcpy(&_v, (loc), size); \
+ break; \
+ default: \
+ _v = bad_unaligned_access_length(); \
+ break; \
+ } \
+ _v; \
+})
+
+#define put_unaligned(value, loc) \
+do { \
+ size_t size = sizeof(*(loc)); \
+ __typeof__(*(loc)) _v = value; \
+ switch(size) { \
+ case 1: case 2: case 4: case 8: \
+ memcpy((loc), &_v, size); \
+ break; \
+ default: \
+ bad_unaligned_access_length(); \
+ break; \
+ } \
+} while(0)
+
+#define _ALIGN_UP_MASK(addr, mask) (((addr) + (mask)) & ~(mask))
+#define _ALIGN_DOWN_MASK(addr, mask) ((addr) & ~(mask))
+
+/* align addr on a size boundary - adjust address up/down if needed */
+#define _ALIGN_UP(addr, size) \
+ _ALIGN_UP_MASK(addr, (typeof(addr))(size) - 1)
+#define _ALIGN_DOWN(addr, size) \
+ _ALIGN_DOWN_MASK(addr, (typeof(addr))(size) - 1)
+
+/* align addr on a size boundary - adjust address up if needed */
+#define _ALIGN(addr, size) _ALIGN_UP(addr, size)
+
+extern unsigned long long mem_min, mem_max;
+extern int kexec_debug;
+
+#define dbgprintf(...) \
+do { \
+ if (kexec_debug) \
+ fprintf(stderr, __VA_ARGS__); \
+} while(0)
+
+struct kexec_segment {
+ const void *buf;
+ size_t bufsz;
+ const void *mem;
+ size_t memsz;
+};
+
+struct memory_range {
+ unsigned long long start, end;
+ unsigned type;
+#define RANGE_RAM 0
+#define RANGE_RESERVED 1
+#define RANGE_ACPI 2
+#define RANGE_ACPI_NVS 3
+#define RANGE_UNCACHED 4
+#define RANGE_PMEM 6
+#define RANGE_PRAM 11
+};
+
+struct memory_ranges {
+ unsigned int size;
+ unsigned int max_size;
+ struct memory_range *ranges;
+};
+
+struct kexec_info {
+ struct kexec_segment *segment;
+ int nr_segments;
+ struct memory_range *memory_range;
+ int memory_ranges;
+ struct memory_range *crash_range;
+ int nr_crash_ranges;
+ void *entry;
+ struct mem_ehdr rhdr;
+ unsigned long backup_start;
+ unsigned long kexec_flags;
+ unsigned long backup_src_start;
+ unsigned long backup_src_size;
+ /* Set to 1 if we are using kexec file syscall */
+ unsigned long file_mode :1;
+
+ /* Filled by kernel image processing code */
+ int kernel_fd;
+ int initrd_fd;
+ char *command_line;
+ int command_line_len;
+
+ int skip_checks;
+};
+
+struct arch_map_entry {
+ const char *machine;
+ unsigned long arch;
+};
+
+extern const struct arch_map_entry arches[];
+long physical_arch(void);
+
+void usage(void);
+int get_memory_ranges(struct memory_range **range, int *ranges,
+ unsigned long kexec_flags);
+int valid_memory_range(struct kexec_info *info,
+ unsigned long sstart, unsigned long send);
+void print_segments(FILE *file, struct kexec_info *info);
+int sort_segments(struct kexec_info *info);
+unsigned long locate_hole(struct kexec_info *info,
+ unsigned long hole_size, unsigned long hole_align,
+ unsigned long hole_min, unsigned long hole_max,
+ int hole_end);
+
+typedef int (probe_t)(const char *kernel_buf, off_t kernel_size);
+typedef int (load_t )(int argc, char **argv,
+ const char *kernel_buf, off_t kernel_size,
+ struct kexec_info *info);
+typedef void (usage_t)(void);
+struct file_type {
+ const char *name;
+ probe_t *probe;
+ load_t *load;
+ usage_t *usage;
+};
+
+extern struct file_type file_type[];
+extern int file_types;
+
+#define OPT_HELP 'h'
+#define OPT_VERSION 'v'
+#define OPT_DEBUG 'd'
+#define OPT_FORCE 'f'
+#define OPT_NOCHECKS 'i'
+#define OPT_NOIFDOWN 'x'
+#define OPT_NOSYNC 'y'
+#define OPT_EXEC 'e'
+#define OPT_LOAD 'l'
+#define OPT_UNLOAD 'u'
+#define OPT_TYPE 't'
+#define OPT_PANIC 'p'
+#define OPT_KEXEC_FILE_SYSCALL 's'
+#define OPT_KEXEC_SYSCALL 'c'
+#define OPT_KEXEC_SYSCALL_AUTO 'a'
+#define OPT_STATUS 'S'
+#define OPT_MEM_MIN 256
+#define OPT_MEM_MAX 257
+#define OPT_REUSE_INITRD 258
+#define OPT_LOAD_PRESERVE_CONTEXT 259
+#define OPT_LOAD_JUMP_BACK_HELPER 260
+#define OPT_ENTRY 261
+#define OPT_PRINT_CKR_SIZE 262
+#define OPT_LOAD_LIVE_UPDATE 263
+#define OPT_EXEC_LIVE_UPDATE 264
+#define OPT_MAX 265
+#define KEXEC_OPTIONS \
+ { "help", 0, 0, OPT_HELP }, \
+ { "version", 0, 0, OPT_VERSION }, \
+ { "force", 0, 0, OPT_FORCE }, \
+ { "no-checks", 0, 0, OPT_NOCHECKS }, \
+ { "no-ifdown", 0, 0, OPT_NOIFDOWN }, \
+ { "no-sync", 0, 0, OPT_NOSYNC }, \
+ { "load", 0, 0, OPT_LOAD }, \
+ { "unload", 0, 0, OPT_UNLOAD }, \
+ { "exec", 0, 0, OPT_EXEC }, \
+ { "exec-live-update", 0, 0, OPT_EXEC_LIVE_UPDATE}, \
+ { "load-preserve-context", 0, 0, OPT_LOAD_PRESERVE_CONTEXT}, \
+ { "load-jump-back-helper", 0, 0, OPT_LOAD_JUMP_BACK_HELPER }, \
+ { "load-live-update", 0, 0, OPT_LOAD_LIVE_UPDATE }, \
+ { "entry", 1, 0, OPT_ENTRY }, \
+ { "type", 1, 0, OPT_TYPE }, \
+ { "load-panic", 0, 0, OPT_PANIC }, \
+ { "mem-min", 1, 0, OPT_MEM_MIN }, \
+ { "mem-max", 1, 0, OPT_MEM_MAX }, \
+ { "reuseinitrd", 0, 0, OPT_REUSE_INITRD }, \
+ { "kexec-file-syscall", 0, 0, OPT_KEXEC_FILE_SYSCALL }, \
+ { "kexec-syscall", 0, 0, OPT_KEXEC_SYSCALL }, \
+ { "kexec-syscall-auto", 0, 0, OPT_KEXEC_SYSCALL_AUTO }, \
+ { "debug", 0, 0, OPT_DEBUG }, \
+ { "status", 0, 0, OPT_STATUS }, \
+ { "print-ckr-size", 0, 0, OPT_PRINT_CKR_SIZE }, \
+
+#define KEXEC_OPT_STR "h?vdfixyluet:pscaS"
+
+extern void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr);
+extern void die(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+extern void *xmalloc(size_t size);
+extern void *xrealloc(void *ptr, size_t size);
+extern char *slurp_file(const char *filename, off_t *r_size);
+extern char *slurp_file_mmap(const char *filename, off_t *r_size);
+extern char *slurp_file_len(const char *filename, off_t size, off_t *nread);
+extern char *slurp_decompress_file(const char *filename, off_t *r_size);
+extern unsigned long virt_to_phys(unsigned long addr);
+extern void add_segment(struct kexec_info *info,
+ const void *buf, size_t bufsz, unsigned long base, size_t memsz);
+extern void add_segment_phys_virt(struct kexec_info *info,
+ const void *buf, size_t bufsz, unsigned long base, size_t memsz,
+ int phys);
+extern unsigned long add_buffer(struct kexec_info *info,
+ const void *buf, unsigned long bufsz, unsigned long memsz,
+ unsigned long buf_align, unsigned long buf_min, unsigned long buf_max,
+ int buf_end);
+extern unsigned long add_buffer_virt(struct kexec_info *info,
+ const void *buf, unsigned long bufsz, unsigned long memsz,
+ unsigned long buf_align, unsigned long buf_min, unsigned long buf_max,
+ int buf_end);
+extern unsigned long add_buffer_phys_virt(struct kexec_info *info,
+ const void *buf, unsigned long bufsz, unsigned long memsz,
+ unsigned long buf_align, unsigned long buf_min, unsigned long buf_max,
+ int buf_end, int phys);
+extern void arch_reuse_initrd(void);
+
+extern int ifdown(void);
+
+extern char purgatory[];
+extern size_t purgatory_size;
+
+#define BOOTLOADER "kexec"
+#define BOOTLOADER_VERSION PACKAGE_VERSION
+
+void arch_usage(void);
+int arch_process_options(int argc, char **argv);
+int arch_compat_trampoline(struct kexec_info *info);
+void arch_update_purgatory(struct kexec_info *info);
+int is_crashkernel_mem_reserved(void);
+int get_crash_kernel_load_range(uint64_t *start, uint64_t *end);
+void remove_parameter(char *line, const char *param_name);
+char *get_command_line(void);
+
+int kexec_iomem_for_each_line(char *match,
+ int (*callback)(void *data,
+ int nr,
+ char *str,
+ unsigned long long base,
+ unsigned long long length),
+ void *data);
+int parse_iomem_single(char *str, uint64_t *start, uint64_t *end);
+const char * proc_iomem(void);
+
+#define MAX_LINE 160
+
+char *concat_cmdline(const char *base, const char *append);
+void cmdline_add_liveupdate(char **base);
+
+int xen_present(void);
+int xen_kexec_load(struct kexec_info *info);
+int xen_kexec_unload(uint64_t kexec_flags);
+int xen_kexec_exec(uint64_t kexec_flags);
+int xen_kexec_status(uint64_t kexec_flags);
+
+extern unsigned long long get_kernel_sym(const char *text);
+
+/* Converts unsigned long to ascii string. */
+static inline void ultoa(unsigned long val, char *str)
+{
+ char buf[36];
+ int len = 0, pos = 0;
+
+ do {
+ buf[len++] = val % 10;
+ val /= 10;
+ } while (val);
+
+ while (len)
+ str[pos++] = buf[--len] + '0';
+ str[pos] = 0;
+}
+
+#endif /* KEXEC_H */