#ifndef KEXEC_H #define KEXEC_H #include "config.h" #include #include #include #include #define USE_BSD #include #include #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; unsigned long elfcorehdr; }; 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_HOTPLUG 265 #define OPT_MAX 266 #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 }, \ { "hotplug", 0, 0, OPT_HOTPLUG }, \ #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_fd(int fd, const char *filename, off_t size, off_t *nread); 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; extern unsigned long elfcorehdrsz; extern int do_hotplug; #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 */