#include <syslinux/linux.h>
#include <sys/ansi.h>
+#include "keymap.h"
#include "efi.h"
#include "fio.h"
uint8_t KeepPXE;
-volatile uint32_t __ms_timer = 0xdeadbeef;
+volatile uint32_t __ms_timer = 0;
volatile uint32_t __jiffies = 0;
static void efi_write_char(uint8_t ch, uint8_t attribute)
mem_init();
}
+static int seq_len = 0;
+static char *key_seq = NULL;
+
char efi_getchar(char *hi)
{
SIMPLE_INPUT_INTERFACE *in = ST->ConIn;
EFI_STATUS status;
char c;
- WaitForSingleEvent(in->WaitForKey, 0);
+ if (seq_len) {
+ /* We are in the middle of key sequence for the scan code */
+ c = *key_seq++;
+ seq_len--;
+ if (!seq_len) {
+ /* end of key sequene, reset state */
+ seq_len = 0;
+ key_seq = NULL;
+ }
+ return c;
+ }
+ /* Fresh key processing */
do {
status = uefi_call_wrapper(in->ReadKeyStroke, 2, in, &key);
} while (status == EFI_NOT_READY);
- c = (char)key.UnicodeChar;
+ if (!key.ScanCode)
+ return (char)key.UnicodeChar;
+
+ /* We need to generate a key sequence for the scan code */
+ if (key.ScanCode <= NCODES) {
+ key_seq = (char *)keycodes[key.ScanCode-1].seq;
+ seq_len = keycodes[key.ScanCode-1].seqlen;
+ seq_len--;
+ c = *key_seq++;
+ } else c = '\0';
+
return c;
}
SIMPLE_INPUT_INTERFACE *in = ST->ConIn;
EFI_STATUS status;
+ if (seq_len) {
+ /* we are in the middle of a key sequence .. say so */
+ return 1;
+ }
status = WaitForSingleEvent(in->WaitForKey, 1);
return status != EFI_TIMEOUT;
}
#define E820_NVS 4
#define E820_UNUSABLE 5
+#define BOOT_SIGNATURE 0xaa55
+#define SYSLINUX_EFILDR 0x30 /* Is this published value? */
+#define DEFAULT_TIMER_TICK_DURATION 500000 /* 500000 == 500000 * 100 * 10^-9 == 50 msec */
+#define DEFAULT_MSTIMER_INC 0x32 /* 50 msec */
struct e820_entry {
uint64_t start;
uint64_t len;
struct e820_entry e820_map[E820MAX];
} __packed;
+/* Allocate boot parameter block aligned to page */
+#define BOOT_PARAM_BLKSIZE EFI_SIZE_TO_PAGES(sizeof(struct boot_params)) * EFI_PAGE_SIZE
+
+/* Routines in support of efi boot loader were obtained from
+ * http://git.kernel.org/?p=boot/efilinux/efilinux.git:
+ * kernel_jump(), handover_jump(),
+ * emalloc()/efree, alloc_pages/free_pages
+ * allocate_pool()/free_pool()
+ * memory_map()
+ */
#if __SIZEOF_POINTER__ == 4
#define EFI_LOAD_SIG "EL32"
+static inline void kernel_jump(EFI_PHYSICAL_ADDRESS kernel_start,
+ struct boot_params *boot_params)
+{
+ asm volatile ("cli \n"
+ "movl %0, %%esi \n"
+ "movl %1, %%ecx \n"
+ "jmp *%%ecx \n"
+ :: "m" (boot_params), "m" (kernel_start));
+}
+
+static inline void handover_jump(EFI_HANDLE image, struct boot_params *bp,
+ EFI_PHYSICAL_ADDRESS kernel_start)
+{
+ /* handover protocol not implemented yet; the linux header needs to be updated */
+#if 0
+ kernel_start += hdr->handover_offset;
+
+ asm volatile ("cli \n"
+ "pushl %0 \n"
+ "pushl %1 \n"
+ "pushl %2 \n"
+ "movl %3, %%ecx \n"
+ "jmp *%%ecx \n"
+ :: "m" (bp), "m" (ST),
+ "m" (image), "m" (kernel_start));
+#endif
+}
#elif __SIZEOF_POINTER__ == 8
#define EFI_LOAD_SIG "EL64"
+typedef void(*kernel_func)(void *, struct boot_params *);
+typedef void(*handover_func)(void *, EFI_SYSTEM_TABLE *, 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);
+}
+
+static inline void handover_jump(EFI_HANDLE image, struct boot_params *bp,
+ EFI_PHYSICAL_ADDRESS kernel_start)
+{
+#if 0
+ /* handover protocol not implemented yet the linux header needs to be updated */
+
+ UINT32 offset = bp->hdr.handover_offset;
+ handover_func hf;
+
+ asm volatile ("cli");
+
+ /* The 64-bit kernel entry is 512 bytes after the start. */
+ kernel_start += 512;
+
+ hf = (handover_func)(kernel_start + offset);
+ hf(image, ST, bp);
+#endif
+}
#else
#error "unsupported architecture"
#endif
uint64_t *base;
} __packed;
-struct dt_desc gdt = { 0x800, 0 };
+struct dt_desc gdt = { 0x800, (uint64_t *)0 };
struct dt_desc idt = { 0, 0 };
static inline EFI_MEMORY_DESCRIPTOR *
FreePool(map);
}
+/**
+ * allocate_pages - Allocate memory pages from the system
+ * @atype: type of allocation to perform
+ * @mtype: type of memory to allocate
+ * @num_pages: number of contiguous 4KB pages to allocate
+ * @memory: used to return the address of allocated pages
+ *
+ * Allocate @num_pages physically contiguous pages from the system
+ * memory and return a pointer to the base of the allocation in
+ * @memory if the allocation succeeds. On success, the firmware memory
+ * map is updated accordingly.
+ *
+ * If @atype is AllocateAddress then, on input, @memory specifies the
+ * address at which to attempt to allocate the memory pages.
+ */
+static inline EFI_STATUS
+allocate_pages(EFI_ALLOCATE_TYPE atype, EFI_MEMORY_TYPE mtype,
+ UINTN num_pages, EFI_PHYSICAL_ADDRESS *memory)
+{
+ return uefi_call_wrapper(BS->AllocatePages, 4, atype,
+ mtype, num_pages, memory);
+}
+/**
+ * free_pages - Return memory allocated by allocate_pages() to the firmware
+ * @memory: physical base address of the page range to be freed
+ * @num_pages: number of contiguous 4KB pages to free
+ *
+ * On success, the firmware memory map is updated accordingly.
+ */
+static inline EFI_STATUS
+free_pages(EFI_PHYSICAL_ADDRESS memory, UINTN num_pages)
+{
+ return uefi_call_wrapper(BS->FreePages, 2, memory, num_pages);
+}
+
static EFI_STATUS allocate_addr(EFI_PHYSICAL_ADDRESS *addr, size_t size)
{
UINTN npages = EFI_SIZE_TO_PAGES(size);
EfiLoaderData, npages,
addr);
}
+/**
+ * allocate_pool - Allocate pool memory
+ * @type: the type of pool to allocate
+ * @size: number of bytes to allocate from pool of @type
+ * @buffer: used to return the address of allocated memory
+ *
+ * Allocate memory from pool of @type. If the pool needs more memory
+ * pages are allocated from EfiConventionalMemory in order to grow the
+ * pool.
+ *
+ * All allocations are eight-byte aligned.
+ */
+static inline EFI_STATUS
+allocate_pool(EFI_MEMORY_TYPE type, UINTN size, void **buffer)
+{
+ return uefi_call_wrapper(BS->AllocatePool, 3, type, size, buffer);
+}
+
+/**
+ * free_pool - Return pool memory to the system
+ * @buffer: the buffer to free
+ *
+ * Return @buffer to the system. The returned memory is marked as
+ * EfiConventionalMemory.
+ */
+static inline EFI_STATUS free_pool(void *buffer)
+{
+ return uefi_call_wrapper(BS->FreePool, 1, buffer);
+}
static void free_addr(EFI_PHYSICAL_ADDRESS addr, size_t size)
{
uefi_call_wrapper(BS->FreePages, 2, addr, npages);
}
+/* cancel the established timer */
+static void cancel_timer(EFI_EVENT ev)
+{
+ uefi_call_wrapper(BS->SetTimer, 3, ev, TimerCancel, 0);
+}
+
+/* Check if timer went off and update default timer counter */
+void timer_handler(EFI_EVENT ev, VOID *ctx)
+{
+ __ms_timer += DEFAULT_MSTIMER_INC;
+ ++__jiffies;
+}
+
+/* Setup a default periodic timer */
+static EFI_STATUS setup_default_timer(EFI_EVENT ev)
+{
+ EFI_STATUS efi_status;
+
+ ev = NULL;
+ efi_status = uefi_call_wrapper( BS->CreateEvent, 5, EVT_TIMER|EVT_NOTIFY_SIGNAL, TPL_NOTIFY, (EFI_EVENT_NOTIFY)timer_handler, NULL, &ev);
+ if (efi_status == EFI_SUCCESS) {
+ efi_status = uefi_call_wrapper(BS->SetTimer, 3, ev, TimerPeriodic, DEFAULT_TIMER_TICK_DURATION);
+ }
+ return efi_status;
+}
+
+/**
+ * memory_map - Allocate and fill out an array of memory descriptors
+ * @map_buf: buffer containing the memory map
+ * @map_size: size of the buffer containing the memory map
+ * @map_key: key for the current memory map
+ * @desc_size: size of the desc
+ * @desc_version: memory descriptor version
+ *
+ * On success, @map_size contains the size of the memory map pointed
+ * to by @map_buf and @map_key, @desc_size and @desc_version are
+ * updated.
+ */
+EFI_STATUS
+memory_map(EFI_MEMORY_DESCRIPTOR **map_buf, UINTN *map_size,
+ UINTN *map_key, UINTN *desc_size, UINT32 *desc_version)
+{
+ EFI_STATUS err = EFI_SUCCESS;
+
+ *map_size = sizeof(**map_buf) * 31;
+
+ /*
+ * Because we're about to allocate memory, we may
+ * potentially create a new memory descriptor, thereby
+ * increasing the size of the memory map. So increase
+ * the buffer size by the size of one memory
+ * descriptor, just in case.
+ */
+ *map_size += sizeof(**map_buf);
+
+ err = allocate_pool(EfiLoaderData, *map_size,
+ (void **)map_buf);
+ if (err == EFI_SUCCESS) {
+ *map_buf = get_memory_map(map_size, map_key, desc_size, desc_version);
+ if (*map_buf == (EFI_MEMORY_DESCRIPTOR *)NULL) {
+ Print(L"Failed to get memory map");
+ err = EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ Print(L"Failed to allocate pool for memory map");
+ }
+
+ return err;
+}
+/**
+ * emalloc - Allocate memory with a strict alignment requirement
+ * @size: size in bytes of the requested allocation
+ * @align: the required alignment of the allocation
+ * @addr: a pointer to the allocated address on success
+ *
+ * If we cannot satisfy @align we return 0.
+ */
+EFI_STATUS emalloc(UINTN size, UINTN align, EFI_PHYSICAL_ADDRESS *addr)
+{
+ UINTN map_size, map_key, desc_size;
+ EFI_MEMORY_DESCRIPTOR *map_buf;
+ UINTN d, map_end;
+ UINT32 desc_version;
+ EFI_STATUS err;
+ UINTN nr_pages = EFI_SIZE_TO_PAGES(size);
+
+ err = memory_map(&map_buf, &map_size, &map_key,
+ &desc_size, &desc_version);
+ if (err != EFI_SUCCESS)
+ goto fail;
+
+ d = (UINTN)map_buf;
+ map_end = (UINTN)map_buf + map_size;
+
+ for (; d < map_end; d += desc_size) {
+ EFI_MEMORY_DESCRIPTOR *desc;
+ EFI_PHYSICAL_ADDRESS start, end, aligned;
+
+ desc = (EFI_MEMORY_DESCRIPTOR *)d;
+ if (desc->Type != EfiConventionalMemory)
+ continue;
+
+ if (desc->NumberOfPages < nr_pages)
+ continue;
+
+ start = desc->PhysicalStart;
+ end = start + (desc->NumberOfPages << EFI_PAGE_SHIFT);
+
+ /* Low-memory is super-precious! */
+ if (end <= 1 << 20)
+ continue;
+ if (start < 1 << 20) {
+ size -= (1 << 20) - start;
+ start = (1 << 20);
+ }
+
+ aligned = (start + align -1) & ~(align -1);
+
+ if ((aligned + size) <= end) {
+ err = allocate_pages(AllocateAddress, EfiLoaderData,
+ nr_pages, &aligned);
+ if (err == EFI_SUCCESS) {
+ *addr = aligned;
+ break;
+ }
+ }
+ }
+
+ if (d == map_end)
+ err = EFI_OUT_OF_RESOURCES;
+
+ free_pool(map_buf);
+fail:
+ return err;
+}
+/**
+ * efree - Return memory allocated with emalloc
+ * @memory: the address of the emalloc() allocation
+ * @size: the size of the allocation
+ */
+void efree(EFI_PHYSICAL_ADDRESS memory, UINTN size)
+{
+ UINTN nr_pages = EFI_SIZE_TO_PAGES(size);
+
+ free_pages(memory, nr_pages);
+}
+
+/* efi_boot_linux:
+ * Boots the linux kernel using the image and parameters to boot with.
+ * The EFI boot loader is reworked taking the cue from
+ * http://git.kernel.org/?p=boot/efilinux/efilinux.git on the need to
+ * cap key kernel data structures at * 0x3FFFFFFF.
+ * The kernel image, kernel command line and boot parameter block are copied
+ * into allocated memory areas that honor the address capping requirement
+ * prior to kernel handoff.
+ *
+ * FIXME
+ * Can we move this allocation requirement to com32 linux loader in order
+ * to avoid double copying kernel image?
+ */
int efi_boot_linux(void *kernel_buf, size_t kernel_size,
struct initramfs *initramfs,
struct setup_data *setup_data,
char *cmdline)
{
EFI_MEMORY_DESCRIPTOR *map;
- struct linux_header *hdr;
+ struct linux_header *hdr, *bhdr;
struct boot_params *bp;
+ struct boot_params *_bp; /* internal, in efi_physical below 0x3FFFFFFF */
struct screen_info *si;
struct e820_entry *e820buf, *e;
EFI_STATUS status;
- EFI_PHYSICAL_ADDRESS first, last;
+ EFI_PHYSICAL_ADDRESS last, addr, pref_address, kernel_start = 0;
+ UINT64 setup_sz, init_size = 0;
UINTN nr_entries, key, desc_sz;
UINT32 desc_ver;
uint32_t e820_type;
addr_t irf_size;
int i;
+ char *_cmdline = NULL; /* internal, in efi_physical below 0x3FFFFFFF */
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");
+ printf("bzImage version 0x%x unsupported\n", hdr->version);
+ goto bail;
+ }
+ if (hdr->version >= 0x20b) {
+ printf("bzImage version 0x%x handover protocol unimplemented \n", hdr->version);
+ goto bail;
+ }
+
+ /* FIXME: check boot sector signature */
+ if (hdr->boot_flag != BOOT_SIGNATURE) {
+ printf("Invalid Boot signature 0x%x, bailing out\n", hdr->boot_flag);
+ goto bail;
+ }
+
+ setup_sz = (hdr->setup_sects + 1) * 512;
+ if (hdr->version >= 0x20a) {
+ pref_address = hdr->pref_address;
+ init_size = hdr->init_size;
+ } else {
+ pref_address = 0x100000;
+
+ /*
+ * We need to account for the fact that the kernel
+ * needs room for decompression, otherwise we could
+ * end up trashing other chunks of allocated memory.
+ */
+ init_size = (kernel_size - setup_sz) * 3;
+ }
+ hdr->type_of_loader = SYSLINUX_EFILDR; /* SYSLINUX boot loader module */
+ /*
+ * The kernel expects cmdline to be allocated pretty low,
+ * Documentation/x86/boot.txt says,
+ *
+ * "The kernel command line can be located anywhere
+ * between the end of the setup heap and 0xA0000"
+ */
+ addr = 0xA0000;
+ status = allocate_pages(AllocateMaxAddress, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(strlen(cmdline) + 1),
+ &addr);
+ if (status != EFI_SUCCESS) {
+ printf("Failed to allocate memory for kernel command line, bailing out\n");
goto bail;
}
+ _cmdline = (char *)(UINTN)addr;
+ memcpy(_cmdline, cmdline, strlen(cmdline) + 1);
+ hdr->cmd_line_ptr = (UINT32)(UINTN)_cmdline;
+ memset((char *)&bp->screen_info, 0x0, sizeof(bp->screen_info));
+
+ addr = pref_address;
+ status = allocate_pages(AllocateAddress, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(init_size), &addr);
+ if (status != EFI_SUCCESS) {
+ /*
+ * We failed to allocate the preferred address, so
+ * just allocate some memory and hope for the best.
+ */
+ status = emalloc(init_size, hdr->kernel_alignment, &addr);
+ if (status != EFI_SUCCESS) {
+ printf("Failed to allocate memory for kernel image, bailing out\n");
+ goto free_map;
+ }
+ }
+ kernel_start = addr;
+ /* FIXME: we copy the kernel into the physical memory allocated here
+ * The syslinux kernel image load elsewhere could allocate the EFI memory from here
+ * prior to copying kernel and save an extra copy
+ */
+ memcpy((void *)(UINTN)kernel_start, kernel_buf+setup_sz, kernel_size-setup_sz);
+
+ /* allocate for boot parameter block */
+ addr = 0x3FFFFFFF;
+ status = allocate_pages(AllocateMaxAddress, EfiLoaderData,
+ BOOT_PARAM_BLKSIZE, &addr);
+ if (status != EFI_SUCCESS) {
+ printf("Failed to allocate memory for kernel boot parameter block, bailing out\n");
+ goto free_map;
+ }
+
+ _bp = (struct boot_params *)(UINTN)addr;
- hdr->type_of_loader = 0x30; /* SYSLINUX unknown module */
- hdr->cmd_line_ptr = cmdline;
+ memset((void *)_bp, 0x0, BOOT_PARAM_BLKSIZE);
+ /* Copy the first two sectors to boot_params */
+ memcpy((char *)_bp, kernel_buf, 2 * 512);
+ bhdr = (struct linux_header *)_bp;
+ bhdr->code32_start = (UINT32)((UINT64)kernel_start);
- si = &bp->screen_info;
+ dprintf("efi_boot_linux: kernel_start 0x%x kernel_size 0x%x initramfs 0x%x setup_data 0x%x cmdline 0x%x\n",
+ kernel_start, kernel_size, initramfs, setup_data, _cmdline);
+ si = &_bp->screen_info;
memset(si, 0, sizeof(*si));
setup_screen(si);
-#if __SIZEOF_POINTER__ == 4
- gdt.base = (uint16_t *)malloc(gdt.limit);
-#elif __SIZEOF_POINTER__ == 8
- gdt.base = (uint64_t *)malloc(gdt.limit);
-#else
-#error "unsupported architecture"
-#endif
+ /*
+ * FIXME: implement handover protocol
+ * Use the kernel's EFI boot stub by invoking the handover
+ * protocol.
+ */
+ /* Allocate gdt consistent with the alignment for architecture */
+ status = emalloc(gdt.limit, __SIZEOF_POINTER__ , (EFI_PHYSICAL_ADDRESS *)&gdt.base);
+ if (status != EFI_SUCCESS) {
+ printf("Failed to allocate memory for GDT, bailing out\n");
+ goto free_map;
+ }
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);
- }
+ /*
+ * 4Gb - (0x100000*0x1000 = 4Gb)
+ * base address=0
+ * code read/exec
+ * granularity=4096, 386 (+5th nibble of limit)
+ */
+ gdt.base[2] = 0x00cf9a000000ffff;
- if (first == -1ULL || status != EFI_SUCCESS) {
- printf("Failed to allocate memory for kernel\n");
- goto bail;
- }
+ /*
+ * 4Gb - (0x100000*0x1000 = 4Gb)
+ * base address=0
+ * data read/write
+ * granularity=4096, 386 (+5th nibble of limit)
+ */
+ gdt.base[3] = 0x00cf92000000ffff;
-#if __SIZEOF_POINTER__ == 4
- hdr->code32_start = (uint32_t)first;
-#elif __SIZEOF_POINTER__ == 8
- hdr->code32_start = (uint32_t)(uint64_t)first;
-#else
-#error "unsupported architecture"
-#endif
+ /* Task segment value */
+ gdt.base[4] = 0x0080890000000000;
- /* Skip the setup headers and copy the code */
- kernel_buf += (hdr->setup_sects + 1) * 512;
- memcpy(hdr->code32_start, kernel_buf, kernel_size);
+ dprintf("efi_boot_linux: setup_sects %d kernel_size %d\n", hdr->setup_sects, kernel_size);
/*
* Figure out the size of the initramfs, and where to put it.
status = allocate_addr(&last, irf_size);
if (!last || status != EFI_SUCCESS) {
- printf("Failed to allocate initramfs memory\n");
- goto free_kernel;
+ printf("Failed to allocate initramfs memory, bailing out\n");
+ goto free_map;
}
hdr->ramdisk_image = (uint32_t)last;
}
if (ip->data_len)
- memcpy(last, ip->data, ip->data_len);
+ memcpy((void *)(UINTN)last, ip->data, ip->data_len);
if (len > ip->data_len)
- memset(last + ip->data_len, 0,
+ memset((void *)(UINTN)(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;
-
-#if __SIZEOF_POINTER__ == 4
- bp->efi.memmap = map;
- bp->efi.memmap_size = nr_entries * desc_sz;
+ goto free_map;
- bp->efi.systab = ST;
- bp->efi.desc_size = desc_sz;
- bp->efi.desc_version = desc_ver;
-#elif __SIZEOF_POINTER__ == 8
- bp->efi.memmap = (uint32_t)(unsigned long)map;
- bp->efi.memmap_hi = ((unsigned long)map) >> 32;
- bp->efi.memmap_size = nr_entries * desc_sz;
-
- bp->efi.systab = (uint32_t)(unsigned long)ST;
- bp->efi.systab_hi = ((unsigned long)ST) >> 32;
- bp->efi.desc_size = desc_sz;
- bp->efi.desc_version = desc_ver;
-#else
-#error "unsupported architecture"
+ _bp->efi.memmap = (uint32_t)(uint64_t)map;
+ _bp->efi.memmap_size = nr_entries * desc_sz;
+ _bp->efi.systab = (uint32_t)(uint64_t)ST;
+ _bp->efi.desc_size = desc_sz;
+ _bp->efi.desc_version = desc_ver;
+#if defined(__x86_64__)
+ _bp->efi.systab_hi = ((unsigned long)ST) >> 32;
+ _bp->efi.memmap_hi = ((unsigned long)map) >> 32;
#endif
+
/*
* 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;
+ 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);
+ map = get_mem_desc(_bp->efi.memmap, desc_sz, i);
e->start = map->PhysicalStart;
e->len = map->NumberOfPages << EFI_PAGE_SHIFT;
e++;
}
- bp->e820_entries = e - e820buf;
+ _bp->e820_entries = e - e820buf;
+ dprintf("efi_boot_linux: exit boot services\n");
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;
+ memcpy(&_bp->efi.load_signature, EFI_LOAD_SIG, sizeof(uint32_t));
asm volatile ("lidt %0" :: "m" (idt));
asm volatile ("lgdt %0" :: "m" (gdt));
-#if __SIZEOF_POINTER__ == 4
- asm volatile ("cli \n"
- "movl %0, %%esi \n"
- "movl %1, %%ecx \n"
- "jmp *%%ecx \n"
- :: "m" (bp), "m" (hdr->code32_start));
-#elif __SIZEOF_POINTER__ == 8
- {
- struct {
- uint32_t kernel_entry;
- uint16_t kernel_cs;
- } kernel_vector;
- void *kstart;
-
- kernel_vector.kernel_entry = hdr->code32_start;
- kernel_vector.kernel_cs = 0x10;
- kstart = (VOID *)&kernel_vector;
- asm volatile ("cli \n"
- "mov %0, %%rsi \n"
- "mov %1, %%rcx \n"
- "ljmp *(%%rcx) \n"
- :: "m" (bp), "m" (kstart));
- }
-#else
-#error "unsupported architecture"
-#endif
+ kernel_jump(kernel_start, _bp);
+
/* NOTREACHED */
free_map:
+ if (_cmdline) efree((EFI_PHYSICAL_ADDRESS)_cmdline, strlen(_cmdline) + 1);
+ if (_bp) efree((EFI_PHYSICAL_ADDRESS)_bp, BOOT_PARAM_BLKSIZE);
+ if (kernel_start) efree(kernel_start, init_size);
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(EFI_HANDLE);
extern void serialcfg(uint16_t *, uint16_t *, uint16_t *);
+
+
struct firmware efi_fw = {
.init = efi_init,
.scan_memory = efi_scan_memory,
extern char __bss_start[];
extern char __bss_end[];
+
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table)
{
EFI_LOADED_IMAGE *info;
const struct fs_ops *ops[] = { &vfat_fs_ops, NULL };
unsigned long len = (unsigned long)__bss_end - (unsigned long)__bss_start;
static struct disk_private priv;
+ EFI_EVENT timer_ev;
memset(__bss_start, 0, len);
InitializeLib(image, table);
Print(L"Failed to locate root device to prep for file operations & ADV initialization\n");
goto out;
}
+ /* setup timer for boot menu system support */
+ status = setup_default_timer(timer_ev);
+ if (status != EFI_SUCCESS) {
+ printf("Failed to set up EFI timer support, bailing out\n");
+ goto out;
+ }
/* TODO: once all errors are captured in efi_errno, bail out if necessary */
priv.dev_handle = info->DeviceHandle;
fs_init(ops, &priv);
load_env32();
+ /* load_env32() failed.. cancel timer and bailout */
+ cancel_timer(timer_ev);
out:
return status;