[syslinux:firmware] firmware: Add EFI linux boot support

syslinux-bot for Matt Fleming matt.fleming at intel.com
Fri Nov 9 09:06:15 PST 2012


Commit-ID:  db7dfa4c8eac192fa3e91a94b47cc324d698715b
Gitweb:     http://www.syslinux.org/commit/db7dfa4c8eac192fa3e91a94b47cc324d698715b
Author:     Matt Fleming <matt.fleming at intel.com>
AuthorDate: Fri, 27 Jan 2012 21:35:02 +0000
Committer:  Matt Fleming <matt.fleming at intel.com>
CommitDate: Thu, 2 Feb 2012 16:24:08 +0000

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 at intel.com>

---
 com32/include/syslinux/firmware.h |    1 +
 com32/include/syslinux/linux.h    |   39 ++++
 com32/lib/syslinux/load_linux.c   |   11 +-
 core/bios.c                       |    3 +
 efi/console.c                     |  169 ++++++++++++++++
 efi/efi.h                         |    2 +
 efi/main.c                        |  385 +++++++++++++++++++++++++++++++++++++
 7 files changed, 608 insertions(+), 2 deletions(-)

diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h
index 3877d62..e23a1b3 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 cf28762..abc71dc 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 8d4f717..86ea862 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 447268d..9e34146 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 baca973..1e475b1 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 7e53fb2..ed3fe8a 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 4afa7d4..e01b35e 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();
 


More information about the Syslinux-commits mailing list