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
This commit is contained in:
Eric W. Biederman 2002-01-08 07:04:35 +00:00
parent d9db3cd6c4
commit 9cda94e6d2
32 changed files with 3383 additions and 117 deletions

View file

@ -1 +1,2 @@
object boot.o
object linuxbios_table.o

View file

@ -1,86 +1,59 @@
#include <boot/uniform_boot.h>
#include <ip_checksum.h>
#include <boot/elf.h>
#include <boot/elf_boot.h>
#include <string.h>
#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));
}

View file

@ -0,0 +1,177 @@
#include <ip_checksum.h>
#include <boot/linuxbios_tables.h>
#include <boot/linuxbios_table.h>
#include <printk.h>
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;
}

View file

@ -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 */

View file

@ -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

View file

@ -57,6 +57,7 @@ static char rcsid[] = "$Id$";
#include <arch/ioapic.h>
#include <smp/atomic.h>
#include <arch/smp/mpspec.h>
#include <boot/linuxbios_table.h>
/* 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");

View file

@ -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;
}

View file

@ -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)

View file

@ -1 +0,0 @@
object uniform_boot.o

View file

@ -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 */

View file

@ -0,0 +1,89 @@
#ifndef ELF_BOOT_H
#define ELF_BOOT_H
#include <stdint.h>
/* 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 */

View file

@ -0,0 +1,23 @@
#ifndef LINUXBIOS_TABLE_H
#define LINUXBIOS_TABLE_H
#include <boot/linuxbios_tables.h>
/* 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 */

View file

@ -0,0 +1,83 @@
#ifndef LINUXBIOS_TABLES_H
#define LINUXBIOS_TABLES_H
#include <stdint.h>
/* 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 */

View file

@ -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 */

View file

@ -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

View file

@ -0,0 +1,20 @@
#include <ip_checksum.h>
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;
}

View file

@ -2,7 +2,7 @@
#include <printk.h>
#include <part/fallback_boot.h>
#include <boot/elf.h>
#include <boot/uniform_boot.h>
#include <boot/elf_boot.h>
#include <rom/read_bytes.h>
#include <string.h>
#include <subr.h>
@ -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");

View file

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

View file

@ -2,7 +2,7 @@
#include <string.h>
#include <printk.h>
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);
}

View file

@ -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

View file

@ -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) {

View file

@ -2,7 +2,7 @@
#include <string.h>
#include <printk.h>
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);
}

View file

@ -3,7 +3,7 @@
#include <printk.h>
#include <cpu/p6/apic.h>
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);
}

341
util/mkelfImage/COPYING Normal file
View file

@ -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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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.
<signature of Ty Coon>, 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.

41
util/mkelfImage/Makefile Normal file
View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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) }
}

View file

@ -0,0 +1,83 @@
#ifndef ELF_BOOT_H
#define ELF_BOOT_H
#include <stdint.h>
/* 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 */

View file

@ -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)

View file

@ -0,0 +1,82 @@
#ifndef LINUXBIOS_TABLES_H
#define LINUXBIOS_TABLES_H
#include <stdint.h>
/* 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 */

View file

@ -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 */

View file

@ -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<mkelfImage> [--command-line=I<command line>] [--kernel=I<path to vmlinux>] [--ramdisk=I<path to ramdisk>] [--output=I<file>] [--ramdisk-base=<start addr>]
=head1 DESCRIPTION
B<mkelfImage> 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 <ebiederman@lnxi.com>