From 595220a3ab61d092f3ee729b78c1280e2ba8c87d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 22 Jan 2002 18:03:40 +0000 Subject: [PATCH] Commit version 1.10 of mkelfImage. The big change is that it now generates ELF notes especially an ELF checksum of the entire image. This finishes my proof of concept implementation of all significant features with respect to ELF booting. Now to do some native ports... --- util/mkelfImage/Makefile | 4 +- util/mkelfImage/elf32-i386/convert_params.c | 337 +++++++------------- util/mkelfImage/elf32-i386/elfImage.lds | 34 +- util/mkelfImage/elf32-i386/elf_boot.h | 3 + util/mkelfImage/elf32-i386/head.S | 141 +++++++- util/mkelfImage/mkelfImage.pl | 163 +++++++++- 6 files changed, 425 insertions(+), 257 deletions(-) diff --git a/util/mkelfImage/Makefile b/util/mkelfImage/Makefile index a574af5c5f..923cef8013 100644 --- a/util/mkelfImage/Makefile +++ b/util/mkelfImage/Makefile @@ -6,8 +6,8 @@ # the result will be a directory tree that you can run mkelfImage in PREFIX=/usr/local/ PERLPATH=/usr/bin/perl -VERSION="1.9" -DATE="7 January 2002" +VERSION="1.10" +DATE="21 January 2002" SHAREDIR=$(PREFIX)/share/mkelfImage BINDIR=$(PREFIX)/bin diff --git a/util/mkelfImage/elf32-i386/convert_params.c b/util/mkelfImage/elf32-i386/convert_params.c index 4ccc5d2936..5c2db91cf2 100644 --- a/util/mkelfImage/elf32-i386/convert_params.c +++ b/util/mkelfImage/elf32-i386/convert_params.c @@ -202,128 +202,11 @@ struct param_info { typedef unsigned size_t; -#define _NOTE __attribute__((__section__(".rodata"))) -static const struct { - Elf_Word namesz; - Elf_Word descsz; - Elf_Word type; - unsigned char name[8]; - unsigned char desc[6]; - unsigned char dummy[2]; -} program _NOTE = { - sizeof(program.name), - sizeof(program.desc), - EIN_PROGRAM_NAME, - "ElfBoot", - "Linux" -}; - -static const struct { - Elf_Word namesz; - Elf_Word descsz; - Elf_Word type; - unsigned char name[8]; - unsigned char desc[64]; -} program_version _NOTE = { - sizeof(program.name), - sizeof(program.desc), - EIN_PROGRAM_NAME, - "ElfBoot", - "2.2.17 (eric@DLT) #21 Wed Jan 3 14:44:09 MST 2001" -}; - -static const struct { - Elf_Word namesz; - Elf_Word descsz; - Elf_Word type; - unsigned char name[6]; - unsigned char dummy[2]; - char command_line[256]; -} note_command_line _NOTE = { - sizeof(program.name), - sizeof(program.desc), - LIN_COMMAND_LINE, - "Linux", { 0, 0 }, - DEFAULT_COMMAND_LINE, -}; - -static const struct { - Elf_Word namesz; - Elf_Word descsz; - Elf_Word type; - unsigned char name[6]; - unsigned char dummy[2]; - unsigned short root_dev; - unsigned char dummy2[2]; -} note_root_dev _NOTE = { - sizeof(program.name), - sizeof(program.desc), - LIN_ROOT_DEV, - "Linux", { 0, 0 }, - DEFAULT_ROOT_DEV, { 0, 0 }, -}; - - -static const struct { - Elf_Word namesz; - Elf_Word descsz; - Elf_Word type; - unsigned char name[6]; - unsigned char dummy[2]; - unsigned short ramdisk_flags; - unsigned char dummy2[2]; -} note_ramdisk_flags _NOTE = { - sizeof(program.name), - sizeof(program.desc), - LIN_RAMDISK_FLAGS, - "Linux", { 0, 0 }, - 0 -#if defined(DEFAULT_RAMDISK_IMAGE_START) - | (DEFAULT_RAMDISK_IMAGE_START & RAMDISK_IMAGE_START_MASK) -#endif -#if defined(DEFAULT_RAMDISK_PROMPT_FLAG) - | RAMDISK_PROMPT_FLAG -#endif -#if defined(DEFAULT_RAMDISK_LOAD_FLAG) - | RAMDISK_LOAD_FLAG -#endif - , { 0 , 0 }, - -}; - - -extern char ramdisk_data[], ramdisk_data_size[]; - -static const struct { - Elf_Word namesz; - Elf_Word descsz; - Elf_Word type; - unsigned char name[6]; - unsigned char dummy[2]; - unsigned initrd_start; -} note_initrd_start _NOTE = { - sizeof(program.name), - sizeof(program.desc), - LIN_INITRD_START, - "Linux", { 0, 0 }, - (unsigned)&ramdisk_data, -}; - -static const struct { - Elf_Word namesz; - Elf_Word descsz; - Elf_Word type; - unsigned char name[6]; - unsigned char dummy[2]; - unsigned initrd_size; -} note_initrd_size _NOTE = { - sizeof(program.name), - sizeof(program.desc), - LIN_INITRD_SIZE, - "Linux", { 0, 0 }, - ((unsigned)&ramdisk_data_size), -}; - +extern char note_command_line[]; +extern unsigned short note_root_dev; +extern unsigned short note_ramdisk_flags; +extern unsigned long note_initrd_start; +extern unsigned long note_initrd_size; /* FIXME handle systems with large EBDA's */ static struct parameters *faked_real_mode = (void *)0x90000; @@ -805,52 +688,36 @@ static void hardware_setup(struct param_info *info) * ============================================================================= */ -static inline unsigned long elf_note_size(Elf_Nhdr *hdr) -{ - unsigned long size; - size = sizeof(*hdr); - size += hdr->n_namesz; - if (size & 3) { - size += 4 - (size & 3); - } - size = hdr->n_descsz; - if (size & 3) { - size += 4 - (size & 3); - } - return size; -} -static inline Elf_Nhdr *next_elf_note(Elf_Nhdr *hdr) -{ - return (void *)(((char *)hdr) + elf_note_size(hdr)); -} - -static inline unsigned char *elf_note_name(Elf_Nhdr *hdr) -{ - return (void *)(((char *)hdr) + sizeof(*hdr)); -} - -static inline unsigned char *elf_note_desc(Elf_Nhdr *hdr) -{ - int offset; - offset = sizeof(*hdr); - offset = hdr->n_namesz; - if (offset & 3) { - offset += 4 - (offset & 3); - } - return (void *)(((char *)hdr) + offset); -} - static int count_elf_notes(Elf_Bhdr *bhdr) { Elf_Nhdr *hdr; - void *start = (void *)bhdr; - void *end = ((char *)start) + bhdr->b_size; + unsigned char *note, *end; int count; count = 0; - for(hdr = start; ((void *)hdr < end) && - (elf_note_size(hdr) <= (end - (void *)hdr)); - hdr = next_elf_note(hdr)) { + note = ((char *)bhdr) + sizeof(*bhdr); + end = ((char *)bhdr) + bhdr->b_size; +#if 0 + puts("count_elf_notes"); put_hex((unsigned long)bhdr); puts("\n"); +#endif + while (note < end) { + Elf_Nhdr *hdr; + unsigned char *n_name, *n_desc, *next; + hdr = (Elf_Nhdr *)note; + n_name = note + sizeof(*hdr); + n_desc = n_name + ((hdr->n_namesz + 3) & ~3); + next = n_desc + ((hdr->n_descsz + 3) & ~3); +#if 0 + puts("elf_note = "); put_hex((unsigned long)note); puts("\n"); + puts("elf_namesz = "); put_hex(hdr->n_namesz); puts("\n"); + puts("elf_descsz = "); put_hex(hdr->n_descsz); puts("\n"); + puts("elf_type = "); put_hex(hdr->n_type); puts("\n"); + puts("elf_name = "); put_hex((unsigned long)n_name); puts("\n"); + puts("elf_desc = "); put_hex((unsigned long)n_desc); puts("\n"); +#endif + if (next > end) + break; count++; + note = next; } return count; } @@ -858,22 +725,24 @@ static int count_elf_notes(Elf_Bhdr *bhdr) static Elf_Nhdr *find_elf_note(Elf_Bhdr *bhdr, Elf_Word namesz, unsigned char *name, Elf_Word type) { - - Elf_Nhdr *hdr; - void *start = (void *)bhdr; - void *end = ((char *)start) + bhdr->b_size; - for(hdr = start; ((void *)hdr < end) && - (elf_note_size(hdr) <= (end - (void *)hdr)); - hdr = next_elf_note(hdr)) { - unsigned char *n_name; - unsigned char *n_desc; - n_name = elf_note_name(hdr); - n_desc = elf_note_desc(hdr); + unsigned char *note, *end; + note = ((char *)bhdr) + sizeof(*bhdr); + end = ((char *)bhdr) + bhdr->b_size; + while(note < end) { + Elf_Nhdr *hdr; + unsigned char *n_name, *n_desc, *next; + hdr = (Elf_Nhdr *)note; + n_name = note + sizeof(*hdr); + n_desc = n_name + ((hdr->n_namesz + 3) & ~3); + next = n_desc + ((hdr->n_descsz + 3) & ~3); + if (next > end) + break; if ((hdr->n_type == type) && (hdr->n_namesz == namesz) && (memcmp(n_name, name, namesz) == 0)) { return hdr; } + note = next; } return 0; } @@ -896,17 +765,19 @@ struct { static void convert_elf_boot(struct param_info *info, Elf_Bhdr *bhdr) { - Elf_Nhdr *hdr; - int i; - void *start = (void *)bhdr; - void *end = ((char *)start) + bhdr->b_size; - for(hdr = start; ((void *)hdr < end) && - (elf_note_size(hdr) <= (end - (void *)hdr)); - hdr = next_elf_note(hdr)) { - unsigned char *n_name; - unsigned char *n_desc; - n_name = elf_note_name(hdr); - n_desc = elf_note_desc(hdr); + unsigned char *note, *end; + note = ((char *)bhdr) + sizeof(*bhdr); + end = ((char *)bhdr) + bhdr->b_size; + while(note < end) { + Elf_Nhdr *hdr; + unsigned char *n_name, *n_desc, *next; + int i; + hdr = (Elf_Nhdr *)note; + n_name = note + sizeof(*hdr); + n_desc = n_name + ((hdr->n_namesz + 3) & ~3); + next = n_desc + ((hdr->n_descsz + 3) & ~3); + if (next > end) + break; for(i = 0; i < sizeof(elf_notes)/sizeof(elf_notes[0]); i++) { if ((hdr->n_type == elf_notes[i].type) && (hdr->n_namesz == elf_notes[i].namesz) && @@ -915,6 +786,7 @@ static void convert_elf_boot(struct param_info *info, Elf_Bhdr *bhdr) break; } } + note = next; } } @@ -949,7 +821,7 @@ static int count_lb_records(void *start, unsigned long length) return count; } -static int find_lb_table(struct param_info *info, void *start, void *end) +static struct lb_header *__find_lb_table(void *start, void *end) { unsigned char *ptr; /* For now be stupid.... */ @@ -966,14 +838,32 @@ static int find_lb_table(struct param_info *info, void *start, void *end) (count_lb_records(ptr + sizeof(*head), head->table_bytes) == head->table_entries) ) { - info->has_linuxbios = 1; - info->lb_table = (void *)ptr; - return 1; + return head; } }; return 0; } +static int find_lb_table(struct param_info *info) +{ + struct lb_header *head; + head = 0; + if (!head) { + /* First try at address 0 */ + head = __find_lb_table((void *)0x00000, (void *)0x1000); + } + if (!head) { + /* Then try at address 0xf0000 */ + head = __find_lb_table((void *)0xf0000, (void *)0x100000); + } + if (head) { + info->has_linuxbios = 1; + info->lb_table = head; + return 1; + } + return 0; +} + static void convert_lb_memory(struct param_info *info, struct lb_memory *mem) { int i; @@ -1148,6 +1038,12 @@ static void query_bootloader_param_class(struct param_info *info) } else { puts("Bad ELF parameter table!\n"); + puts(" checksum = "); put_hex(checksum); puts("\n"); + puts(" count = "); put_hex(count); puts("\n"); + puts(" hdr = "); put_hex((unsigned long)hdr); puts("\n"); + puts(" b_size = "); put_hex(hdr->b_size); puts("\n"); + puts("b_signature = "); put_hex(hdr->b_signature); puts("\n"); + puts(" b_records = "); put_hex(hdr->b_records); puts("\n"); } } if (!has_bootloader_type) { @@ -1178,33 +1074,52 @@ static void query_bootloader_values(struct param_info *info) static int bootloader_query_firmware_class(struct param_info *info) { Elf_Nhdr *hdr; + unsigned char *note, *n_name, *n_desc; + int detected_firmware_type; if (!info->has_elf_boot) { /* Only the elf boot tables gives us a firmware type */ return 0; } + detected_firmware_type = 0; + hdr = find_elf_note(info->data, 0, 0, EBN_FIRMWARE_TYPE); if (!hdr) { info->has_pcbios = 1; + detected_firmware_type = 1; + } else { + note = (char *)hdr; + n_name = note + sizeof(*hdr); + n_desc = n_name + ((hdr->n_namesz + 3) & ~3); } - else if ((hdr->n_descsz == 7) && - (memcmp(elf_note_desc(hdr), "PCBIOS", 7) == 0)) { + if (!detected_firmware_type && hdr && + (hdr->n_descsz == 7) && + (memcmp(n_desc, "PCBIOS", 7) == 0)) { info->has_pcbios = 1; + detected_firmware_type = 1; } - else if ((hdr->n_descsz == 10) && - (memcmp(elf_note_desc(hdr), "LinuxBIOS", 10) == 0)) { - info->has_linuxbios = 1; + if (!detected_firmware_type && hdr && + (hdr->n_descsz == 10) && + (memcmp(n_desc, "LinuxBIOS", 10) == 0)) { + /* Don't believe I'm linuxBIOS unless I can + * find the linuxBIOS table.. + */ + detected_firmware_type = find_lb_table(info); } - else if (hdr->n_descsz == 0) { + if (!detected_firmware_type && hdr && + (hdr->n_descsz == 0)) { /* No firmware is present */ + detected_firmware_type = 1; } - else if ((hdr->n_descsz == 1) && - (memcmp(elf_note_desc(hdr), "", 1) == 0)) { + if (!detected_firmware_type && hdr && + (hdr->n_descsz == 1) && + (memcmp(n_desc, "", 1) == 0)) { /* No firmware is present */ + detected_firmware_type = 1; } - else { - puts("Unknow firmware type!"); + if (!detected_firmware_type && hdr) { + puts("Unknown firmware type:"); puts(n_desc); puts("\n"); } - return 1; + return detected_firmware_type; } static void query_firmware_class(struct param_info *info) @@ -1222,15 +1137,7 @@ static void query_firmware_class(struct param_info *info) /* See if we can detect linuxbios. */ if (!detected_firmware_type) { - /* First try at address 0 */ - detected_firmware_type = - find_lb_table(info, (void*)0x00000, (void*)0x1000); - } - - if (!detected_firmware_type) { - /* Then try at address 0xf0000 */ - detected_firmware_type = - find_lb_table(info, (void*)0xf0000, (void*)0x100000); + detected_firmware_type = find_lb_table(info); } if (!detected_firmware_type) { @@ -1424,8 +1331,8 @@ void initialize_linux_params(struct param_info *info) info->real_mode->cl_offset = 2048; /* Now set the command line */ - len = strnlen(note_command_line.command_line, sizeof(info->real_mode->command_line) -1); - memcpy(info->real_mode->command_line, note_command_line.command_line, len); + len = strnlen(note_command_line, sizeof(info->real_mode->command_line) -1); + memcpy(info->real_mode->command_line, note_command_line, len); info->real_mode->command_line[len] = '\0'; /* from the bios initially */ @@ -1446,12 +1353,12 @@ void initialize_linux_params(struct param_info *info) /* old ramdisk options, These really should be command line * things... */ - info->real_mode->ramdisk_flags = note_ramdisk_flags.ramdisk_flags; + info->real_mode->ramdisk_flags = note_ramdisk_flags; /* default to /dev/hda. * Override this on the command line if necessary */ - info->real_mode->orig_root_dev = note_root_dev.root_dev; + info->real_mode->orig_root_dev = note_root_dev; /* Originally from the bios? */ info->real_mode->aux_device_info = 0; @@ -1469,9 +1376,9 @@ void initialize_linux_params(struct param_info *info) /* Ramdisk address and size ... */ info->real_mode->initrd_start = 0; info->real_mode->initrd_size = 0; - if (note_initrd_size.initrd_size) { - info->real_mode->initrd_start = note_initrd_start.initrd_start; - info->real_mode->initrd_size = note_initrd_size.initrd_size; + if (note_initrd_size) { + info->real_mode->initrd_start = note_initrd_start; + info->real_mode->initrd_size = note_initrd_size; } /* Now remember those things that I need */ diff --git a/util/mkelfImage/elf32-i386/elfImage.lds b/util/mkelfImage/elf32-i386/elfImage.lds index 89b5641b20..1343fe0f0b 100644 --- a/util/mkelfImage/elf32-i386/elfImage.lds +++ b/util/mkelfImage/elf32-i386/elfImage.lds @@ -18,25 +18,31 @@ INCLUDE mkelfImage.lds OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) -MEMORY + +PHDRS { - /* 0x10000 - 0x90000 A good safe area in low memory I can use */ - low (rwx) : ORIGIN = 0x010000, LENGTH = 0x0080000 - middle (rwx) : ORIGIN = 0x091000, LENGTH = 0x0001000 - upper (rwx) : ORIGIN = 0x100000, LENGTH = 0x37f00000 + note PT_NOTE ; + low PT_LOAD ; + middle PT_LOAD ; + upper PT_LOAD ; + ramdisk PT_LOAD ; } + ENTRY(startup_32) SECTIONS { . = 0x10000 ; _text = .; /* Text and read-only data */ - .text (.): { + .note . : { + *(.note.data) + } :note :low + .text . : { *(.text) *(.fixup) *(.gnu.warning) - } > low = 0x9090 - .rodata (.): { *(.rodata) *(.note.data)} > low - .kstrtab (.): { *(.kstrtab) } > low + } :low = 0x9090 + .rodata (.): { *(.rodata) } :low + .kstrtab (.): { *(.kstrtab) } :low . = ALIGN(16); /* Exception table */ @@ -45,29 +51,29 @@ SECTIONS .data (.): { /* Data */ *(.data) CONSTRUCTORS - } > low + } :low _edata = .; /* End of data section */ __bss_start = .; /* BSS */ .bss (.): { *(.bss) - } > low + } :low _end = . ; . = 0x91000 ; .nokill (.): { *(.nokill) - } > middle + } :middle . = 0x100000 ; .kernel (.): { *(.kernel) - } > upper + } :upper . = initrd_base; .ramdisk (ALIGN(4096)) : { *(.ramdisk) - } > upper + } :ramdisk ramdisk_data_size = (ramdisk_data_end - ramdisk_data); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff --git a/util/mkelfImage/elf32-i386/elf_boot.h b/util/mkelfImage/elf32-i386/elf_boot.h index b9b66b3752..2f93ceb89d 100644 --- a/util/mkelfImage/elf32-i386/elf_boot.h +++ b/util/mkelfImage/elf32-i386/elf_boot.h @@ -1,6 +1,7 @@ #ifndef ELF_BOOT_H #define ELF_BOOT_H +#ifndef ASSEMBLY #include /* This defines the structure of a table of parameters useful for ELF @@ -38,6 +39,8 @@ typedef struct Elf_Word n_type; /* Type of the note. */ } Elf_Nhdr; +#endif /* ASSEMBLY */ + /* For standard notes n_namesz must be zero */ /* All of the following standard note types provide a single null * terminated string in the descriptor. diff --git a/util/mkelfImage/elf32-i386/head.S b/util/mkelfImage/elf32-i386/head.S index f60598873e..7948fe983b 100644 --- a/util/mkelfImage/elf32-i386/head.S +++ b/util/mkelfImage/elf32-i386/head.S @@ -1,13 +1,15 @@ -# -# exec_kernel/user_space/head.S -# -# Copyright (C) 2000 Eric Biederman -# -# Parts of this code were take from the linux startup -# code of linux-2.4.0-test9 -# -# Other parts were taken from etherboot-5.0.5 -# +/* + * exec_kernel/user_space/head.S + * + * Copyright (C) 2000 Eric Biederman + * + * Parts of this code were take from the linux startup + * code of linux-2.4.0-test9 + * + * Other parts were taken from etherboot-5.0.5 + */ + +#define ASSEMBLY 1 #define RELOC 0x10000 #define KERN_CODE_SEG 0x10 @@ -17,6 +19,7 @@ .equ CR0_PE,1 +#if 0 #define TTYS0_BASE 0x3f8 #define TTYS0_RBR (TTYS0_BASE+0x00) #define TTYS0_TBR TTYS0_RBR @@ -38,6 +41,7 @@ #define TTYS0_TX_CHAR(byte) \ mov byte, %al ; \ TTYS0_TX_AL +#endif .text .code32 @@ -112,6 +116,8 @@ startup_32: /* Routines to query the BIOS... */ + +#if 0 .globl noop noop: TTYS0_TX_CHAR($'a') @@ -128,6 +134,7 @@ noop: TTYS0_TX_CHAR($'\r') TTYS0_TX_CHAR($'\n') ret +#endif /************************************************************************** E820_MEMSIZE - Get a listing of memory regions @@ -388,3 +395,117 @@ gdt: .byte (RELOC>>16),0x93,0x00,(RELOC>>24) +.section ".note.data", "a", @progbits +#include "elf_boot.h" +/* You can probably do this in C if everything was all in one structure, + * but doing it pieces resulted in strange alignments of the data structures. + * Since that breaks the definition of the .note section I do it here in + * in assembly. The control is better and for simplicity it is a toss up. + */ + .balign 4 + .int 2f - 1f + .int 4f - 3f + .int EIN_PROGRAM_NAME +1: .asciz "ELFBoot" +2: + .balign 4 +3: + .asciz "Linux" +4: + + + .balign 4 + .int 2f - 1f + .int 4f - 3f + .int EIN_PROGRAM_VERSION +1: .asciz "ELFBoot" +2: + .balign 4 +3: + .asciz DEFAULT_PROGRAM_VERSION +4: + + + + .balign 4 + .int 2f - 1f + .int 4f - 3f + .int EIN_PROGRAM_CHECKSUM +1: .asciz "ELFBoot" +2: + .balign 4 +3: + .word 0 +4: + + + .balign 4 + .int 2f - 1f + .int 4f - 3f + .int LIN_COMMAND_LINE +1: .asciz "Linux" +2: + .balign 4 +3: + .globl note_command_line +note_command_line: + .asciz DEFAULT_COMMAND_LINE +33: + .fill 256 - (33b - 3b), 1, 0 +4: + + + .balign 4 + .int 2f - 1f + .int 4f - 3f + .int LIN_ROOT_DEV +1: .asciz "Linux" +2: + .balign 4 +3: + .globl note_root_dev +note_root_dev: + .word DEFAULT_ROOT_DEV +4: + + .balign 4 + .int 2f - 1f + .int 4f - 3f + .int LIN_RAMDISK_FLAGS +1: .asciz "Linux" +2: + .balign 4 +3: + .globl note_ramdisk_flags +note_ramdisk_flags: + .word 0 +4: + + .balign 4 + .int 2f - 1f + .int 4f - 3f + .int LIN_INITRD_START +1: .asciz "Linux" +2: + .balign 4 +3: + .globl note_initrd_start +note_initrd_start: + .int ramdisk_data +4: + + .balign 4 + .int 2f - 1f + .int 4f - 3f + .int LIN_INITRD_SIZE +1: .asciz "Linux" +2: + .balign 4 +3: + .globl note_initrd_size +note_initrd_size: + .int ramdisk_data_size +4: + .balign 4 + .previous + diff --git a/util/mkelfImage/mkelfImage.pl b/util/mkelfImage/mkelfImage.pl index 9980b5b056..fccdf4841b 100644 --- a/util/mkelfImage/mkelfImage.pl +++ b/util/mkelfImage/mkelfImage.pl @@ -20,8 +20,9 @@ $params{PREFIX}=undef(); $params{RAMDISK}=""; $params{VMLINUX}="/usr/src/linux/vmlinux"; $params{TARGET}="elfImage"; -$params{ROOT_DEV}='((0x3<<16)| 0)'; +$params{ROOT_DEV}='((0x3<<8)| 0)'; $params{COMMAND_LINE}=''; +$params{PROGRAM_VERSION}=''; $params{OUTPUT_FORMAT}='elf32-i386'; $params{INITRD_BASE}=0x00800000; # 8MB @@ -30,18 +31,9 @@ sub compile_file { my ($params, $src, $dst) = @_; my ($options, $cmd); - $options = "-DDEFAULT_ROOT_DEV='((unsigned short)$params->{ROOT_DEV})'"; + $options = "-DDEFAULT_ROOT_DEV='($params->{ROOT_DEV})'"; $options .= " -DDEFAULT_COMMAND_LINE='\"$params->{COMMAND_LINE}\"'"; - if (defined($params->{RAMDISK_IMAGE_START})) { - $options .= " -DDEFAULT_RAMDISK_IMAGE_START=" . - "'((unsigned short)$params->{RAMDISK_IMAGE_START})'"; - } - if ($params->{RAMDISK_PROMPT_FLAG}) { - $options .= " -DDEFAULT_RAMDISK_PROMPT_FLAG"; - } - if ($params->{RAMDISK_LOAD_FLAG}) { - $options .= " -DDEFAULT_RAMDISK_LOAD_FLAG"; - } + $options .= " -DDEFAULT_PROGRAM_VERSION='\"$params->{PROGRAM_VERSION}\"'"; $cmd = "$params->{CC} $params->{CFLAGS} $options -c $params->{PREFIX}/$src -o $dst"; print " Running $cmd \n"; system($cmd); @@ -73,6 +65,18 @@ sub build_kernel_piggy $ramsize, $vidmode, $rootdev); (undef, $setupsects, $flags, $syssize, $swapdev, $ramsize, $vidmode, $rootdev) = unpack('a497Cv6', $buffer); + $fd_in->read($buffer, 32768) == 32768 + or die "Error reading setup sector of $src"; + my (undef, $header, $version, undef, $start_sys, $kver_addr) + = unpack('a2a4Sa4SS', $buffer); + if ($header ne 'HdrS') { + die "Not an linux kernel"; + } + if ($setupsects == 0) { + $setupsects = 4; + } + $params->{PROGRAM_VERSION} = unpack('Z32768', substr($buffer, $kver_addr)); + my $fd_out = new FileHandle; $fd_out->open(">${dst}.obj") or die "Cannot open ${dst}.obj"; $fd_in->seek(512 + (512*$setupsects), 0); @@ -152,6 +156,136 @@ sub build_elf_image return $dst; } +sub compute_ip_checksum +{ + my ($str) = @_; + my ($checksum, $i, $size, $shorts); + $checksum = 0; + $size = length($str); + $shorts = $size >> 1; + for($i = 0; $i < $shorts; $i++) { + $checksum += unpack('S', substr($str, $i <<1, 2)); + $checksum -= 0xFFFF unless ($checksum <= 0xFFFF); + } + if ($size & 1) { + $checksum -= 0xFFFF unless ($checksum <= 0xFFFF); + $checksum += unpack('C', substr($str, -1, 1)); + } + return (~$checksum) & 0xFFFF; +} + +sub add_ip_checksums +{ + my ($offset, $sum, $new) = @_; + my $checksum; + $sum = ~$sum & 0xFFFF; + $new = ~$new & 0xFFFF; + if ($offset & 1) { + $new = (($new >> 8) & 0xff) | (($new << 8) & 0xff00); + } + $checksum = $sum + $new; + if ($checksum > 0xFFFF) { + $checksum -= 0xFFFF; + } + return (~$checksum) & 0xFFFF; +} + + +sub write_ip_checksum +{ + my ($file) = @_; + my ($fd, $buffer, %ehdr, @phdrs, $key, $size, $i); + my ($checksum, $offset) = 0; + $fd = new FileHandle; + $fd->open("+<$file") or die "Cannot open $file\n"; + $fd->read($buffer, 52) == 52 or die "Cannot read ELF header\n"; + @ehdr{e_ident, e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, + e_flags, e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, + e_shstrndx} = unpack('a16SSLLLLLSSSSSS', $buffer); + $checksum = compute_ip_checksum($buffer); + $offset += 52; + + + ## FIXME add some sanity checks here... + #foreach $key (keys(%ehdr)) { + # print "$key: $ehdr{$key}\n"; + #} + + $fd->seek($ehdr{e_phoff}, 0) or die "Cannot seek to $ehdr{e_phoff}\n"; + $size = $ehdr{e_phnum}*32; + $fd->read($buffer, $size) == $size or die "Cannot read ELF Program header $size\n"; + for($i = 0; $i < $ehdr{e_phnum} ; $i++) { + my %phdr; + @phdr{p_type, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, + p_flags, p_align} + = unpack('LLLLLLLL', substr($buffer, $i*32, 32)); + push(@phdrs, \%phdr); + } + $checksum = add_ip_checksums($offset, $checksum, + compute_ip_checksum($buffer)); + $offset += $size; + + + for($i = 0; $i < scalar(@phdrs); $i++) { + my $phdr = $phdrs[$i]; + #print("\n"); + #foreach $key (keys(%$phdr)) { + # printf("%10s: %08x\n", $key, $phdr->{$key}); + #} + # Only worry about PT_LOAD segments + next unless ($phdr->{p_type} == 1); + $fd->seek($phdr->{p_offset}, 0) or die "Cannot seek to $phdr->{p_offset}\n"; + $fd->read($buffer, $phdr->{p_filesz}) == $phdr->{p_filesz} + or die "Cannot read ELF segment $phdr->{p_filesz}\n"; + $buffer .= "\0" x ($phdr->{p_memsz} - $phdr->{p_filesz}); + $checksum = add_ip_checksums($offset, $checksum, + compute_ip_checksum($buffer)); + $offset += $phdr->{p_memsz} + } + printf("checksum: %04x\n", $checksum); + + my $phdr = $phdrs[0]; + # Do I have a PT_NOTE segment? + if ($phdr->{p_type} == 4) { + my $offset; + $fd->seek($phdr->{p_offset}, 0) or die "Cannot seek to $phdr->{p_offset}\n"; + $fd->read($buffer, $phdr->{p_filesz}) == $phdr->{p_filesz} + or die "Cannot read ELF segment $phdr->{p_filesz}\n"; + + $offset = 0; + while($offset < length($buffer)) { + my %note; + @note{n_namesz, n_descsz, n_type} + = unpack('LLL', substr($buffer, $offset, 12)); + $offset += 12; + $note{n_name} = unpack("a$note{n_namesz}", + substr($buffer, $offset, $note{n_namesz})); + $offset += ($note{n_namesz} + 3) & ~3; + $note{n_desc} = unpack("a$note{n_descsz}", + substr($buffer, $offset, $note{n_descsz})); + + #printf("n_type: %08x n_name(%d): %s n_desc(%d): %s\n", + # $note{n_type}, + # $note{n_namesz}, $note{n_name}, + # $note{n_descsz}, $note{n_desc}); + if (($note{n_namesz} == 8) && + ($note{n_name} eq "ELFBoot\0") && + ($note{n_type} == 3)) { + my ($foffset, $buffer); + $foffset = $phdr->{p_offset} + $offset; + $buffer = pack('S', $checksum); + $fd->seek($foffset, 0) or die "Cannot seek to $foffset"; + $fd->print($buffer); + #print("checksum note...\n"); + + } + $offset += ($note{n_descsz} + 3) & ~3; + } + } + $fd->close(); + +} + sub build { my ($params) = @_; @@ -171,6 +305,7 @@ sub build "$tempdir/head_$$.o")); build_elf_image($params, $params->{TARGET}, @objects); unlink(@objects); + write_ip_checksum($params->{TARGET}); } @@ -186,10 +321,6 @@ sub main 'output=s' => \$params->{TARGET}, 'version' => \$wantversion, 'ramdisk-base=i' =>\$params->{INITRD_BASE}, - # FIXME figure out what the old RAMDISK_IMAGE flags are about. - #'ramdisk-image-start=i' => \$params{RAMDISK_IMAGE_START}, - #'ramdisk-prompt-flag!' => \$params{RAMDISK_PROMPT_FLAG}, - #'ramdisk-load-flag!' => \$params{RAMDISK_LOAD_FLAG}, ); if (defined($wantversion) && $wantversion) { print "$0 $VERSION\n";