aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-01-27 21:35:02 +0000
committerMatt Fleming <matt.fleming@intel.com>2012-02-02 16:24:08 +0000
commitdb7dfa4c8eac192fa3e91a94b47cc324d698715b (patch)
tree0bb74b28725c44a5a4d5a0ba7b59c3e98977012d
parent6414cda12d09d39b894e5d7f5af20fa71bfb9e04 (diff)
downloadsyslinux-db7dfa4c8eac192fa3e91a94b47cc324d698715b.tar.gz
syslinux-db7dfa4c8eac192fa3e91a94b47cc324d698715b.tar.xz
syslinux-db7dfa4c8eac192fa3e91a94b47cc324d698715b.zip
firmware: Add EFI linux boot support
Add .boot_linux to 'struct firmware', we do quite a lot of things differently for BIOS and EFI. For EFI we don't need the movelist code because we have little control over the memory map, and so can't guarantee we can place code/data at specific addresses. Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--com32/include/syslinux/firmware.h1
-rw-r--r--com32/include/syslinux/linux.h39
-rw-r--r--com32/lib/syslinux/load_linux.c11
-rw-r--r--core/bios.c3
-rw-r--r--efi/console.c169
-rw-r--r--efi/efi.h2
-rw-r--r--efi/main.c385
7 files changed, 608 insertions, 2 deletions
diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h
index 3877d624..e23a1b3d 100644
--- a/com32/include/syslinux/firmware.h
+++ b/com32/include/syslinux/firmware.h
@@ -36,6 +36,7 @@ struct firmware {
void (*get_serial_console_info)(uint16_t *, uint16_t *, uint16_t *);
bool (*ipappend_strings)(char **, int *);
struct adv_ops *adv_ops;
+ int (*boot_linux)(void *, size_t, struct initramfs *, char *);
};
extern struct firmware *firmware;
diff --git a/com32/include/syslinux/linux.h b/com32/include/syslinux/linux.h
index cf28762d..abc71dc1 100644
--- a/com32/include/syslinux/linux.h
+++ b/com32/include/syslinux/linux.h
@@ -94,6 +94,45 @@ struct linux_header {
uint32_t init_size;
} __packed;
+struct screen_info {
+ uint8_t orig_x; /* 0x00 */
+ uint8_t orig_y; /* 0x01 */
+ uint16_t ext_mem_k; /* 0x02 */
+ uint16_t orig_video_page; /* 0x04 */
+ uint8_t orig_video_mode; /* 0x06 */
+ uint8_t orig_video_cols; /* 0x07 */
+ uint8_t flags; /* 0x08 */
+ uint8_t unused2; /* 0x09 */
+ uint16_t orig_video_ega_bx;/* 0x0a */
+ uint16_t unused3; /* 0x0c */
+ uint8_t orig_video_lines; /* 0x0e */
+ uint8_t orig_video_isVGA; /* 0x0f */
+ uint16_t orig_video_points;/* 0x10 */
+
+ /* VESA graphic mode -- linear frame buffer */
+ uint16_t lfb_width; /* 0x12 */
+ uint16_t lfb_height; /* 0x14 */
+ uint16_t lfb_depth; /* 0x16 */
+ uint32_t lfb_base; /* 0x18 */
+ uint32_t lfb_size; /* 0x1c */
+ uint16_t cl_magic, cl_offset; /* 0x20 */
+ uint16_t lfb_linelength; /* 0x24 */
+ uint8_t red_size; /* 0x26 */
+ uint8_t red_pos; /* 0x27 */
+ uint8_t green_size; /* 0x28 */
+ uint8_t green_pos; /* 0x29 */
+ uint8_t blue_size; /* 0x2a */
+ uint8_t blue_pos; /* 0x2b */
+ uint8_t rsvd_size; /* 0x2c */
+ uint8_t rsvd_pos; /* 0x2d */
+ uint16_t vesapm_seg; /* 0x2e */
+ uint16_t vesapm_off; /* 0x30 */
+ uint16_t pages; /* 0x32 */
+ uint16_t vesa_attributes; /* 0x34 */
+ uint32_t capabilities; /* 0x36 */
+ uint8_t _reserved[6]; /* 0x3a */
+} __packed;
+
int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
struct initramfs *initramfs, char *cmdline);
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index 8d4f7175..86ea862a 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -43,6 +43,7 @@
#include <syslinux/linux.h>
#include <syslinux/bootrm.h>
#include <syslinux/movebits.h>
+#include <syslinux/firmware.h>
#ifndef DEBUG
# define DEBUG 0
@@ -129,8 +130,8 @@ static int map_initramfs(struct syslinux_movelist **fraglist,
return 0;
}
-int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline)
+int bios_boot_linux(void *kernel_buf, size_t kernel_size,
+ struct initramfs *initramfs, char *cmdline)
{
struct linux_header hdr, *whdr;
size_t real_mode_size, prot_mode_size;
@@ -428,3 +429,9 @@ bail:
syslinux_free_memmap(amap);
return -1;
}
+
+int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
+ struct initramfs *initramfs, char *cmdline)
+{
+ firmware->boot_linux(kernel_buf, kernel_size, initramfs, cmdline);
+}
diff --git a/core/bios.c b/core/bios.c
index 447268d6..9e341467 100644
--- a/core/bios.c
+++ b/core/bios.c
@@ -93,6 +93,8 @@ struct adv_ops bios_adv_ops = {
.write = bios_adv_write,
};
+extern int bios_boot_linux(void *, size_t, struct initramfs *, char *);
+
struct firmware bios_fw = {
.init = bios_init,
.scan_memory = bios_scan_memory,
@@ -105,6 +107,7 @@ struct firmware bios_fw = {
.get_config_file_name = bios_get_config_file_name,
.get_serial_console_info = bios_get_serial_console_info,
.adv_ops = &bios_adv_ops,
+ .boot_linux = bios_boot_linux,
};
void syslinux_register_bios(void)
diff --git a/efi/console.c b/efi/console.c
index baca9733..1e475b17 100644
--- a/efi/console.c
+++ b/efi/console.c
@@ -1,6 +1,175 @@
+#include <syslinux/linux.h>
#include "efi.h"
+extern EFI_GUID GraphicsOutputProtocol;
+
void writechr(char data)
{
Print(L"Wanted to print something\n");
}
+
+static inline EFI_STATUS open_protocol(EFI_HANDLE handle, EFI_GUID *protocol,
+ void **interface, EFI_HANDLE agent,
+ EFI_HANDLE controller, UINT32 attributes)
+{
+ return uefi_call_wrapper(BS->OpenProtocol, 6, handle, protocol,
+ interface, agent, controller, attributes);
+}
+
+static inline EFI_STATUS
+gop_query_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, UINTN *size,
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **info)
+{
+ return uefi_call_wrapper(gop->QueryMode, 4, gop,
+ gop->Mode->Mode, size, info);
+}
+
+static inline void bit_mask(uint32_t mask, uint8_t *pos, uint8_t *size)
+{
+ *pos = 0;
+ *size = 0;
+
+ if (mask) {
+ while (!(mask & 0x1)) {
+ mask >>= 1;
+ (*pos)++;
+ }
+
+ while (mask & 0x1) {
+ mask >>= 1;
+ (*size)++;
+ }
+ }
+}
+
+void setup_screen(struct screen_info *si)
+{
+ EFI_HANDLE *handles = NULL;
+ EFI_STATUS status;
+ UINTN nr_handles;
+ UINTN size;
+ uint16_t lfb_width, lfb_height;
+ uint32_t lfb_base, lfb_size;
+ int i;
+
+ status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
+ NULL, &nr_handles, &handles);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, *found;
+ EFI_GRAPHICS_PIXEL_FORMAT pixel_fmt;
+ EFI_PIXEL_BITMASK pixel_info;
+ uint32_t pixel_scanline;
+
+ handles = AllocatePool(nr_handles);
+ if (!handles)
+ return;
+
+ status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
+ NULL, &nr_handles, &handles);
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ found = NULL;
+ for (i = 0; i < (nr_handles / sizeof(EFI_HANDLE)); i++) {
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
+ EFI_PCI_IO *pciio = NULL;
+ EFI_HANDLE *h = handles[i];
+
+ status = open_protocol(h, &GraphicsOutputProtocol,
+ (void **)&gop,
+ image_handle, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ status = open_protocol(h, &PciIoProtocol,
+ (void **)&pciio,
+ image_handle, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ status = gop_query_mode(gop, &size, &info);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ if (!pciio && found)
+ continue;
+ found = gop;
+
+ lfb_width = info->HorizontalResolution;
+ lfb_height = info->VerticalResolution;
+ lfb_base = gop->Mode->FrameBufferBase;
+ lfb_size = gop->Mode->FrameBufferSize;
+ pixel_fmt = info->PixelFormat;
+ pixel_info = info->PixelInformation;
+ pixel_scanline = info->PixelsPerScanLine;
+
+ if (pciio)
+ break;
+ }
+
+ if (!found)
+ goto out;
+
+ si->orig_video_isVGA = 0x70; /* EFI framebuffer */
+
+ si->lfb_base = lfb_base;
+ si->lfb_size = lfb_size;
+ si->lfb_width = lfb_width;
+ si->lfb_height = lfb_height;
+ si->pages = 1;
+
+ switch (pixel_fmt) {
+ case PixelRedGreenBlueReserved8BitPerColor:
+ si->lfb_depth = 32;
+ si->lfb_linelength = pixel_scanline * 4;
+ 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;
+ break;
+ case PixelBlueGreenRedReserved8BitPerColor:
+ si->lfb_depth = 32;
+ si->lfb_linelength = pixel_scanline * 4;
+ 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;
+ break;
+ case PixelBitMask:
+ bit_mask(pixel_info.RedMask, &si->red_pos,
+ &si->red_size);
+ bit_mask(pixel_info.GreenMask, &si->green_pos,
+ &si->green_size);
+ bit_mask(pixel_info.BlueMask, &si->blue_pos,
+ &si->blue_size);
+ bit_mask(pixel_info.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 = (pixel_scanline * si->lfb_depth) / 8;
+ break;
+ default:
+ si->lfb_depth = 4;;
+ si->lfb_linelength = si->lfb_width / 2;
+ 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;
+ break;
+ }
+ }
+
+out:
+ FreePool(handles);
+}
diff --git a/efi/efi.h b/efi/efi.h
index 7e53fb2a..ed3fe8a3 100644
--- a/efi/efi.h
+++ b/efi/efi.h
@@ -8,4 +8,6 @@
#include <efilib.h>
#include <efistdarg.h>
+extern EFI_HANDLE image_handle;
+
#endif /* _SYSLINUX_EFI_H */
diff --git a/efi/main.c b/efi/main.c
index 4afa7d47..e01b35e1 100644
--- a/efi/main.c
+++ b/efi/main.c
@@ -3,6 +3,7 @@
#include <com32.h>
#include <syslinux/memscan.h>
#include <syslinux/firmware.h>
+#include <syslinux/linux.h>
#include <sys/ansi.h>
#include "efi.h"
@@ -270,6 +271,388 @@ struct adv_ops efi_adv_ops = {
.write = efi_adv_write,
};
+struct efi_info {
+ uint32_t load_signature;
+ uint32_t systab;
+ uint32_t desc_size;
+ uint32_t desc_version;
+ uint32_t memmap;
+ uint32_t memmap_size;
+ uint32_t systab_hi;
+ uint32_t memmap_hi;
+};
+
+#define E820MAX 128
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_UNUSABLE 5
+
+struct e820_entry {
+ uint64_t start;
+ uint64_t len;
+ uint32_t type;
+} __packed;
+
+struct boot_params {
+ struct screen_info screen_info;
+ uint8_t _pad[0x1c0 - sizeof(struct screen_info)];
+ struct efi_info efi;
+ uint8_t _pad2[8];
+ uint8_t e820_entries;
+ uint8_t _pad3[0x2d0 - 0x1e8 - sizeof(uint8_t)];
+ struct e820_entry e820_map[E820MAX];
+} __packed;
+
+#define EFI_LOAD_SIG "EL32"
+
+struct dt_desc {
+ uint16_t limit;
+ uint64_t *base;
+} __packed;
+
+struct dt_desc gdt = { 0x800, 0 };
+struct dt_desc idt = { 0, 0 };
+
+static inline EFI_MEMORY_DESCRIPTOR *
+get_mem_desc(addr_t memmap, UINTN desc_sz, int i)
+{
+ return (EFI_MEMORY_DESCRIPTOR *)(memmap + (i * desc_sz));
+}
+
+EFI_HANDLE image_handle;
+
+static inline UINT64 round_up(UINT64 x, UINT64 y)
+{
+ return (((x - 1) | (y - 1)) + 1);
+}
+
+static inline UINT64 round_down(UINT64 x, UINT64 y)
+{
+ return (x & ~(y - 1));
+}
+
+static void find_addr(EFI_PHYSICAL_ADDRESS *first,
+ EFI_PHYSICAL_ADDRESS *last,
+ EFI_PHYSICAL_ADDRESS min,
+ EFI_PHYSICAL_ADDRESS max,
+ size_t size, size_t align)
+{
+ EFI_MEMORY_DESCRIPTOR *map;
+ EFI_STATUS status;
+ UINT32 desc_ver;
+ UINTN nr_entries, key, desc_sz;
+ UINT64 addr;
+ int i;
+
+ map = get_memory_map(&nr_entries, &key, &desc_sz, &desc_ver);
+ if (!map)
+ return;
+
+ for (i = 0; i < nr_entries; i++) {
+ EFI_MEMORY_DESCRIPTOR *m;
+ EFI_PHYSICAL_ADDRESS best;
+ UINT64 start, end;
+
+ m = get_mem_desc((addr_t)map, desc_sz, i);
+ if (m->Type != EfiConventionalMemory)
+ continue;
+
+ if (m->NumberOfPages < EFI_SIZE_TO_PAGES(size))
+ continue;
+
+ start = m->PhysicalStart;
+ end = m->PhysicalStart + (m->NumberOfPages << EFI_PAGE_SHIFT);
+ if (first) {
+ if (end < min)
+ continue;
+
+ /* What's the best address? */
+ if (start < min && min < end)
+ best = min;
+ else
+ best = m->PhysicalStart;
+
+ start = round_up(best, align);
+ if (start > max)
+ continue;
+
+ /* Have we run out of space in this region? */
+ if (end < start || (start + size) > end)
+ continue;
+
+ if (start < *first)
+ *first = start;
+ }
+
+ if (last) {
+ if (start > max)
+ continue;
+
+ /* What's the best address? */
+ if (start < max && max < end)
+ best = max - size;
+ else
+ best = end - size;
+
+ start = round_down(best, align);
+ if (start < min || start < m->PhysicalStart)
+ continue;
+
+ if (start > *last)
+ *last = start;
+ }
+ }
+
+ FreePool(map);
+}
+
+static EFI_STATUS allocate_addr(EFI_PHYSICAL_ADDRESS *addr, size_t size)
+{
+ UINTN npages = EFI_SIZE_TO_PAGES(size);
+
+ return uefi_call_wrapper(BS->AllocatePages, 4,
+ AllocateAddress,
+ EfiLoaderData, npages,
+ addr);
+}
+
+static void free_addr(EFI_PHYSICAL_ADDRESS addr, size_t size)
+{
+ UINTN npages = EFI_SIZE_TO_PAGES(size);
+
+ uefi_call_wrapper(BS->FreePages, 2, addr, npages);
+}
+
+int efi_boot_linux(void *kernel_buf, size_t kernel_size,
+ struct initramfs *initramfs, char *cmdline)
+{
+ EFI_MEMORY_DESCRIPTOR *map;
+ struct linux_header *hdr;
+ struct boot_params *bp;
+ struct screen_info *si;
+ struct e820_entry *e820buf, *e;
+ EFI_STATUS status;
+ EFI_PHYSICAL_ADDRESS first, last;
+ UINTN nr_entries, key, desc_sz;
+ UINT32 desc_ver;
+ uint32_t e820_type;
+ addr_t irf_size;
+ int i;
+
+ hdr = (struct linux_header *)kernel_buf;
+ bp = (struct boot_params *)hdr;
+
+ /*
+ * We require a relocatable kernel because we have no control
+ * over free memory in the memory map.
+ */
+ if (hdr->version < 0x20a || !hdr->relocatable_kernel) {
+ printf("bzImage version unsupported\n");
+ goto bail;
+ }
+
+ hdr->type_of_loader = 0x30; /* SYSLINUX unknown module */
+ hdr->cmd_line_ptr = cmdline;
+
+ si = &bp->screen_info;
+ memset(si, 0, sizeof(*si));
+ setup_screen(si);
+
+ gdt.base = (uint16_t *)malloc(gdt.limit);
+ memset(gdt.base, 0x0, gdt.limit);
+
+ first = -1ULL;
+ find_addr(&first, NULL, 0x1000, -1ULL, kernel_size,
+ hdr->kernel_alignment);
+ if (first != -1ULL)
+ status = allocate_addr(&first, kernel_size);
+
+ if (first == -1ULL || status != EFI_SUCCESS) {
+ printf("Failed to allocate memory for kernel\n");
+ goto bail;
+ }
+
+ hdr->code32_start = (uint32_t)first;
+
+ /* Skip the setup headers and copy the code */
+ kernel_buf += (hdr->setup_sects + 1) * 512;
+ memcpy(hdr->code32_start, kernel_buf, kernel_size);
+
+ /*
+ * Figure out the size of the initramfs, and where to put it.
+ * We should put it at the highest possible address which is
+ * <= hdr->initrd_addr_max, which fits the entire initramfs.
+ */
+ irf_size = initramfs_size(initramfs); /* Handles initramfs == NULL */
+ if (irf_size) {
+ struct initramfs *ip;
+ addr_t next_addr, len, pad;
+
+ last = 0;
+ find_addr(NULL, &last, 0x1000, hdr->initrd_addr_max,
+ irf_size, INITRAMFS_MAX_ALIGN);
+ if (last)
+ status = allocate_addr(&last, irf_size);
+
+ if (!last || status != EFI_SUCCESS) {
+ printf("Failed to allocate initramfs memory\n");
+ goto free_kernel;
+ }
+
+ hdr->ramdisk_image = (uint32_t)last;
+ hdr->ramdisk_size = irf_size;
+
+ /* Copy initramfs into allocated memory */
+ for (ip = initramfs->next; ip->len; ip = ip->next) {
+ len = ip->len;
+ next_addr = last + len;
+
+ /*
+ * If this isn't the last entry, extend the
+ * zero-pad region to enforce the alignment of
+ * the next chunk.
+ */
+ if (ip->next->len) {
+ pad = -next_addr & (ip->next->align - 1);
+ len += pad;
+ next_addr += pad;
+ }
+
+ if (ip->data_len)
+ memcpy(last, ip->data, ip->data_len);
+
+ if (len > ip->data_len)
+ memset(last + ip->data_len, 0,
+ len - ip->data_len);
+
+ last = next_addr;
+ }
+ }
+
+ /* Build efi memory map */
+ map = get_memory_map(&nr_entries, &key, &desc_sz, &desc_ver);
+ if (!map)
+ goto free_irf;
+
+ bp->efi.memmap = map;
+ bp->efi.memmap_size = nr_entries * desc_sz;
+
+ bp->efi.systab = ST;
+ bp->efi.desc_size = desc_sz;
+ bp->efi.desc_version = desc_ver;
+
+ /*
+ * Even though 'memmap' contains the memory map we provided
+ * previously in efi_scan_memory(), we should recalculate the
+ * e820 map because it will most likely have changed in the
+ * interim.
+ */
+ e = e820buf = bp->e820_map;
+ for (i = 0; i < nr_entries && i < E820MAX; i++) {
+ struct e820_entry *prev = NULL;
+
+ if (e > e820buf)
+ prev = e - 1;
+
+ map = get_mem_desc(bp->efi.memmap, desc_sz, i);
+ e->start = map->PhysicalStart;
+ e->len = map->NumberOfPages << EFI_PAGE_SHIFT;
+
+ switch (map->Type) {
+ case EfiReservedMemoryType:
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ case EfiMemoryMappedIO:
+ case EfiMemoryMappedIOPortSpace:
+ case EfiPalCode:
+ e820_type = E820_RESERVED;
+ break;
+
+ case EfiUnusableMemory:
+ 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:
+ continue;
+ }
+
+ e->type = e820_type;
+
+ /* Check for adjacent entries we can merge. */
+ if (prev && (prev->start + prev->len) == e->start &&
+ prev->type == e->type)
+ prev->len += e->len;
+ else
+ e++;
+ }
+
+ bp->e820_entries = e - e820buf;
+
+ status = uefi_call_wrapper(BS->ExitBootServices, 2, image_handle, key);
+ if (status != EFI_SUCCESS) {
+ printf("Failed to exit boot services: 0x%016lx\n", status);
+ goto free_map;
+ }
+
+ memcpy(&bp->efi.load_signature, EFI_LOAD_SIG, sizeof(uint32_t));
+
+ /*
+ * 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;
+
+ asm volatile ("lidt %0" :: "m" (idt));
+ asm volatile ("lgdt %0" :: "m" (gdt));
+
+ asm volatile ("cli \n"
+ "movl %0, %%esi \n"
+ "movl %1, %%ecx \n"
+ "jmp *%%ecx \n"
+ :: "m" (bp), "m" (hdr->code32_start));
+ /* NOTREACHED */
+
+free_map:
+ FreePool(map);
+free_irf:
+ if (irf_size)
+ free_addr(last, irf_size);
+free_kernel:
+ free_addr(first, kernel_size);
+bail:
+ return -1;
+}
+
extern struct disk *efi_disk_init(com32sys_t *);
extern void serialcfg(uint16_t *, uint16_t *, uint16_t *);
@@ -283,6 +666,7 @@ struct firmware efi_fw = {
.get_serial_console_info = serialcfg,
.ipappend_strings = efi_ipappend_strings,
.adv_ops = &efi_adv_ops,
+ .boot_linux = efi_boot_linux,
};
static inline void syslinux_register_efi(void)
@@ -307,6 +691,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table)
memset(__bss_start, 0, len);
InitializeLib(image, table);
+ image_handle = image;
syslinux_register_efi();
init();