aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@linux.intel.com>2011-06-27 12:19:32 +0100
committerMatt Fleming <matt.fleming@linux.intel.com>2011-07-28 12:22:32 +0100
commita2821f29fdf972f73f1ff208311704422c7f3386 (patch)
tree7830771eb349eac68d6283a95c18db78e9f906a8
parentd070f3d778064e5d128954b81c2afb2dce7cbb8d (diff)
downloadefilinux-a2821f29fdf972f73f1ff208311704422c7f3386.tar.gz
efilinux: Add loader infrastructure and bzImage support
This patch provides the necessary glue to load binary files and transfer execution to them. Currently, we only support the Linux kernel bzImage format but other formats should be trivial to handle later. Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
-rw-r--r--Makefile10
-rw-r--r--efilinux.h4
-rw-r--r--entry.c8
-rw-r--r--loaders/bzimage/bzimage.c393
-rw-r--r--loaders/bzimage/bzimage.h177
-rw-r--r--loaders/bzimage/graphics.c179
-rw-r--r--loaders/bzimage/i386.h39
-rw-r--r--loaders/bzimage/x86_64.h58
-rw-r--r--loaders/loader.c35
-rw-r--r--loaders/loader.h46
10 files changed, 945 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 7a0bda6..1f81080 100644
--- a/Makefile
+++ b/Makefile
@@ -53,19 +53,23 @@ LDSCRIPT=$(LIBDIR)/gnuefi/elf_$(ARCH)_efi.lds
CFLAGS=-I. -I/usr/include/efi -I/usr/include/efi/$(ARCH) \
-DEFI_FUNCTION_WRAPPER -fPIC -fshort-wchar -ffreestanding \
- -Wall -Ifs/ -D$(ARCH)
+ -Wall -Ifs/ -Iloaders/ -D$(ARCH)
LDFLAGS=-T $(LDSCRIPT) -Bsymbolic -shared -nostdlib -L$(LIBDIR) $(CRT0)
IMAGE=efilinux.efi
OBJS = entry.o malloc.o
FS = fs/fs.o
+LOADERS = loaders/loader.o \
+ loaders/bzimage/bzimage.o \
+ loaders/bzimage/graphics.o
+
all: $(IMAGE)
efilinux.efi: efilinux.so
-efilinux.so: $(OBJS) $(FS)
+efilinux.so: $(OBJS) $(FS) $(LOADERS)
$(LD) $(LDFLAGS) -o $@ $^ -lgnuefi -lefi $(shell $(CC) -print-libgcc-file-name)
clean:
- rm -f $(IMAGE) efilinux.so $(OBJS) $(FS)
+ rm -f $(IMAGE) efilinux.so $(OBJS) $(FS) $(LOADERS)
diff --git a/efilinux.h b/efilinux.h
index 0571640..055a1bd 100644
--- a/efilinux.h
+++ b/efilinux.h
@@ -214,4 +214,8 @@ static inline const CHAR16 *memory_type_to_str(UINT32 type)
return memory_types[type];
}
+extern EFI_STATUS memory_map(EFI_MEMORY_DESCRIPTOR **map_buf,
+ UINTN *map_size, UINTN *map_key,
+ UINTN *desc_size, UINT32 *desc_version);
+
#endif /* __EFILINUX_H__ */
diff --git a/entry.c b/entry.c
index 9197bb1..0bc6a0f 100644
--- a/entry.c
+++ b/entry.c
@@ -36,6 +36,8 @@
#include "efilinux.h"
#include "fs.h"
#include "protocol.h"
+#include "loader.h"
+#include "stdlib.h"
#define ERROR_STRING_LENGTH 32
@@ -57,7 +59,7 @@ EFI_RUNTIME_SERVICES *runtime;
* to by @map_buf and @map_key, @desc_size and @desc_version are
* updated.
*/
-static EFI_STATUS
+EFI_STATUS
memory_map(EFI_MEMORY_DESCRIPTOR **map_buf, UINTN *map_size,
UINTN *map_key, UINTN *desc_size, UINT32 *desc_version)
{
@@ -289,6 +291,10 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *_table)
if (err != EFI_SUCCESS)
goto failed;
+ err = load_image(image, name, cmdline);
+ if (err != EFI_SUCCESS)
+ goto failed;
+
return EFI_SUCCESS;
failed:
diff --git a/loaders/bzimage/bzimage.c b/loaders/bzimage/bzimage.c
new file mode 100644
index 0000000..0b93611
--- /dev/null
+++ b/loaders/bzimage/bzimage.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+#include "efilinux.h"
+#include "bzimage.h"
+#include "fs.h"
+#include "loader.h"
+#include "protocol.h"
+#include "stdlib.h"
+
+#ifdef x86_64
+#include "x86_64.h"
+#else
+#include "i386.h"
+#endif
+
+dt_addr_t gdt = { 0x800, (UINT64 *)0 };
+dt_addr_t idt = { 0, 0 };
+
+/**
+ * load_kernel - Load a kernel image into memory from the boot device
+ */
+EFI_STATUS
+load_kernel(EFI_HANDLE image, CHAR16 *name, char *cmdline)
+{
+ UINTN map_size, _map_size, map_key;
+ EFI_PHYSICAL_ADDRESS kernel_start;
+ struct boot_params *boot_params;
+ EFI_MEMORY_DESCRIPTOR *map_buf;
+ struct e820_entry *e820_map;
+ struct boot_params *buf;
+ struct efi_info *efi;
+ UINT32 desc_version;
+ UINT8 nr_setup_secs;
+ struct file *file;
+ UINTN desc_size;
+ EFI_STATUS err;
+ UINTN size = 0;
+ char *initrd;
+ int i;
+
+ err = file_open(name, &file);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ err = file_set_position(file, (UINT64)0x1F1);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ size = 1;
+ err = file_read(file, &size, &nr_setup_secs);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ nr_setup_secs++; /* Add the boot sector */
+ size = nr_setup_secs * 512;
+
+ buf = malloc(size);
+ if (!buf)
+ goto out;
+
+ err = file_set_position(file, (UINT64)0);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ err = file_read(file, &size, buf);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ /* Check boot sector signature */
+ if (buf->hdr.signature != 0xAA55) {
+ Print(L"bzImage kernel corrupt");
+ err = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (buf->hdr.header != SETUP_HDR) {
+ Print(L"Setup code version is invalid");
+ err = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /*
+ * Which setup code version?
+ *
+ * We only support relocatable kernels which require a setup
+ * code version >= 2.05.
+ */
+ if (buf->hdr.version < 0x205) {
+ Print(L"Setup code version unsupported (too old)");
+ err = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /* Don't need an allocated ID, we're a prototype */
+ buf->hdr.loader_id = 0x1;
+
+ /*
+ * Has there been an initrd specified on the cmdline?
+ */
+ initrd = strstr(cmdline, "initrd");
+ if (initrd) {
+ initrd += strlen("initrd");
+
+ /* Make sure the initrd string is valid */
+ if (*initrd++ == '=') {
+ CHAR16 filename[MAX_FILENAME], *n;
+ struct file *file;
+ char *o, *p;
+ UINT64 size;
+ void *rd;
+
+ p = initrd;
+ while (*p && *p != ' ')
+ p++;
+
+ for (o = initrd, n = filename; o != p; o++, n++)
+ *n = *o;
+
+ *n = '\0';
+ err = file_open(filename, &file);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ file_size(file, &size);
+ err = emalloc(size, 1, (EFI_PHYSICAL_ADDRESS *)&rd);
+ if (err != EFI_SUCCESS) {
+ file_close(file);
+ goto out;
+ }
+
+ if ((UINT32)(UINT64)rd > buf->hdr.ramdisk_max) {
+ Print(L"ramdisk address is too high!\n");
+ efree((EFI_PHYSICAL_ADDRESS)rd, size);
+ file_close(file);
+ goto out;
+ }
+
+ err = file_read(file, &size, rd);
+ file_close(file);
+
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ buf->hdr.ramdisk_start = (UINT32)(UINT64)rd;
+ buf->hdr.ramdisk_len = size;
+ }
+ } else {
+ buf->hdr.ramdisk_start = 0;
+ buf->hdr.ramdisk_len = 0;
+ }
+
+ buf->hdr.cmd_line_ptr = (UINT32)(UINT64)cmdline;
+ buf->hdr.cmdline_size = strlen(cmdline);
+
+ memset((char *)&buf->screen_info, 0x0, sizeof(buf->screen_info));
+
+ err = setup_graphics(buf);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ /*
+ * Time to allocate our memory.
+ *
+ * Because the kernel needs to decompress itself we first
+ * allocate boot_params, gdt and space for the memory map
+ * under the assumption that they'll be allocated at lower
+ * addresses than the kernel. If we dont't allocate these data
+ * structures first there is the potential for them to be
+ * trashed when the kernel is decompressed! Allocating them
+ * underneath the kernel should be safe.
+ *
+ * Max kernel size is 8MB
+ */
+ err = emalloc(16384, 1, (EFI_PHYSICAL_ADDRESS *)&boot_params);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ memset((void *)boot_params, 0x0, 16384);
+
+ /* Copy first two sectors to boot_params */
+ memcpy((char *)boot_params, (char *)buf, 2 * 512);
+
+ err = emalloc(gdt.limit, 8, (EFI_PHYSICAL_ADDRESS *)&gdt.base);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ memset((char *)gdt.base, 0x0, gdt.limit);
+
+ /*
+ * 4Gb - (0x100000*0x1000 = 4Gb)
+ * base address=0
+ * code read/exec
+ * granularity=4096, 386 (+5th nibble of limit)
+ */
+ gdt.base[2] = 0x00cf9a000000ffff;
+
+ /*
+ * 4Gb - (0x100000*0x1000 = 4Gb)
+ * base address=0
+ * data read/write
+ * granularity=4096, 386 (+5th nibble of limit)
+ */
+ gdt.base[3] = 0x00cf92000000ffff;
+
+ /* Task segment value */
+ gdt.base[4] = 0x0080890000000000;
+
+ /*
+ * Free any memory that we will no longer need once we jump to
+ * the kernel entry point.
+ */
+ fs_exit();
+
+ /* We're just interested in the map's size for now */
+ map_size = 0;
+ err = get_memory_map(&map_size, NULL, NULL, NULL, NULL);
+ if (err != EFI_SUCCESS && err != EFI_BUFFER_TOO_SMALL)
+ goto out;
+
+again:
+ _map_size = map_size;
+ err = emalloc(map_size, 1, (EFI_PHYSICAL_ADDRESS *)&map_buf);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ size = 0x800000;
+ err = emalloc(size, buf->hdr.kernel_alignment, &kernel_start);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ /*
+ * If the firmware doesn't sort the memory map by increasing
+ * address it's possible that kernel_start may have been
+ * allocated below boot_params or gdt.base.
+ *
+ * Print a warning and hope for the best.
+ */
+ if (kernel_start < (EFI_PHYSICAL_ADDRESS)boot_params ||
+ kernel_start < (EFI_PHYSICAL_ADDRESS)map_buf ||
+ kernel_start < (EFI_PHYSICAL_ADDRESS)gdt.base)
+ Print(L"Warning: kernel_start is too low.\n");
+
+ /*
+ * Read the rest of the kernel image.
+ */
+ err = file_read(file, &size, (void *)kernel_start);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ boot_params->hdr.code32_start = (UINT32)((UINT64)kernel_start);
+
+ /*
+ * Remember! We've already allocated map_buf with emalloc (and
+ * 'map_size' contains its size) which means that it should be
+ * positioned below our allocation for the kernel. Use that
+ * space for the memory map.
+ */
+ err = get_memory_map(&map_size, map_buf, &map_key,
+ &desc_size, &desc_version);
+ if (err != EFI_SUCCESS) {
+ if (err == EFI_BUFFER_TOO_SMALL) {
+ /*
+ * Argh! The buffer that we allocated further
+ * up wasn't large enough which means we need
+ * to allocate them again, but this time
+ * larger. 'map_size' has been updated by the
+ * call to memory_map().
+ */
+ efree(kernel_start, 0x800000);
+ efree((EFI_PHYSICAL_ADDRESS)map_buf, _map_size);
+ file_set_position(file, (UINT64)nr_setup_secs * 512);
+ goto again;
+ }
+ goto out;
+ }
+
+ err = exit_boot_services(image, map_key);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ efi = &boot_params->efi_info;
+ efi->efi_systab = (UINT32)(UINT64)sys_table;
+ efi->efi_memdesc_size = desc_size;
+ efi->efi_memdesc_version = desc_version;
+ efi->efi_memmap = (UINT32)(UINT64)map_buf;
+ efi->efi_memmap_size = map_size;
+ efi->efi_systab_hi = (unsigned long)sys_table >> 32;
+ efi->efi_memmap_hi = (unsigned long)map_buf >> 32;
+
+ memcpy((char *)&efi->efi_loader_signature,
+ EFI_LOADER_SIGNATURE, sizeof(UINT32));
+
+ boot_params->alt_mem_k = 32 * 1024;
+
+ e820_map = &boot_params->e820_map[0];
+
+ /*
+ * Convert the EFI memory map to E820.
+ */
+ for (i = 0; i < map_size / desc_size; i++) {
+ EFI_MEMORY_DESCRIPTOR *d;
+ unsigned int e820_type = 0;
+
+ d = (EFI_MEMORY_DESCRIPTOR *)((unsigned long)map_buf + (i * desc_size));
+ switch(d->Type) {
+ case EfiReservedMemoryType:
+ case EfiRuntimeServicesData:
+ case EfiUnusableMemory:
+ case EfiMemoryMappedIO:
+ case EfiMemoryMappedIOPortSpace:
+ case EfiPalCode:
+ e820_type = E820_RESERVED;
+ break;
+
+ case EfiRuntimeServicesCode:
+ e820_type = E820_UNUSABLE;
+ break;
+
+ case EfiACPIReclaimMemory:
+ e820_type = E820_ACPI;
+ break;
+
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiConventionalMemory:
+ e820_type = E820_RAM;
+ break;
+
+ case EfiACPIMemoryNVS:
+ e820_type = E820_NVS;
+ break;
+
+ default:
+ Print(L"Invalid EFI memory descriptor type!\n");
+ continue;
+ }
+
+ e820_map->addr = d->PhysicalStart;
+ e820_map->size = d->NumberOfPages << EFI_PAGE_SHIFT;
+ e820_map->type = e820_type;
+ e820_map++;
+ }
+
+ boot_params->e820_entries = i;
+
+ asm volatile ("lidt %0" :: "m" (idt));
+ asm volatile ("lgdt %0" :: "m" (gdt));
+
+ kernel_jump(kernel_start, boot_params);
+
+ Print(L"Error: bzImage returned control to efilinux!");
+out:
+ return err;
+}
+
+struct loader bzimage_loader = {
+ load_kernel,
+};
diff --git a/loaders/bzimage/bzimage.h b/loaders/bzimage/bzimage.h
new file mode 100644
index 0000000..370d126
--- /dev/null
+++ b/loaders/bzimage/bzimage.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BZIMAGE_H__
+#define __BZIMAGE_H__
+
+#define BOOTSIG 0x1FE
+#define SETUP_VERSION 0x206
+#define SETUP_HDR 0x53726448 /* 0x53726448 == "HdrS" */
+
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_UNUSABLE 5
+
+struct setup_header {
+ UINT8 setup_secs; /* Sectors for setup code */
+ UINT16 root_flags;
+ UINT32 sys_size;
+ UINT16 ram_size;
+ UINT16 video_mode;
+ UINT16 root_dev;
+ UINT16 signature; /* Boot signature */
+ UINT16 jump;
+ UINT32 header;
+ UINT16 version;
+ UINT16 su_switch;
+ UINT16 setup_seg;
+ UINT16 start_sys;
+ UINT16 kernel_ver;
+ UINT8 loader_id;
+ UINT8 load_flags;
+ UINT16 movesize;
+ UINT32 code32_start; /* Start of code loaded high */
+ UINT32 ramdisk_start; /* Start of initial ramdisk */
+ UINT32 ramdisk_len; /* Lenght of initial ramdisk */
+ UINT32 bootsect_kludge;
+ UINT16 heap_end;
+ UINT8 ext_loader_ver; /* Extended boot loader version */
+ UINT8 ext_loader_type; /* Extended boot loader ID */
+ UINT32 cmd_line_ptr; /* 32-bit pointer to the kernel command line */
+ UINT32 ramdisk_max; /* Highest legal initrd address */
+ UINT32 kernel_alignment; /* Physical addr alignment required for kernel */
+ UINT8 relocatable_kernel; /* Whether kernel is relocatable or not */
+ UINT8 _pad2[3];
+ UINT32 cmdline_size;
+ UINT32 hardware_subarch;
+ UINT64 hardware_subarch_data;
+ UINT32 payload_offset;
+ UINT32 payload_length;
+ UINT64 setup_data;
+} __attribute__((packed));
+
+struct efi_info {
+ UINT32 efi_loader_signature;
+ UINT32 efi_systab;
+ UINT32 efi_memdesc_size;
+ UINT32 efi_memdesc_version;
+ UINT32 efi_memmap;
+ UINT32 efi_memmap_size;
+ UINT32 efi_systab_hi;
+ UINT32 efi_memmap_hi;
+};
+
+struct e820_entry {
+ UINT64 addr; /* start of memory segment */
+ UINT64 size; /* size of memory segment */
+ UINT32 type; /* type of memory segment */
+} __attribute__((packed));
+
+struct screen_info {
+ UINT8 orig_x; /* 0x00 */
+ UINT8 orig_y; /* 0x01 */
+ UINT16 ext_mem_k; /* 0x02 */
+ UINT16 orig_video_page; /* 0x04 */
+ UINT8 orig_video_mode; /* 0x06 */
+ UINT8 orig_video_cols; /* 0x07 */
+ UINT8 flags; /* 0x08 */
+ UINT8 unused2; /* 0x09 */
+ UINT16 orig_video_ega_bx;/* 0x0a */
+ UINT16 unused3; /* 0x0c */
+ UINT8 orig_video_lines; /* 0x0e */
+ UINT8 orig_video_isVGA; /* 0x0f */
+ UINT16 orig_video_points;/* 0x10 */
+
+ /* VESA graphic mode -- linear frame buffer */
+ UINT16 lfb_width; /* 0x12 */
+ UINT16 lfb_height; /* 0x14 */
+ UINT16 lfb_depth; /* 0x16 */
+ UINT32 lfb_base; /* 0x18 */
+ UINT32 lfb_size; /* 0x1c */
+ UINT16 cl_magic, cl_offset; /* 0x20 */
+ UINT16 lfb_linelength; /* 0x24 */
+ UINT8 red_size; /* 0x26 */
+ UINT8 red_pos; /* 0x27 */
+ UINT8 green_size; /* 0x28 */
+ UINT8 green_pos; /* 0x29 */
+ UINT8 blue_size; /* 0x2a */
+ UINT8 blue_pos; /* 0x2b */
+ UINT8 rsvd_size; /* 0x2c */
+ UINT8 rsvd_pos; /* 0x2d */
+ UINT16 vesapm_seg; /* 0x2e */
+ UINT16 vesapm_off; /* 0x30 */
+ UINT16 pages; /* 0x32 */
+ UINT16 vesa_attributes; /* 0x34 */
+ UINT32 capabilities; /* 0x36 */
+ UINT8 _reserved[6]; /* 0x3a */
+} __attribute__((packed));
+
+struct boot_params {
+ struct screen_info screen_info;
+ UINT8 apm_bios_info[0x14];
+ UINT8 _pad2[4];
+ UINT64 tboot_addr;
+ UINT8 ist_info[0x10];
+ UINT8 _pad3[16];
+ UINT8 hd0_info[16];
+ UINT8 hd1_info[16];
+ UINT8 sys_desc_table[0x10];
+ UINT8 olpc_ofw_header[0x10];
+ UINT8 _pad4[128];
+ UINT8 edid_info[0x80];
+ struct efi_info efi_info;
+ UINT32 alt_mem_k;
+ UINT32 scratch;
+ UINT8 e820_entries;
+ UINT8 eddbuf_entries;
+ UINT8 edd_mbr_sig_buf_entries;
+ UINT8 _pad6[6];
+ struct setup_header hdr;
+ UINT8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
+ UINT32 edd_mbr_sig_buffer[16];
+ struct e820_entry e820_map[128];
+ UINT8 _pad8[48];
+ UINT8 eddbuf[0x1ec];
+ UINT8 _pad9[276];
+};
+
+typedef struct {
+ UINT16 limit;
+ UINT64 *base;
+} __attribute__((packed)) dt_addr_t;
+
+extern EFI_STATUS setup_graphics(struct boot_params *buf);
+
+#endif /* __BZIMAGE_H__ */
diff --git a/loaders/bzimage/graphics.c b/loaders/bzimage/graphics.c
new file mode 100644
index 0000000..22a4d81
--- /dev/null
+++ b/loaders/bzimage/graphics.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <efi.h>
+#include <efilib.h>
+#include "efilinux.h"
+#include "bzimage.h"
+#include "protocol.h"
+#include "stdlib.h"
+
+static void find_bits(unsigned long mask, UINT8 *pos, UINT8 *size)
+{
+ UINT8 first, len;
+
+ first = 0;
+ len = 0;
+
+ if (mask) {
+ while (!(mask & 0x1)) {
+ mask = mask >> 1;
+ first++;
+ }
+
+ while (mask & 0x1) {
+ mask = mask >> 1;
+ len++;
+ }
+ }
+ *pos = first;
+ *size = len;
+}
+
+EFI_STATUS setup_graphics(struct boot_params *buf)
+{
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
+ EFI_GUID graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
+ EFI_HANDLE *gop_handle = NULL;
+ struct screen_info *si;
+ EFI_STATUS err;
+ UINTN nr_gops;
+ UINTN size;
+ int i;
+
+ /* See if we have graphics output protocol */
+ size = 0;
+ err = locate_handle(ByProtocol, &graphics_proto, NULL,
+ &size, (void **)gop_handle);
+ if (err != EFI_SUCCESS && err != EFI_BUFFER_TOO_SMALL)
+ goto out;
+
+ gop_handle = malloc(size);
+ if (!gop_handle)
+ goto out;
+
+ err = locate_handle(ByProtocol, &graphics_proto, NULL,
+ &size, (void **)gop_handle);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ nr_gops = size / sizeof(EFI_HANDLE);
+ for (i = 0; i < nr_gops; i++) {
+ EFI_HANDLE *h = &gop_handle[i];
+
+ err = handle_protocol(*h, &graphics_proto, (void **)&gop);
+ if (err != EFI_SUCCESS)
+ continue;
+
+ err = uefi_call_wrapper(gop->QueryMode, 4, gop,
+ gop->Mode->Mode, &size, &info);
+ if (err == EFI_SUCCESS)
+ break;
+ }
+
+ /* We found a GOP */
+ if (i != nr_gops) {
+ si = &buf->screen_info;
+
+ /* EFI framebuffer */
+ si->orig_video_isVGA = 0x70;
+
+ si->orig_x = 0;
+ si->orig_y = 0;
+ si->orig_video_page = 0;
+ si->orig_video_mode = 0;
+ si->orig_video_cols = 0;
+ si->orig_video_lines = 0;
+ si->orig_video_ega_bx = 0;
+ si->orig_video_points = 0;
+
+ si->lfb_base = gop->Mode->FrameBufferBase;
+ si->lfb_size = gop->Mode->FrameBufferSize;
+ si->lfb_width = info->HorizontalResolution;
+ si->lfb_height = info->VerticalResolution;
+ si->pages = 1;
+ si->vesapm_seg = 0;
+ si->vesapm_off = 0;
+
+ if (info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
+ si->lfb_depth = 32;
+ si->red_size = 8;
+ si->red_pos = 0;
+ si->green_size = 8;
+ si->green_pos = 8;
+ si->blue_size = 8;
+ si->blue_pos = 16;
+ si->rsvd_size = 8;
+ si->rsvd_pos = 24;
+ si->lfb_linelength = info->PixelsPerScanLine * 4;
+
+ } else if (info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
+ si->lfb_depth = 32;
+ si->red_size = 8;
+ si->red_pos = 16;
+ si->green_size = 8;
+ si->green_pos = 8;
+ si->blue_size = 8;
+ si->blue_pos = 0;
+ si->rsvd_size = 8;
+ si->rsvd_pos = 24;
+ si->lfb_linelength = info->PixelsPerScanLine * 4;
+ } else if (info->PixelFormat == PixelBitMask) {
+ find_bits(info->PixelInformation.RedMask,
+ &si->red_pos, &si->red_size);
+ find_bits(info->PixelInformation.GreenMask,
+ &si->green_pos, &si->green_size);
+ find_bits(info->PixelInformation.BlueMask,
+ &si->blue_pos, &si->blue_size);
+ find_bits(info->PixelInformation.ReservedMask,
+ &si->rsvd_pos, &si->rsvd_size);
+ si->lfb_depth = si->red_size + si->green_size +
+ si->blue_size + si->rsvd_size;
+ si->lfb_linelength = (info->PixelsPerScanLine * si->lfb_depth) / 8;
+ } else {
+ si->lfb_depth = 4;
+ si->red_size = 0;
+ si->red_pos = 0;
+ si->green_size = 0;
+ si->green_pos = 0;
+ si->blue_size = 0;
+ si->blue_pos = 0;
+ si->rsvd_size = 0;
+ si->rsvd_pos = 0;
+ si->lfb_linelength = si->lfb_width / 2;
+ }
+ }
+
+out:
+ return err;
+}
diff --git a/loaders/bzimage/i386.h b/loaders/bzimage/i386.h
new file mode 100644
index 0000000..367f426
--- /dev/null
+++ b/loaders/bzimage/i386.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __I386_H__
+#define __I386_H__
+
+#define EFI_LOADER_SIGNATURE "EL32"
+
+#endif /* __I386_H__ */
diff --git a/loaders/bzimage/x86_64.h b/loaders/bzimage/x86_64.h
new file mode 100644
index 0000000..e3e7a33
--- /dev/null
+++ b/loaders/bzimage/x86_64.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __X86_64_H__
+#define __X86_64_H__
+
+#define EFI_LOADER_SIGNATURE "EL64"
+
+typedef void(*kernel_func)(void *, struct boot_params *);
+
+static inline void kernel_jump(EFI_PHYSICAL_ADDRESS kernel_start,
+ struct boot_params *boot_params)
+{
+ kernel_func kf;
+
+ asm volatile ("cli");
+
+ /* The 64-bit kernel entry is 512 bytes after the start. */
+ kf = (kernel_func)kernel_start + 512;
+
+ /*
+ * The first parameter is a dummy because the kernel expects
+ * boot_params in %[re]si.
+ */
+ kf(NULL, boot_params);
+}
+
+#endif /* __X86_64_H__ */
diff --git a/loaders/loader.c b/loaders/loader.c
new file mode 100644
index 0000000..6a0e677
--- /dev/null
+++ b/loaders/loader.c
@@ -0,0 +1,35 @@
+#include <efi.h>
+#include "loader.h"
+
+extern struct loader bzimage_loader;
+
+struct loader *loaders[] = {
+ &bzimage_loader,
+ NULL,
+};
+
+/**
+ * load_image - Attempt to load a new image
+ * @handle: firmware-allocated handle that identifies the efilinux image
+ * @name: filename of the new image to load
+ * @cmdline: ascii command-line argument
+ *
+ * Try all of the registered loaders to see if any of them want to
+ * load @name. If a loader successfully loads @name, it may not return
+ * control to load_image(), for example see the bzImage loader.
+ */
+EFI_STATUS
+load_image(EFI_HANDLE handle, CHAR16 *name, char *cmdline)
+{
+ struct loader **loader;
+ EFI_STATUS err;
+
+ err = EFI_UNSUPPORTED;
+ for (loader = loaders; *loader != NULL; loader++) {
+ err = (*loader)->load(handle, name, cmdline);
+ if (err == EFI_SUCCESS)
+ break;
+ }
+
+ return err;
+}
diff --git a/loaders/loader.h b/loaders/loader.h
new file mode 100644
index 0000000..2a3d271
--- /dev/null
+++ b/loaders/loader.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __LOADER_H__
+#define __LOADER_H__
+
+struct loader {
+ EFI_STATUS (*load)(EFI_HANDLE, CHAR16 *, char *);
+};
+
+extern struct loader *loaders[];
+
+extern EFI_STATUS load_image(EFI_HANDLE image, CHAR16 *name, char *cmdline);
+
+#endif /* __LOADER_H__ */