[PATCH 2.5.12] x86 Boot enhancements, bzElf support 11/11

From: Eric W. Biederman (ebiederm@xmission.com)
Date: Thu May 02 2002 - 10:15:57 EST


Please apply,

This patch allows a bzELF image to be built instead of a bzImage.
A bzELF is just a bzImage represented in the ELF file format. The transform
from bzELF to bzImage is 1-1.

Eric

diff -uNr linux-2.5.12.boot.linuxbios/arch/i386/Makefile linux-2.5.12.boot.elf/arch/i386/Makefile
--- linux-2.5.12.boot.linuxbios/arch/i386/Makefile Wed May 1 09:38:47 2002
+++ linux-2.5.12.boot.elf/arch/i386/Makefile Wed May 1 09:41:44 2002
@@ -119,6 +119,9 @@
 bzImage: vmlinux
         @$(MAKEBOOT) bzImage
 
+bzElf: vmlinux
+ @$(MAKEBOOT) bzElf
+
 compressed: zImage
 
 zlilo: vmlinux
diff -uNr linux-2.5.12.boot.linuxbios/arch/i386/boot/Makefile linux-2.5.12.boot.elf/arch/i386/boot/Makefile
--- linux-2.5.12.boot.linuxbios/arch/i386/boot/Makefile Wed May 1 09:40:42 2002
+++ linux-2.5.12.boot.elf/arch/i386/boot/Makefile Wed May 1 09:41:44 2002
@@ -18,6 +18,9 @@
 bzImage: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux brealmode compressed/bvmlinux
         tools/build -b $(TOPDIR)/vmlinux brealmode compressed/bvmlinux bzImage
 
+bzElf: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux brealmode compressed/bvmlinux
+ tools/build -e -b $(TOPDIR)/vmlinux brealmode compressed/bvmlinux bzElf
+
 compressed/vmlinux: $(TOPDIR)/vmlinux
         @$(MAKE) -C compressed vmlinux
 
@@ -75,5 +78,5 @@
 clean:
         rm -f tools/build
         rm -f realmode zImage
- rm -f brealmode bzImage
+ rm -f brealmode bzImage bzElf
         @$(MAKE) -C compressed clean
diff -uNr linux-2.5.12.boot.linuxbios/arch/i386/boot/tools/build.c linux-2.5.12.boot.elf/arch/i386/boot/tools/build.c
--- linux-2.5.12.boot.linuxbios/arch/i386/boot/tools/build.c Wed May 1 09:40:42 2002
+++ linux-2.5.12.boot.elf/arch/i386/boot/tools/build.c Wed May 1 09:41:44 2002
@@ -80,11 +80,12 @@
 #define ISEGS 3
 
 /* Segments of the output file */
-#define OREAL 0
-#define OKERN 1
-#define OBSS1 2
-#define OBSS2 3
-#define OSEGS 4
+#define OEHDR 0
+#define OREAL 1
+#define OKERN 2
+#define OBSS1 3
+#define OBSS2 4
+#define OSEGS 5
 
 struct file_seg
 {
@@ -96,6 +97,37 @@
         unsigned char *data;
 };
 
+/* Kernel version */
+#define LINUX_KERNEL_VERSION \
+ UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") " UTS_VERSION
+
+typedef uint16_t Elf_Half;
+typedef uint32_t Elf_Word;
+typedef uint64_t Elf_Xword;
+
+typedef struct
+{
+ Elf_Word n_namesz; /* Length of the note's name. */
+ Elf_Word n_descsz; /* Length of the note's descriptor. */
+ Elf_Word n_type; /* Type of the note. */
+} Elf_Nhdr;
+
+typedef struct
+{
+ Elf_Word n_paddr;
+ Elf_Word n_size;
+} Elf_Pdesc;
+
+/* Elf image notes for booting... The name for all of these is ELFBoot */
+
+#define EIN_NOTE_NAME "ELFBoot"
+#define EIN_PROGRAM_NAME 0x00000001
+/* The program in this ELF file */
+#define EIN_PROGRAM_VERSION 0x00000002
+/* The version of the program in this ELF file */
+#define EIN_PROGRAM_CHECKSUM 0x00000003
+/* ip style checksum of the memory image. */
+
 struct boot_params {
         uint8_t reserved1[0x1f1]; /* 0x000 */
         uint8_t setup_sects; /* 0x1f1 */
@@ -335,6 +367,76 @@
         return result;
 }
 
+static unsigned long compute_ip_checksum(void *addr, unsigned long length)
+{
+ uint16_t *ptr;
+ unsigned long sum;
+ unsigned long len;
+ unsigned long laddr;
+ /* compute an ip style checksum */
+ laddr = (unsigned long )addr;
+ sum = 0;
+ if (laddr & 1) {
+ uint16_t buffer;
+ unsigned char *ptr;
+ /* copy the first byte into a 2 byte buffer.
+ * This way automatically handles the endian question
+ * of which byte (low or high) the last byte goes in.
+ */
+ buffer = 0;
+ ptr = addr;
+ memcpy(&buffer, ptr, 1);
+ sum += buffer;
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ length -= 1;
+ addr = ptr +1;
+ }
+ len = length >> 1;
+ ptr = addr;
+ while (len--) {
+ sum += *(ptr++);
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ addr = ptr;
+ if (length & 1) {
+ uint16_t buffer;
+ unsigned char *ptr;
+ /* copy the last byte into a 2 byte buffer.
+ * This way automatically handles the endian question
+ * of which byte (low or high) the last byte goes in.
+ */
+ buffer = 0;
+ ptr = addr;
+ memcpy(&buffer, ptr, 1);
+ sum += buffer;
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ return (~sum) & 0xFFFF;
+
+}
+
+static unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new)
+{
+ unsigned long checksum;
+ sum = ~sum & 0xFFFF;
+ new = ~new & 0xFFFF;
+ if (offset & 1) {
+ /* byte swap the sum if it came from an odd offset
+ * since the computation is endian independant this
+ * works.
+ */
+ new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
+ }
+ checksum = sum + new;
+ if (checksum > 0xFFFF) {
+ checksum -= 0xFFFF;
+ }
+ return (~checksum) & 0xFFFF;
+}
+
 static void check_ehdr(Elf32_Ehdr *ehdr, char *name)
 {
         /* Do some basic to ensure it is an ELF image */
@@ -489,6 +591,7 @@
 
 struct image_info {
         int is_big_kernel;
+ int is_elf;
         size_t entry32;
         size_t setup_sectors;
         size_t sys_size;
@@ -518,11 +621,114 @@
         zhdr->output_overhang = cpu_to_le32(info->unzip_overhang);
         zhdr->kernel_memsz = cpu_to_le32(iseg[IKERN].mem_size);
         zhdr->kernel_filesz = cpu_to_le32(iseg[IKERN].data_size);
+ if (info->is_elf) {
+ /* For ELF images we don't expect the header to be relocated */
+ param->loadflags |= cpu_to_le32(LOADFLAG_STAY_PUT);
+ param->type_of_loader = LOADER_UNKNOWN;
+ }
+}
+
+struct elf_header {
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr[OSEGS - (OEHDR + 1)];
+ Elf_Nhdr program_name_hdr;
+ uint8_t program_name_name[8];
+ uint8_t program_name_desc[8];
+ Elf_Nhdr program_version_hdr;
+ uint8_t program_version_name[8];
+ uint8_t program_version_desc[(sizeof(LINUX_KERNEL_VERSION) + 3) & ~3];
+ Elf_Nhdr program_checksum_hdr;
+ uint8_t program_checksum_name[8];
+ uint16_t program_checksum;
+ uint16_t program_checksum_pad;
+} __attribute__((packed));
+
+static void build_elf_header(struct file_seg *seg, struct image_info *info)
+{
+ struct elf_header *hdr;
+ size_t checksum, bytes;
+ size_t offset, size;
+ int i;
+ hdr = checked_malloc(sizeof(*hdr));
+ memset(hdr, 0, sizeof(*hdr));
+ memcpy(hdr->ehdr.e_ident, ELFMAG, 4);
+ hdr->ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+ hdr->ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+ hdr->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ hdr->ehdr.e_type = cpu_to_le16(ET_EXEC);
+ hdr->ehdr.e_machine = cpu_to_le16(EM_386);
+ hdr->ehdr.e_version = cpu_to_le32(EV_CURRENT);
+ hdr->ehdr.e_entry = cpu_to_le32(info->entry32);
+ hdr->ehdr.e_phoff = cpu_to_le32(offsetof(struct elf_header, phdr));
+ hdr->ehdr.e_shoff = cpu_to_le32(0);
+ hdr->ehdr.e_flags = cpu_to_le16(0);
+ hdr->ehdr.e_ehsize = cpu_to_le16(sizeof(hdr->ehdr));
+ hdr->ehdr.e_phentsize = cpu_to_le16(sizeof(hdr->phdr[0]));
+ hdr->ehdr.e_phnum = cpu_to_le16(sizeof(hdr->phdr)/sizeof(hdr->phdr[0]));
+ hdr->ehdr.e_shentsize = cpu_to_le16(0);
+ hdr->ehdr.e_shnum = cpu_to_le16(0);
+ hdr->ehdr.e_shstrndx = cpu_to_le16(0);
+
+ offset = offsetof(struct elf_header, program_name_hdr);
+ size = sizeof(*hdr) - offset;
+ hdr->phdr[0].p_type = cpu_to_le32(PT_NOTE);
+ hdr->phdr[0].p_offset = cpu_to_le32(offset);
+ hdr->phdr[0].p_vaddr = cpu_to_le32(0);
+ hdr->phdr[0].p_paddr = cpu_to_le32(0);
+ hdr->phdr[0].p_filesz = cpu_to_le32(size);
+ hdr->phdr[0].p_memsz = cpu_to_le32(size);
+ hdr->phdr[0].p_flags = cpu_to_le32(0);
+ hdr->phdr[0].p_align = cpu_to_le32(0);
+
+ for(i = OEHDR +1; i < OSEGS; i++) {
+ hdr->phdr[i].p_type = cpu_to_le32(PT_NULL);
+ if (seg[i].mem_size == 0)
+ continue;
+ hdr->phdr[i].p_type = cpu_to_le32(PT_LOAD);
+ hdr->phdr[i].p_offset = cpu_to_le32(seg[i].file_offset);
+ hdr->phdr[i].p_vaddr = cpu_to_le32(seg[i].mem_addr);
+ hdr->phdr[i].p_paddr = cpu_to_le32(seg[i].mem_addr);
+ hdr->phdr[i].p_filesz = cpu_to_le32(seg[i].data_size);
+ hdr->phdr[i].p_memsz = cpu_to_le32(seg[i].mem_size);
+ hdr->phdr[i].p_flags = cpu_to_le32(0);
+ hdr->phdr[i].p_align = cpu_to_le32(0);
+ }
+
+ hdr->program_name_hdr.n_namesz = cpu_to_le32(strlen(EIN_NOTE_NAME) +1);
+ hdr->program_name_hdr.n_descsz = cpu_to_le32(strlen("Linux") +1);
+ hdr->program_name_hdr.n_type = cpu_to_le32(EIN_PROGRAM_NAME);
+ strcpy(hdr->program_name_name, EIN_NOTE_NAME);
+ strcpy(hdr->program_name_desc, "Linux");
+
+ hdr->program_version_hdr.n_namesz = cpu_to_le32(strlen(EIN_NOTE_NAME) +1);
+ hdr->program_version_hdr.n_descsz = cpu_to_le32(strlen(LINUX_KERNEL_VERSION)+1);
+ hdr->program_version_hdr.n_type = cpu_to_le32(EIN_PROGRAM_VERSION);
+ strcpy(hdr->program_version_name, EIN_NOTE_NAME);
+ strcpy(hdr->program_version_desc, LINUX_KERNEL_VERSION);
+
+ hdr->program_checksum_hdr.n_namesz = cpu_to_le32(strlen(EIN_NOTE_NAME) +1);
+ hdr->program_checksum_hdr.n_descsz = cpu_to_le32(2);
+ hdr->program_checksum_hdr.n_type = cpu_to_le32(EIN_PROGRAM_CHECKSUM);
+ strcpy(hdr->program_checksum_name, EIN_NOTE_NAME);
+ hdr->program_checksum = cpu_to_le16(0); /* This is written later */
+
+ /* Compute the image checksum, this covers everything except the
+ * ELF notes.
+ */
+ bytes = sizeof(hdr->ehdr) + sizeof(hdr->phdr);
+ checksum = compute_ip_checksum(hdr, bytes);
+ for(i = 1; i < 4; i++) {
+ checksum = add_ip_checksums(bytes, checksum,
+ compute_ip_checksum(seg[i].data, seg[i].data_size));
+ bytes += seg[i].mem_size;
+ }
+ hdr->program_checksum = cpu_to_le16(checksum);
+ seg[OEHDR].data = (unsigned char *)hdr;
 }
 
 static void usage(void)
 {
- die("Usage: build [-b] vmlinux realmode compressed/vmlinux image");
+ die("Usage: build [-e] [-b] vmlinux realmode compressed/vmlinux image");
 }
 
 int main(int argc, char ** argv)
@@ -544,6 +750,12 @@
         memset(oseg, 0, sizeof(oseg));
         memset(&info, 0, sizeof(info));
         info.is_big_kernel = 0;
+ info.is_elf = 0;
+ if (argc > 2 && (strcmp(argv[1], "-e") == 0)) {
+ info.is_elf = 1;
+ argc--;
+ argv++;
+ }
         if (argc > 2 && (strcmp(argv[1], "-b") == 0)) {
                 info.is_big_kernel = 1;
                 argc--;
@@ -626,7 +838,7 @@
         } else {
                 /* bzImage */
                 size_t unzip_bufsz;
-
+
                 /* Compute the bzImage decompressor memory size */
                 unzip_bufsz = iseg[IKERN].data_size + info.unzip_overhang;
                 if (unzip_bufsz > oseg[OKERN].mem_size) {
@@ -653,7 +865,15 @@
         info.setup_sectors = (oseg[OREAL].data_size - 512 + 511)/512;
         if (info.setup_sectors < SETUP_SECTS)
                 info.setup_sectors = SETUP_SECTS;
+ if (info.is_elf) {
+ oseg[OEHDR].data_size = sizeof(struct elf_header);
+ }
 
+ /* Note: for ELF images I don't have to make OREAL
+ * info.setup_sectors long, but it makes the conversion back
+ * to a bzImage just a trivial header removal.
+ */
+ oseg[OREAL].file_offset = oseg[OEHDR].file_offset + oseg[OEHDR].data_size;
         oseg[OKERN].file_offset = oseg[OREAL].file_offset + (info.setup_sectors +1)*512;
 
         /* Check and print the values to write back. */
@@ -692,6 +912,10 @@
 
         /* Write the values back */
         update_image(iseg, oseg, &info);
+ if (info.is_elf) {
+ build_elf_header(oseg, &info);
+ printf("elf_header_size=%d\n", oseg[OEHDR].data_size);
+ }
 
         /* Write destination file */
         image_fd = checked_open(image, O_RDWR | O_CREAT | O_TRUNC, 0666);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue May 07 2002 - 22:00:13 EST