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";