diff -rNu kexec-tools-1.8/kexec/Makefile kexec-tools/kexec/Makefile --- kexec-tools-1.8/kexec/Makefile 2002-11-17 20:10:08.000000000 +0000 +++ kexec-tools/kexec/Makefile 2003-03-11 16:12:24.000000000 +0000 @@ -4,8 +4,10 @@ KEXEC_C_SRCS:= kexec/kexec.c kexec/kexec-syscall.c KEXEC_S_SRCS:= KEXEC_C_SRCS+= kexec/kexec-x86.c kexec/kexec-elf32-x86.c kexec/kexec-bzImage.c +KEXEC_C_SRCS+= kexec/kexec-multiboot-x86.c KEXEC_C_SRCS+= kexec/ifdown.c -KEXEC_S_SRCS+= kexec/x86-setup-32.S kexec/x86-setup-16.S kexec/x86-setup-16-debug.S +KEXEC_S_SRCS+= kexec/x86-setup-32.S kexec/x86-setup-16.S +KEXEC_S_SRCS+= kexec/x86-setup-16-debug.S kexec/x86-reset-vga.S KEXEC_C_OBJS:= $(patsubst %.c, $(OBJDIR)/%.o, $(KEXEC_C_SRCS)) KEXEC_C_DEPS:= $(patsubst %.c, $(OBJDIR)/%.d, $(KEXEC_C_SRCS)) KEXEC_S_OBJS:= $(patsubst %.S, $(OBJDIR)/%.o, $(KEXEC_S_SRCS)) diff -rNu kexec-tools-1.8/kexec/kexec-multiboot-x86.c kexec-tools/kexec/kexec-multiboot-x86.c --- kexec-tools-1.8/kexec/kexec-multiboot-x86.c 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools/kexec/kexec-multiboot-x86.c 2003-03-11 16:23:57.000000000 +0000 @@ -0,0 +1,570 @@ +/* + * kexec-multiboot-x86.c + * + * (partial) multiboot support for kexec. Only supports ELF32 + * kernels, and a subset of the multiboot info page options + * (i.e. enough to boot the Xen hypervisor). + * + * TODO: + * - smarter allocation of new segments + * - proper support for the MULTIBOOT_VIDEO_MODE bit + * - support for the MULTIBOOT_AOUT_KLUDGE bit + * + * + * Copyright (C) 2003 Tim Deegan (tjd21@cl.cam.ac.uk) + * + * Parts based on GNU GRUB, Copyright (C) 2000 Free Software Foundation, Inc + * Parts copied from kexec-elf32-x86.c, written by Eric Biederman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kexec.h" +#include "kexec-x86.h" + +/* From GNU GRUB */ +#include "mb_header.h" +#include "mb_info.h" + +/* Static storage */ +static char headerbuf[MULTIBOOT_SEARCH]; +static struct multiboot_header *mbh = NULL; + +/* Magic for resetting VGA cards to text mode 3 */ +extern unsigned char x86_reset_vga[]; +extern unsigned char x86_reset_vga_end[]; + +#define BOOTLOADER "kexec" +#define BOOTLOADER_VERSION VERSION +#define VGA_RESET_SIZE (x86_reset_vga_end - x86_reset_vga) +#define SETUP_SPACE ((VGA_RESET_SIZE + setup32_size + 3) & ~3) +#define MIN(_x,_y) (((_x)<=(_y))?(_x):(_y)) + + +int multiboot_x86_probe(FILE *file) +/* Is it a good idea to try booting this file? */ +{ + int i, len; + /* First of all, check that this is an ELF file */ + if ((i=elf32_x86_probe(file)) <= 0) { + return i; + } + /* Now look for a multiboot header in the first 8KB */ + if (fseek(file, 0, SEEK_SET) < 0) { + fprintf(stderr, "seek error: %s\n", + strerror(errno)); + return -1; + } + if ((len = fread(headerbuf, 1, MULTIBOOT_SEARCH, file)) + < MULTIBOOT_SEARCH) + { + if (feof(file)) /* Short file */ + { + if (len < 12) return 0; + } else { + fprintf(stderr, "read error: %s\n", + strerror(errno)); + return -1; + } + } + for (i = 0; i <= (len - 12); i += 4) + { + /* Search for a multiboot header */ + mbh = (struct multiboot_header *)(headerbuf + i); + if (mbh->magic != MULTIBOOT_MAGIC + || ((mbh->magic+mbh->flags+mbh->checksum) & 0xffffffff)) + { + /* Not a multiboot header */ + continue; + } + if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) { + /* Requires options we don't support */ + fprintf(stderr, + "Found a multiboot header, but it uses " + "a non-ELF header layout,\n" + "and I can't do that (yet). Sorry.\n"); + return -1; + } + if (mbh->flags & MULTIBOOT_UNSUPPORTED) { + /* Requires options we don't support */ + fprintf(stderr, + "Found a multiboot header, but it " + "requires multiboot options that I\n" + "don't understand. Sorry.\n"); + return -1; + } + if (mbh->flags & MULTIBOOT_VIDEO_MODE) { + /* Asked for screen mode information */ + /* XXX carry on regardless */ + fprintf(stderr, + "BEWARE! Found a multiboot header which asks " + "for screen mode information.\n" + "BEWARE! I am NOT supplying screen mode " + "information, but loading it regardless.\n"); + + } + /* Bootable */ + return 1; + } + /* Not multiboot */ + return 0; +} + + +void multiboot_x86_usage(void) +/* Multiboot-specific options */ +{ + printf(" --command-line=STRING Set the kernel command line to STRING.\n"); + printf(" --module=\"MOD arg1 arg2...\" Load module MOD with command-line \"arg1...\"\n"); + printf(" (can be used multiple times).\n"); + printf(" --reset-vga Include code to set VGA text mode 3.\n"); + printf(" (use this flag at load time).\n"); +} + + +static unsigned long locate_seg(struct kexec_segment *segment, + int nr_segments, + size_t size, + unsigned long align_mask) +/* Find somewhere to put this segment + * Only call this if you know the highest segment is last in the list */ +{ + struct kexec_segment s; + + s.mem = segment[nr_segments-1].mem + segment[nr_segments-1].memsz; + s.mem = (void *)(((unsigned long)s.mem + align_mask) & ~align_mask); + s.memsz = size; + if (valid_memory_range(&s)) { + fprintf(stderr, "Bad place for a segment: %#lx + %#lx\n", + (unsigned long) s.mem, (unsigned long) s.memsz); + return 0; + } else { + return (unsigned long)s.mem; + } +} + + +int multiboot_x86_load(FILE *file, int argc, char **argv, + void **ret_entry, struct kexec_segment **ret_segments, + int *ret_nr_segments) +/* Marshal up a multiboot-style kernel */ +{ + struct multiboot_info *mbi; + void *mbi_buf; + struct mod_list *modp; + struct kexec_segment *segment; + int nr_segments; + unsigned long freespace; + unsigned long long mem_lower = 0, mem_upper = 0; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + size_t mbi_bytes, mbi_offset; + const char *command_line=NULL; + char *imagename, *cp; + struct memory_range *range; + int ranges; + struct AddrRangeDesc *mmap; + int command_line_len; + int i; + int opt; + int modules, mod_command_line_space; + int extras; + int frob_vga; +#define OPT_CL OPT_MAX+0 +#define OPT_MOD OPT_MAX+1 +#define OPT_VGA OPT_MAX+2 + static const struct option options[] = { + KEXEC_OPTIONS + { "command-line", 1, 0, OPT_CL }, + { "append", 1, 0, OPT_CL }, + { "module", 1, 0, OPT_MOD }, + { "reset-vga", 0, 0, OPT_VGA }, + { 0, 0, 0, 0 }, + }; + static const char short_options[] = KEXEC_OPT_STR ""; + + /* Probe for the MB header if it's not already found */ + if (mbh == NULL && multiboot_x86_probe(file) != 1) + { + fprintf(stderr, "Cannot find a loadable multiboot header.\n"); + return -1; + } + + + /* Parse the command line */ + command_line = ""; + command_line_len = 0; + modules = 0; + mod_command_line_space = 0; + frob_vga = 0; + while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) + { + switch(opt) { + default: + /* Ignore core options */ + if (opt < OPT_MAX) { + break; + } + case '?': + usage(); + return -1; + case OPT_CL: + command_line = optarg; + break; + case OPT_MOD: + modules++; + mod_command_line_space += strlen(optarg) + 1; + break; + case OPT_VGA: + frob_vga = 1; + break; + } + } + imagename = argv[optind]; + command_line_len = strlen(command_line) + strlen(imagename) + 2; + + /* Find the ELF headers at the start of the file */ + ehdr = (Elf32_Ehdr *)headerbuf; + phdr = (Elf32_Phdr *)(headerbuf + ehdr->e_phoff); + if (ehdr->e_phoff + ehdr->e_phnum*sizeof(*phdr) > sizeof(headerbuf)) { + /* Don't expect this will happen with sane kernels */ + fprintf(stderr, "too much ELF for me. \n"); + return -1; + } + + /* We'll need segments for the kernel, modules and other bits */ + extras = 1; + /* if (mbh->flags & MULTIBOOT_VIDEO_MODE) extras++; */ + if (mbh->flags & MULTIBOOT_MEMORY_INFO) extras++; + segment = malloc(sizeof(*segment)*(ehdr->e_phnum + modules + extras)); + if (segment == 0) { + fprintf(stderr, "malloc failed: %s\n", + strerror(errno)); + return -1; + } + + /* The first segment will contain the multiboot headers: + * ============= + * VGA reset code + * ------------- + * 32-bit CPU setup code + * ------------- + * multiboot information (mbi) + * ------------- + * kernel command line + * ------------- + * bootloader name + * ------------- + * module information entries + * ------------- + * module command lines + * ============== + */ + mbi_bytes = (SETUP_SPACE + sizeof(*mbi) + command_line_len + + strlen (BOOTLOADER " " BOOTLOADER_VERSION) + 1 + + 3) & ~3; + mbi_buf = malloc(mbi_bytes); + if (mbi_buf == NULL) { + fprintf(stderr, "malloc failed: %s\n", + strerror(errno)); + return -1; + } + mbi = mbi_buf + SETUP_SPACE; + memset(mbi, 0, sizeof(*mbi)); + sprintf(((char *)mbi) + sizeof(*mbi), "%s %s", + imagename, command_line); + sprintf(((char *)mbi) + sizeof(*mbi) + command_line_len, "%s", + BOOTLOADER " " BOOTLOADER_VERSION); + mbi->flags = MB_INFO_CMDLINE | MB_INFO_BOOT_LOADER_NAME; + /* We'll relocate these to absolute addresses later. For now, + * all addresses within the first segment are relative to the + * start of the MBI. */ + mbi->cmdline = sizeof(*mbi); + mbi->boot_loader_name = sizeof(*mbi) + command_line_len; + /* Sort these out later when we know where it's going */ + segment[0].buf = 0; + segment[0].bufsz = 0; + segment[0].mem = 0; + segment[0].memsz = 0; + nr_segments=1; + + + /* Load all the rest of the kernel segments (using the ELF headers) */ + for(i = 0; i < ehdr->e_phnum; i++) { + char *buf; + size_t size; + size = phdr[i].p_filesz; + if (size > phdr[i].p_memsz) { + size = phdr[i].p_memsz; + } + buf = malloc(size); + if (buf == 0) { + fprintf(stderr, "malloc failed: %s\n", + strerror(errno)); + return -1; + } + segment[nr_segments].buf = buf; + segment[nr_segments].bufsz = size; + segment[nr_segments].mem = (void *)phdr[i].p_paddr; + segment[nr_segments].memsz = phdr[i].p_memsz; + if (valid_memory_range(segment + nr_segments) < 0) { + fprintf(stderr, "Invalid memory segment %p - %p\n", + segment[nr_segments].mem, + ((char*)segment[nr_segments].mem) + segment[nr_segments].memsz); + return -1; + } + nr_segments++; + if (size == 0 || phdr[i].p_type != PT_LOAD) { + /* Don't do file I/O if there is nothing in the file */ + continue; + } + if (fseek(file, phdr[i].p_offset, SEEK_SET) != 0) { + fprintf(stderr, "seek failed: %s\n", + strerror(errno)); + return -1; + } + if (fread(buf, size, 1, file) != 1) { + fprintf(stderr, "Read failed: %s\n", + strerror(errno)); + return -1; + } + } + + /* Make it easy to find space for the next segment */ + if (sort_segments(segment, nr_segments) < 0) { + return -1; + } + + + /* Memory map */ + if ((get_memory_ranges(&range, &ranges) < 0) || ranges == 0) { + fprintf(stderr, "Cannot get memory information\n"); + return -1; + } + if ((mmap = malloc(ranges * sizeof(*mmap))) == NULL) { + fprintf(stderr, "malloc failed: %s\n", + strerror(errno)); + return -1; + } + for (i=0; i mem_lower)) + mem_lower = range[i].end; + /* Is this the "high" memory? */ + if ((range[i].start <= 0x100000) + && (range[i].end > mem_upper + 0x100000)) + mem_upper = range[i].end - 0x100000; + } + else + mmap[i].Type = 0xbad; /* Not RAM */ + } + + + if (mbh->flags & MULTIBOOT_MEMORY_INFO) { + /* Provide a copy of the memory map to the kernel */ + + mbi->flags |= MB_INFO_MEMORY | MB_INFO_MEM_MAP; + freespace = locate_seg(segment, nr_segments, + ranges * sizeof(*mmap), 3); + if (!freespace) { + fprintf(stderr, "Cannot find space for new segment\n"); + return -1; + } + + segment[nr_segments].buf = mmap; + segment[nr_segments].bufsz = ranges * sizeof(*mmap); + segment[nr_segments].mem = (void *)freespace; + segment[nr_segments].memsz = ranges * sizeof(*mmap); + mbi->mmap_addr = freespace; + mbi->mmap_length = ranges * sizeof(*mmap); + + /* For kernels that care naught for fancy memory maps + * and just want the size of low and high memory */ + mbi->mem_lower = MIN(mem_lower>>10, 0xffffffff); + mbi->mem_upper = MIN(mem_upper>>10, 0xffffffff); + + /* done */ + nr_segments++; + } + + + /* Load modules */ + if (modules) { + char *mod_filename, *mod_command_line, *mod_clp, *buf; + FILE *mod_file; + struct stat sb; + + /* We'll relocate this to an absolute address later */ + mbi->mods_addr = (mbi_bytes - SETUP_SPACE); + mbi->mods_count = 0; + mbi->flags |= MB_INFO_MODS; + + /* Add room for the module descriptors to the MBI buffer */ + mbi_bytes += (sizeof(*modp) * modules) + + mod_command_line_space; + if ((mbi_buf = realloc(mbi_buf, mbi_bytes)) == NULL) { + fprintf(stderr, "realloc failed: %s\n", + strerror(errno)); + return -1; + } + + /* mbi might have moved */ + mbi = mbi_buf + SETUP_SPACE; + /* module descriptors go in the newly added space */ + modp = ((void *)mbi) + mbi->mods_addr; + /* module command lines go after the descriptors */ + mod_clp = ((void *)modp) + (sizeof(*modp) * modules); + + /* Go back and parse the module command lines */ + optind = opterr = 1; + while((opt = getopt_long(argc, argv, + short_options, options, 0)) != -1) + { + if (opt != OPT_MOD) continue; + + /* Split module filename from command line */ + mod_command_line = mod_filename = optarg; + if ((cp = strchr(mod_filename, ' ')) != NULL) { + /* See as I discard the 'const' modifier */ + *cp = '\0'; + } + + /* Load the module */ + if (stat(mod_filename, &sb) != 0) { + fprintf(stderr, "Cannot stat %s: %s\n", + mod_filename, strerror(errno)); + return -1; + } + if ((buf = malloc(sb.st_size)) == NULL) { + fprintf(stderr, "malloc failed: %s\n", + strerror(errno)); + return -1; + } + if ((mod_file = fopen(mod_filename, "rb")) == NULL) { + fprintf(stderr, "Cannot open %s: %s\n", + mod_filename, strerror(errno)); + return -1; + } + if ((fread(buf, sb.st_size, 1, mod_file)) != 1) { + fprintf(stderr, "Cannot read %s: %s\n", + mod_filename, strerror(errno)); + return -1; + } + fclose(mod_file); + + if (cp != NULL) *cp = ' '; + + /* Pick the next aligned spot to load it in */ + freespace = locate_seg(segment, + nr_segments,sb.st_size, + (PAGE_SIZE-1)); + /* XXX That should be + * (mbh->flags&MULTIBOOT_PAGE_ALIGN)?(PAGE_SIZE-1):3) + * but for now, forcing page-align makes Xen boot... */ + + if (!freespace) { + fprintf(stderr, + "Cannot find space for new segment\n"); + return -1; + } + + /* Add the module command line */ + sprintf(mod_clp, "%s", mod_command_line); + + /* Record the module location */ + segment[nr_segments].buf = buf; + segment[nr_segments].bufsz = sb.st_size; + segment[nr_segments].mem = (void *)freespace; + segment[nr_segments].memsz = sb.st_size; + modp->mod_start = freespace; + modp->mod_end = freespace + sb.st_size; + modp->cmdline = (void *)mod_clp - (void *)mbi; + modp->pad = 0; + + /* Done */ + nr_segments++; + mbi->mods_count++; + mod_clp += strlen(mod_clp) + 1; + modp++; + } + + } + + + /* Find a place for the MBI to live */ + if (sort_segments(segment, nr_segments) < 0) { + return -1; + } + segment[0].buf = mbi_buf; + segment[0].bufsz = mbi_bytes; + segment[0].mem = 0; + segment[0].memsz = mbi_bytes; + if (locate_arguments(segment, nr_segments, 4, 0xFFFFFFFFUL) < 0) { + return -1; + } + + /* Relocate offsets in the MBI to absolute addresses */ + mbi_offset = (unsigned long)segment[0].mem + SETUP_SPACE; + modp = ((void *)mbi) + mbi->mods_addr; + for (i=0; imods_count; i++) { + modp[i].cmdline += mbi_offset; + } + mbi->mods_addr += mbi_offset; + mbi->cmdline += mbi_offset; + mbi->boot_loader_name += mbi_offset; + + /* Specify the initial CPU state and copy the setup code */ + memset(&setup32_regs, 0, sizeof(setup32_regs)); + setup32_regs.eax = 0x2BADB002; + setup32_regs.ebx = mbi_offset; + setup32_regs.eip = ehdr->e_entry; + memcpy(mbi_buf, x86_reset_vga, VGA_RESET_SIZE); + memcpy(mbi_buf + VGA_RESET_SIZE, setup32_start, setup32_size); + + /* Done */ + *ret_entry = frob_vga ? segment[0].mem : segment[0].mem+VGA_RESET_SIZE; + *ret_segments = segment; + *ret_nr_segments = nr_segments; + return 0; +} + +/* + * EOF (kexec-multiboot-x86.c) + */ + diff -rNu kexec-tools-1.8/kexec/kexec-x86.c kexec-tools/kexec/kexec-x86.c --- kexec-tools-1.8/kexec/kexec-x86.c 2002-12-02 03:49:30.000000000 +0000 +++ kexec-tools/kexec/kexec-x86.c 2003-03-02 20:22:21.000000000 +0000 @@ -72,6 +72,8 @@ } struct file_type file_type[] = { + { "multiboot-x86", multiboot_x86_probe, multiboot_x86_load, + multiboot_x86_usage }, { "elf32-x86", elf32_x86_probe, elf32_x86_load, elf32_x86_usage }, { "bzImage", bzImage_probe, bzImage_load, bzImage_usage }, }; diff -rNu kexec-tools-1.8/kexec/kexec-x86.h kexec-tools/kexec/kexec-x86.h --- kexec-tools-1.8/kexec/kexec-x86.h 2002-12-02 02:45:36.000000000 +0000 +++ kexec-tools/kexec/kexec-x86.h 2003-03-02 20:22:07.000000000 +0000 @@ -39,6 +39,12 @@ uint16_t cs; } setup16_regs, setup16_debug_regs; + +int multiboot_x86_probe(FILE *file); +int multiboot_x86_load(FILE *file, int argc, char **argv, + void **ret_entry, struct kexec_segment **ret_segments, int *ret_nr_segments); +void multiboot_x86_usage(void); + int elf32_x86_probe(FILE *file); int elf32_x86_load(FILE *file, int argc, char **argv, void **ret_entry, struct kexec_segment **ret_segments, int *ret_nr_segments); diff -rNu kexec-tools-1.8/kexec/kexec.c kexec-tools/kexec/kexec.c --- kexec-tools-1.8/kexec/kexec.c 2002-12-02 03:40:08.000000000 +0000 +++ kexec-tools/kexec/kexec.c 2003-03-11 16:03:59.000000000 +0000 @@ -7,6 +7,9 @@ #include #include "kexec.h" +#ifndef MAX +#define MAX(_x,_y) (((_x)>=(_y))?(_x):(_y)) +#endif /* local variables */ static struct memory_range *memory_range; @@ -72,6 +75,7 @@ int i, j; struct memory_range *mem_range; int max_mem_ranges, mem_ranges; + unsigned long start = 0, size; /* Compute the free memory ranges */ max_mem_ranges = memory_ranges + (segments -1); @@ -107,8 +111,7 @@ } /* Now find the first memory_range I can use */ for(i = 0; i < mem_ranges; i++) { - unsigned long start, size; - start = (mem_range[i].start + align -1) & ~(align -1); + start = (MAX(mem_range[i].start,0x100) +align-1) & ~(align-1); size = mem_range[i].end - start; if (size >= segment[0].memsz) { break; @@ -123,7 +126,7 @@ max); return -1; } - segment[0].mem = (void *)(unsigned long)((mem_range[i].start + align - 1) & ~(align -1)); + segment[0].mem = (void *)start; return 0; } @@ -134,7 +137,7 @@ { char *kernel; FILE *fp_kernel; - int i; + int i, ft; int result; struct kexec_segment *segments; int nr_segments; @@ -157,20 +160,24 @@ fprintf(stderr, "Could not get memory layout\n"); return -1; } - for(i = 0; i < file_types; i++) { - if (type && (strcmp(type, file_type[i].name) != 0)) { + for(ft = 0; ft < file_types; ft++) { + if (type && (strcmp(type, file_type[ft].name) == 0)) { break; } - if (file_type[i].probe(fp_kernel) > 0) { - break; + if (!type) { + result = file_type[ft].probe(fp_kernel); + if (result < 0) + return result; + if (result > 0) + break; } } - if (i == file_types) { + if (ft == file_types) { fprintf(stderr, "Can not determine the file type of %s\n", kernel); return -1; } - if (file_type[i].load(fp_kernel, argc, argv, + if (file_type[ft].load(fp_kernel, argc, argv, &entry, &segments, &nr_segments) < 0) { fprintf(stderr, "Can not load %s\n", kernel); return -1; @@ -193,14 +200,17 @@ /* The load failed, print some debugging information */ fprintf(stderr, "kexec_load failed: %s\n", strerror(errno)); - fprintf(stderr, "entry = %p\n", entry); - fprintf(stderr, "nr_segments = %d\n", nr_segments); - for(i = 0; i < nr_segments; i++) { - fprintf(stderr, "segment[%d].buf = %p\n", i, segments[i].buf); - fprintf(stderr, "segment[%d].bufsz = %x\n", i, segments[i].bufsz); - fprintf(stderr, "segment[%d].mem = %p\n", i, segments[i].mem); - fprintf(stderr, "segment[%d].memsz = %x\n", i, segments[i].memsz); - } + } else { + fprintf(stderr, "kexec_load succeeded (%s)\n", + file_type[ft].name); + } + fprintf(stderr, "entry = %p\n", entry); + fprintf(stderr, "nr_segments = %d\n", nr_segments); + for(i = 0; i < nr_segments; i++) { + fprintf(stderr, "segment[%d].buf = %p\n", i, segments[i].buf); + fprintf(stderr, "segment[%d].bufsz = %x\n", i, segments[i].bufsz); + fprintf(stderr, "segment[%d].mem = %p\n", i, segments[i].mem); + fprintf(stderr, "segment[%d].memsz = %x\n", i, segments[i].memsz); } return result; } diff -rNu kexec-tools-1.8/kexec/mb_header.h kexec-tools/kexec/mb_header.h --- kexec-tools-1.8/kexec/mb_header.h 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools/kexec/mb_header.h 2003-03-02 15:44:13.000000000 +0000 @@ -0,0 +1,90 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * MultiBoot Header description + */ + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see below. */ + unsigned magic; + + /* Feature flags - see below. */ + unsigned flags; + + /* + * Checksum + * + * The above fields plus this one must equal 0 mod 2^32. + */ + unsigned checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + unsigned header_addr; + unsigned load_addr; + unsigned load_end_addr; + unsigned bss_end_addr; + unsigned entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + unsigned mode_type; + unsigned width; + unsigned height; + unsigned depth; +}; + +/* + * The entire multiboot_header must be contained + * within the first MULTIBOOT_SEARCH bytes of the kernel image. + */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_FOUND(addr, len) \ + (! ((addr) & 0x3) \ + && (len) >= 12 \ + && *((int *) (addr)) == MULTIBOOT_MAGIC \ + && ! (*((unsigned *) (addr)) + *((unsigned *) (addr + 4)) \ + + *((unsigned *) (addr + 8))) \ + && (! (MULTIBOOT_AOUT_KLUDGE & *((int *) (addr + 4))) || (len) >= 32) \ + && (! (MULTIBOOT_VIDEO_MODE & *((int *) (addr + 4))) || (len) >= 48)) + +/* Magic value identifying the multiboot_header. */ +#define MULTIBOOT_MAGIC 0x1BADB002 + +/* + * Features flags for 'flags'. + * If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set + * and it doesn't understand it, it must fail. + */ +#define MULTIBOOT_MUSTKNOW 0x0000FFFF + +/* currently unsupported flags... this is a kind of version number. */ +#define MULTIBOOT_UNSUPPORTED 0x0000FFF8 + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 diff -rNu kexec-tools-1.8/kexec/mb_info.h kexec-tools/kexec/mb_info.h --- kexec-tools-1.8/kexec/mb_info.h 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools/kexec/mb_info.h 2003-03-02 16:40:30.000000000 +0000 @@ -0,0 +1,217 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * The structure type "mod_list" is used by the "multiboot_info" structure. + */ + +struct mod_list +{ + /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ + unsigned long mod_start; + unsigned long mod_end; + + /* Module command line */ + unsigned long cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + unsigned long pad; +}; + + +/* + * INT-15, AX=E820 style "AddressRangeDescriptor" + * ...with a "size" parameter on the front which is the structure size - 4, + * pointing to the next one, up until the full buffer length of the memory + * map has been reached. + */ + +struct AddrRangeDesc +{ + unsigned long size; + unsigned long long BaseAddr; + unsigned long long Length; + unsigned long Type; + + /* unspecified optional padding... */ +}; + +/* usable memory "Type", all others are reserved. */ +#define MB_ARD_MEMORY 1 + + +/* Drive Info structure. */ +struct drive_info +{ + /* The size of this structure. */ + unsigned long size; + + /* The BIOS drive number. */ + unsigned char drive_number; + + /* The access mode (see below). */ + unsigned char drive_mode; + + /* The BIOS geometry. */ + unsigned short drive_cylinders; + unsigned char drive_heads; + unsigned char drive_sectors; + + /* The array of I/O ports used for the drive. */ + unsigned short drive_ports[0]; +}; + +/* Drive Mode. */ +#define MB_DI_CHS_MODE 0 +#define MB_DI_LBA_MODE 1 + + +/* APM BIOS info. */ +struct apm_info +{ + unsigned short version; + unsigned short cseg; + unsigned long offset; + unsigned short cseg_16; + unsigned short dseg_16; + unsigned short cseg_len; + unsigned short cseg_16_len; + unsigned short dseg_16_len; +}; + + +/* + * MultiBoot Info description + * + * This is the struct passed to the boot image. This is done by placing + * its address in the EAX register. + */ + +struct multiboot_info +{ + /* MultiBoot info version number */ + unsigned long flags; + + /* Available memory from BIOS */ + unsigned long mem_lower; + unsigned long mem_upper; + + /* "root" partition */ + unsigned long boot_device; + + /* Kernel command line */ + unsigned long cmdline; + + /* Boot-Module list */ + unsigned long mods_count; + unsigned long mods_addr; + + union + { + struct + { + /* (a.out) Kernel symbol table info */ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long pad; + } + a; + + struct + { + /* (ELF) Kernel section header table */ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; + } + e; + } + syms; + + /* Memory Mapping buffer */ + unsigned long mmap_length; + unsigned long mmap_addr; + + /* Drive Info buffer */ + unsigned long drives_length; + unsigned long drives_addr; + + /* ROM configuration table */ + unsigned long config_table; + + /* Boot Loader Name */ + unsigned long boot_loader_name; + + /* APM table */ + unsigned long apm_table; + + /* Video */ + unsigned long vbe_control_info; + unsigned long vbe_mode_info; + unsigned short vbe_mode; + unsigned short vbe_interface_seg; + unsigned short vbe_interface_off; + unsigned short vbe_interface_len; +}; + +/* + * Flags to be set in the 'flags' parameter above + */ + +/* is there basic lower/upper memory information? */ +#define MB_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MB_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MB_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MB_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MB_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MB_INFO_ELF_SHDR 0x00000020 + +/* is there a full memory map? */ +#define MB_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MB_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MB_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MB_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MB_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MB_INFO_VIDEO_INFO 0x00000800 + +/* + * The following value must be present in the EAX register. + */ + +#define MULTIBOOT_VALID 0x2BADB002 diff -rNu kexec-tools-1.8/kexec/x86-reset-vga.S kexec-tools/kexec/x86-reset-vga.S --- kexec-tools-1.8/kexec/x86-reset-vga.S 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools/kexec/x86-reset-vga.S 2003-03-12 11:42:53.000000000 +0000 @@ -0,0 +1,260 @@ +/* Crudely reset a VGA card to text mode 3, by writing plausible default */ +/* values into its registers. */ +/* Tim Deegan (tjd21@cl.cam.ac.uk), March 2003 */ +/* Based on Keir Fraser's start-of-day reset code from the Xen hypervisor */ + .code32 + .globl x86_reset_vga, x86_reset_vga_end +x86_reset_vga: + push %eax + push %edx + /* Hello */ + movw $0x3da, %dx + inb %dx, %al + movb $0x00, %al + movw $0x3c0, %dx + outb %al, %dx + /* Sequencer registers */ + movw $0x3c4, %dx + movw $0x0300, %ax + outw %ax, %dx + movw $0x0001, %ax + outw %ax, %dx + movw $0x0302, %ax + outw %ax, %dx + movw $0x0003, %ax + outw %ax, %dx + movw $0x0204, %ax + outw %ax, %dx + /* Ensure CRTC regs 0-7 are unlocked by clearing bit 7 of CRTC[17] */ + movw $0x3d4, %dx + movw $0x0e11, %ax + outw %ax, %dx + /* CRTC registers */ + movw $0x5f00, %ax + outw %ax, %dx + movw $0x4f01, %ax + outw %ax, %dx + movw $0x5002, %ax + outw %ax, %dx + movw $0x8203, %ax + outw %ax, %dx + movw $0x5504, %ax + outw %ax, %dx + movw $0x8105, %ax + outw %ax, %dx + movw $0xbf06, %ax + outw %ax, %dx + movw $0x1f07, %ax + outw %ax, %dx + movw $0x0008, %ax + outw %ax, %dx + movw $0x4f09, %ax + outw %ax, %dx + movw $0x200a, %ax + outw %ax, %dx + movw $0x0e0b, %ax + outw %ax, %dx + movw $0x000c, %ax + outw %ax, %dx + movw $0x000d, %ax + outw %ax, %dx + movw $0x010e, %ax + outw %ax, %dx + movw $0xe00f, %ax + outw %ax, %dx + movw $0x9c10, %ax + outw %ax, %dx + movw $0x8e11, %ax + outw %ax, %dx + movw $0x8f12, %ax + outw %ax, %dx + movw $0x2813, %ax + outw %ax, %dx + movw $0x1f14, %ax + outw %ax, %dx + movw $0x9615, %ax + outw %ax, %dx + movw $0xb916, %ax + outw %ax, %dx + movw $0xa317, %ax + outw %ax, %dx + movw $0xff18, %ax + outw %ax, %dx + /* Graphic registers */ + movw $0x3ce, %dx + movw $0x0000, %ax + outw %ax, %dx + movw $0x0001, %ax + outw %ax, %dx + movw $0x0002, %ax + outw %ax, %dx + movw $0x0003, %ax + outw %ax, %dx + movw $0x0004, %ax + outw %ax, %dx + movw $0x1005, %ax + outw %ax, %dx + movw $0x0e06, %ax + outw %ax, %dx + movw $0x0007, %ax + outw %ax, %dx + movw $0xff08, %ax + outw %ax, %dx + /* Attribute registers */ + movw $0x3da, %dx + inb %dx, %al + movb $0x00, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x00, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x01, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x01, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x02, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x02, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x03, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x03, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x04, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x04, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x05, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x05, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x06, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x14, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x07, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x07, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x08, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x38, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x09, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x39, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x0a, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x3a, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x0b, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x3b, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x0c, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x3c, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x0d, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x3d, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x0e, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x3e, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x0f, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x3f, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x10, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x0c, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x11, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x00, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x12, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x0f, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x13, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x08, %al + outb %al, %dx + movw $0x3da, %dx + inb %dx, %al + movb $0x14, %al + movw $0x3c0, %dx + outb %al, %dx + movb $0x00, %al + outb %al, %dx + /* Goodbye */ + movw $0x3da, %dx + inb %dx, %al + movb $0x20, %al + movw $0x3c0, %dx + outb %al, %dx + pop %edx + pop %eax + nop +x86_reset_vga_end: