diff options
Diffstat (limited to 'kexec/kexec.h')
-rw-r--r-- | kexec/kexec.h | 350 |
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 */ |