From 9cda94e6d23ab8fe40f8f962d3fa093d284c5071 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 8 Jan 2002 07:04:35 +0000 Subject: [PATCH] Updates to produce a linuxBIOS table. Modeled on the earlier uniform_boot work, but relocated. You need the new mkelfImage to use the elf boot format. Previous tables were updated so I could find both the start and the end of where they were written in memory. Minor p4dc6 updates, to disable some debugging code. The mkelfImage-1.9 is checked in as util/mkelfImage --- src/arch/i386/boot/Config | 1 + src/arch/i386/boot/boot.c | 121 +- src/arch/i386/boot/linuxbios_table.c | 177 ++ src/arch/i386/include/arch/pirq_routing.h | 4 +- src/arch/i386/include/arch/smp/mpspec.h | 6 +- src/arch/i386/lib/hardwaremain.c | 42 +- src/arch/i386/lib/pirq_routing.c | 13 +- src/arch/i386/smp/mpspec.c | 9 +- src/boot/Config | 1 - src/include/boot/elf.h | 9 +- src/include/boot/elf_boot.h | 89 + src/include/boot/linuxbios_table.h | 23 + src/include/boot/linuxbios_tables.h | 83 + src/include/ip_checksum.h | 6 + src/lib/Config | 1 + src/lib/compute_ip_checksum.c | 20 + src/lib/elfboot.c | 13 +- src/lib/linuxbiosmain.c | 2 +- src/mainboard/intel/l440gx/mptable.c | 10 +- src/mainboard/supermicro/p4dc6/Config | 4 +- src/mainboard/supermicro/p4dc6/mainboard.c | 8 +- src/mainboard/supermicro/p4dc6/mptable.c | 10 +- src/mainboard/tyan/guiness/mptable.c | 10 +- util/mkelfImage/COPYING | 341 ++++ util/mkelfImage/Makefile | 41 + util/mkelfImage/elf32-i386/convert_params.c | 1515 +++++++++++++++++ util/mkelfImage/elf32-i386/elfImage.lds | 80 + util/mkelfImage/elf32-i386/elf_boot.h | 83 + util/mkelfImage/elf32-i386/head.S | 390 +++++ util/mkelfImage/elf32-i386/linuxbios_tables.h | 82 + util/mkelfImage/elf32-i386/uniform_boot.h | 67 + util/mkelfImage/mkelfImage.pl | 239 +++ 32 files changed, 3383 insertions(+), 117 deletions(-) create mode 100644 src/arch/i386/boot/linuxbios_table.c create mode 100644 src/include/boot/elf_boot.h create mode 100644 src/include/boot/linuxbios_table.h create mode 100644 src/include/boot/linuxbios_tables.h create mode 100644 src/include/ip_checksum.h create mode 100644 src/lib/compute_ip_checksum.c create mode 100644 util/mkelfImage/COPYING create mode 100644 util/mkelfImage/Makefile create mode 100644 util/mkelfImage/elf32-i386/convert_params.c create mode 100644 util/mkelfImage/elf32-i386/elfImage.lds create mode 100644 util/mkelfImage/elf32-i386/elf_boot.h create mode 100644 util/mkelfImage/elf32-i386/head.S create mode 100644 util/mkelfImage/elf32-i386/linuxbios_tables.h create mode 100644 util/mkelfImage/elf32-i386/uniform_boot.h create mode 100644 util/mkelfImage/mkelfImage.pl diff --git a/src/arch/i386/boot/Config b/src/arch/i386/boot/Config index 178df54605..522116f334 100644 --- a/src/arch/i386/boot/Config +++ b/src/arch/i386/boot/Config @@ -1 +1,2 @@ object boot.o +object linuxbios_table.o diff --git a/src/arch/i386/boot/boot.c b/src/arch/i386/boot/boot.c index 58abbeca42..a0a0eff59e 100644 --- a/src/arch/i386/boot/boot.c +++ b/src/arch/i386/boot/boot.c @@ -1,86 +1,59 @@ -#include +#include #include +#include +#include #ifndef CMD_LINE #define CMD_LINE "" #endif -/* FIXME: the current placement of ube_all could lead to problems... - * It should be in a location normally reserved for the bios. - */ + + +#define UPSZ(X) ((sizeof(X) + 3) &~3) static struct { - struct uniform_boot_header header; - struct linuxbios_header lb_header; - struct { - struct { - struct ube_memory memory; - struct ube_memory_range range[2]; - } mem; - }env; - unsigned char command_line[1024]; -} ube_all = { - .header = { - .header_bytes = sizeof(ube_all.header), - .header_checksum = 0, - .arg = (unsigned long)&ube_all.command_line, - .arg_bytes = sizeof(ube_all.command_line), - .env = (unsigned long)&ube_all.env, - .env_bytes = sizeof(ube_all.env), + Elf_Bhdr hdr; + Elf_Nhdr ft_hdr; + unsigned char ft_desc[UPSZ(FIRMWARE_TYPE)]; + Elf_Nhdr bl_hdr; + unsigned char bl_desc[UPSZ(BOOTLOADER)]; + Elf_Nhdr blv_hdr; + unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)]; + Elf_Nhdr cmd_hdr; + unsigned char cmd_desc[UPSZ(CMD_LINE)]; +} elf_boot_notes = { + .hdr = { + .b_signature = 0x0E1FB007, + .b_size = sizeof(elf_boot_notes), + .b_checksum = 0, + .b_records = 4, }, - .lb_header = { - .signature = { 'L', 'B', 'I', 'O' }, - .header_bytes = sizeof(ube_all.lb_header), - .header_checksum = 0, - .env_bytes = sizeof(ube_all.env), - .env_checksum = 0, - .env_entries = 0, + .ft_hdr = { + .n_namesz = 0, + .n_descsz = sizeof(FIRMWARE_TYPE), + .n_type = EBN_FIRMWARE_TYPE, }, - .env = { - .mem = { - .memory = { - .tag = UBE_TAG_MEMORY, - .size = sizeof(ube_all.env.mem), - }, - .range = { -#if 0 - { - .start = 0, - .size = 0xa0000, /* 640k */ - .type = UBE_MEM_RAM, - }, -#else - { - .start = 4096, /* skip the first page */ - .size = 0x9f000, /* 640k */ - .type = UBE_MEM_RAM, - }, -#endif - { - .start = 0x00100000, /* 1M */ - .size = 0, /* Fill in the size */ - .type = UBE_MEM_RAM, - }, - }, - }, - + .ft_desc = FIRMWARE_TYPE, + .bl_hdr = { + .n_namesz = 0, + .n_descsz = sizeof(BOOTLOADER), + .n_type = EBN_BOOTLOADER_NAME, }, - .command_line = CMD_LINE, + .bl_desc = BOOTLOADER, + .blv_hdr = { + .n_namesz = 0, + .n_descsz = sizeof(BOOTLOADER_VERSION), + .n_type = EBN_BOOTLOADER_VERSION, + }, + .blv_desc = BOOTLOADER_VERSION, + .cmd_hdr = { + .n_namesz = 0, + .n_descsz = sizeof(CMD_LINE), + .n_type = EBN_COMMAND_LINE, + }, + .cmd_desc = CMD_LINE, }; -void *get_ube_pointer(unsigned long totalram) -{ - ube_all.env.mem.range[1].size = ((totalram - 1024) << 10); - ube_all.header.header_checksum = 0; - ube_all.header.header_checksum = - uniform_boot_compute_header_checksum(&ube_all.header); - ube_all.lb_header.env_entries = 1; /* FIXME remove this hardcode.. */ - ube_all.lb_header.env_checksum = - compute_checksum(&ube_all.env, sizeof(ube_all.env)); - ube_all.lb_header.header_checksum = - compute_checksum(&ube_all.lb_header, sizeof(ube_all.lb_header)); - return &ube_all.header; -} int elf_check_arch(Elf_ehdr *ehdr) { @@ -92,9 +65,11 @@ int elf_check_arch(Elf_ehdr *ehdr) } -void jmp_to_elf_entry(void *entry, void *ube) +void jmp_to_elf_entry(void *entry) { - unsigned long type = 0x0A11B007; + unsigned long type = 0x0E1FB007; + elf_boot_notes.hdr.b_checksum = + compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes)); /* Jump to kernel */ __asm__ __volatile__( @@ -104,7 +79,7 @@ void jmp_to_elf_entry(void *entry, void *ube) "popl %%ebx\n\t" "popl %%eax\n\t" "ret\n\t" - :: "g" (entry), "g"(type), "g"(ube)); + :: "g" (entry), "g"(type), "g"(&elf_boot_notes)); } diff --git a/src/arch/i386/boot/linuxbios_table.c b/src/arch/i386/boot/linuxbios_table.c new file mode 100644 index 0000000000..d75bf65bd3 --- /dev/null +++ b/src/arch/i386/boot/linuxbios_table.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include + +struct lb_header *lb_table_init(unsigned long addr) +{ + struct lb_header *header; + + /* 16 byte align the address */ + addr += 15; + addr &= ~15; + + header = (void *)addr; + header->signature[0] = 'L'; + header->signature[1] = 'B'; + header->signature[2] = 'I'; + header->signature[3] = 'O'; + header->header_bytes = sizeof(*header); + header->header_checksum = 0; + header->table_bytes = 0; + header->table_checksum = 0; + header->table_entries = 0; + return header; +} + +struct lb_record *lb_first_record(struct lb_header *header) +{ + struct lb_record *rec; + rec = (void *)(((char *)header) + sizeof(*header)); + return rec; +} + +struct lb_record *lb_last_record(struct lb_header *header) +{ + struct lb_record *rec; + rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes); + return rec; +} + +struct lb_record *lb_next_record(struct lb_record *rec) +{ + rec = (void *)(((char *)rec) + rec->size); + return rec; +} + +struct lb_record *lb_new_record(struct lb_header *header) +{ + struct lb_record *rec; + rec = lb_last_record(header); + if (header->table_entries) { + header->table_bytes += rec->size; + } + rec = lb_last_record(header); + header->table_entries++; + rec->tag = LB_TAG_UNUSED; + rec->size = sizeof(*rec); + return rec; +} + + +struct lb_memory *lb_memory(struct lb_header *header) +{ + struct lb_record *rec; + struct lb_memory *mem; + rec = lb_new_record(header); + mem = (struct lb_memory *)rec; + mem->tag = LB_TAG_MEMORY; + mem->size = sizeof(*mem); + return mem; +} + +/* Some version of gcc have problems with 64 bit types so + * take an unsigned long instead of a uint64_t for now. + */ +void lb_memory_range(struct lb_memory *mem, + uint32_t type, unsigned long start, unsigned long size) +{ + int entries; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + mem->map[entries].start = start; + mem->map[entries].size = size; + mem->map[entries].type = type; + mem->size += sizeof(mem->map[0]); +} + +static void lb_reserve_table_memory(struct lb_header *head) +{ + struct lb_record *rec, *last_rec; + struct lb_memory *mem; + uint64_t start; + uint64_t end; + int i, entries; + last_rec = lb_last_record(head); + mem = 0; + for(rec = lb_first_record(head); rec < last_rec; lb_next_record(rec)) { + if (rec->tag == LB_TAG_MEMORY) { + mem = (struct lb_memory *)rec; + break; + } + } + if (!mem) + return; +printk_debug("head = %p last_rec = %p\n", head, last_rec); + start = (unsigned long)head; + end = (unsigned long)last_rec; +printk_debug("start = 0x%08lx end = 0x%08lx\n", (unsigned long)start, (unsigned long)end); + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + /* Resize the right two memory areas so this table is in + * a reserved area of memory. Everything has been carefully + * setup so that is all we need to do. + */ + for(i = 0; i < entries; i++ ) { + uint64_t map_start = mem->map[i].start; + uint64_t map_end = map_start + mem->map[i].size; + /* Does this area need to be expanded? */ + if (map_end == start) { + mem->map[i].size = end - map_start; + } + /* Does this area need to be contracted? */ + else if (map_start == start) { + mem->map[i].start = end; + mem->map[i].size = map_end - end; + } + } +} + +unsigned long lb_table_fini(struct lb_header *head) +{ + struct lb_record *rec, *first_rec; + rec = lb_last_record(head); + if (head->table_entries) { + head->table_bytes += rec->size; + } + lb_reserve_table_memory(head); + first_rec = lb_first_record(head); + head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes); + head->header_checksum = 0; + head->header_checksum = compute_ip_checksum(head, sizeof(*head)); + printk_debug("Write linuxbios table at: %p - %p\n", + head, rec); + return (unsigned long)rec; +} + +unsigned long setup_memory_table( + struct lb_memory *mem, + unsigned long totalram, + unsigned long low_table_start, unsigned long low_table_end) +{ +} + +unsigned long write_linuxbios_table( + unsigned long *processor_map, + unsigned long totalram, + unsigned long low_table_start, unsigned long low_table_end, + unsigned long rom_table_start, unsigned long rom_table_end) +{ + struct lb_header *head; + struct lb_memory *mem; + + head = lb_table_init(low_table_end); + low_table_end = (unsigned long)head; + + mem = lb_memory(head); + /* Reserve our tables in low memory */ + lb_memory_range(mem, LB_MEM_RESERVED, low_table_start, low_table_end - low_table_start); + lb_memory_range(mem, LB_MEM_RAM, low_table_end, 640*1024 - low_table_end); + /* Reserve the whole dos BIOS reserved area, we can probably do + * better but it isn't too important right now + */ + lb_memory_range(mem, LB_MEM_RESERVED, 0x000a0000, 0x00060000); + /* Now show all of memory */ + lb_memory_range(mem, LB_MEM_RAM, 0x00100000, (totalram - 1024) << 10); + + low_table_end = lb_table_fini(head); + return low_table_end; +} diff --git a/src/arch/i386/include/arch/pirq_routing.h b/src/arch/i386/include/arch/pirq_routing.h index fc27ed6633..284002e9bc 100644 --- a/src/arch/i386/include/arch/pirq_routing.h +++ b/src/arch/i386/include/arch/pirq_routing.h @@ -38,9 +38,9 @@ void check_pirq_routing_table(void); #endif #if defined(HAVE_PIRQ_TABLE) -void copy_pirq_routing_table(void); +unsigned long copy_pirq_routing_table(unsigned long start); #else -#define copy_pirq_routing_table() do {} while(0) +#define copy_pirq_routing_table(start) (start) #endif #endif /* ARCH_PIRQ_ROUTING_H */ diff --git a/src/arch/i386/include/arch/smp/mpspec.h b/src/arch/i386/include/arch/smp/mpspec.h index 9448e7aa1f..318531907b 100644 --- a/src/arch/i386/include/arch/smp/mpspec.h +++ b/src/arch/i386/include/arch/smp/mpspec.h @@ -264,8 +264,8 @@ void smp_write_compatibility_address_space(struct mp_config_table *mc, unsigned char busid, unsigned char address_modifier, unsigned int range_list); unsigned char smp_compute_checksum(void *v, int len); -void smp_write_floating_table(void *v); -void write_smp_table(void *v, unsigned long *processor_map); +void *smp_write_floating_table(unsigned long addr); +unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map); /* A table (per mainboard) listing the initial apicid of each cpu. */ extern unsigned long initial_apicid[MAX_CPUS]; @@ -273,7 +273,7 @@ extern unsigned long initial_apicid[MAX_CPUS]; #else /* HAVE_MP_TABLE */ #define CPU_ENABLED 1 /* Processor is available */ #define CPU_BOOTPROCESSOR 2 /* Processor is the BP */ -#define write_smp_table(v,p) do {} while(0) +#define write_smp_table(v,p) ({ p; v; }) #endif /* HAVE_MP_TABLE */ #endif diff --git a/src/arch/i386/lib/hardwaremain.c b/src/arch/i386/lib/hardwaremain.c index 857713ef09..7b44ec80a7 100644 --- a/src/arch/i386/lib/hardwaremain.c +++ b/src/arch/i386/lib/hardwaremain.c @@ -57,6 +57,7 @@ static char rcsid[] = "$Id$"; #include #include #include +#include /* The processor map. @@ -157,6 +158,36 @@ static void wait_for_other_cpus(void) #define wait_for_other_cpus() do {} while(0) #endif /* SMP */ +void write_tables(unsigned long totalram) +{ + unsigned long low_table_start, low_table_end; + unsigned long rom_table_start, rom_table_end; + + rom_table_start = 0xf0000; + rom_table_end = 0xf0000; + /* Start low addr at 16 bytes instead of 0 because of a buglet + * in the generic linux bunzip code, as it tests for the a20 line. + */ + low_table_start = 0; + low_table_end = 16; + + post_code(0x9a); + check_pirq_routing_table(); + /* This table must be betweeen 0xf0000 & 0x100000 */ + rom_table_end = copy_pirq_routing_table(rom_table_end); + + /* copy the smp block to address 0 */ + post_code(0x96); + /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */ + low_table_end = write_smp_table(low_table_end, processor_map); + + /* The linuxbios table must be in 0-1K or 960K-1M */ + write_linuxbios_table( + processor_map, totalram, + low_table_start, low_table_end, + rom_table_start, rom_table_end); +} + void hardwaremain(int boot_complete) { /* Processor ID of the BOOT cpu (i.e. the one running this code) */ @@ -266,10 +297,7 @@ void hardwaremain(int boot_complete) pci_zero_irq_settings(); - check_pirq_routing_table(); - copy_pirq_routing_table(); - post_code(0x9a); /* to do: intel_serial_on(); */ @@ -285,9 +313,11 @@ void hardwaremain(int boot_complete) /* make certain we are the only cpu running in linuxBIOS */ wait_for_other_cpus(); - /* copy the smp block to address 0 */ - post_code(0x96); - write_smp_table((void *)16, processor_map); + /* Now that we have collected all of our information + * write our configuration tables. + */ + write_tables(totalram); + #ifdef LINUXBIOS printk_info("Jumping to linuxbiosmain()...\n"); diff --git a/src/arch/i386/lib/pirq_routing.c b/src/arch/i386/lib/pirq_routing.c index 4d6aa8a7af..ececa99b04 100644 --- a/src/arch/i386/lib/pirq_routing.c +++ b/src/arch/i386/lib/pirq_routing.c @@ -53,11 +53,16 @@ void check_pirq_routing_table(void) } #endif -#define RTABLE_DEST 0xf0000 - -void copy_pirq_routing_table(void) +unsigned long copy_pirq_routing_table(unsigned long addr) { + /* Align the table to be 16 byte aligned. */ + addr += 15; + addr &= ~15; + + /* This table must be betweeen 0xf0000 & 0x100000 */ printk_info("Copying IRQ routing tables..."); - memcpy((char *) RTABLE_DEST, &intel_irq_routing_table, intel_irq_routing_table.size); + memcpy((void *)addr, &intel_irq_routing_table, intel_irq_routing_table.size); printk_info("done.\n"); + + return addr + intel_irq_routing_table.size; } diff --git a/src/arch/i386/smp/mpspec.c b/src/arch/i386/smp/mpspec.c index 7625486783..309e815ae2 100644 --- a/src/arch/i386/smp/mpspec.c +++ b/src/arch/i386/smp/mpspec.c @@ -22,9 +22,15 @@ unsigned char smp_compute_checksum(void *v, int len) return checksum; } -void smp_write_floating_table(void *v) +void *smp_write_floating_table(unsigned long addr) { struct intel_mp_floating *mf; + void *v; + + /* 16 byte align the table address */ + addr += 15; + addr &= ~15; + v = (void *)addr; mf = v; mf->mpf_signature[0] = '_'; @@ -41,6 +47,7 @@ void smp_write_floating_table(void *v) mf->mpf_feature4 = 0; mf->mpf_feature5 = 0; mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16); + return v; } void *smp_next_mpc_entry(struct mp_config_table *mc) diff --git a/src/boot/Config b/src/boot/Config index 5bc5aa2ad4..e69de29bb2 100644 --- a/src/boot/Config +++ b/src/boot/Config @@ -1 +0,0 @@ -object uniform_boot.o diff --git a/src/include/boot/elf.h b/src/include/boot/elf.h index 6884fe91fe..8bfcb3aef3 100644 --- a/src/include/boot/elf.h +++ b/src/include/boot/elf.h @@ -390,6 +390,11 @@ typedef Elf64_Phdr Elf_phdr; #endif extern int elf_check_arch(Elf_ehdr *ehdr); -extern void jmp_to_elf_entry(void *entry, void *ube); -extern int elfboot(size_t totalram); +extern void jmp_to_elf_entry(void *entry); +extern int elfboot(void); + +#define FIRMWARE_TYPE "LinuxBIOS" +#define BOOTLOADER "elfboot" +#define BOOTLOADER_VERSION "0.99999" + #endif /* elf.h */ diff --git a/src/include/boot/elf_boot.h b/src/include/boot/elf_boot.h new file mode 100644 index 0000000000..ee6750d293 --- /dev/null +++ b/src/include/boot/elf_boot.h @@ -0,0 +1,89 @@ +#ifndef ELF_BOOT_H +#define ELF_BOOT_H + +#include + +/* This defines the structure of a table of parameters useful for ELF + * bootable images. These parameters are all passed and generated + * by the bootloader to the booted image. For simplicity and + * consistency the Elf Note format is reused. + * + * All of the information must be Position Independent Data. + * That is it must be safe to relocate the whole ELF boot parameter + * block without changing the meaning or correctnes of the data. + * Additionally it must be safe to permute the order of the ELF notes + * to any possible permutation without changing the meaning or correctness + * of the data. + * + */ + +#define ELF_HEAD_SIZE (8*1024) +#define ELF_BOOT_MAGIC 0x0E1FB007 + +typedef uint16_t Elf_Half; +typedef uint32_t Elf_Word; +typedef uint64_t Elf_Xword; + +typedef struct +{ + Elf_Word b_signature; /* "0x0E1FB007" */ + Elf_Word b_size; + Elf_Half b_checksum; + Elf_Half b_records; +} Elf_Bhdr; + +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; + + +/* For standard notes n_namesz must be zero */ +/* All of the following standard note types provide a single null + * terminated string in the descriptor. + */ +#define EBN_FIRMWARE_TYPE 0x00000001 +/* On platforms that support multiple classes of firmware this field + * specifies the class of firmware you are loaded under. + */ +#define EBN_BOOTLOADER_NAME 0x00000002 +/* This specifies just the name of the bootloader for easy comparison */ +#define EBN_BOOTLOADER_VERSION 0x00000003 +/* This specifies the version of the bootlader */ +#define EBN_COMMAND_LINE 0x00000004 +/* This specifies a command line that can be set by user interaction, + * and is provided as a free form string to the loaded image. + */ + + +/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */ + +#define ELF_NOTE_BOOT "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. */ + + +/* Linux image notes for booting... The name for all of these is Linux */ + +#define LINUX_NOTE_BOOT "Linux" + +#define LIN_COMMAND_LINE 0x00000001 +/* The command line to pass to the loaded kernel. */ +#define LIN_ROOT_DEV 0x00000002 +/* The root dev to pass to the loaded kernel. */ +#define LIN_RAMDISK_FLAGS 0x00000003 +/* Various old ramdisk flags */ +#define LIN_INITRD_START 0x00000004 +/* Start of the ramdisk in bytes */ +#define LIN_INITRD_SIZE 0x00000005 +/* Size of the ramdisk in bytes */ + + +#endif /* ELF_BOOT_H */ diff --git a/src/include/boot/linuxbios_table.h b/src/include/boot/linuxbios_table.h new file mode 100644 index 0000000000..fbbc173657 --- /dev/null +++ b/src/include/boot/linuxbios_table.h @@ -0,0 +1,23 @@ +#ifndef LINUXBIOS_TABLE_H +#define LINUXBIOS_TABLE_H + +#include + +/* This file holds function prototypes for building the linuxbios table. */ +unsigned long write_linuxbios_table( + unsigned long *processor_map, + unsigned long totalram, + unsigned long low_table_start, unsigned long low_table_end, + unsigned long rom_table_start, unsigned long rom_table_end); + +struct lb_header *lb_table_init(unsigned long addr); +struct lb_record *lb_first_record(struct lb_header *header); +struct lb_record *lb_last_record(struct lb_header *header); +struct lb_record *lb_next_record(struct lb_record *rec); +struct lb_record *lb_new_record(struct lb_header *header); +struct lb_memory *lb_memory(struct lb_header *header); +void lb_memory_range(struct lb_memory *mem, + uint32_t type, unsigned long start, unsigned long size); +unsigned long lb_table_fini(struct lb_header *header); + +#endif /* LINUXBIOS_TABLE_H */ diff --git a/src/include/boot/linuxbios_tables.h b/src/include/boot/linuxbios_tables.h new file mode 100644 index 0000000000..2da0b65e00 --- /dev/null +++ b/src/include/boot/linuxbios_tables.h @@ -0,0 +1,83 @@ +#ifndef LINUXBIOS_TABLES_H +#define LINUXBIOS_TABLES_H + +#include + +/* The linuxbios table information is for conveying information + * from the firmware to the loaded OS image. Primarily this + * is expected to be information that cannot be discovered by + * other means, such as quering the hardware directly. + * + * All of the information should be Position Independent Data. + * That is it should be safe to relocated any of the information + * without it's meaning/correctnes changing. For table that + * can reasonably be used on multiple architectures the data + * size should be fixed. This should ease the transition between + * 32 bit and 64 bit architectures etc. + * + * The completeness test for the information in this table is: + * - Can all of the hardware be detected? + * - Are the per motherboard constants available? + * - Is there enough to allow a kernel to run that was written before + * a particular motherboard is constructed? (Assuming the kernel + * has drivers for all of the hardware but it does not have + * assumptions on how the hardware is connected together). + * + * With this test it should be straight forward to determine if a + * table entry is required or not. This should remove much of the + * long term compatibility burden as table entries which are + * irrelevant or have been replaced by better alternatives may be + * dropped. Of course it is polite and expidite to include extra + * table entries and be backwards compatible, but it is not required. + */ + + +struct lb_header +{ + uint8_t signature[4]; /* LBIO */ + uint32_t header_bytes; + uint32_t header_checksum; + uint32_t table_bytes; + uint32_t table_checksum; + uint32_t table_entries; +}; + +/* Every entry in the boot enviroment list will correspond to a boot + * info record. Encoding both type and size. The type is obviously + * so you can tell what it is. The size allows you to skip that + * boot enviroment record if you don't know what it easy. This allows + * forward compatibility with records not yet defined. + */ +struct lb_record { + uint32_t tag; /* tag ID */ + uint32_t size; /* size of record (in bytes) */ +}; + +#define LB_TAG_UNUSED 0x0000 + +#define LB_TAG_MEMORY 0x0001 + +struct lb_memory_range { + uint64_t start; + uint64_t size; + uint32_t type; +#define LB_MEM_RAM 1 +#define LB_MEM_RESERVED 2 + +}; + +struct lb_memory { + uint32_t tag; + uint32_t size; + struct lb_memory_range map[0]; +}; + +#define LB_TAG_HWRPB 0x0002 +struct lb_hwrpb { + uint32_t tag; + uint32_t size; + uint64_t hwrpb; +}; + + +#endif /* LINUXBIOS_TABLES_H */ diff --git a/src/include/ip_checksum.h b/src/include/ip_checksum.h new file mode 100644 index 0000000000..106c64c99a --- /dev/null +++ b/src/include/ip_checksum.h @@ -0,0 +1,6 @@ +#ifndef IP_CHECKSUM_H +#define IP_CHECKSUM_H + +unsigned long compute_ip_checksum(void *addr, unsigned long length); + +#endif /* IP_CHECKSUM_H */ diff --git a/src/lib/Config b/src/lib/Config index cc966cb9ca..338c78cef8 100644 --- a/src/lib/Config +++ b/src/lib/Config @@ -16,3 +16,4 @@ object do_inflate.o object floppy_subr.o object delay.o object fallback_boot.o USE_FALLBACK_BOOT +object compute_ip_checksum.o \ No newline at end of file diff --git a/src/lib/compute_ip_checksum.c b/src/lib/compute_ip_checksum.c new file mode 100644 index 0000000000..940252e9f2 --- /dev/null +++ b/src/lib/compute_ip_checksum.c @@ -0,0 +1,20 @@ +#include + +unsigned long compute_ip_checksum(void *addr, unsigned long length) +{ + unsigned short *ptr; + unsigned long sum; + unsigned long len; + /* Assumes len is a multiple of two, and addr is 2 byte aligned. */ + /* compute an ip style checksum */ + sum = 0; + len = length >> 1; + ptr = addr; + while (len--) { + sum += *(ptr++); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + return (~sum) & 0xFFFF; + +} diff --git a/src/lib/elfboot.c b/src/lib/elfboot.c index 144ae8d2c3..45a0b826b8 100644 --- a/src/lib/elfboot.c +++ b/src/lib/elfboot.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -57,7 +57,7 @@ static int safe_range(unsigned long start, unsigned long len) return 1; } -int elfboot(size_t totalram) +int elfboot(void) { static unsigned char header[ELF_HEAD_SIZE]; unsigned long offset; @@ -68,15 +68,14 @@ int elfboot(size_t totalram) int i; printk_info("\n"); - printk_info("Welcome to elfboot, the open sourced starter.\n"); - printk_info("Febuary 2001, Eric Biederman.\n"); - printk_info("Version 0.9999\n"); + printk_info("Welcome to %s, the open sourced starter.\n", BOOTLOADER); + printk_info("January 2002, Eric Biederman.\n"); + printk_info("Version %s\n", BOOTLOADER_VERSION); printk_info("\n"); if (streams->init() < 0) { printk_err("Could not initialize driver...\n"); goto out; } - ptr = get_ube_pointer(totalram); post_code(0xf8); /* Read in the initial ELF_HEAD_SIZE bytes */ @@ -228,7 +227,7 @@ int elfboot(size_t totalram) post_code(0xfe); /* Jump to kernel */ - jmp_to_elf_entry(entry, ptr); + jmp_to_elf_entry(entry); out: printk_err("Bad ELF Image\n"); diff --git a/src/lib/linuxbiosmain.c b/src/lib/linuxbiosmain.c index 04dd286d4e..5e4842fcbf 100644 --- a/src/lib/linuxbiosmain.c +++ b/src/lib/linuxbiosmain.c @@ -51,7 +51,7 @@ int linuxbiosmain(unsigned long base, unsigned long totalram) #endif /* USE_TFTP */ #if USE_ELF_BOOT - return elfboot(totalram); + return elfboot(); #else /* !ELF_BOOT */ printk_info("\n"); printk_info("Welcome to start32, the open sourced starter.\n"); diff --git a/src/mainboard/intel/l440gx/mptable.c b/src/mainboard/intel/l440gx/mptable.c index fa13423433..ef6173902f 100644 --- a/src/mainboard/intel/l440gx/mptable.c +++ b/src/mainboard/intel/l440gx/mptable.c @@ -2,7 +2,7 @@ #include #include -void smp_write_config_table(void *v, unsigned long * processor_map) +void *smp_write_config_table(void *v, unsigned long * processor_map) { int ioapicid = 0; static const char sig[4] = "PCMP"; @@ -120,12 +120,14 @@ void smp_write_config_table(void *v, unsigned long * processor_map) mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length); printk_debug("Wrote the mp table end at: %p - %p\n", mc, smp_next_mpe_entry(mc)); + return smp_next_mpe_entry(mc); } -void write_smp_table(void *v, unsigned long *processor_map) +unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map) { - smp_write_floating_table(v); - smp_write_config_table(v, processor_map); + void *v; + v = smp_write_floating_table(addr); + return (unsigned long)smp_write_config_table(v, processor_map); } diff --git a/src/mainboard/supermicro/p4dc6/Config b/src/mainboard/supermicro/p4dc6/Config index 7f1e9aa29c..a9b14d0789 100644 --- a/src/mainboard/supermicro/p4dc6/Config +++ b/src/mainboard/supermicro/p4dc6/Config @@ -16,8 +16,8 @@ nooption USE_DEFAULT_LAYOUT option STACK_SIZE=0x2000 option USE_FALLBACK_BOOT=1 -option USE_RAMTEST=1 -dir /src/ram +#option USE_RAMTEST=1 +#dir /src/ram #/* falback */ option ZKERNEL_START=0xffff0000 diff --git a/src/mainboard/supermicro/p4dc6/mainboard.c b/src/mainboard/supermicro/p4dc6/mainboard.c index 87ef9db7bb..4781f7500e 100644 --- a/src/mainboard/supermicro/p4dc6/mainboard.c +++ b/src/mainboard/supermicro/p4dc6/mainboard.c @@ -82,7 +82,7 @@ void cache_ram_start(void) init_memory(); -#if 1 +#if 0 { unsigned long addr; for(addr = 0; addr < 0x20000000; addr += 0x02000000) { @@ -97,6 +97,7 @@ void cache_ram_start(void) } } #endif +#if 0 error |= ramcheck(0x00000000, 0x00080000, 20); error |= ramcheck(0x02000000, 0x02080000, 20); error |= ramcheck(0x04000000, 0x04080000, 20); @@ -114,13 +115,14 @@ void cache_ram_start(void) error |= ramcheck(0x1a000000, 0x1a080000, 20); error |= ramcheck(0x1c000000, 0x1c080000, 20); error |= ramcheck(0x1e000000, 0x1e080000, 20); +#endif #if 0 error |= ramcheck(0x00000000, 0x00080000, 20); #endif -#if 1 +#if 0 display_rdram_regs(rdram_chips ); #endif -#if 1 +#if 0 display_mch_regs(); #endif if (error) { diff --git a/src/mainboard/supermicro/p4dc6/mptable.c b/src/mainboard/supermicro/p4dc6/mptable.c index 3865313be3..bd7099b853 100644 --- a/src/mainboard/supermicro/p4dc6/mptable.c +++ b/src/mainboard/supermicro/p4dc6/mptable.c @@ -2,7 +2,7 @@ #include #include -void smp_write_config_table(void *v, unsigned long * processor_map) +void *smp_write_config_table(void *v, unsigned long * processor_map) { int ioapicid = 0; static const char sig[4] = "PCMP"; @@ -125,12 +125,14 @@ void smp_write_config_table(void *v, unsigned long * processor_map) mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length); printk_debug("Wrote the mp table end at: %p - %p\n", mc, smp_next_mpe_entry(mc)); + return smp_next_mpe_entry(mc); } -void write_smp_table(void *v, unsigned long *processor_map) +unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map) { - smp_write_floating_table(v); - smp_write_config_table(v, processor_map); + void *v; + v = smp_write_floating_table(addr); + return (unsigned long)smp_write_config_table(v, processor_map); } diff --git a/src/mainboard/tyan/guiness/mptable.c b/src/mainboard/tyan/guiness/mptable.c index 089d46d971..8fe88fcb80 100644 --- a/src/mainboard/tyan/guiness/mptable.c +++ b/src/mainboard/tyan/guiness/mptable.c @@ -3,7 +3,7 @@ #include #include -void smp_write_config_table(void *v, unsigned long * processor_map) +void *smp_write_config_table(void *v, unsigned long * processor_map) { static const char sig[4] = "PCMP"; static const char oem[8] = "TYAN "; @@ -145,13 +145,15 @@ void smp_write_config_table(void *v, unsigned long * processor_map) mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length); printk_debug("Wrote the mp table end at: %p - %p\n", mc, smp_next_mpe_entry(mc)); + return smp_next_mpe_entry(mc); } -void write_smp_table(void *v, unsigned long *processor_map) +unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map) { + void *v; printk_debug("Writing the mp table\n"); - smp_write_floating_table(v); - smp_write_config_table(v, processor_map); + v = smp_write_floating_table(addr); + return (unsigned long)smp_write_config_table(v, processor_map); } diff --git a/util/mkelfImage/COPYING b/util/mkelfImage/COPYING new file mode 100644 index 0000000000..a52b16e406 --- /dev/null +++ b/util/mkelfImage/COPYING @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/util/mkelfImage/Makefile b/util/mkelfImage/Makefile new file mode 100644 index 0000000000..94052a91b7 --- /dev/null +++ b/util/mkelfImage/Makefile @@ -0,0 +1,41 @@ +PREFIX=/opt/lnxi +PERLPATH=/usr/bin/perl +VERSION="1.9" +DATE="7 January 2002" + +SHAREDIR=$(PREFIX)/share/mkelfImage +BINDIR=$(PREFIX)/bin +MANDIR=$(PREFIX)/man/man1 + +DIRS=$(SHAREDIR) $(BINDIR) $(MANDIR) + +MANS=mkelfImage.1 + +FILES=mkelfImage $(MANS) + +all: $(FILES) + +clean: + rm -f $(FILES) + +install: $(DIRS) $(FILES) + mkdir -p $(SHAREDIR) $(BINDIR) $(MANDIR) + cp -fr elf32-i386/ $(SHAREDIR) + find $(SHAREDIR) -type d | xargs chmod a+x + find $(SHAREDIR) -type f | xargs chmod 444 + cp -f mkelfImage $(BINDIR) + cp -f $(MANS) $(MANDIR) + +$(DIRS): + mkdir -p $@ + +%.1 : %.pl Makefile + pod2man --date=$(DATE) --release=$(VERSION) $*.pl > $@ + +mkelfImage: mkelfImage.pl Makefile + echo 's|^$$params{MYDATA}=".";$$|$$params{MYDATA}="$(SHAREDIR)";|' > sedfile + echo 's|^#!/usr/bin/perl|#!$(PERLPATH)|' >> sedfile + sed -f sedfile mkelfImage.pl > $@ + chmod a+x $@ + rm -f sedfile + diff --git a/util/mkelfImage/elf32-i386/convert_params.c b/util/mkelfImage/elf32-i386/convert_params.c new file mode 100644 index 0000000000..4ccc5d2936 --- /dev/null +++ b/util/mkelfImage/elf32-i386/convert_params.c @@ -0,0 +1,1515 @@ +#include +#include +#include "uniform_boot.h" +#include "linuxbios_tables.h" +#include "elf_boot.h" +#define STACK_SIZE (4096) + +long user_stack [STACK_SIZE]; + +unsigned long * stack_start = & user_stack[STACK_SIZE]; + +/* FIXME expand on drive_info_)struct... */ +struct drive_info_struct { + uint8_t dummy[32]; +}; +struct sys_desc_table { + uint16_t length; + uint8_t table[318]; +}; + +/* + * These are set up by the setup-routine at boot-time: + */ + +struct screen_info { + uint8_t orig_x; /* 0x00 */ + uint8_t orig_y; /* 0x01 */ + uint16_t dontuse1; /* 0x02 -- EXT_MEM_K sits here */ + uint16_t orig_video_page; /* 0x04 */ + uint8_t orig_video_mode; /* 0x06 */ + uint8_t orig_video_cols; /* 0x07 */ + uint16_t unused2; /* 0x08 */ + uint16_t orig_video_ega_bx; /* 0x0a */ + uint16_t unused3; /* 0x0c */ + uint8_t orig_video_lines; /* 0x0e */ + uint8_t orig_video_isVGA; /* 0x0f */ + uint16_t orig_video_points; /* 0x10 */ + + /* VESA graphic mode -- linear frame buffer */ + uint16_t lfb_width; /* 0x12 */ + uint16_t lfb_height; /* 0x14 */ + uint16_t lfb_depth; /* 0x16 */ + uint32_t lfb_base; /* 0x18 */ + uint32_t lfb_size; /* 0x1c */ + uint16_t dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */ + uint16_t lfb_linelength; /* 0x24 */ + uint8_t red_size; /* 0x26 */ + uint8_t red_pos; /* 0x27 */ + uint8_t green_size; /* 0x28 */ + uint8_t green_pos; /* 0x29 */ + uint8_t blue_size; /* 0x2a */ + uint8_t blue_pos; /* 0x2b */ + uint8_t rsvd_size; /* 0x2c */ + uint8_t rsvd_pos; /* 0x2d */ + uint16_t vesapm_seg; /* 0x2e */ + uint16_t vesapm_off; /* 0x30 */ + uint16_t pages; /* 0x32 */ +}; + + +#define PAGE_SIZE 4096 + + +#define E820MAP 0x2d0 /* our map */ +#define E820MAX 32 /* number of entries in E820MAP */ +#define E820NR 0x1e8 /* # entries in E820MAP */ + + +struct e820entry { + unsigned long long addr; /* start of memory segment */ + unsigned long long size; /* size of memory segment */ + unsigned long type; /* type of memory segment */ +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ +#define E820_NVS 4 +}; + +struct e820map { + int nr_map; + struct e820entry map[E820MAX]; +}; + + +struct apm_bios_info { + uint16_t version; /* 0x40 */ + uint16_t cseg; /* 0x42 */ + uint32_t offset; /* 0x44 */ + uint16_t cseg_16; /* 0x48 */ + uint16_t dseg; /* 0x4a */ + uint16_t flags; /* 0x4c */ + uint16_t cseg_len; /* 0x4e */ + uint16_t cseg_16_len; /* 0x50 */ + uint16_t dseg_len; /* 0x52 */ + uint8_t reserved[44]; /* 0x54 */ +}; + + +struct parameters { + uint8_t orig_x; /* 0x00 */ + uint8_t orig_y; /* 0x01 */ + uint16_t ext_mem_k; /* 0x02 -- EXT_MEM_K sits here */ + uint16_t orig_video_page; /* 0x04 */ + uint8_t orig_video_mode; /* 0x06 */ + uint8_t orig_video_cols; /* 0x07 */ + uint16_t unused2; /* 0x08 */ + uint16_t orig_video_ega_bx; /* 0x0a */ + uint16_t unused3; /* 0x0c */ + uint8_t orig_video_lines; /* 0x0e */ + uint8_t orig_video_isVGA; /* 0x0f */ + uint16_t orig_video_points; /* 0x10 */ + + /* VESA graphic mode -- linear frame buffer */ + uint16_t lfb_width; /* 0x12 */ + uint16_t lfb_height; /* 0x14 */ + uint16_t lfb_depth; /* 0x16 */ + uint32_t lfb_base; /* 0x18 */ + uint32_t lfb_size; /* 0x1c */ + uint16_t cl_magic; /* 0x20 */ +#define CL_MAGIC_VALUE 0xA33F + uint16_t cl_offset; /* 0x22 */ + uint16_t lfb_linelength; /* 0x24 */ + uint8_t red_size; /* 0x26 */ + uint8_t red_pos; /* 0x27 */ + uint8_t green_size; /* 0x28 */ + uint8_t green_pos; /* 0x29 */ + uint8_t blue_size; /* 0x2a */ + uint8_t blue_pos; /* 0x2b */ + uint8_t rsvd_size; /* 0x2c */ + uint8_t rsvd_pos; /* 0x2d */ + uint16_t vesapm_seg; /* 0x2e */ + uint16_t vesapm_off; /* 0x30 */ + uint16_t pages; /* 0x32 */ + uint8_t reserved4[12]; /* 0x34 -- 0x3f reserved for future expansion */ + + struct apm_bios_info apm_bios_info; /* 0x40 */ + struct drive_info_struct drive_info; /* 0x80 */ + struct sys_desc_table sys_desc_table; /* 0xa0 */ + uint32_t alt_mem_k; /* 0x1e0 */ + uint8_t reserved5[4]; /* 0x1e4 */ + uint8_t e820_map_nr; /* 0x1e8 */ + uint8_t reserved6[9]; /* 0x1e9 */ + uint16_t mount_root_rdonly; /* 0x1f2 */ + uint8_t reserved7[4]; /* 0x1f4 */ + uint16_t ramdisk_flags; /* 0x1f8 */ +#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_PROMPT_FLAG 0x8000 +#define RAMDISK_LOAD_FLAG 0x4000 + uint8_t reserved8[2]; /* 0x1fa */ + uint16_t orig_root_dev; /* 0x1fc */ + uint8_t reserved9[1]; /* 0x1fe */ + uint8_t aux_device_info; /* 0x1ff */ + uint8_t reserved10[2]; /* 0x200 */ + uint8_t param_block_signature[4]; /* 0x202 */ + uint16_t param_block_version; /* 0x206 */ + uint8_t reserved11[8]; /* 0x208 */ + uint8_t loader_type; /* 0x210 */ +#define LOADER_TYPE_LOADLIN 1 +#define LOADER_TYPE_BOOTSECT_LOADER 2 +#define LOADER_TYPE_SYSLINUX 3 +#define LOADER_TYPE_ETHERBOOT 4 +#define LOADER_TYPE_KERNEL 5 + uint8_t loader_flags; /* 0x211 */ + uint8_t reserved12[2]; /* 0x212 */ + uint32_t kernel_start; /* 0x214 */ + uint32_t initrd_start; /* 0x218 */ + uint32_t initrd_size; /* 0x21c */ + uint8_t reserved13[176]; /* 0x220 */ + struct e820entry e820_map[E820MAX]; /* 0x2d0 */ + uint8_t reserved16[688]; /* 0x550 */ +#define COMMAND_LINE_SIZE 256 + uint8_t command_line[COMMAND_LINE_SIZE]; /* 0x800 */ + uint8_t reserved17[1792]; /* 0x900 - 0x1000 */ +}; + +/* Keep track of which information I need to acquire. */ +struct param_info { + unsigned type; + void *data; + struct parameters *real_mode; + /* bootloader type */ + int has_multiboot; + int has_uniform_boot; + int has_elf_boot; + /* firmware type */ + int has_pcbios; + int has_linuxbios; + struct lb_header *lb_table; + /* machine information needed */ + int need_mem_sizes; +}; +/* + * This is set up by the setup-routine at boot-time + */ + + + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +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), +}; + + +/* FIXME handle systems with large EBDA's */ +static struct parameters *faked_real_mode = (void *)0x90000; + + + +/* + * Output + * ============================================================================= + */ + +/* Base Address */ +#define TTYS0 0x3f8 +#define TTYS0_LSR (TTYS0+0x05) +#define TTYS0_TBR (TTYS0+0x00) + +static void ttys0_tx_byte(unsigned byte) +{ + /* Wait until I can send a byte */ + while((inb(TTYS0_LSR) & 0x20) == 0) + ; + outb(byte, TTYS0_TBR); + /* Wait until the byte is transmitted */ + while(!(inb(TTYS0_LSR) & 0x40)) + ; +} +static void put_char_serial(int c) +{ + if (c == '\n') { + ttys0_tx_byte('\r'); + } + ttys0_tx_byte(c); +} + +static void put_char(int c) +{ +#if 0 + put_char_video(c); +#endif + put_char_serial(c); +} + +static void puts(const char *str) +{ + int c; + while(c = *str++) { + put_char(c); + } +} + +static void __put_hex(unsigned long long x, int bits) +{ + static const char digit[] = "0123456789ABCDEF"; + int i; + for(i = bits -4; i >= 0; i -= 4) { + put_char(digit[(x >> i) & 0xf]); + } +} + +static void put_hex(unsigned x) +{ + puts("0x"); + __put_hex(x, 32); +} + +static void put_lhex(unsigned long long x) +{ + puts("0x"); + __put_hex(x, 64); +} + + +/* + * String Functions + * ============================================================================= + */ + + +size_t strnlen(const char *s, size_t max) +{ + size_t len = 0; + while(len < max && *s) { + len++; + s++; + } + return len; +} + +void* memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 1; + remainder = len & 1; + while(len--) { + partial += *(ptr++); + if (partial > 0xFFFF) + partial -= 0xFFFF; + } + if (remainder) { + unsigned char *ptr2 = (void *)ptr; + partial += *ptr2; + if (partial > 0xFFFF) + partial -= 0xFFFF; + } + return partial; +} + +static unsigned long checksum_final(unsigned long partial) +{ + return (~partial) & 0xFFFF; +} + +static unsigned long compute_checksum(void *vaddr, unsigned long length) +{ + return checksum_final(checksum_partial(0, vaddr, length)); +} + +/* + * Helper functions + * ============================================================================= + */ + + +void append_command_line(struct parameters *real_mode, char *arg, int arg_bytes) +{ + int len, max; + char *dest; + /* skip over what has already been set */ + len = strnlen(real_mode->command_line, sizeof(real_mode->command_line)); + dest = real_mode->command_line + len; + max = sizeof(real_mode->command_line) - 1; + if (max < 1) { + /* No room to append anything :( */ + return; + } + /* Add a space in between strings */ + *dest++ = ' '; + /* Append the added command line */ + max = sizeof(real_mode->command_line) - 1; + if (max > arg_bytes) { + max = arg_bytes; + } + len = strnlen(arg, max); + memcpy(dest, arg, len); + /* Null terminate the string */ + *dest++ = '\0'; +} + +static void set_memsize_k(struct parameters *real_mode, unsigned long mem_k) +{ + /* ALT_MEM_K maxes out at 4GB */ + if (mem_k > 0x3fffff) { + mem_k = 0x3fffff; + } + if (mem_k > (real_mode->alt_mem_k + (1 << 10))) { + /* Use our memory size less 1M */ + real_mode->alt_mem_k = mem_k - (1 << 10); + real_mode->ext_mem_k = mem_k - (1 << 10); + if ((mem_k - (1 << 10)) > 0xFFFF) { + real_mode->ext_mem_k = 0xFC00; /* 64 M */ + } + } +} + +static void add_e820_map(struct parameters *real_mode, + unsigned long long addr, unsigned long long size, + unsigned long type) +{ + unsigned long long high; + unsigned long mem_k; + int i; + i = real_mode->e820_map_nr; + if (i < E820MAX) { + real_mode->e820_map[i].addr = addr; + real_mode->e820_map[i].size = size; + real_mode->e820_map[i].type = type; + real_mode->e820_map_nr++; + } + /* policy I assume that for the legacy memory + * variables memory is contiguous. + */ + if (type == E820_RAM) { + high = addr + size; + if (high >= 0x40000000000ULL) { + mem_k = 0xFFFFFFFF; + } else { + mem_k = high >> 10; + } + set_memsize_k(real_mode, mem_k); + } +} + +/* + * Multiboot + * ============================================================================= + */ + +#define MULTI_MEM_DEBUG 0 +#if MULTI_MEM_DEBUG +#define multi_puts(x) puts(x) +#define multi_put_hex(x) put_hex(x) +#define multi_put_lhex(x) put_lhex(x) +#else +#define multi_puts(x) +#define multi_put_hex(x) +#define multi_put_lhex(x) +#endif /* MULTI_MEM_DEBUG */ + +/* Multiboot Specification */ +struct multiboot_mods { + unsigned mod_start; + unsigned mod_end; + unsigned char *string; + unsigned reserved; +}; + +struct memory_segment { + unsigned long long addr; + unsigned long long size; + unsigned type; +}; + +struct multiboot_info { + unsigned flags; +#define MULTIBOOT_MEM_VALID 0x01 +#define MULTIBOOT_BOOT_DEV_VALID 0x02 +#define MULTIBOOT_CMDLINE_VALID 0x04 +#define MULTIBOOT_MODS_VALID 0x08 +#define MULTIBOOT_AOUT_SYMS_VALID 0x10 +#define MULTIBOOT_ELF_SYMS_VALID 0x20 +#define MULTIBOOT_MMAP_VALID 0x40 + unsigned mem_lower; + unsigned mem_upper; + unsigned char boot_device[4]; + void *command_line; + unsigned mods_count; + struct multiboot_mods *mods_addr; + unsigned syms_num; + unsigned syms_size; + unsigned syms_addr; + unsigned syms_shndx; + unsigned mmap_length; + struct memory_segment *mmap_addr; +}; + +#define MULTIBOOT_MAX_COMMAND_LINE 0xFFFFFFFF + +static void convert_multiboot_memmap( + struct parameters *real_mode, + struct multiboot_info *info) +{ + unsigned size; + unsigned *size_addr; + int i; +#define next_seg(seg, size) ((struct memory_segment *)((char *)(seg) + (size))) + struct memory_segment *seg, *end; + + seg = info->mmap_addr; + end = (void *)(((char *)seg) + info->mmap_length); + size_addr = (unsigned *)(((char *)seg) - 4); + size = *size_addr; + multi_puts("mmap_addr: "); multi_put_hex((unsigned)info->mmap_addr); multi_puts("\n"); + multi_puts("mmap_length: "); multi_put_hex(info->mmap_length); multi_puts("\n"); + multi_puts("size_addr: "); multi_put_hex((unsigned)size_addr); multi_puts("\n"); + multi_puts("size: "); multi_put_hex(size); multi_puts("\n"); + multi_puts("end: "); multi_put_hex((unsigned)end); multi_puts("\n"); + for(seg = info->mmap_addr; (seg < end); seg = next_seg(seg,size)) { + multi_puts("multi-mem: "); + multi_put_lhex(seg->size); + multi_puts(" @ "); + multi_put_lhex(seg->addr); + multi_puts(" ("); + switch(seg->type) { + case E820_RAM: + multi_puts("ram"); + break; + case E820_ACPI: + multi_puts("ACPI data"); + break; + case E820_NVS: + multi_puts("ACPI NVS"); + break; + case E820_RESERVED: + default: + multi_puts("reserved"); + break; + } + multi_puts(")\n"); + add_e820_map(real_mode, seg->addr, seg->size, seg->type); + } +#undef next_seg +} + +static void convert_multiboot( + struct param_info *info, struct multiboot_info *mb_info) +{ + if (info->need_mem_sizes && (mb_info->flags & MULTIBOOT_MEM_VALID)) { + /* info->memory is short 1M */ + set_memsize_k(info->real_mode, mb_info->mem_upper + (1 << 10)); + } + if (mb_info->flags & MULTIBOOT_CMDLINE_VALID) { + append_command_line(info->real_mode, mb_info->command_line, + MULTIBOOT_MAX_COMMAND_LINE); + } + if (info->need_mem_sizes && (mb_info->flags & MULTIBOOT_MMAP_VALID)) { + convert_multiboot_memmap(info->real_mode, mb_info); + } + if (mb_info->flags & (MULTIBOOT_MEM_VALID | MULTIBOOT_MMAP_VALID)) { + info->need_mem_sizes = 0; + } +} + + +/* + * Uniform Boot Environment + * ============================================================================= + */ + +#define UBE_MEM_DEBUG 0 +#if UBE_MEM_DEBUG +#define ube_puts(x) puts(x) +#define ube_put_hex(x) put_hex(x) +#define ube_put_lhex(x) put_lhex(x) +#else +#define ube_puts(x) +#define ube_put_hex(x) +#define ube_put_lhex(x) +#endif /* UBE_MEM_DEBUG */ +static void convert_uniform_boot_memory( + struct parameters *real_mode, struct ube_memory *mem) +{ + int i; + int entries; + unsigned long mem_k; + mem_k = 0; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + for(i = 0; (i < entries) && (i < E820MAX); i++) { + unsigned long type; + ube_puts("ube-mem: "); + ube_put_lhex(mem->map[i].size); + ube_puts(" @ "); + ube_put_lhex(mem->map[i].start); + ube_puts(" ("); + switch(mem->map[i].type) { + case UBE_MEM_RAM: + type = E820_RAM; + ube_puts("ram"); + break; + case UBE_MEM_ACPI: + type = E820_ACPI; + ube_puts("ACPI data"); + break; + case UBE_MEM_NVS: + type = E820_NVS; + ube_puts("ACPI NVS"); + break; + case UBE_MEM_RESERVED: + default: + type = E820_RESERVED; + ube_puts("reserved"); + break; + } + ube_puts(")\n"); + add_e820_map(real_mode, + mem->map[i].start, mem->map[i].size, type); + } +} + +static void convert_uniform_boot(struct param_info *info, + struct uniform_boot_header *header) +{ + /* Uniform boot environment */ + unsigned long env_bytes; + char *env; + if (header->arg_bytes) { + append_command_line(info->real_mode, (void *)(header->arg), header->arg_bytes); + } + env = (void *)(header->env); + env_bytes = header->env_bytes; + while(env_bytes) { + struct ube_record *record; + unsigned long mem_k; + record = (void *)env; + if (record->tag == UBE_TAG_MEMORY) { + if (info->need_mem_sizes) { + convert_uniform_boot_memory(info->real_mode, (void *)record); + info->need_mem_sizes = 0; + } + } + env += record->size; + env_bytes -= record->size; + } +} + + + + +/* + * Hardware + * ============================================================================= + */ + +/* we're getting screwed again and again by this problem of the 8259. + * so we're going to leave this lying around for inclusion into + * crt0.S on an as-needed basis. + * well, that went ok, I hope. Now we have to reprogram the interrupts :-( + * we put them right after the intel-reserved hardware interrupts, at + * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really + * messed this up with the original PC, and they haven't been able to + * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, + * which is used for the internal hardware interrupts as well. We just + * have to reprogram the 8259's, and it isn't fun. + */ + +static void setup_i8259(void) +{ + outb_p(0x11, 0x20); /*! initialization sequence to 8259A-1*/ + outb_p(0x11, 0xA0); /*! and to 8259A-2*/ + + outb_p(0x20, 0x21); /*! start of hardware int's (0x20)*/ + outb_p(0x28, 0xA1); /*! start of hardware int's 2 (0x28)*/ + + outb_p(0x04, 0x21); /*! 8259-1 is master*/ + outb_p(0x02, 0xA1); /*! 8259-2 is slave*/ + + outb_p(0x01, 0x21); /*! 8086 mode for both*/ + outb_p(0x01, 0xA1); + + outb_p(0xFF, 0xA1); /*! mask off all interrupts for now*/ + outb_p(0xFB, 0x21); /*! mask all irq's but irq2 which is cascaded*/ +} + +static void hardware_setup(struct param_info *info) +{ + /* Disable nmi */ + outb(0x80, 0x70); + + /* Make sure any coprocessor is properly reset.. */ + outb_p(0, 0xf0); + outb_p(0, 0xf1); + + setup_i8259(); +} + + +/* + * ELF Boot loader + * ============================================================================= + */ + +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; + int count; + count = 0; + for(hdr = start; ((void *)hdr < end) && + (elf_note_size(hdr) <= (end - (void *)hdr)); + hdr = next_elf_note(hdr)) { + count++; + } + return count; +} + +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); + if ((hdr->n_type == type) && + (hdr->n_namesz == namesz) && + (memcmp(n_name, name, namesz) == 0)) { + return hdr; + } + } + return 0; +} + +static void convert_elf_command_line(struct param_info *info, + Elf_Word descsz, unsigned char *desc) +{ + append_command_line(info->real_mode, desc, descsz); +} + +struct { + Elf_Word namesz; + unsigned char *name; + Elf_Word type; + void (*convert)(struct param_info *info, Elf_Word descsz, unsigned char *desc); +} elf_notes[] = +{ + { 0, "", EBN_COMMAND_LINE, convert_elf_command_line }, +}; + +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); + 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) && + (memcmp(n_name, elf_notes[i].name, elf_notes[i].namesz) == 0)) { + elf_notes[i].convert(info, hdr->n_descsz, n_desc); + break; + } + } + } +} + +/* + * LinuxBIOS + * ============================================================================= + */ + +#define LB_MEM_DEBUG 0 +#if LB_MEM_DEBUG +#define lb_puts(x) puts(x) +#define lb_put_hex(x) put_hex(x) +#define lb_put_lhex(x) put_lhex(x) +#else +#define lb_puts(x) +#define lb_put_hex(x) +#define lb_put_lhex(x) +#endif /* LB_MEM_DEBUG */ + +static int count_lb_records(void *start, unsigned long length) +{ + struct lb_record *rec; + void *end; + int count; + count = 0; + end = ((char *)start) + length; + for(rec = start; ((void *)rec < end) && + (rec->size <= (end - (void *)rec)); + rec = (void *)(((char *)rec) + rec->size)) { + count++; + } + return count; +} + +static int find_lb_table(struct param_info *info, void *start, void *end) +{ + unsigned char *ptr; + /* For now be stupid.... */ + for(ptr = start; (void *)ptr < end; ptr += 16) { + struct lb_header *head = (void *)ptr; + if ((head->signature[0] == 'L') && + (head->signature[1] == 'B') && + (head->signature[2] == 'I') && + (head->signature[3] == 'O') && + (head->header_bytes == sizeof(*head)) && + (compute_checksum(head, sizeof(*head)) == 0) && + (compute_checksum(ptr + sizeof(*head), head->table_bytes) == + head->table_checksum) && + (count_lb_records(ptr + sizeof(*head), head->table_bytes) == + head->table_entries) + ) { + info->has_linuxbios = 1; + info->lb_table = (void *)ptr; + return 1; + } + }; + return 0; +} + +static void convert_lb_memory(struct param_info *info, struct lb_memory *mem) +{ + int i; + int entries; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + for(i = 0; (i < entries) && (i < E820MAX); i++) { + unsigned long type; + unsigned long long end; + end = mem->map[i].start + mem->map[i].size; + lb_puts("lb-mem: "); + lb_put_lhex(mem->map[i].start); + lb_puts(" - "); + lb_put_lhex(end); + lb_puts(" ("); + switch(mem->map[i].type) { + case LB_MEM_RAM: + type = E820_RAM; + lb_puts("ram"); + break; + default: + type = E820_RESERVED; + lb_puts("reserved"); + break; + } + lb_puts(")\n"); + add_e820_map(info->real_mode, + mem->map[i].start, mem->map[i].size, type); + } + info->need_mem_sizes = 0; +} + +static void query_lb_values(struct param_info *info) +{ + struct lb_header *head; + struct lb_record *rec; + void *start, *end; + head = info->lb_table; + start = ((unsigned char *)head) + sizeof(*head); + end = ((char *)start) + head->table_bytes; + for(rec = start; ((void *)rec < end) && + (rec->size <= (end - (void *)rec)); + rec = (void *)(((char *)rec) + rec->size)) { + switch(rec->tag) { + case LB_TAG_MEMORY: + { + struct lb_memory *mem; + mem = (struct lb_memory *) rec; + convert_lb_memory(info, mem); + break; + } + default: + break; + }; + } +} + +/* + * PCBIOS + * ============================================================================= + */ +#define PC_MEM_DEBUG 0 +#if PC_MEM_DEBUG +#define pc_puts(x) puts(x) +#define pc_put_hex(x) put_hex(x) +#define pc_put_lhex(x) put_lhex(x) +#else +#define pc_puts(x) +#define pc_put_hex(x) +#define pc_put_lhex(x) +#endif /* PC_MEM_DEBUG */ + +/* functions for querying the pcbios */ +extern void noop(void); /* for testing purposes only */ +extern int meme820(struct e820entry *buf, int count); +extern unsigned int meme801(void); +extern unsigned short mem88(void); +extern unsigned short basememsize(void); + +struct meminfo { + int map_count; + struct e820entry map[E820MAX]; +}; + +static struct meminfo meminfo; +static void get_meminfo(struct param_info *info) +{ + int i; + pc_puts("getting meminfo...\n"); + meminfo.map_count = meme820(meminfo.map, E820MAX); + pc_puts("got meminfo count="); pc_put_hex(meminfo.map_count); pc_puts("\n"); + for(i = 0; i < meminfo.map_count; i++) { + unsigned long long end; + struct e820entry *seg = meminfo.map + i; + end = seg->addr + seg->size; + pc_puts("BIOS-e820: "); + pc_put_lhex(seg->addr); + pc_puts(" - "); + pc_put_lhex(end); + pc_puts(" ("); + switch(seg->type) { + case E820_RAM: + pc_puts("ram"); + info->need_mem_sizes = 0; + break; + case E820_ACPI: + pc_puts("ACPI data"); + break; + case E820_NVS: + pc_puts("ACPI NVS"); + break; + case E820_RESERVED: + default: + pc_puts("reserved"); + break; + } + pc_puts(")\n"); + add_e820_map(info->real_mode, + seg->addr, seg->size, seg->type); + } + info->real_mode->alt_mem_k = meme801(); + info->real_mode->ext_mem_k = mem88(); + if (info->real_mode->alt_mem_k || info->real_mode->ext_mem_k) { + info->need_mem_sizes = 0; + } +} + +static void query_pcbios_values(struct param_info *info) +{ + get_meminfo(info); +} + +/* + * Bootloaders + * ============================================================================= + */ + + +static void query_bootloader_param_class(struct param_info *info) +{ + int has_bootloader_type = 0; + if (!has_bootloader_type && (info->type == 0x2BADB002)) { + /* Orignal multiboot specification */ + info->has_multiboot = 1; + has_bootloader_type = 1; + } + if (!has_bootloader_type && (info->type == 0x0A11B007)) { + /* Uniform boot proposal */ + unsigned long checksum; + struct uniform_boot_header *header; + header = info->data; + checksum = compute_checksum(header, header->header_bytes); + if (checksum == 0) { + info->has_uniform_boot = 1; + has_bootloader_type = 1; + } else{ + puts("Bad uniform boot header checksum!\n"); + } + } + if (!has_bootloader_type && (info->type == 0x0E1FB007)) { + /* Good ELF boot proposal... */ + Elf_Bhdr *hdr; + unsigned long checksum; + int count; + hdr = info->data; + checksum = compute_checksum(hdr, hdr->b_size); + count = count_elf_notes(hdr); + if ((hdr->b_signature == ELF_BOOT_MAGIC) && + (checksum == 0) && + hdr->b_records == count) { + info->has_elf_boot = 1; + has_bootloader_type = 1; + } + else { + puts("Bad ELF parameter table!\n"); + } + } + if (!has_bootloader_type) { + puts("Unknown bootloader class!\n"); + puts("type="); put_hex(info->type); puts("\n"); + puts("data="); put_hex((unsigned)info->data); puts("\n"); + } +} + +static void query_bootloader_values(struct param_info *info) +{ + if (info->has_multiboot) { + convert_multiboot(info, info->data); + } + else if (info->has_uniform_boot) { + convert_uniform_boot(info, info->data); + } + else if (info->has_elf_boot) { + convert_elf_boot(info, info->data); + } +} + +/* + * Firmware + * ============================================================================= + */ + +static int bootloader_query_firmware_class(struct param_info *info) +{ + Elf_Nhdr *hdr; + if (!info->has_elf_boot) { + /* Only the elf boot tables gives us a firmware type */ + return 0; + } + hdr = find_elf_note(info->data, 0, 0, EBN_FIRMWARE_TYPE); + if (!hdr) { + info->has_pcbios = 1; + } + else if ((hdr->n_descsz == 7) && + (memcmp(elf_note_desc(hdr), "PCBIOS", 7) == 0)) { + info->has_pcbios = 1; + } + else if ((hdr->n_descsz == 10) && + (memcmp(elf_note_desc(hdr), "LinuxBIOS", 10) == 0)) { + info->has_linuxbios = 1; + } + else if (hdr->n_descsz == 0) { + /* No firmware is present */ + } + else if ((hdr->n_descsz == 1) && + (memcmp(elf_note_desc(hdr), "", 1) == 0)) { + /* No firmware is present */ + } + else { + puts("Unknow firmware type!"); + } + return 1; +} + +static void query_firmware_class(struct param_info *info) +{ + int detected_firmware_type = 0; + + /* First say I have no firmware at all... */ + info->has_pcbios = 0; + info->has_linuxbios = 0; + + /* See if the bootloader has told us what + * kind of firmware we are running on. + */ + detected_firmware_type = bootloader_query_firmware_class(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); + } + + if (!detected_firmware_type) { + /* if all else fails assume a standard pcbios... */ + info->has_pcbios = 1; + } + + /* Now print out the firmware type... */ + puts("Firmware type:"); + if (info->has_linuxbios) { + puts(" linuxBIOS"); + } + if (info->has_pcbios) { + puts(" PCBIOS"); + } + puts("\n"); +} + +static void query_firmware_values(struct param_info *info) +{ + if (info->has_linuxbios) { + query_lb_values(info); + } + if (info->has_pcbios) { + query_pcbios_values(info); + } + +} + +/* + * Debug + * ============================================================================= + */ + +#if 0 +static print_offsets(void) +{ + struct parameters *real_mode = 0; + puts("print_offsets\n"); + + puts("orig_x="); put_hex((uint32_t)&real_mode->orig_x); puts("\n"); + puts("orig_y="); put_hex((uint32_t)&real_mode->orig_y); puts("\n"); + puts("ext_mem_k="); put_hex((uint32_t)&real_mode->ext_mem_k); puts("\n"); + puts("orig_video_page="); put_hex((uint32_t)&real_mode->orig_video_page); puts("\n"); + puts("orig_video_mode="); put_hex((uint32_t)&real_mode->orig_video_mode); puts("\n"); + puts("orig_video_cols="); put_hex((uint32_t)&real_mode->orig_video_cols); puts("\n"); + puts("unused2="); put_hex((uint32_t)&real_mode->unused2); puts("\n"); + puts("orig_video_ega_bx="); put_hex((uint32_t)&real_mode->orig_video_ega_bx); puts("\n"); + puts("unused3="); put_hex((uint32_t)&real_mode->unused3); puts("\n"); + puts("orig_video_lines="); put_hex((uint32_t)&real_mode->orig_video_lines); puts("\n"); + puts("orig_video_isVGA="); put_hex((uint32_t)&real_mode->orig_video_isVGA); puts("\n"); + puts("orig_video_points="); put_hex((uint32_t)&real_mode->orig_video_points); puts("\n"); + puts("lfb_width="); put_hex((uint32_t)&real_mode->lfb_width); puts("\n"); + puts("lfb_height="); put_hex((uint32_t)&real_mode->lfb_height); puts("\n"); + puts("lfb_depth="); put_hex((uint32_t)&real_mode->lfb_depth); puts("\n"); + puts("lfb_base="); put_hex((uint32_t)&real_mode->lfb_base); puts("\n"); + puts("lfb_size="); put_hex((uint32_t)&real_mode->lfb_size); puts("\n"); + puts("cl_magic="); put_hex((uint32_t)&real_mode->cl_magic); puts("\n"); + puts("cl_offset="); put_hex((uint32_t)&real_mode->cl_offset); puts("\n"); + puts("lfb_linelength="); put_hex((uint32_t)&real_mode->lfb_linelength); puts("\n"); + puts("red_size="); put_hex((uint32_t)&real_mode->red_size); puts("\n"); + puts("red_pos="); put_hex((uint32_t)&real_mode->red_pos); puts("\n"); + puts("green_size="); put_hex((uint32_t)&real_mode->green_size); puts("\n"); + puts("green_pos="); put_hex((uint32_t)&real_mode->green_pos); puts("\n"); + puts("blue_size="); put_hex((uint32_t)&real_mode->blue_size); puts("\n"); + puts("blue_pos="); put_hex((uint32_t)&real_mode->blue_pos); puts("\n"); + puts("rsvd_size="); put_hex((uint32_t)&real_mode->rsvd_size); puts("\n"); + puts("rsvd_pos="); put_hex((uint32_t)&real_mode->rsvd_pos); puts("\n"); + puts("vesapm_seg="); put_hex((uint32_t)&real_mode->vesapm_seg); puts("\n"); + puts("vesapm_off="); put_hex((uint32_t)&real_mode->vesapm_off); puts("\n"); + puts("pages="); put_hex((uint32_t)&real_mode->pages); puts("\n"); + puts("reserved4="); put_hex((uint32_t)&real_mode->reserved4); puts("\n"); + puts("apm_bios_info="); put_hex((uint32_t)&real_mode->apm_bios_info); puts("\n"); + puts("drive_info="); put_hex((uint32_t)&real_mode->drive_info); puts("\n"); + puts("sys_desc_table="); put_hex((uint32_t)&real_mode->sys_desc_table); puts("\n"); + puts("alt_mem_k="); put_hex((uint32_t)&real_mode->alt_mem_k); puts("\n"); + puts("reserved5="); put_hex((uint32_t)&real_mode->reserved5); puts("\n"); + puts("e820_map_nr="); put_hex((uint32_t)&real_mode->e820_map_nr); puts("\n"); + puts("reserved6="); put_hex((uint32_t)&real_mode->reserved6); puts("\n"); + puts("mount_root_rdonly="); put_hex((uint32_t)&real_mode->mount_root_rdonly); puts("\n"); + puts("reserved7="); put_hex((uint32_t)&real_mode->reserved7); puts("\n"); + puts("ramdisk_flags="); put_hex((uint32_t)&real_mode->ramdisk_flags); puts("\n"); + puts("reserved8="); put_hex((uint32_t)&real_mode->reserved8); puts("\n"); + puts("orig_root_dev="); put_hex((uint32_t)&real_mode->orig_root_dev); puts("\n"); + puts("reserved9="); put_hex((uint32_t)&real_mode->reserved9); puts("\n"); + puts("aux_device_info="); put_hex((uint32_t)&real_mode->aux_device_info); puts("\n"); + puts("reserved10="); put_hex((uint32_t)&real_mode->reserved10); puts("\n"); + puts("param_block_signature="); put_hex((uint32_t)&real_mode->param_block_signature); puts("\n"); + puts("param_block_version="); put_hex((uint32_t)&real_mode->param_block_version); puts("\n"); + puts("reserved11="); put_hex((uint32_t)&real_mode->reserved11); puts("\n"); + puts("loader_type="); put_hex((uint32_t)&real_mode->loader_type); puts("\n"); + puts("loader_flags="); put_hex((uint32_t)&real_mode->loader_flags); puts("\n"); + puts("reserved12="); put_hex((uint32_t)&real_mode->reserved12); puts("\n"); + puts("kernel_start="); put_hex((uint32_t)&real_mode->kernel_start); puts("\n"); + puts("initrd_start="); put_hex((uint32_t)&real_mode->initrd_start); puts("\n"); + puts("initrd_size="); put_hex((uint32_t)&real_mode->initrd_size); puts("\n"); + puts("reserved13="); put_hex((uint32_t)&real_mode->reserved13); puts("\n"); + puts("e820_map="); put_hex((uint32_t)&real_mode->e820_map); puts("\n"); + puts("reserved16="); put_hex((uint32_t)&real_mode->reserved16); puts("\n"); + puts("command_line="); put_hex((uint32_t)&real_mode->command_line); puts("\n"); + puts("reserved17="); put_hex((uint32_t)&real_mode->reserved17); puts("\n"); +} + +static print_linux_params(struct param_info *info) +{ + int i; + + puts("print_linux_params\n"); + /* Default screen size */ + puts("orig_x ="); put_hex(info->real_mode->orig_x); puts("\n"); + puts("orig_y ="); put_hex(info->real_mode->orig_y); puts("\n"); + puts("orig_video_page ="); put_hex(info->real_mode->orig_video_page); puts("\n"); + puts("orig_video_mode ="); put_hex(info->real_mode->orig_video_mode); puts("\n"); + puts("orig_video_cols ="); put_hex(info->real_mode->orig_video_cols); puts("\n"); + puts("orig_video_lines ="); put_hex(info->real_mode->orig_video_lines); puts("\n"); + puts("orig_video_ega_bx="); put_hex(info->real_mode->orig_video_ega_bx); puts("\n"); + puts("orig_video_isVGA ="); put_hex(info->real_mode->orig_video_isVGA); puts("\n"); + puts("orig_video_points="); put_hex(info->real_mode->orig_video_points); puts("\n"); + + + /* System descriptor table... */ + puts("sys_dest_table_len="); put_hex(info->real_mode->sys_desc_table.length); puts("\n"); + + /* Memory sizes */ + puts("ext_mem_k ="); put_hex(info->real_mode->ext_mem_k); puts("\n"); + puts("alt_mem_k ="); put_hex(info->real_mode->alt_mem_k); puts("\n"); + puts("e820_map_nr ="); put_hex(info->real_mode->e820_map_nr); puts("\n"); + for(i = 0; i < E820MAX; i++) { + puts("addr["); put_hex(i); puts("] ="); + put_lhex(info->real_mode->e820_map[i].addr); + puts("\n"); + puts("size["); put_hex(i); puts("] ="); + put_lhex(info->real_mode->e820_map[i].size); + puts("\n"); + puts("type["); put_hex(i); puts("] ="); + put_hex(info->real_mode->e820_map[i].type); + puts("\n"); + } + puts("mount_root_rdonly="); put_hex(info->real_mode->mount_root_rdonly); puts("\n"); + puts("ramdisk_flags ="); put_hex(info->real_mode->ramdisk_flags); puts("\n"); + puts("orig_root_dev ="); put_hex(info->real_mode->orig_root_dev); puts("\n"); + puts("aux_device_info ="); put_hex(info->real_mode->aux_device_info); puts("\n"); + puts("param_block_signature="); put_hex(*((uint32_t *)info->real_mode->param_block_signature)); puts("\n"); + puts("loader_type ="); put_hex(info->real_mode->loader_type); puts("\n"); + puts("loader_flags ="); put_hex(info->real_mode->loader_flags); puts("\n"); + puts("initrd_start ="); put_hex(info->real_mode->initrd_start); puts("\n"); + puts("initrd_size ="); put_hex(info->real_mode->initrd_size); puts("\n"); + + /* Where I'm putting the command line */ + puts("cl_magic ="); put_hex(info->real_mode->cl_magic); puts("\n"); + puts("cl_offset ="); put_hex(info->real_mode->cl_offset); puts("\n"); + + /* Now print the command line */ + puts("command_line ="); puts(info->real_mode->command_line); puts("\n"); + +} + + +#endif + +/* + * main + * ============================================================================= + */ + +void initialize_linux_params(struct param_info *info) +{ + int len; + /* First the defaults */ + memset(info->real_mode, 0, PAGE_SIZE); + + /* Default screen size */ + info->real_mode->orig_x = 0; + info->real_mode->orig_y = 25; + info->real_mode->orig_video_page = 0; + info->real_mode->orig_video_mode = 0; + info->real_mode->orig_video_cols = 80; + info->real_mode->orig_video_lines = 25; + info->real_mode->orig_video_ega_bx = 0; + info->real_mode->orig_video_isVGA = 1; + info->real_mode->orig_video_points = 16; + + /* Fill this in later */ + info->real_mode->ext_mem_k = 0; + + /* Fill in later... */ + info->real_mode->e820_map_nr = 0; + + /* Where I'm putting the command line */ + info->real_mode->cl_magic = CL_MAGIC_VALUE; + 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); + info->real_mode->command_line[len] = '\0'; + + /* from the bios initially */ + memset(&info->real_mode->apm_bios_info, 0, sizeof(info->real_mode->apm_bios_info)); + + memset(&info->real_mode->drive_info, 0, sizeof(info->real_mode->drive_info)); + + /* forget it for now... */ + info->real_mode->sys_desc_table.length = 0; + + /* Fill this in later */ + info->real_mode->alt_mem_k = 0; + info->real_mode->ext_mem_k = 0; + + /* default yes: this can be overridden on the command line */ + info->real_mode->mount_root_rdonly = 0xFFFF; + + /* old ramdisk options, These really should be command line + * things... + */ + info->real_mode->ramdisk_flags = note_ramdisk_flags.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; + + /* Originally from the bios? */ + info->real_mode->aux_device_info = 0; + + /* Boot block magic */ + memcpy(info->real_mode->param_block_signature, "HdrS", 4); + info->real_mode->param_block_version = 0x0201; + + /* Say I'm a kernel boot loader */ + info->real_mode->loader_type = (LOADER_TYPE_KERNEL << 4) + 0 /* version */; + + /* No loader flags */ + info->real_mode->loader_flags = 0; + + /* 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; + } + + /* Now remember those things that I need */ + info->need_mem_sizes = 1; +} + + + + +void *convert_params(unsigned type, void *data) +{ + struct param_info info; + size_t len; + int have_realmode; +#if 0 + puts("hello world\n"); +#endif + info.real_mode = faked_real_mode; + info.type = type; + info.data = data; + initialize_linux_params(&info); + query_bootloader_param_class(&info); + query_firmware_class(&info); + query_firmware_values(&info); + query_bootloader_values(&info); + + /* Do the hardware setup that linux might forget... */ + hardware_setup(&info); + + /* Print some debugging information */ +#if 0 + puts("EXT_MEM_K="); put_hex(info.real_mode->ext_mem_k); puts("\n"); + puts("ALT_MEM_K="); put_hex(info.real_mode->alt_mem_k); puts("\n"); +#endif +#if 0 + print_offsets(); + print_linux_params(&info); +#endif + return info.real_mode; +} + diff --git a/util/mkelfImage/elf32-i386/elfImage.lds b/util/mkelfImage/elf32-i386/elfImage.lds new file mode 100644 index 0000000000..89b5641b20 --- /dev/null +++ b/util/mkelfImage/elf32-i386/elfImage.lds @@ -0,0 +1,80 @@ +/* This setup assumes you have at least a 16M machine + * The problem is that with 2GB of RAM you use nearly 23M + * of memory in the kernel page tables, and since 2.2 doesn't check + * where the initrd is placed before allocating memory this is a + * problem. With a 8M Ramdisk + 23M kernel that is 31M leaving + * little room for things to grow. + * With the limit at 112M (i.e. 0x00700000) we should be o.k.) + * + * If you need to change the amount of assumed memory. + * The uppper.LENGTH needs to change so that + * upper.LENGTH + upper.ORIGIN = MEMORY_SIZE + * and the computation just before ramdisk placing also should + * be corrected, to be: + * . = MEMORY_SIZE - ((ramdisk_data_end - ramdisk_data) + 4095) + * .ramdisk(ALIGN(4096)) + */ + +INCLUDE mkelfImage.lds +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +MEMORY +{ + /* 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 +} +ENTRY(startup_32) +SECTIONS +{ + . = 0x10000 ; + _text = .; /* Text and read-only data */ + .text (.): { + *(.text) + *(.fixup) + *(.gnu.warning) + } > low = 0x9090 + .rodata (.): { *(.rodata) *(.note.data)} > low + .kstrtab (.): { *(.kstrtab) } > low + + + . = ALIGN(16); /* Exception table */ + _etext = .; /* End of text section */ + + .data (.): { /* Data */ + *(.data) + CONSTRUCTORS + } > low + + _edata = .; /* End of data section */ + __bss_start = .; /* BSS */ + .bss (.): { + *(.bss) + } > low + _end = . ; + + + . = 0x91000 ; + .nokill (.): { + *(.nokill) + } > middle + + . = 0x100000 ; + .kernel (.): { + *(.kernel) + } > upper + . = initrd_base; + .ramdisk (ALIGN(4096)) : { + *(.ramdisk) + } > upper + ramdisk_data_size = (ramdisk_data_end - ramdisk_data); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/util/mkelfImage/elf32-i386/elf_boot.h b/util/mkelfImage/elf32-i386/elf_boot.h new file mode 100644 index 0000000000..b9b66b3752 --- /dev/null +++ b/util/mkelfImage/elf32-i386/elf_boot.h @@ -0,0 +1,83 @@ +#ifndef ELF_BOOT_H +#define ELF_BOOT_H + +#include + +/* This defines the structure of a table of parameters useful for ELF + * bootable images. These parameters are all passed and generated + * by the bootloader to the booted image. For simplicity and + * consistency the Elf Note format is reused. + * + * All of the information must be Position Independent Data. + * That is it must be safe to relocate the whole ELF boot parameter + * block without changing the meaning or correctnes of the data. + * Additionally it must be safe to permute the order of the ELF notes + * to any possible permutation without changing the meaning or correctness + * of the data. + * + */ + +#define ELF_BOOT_MAGIC 0x0E1FB007 + +typedef uint16_t Elf_Half; +typedef uint32_t Elf_Word; +typedef uint64_t Elf_Xword; + +typedef struct +{ + Elf_Word b_signature; /* "0x0E1FB007" */ + Elf_Word b_size; + Elf_Half b_checksum; + Elf_Half b_records; +} Elf_Bhdr; + +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; + +/* For standard notes n_namesz must be zero */ +/* All of the following standard note types provide a single null + * terminated string in the descriptor. + */ +#define EBN_FIRMWARE_TYPE 0x00000001 +/* On platforms that support multiple classes of firmware this field + * specifies the class of firmware you are loaded under. + */ +#define EBN_BOOTLOADER_NAME 0x00000002 +/* This specifies just the name of the bootloader for easy comparison */ +#define EBN_BOOTLOADER_VERSION 0x00000003 +/* This specifies the version of the bootlader */ +#define EBN_COMMAND_LINE 0x00000004 +/* This specifies a command line that can be set by user interaction, + * and is provided as a free form string to the loaded image. + */ + + +/* Standardized Elf image notes for booting... The name for all of these is 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. */ + + +/* Linux image notes for booting... The name for all of these is Linux */ + +#define LIN_COMMAND_LINE 0x00000001 +/* The command line to pass to the loaded kernel. */ +#define LIN_ROOT_DEV 0x00000002 +/* The root dev to pass to the loaded kernel. */ +#define LIN_RAMDISK_FLAGS 0x00000003 +/* Various old ramdisk flags */ +#define LIN_INITRD_START 0x00000004 +/* Start of the ramdisk in bytes */ +#define LIN_INITRD_SIZE 0x00000005 +/* Size of the ramdisk in bytes */ + + +#endif /* ELF_BOOT_H */ diff --git a/util/mkelfImage/elf32-i386/head.S b/util/mkelfImage/elf32-i386/head.S new file mode 100644 index 0000000000..f60598873e --- /dev/null +++ b/util/mkelfImage/elf32-i386/head.S @@ -0,0 +1,390 @@ +# +# 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 RELOC 0x10000 +#define KERN_CODE_SEG 0x10 +#define KERN_DATA_SEG 0x18 +#define REAL_CODE_SEG 0x08 +#define REAL_DATA_SEG 0x20 + + .equ CR0_PE,1 + +#define TTYS0_BASE 0x3f8 +#define TTYS0_RBR (TTYS0_BASE+0x00) +#define TTYS0_TBR TTYS0_RBR +#define TTYS0_LSR (TTYS0_BASE+0x05) + + + /* uses: ax, dx */ +#define TTYS0_TX_AL \ + mov %al, %ah ; \ +9: mov $TTYS0_LSR, %dx ; \ + inb %dx, %al ; \ + test $0x20, %al ; \ + je 9b ; \ + mov $TTYS0_TBR, %dx ; \ + mov %ah, %al ; \ + outb %al, %dx + + /* uses: ax, dx */ +#define TTYS0_TX_CHAR(byte) \ + mov byte, %al ; \ + TTYS0_TX_AL + +.text + .code32 + .globl startup_32 +startup_32: + cld + cli + + # Save the arguments safely out of the way + movl %eax, %ebp + movl %ebx, %esi + + movl stack_start, %esp + + + # Clear eflags + pushl $0 + popfl + + # Clear BSS + xorl %eax,%eax + movl $ _edata,%edi + movl $ _end,%ecx + subl %edi,%ecx + cld + rep + stosb + + # Linux makes stupid assumptions about the segments + # that are already setup, so setup a new gdt & ldt + # and then reload the segment registers. + + lgdt gdt_48 + lidt idt_48 + + # Load the data segment registers + movl $ 0x18, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + pushl %esi # boot data pointer as second arg + pushl %ebp # boot data type as first argument + call convert_params + + movl %eax, %esi # put the real mode pointer in a safe place + addl $8, %esp # pop the arguments + + # Setup the registers before jumping to linux + + + # clear eflags + pushl $0 + popfl + + # Flag to indicate we are the bootstrap processor + xorl %ebx, %ebx + + # Clear the unspecified registers for good measure + xorl %eax, %eax + xorl %ecx, %ecx + xorl %edx, %edx + xorl %edi, %edi + xorl %esp, %esp + xorl %ebp, %ebp + + + # Jump to the linux kernel + ljmp $ 0x10 , $ 0x100000 + + + /* Routines to query the BIOS... */ + .globl noop +noop: + TTYS0_TX_CHAR($'a') + TTYS0_TX_CHAR($'\r') + TTYS0_TX_CHAR($'\n') + call _prot_to_real + .code16 + TTYS0_TX_CHAR($'b') + TTYS0_TX_CHAR($'\r') + TTYS0_TX_CHAR($'\n') + data32 call _real_to_prot + .code32 + TTYS0_TX_CHAR($'c') + TTYS0_TX_CHAR($'\r') + TTYS0_TX_CHAR($'\n') + ret + +/************************************************************************** +E820_MEMSIZE - Get a listing of memory regions +**************************************************************************/ +#define SMAP 0x534d4150 + .globl meme820 +meme820: + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %esi + pushl %edi + movl 8(%ebp), %edi /* Address to return e820 structures at */ + subl $RELOC, %edi + movl 12(%ebp), %esi /* Maximum number of e820 structurs to return */ + pushl %esi + call _prot_to_real + .code16 + xorl %ebx, %ebx +jmpe820: + movl $0xe820, %eax + movl $SMAP, %edx + movl $20, %ecx + /* %di was setup earlier */ + int $0x15 + jc bail820 + + cmpl $SMAP, %eax + jne bail820 + +good820: + /* If this is useable memory, we save it by simply advancing %di by + * sizeof(e820rec) + */ + decl %esi + testl %esi,%esi + jz bail820 + + addw $20, %di +again820: + cmpl $0, %ebx /* check to see if %ebx is set to EOF */ + jne jmpe820 + +bail820: + data32 call _real_to_prot + .code32 + popl %eax + subl %esi, %eax /* Compute how many structure we read */ + + /* Restore everything else */ + popl %edi + popl %esi + popl %ebx + movl %ebp, %esp + popl %ebp + ret + + +/************************************************************************** +MEME801 - Determine size of extended memory +**************************************************************************/ + .globl meme801 +meme801: + pushl %ebx + pushl %esi + pushl %edi + call _prot_to_real + .code16 + + stc # fix to work around buggy + xorw %cx,%cx # BIOSes which dont clear/set + xorw %dx,%dx # carry on pass/error of + # e801h memory size call + # or merely pass cx,dx though + # without changing them. + movw $0xe801,%ax + int $0x15 + jc e801absent + + cmpw $0x0, %cx # Kludge to handle BIOSes + jne e801usecxdx # which report their extended + cmpw $0x0, %dx # memory in AX/BX rather than + jne e801usecxdx # CX/DX. The spec I have read + movw %ax, %cx # seems to indicate AX/BX + movw %bx, %dx # are more reasonable anyway... + +e801usecxdx: + andl $0xffff, %edx # clear sign extend + shll $6, %edx # and go from 64k to 1k chunks + movl %edx, %eax # store extended memory size + andl $0xffff, %ecx # clear sign extend + addl %ecx, %eax # and add lower memory into + + jmp e801out +e801absent: + xorl %eax,%eax + +e801out: + data32 call _real_to_prot + .code32 + /* Restore Everything */ + popl %edi + popl %esi + popl %ebx + ret + +/************************************************************************** +MEM88 - Determine size of extended memory +**************************************************************************/ + .globl mem88 +mem88: + pushl %ebx + pushl %esi + pushl %edi + call _prot_to_real + .code16 + + movb $0x88, %ah + int $0x15 + andl $0xffff, %eax + + data32 call _real_to_prot + .code32 + + /* Restore Everything */ + popl %edi + popl %esi + popl %ebx + ret + + +/************************************************************************** +BASEMEMSIZE - Get size of the conventional (base) memory +**************************************************************************/ + .globl basememsize +basememsize: + call _prot_to_real + .code16 + int $0x12 + movw %ax,%cx + DATA32 call _real_to_prot + .code32 + movw %cx,%ax + ret + +/************************************************************************** +_REAL_TO_PROT - Go from REAL mode to Protected Mode +**************************************************************************/ + .globl _real_to_prot +_real_to_prot: + .code16 + cli + cs + addr32 lgdt gdt_48 - RELOC + movl %cr0,%eax + orl $CR0_PE,%eax + movl %eax,%cr0 /* turn on protected mode */ + + /* flush prefetch queue, and reload %cs:%eip */ + data32 ljmp $KERN_CODE_SEG,$1f +1: + .code32 + /* reload other segment registers */ + movl $KERN_DATA_SEG,%eax + movl %eax,%ds + movl %eax,%es + movl %eax,%ss + addl $RELOC,%esp /* Fix up stack pointer */ + xorl %eax,%eax + movl %eax,%fs + movl %eax,%gs + popl %eax /* Fix up return address */ + addl $RELOC,%eax + pushl %eax + + /* switch to protected mode idt */ + cs + lidt idt_48 + ret + +/************************************************************************** +_PROT_TO_REAL - Go from Protected Mode to REAL Mode +**************************************************************************/ + .globl _prot_to_real +_prot_to_real: + .code32 + popl %eax + subl $RELOC,%eax /* Adjust return address */ + pushl %eax + subl $RELOC,%esp /* Adjust stack pointer */ + ljmp $REAL_CODE_SEG,$1f- RELOC /* jump to a 16 bit segment */ +1: + .code16 + /* clear the PE bit of CR0 */ + movl %cr0,%eax + andl $0!CR0_PE,%eax + movl %eax,%cr0 + + /* make intersegment jmp to flush the processor pipeline + * and reload %cs:%eip (to clear upper 16 bits of %eip). + */ + data32 ljmp $(RELOC)>>4,$2f- RELOC +2: + /* we are in real mode now + * set up the real mode segment registers : %ds, $ss, %es + */ + movw %cs,%ax + movw %ax,%ds + movw %ax,%es + movw %ax,%ss + movw %ax,%fs + movw %ax,%gs + + /* Switch to the real mode idt */ + cs + addr32 lidt idt_real - RELOC + + sti + data32 ret /* There is a 32 bit return address on the stack */ + .code32 + +idt_real: + .word 0x400 # idt limit = 256 + .word 0, 0 +idt_48: + .word 0 # idt limit = 0 + .word 0, 0 # idt base = 0L +gdt_48: + .word 0x28 # gdt limit=40, + # (5 GDT entries) + .long gdt # gdt base + +# Descriptor tables +# These need to be in a seperate section so I can be +# certain later activities dont stomp them +.section .nokill, "awx", @progbits +gdt: + .word 0, 0, 0, 0 # dummy + + /* 16 bit real mode code segment */ + .word 0xffff,(RELOC&0xffff) + .byte (RELOC>>16),0x9b,0x00,(RELOC>>24) + + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9A00 # code read/exec + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) + + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9200 # data read/write + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) + + /* 16 bit real mode data segment */ + .word 0xffff,(RELOC&0xffff) + .byte (RELOC>>16),0x93,0x00,(RELOC>>24) + + diff --git a/util/mkelfImage/elf32-i386/linuxbios_tables.h b/util/mkelfImage/elf32-i386/linuxbios_tables.h new file mode 100644 index 0000000000..c324cf543a --- /dev/null +++ b/util/mkelfImage/elf32-i386/linuxbios_tables.h @@ -0,0 +1,82 @@ +#ifndef LINUXBIOS_TABLES_H +#define LINUXBIOS_TABLES_H + +#include + +/* The linuxbios table information is for conveying information + * from the firmware to the loaded OS image. Primarily this + * is expected to be information that cannot be discovered by + * other means, such as quering the hardware directly. + * + * All of the information should be Position Independent Data. + * That is it should be safe to relocated any of the information + * without it's meaning/correctnes changing. For table that + * can reasonably be used on multiple architectures the data + * size should be fixed. This should ease the transition between + * 32 bit and 64 bit architectures etc. + * + * The completeness test for the information in this table is: + * - Can all of the hardware be detected? + * - Are the per motherboard constants available? + * - Is there enough to allow a kernel to run that was written before + * a particular motherboard is constructed? (Assuming the kernel + * has drivers for all of the hardware but it does not have + * assumptions on how the hardware is connected together). + * + * With this test it should be straight forward to determine if a + * table entry is required or not. This should remove much of the + * long term compatibility burden as table entries which are + * irrelevant or have been replaced by better alternatives may be + * dropped. Of course it is polite and expidite to include extra + * table entries and be backwards compatible, but it is not required. + */ + + +struct lb_header +{ + uint8_t signature[4]; /* LBIO */ + uint32_t header_bytes; + uint32_t header_checksum; + uint32_t table_bytes; + uint32_t table_checksum; + uint32_t table_entries; +}; + +/* Every entry in the boot enviroment list will correspond to a boot + * info record. Encoding both type and size. The type is obviously + * so you can tell what it is. The size allows you to skip that + * boot enviroment record if you don't know what it easy. This allows + * forward compatibility with records not yet defined. + */ +struct lb_record { + uint32_t tag; /* tag ID */ + uint32_t size; /* size of record (in bytes) */ +}; + +#define LB_TAG_UNUSED 0x0000 + +#define LB_TAG_MEMORY 0x0001 + +struct lb_memory_range { + uint64_t start; + uint64_t size; + uint32_t type; +#define LB_MEM_RAM 1 +#define LB_MEM_RESERVED 2 + +}; + +struct lb_memory { + uint32_t tag; + uint32_t size; + struct lb_memory_range map[0]; +}; + +#define LB_TAG_HWRPB 0x0002 +struct lb_hwrpb { + uint32_t tag; + uint32_t size; + uint64_t hwrpb; +}; + +#endif /* LINUXBIOS_TABLES_H */ diff --git a/util/mkelfImage/elf32-i386/uniform_boot.h b/util/mkelfImage/elf32-i386/uniform_boot.h new file mode 100644 index 0000000000..5291fa66bb --- /dev/null +++ b/util/mkelfImage/elf32-i386/uniform_boot.h @@ -0,0 +1,67 @@ +#ifndef _LINUX_UNIFORM_BOOT_H +#define _LINUX_UNIFORM_BOOT_H + +/* The uniform boot environment information is restricted to + * hardware information. In particular for a simple enough machine + * all of the environment information should be able to reside in + * a rom and not need to be moved. This information is the + * information a trivial boot room can pass to linux to let it + * run the hardware. + * + * Also all of the information should be Position Independent Data. + * That is it should be safe to relocated any of the information + * without it's meaning/correctnes changing. The exception is the + * uniform_boot_header with it's two pointers arg & env. + * + * The addresses in the arg & env pointers must be physical + * addresses. A physical address is an address you put in the page + * table. + * + * The Command line is for user policy. Things like the default + * root device. + * + */ + +struct uniform_boot_header +{ + unsigned long header_bytes; + unsigned long header_checksum; + unsigned long arg; + unsigned long arg_bytes; + unsigned long env; + unsigned long env_bytes; +}; + +/* Every entry in the boot enviroment list will correspond to a boot + * info record. Encoding both type and size. The type is obviously + * so you can tell what it is. The size allows you to skip that + * boot enviroment record if you don't know what it easy. This allows + * forward compatibility with records not yet defined. + */ +struct ube_record { + unsigned long tag; /* tag ID */ + unsigned long size; /* size of record (in bytes) */ + unsigned long data[0]; /* data */ +}; + + +#define UBE_TAG_MEMORY 0x0001 + +struct ube_memory_range { + unsigned long long start; + unsigned long long size; + unsigned long type; +#define UBE_MEM_RAM 1 +#define UBE_MEM_RESERVED 2 +#define UBE_MEM_ACPI 3 +#define UBE_MEM_NVS 4 + +}; + +struct ube_memory { + unsigned long tag; + unsigned long size; + struct ube_memory_range map[0]; +}; + +#endif /* _LINUX_UNIFORM_BOOT_H */ diff --git a/util/mkelfImage/mkelfImage.pl b/util/mkelfImage/mkelfImage.pl new file mode 100644 index 0000000000..6d490a7b42 --- /dev/null +++ b/util/mkelfImage/mkelfImage.pl @@ -0,0 +1,239 @@ +#!/usr/bin/perl -w +# +# This program is (C) 2000 by Eric Biederman +# + +use FileHandle; +use Getopt::Long; +use Cwd; + +my %params; +my $VERSION=""; +# Hardcoded parameters for now... +$params{OBJCOPY}="objcopy"; +$params{LD}="ld"; +$params{CC}="gcc"; +$params{CFLAGS}="-O2"; +$params{MYDATA}="."; +$params{PREFIX}=undef(); +# Parameters that get set... +$params{RAMDISK}=""; +$params{VMLINUX}="/usr/src/linux/vmlinux"; +$params{TARGET}="elfImage"; +$params{ROOT_DEV}='((0x3<<16)| 0)'; +$params{COMMAND_LINE}=''; +$params{OUTPUT_FORMAT}='elf32-i386'; +$params{INITRD_BASE}=0x00800000; # 8MB + + +sub compile_file +{ + my ($params, $src, $dst) = @_; + my ($options, $cmd); + $options = "-DDEFAULT_ROOT_DEV='((unsigned short)$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"; + } + $cmd = "$params->{CC} $params->{CFLAGS} $options -c $params->{PREFIX}/$src -o $dst"; + system($cmd); + die "$cmd\nrc = $?" unless ($? == 0); + return $dst; +} + +sub build_kernel_piggy +{ + my ($params, $section, $src, $dst) = @_; + my ($buffer, $elf_sig, $bootsector_sig); + + $fd_in = new FileHandle; + $fd_in->open("<$src") or die "Cannot open $src\n"; + $fd_in->read($buffer, 512) == 512 + or die "Error reading boot sector of $src"; + ($elf_sig, undef, $bootsector_sig) = unpack('a4a506v1', $buffer); + + if ($elf_sig eq "\x7FELF") { + # It's an elf image + # Assume the input file uses contiguous memory... + system("objcopy ${src} -O binary ${dst}.obj"); + die "rc = $?" unless ($? == 0); + } + elsif ($bootsector_sig == 0xAA55) { + # It's an x86 boot sector + # Pull out the kernel... + my ($setupsects, $flags, $syssize, $swapdev, + $ramsize, $vidmode, $rootdev); + (undef, $setupsects, $flags, $syssize, $swapdev, $ramsize, + $vidmode, $rootdev) = unpack('a497Cv6', $buffer); + my $fd_out = new FileHandle; + $fd_out->open(">${dst}.obj") or die "Cannot open ${dst}.obj"; + $fd_in->seek(512 + (512*$setupsects), 0); + while ($fd_in->read($buffer, 8192) > 0) { + $fd_out->print($buffer); + } + $fd_in->close(); + $fd_out->close(); + } + else { + die "Unkown kernel file type"; + } + + my $fd = new FileHandle; +$fd->open("| $params->{LD} -r -o ${dst} -T /dev/fd/0 -b binary ${dst}.obj"); +$fd->print( << "EOSCRIPT"); +OUTPUT_FORMAT($params->{OUTPUT_FORMAT}); +SECTIONS { + .$section : { + ${section}_data = . ; + *(*) + ${section}_data_end = . ; + } +} +EOSCRIPT + $fd->close(); + die "rc = $?" unless ($? == 0); + unlink("${dst}.obj"); + return $dst; +} + +sub build_ramdisk_piggy +{ +# Assumes input file uses continguos memory... + my ($params, $section, $src, $dst) = @_; + my $fd = new FileHandle; + if (defined($src) && ($src ne "")) { + system("cp ${src} ${dst}.obj"); + } + else { + # Now create the dummy file + $fd->open(">${dst}.obj") or die "${dst}.obj: $!"; + $fd->close(); + } +$fd->open("| $params->{LD} -r -o ${dst} -T /dev/fd/0 -b binary ${dst}.obj"); +$fd->print( << "EOSCRIPT"); +OUTPUT_FORMAT($params->{OUTPUT_FORMAT}); +SECTIONS { + .$section : { + ${section}_data = . ; + *(*) + ${section}_data_end = . ; + } +} +EOSCRIPT + $fd->close(); + die "rc = $?" unless ($? == 0); + unlink("${dst}.obj"); + return $dst; +} + +sub build_elf_image +{ + my ($params, $dst, @srcs) = @_; + my $lscript = "mkelfImage.lds"; + my $fd = new FileHandle; + $fd->open(">$lscript"); + $fd->print("initrd_base = $params->{INITRD_BASE};\n"); + $fd->close(); + my $script = "$params->{PREFIX}/elfImage.lds"; + my $cmd = "$params->{LD} -o ${dst} -T $script " . join(" ", @srcs); + system("$cmd"); + die "rc = $?" unless ($? == 0); + unlink("${dst}.obj",$lscript); + return $dst; +} + +sub build +{ + my ($params) = @_; + my @objects; + my $tempdir=getcwd(); + + $params->{PREFIX} = "$params->{MYDATA}/$params->{OUTPUT_FORMAT}"; + push(@objects,build_kernel_piggy($params, "kernel", + $params->{VMLINUX}, "$tempdir/kernel_piggy_$$.o")); + + push(@objects, build_ramdisk_piggy($params, "ramdisk", + $params->{RAMDISK}, "$tempdir/ramdisk_piggy_$$.o")); + + push(@objects, compile_file($params, "convert_params.c", + "$tempdir/convert_params_$$.o")); + push(@objects, compile_file($params, "head.S", + "$tempdir/head_$$.o")); + build_elf_image($params, $params->{TARGET}, @objects); + unlink(@objects); + +} + +sub main +{ + my ($params) = @_; + my $wantversion; + GetOptions('command-line=s' => \$params->{COMMAND_LINE}, + 'ramdisk=s' => \$params->{RAMDISK}, + 'vmlinux=s' => \$params->{VMLINUX}, + 'kernel=s' => \$params->{VMLINUX}, + 'root-dev=s' => \$params->{ROOT_DEV}, + '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"; + exit(0); + } + build($params); +} + +main(\%params, @ARGV); + +__END__ + +=head1 NAME + +mkelfImage - make an elf network bootable image for linux + +=head1 SYNOPSIS + +B [--command-line=I] [--kernel=I] [--ramdisk=I] [--output=I] [--ramdisk-base=] + +=head1 DESCRIPTION + +B is a program that makes a elf boot image for linux kernel +images. The image should work with any i386 multiboot compliant boot loader, +an ELF bootloader that passes no options, a loader compliant with the linuxBIOS +elf booting spec or with the linux kexec kernel patch. A key feature +here is that nothing relies upon BIOS, but they are made when +necessary useful for systems running linuxbios. + +=head1 BUGS + +Not all kernel parameters can be passed with the multiboot image format. +ip configuration is not automatically passed to a node. +The ramdisk base is hard coded to 8MB by default. + +=head1 SEE ALSO + +The exec kernel patch. +LinusBIOS. +etherboot. +The multiboot standard. + +=head1 COPYRIGHT + +mkelfImage is under the GNU Public License version 2 + +=head1 AUTHOR + +Eric Biederman +