From 1dff7e414d78d5fd8ff62a57b67617aa1f73e532 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 7 Jul 2014 18:02:53 +0200 Subject: Add initial EFI architecture support This adds support for running barebox in an EFI environment on X86 PC hardware. Signed-off-by: Sascha Hauer --- .gitignore | 1 + Makefile | 3 +- arch/efi/Kconfig | 51 ++ arch/efi/Makefile | 41 + arch/efi/configs/efi_defconfig | 78 ++ arch/efi/efi/Makefile | 2 + arch/efi/efi/clocksource.c | 60 ++ arch/efi/efi/efi-block-io.c | 174 ++++ arch/efi/efi/efi-device.c | 348 +++++++ arch/efi/efi/efi-image.c | 105 +++ arch/efi/efi/efi.c | 342 +++++++ arch/efi/efi/env-efi/network/eth0-discover | 5 + arch/efi/include/asm/barebox.h | 1 + arch/efi/include/asm/bitops.h | 15 + arch/efi/include/asm/byteorder.h | 8 + arch/efi/include/asm/common.h | 4 + arch/efi/include/asm/dma.h | 13 + arch/efi/include/asm/elf.h | 60 ++ arch/efi/include/asm/io.h | 55 ++ arch/efi/include/asm/posix_types.h | 93 ++ arch/efi/include/asm/sections.h | 1 + arch/efi/include/asm/string.h | 1 + arch/efi/include/asm/swab.h | 6 + arch/efi/include/asm/types.h | 73 ++ arch/efi/include/asm/unaligned.h | 19 + arch/efi/include/mach/debug_ll.h | 20 + arch/efi/include/mach/efi-device.h | 45 + arch/efi/include/mach/efi.h | 24 + arch/efi/lib/.gitignore | 2 + arch/efi/lib/Makefile | 4 + arch/efi/lib/crt0-efi-ia32.S | 76 ++ arch/efi/lib/crt0-efi-x86_64.S | 75 ++ arch/efi/lib/elf_ia32_efi.lds.S | 102 +++ arch/efi/lib/elf_x86_64_efi.lds.S | 93 ++ arch/efi/lib/reloc_ia32.c | 97 ++ arch/efi/lib/reloc_x86_64.c | 96 ++ common/Kconfig | 8 + common/Makefile | 4 +- common/efi-devicepath.c | 1370 ++++++++++++++++++++++++++++ common/efi-guid.c | 11 + common/memory.c | 2 +- common/partitions/efi.c | 2 +- drivers/of/Kconfig | 2 +- include/efi.h | 469 +++++----- 44 files changed, 3791 insertions(+), 270 deletions(-) create mode 100644 arch/efi/Kconfig create mode 100644 arch/efi/Makefile create mode 100644 arch/efi/configs/efi_defconfig create mode 100644 arch/efi/efi/Makefile create mode 100644 arch/efi/efi/clocksource.c create mode 100644 arch/efi/efi/efi-block-io.c create mode 100644 arch/efi/efi/efi-device.c create mode 100644 arch/efi/efi/efi-image.c create mode 100644 arch/efi/efi/efi.c create mode 100644 arch/efi/efi/env-efi/network/eth0-discover create mode 100644 arch/efi/include/asm/barebox.h create mode 100644 arch/efi/include/asm/bitops.h create mode 100644 arch/efi/include/asm/byteorder.h create mode 100644 arch/efi/include/asm/common.h create mode 100644 arch/efi/include/asm/dma.h create mode 100644 arch/efi/include/asm/elf.h create mode 100644 arch/efi/include/asm/io.h create mode 100644 arch/efi/include/asm/posix_types.h create mode 100644 arch/efi/include/asm/sections.h create mode 100644 arch/efi/include/asm/string.h create mode 100644 arch/efi/include/asm/swab.h create mode 100644 arch/efi/include/asm/types.h create mode 100644 arch/efi/include/asm/unaligned.h create mode 100644 arch/efi/include/mach/debug_ll.h create mode 100644 arch/efi/include/mach/efi-device.h create mode 100644 arch/efi/include/mach/efi.h create mode 100644 arch/efi/lib/.gitignore create mode 100644 arch/efi/lib/Makefile create mode 100644 arch/efi/lib/crt0-efi-ia32.S create mode 100644 arch/efi/lib/crt0-efi-x86_64.S create mode 100644 arch/efi/lib/elf_ia32_efi.lds.S create mode 100644 arch/efi/lib/elf_x86_64_efi.lds.S create mode 100644 arch/efi/lib/reloc_ia32.c create mode 100644 arch/efi/lib/reloc_x86_64.c create mode 100644 common/efi-devicepath.c create mode 100644 common/efi-guid.c diff --git a/.gitignore b/.gitignore index 135fdeb630..19534c9a73 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ barebox.uimage barebox.map barebox.kwb barebox.kwbuart +barebox.efi barebox-flash-image System.map Module.symvers diff --git a/Makefile b/Makefile index 63139c2512..69320d8100 100644 --- a/Makefile +++ b/Makefile @@ -997,7 +997,8 @@ CLEAN_FILES += barebox System.map include/generated/barebox_default_env.h \ .tmp_kallsyms* common/barebox_default_env* barebox.ldr \ scripts/bareboxenv-target barebox-flash-image \ Doxyfile.version barebox.srec barebox.s5p barebox.ubl \ - barebox.uimage barebox.spi barebox.kwb barebox.kwbuart + barebox.uimage barebox.spi barebox.kwb barebox.kwbuart \ + barebox.efi # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config include2 usr/include diff --git a/arch/efi/Kconfig b/arch/efi/Kconfig new file mode 100644 index 0000000000..71ac1c74e8 --- /dev/null +++ b/arch/efi/Kconfig @@ -0,0 +1,51 @@ +config ARCH_EFI + bool + default y + select HAS_DEBUG_LL + select HAS_KALLSYMS + select HAVE_DEFAULT_ENVIRONMENT_NEW + select EFI_GUID + select EFI_DEVICEPATH + select PRINTF_UUID + +config ARCH_TEXT_BASE + hex + default 0x0 + +menu "EFI specific settings" + +config 64BIT + def_bool y + help + Say yes to build a 64-bit binary - formerly known as x86_64 + Say no to build a 32-bit binary - formerly known as i386. + + 32-bit support currently does not compile and is not tested + due to the lack of hardware. + +config X86_32 + def_bool y + depends on !64BIT + +config X86_64 + def_bool y + depends on 64BIT + +config ARCH_EFI_REGISTER_COM1 + bool "Register first serial port" + help + Say yes here to register the first serial port on ioport 0x3f8. + This is useful to control barebox over a serial port if the board + has one. Enabling this option may not work on boards which do not + have a serial port. Also enable DRIVER_SERIAL_NS16550 to enable + the NS16550 driver. + +endmenu + +source common/Kconfig +source commands/Kconfig +source net/Kconfig +source drivers/Kconfig +source fs/Kconfig +source lib/Kconfig +source crypto/Kconfig diff --git a/arch/efi/Makefile b/arch/efi/Makefile new file mode 100644 index 0000000000..af280859f0 --- /dev/null +++ b/arch/efi/Makefile @@ -0,0 +1,41 @@ +CFLAGS += -fpic -fshort-wchar -mno-sse -mno-mmx + +ifeq ($(CONFIG_X86_32),y) + UTS_MACHINE := i386 + biarch := $(call cc-option,-m32) + AFLAGS += $(biarch) + CFLAGS += $(biarch) + TARGET = efi-app-ia32 +else + UTS_MACHINE := x86_64 + AFLAGS += -m64 + CFLAGS += -m64 -mno-red-zone + TARGET = efi-app-x86_64 +endif + +lds-$(CONFIG_X86_32) := arch/efi/lib/elf_ia32_efi.lds +lds-$(CONFIG_X86_64) := arch/efi/lib/elf_x86_64_efi.lds + +cmd_barebox__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_barebox) -o $@ \ + -T $(lds-y) \ + -shared -Bsymbolic -nostdlib -znocombreloc \ + --start-group $(barebox-common) \ + --end-group \ + $(filter-out $(barebox-lds) $(barebox-common) FORCE ,$^) + +quiet_cmd_efi_image = EFI-IMG $@ + cmd_efi_image = objcopy -j .text -j .sdata -j .data -j .dynamic \ + -j .dynsym -j .rel -j .rela -j .reloc -j __barebox_initcalls \ + -j __barebox_cmd -j .barebox_magicvar -j .bbenv.* \ + --target=$(TARGET) $< $@ + +KBUILD_BINARY := barebox + +LDFLAGS := -m elf_$(UTS_MACHINE) --no-undefined + +barebox.efi: $(KBUILD_BINARY) FORCE + $(call if_changed,efi_image) + +KBUILD_IMAGE := barebox.efi + +common-y += arch/efi/efi/ arch/efi/lib/ diff --git a/arch/efi/configs/efi_defconfig b/arch/efi/configs/efi_defconfig new file mode 100644 index 0000000000..456f70d32b --- /dev/null +++ b/arch/efi/configs/efi_defconfig @@ -0,0 +1,78 @@ +CONFIG_MMU=y +CONFIG_MALLOC_SIZE=0x0 +CONFIG_MALLOC_TLSF=y +CONFIG_PROMPT="barebox> " +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_MENU=y +# CONFIG_TIMESTAMP is not set +CONFIG_CONSOLE_ACTIVATE_ALL=y +CONFIG_PARTITION_DISK_EFI=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y +CONFIG_POLLER=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL=y +CONFIG_LONGHELP=y +CONFIG_CMD_IOMEM=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_GO=y +CONFIG_CMD_LOADB=y +CONFIG_CMD_RESET=y +CONFIG_CMD_UIMAGE=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_FILETYPE=y +CONFIG_CMD_LN=y +CONFIG_CMD_MD5SUM=y +CONFIG_CMD_UNCOMPRESS=y +CONFIG_CMD_LET=y +CONFIG_CMD_MSLEEP=y +CONFIG_CMD_READF=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_HOST=y +CONFIG_CMD_PING=y +CONFIG_CMD_TFTP=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_MENU=y +CONFIG_CMD_MENUTREE=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_CRC=y +CONFIG_CMD_CRC_CMP=y +CONFIG_CMD_MM=y +CONFIG_CMD_DETECT=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_2048=y +CONFIG_CMD_BAREBOX_UPDATE=y +CONFIG_CMD_OF_NODE=y +CONFIG_CMD_OF_PROPERTY=y +CONFIG_CMD_OFTREE=y +CONFIG_CMD_TIME=y +CONFIG_NET=y +CONFIG_NET_NFS=y +CONFIG_NET_NETCONSOLE=y +CONFIG_DRIVER_SERIAL_EFI_STDIO=y +CONFIG_DRIVER_SERIAL_NS16550=y +CONFIG_DRIVER_NET_EFI_SNP=y +# CONFIG_SPI is not set +CONFIG_DISK=y +CONFIG_FS_EXT4=y +CONFIG_FS_TFTP=y +CONFIG_FS_NFS=y +CONFIG_FS_EFI=y +CONFIG_FS_EFIVARFS=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_WRITE=y +CONFIG_FS_FAT_LFN=y diff --git a/arch/efi/efi/Makefile b/arch/efi/efi/Makefile new file mode 100644 index 0000000000..a856e5907c --- /dev/null +++ b/arch/efi/efi/Makefile @@ -0,0 +1,2 @@ +obj-y += efi.o clocksource.o efi-block-io.o efi-device.o efi-image.o +bbenv-y += env-efi diff --git a/arch/efi/efi/clocksource.c b/arch/efi/efi/clocksource.c new file mode 100644 index 0000000000..2f33b43cce --- /dev/null +++ b/arch/efi/efi/clocksource.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +#ifdef __x86_64__ +uint64_t ticks_read(void) +{ + uint64_t a, d; + + __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d)); + + return (d << 32) | a; +} +#else +uint64_t ticks_read(void) +{ + uint64_t val; + + __asm__ volatile ("rdtsc" : "=A" (val)); + + return val; +} +#endif + +static uint64_t freq; + +/* count TSC ticks during a millisecond delay */ +static uint64_t ticks_freq(void) +{ + uint64_t ticks_start, ticks_end; + + ticks_start = ticks_read(); + BS->stall(1000); + ticks_end = ticks_read(); + + return (ticks_end - ticks_start) * 1000; +} + +static uint64_t efi_clocksource_read(void) +{ + return 1000 * 1000 * ticks_read() / freq; +} + +static struct clocksource cs = { + .read = efi_clocksource_read, + .mask = CLOCKSOURCE_MASK(64), + .shift = 0, +}; + +int efi_clocksource_init(void) +{ + cs.mult = clocksource_hz2mult(1000 * 1000, cs.shift); + + freq = ticks_freq(); + + init_clock(&cs); + + return 0; +} diff --git a/arch/efi/efi/efi-block-io.c b/arch/efi/efi/efi-block-io.c new file mode 100644 index 0000000000..00115317fc --- /dev/null +++ b/arch/efi/efi/efi-block-io.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EFI_BLOCK_IO_PROTOCOL_REVISION2 0x00020001 +#define EFI_BLOCK_IO_PROTOCOL_REVISION3 ((2<<16) | (31)) + +struct efi_block_io_media{ + u32 media_id; + bool removable_media; + bool media_present; + bool logical_partition; + bool read_only; + bool write_caching; + u32 block_size; + u32 io_align; + u64 last_block; + u64 lowest_aligned_lba; /* added in Revision 2 */ + u32 logical_blocks_per_physical_block; /* added in Revision 2 */ + u32 optimal_transfer_length_granularity; /* added in Revision 3 */ +}; + +struct efi_block_io_protocol { + u64 revision; + struct efi_block_io_media *media; + efi_status_t(EFIAPI *reset)(struct efi_block_io_protocol *this, + bool ExtendedVerification); + efi_status_t(EFIAPI *read)(struct efi_block_io_protocol *this, u32 media_id, + u64 lba, unsigned long buffer_size, void *buf); + efi_status_t(EFIAPI *write)(struct efi_block_io_protocol *this, u32 media_id, + u64 lba, unsigned long buffer_size, void *buf); + efi_status_t(EFIAPI *flush)(struct efi_block_io_protocol *this); +}; + +struct efi_bio_priv { + struct efi_block_io_protocol *protocol; + struct device_d *dev; + struct block_device blk; + u32 media_id; +}; + +static int efi_bio_read(struct block_device *blk, void *buffer, int block, + int num_blocks) +{ + struct efi_bio_priv *priv = container_of(blk, struct efi_bio_priv, blk); + efi_status_t efiret; + + efiret = priv->protocol->read(priv->protocol, priv->media_id, + block, num_blocks * 512, buffer); + + if (EFI_ERROR(efiret)) + return -efi_errno(efiret); + + return 0; +} + +static int efi_bio_write(struct block_device *blk, + const void *buffer, int block, int num_blocks) +{ + struct efi_bio_priv *priv = container_of(blk, struct efi_bio_priv, blk); + efi_status_t efiret; + + efiret = priv->protocol->write(priv->protocol, priv->media_id, + block, num_blocks * 512, (void *)buffer); + if (EFI_ERROR(efiret)) + return -efi_errno(efiret); + + return 0; +} + +static int efi_bio_flush(struct block_device *blk) +{ + struct efi_bio_priv *priv = container_of(blk, struct efi_bio_priv, blk); + efi_status_t efiret; + + efiret = priv->protocol->flush(priv->protocol); + if (EFI_ERROR(efiret)) + return -efi_errno(efiret); + + return 0; +} + +static struct block_device_ops efi_bio_ops = { + .read = efi_bio_read, + .write = efi_bio_write, + .flush = efi_bio_flush, +}; + +static void efi_bio_print_info(struct efi_bio_priv *priv) +{ + struct efi_block_io_media *media = priv->protocol->media; + u64 revision = priv->protocol->revision; + + dev_dbg(priv->dev, "revision: 0x%016llx\n", revision); + dev_dbg(priv->dev, "media_id: 0x%08x\n", media->media_id); + dev_dbg(priv->dev, "removable_media: %d\n", media->removable_media); + dev_dbg(priv->dev, "media_present: %d\n", media->media_present); + dev_dbg(priv->dev, "logical_partition: %d\n", media->logical_partition); + dev_dbg(priv->dev, "read_only: %d\n", media->read_only); + dev_dbg(priv->dev, "write_caching: %d\n", media->write_caching); + dev_dbg(priv->dev, "block_size: 0x%08x\n", media->block_size); + dev_dbg(priv->dev, "io_align: 0x%08x\n", media->io_align); + dev_dbg(priv->dev, "last_block: 0x%016llx\n", media->last_block); + + if (revision < EFI_BLOCK_IO_PROTOCOL_REVISION2) + return; + + dev_dbg(priv->dev, "u64 lowest_aligned_lba: 0x%08llx\n", + media->lowest_aligned_lba); + dev_dbg(priv->dev, "logical_blocks_per_physical_block: 0x%08x\n", + media->logical_blocks_per_physical_block); + + if (revision < EFI_BLOCK_IO_PROTOCOL_REVISION3) + return; + + dev_dbg(priv->dev, "optimal_transfer_length_granularity: 0x%08x\n", + media->optimal_transfer_length_granularity); +} + +int efi_bio_probe(struct efi_device *efidev) +{ + int ret; + struct efi_bio_priv *priv; + struct efi_block_io_media *media; + + priv = xzalloc(sizeof(*priv)); + + BS->handle_protocol(efidev->handle, &efi_block_io_protocol_guid, + (void **)&priv->protocol); + if (!priv->protocol) + return -ENODEV; + + media = priv->protocol->media; + efi_bio_print_info(priv); + priv->dev = &efidev->dev; + + priv->blk.cdev.name = asprintf("disk%d", cdev_find_free_index("disk")); + priv->blk.blockbits = ffs(media->block_size) - 1; + priv->blk.num_blocks = media->last_block; + priv->blk.ops = &efi_bio_ops; + priv->blk.dev = &efidev->dev; + + priv->media_id = media->media_id; + + ret = blockdevice_register(&priv->blk); + if (ret) + return ret; + + parse_partition_table(&priv->blk); + + return 0; +} + +static struct efi_driver efi_fs_driver = { + .driver = { + .name = "efi-block-io", + }, + .probe = efi_bio_probe, + .guid = EFI_BLOCK_IO_PROTOCOL_GUID, +}; +device_efi_driver(efi_fs_driver); diff --git a/arch/efi/efi/efi-device.c b/arch/efi/efi/efi-device.c new file mode 100644 index 0000000000..71526b999f --- /dev/null +++ b/arch/efi/efi/efi-device.c @@ -0,0 +1,348 @@ +/* + * efi-device.c - barebox EFI payload support + * + * Copyright (c) 2014 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int efi_locate_handle(enum efi_locate_search_type search_type, + efi_guid_t *protocol, + void *search_key, + unsigned long *no_handles, + efi_handle_t **buffer) +{ + efi_status_t efiret; + unsigned long buffer_size = 0; + efi_handle_t *buf; + + efiret = BS->locate_handle(search_type, protocol, search_key, &buffer_size, + NULL); + if (EFI_ERROR(efiret) && efiret != EFI_BUFFER_TOO_SMALL) + return -efi_errno(efiret); + + buf = malloc(buffer_size); + if (!buf) + return -ENOMEM; + + efiret = BS->locate_handle(search_type, protocol, search_key, &buffer_size, + buf); + if (EFI_ERROR(efiret)) { + free(buf); + return -efi_errno(efiret); + } + + *no_handles = buffer_size / sizeof(efi_handle_t); + *buffer = buf; + + return 0; +} + +static struct efi_device *efi_find_device(efi_handle_t *handle) +{ + struct device_d *dev; + struct efi_device *efidev; + + bus_for_each_device(&efi_bus, dev) { + efidev = container_of(dev, struct efi_device, dev); + + if (efidev->handle == handle) + return efidev; + } + + return NULL; +} + +static void efi_devinfo(struct device_d *dev) +{ + struct efi_device *efidev = to_efi_device(dev); + int i; + + printf("Protocols:\n"); + + for (i = 0; i < efidev->num_guids; i++) + printf(" %d: %pUl\n", i, &efidev->guids[i]); +} + +static efi_handle_t *efi_find_parent(efi_handle_t *handle) +{ + unsigned long handle_count = 0; + efi_handle_t *handles = NULL, *parent; + unsigned long num_guids; + efi_guid_t **guids; + int ret, i, j, k; + efi_status_t efiret; + struct efi_open_protocol_information_entry *entry_buffer; + unsigned long entry_count; + + ret = efi_locate_handle(all_handles, NULL, NULL, &handle_count, &handles); + if (ret) + return NULL; + + /* + * Normally one would expect a function/pointer to retrieve the parent. + * With EFI we have to: + * - get all handles + * - for each handle get the registered protocols + * - for each protocol get the users + * - the user which matches the input handle is the parent + */ + for (i = 0; i < handle_count; i++) { + efiret = BS->open_protocol(handles[i], &efi_device_path_protocol_guid, + NULL, NULL, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (EFI_ERROR(efiret)) + continue; + + BS->protocols_per_handle(handles[i], &guids, &num_guids); + for (j = 0; j < num_guids; j++) { + efiret = BS->open_protocol_information(handles[i], guids[j], + &entry_buffer, &entry_count); + for (k = 0; k < entry_count; k++) { + if (entry_buffer[k].controller_handle == NULL) + continue; + if (entry_buffer[k].controller_handle == handles[i]) + continue; + if (entry_buffer[k].controller_handle == handle) { + parent = handles[i]; + goto out; + } + } + } + } + + parent = NULL; + + free(handles); +out: + return parent; +} + +static struct efi_device *efi_add_device(efi_handle_t *handle, efi_guid_t **guids, + int num_guids) +{ + struct efi_device *efidev; + int i; + efi_guid_t *guidarr; + efi_status_t efiret; + void *devpath; + + efidev = efi_find_device(handle); + if (efidev) + return ERR_PTR(-EEXIST); + + efiret = BS->open_protocol(handle, &efi_device_path_protocol_guid, + NULL, NULL, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (EFI_ERROR(efiret)) + return ERR_PTR(-EINVAL); + + guidarr = malloc(sizeof(efi_guid_t) * num_guids); + + for (i = 0; i < num_guids; i++) + memcpy(&guidarr[i], guids[i], sizeof(efi_guid_t)); + + efiret = BS->open_protocol(handle, &efi_device_path_protocol_guid, + &devpath, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(efiret)) + return ERR_PTR(-EINVAL); + + efidev = xzalloc(sizeof(*efidev)); + + efidev->guids = guidarr; + efidev->num_guids = num_guids; + efidev->handle = handle; + efidev->dev.bus = &efi_bus; + efidev->dev.id = DEVICE_ID_SINGLE; + efidev->dev.info = efi_devinfo; + efidev->devpath = devpath; + + BS->handle_protocol(handle, &guidarr[0], &efidev->protocol); + + sprintf(efidev->dev.name, "handle-%p", handle); + + efidev->parent_handle = efi_find_parent(efidev->handle); + + return efidev; +} + + +static int efi_register_device(struct efi_device *efidev) +{ + char *dev_path_str; + struct efi_device *parent; + int ret; + + if (efi_find_device(efidev->handle)) + return -EEXIST; + + if (efidev->parent_handle) { + parent = efi_find_device(efidev->parent_handle); + if (!parent) + return -EINVAL; + + efidev->dev.parent = &parent->dev; + } + + ret = register_device(&efidev->dev); + if (ret) + return ret; + + dev_path_str = device_path_to_str(efidev->devpath); + if (dev_path_str) { + dev_add_param_fixed(&efidev->dev, "devpath", dev_path_str); + free(dev_path_str); + } + + debug("registered efi device %s\n", dev_name(&efidev->dev)); + + return 0; +} + +/** + * efi_register_devices - iterate over all EFI handles and register + * the devices found + * + * in barebox we treat all EFI handles which support the device_path + * protocol as devices. This function iterates over all handles and + * registers the corresponding devices. efi_register_devices is safe + * to call multiple times. Already registered devices will be ignored. + * + */ +void efi_register_devices(void) +{ + unsigned long handle_count = 0; + efi_handle_t *handles = NULL; + unsigned long num_guids; + efi_guid_t **guids; + int ret, i; + struct efi_device **efidevs; + int registered; + + ret = efi_locate_handle(all_handles, NULL, NULL, &handle_count, &handles); + if (ret) + return; + + efidevs = xzalloc(handle_count * sizeof(struct efi_device *)); + + for (i = 0; i < handle_count; i++) { + BS->protocols_per_handle(handles[i], &guids, &num_guids); + + efidevs[i] = efi_add_device(handles[i], guids, num_guids); + } + + /* + * We have a list of devices we want to register, but can only + * register a device when all parents are registered already. + * Do this by continiously iterating over the list until no + * further devices are registered. + */ + do { + registered = 0; + + for (i = 0; i < handle_count; i++) { + if (IS_ERR(efidevs[i])) + continue; + + ret = efi_register_device(efidevs[i]); + if (!ret) { + efidevs[i] = ERR_PTR(-EEXIST); + registered = 1; + } + } + } while (registered); + + free(efidevs); + free(handles); +} + +int efi_connect_all(void) +{ + efi_status_t efiret; + unsigned long handle_count; + efi_handle_t *handle_buffer; + int i; + + efiret = BS->locate_handle_buffer(all_handles, NULL, NULL, &handle_count, + &handle_buffer); + if (EFI_ERROR(efiret)) + return -efi_errno(efiret); + + for (i = 0; i < handle_count; i++) + efiret = BS->connect_controller(handle_buffer[i], NULL, NULL, true); + + if (handle_buffer) + BS->free_pool(handle_buffer); + + return 0; +} + +static int efi_bus_match(struct device_d *dev, struct driver_d *drv) +{ + struct efi_driver *efidrv = to_efi_driver(drv); + struct efi_device *efidev = to_efi_device(dev); + int i; + + for (i = 0; i < efidev->num_guids; i++) { + if (!memcmp(&efidrv->guid, &efidev->guids[i], sizeof(efi_guid_t))) + return 0; + } + + return 1; +} + +static int efi_bus_probe(struct device_d *dev) +{ + struct efi_driver *efidrv = to_efi_driver(dev->driver); + struct efi_device *efidev = to_efi_device(dev); + + return efidrv->probe(efidev); +} + +static void efi_bus_remove(struct device_d *dev) +{ + struct efi_driver *efidrv = to_efi_driver(dev->driver); + struct efi_device *efidev = to_efi_device(dev); + + return efidrv->remove(efidev); +} + +struct bus_type efi_bus = { + .name = "efi", + .match = efi_bus_match, + .probe = efi_bus_probe, + .remove = efi_bus_remove, +}; + +static int efi_init_devices(void) +{ + bus_register(&efi_bus); + + efi_register_devices(); + + return 0; +} +core_initcall(efi_init_devices); diff --git a/arch/efi/efi/efi-image.c b/arch/efi/efi/efi-image.c new file mode 100644 index 0000000000..18757d2697 --- /dev/null +++ b/arch/efi/efi/efi-image.c @@ -0,0 +1,105 @@ +/* + * efi-image.c - barebox EFI payload support + * + * Copyright (c) 2014 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int efi_execute_image(const char *file) +{ + void *exe; + size_t size; + efi_handle_t handle; + efi_status_t efiret; + const char *options; + efi_loaded_image_t *loaded_image; + + exe = read_file(file, &size); + if (!exe) + return -EINVAL; + + efiret = BS->load_image(false, efi_parent_image, efi_device_path, exe, size, + &handle); + if (EFI_ERROR(efiret)) { + pr_err("failed to LoadImage: %s\n", efi_strerror(efiret)); + return -efi_errno(efiret);; + }; + + efiret = BS->open_protocol(handle, &efi_loaded_image_protocol_guid, + (void **)&loaded_image, + efi_parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(efiret)) + return -efi_errno(efiret); + + options = linux_bootargs_get(); + loaded_image->load_options = strdup_char_to_wchar(options); + loaded_image->load_options_size = (strlen(options) + 1) * sizeof(wchar_t); + + efiret = BS->start_image(handle, NULL, NULL); + + efi_connect_all(); + efi_register_devices(); + + return 0; +} + +static int do_bootm_efi(struct image_data *data) +{ + return efi_execute_image(data->os_file); +} + +static struct image_handler efi_handle_tr = { + .name = "EFI Application", + .bootm = do_bootm_efi, + .filetype = filetype_exe, +}; + +static int efi_execute(struct binfmt_hook *b, char *file, int argc, char **argv) +{ + return efi_execute_image(file); +} + +static struct binfmt_hook binfmt_efi_hook = { + .type = filetype_exe, + .hook = efi_execute, +}; + +static int efi_register_image_handler(void) +{ + register_image_handler(&efi_handle_tr); + binfmt_register(&binfmt_efi_hook); + + return 0; +} +late_initcall(efi_register_image_handler); diff --git a/arch/efi/efi/efi.c b/arch/efi/efi/efi.c new file mode 100644 index 0000000000..48b7d9a438 --- /dev/null +++ b/arch/efi/efi/efi.c @@ -0,0 +1,342 @@ +/* + * efi.c - barebox EFI payload support + * + * Copyright (c) 2014 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +efi_runtime_services_t *RT; +efi_boot_services_t *BS; +efi_system_table_t *efi_sys_table; +efi_handle_t efi_parent_image; +struct efi_device_path *efi_device_path; +efi_loaded_image_t *efi_loaded_image; + +void *efi_get_variable(char *name, efi_guid_t *vendor, int *var_size) +{ + efi_status_t efiret; + void *buf; + unsigned long size = 0; + s16 *name16 = strdup_char_to_wchar(name); + + efiret = RT->get_variable(name16, vendor, NULL, &size, NULL); + + if (EFI_ERROR(efiret) && efiret != EFI_BUFFER_TOO_SMALL) { + buf = ERR_PTR(-efi_errno(efiret)); + goto out; + } + + buf = malloc(size); + if (!buf) { + buf = ERR_PTR(-ENOMEM); + goto out; + } + + efiret = RT->get_variable(name16, vendor, NULL, &size, buf); + if (EFI_ERROR(efiret)) { + free(buf); + buf = ERR_PTR(-efi_errno(efiret)); + goto out; + } + + if (var_size) + *var_size = size; + +out: + free(name16); + + return buf; +} + +struct efi_boot { + u32 attributes; + u16 file_path_len; + char *description; + struct efi_device_path *path; + void *binary; +}; + +struct efi_boot *efi_get_boot(int num) +{ + struct efi_boot *boot = xzalloc(sizeof(*boot)); + void *buf, *ptr; + int size; + char *name; + + name = asprintf("Boot%04X", num); + + buf = efi_get_global_var(name, &size); + + free(name); + + if (!buf) { + free(boot); + return NULL; + } + + ptr = buf; + + boot->attributes = *(u32 *)ptr; + + ptr += sizeof(u32); + + boot->file_path_len = *(u16 *)ptr; + + ptr += sizeof(u16); + + boot->description = strdup_wchar_to_char(ptr); + + ptr += (strlen(boot->description) + 1) * 2; + + printf("description: %s\n", boot->description); + + boot->path = memdup(ptr, boot->file_path_len); + + printf("path: %s\n", device_path_to_str(boot->path)); + + return boot; +} + +static int misc_init(void) +{ + efi_get_boot(1); + efi_get_boot(2); + efi_get_boot(3); + + return 0; +} +late_initcall(misc_init); + +const char *efi_strerror(efi_status_t err) +{ + const char *str; + + switch (err) { + case EFI_SUCCESS: str = "Success"; break; + case EFI_LOAD_ERROR: str = "Load Error"; break; + case EFI_INVALID_PARAMETER: str = "Invalid Parameter"; break; + case EFI_UNSUPPORTED: str = "Unsupported"; break; + case EFI_BAD_BUFFER_SIZE: str = "Bad Buffer Size"; break; + case EFI_BUFFER_TOO_SMALL: str = "Buffer Too Small"; break; + case EFI_NOT_READY: str = "Not Ready"; break; + case EFI_DEVICE_ERROR: str = "Device Error"; break; + case EFI_WRITE_PROTECTED: str = "Write Protected"; break; + case EFI_OUT_OF_RESOURCES: str = "Out of Resources"; break; + case EFI_VOLUME_CORRUPTED: str = "Volume Corrupt"; break; + case EFI_VOLUME_FULL: str = "Volume Full"; break; + case EFI_NO_MEDIA: str = "No Media"; break; + case EFI_MEDIA_CHANGED: str = "Media changed"; break; + case EFI_NOT_FOUND: str = "Not Found"; break; + case EFI_ACCESS_DENIED: str = "Access Denied"; break; + case EFI_NO_RESPONSE: str = "No Response"; break; + case EFI_NO_MAPPING: str = "No mapping"; break; + case EFI_TIMEOUT: str = "Time out"; break; + case EFI_NOT_STARTED: str = "Not started"; break; + case EFI_ALREADY_STARTED: str = "Already started"; break; + case EFI_ABORTED: str = "Aborted"; break; + case EFI_ICMP_ERROR: str = "ICMP Error"; break; + case EFI_TFTP_ERROR: str = "TFTP Error"; break; + case EFI_PROTOCOL_ERROR: str = "Protocol Error"; break; + case EFI_INCOMPATIBLE_VERSION: str = "Incompatible Version"; break; + case EFI_SECURITY_VIOLATION: str = "Security Violation"; break; + case EFI_CRC_ERROR: str = "CRC Error"; break; + case EFI_END_OF_MEDIA: str = "End of Media"; break; + case EFI_END_OF_FILE: str = "End of File"; break; + case EFI_INVALID_LANGUAGE: str = "Invalid Language"; break; + case EFI_COMPROMISED_DATA: str = "Compromised Data"; break; + default: str = "unknown error"; + } + + return str; +} + +int efi_errno(efi_status_t err) +{ + int ret; + + switch (err) { + case EFI_SUCCESS: ret = 0; break; + case EFI_LOAD_ERROR: ret = EIO; break; + case EFI_INVALID_PARAMETER: ret = EINVAL; break; + case EFI_UNSUPPORTED: ret = ENOTSUPP; break; + case EFI_BAD_BUFFER_SIZE: ret = EINVAL; break; + case EFI_BUFFER_TOO_SMALL: ret = EINVAL; break; + case EFI_NOT_READY: ret = EAGAIN; break; + case EFI_DEVICE_ERROR: ret = EIO; break; + case EFI_WRITE_PROTECTED: ret = EROFS; break; + case EFI_OUT_OF_RESOURCES: ret = ENOMEM; break; + case EFI_VOLUME_CORRUPTED: ret = EIO; break; + case EFI_VOLUME_FULL: ret = ENOSPC; break; + case EFI_NO_MEDIA: ret = ENOMEDIUM; break; + case EFI_MEDIA_CHANGED: ret = ENOMEDIUM; break; + case EFI_NOT_FOUND: ret = ENODEV; break; + case EFI_ACCESS_DENIED: ret = EACCES; break; + case EFI_NO_RESPONSE: ret = ETIMEDOUT; break; + case EFI_NO_MAPPING: ret = EINVAL; break; + case EFI_TIMEOUT: ret = ETIMEDOUT; break; + case EFI_NOT_STARTED: ret = EINVAL; break; + case EFI_ALREADY_STARTED: ret = EINVAL; break; + case EFI_ABORTED: ret = EINTR; break; + case EFI_ICMP_ERROR: ret = EINVAL; break; + case EFI_TFTP_ERROR: ret = EINVAL; break; + case EFI_PROTOCOL_ERROR: ret = EPROTO; break; + case EFI_INCOMPATIBLE_VERSION: ret = EINVAL; break; + case EFI_SECURITY_VIOLATION: ret = EINVAL; break; + case EFI_CRC_ERROR: ret = EINVAL; break; + case EFI_END_OF_MEDIA: ret = EINVAL; break; + case EFI_END_OF_FILE: ret = EINVAL; break; + case EFI_INVALID_LANGUAGE: ret = EINVAL; break; + case EFI_COMPROMISED_DATA: ret = EINVAL; break; + default: ret = EINVAL; + } + + return ret; +} + +static struct NS16550_plat ns16550_plat = { + .clock = 115200 * 16, +}; + +static int efi_console_init(void) +{ + add_generic_device("efi-stdio", DEVICE_ID_SINGLE, NULL, 0 , 0, 0, NULL); + + if (IS_ENABLED(CONFIG_ARCH_EFI_REGISTER_COM1)) + add_ns16550_device(0, 0x3f8, 0x10, IORESOURCE_IO | IORESOURCE_MEM_8BIT, + &ns16550_plat); + + return 0; +} +console_initcall(efi_console_init); + +void reset_cpu(unsigned long addr) +{ + BS->exit(efi_parent_image, EFI_SUCCESS, 0, NULL); + + while(1); +} + +extern char image_base[]; +extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[], + __barebox_initcalls_end[]; + +/* + * We have a position independent binary generated with -fpic. This function + * fixes the linker generated tables. + */ +static void fixup_tables(void) +{ + initcall_t *initcall; + unsigned long offset = (unsigned long)image_base; + struct command *cmdtp; + struct magicvar *m; + + for (initcall = __barebox_initcalls_start; + initcall < __barebox_initcalls_end; initcall++) + *initcall += offset; + + for (cmdtp = &__barebox_cmd_start; + cmdtp != &__barebox_cmd_end; + cmdtp++) { + cmdtp->name += offset; + cmdtp->cmd += offset; + if (cmdtp->complete) + cmdtp->complete += offset; + if (cmdtp->desc) + cmdtp->desc += offset; + if (cmdtp->help) + cmdtp->help += offset; + if (cmdtp->opts) + cmdtp->opts += offset; + if (cmdtp->aliases) + cmdtp->aliases = (void *)cmdtp->aliases + offset; + } + + for (m = &__barebox_magicvar_start; + m != &__barebox_magicvar_end; + m++) { + m->name += offset; + m->description += offset; + } +} + +static int efi_init(void) +{ + barebox_set_model("barebox EFI payload"); + + defaultenv_append_directory(env_efi); + + return 0; +} +device_initcall(efi_init); + +/** + * efi-main - Entry point for EFI images + */ +efi_status_t efi_main(efi_handle_t image, efi_system_table_t *sys_table) +{ + void *mem; + efi_status_t efiret; + +#ifdef DEBUG + sys_table->con_out->output_string(sys_table->con_out, L"barebox\n"); +#endif + + BS = sys_table->boottime; + + efi_parent_image = image; + efi_sys_table = sys_table; + RT = sys_table->runtime; + + efiret = BS->open_protocol(efi_parent_image, &efi_loaded_image_protocol_guid, + (void **)&efi_loaded_image, + efi_parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(efiret)) + BS->handle_protocol(efi_loaded_image->device_handle, + &efi_device_path_protocol_guid, (void **)&efi_device_path); + + fixup_tables(); + + BS->allocate_pool(efi_loaded_image->image_data_type, SZ_16M, &mem); + mem_malloc_init(mem, mem + SZ_16M); + + efi_clocksource_init(); + + start_barebox(); + + return EFI_SUCCESS; +} diff --git a/arch/efi/efi/env-efi/network/eth0-discover b/arch/efi/efi/env-efi/network/eth0-discover new file mode 100644 index 0000000000..62c31a553c --- /dev/null +++ b/arch/efi/efi/env-efi/network/eth0-discover @@ -0,0 +1,5 @@ +#!/bin/sh + +for i in /boot/network-drivers/*; do + $i; +done diff --git a/arch/efi/include/asm/barebox.h b/arch/efi/include/asm/barebox.h new file mode 100644 index 0000000000..2997587d82 --- /dev/null +++ b/arch/efi/include/asm/barebox.h @@ -0,0 +1 @@ +/* dummy */ diff --git a/arch/efi/include/asm/bitops.h b/arch/efi/include/asm/bitops.h new file mode 100644 index 0000000000..94646d4d0d --- /dev/null +++ b/arch/efi/include/asm/bitops.h @@ -0,0 +1,15 @@ +#ifndef _SANDBOX_BITOPS_H +#define _SANDBOX_BITOPS_H + +/* nothing but the defaults.. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/arch/efi/include/asm/byteorder.h b/arch/efi/include/asm/byteorder.h new file mode 100644 index 0000000000..37316f2371 --- /dev/null +++ b/arch/efi/include/asm/byteorder.h @@ -0,0 +1,8 @@ +#ifndef _I386_BYTEORDER_H +#define _I386_BYTEORDER_H + +#include + +#include + +#endif /* _I386_BYTEORDER_H */ diff --git a/arch/efi/include/asm/common.h b/arch/efi/include/asm/common.h new file mode 100644 index 0000000000..b0e6b7fb18 --- /dev/null +++ b/arch/efi/include/asm/common.h @@ -0,0 +1,4 @@ +#ifndef ASM_COMMON_H +#define ASM_COMMON_H + +#endif /* ASM_COMMON_H */ diff --git a/arch/efi/include/asm/dma.h b/arch/efi/include/asm/dma.h new file mode 100644 index 0000000000..459536779e --- /dev/null +++ b/arch/efi/include/asm/dma.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#ifndef __ASM_DMA_H +#define __ASM_DMA_H + +/* empty*/ + +#endif /* __ASM_DMA_H */ diff --git a/arch/efi/include/asm/elf.h b/arch/efi/include/asm/elf.h new file mode 100644 index 0000000000..ddde035188 --- /dev/null +++ b/arch/efi/include/asm/elf.h @@ -0,0 +1,60 @@ +#ifndef __ASM_SANDBOX_ELF_H__ +#define __ASM_SANDBOX_ELF_H__ + +#ifdef __i386__ + +typedef struct user_fxsr_struct elf_fpxregset_t; + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + +#else + +/* x86-64 relocation types */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ + +#define R_X86_64_NUM 16 + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_X86_64 + +#endif + +#endif /* __ASM_SANDBOX_ELF_H__ */ diff --git a/arch/efi/include/asm/io.h b/arch/efi/include/asm/io.h new file mode 100644 index 0000000000..ac8a9c1b35 --- /dev/null +++ b/arch/efi/include/asm/io.h @@ -0,0 +1,55 @@ +#ifndef __ASM_SANDBOX_IO_H +#define __ASM_SANDBOX_IO_H + +#define build_mmio_read(name, size, type, reg, barrier) \ + static inline type name(const volatile void *addr) \ + { type ret; asm volatile("mov" size " %1,%0":reg (ret) \ + :"m" (*(volatile type*)addr) barrier); return ret; } + +build_mmio_read(readb, "b", unsigned char, "=q", :"memory") +build_mmio_read(readw, "w", unsigned short, "=r", :"memory") +build_mmio_read(readl, "l", unsigned int, "=r", :"memory") + +#define build_mmio_write(name, size, type, reg, barrier) \ + static inline void name(type val, volatile void *addr) \ + { asm volatile("mov" size " %0,%1": :reg (val), \ + "m" (*(volatile type*)addr) barrier); } + +build_mmio_write(writeb, "b", unsigned char, "q", :"memory") +build_mmio_write(writew, "w", unsigned short, "r", :"memory") +build_mmio_write(writel, "l", unsigned int, "r", :"memory") + +#define BUILDIO(bwl, bw, type) \ +static inline void out##bwl(unsigned type value, int port) \ +{ \ + asm volatile("out" #bwl " %" #bw "0, %w1" \ + : : "a"(value), "Nd"(port)); \ +} \ + \ +static inline unsigned type in##bwl(int port) \ +{ \ + unsigned type value; \ + asm volatile("in" #bwl " %w1, %" #bw "0" \ + : "=a"(value) : "Nd"(port)); \ + return value; \ +} \ + \ +static inline void outs##bwl(int port, const void *addr, unsigned long count) \ +{ \ + asm volatile("rep; outs" #bwl \ + : "+S"(addr), "+c"(count) : "d"(port)); \ +} \ + \ +static inline void ins##bwl(int port, void *addr, unsigned long count) \ +{ \ + asm volatile("rep; ins" #bwl \ + : "+D"(addr), "+c"(count) : "d"(port)); \ +} + +BUILDIO(b, b, char) +BUILDIO(w, w, short) +BUILDIO(l, , int) + +#define IO_SPACE_LIMIT 0xffff + +#endif /* __ASM_SANDBOX_IO_H */ diff --git a/arch/efi/include/asm/posix_types.h b/arch/efi/include/asm/posix_types.h new file mode 100644 index 0000000000..6985b8eb4a --- /dev/null +++ b/arch/efi/include/asm/posix_types.h @@ -0,0 +1,93 @@ +#ifndef __ARCH_I386_POSIX_TYPES_H +#define __ARCH_I386_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +/* + * Most 32 bit architectures use "unsigned int" size_t, + * and all 64 bit architectures use "unsigned long" size_t. + * + * TODO: It's not clean to use __x86_64__ here. It's better + * to check on __BITS_PER_LONG here. But this is wrong set in + * arch/sandbox/include/asm/types.h. + */ +#ifdef __x86_64__ +typedef unsigned long __kernel_size_t; +typedef long __kernel_ssize_t; +typedef long __kernel_ptrdiff_t; +#else +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +#endif +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +#define __FD_SET(fd,fdsetp) \ + __asm__ __volatile__("btsl %1,%0": \ + "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) + +#undef __FD_CLR +#define __FD_CLR(fd,fdsetp) \ + __asm__ __volatile__("btrl %1,%0": \ + "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) + +#undef __FD_ISSET +#define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ + unsigned char __result; \ + __asm__ __volatile__("btl %1,%2 ; setb %0" \ + :"=q" (__result) :"r" ((int) (fd)), \ + "m" (*(__kernel_fd_set *) (fdsetp))); \ + __result; })) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ +do { \ + int __d0, __d1; \ + __asm__ __volatile__("cld ; rep ; stosl" \ + :"=m" (*(__kernel_fd_set *) (fdsetp)), \ + "=&c" (__d0), "=&D" (__d1) \ + :"a" (0), "1" (__FDSET_LONGS), \ + "2" ((__kernel_fd_set *) (fdsetp)) : "memory"); \ +} while (0) + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + +#endif diff --git a/arch/efi/include/asm/sections.h b/arch/efi/include/asm/sections.h new file mode 100644 index 0000000000..2b8c516038 --- /dev/null +++ b/arch/efi/include/asm/sections.h @@ -0,0 +1 @@ +#include diff --git a/arch/efi/include/asm/string.h b/arch/efi/include/asm/string.h new file mode 100644 index 0000000000..2997587d82 --- /dev/null +++ b/arch/efi/include/asm/string.h @@ -0,0 +1 @@ +/* dummy */ diff --git a/arch/efi/include/asm/swab.h b/arch/efi/include/asm/swab.h new file mode 100644 index 0000000000..60a90120b6 --- /dev/null +++ b/arch/efi/include/asm/swab.h @@ -0,0 +1,6 @@ +#ifndef _ASM_SWAB_H +#define _ASM_SWAB_H + +/* nothing. use generic functions */ + +#endif /* _ASM_SWAB_H */ diff --git a/arch/efi/include/asm/types.h b/arch/efi/include/asm/types.h new file mode 100644 index 0000000000..3204448dce --- /dev/null +++ b/arch/efi/include/asm/types.h @@ -0,0 +1,73 @@ +#ifndef __ASM_I386_TYPES_H +#define __ASM_I386_TYPES_H + +#ifndef __ASSEMBLY__ + +#ifdef __x86_64__ +/* + * This is used in dlmalloc. On X86_64 we need it to be + * 64 bit + */ +#define INTERNAL_SIZE_T unsigned long + +/* + * This is a Kconfig variable in the Kernel, but we want to detect + * this during compile time, so we set it here. + */ +#define CONFIG_PHYS_ADDR_T_64BIT + +#endif + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#ifdef __x86_64__ +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; + +#endif /* __KERNEL__ */ + +#endif + +#endif diff --git a/arch/efi/include/asm/unaligned.h b/arch/efi/include/asm/unaligned.h new file mode 100644 index 0000000000..d02da6e60d --- /dev/null +++ b/arch/efi/include/asm/unaligned.h @@ -0,0 +1,19 @@ +#ifndef _ASM_SANDBOX_UNALIGNED_H +#define _ASM_SANDBOX_UNALIGNED_H + +/* + * The architecture sandbox is compiled on can do unaligned accesses itself. + */ + +#include +#include + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define get_unaligned __get_unaligned_le +#define put_unaligned __put_unaligned_le +#else +#define get_unaligned __get_unaligned_be +#define put_unaligned __put_unaligned_be +#endif + +#endif /* _ASM_SANDBOX_UNALIGNED_H */ diff --git a/arch/efi/include/mach/debug_ll.h b/arch/efi/include/mach/debug_ll.h new file mode 100644 index 0000000000..0fb2cb8c2a --- /dev/null +++ b/arch/efi/include/mach/debug_ll.h @@ -0,0 +1,20 @@ +#ifndef __MACH_DEBUG_LL_H__ +#define __MACH_DEBUG_LL_H__ + +#define EFI_DEBUG 0 +#define EFI_DEBUG_CLEAR_MEMORY 0 + +#include +#include + +static inline void PUTC_LL(char c) +{ + uint16_t str[2] = {}; + struct efi_simple_text_output_protocol *con_out = efi_sys_table->con_out; + + str[0] = c; + + con_out->output_string(con_out, str); +} + +#endif diff --git a/arch/efi/include/mach/efi-device.h b/arch/efi/include/mach/efi-device.h new file mode 100644 index 0000000000..fe074a44bb --- /dev/null +++ b/arch/efi/include/mach/efi-device.h @@ -0,0 +1,45 @@ +#ifndef __MACH_EFI_DEVICE_H +#define __MACH_EFI_DEVICE_H + +struct efi_device { + struct device_d dev; + efi_guid_t *guids; + int num_guids; + efi_handle_t handle; + efi_handle_t parent_handle; + void *protocol; + struct efi_device_path *devpath; +}; + +struct efi_driver { + struct driver_d driver; + int (*probe)(struct efi_device *efidev); + void (*remove)(struct efi_device *efidev); + efi_guid_t guid; +}; + +extern struct bus_type efi_bus; + +static inline struct efi_device *to_efi_device(struct device_d *dev) +{ + return container_of(dev, struct efi_device, dev); +} + +static inline struct efi_driver *to_efi_driver(struct driver_d *drv) +{ + return container_of(drv, struct efi_driver, driver); +} + +#define device_efi_driver(drv) \ + register_driver_macro(device, efi, drv) + +static inline int efi_driver_register(struct efi_driver *efidrv) +{ + efidrv->driver.bus = &efi_bus; + return register_driver(&efidrv->driver); +} + +int efi_connect_all(void); +void efi_register_devices(void); + +#endif /* __MACH_EFI_DEVICE_H */ diff --git a/arch/efi/include/mach/efi.h b/arch/efi/include/mach/efi.h new file mode 100644 index 0000000000..1e9782a136 --- /dev/null +++ b/arch/efi/include/mach/efi.h @@ -0,0 +1,24 @@ +#ifndef __MACH_EFI_H +#define __MACH_EFI_H + +#include + +const char *efi_strerror(efi_status_t err); + +extern efi_system_table_t *efi_sys_table; +extern efi_handle_t efi_parent_image; +extern struct efi_device_path *efi_device_path; +extern efi_loaded_image_t *efi_loaded_image; + +int efi_errno(efi_status_t err); + +int efi_clocksource_init(void); + +void *efi_get_variable(char *name, efi_guid_t *vendor, int *var_size); + +static inline void *efi_get_global_var(char *name, int *var_size) +{ + return efi_get_variable(name, &efi_global_variable_guid, var_size); +} + +#endif /* __MACH_EFI_H */ diff --git a/arch/efi/lib/.gitignore b/arch/efi/lib/.gitignore new file mode 100644 index 0000000000..847e317701 --- /dev/null +++ b/arch/efi/lib/.gitignore @@ -0,0 +1,2 @@ +elf_x86_64_efi.lds +elf_ia32_efi.lds diff --git a/arch/efi/lib/Makefile b/arch/efi/lib/Makefile new file mode 100644 index 0000000000..c8a97bae07 --- /dev/null +++ b/arch/efi/lib/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_X86_64) += reloc_x86_64.o crt0-efi-x86_64.o +obj-$(CONFIG_X86_32) += reloc_ia32.o crt0-efi-ia32.o +extra-$(CONFIG_X86_32) += elf_ia32_efi.lds +extra-$(CONFIG_X86_64) += elf_x86_64_efi.lds diff --git a/arch/efi/lib/crt0-efi-ia32.S b/arch/efi/lib/crt0-efi-ia32.S new file mode 100644 index 0000000000..6f0f2e872e --- /dev/null +++ b/arch/efi/lib/crt0-efi-ia32.S @@ -0,0 +1,76 @@ +/* crt0-efi-ia32.S - x86 EFI startup code. + Copyright (C) 1999 Hewlett-Packard Co. + Contributed by David Mosberger . + + 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 Hewlett-Packard Co. 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 ANYDIRECT, 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. +*/ + + .text + .align 4 + + .globl _start +_start: + pushl %ebp + movl %esp,%ebp + + pushl 12(%ebp) # copy "image" argument + pushl 8(%ebp) # copy "systab" argument + + call 0f +0: popl %eax + movl %eax,%ebx + + addl $image_base-0b,%eax # %eax = ldbase + addl $_DYNAMIC-0b,%ebx # %ebx = _DYNAMIC + + pushl %ebx # pass _DYNAMIC as second argument + pushl %eax # pass ldbase as first argument + call _relocate + popl %ebx + popl %ebx + testl %eax,%eax + jne .exit + + call efi_main # call app with "image" and "systab" argument + +.exit: leave + ret + + /* hand-craft a dummy .reloc section so EFI knows it's a relocatable executable: */ + + .data +dummy: .long 0 + +#define IMAGE_REL_ABSOLUTE 0 + .section .reloc + .long dummy /* Page RVA */ + .long 10 /* Block Size (2*4+2) */ + .word (IMAGE_REL_ABSOLUTE<<12) + 0 /* reloc for dummy */ diff --git a/arch/efi/lib/crt0-efi-x86_64.S b/arch/efi/lib/crt0-efi-x86_64.S new file mode 100644 index 0000000000..aa03106e9c --- /dev/null +++ b/arch/efi/lib/crt0-efi-x86_64.S @@ -0,0 +1,75 @@ +/* crt0-efi-x86_64.S - x86_64 EFI startup code. + Copyright (C) 1999 Hewlett-Packard Co. + Contributed by David Mosberger . + Copyright (C) 2005 Intel Co. + Contributed by Fenghua Yu . + + 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 Hewlett-Packard Co. 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 ANYDIRECT, 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. +*/ + .text + .align 4 + + .globl _start +_start: + subq $8, %rsp + pushq %rcx + pushq %rdx + +0: + lea image_base(%rip), %rdi + lea _DYNAMIC(%rip), %rsi + + popq %rcx + popq %rdx + pushq %rcx + pushq %rdx + call _relocate + + popq %rdi + popq %rsi + + call efi_main + addq $8, %rsp + +.exit: + ret + + /* hand-craft a dummy .reloc section so EFI knows it's a relocatable executable: */ + + .data +dummy: .long 0 + +#define IMAGE_REL_ABSOLUTE 0 + .section .reloc, "a" +label1: + .long dummy-label1 /* Page RVA */ + .long 10 /* Block Size (2*4+2) */ + .word (IMAGE_REL_ABSOLUTE<<12) + 0 /* reloc for dummy */ diff --git a/arch/efi/lib/elf_ia32_efi.lds.S b/arch/efi/lib/elf_ia32_efi.lds.S new file mode 100644 index 0000000000..a5f6287500 --- /dev/null +++ b/arch/efi/lib/elf_ia32_efi.lds.S @@ -0,0 +1,102 @@ +#include + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = 0; + image_base = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = ALIGN(4096); + .text : + { + _stext = .; + _text = .; + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + + _etext = .; + + . = ALIGN(4096); + .sdata : { + *(.got.plt) + *(.got) + *(.srodata) + *(.sdata) + *(.sbss) + *(.scommon) + } + + . = ALIGN(4096); + _sdata = .; + + .data : { + *(.rodata*) + *(.data) + *(.data1) + *(.data.*) + *(.sdata) + *(.got.plt) + *(.got) + /* the EFI loader doesn't seem to like a .bss section, so we stick + * it all into .data: */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + + . = ALIGN(64); + + __barebox_initcalls_start = .; + __barebox_initcalls : { INITCALLS } + __barebox_initcalls_end = .; + + . = ALIGN(64); + __barebox_magicvar_start = .; + .barebox_magicvar : { BAREBOX_MAGICVARS } + __barebox_magicvar_end = .; + + . = ALIGN(64); + __barebox_cmd_start = .; + __barebox_cmd : { BAREBOX_CMDS } + __barebox_cmd_end = .; + + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rel : { + *(.rel.data) + *(.rel.data.*) + *(.rel.got) + *(.rel.stab) + *(.data.rel.ro.local) + *(.data.rel.local) + *(.data.rel.ro) + *(.data.rel*) + } + + . = ALIGN(4096); + .reloc : /* This is the PECOFF .reloc section! */ + { + *(.reloc) + } + + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + /DISCARD/ : + { + *(.rel.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + + .comment 0 : { *(.comment) } +} diff --git a/arch/efi/lib/elf_x86_64_efi.lds.S b/arch/efi/lib/elf_x86_64_efi.lds.S new file mode 100644 index 0000000000..d48432d21b --- /dev/null +++ b/arch/efi/lib/elf_x86_64_efi.lds.S @@ -0,0 +1,93 @@ +#include + +/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */ + +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + . = 0; + image_base = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = ALIGN(4096); + .eh_frame : { + *(.eh_frame) + } + + . = ALIGN(4096); + + .text : { + _stext = .; + _text = .; + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + + _etext = .; + + . = ALIGN(4096); + + .reloc : { + *(.reloc) + } + + . = ALIGN(4096); + _sdata = .; + + .data : { + *(.rodata*) + *(.got.plt) + *(.got) + *(.data*) + *(.sdata) + /* the EFI loader doesn't seem to like a .bss section, so we stick + * it all into .data: */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + *(.rel.local) + } + + . = ALIGN(64); + + __barebox_initcalls_start = .; + __barebox_initcalls : { INITCALLS } + __barebox_initcalls_end = .; + + . = ALIGN(64); + __barebox_magicvar_start = .; + .barebox_magicvar : { BAREBOX_MAGICVARS } + __barebox_magicvar_end = .; + + . = ALIGN(64); + __barebox_cmd_start = .; + __barebox_cmd : { BAREBOX_CMDS } + __barebox_cmd_end = .; + + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + + .rela : { + *(.rela.data*) + *(.rela.got) + *(.rela.stab) + } + + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .ignored.reloc : { + *(.rela.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + + .comment 0 : { *(.comment) } +} diff --git a/arch/efi/lib/reloc_ia32.c b/arch/efi/lib/reloc_ia32.c new file mode 100644 index 0000000000..46929631ec --- /dev/null +++ b/arch/efi/lib/reloc_ia32.c @@ -0,0 +1,97 @@ +/* reloc_ia32.c - position independent x86 ELF shared object relocator + Copyright (C) 1999 Hewlett-Packard Co. + Contributed by David Mosberger . + + 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 Hewlett-Packard Co. 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 ANYDIRECT, 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 +#include + +#include + +efi_status_t _relocate(long ldbase, Elf32_Dyn *dyn, efi_handle_t image, efi_system_table_t *systab) +{ + long relsz = 0, relent = 0; + Elf32_Rel *rel = 0; + unsigned long *addr; + int i; + + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { + switch (dyn[i].d_tag) { + case DT_REL: + rel = (Elf32_Rel*) + ((unsigned long)dyn[i].d_un.d_ptr + + ldbase); + break; + + case DT_RELSZ: + relsz = dyn[i].d_un.d_val; + break; + + case DT_RELENT: + relent = dyn[i].d_un.d_val; + break; + + case DT_RELA: + break; + + default: + break; + } + } + + if (!rel && relent == 0) + return EFI_SUCCESS; + + if (!rel || relent == 0) + return EFI_LOAD_ERROR; + + while (relsz > 0) { + /* apply the relocs */ + switch (ELF32_R_TYPE (rel->r_info)) { + case R_386_NONE: + break; + + case R_386_RELATIVE: + addr = (unsigned long *) + (ldbase + rel->r_offset); + *addr += ldbase; + break; + + default: + break; + } + rel = (Elf32_Rel*) ((char *) rel + relent); + relsz -= relent; + } + return EFI_SUCCESS; +} diff --git a/arch/efi/lib/reloc_x86_64.c b/arch/efi/lib/reloc_x86_64.c new file mode 100644 index 0000000000..1db72f5dbc --- /dev/null +++ b/arch/efi/lib/reloc_x86_64.c @@ -0,0 +1,96 @@ +/* reloc_x86_64.c - position independent x86_64 ELF shared object relocator + Copyright (C) 1999 Hewlett-Packard Co. + Contributed by David Mosberger . + Copyright (C) 2005 Intel Co. + Contributed by Fenghua Yu . + + 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 Hewlett-Packard Co. 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 ANYDIRECT, 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 +#include + +#include + +efi_status_t _relocate (long ldbase, Elf64_Dyn *dyn, efi_handle_t image, efi_system_table_t *systab) +{ + long relsz = 0, relent = 0; + Elf64_Rel *rel = 0; + unsigned long *addr; + int i; + + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { + switch (dyn[i].d_tag) { + case DT_RELA: + rel = (Elf64_Rel*) + ((unsigned long)dyn[i].d_un.d_ptr + + ldbase); + break; + + case DT_RELASZ: + relsz = dyn[i].d_un.d_val; + break; + + case DT_RELAENT: + relent = dyn[i].d_un.d_val; + break; + + default: + break; + } + } + + if (!rel && relent == 0) + return EFI_SUCCESS; + + if (!rel || relent == 0) + return EFI_LOAD_ERROR; + + while (relsz > 0) { + /* apply the relocs */ + switch (ELF64_R_TYPE (rel->r_info)) { + case R_X86_64_NONE: + break; + + case R_X86_64_RELATIVE: + addr = (unsigned long *) + (ldbase + rel->r_offset); + *addr += ldbase; + break; + + default: + break; + } + rel = (Elf64_Rel*) ((char *) rel + relent); + relsz -= relent; + } + return EFI_SUCCESS; +} diff --git a/common/Kconfig b/common/Kconfig index bba7f159c1..8b361260c0 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -64,6 +64,14 @@ config MENUTREE select GLOB select GLOB_SORT +config EFI_GUID + bool + help + With this option a table of EFI guids is compiled in. + +config EFI_DEVICEPATH + bool + menu "General Settings" config LOCALVERSION diff --git a/common/Makefile b/common/Makefile index 204241c919..4220e15127 100644 --- a/common/Makefile +++ b/common/Makefile @@ -43,7 +43,9 @@ obj-$(CONFIG_RESET_SOURCE) += reset_source.o obj-$(CONFIG_SHELL_HUSH) += hush.o obj-$(CONFIG_SHELL_SIMPLE) += parser.o obj-$(CONFIG_UIMAGE) += image.o uimage.o -obj-$(CONFIG_MENUTREE) += menutree.o +obj-$(CONFIG_MENUTREE) += menutree.o +obj-$(CONFIG_EFI_GUID) += efi-guid.o +obj-$(CONFIG_EFI_DEVICEPATH) += efi-devicepath.o quiet_cmd_pwd_h = PWDH $@ ifdef CONFIG_PASSWORD diff --git a/common/efi-devicepath.c b/common/efi-devicepath.c new file mode 100644 index 0000000000..2b1d916768 --- /dev/null +++ b/common/efi-devicepath.c @@ -0,0 +1,1370 @@ +#include +#include +#include +#include +#include + +struct string { + char *str; + int len; +}; + +char *cprintf(struct string *str, const char *fmt, ...) + __attribute__ ((format(__printf__, 2, 3))); + +char *cprintf(struct string *str, const char *fmt, ...) +{ + va_list args; + int len; + + va_start(args, fmt); + if (str->str) + len = vsprintf(str->str + str->len, fmt, args); + else + len = vsnprintf(NULL, 0, fmt, args); + va_end(args); + + str->len += len; + + return NULL; +} + +#define MIN_ALIGNMENT_SIZE 8 /* FIXME: X86_64 specific */ +#define ALIGN_SIZE(a) ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0) + +#define EFI_DP_TYPE_MASK 0x7f +#define EFI_DP_TYPE_UNPACKED 0x80 + +#define END_DEVICE_PATH_TYPE 0x7f + +#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff +#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 +#define END_DEVICE_PATH_LENGTH (sizeof(struct efi_device_path)) + +#define DP_IS_END_TYPE(a) +#define DP_IS_END_SUBTYPE(a) ( ((a)->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE ) + +#define device_path_type(a) ( ((a)->type) & EFI_DP_TYPE_MASK ) +#define next_device_path_node(a) ( (struct efi_device_path *) ( ((u8 *) (a)) + (a)->length)) +#define is_device_path_end_type(a) ( device_path_type(a) == END_DEVICE_PATH_TYPE ) +#define is_device_path_end_sub_type(a) ( (a)->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE ) +#define is_device_path_end(a) ( is_device_path_end_type(a) && is_device_path_end_sub_type(a) ) +#define is_device_path_unpacked(a) ( (a)->type & EFI_DP_TYPE_UNPACKED ) + +#define set_device_path_end_node(a) { \ + (a)->type = END_DEVICE_PATH_TYPE; \ + (a)->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE; \ + (a)->length = sizeof(struct efi_device_path); \ + } + +/* + * Hardware Device Path (UEFI 2.4 specification, version 2.4 § 9.3.2.) + */ + +#define HARDWARE_DEVICE_PATH 0x01 + +#define HW_PCI_DP 0x01 +struct pci_device_path { + struct efi_device_path header; + u8 Function; + u8 Device; +}; + +#define HW_PCCARD_DP 0x02 +struct pccard_device_path { + struct efi_device_path header; + u8 function_number; +}; + +#define HW_MEMMAP_DP 0x03 +struct memmap_device_path { + struct efi_device_path header; + u32 memory_type; + efi_physical_addr_t starting_address; + efi_physical_addr_t ending_address; +}; + +#define HW_VENDOR_DP 0x04 +struct vendor_device_path { + struct efi_device_path header; + efi_guid_t Guid; +}; + +struct unknown_device_vendor_device_path { + struct vendor_device_path device_path; + u8 legacy_drive_letter; +}; + +#define HW_CONTROLLER_DP 0x05 +struct controller_device_path { + struct efi_device_path header; + u32 Controller; +}; + +/* + * ACPI Device Path (UEFI 2.4 specification, version 2.4 § 9.3.3 and 9.3.4.) + */ +#define ACPI_DEVICE_PATH 0x02 + +#define ACPI_DP 0x01 +struct acpi_hid_device_path { + struct efi_device_path header; + u32 HID; + u32 UID; +}; + +#define EXPANDED_ACPI_DP 0x02 +struct expanded_acpi_hid_device_path { + struct efi_device_path header; + u32 HID; + u32 UID; + u32 CID; + u8 hid_str[1]; +}; + +#define ACPI_ADR_DP 3 +struct acpi_adr_device_path { + struct efi_device_path header; + u32 ADR; +}; + +/* + * EISA ID Macro + * EISA ID Definition 32-bits + * bits[15:0] - three character compressed ASCII EISA ID. + * bits[31:16] - binary number + * Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z' + */ +#define PNP_EISA_ID_CONST 0x41d0 +#define EISA_ID(_Name, _Num) ((u32) ((_Name) | (_Num) << 16)) +#define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) + +#define PNP_EISA_ID_MASK 0xffff +#define EISA_ID_TO_NUM(_Id) ((_Id) >> 16) + +/* + * Messaging Device Path (UEFI 2.4 specification, version 2.4 § 9.3.5.) + */ +#define MESSAGING_DEVICE_PATH 0x03 + +#define MSG_ATAPI_DP 0x01 +struct atapi_device_path { + struct efi_device_path header; + u8 primary_secondary; + u8 slave_master; + u16 Lun; +}; + +#define MSG_SCSI_DP 0x02 +struct scsi_device_path { + struct efi_device_path header; + u16 Pun; + u16 Lun; +}; + +#define MSG_FIBRECHANNEL_DP 0x03 +struct fibrechannel_device_path { + struct efi_device_path header; + u32 Reserved; + u64 WWN; + u64 Lun; +}; + +/** + * Fibre Channel Ex sub_type. + * UEFI 2.0 specification version 2.4 § 9.3.5.6. + */ +#define MSG_FIBRECHANNELEX_DP 21 +struct fibrechannelex_device_path { + struct efi_device_path header; + u32 Reserved; + u8 WWN[8]; /* World Wide Name */ + u8 Lun[8]; /* Logical unit, T-10 SCSI Architecture Model 4 specification */ +}; + +#define MSG_1394_DP 0x04 +struct f1394_device_path { + struct efi_device_path header; + u32 Reserved; + u64 Guid; +}; + +#define MSG_USB_DP 0x05 +struct usb_device_path { + struct efi_device_path header; + u8 Port; + u8 Endpoint; +}; + +/** + * SATA Device Path sub_type. + * UEFI 2.0 specification version 2.4 § 9.3.5.6. + */ +#define MSG_SATA_DP 18 +struct sata_device_path { + struct efi_device_path header; + u16 HBAPort_number; + u16 port_multiplier_port_number; + u16 Lun; /* Logical Unit Number */ +}; + +/** + * USB WWID Device Path sub_type. + * UEFI 2.0 specification version 2.4 § 9.3.5.7. + */ +#define MSG_USB_WWID_DP 16 +struct usb_wwid_device_path { + struct efi_device_path header; + u16 interface_number; + u16 vendor_id; + u16 product_id; + s16 serial_number[1]; /* UTF-16 characters of the USB serial number */ +}; + +/** + * Device Logical Unit sub_type. + * UEFI 2.0 specification version 2.4 § 9.3.5.8. + */ +#define MSG_DEVICE_LOGICAL_UNIT_DP 17 +struct device_logical_unit_device_path { + struct efi_device_path header; + u8 Lun; /* Logical Unit Number */ +}; + +#define MSG_USB_CLASS_DP 0x0_f +struct usb_class_device_path { + struct efi_device_path header; + u16 vendor_id; + u16 product_id; + u8 device_class; + u8 device_subclass; + u8 device_protocol; +}; + +#define MSG_I2_o_DP 0x06 +struct i2_o_device_path { + struct efi_device_path header; + u32 Tid; +}; + +#define MSG_MAC_ADDR_DP 0x0b +struct mac_addr_device_path { + struct efi_device_path header; + efi_mac_address mac_address; + u8 if_type; +}; + +#define MSG_IPv4_DP 0x0c +struct ipv4_device_path { + struct efi_device_path header; + efi_ipv4_address local_ip_address; + efi_ipv4_address remote_ip_address; + u16 local_port; + u16 remote_port; + u16 Protocol; + bool static_ip_address; + /* new from UEFI version 2, code must check length field in header */ + efi_ipv4_address gateway_ip_address; + efi_ipv4_address subnet_mask; +}; + +#define MSG_IPv6_DP 0x0d +struct ipv6_device_path { + struct efi_device_path header; + efi_ipv6_address local_ip_address; + efi_ipv6_address remote_ip_address; + u16 local_port; + u16 remote_port; + u16 Protocol; + bool IPAddress_origin; + /* new from UEFI version 2, code must check length field in header */ + u8 prefix_length; + efi_ipv6_address gateway_ip_address; +}; + +/** + * Device Logical Unit sub_type. + * UEFI 2.0 specification version 2.4 § 9.3.5.8. + */ +#define MSG_VLAN_DP 20 +struct vlan_device_path { + struct efi_device_path header; + u16 vlan_id; +}; + +#define MSG_INFINIBAND_DP 0x09 +struct infiniband_device_path { + struct efi_device_path header; + u32 resource_flags; + efi_guid_t port_gid; + u64 service_id; + u64 target_port_id; + u64 device_id; +}; + +#define MSG_UART_DP 0x0e +struct uart_device_path { + struct efi_device_path header; + u32 Reserved; + u64 baud_rate; + u8 data_bits; + u8 Parity; + u8 stop_bits; +}; + +#define MSG_VENDOR_DP 0x0a +/* Use VENDOR_DEVICE_PATH struct */ + +#define DEVICE_PATH_MESSAGING_PC_ANSI \ + { 0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define DEVICE_PATH_MESSAGING_VT_100 \ + { 0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define DEVICE_PATH_MESSAGING_VT_100_PLUS \ + { 0x7baec70b , 0x57e0 , 0x4c76 , { 0x8e , 0x87 , 0x2f , 0x9e , 0x28 , 0x08 , 0x83 , 0x43 } } + +#define DEVICE_PATH_MESSAGING_VT_UTF8 \ + { 0xad15a0d6 , 0x8bec , 0x4acf , { 0xa0 , 0x73 , 0xd0 , 0x1d , 0xe7 , 0x7e , 0x2d , 0x88 } } + +#define EFI_PC_ANSI_GUID \ + { 0xe0c14753 , 0xf9be , 0x11d2 , 0x9a , 0x0c , 0x00 , 0x90 , 0x27 , 0x3f , 0xc1 , 0x4d } + +#define EFI_VT_100_GUID \ + { 0xdfa66065 , 0xb419 , 0x11d3 , 0x9a , 0x2d , 0x00 , 0x90 , 0x27 , 0x3f , 0xc1 , 0x4d } + +#define EFI_VT_100_PLUS_GUID \ + { 0x7baec70b , 0x57e0 , 0x4c76 , 0x8e , 0x87 , 0x2f , 0x9e , 0x28 , 0x08 , 0x83 , 0x43 } + +#define EFI_VT_UTF8_GUID \ + { 0xad15a0d6 , 0x8bec , 0x4acf , 0xa0 , 0x73 , 0xd0 , 0x1d , 0xe7 , 0x7e , 0x2d , 0x88 } + +/* + * Media Device Path (UEFI 2.4 specification, version 2.4 § 9.3.6.) + */ +#define MEDIA_DEVICE_PATH 0x04 + +#define MEDIA_HARDDRIVE_DP 0x01 +struct harddrive_device_path { + struct efi_device_path header; + u32 partition_number; + u64 partition_start; + u64 partition_size; + u8 signature[16]; + u8 mbr_type; + u8 signature_type; +}; + +#define MBR_TYPE_PCAT 0x01 +#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02 + +#define SIGNATURE_TYPE_MBR 0x01 +#define SIGNATURE_TYPE_GUID 0x02 + +#define MEDIA_CDROM_DP 0x02 +struct cdrom_device_path { + struct efi_device_path header; + u32 boot_entry; + u64 partition_start; + u64 partition_size; +}; + +#define MEDIA_VENDOR_DP 0x03 +/* Use VENDOR_DEVICE_PATH struct */ + +#define MEDIA_FILEPATH_DP 0x04 +struct filepath_device_path { + struct efi_device_path header; + s16 path_name[1]; +}; + +#define SIZE_OF_FILEPATH_DEVICE_PATH offsetof(FILEPATH_DEVICE_PATH,path_name) + +#define MEDIA_PROTOCOL_DP 0x05 +struct media_protocol_device_path { + struct efi_device_path header; + efi_guid_t Protocol; +}; + +/** + * PIWG Firmware File sub_type. + * UEFI 2.0 specification version 2.4 § 9.3.6.6. + */ +#define MEDIA_PIWG_FW_FILE_DP 6 +struct media_fw_vol_filepath_device_path { + struct efi_device_path header; + efi_guid_t fv_file_name; +}; + +/** + * PIWG Firmware Volume Device Path sub_type. + * UEFI 2.0 specification version 2.4 § 9.3.6.7. + */ +#define MEDIA_PIWG_FW_VOL_DP 7 +struct media_fw_vol_device_path { + struct efi_device_path header; + efi_guid_t fv_name; +}; + +/** + * Media relative offset range device path. + * UEFI 2.0 specification version 2.4 § 9.3.6.8. + */ +#define MEDIA_RELATIVE_OFFSET_RANGE_DP 8 +struct media_relative_offset_range_device_path { + struct efi_device_path header; + u32 Reserved; + u64 starting_offset; + u64 ending_offset; +}; + +/* + * BIOS Boot Specification Device Path (UEFI 2.4 specification, version 2.4 § 9.3.7.) + */ +#define BBS_DEVICE_PATH 0x05 + +#define BBS_BBS_DP 0x01 +struct bbs_bbs_device_path { + struct efi_device_path header; + u16 device_type; + u16 status_flag; + s8 String[1]; +}; + +/* device_type definitions - from BBS specification */ +#define BBS_TYPE_FLOPPY 0x01 +#define BBS_TYPE_HARDDRIVE 0x02 +#define BBS_TYPE_CDROM 0x03 +#define BBS_TYPE_PCMCIA 0x04 +#define BBS_TYPE_USB 0x05 +#define BBS_TYPE_EMBEDDED_NETWORK 0x06 +#define BBS_TYPE_DEV 0x80 +#define BBS_TYPE_UNKNOWN 0x_fF + +struct efi_device_path end_device_path = { + .type = END_DEVICE_PATH_TYPE, + .sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE, + .length = END_DEVICE_PATH_LENGTH, +}; + +struct efi_device_path end_instance_device_path = { + .type = END_DEVICE_PATH_TYPE, + .sub_type = END_INSTANCE_DEVICE_PATH_SUBTYPE, + .length = END_DEVICE_PATH_LENGTH, +}; + +unsigned long +device_path_size(struct efi_device_path *dev_path) +{ + struct efi_device_path *Start; + + Start = dev_path; + while (!is_device_path_end(dev_path)) + dev_path = next_device_path_node(dev_path); + + return ((unsigned long) dev_path - (unsigned long) Start) + + sizeof (struct efi_device_path); +} + +struct efi_device_path * +duplicate_device_path(struct efi_device_path *dev_path) +{ + struct efi_device_path *new_dev_path; + unsigned long Size; + + Size = device_path_size(dev_path); + + new_dev_path = malloc(Size); + if (new_dev_path) + memcpy(new_dev_path, dev_path, Size); + + return new_dev_path; +} + +struct efi_device_path * +device_path_from_handle(efi_handle_t Handle) +{ + efi_status_t Status; + struct efi_device_path *device_path; + + Status = BS->handle_protocol(Handle, &efi_device_path_protocol_guid, + (void *) &device_path); + if (EFI_ERROR(Status)) + device_path = NULL; + + return device_path; +} + +struct efi_device_path * +device_path_instance(struct efi_device_path **device_path, unsigned long *Size) +{ + struct efi_device_path *Start, *Next, *dev_path; + unsigned long Count; + + dev_path = *device_path; + Start = dev_path; + + if (!dev_path) + return NULL; + + for (Count = 0;; Count++) { + Next = next_device_path_node(dev_path); + + if (is_device_path_end_type(dev_path)) + break; + + dev_path = Next; + } + + if (dev_path->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE) + Next = NULL; + + *device_path = Next; + + *Size = ((u8 *) dev_path) - ((u8 *) Start); + + return Start; +} + +unsigned long +device_path_instance_count(struct efi_device_path *device_path) +{ + unsigned long Count, Size; + + Count = 0; + while (device_path_instance(&device_path, &Size)) { + Count += 1; + } + + return Count; +} + +struct efi_device_path * +append_device_path(struct efi_device_path *Src1, struct efi_device_path *Src2) +/* + * Src1 may have multiple "instances" and each instance is appended + * Src2 is appended to each instance is Src1. (E.g., it's possible + * to append a new instance to the complete device path by passing + * it in Src2) + */ +{ + unsigned long src1_size, src1_inst, src2_size, Size; + struct efi_device_path *Dst, *Inst; + u8 *dst_pos; + + if (!Src1) + return duplicate_device_path(Src2); + + if (!Src2) { + return duplicate_device_path(Src1); + } + + src1_size = device_path_size(Src1); + src1_inst = device_path_instance_count(Src1); + src2_size = device_path_size(Src2); + Size = src1_size * src1_inst + src2_size; + + Dst = malloc(Size); + if (Dst) { + dst_pos = (u8 *) Dst; + + /* Copy all device path instances */ + + while ((Inst = device_path_instance(&Src1, &Size))) { + + memcpy(dst_pos, Inst, Size); + dst_pos += Size; + + memcpy(dst_pos, Src2, src2_size); + dst_pos += src2_size; + + memcpy(dst_pos, &end_instance_device_path, + sizeof (struct efi_device_path)); + dst_pos += sizeof (struct efi_device_path); + } + + /* Change last end marker */ + dst_pos -= sizeof (struct efi_device_path); + memcpy(dst_pos, &end_device_path, + sizeof (struct efi_device_path)); + } + + return Dst; +} + +struct efi_device_path * +append_device_path_node(struct efi_device_path *Src1, + struct efi_device_path *Src2) +/* + * Src1 may have multiple "instances" and each instance is appended + * Src2 is a signal device path node (without a terminator) that is + * appended to each instance is Src1. + */ +{ + struct efi_device_path *Temp, *Eop; + unsigned long length; + + /* Build a Src2 that has a terminator on it */ + + length = Src2->length; + Temp = malloc(length + sizeof (struct efi_device_path)); + if (!Temp) + return NULL; + + memcpy(Temp, Src2, length); + Eop = next_device_path_node(Temp); + set_device_path_end_node(Eop); + + /* Append device paths */ + + Src1 = append_device_path(Src1, Temp); + free(Temp); + return Src1; +} + +struct efi_device_path * +unpack_device_path(struct efi_device_path *dev_path) +{ + struct efi_device_path *Src, *Dest, *new_path; + unsigned long Size; + + /* Walk device path and round sizes to valid boundries */ + + Src = dev_path; + Size = 0; + for (;;) { + Size += Src->length; + Size += ALIGN_SIZE(Size); + + if (is_device_path_end(Src)) { + break; + } + + Src = next_device_path_node(Src); + } + + new_path = xzalloc(Size); + + Src = dev_path; + Dest = new_path; + for (;;) { + Size = Src->length; + memcpy(Dest, Src, Size); + Size += ALIGN_SIZE(Size); + Dest->length = Size; + Dest->type |= EFI_DP_TYPE_UNPACKED; + Dest = + (struct efi_device_path *) (((u8 *) Dest) + Size); + + if (is_device_path_end(Src)) + break; + + Src = next_device_path_node(Src); + } + + return new_path; +} + +struct efi_device_path * +append_device_path_instance(struct efi_device_path *Src, + struct efi_device_path *Instance) +{ + u8 *Ptr; + struct efi_device_path *dev_path; + unsigned long src_size; + unsigned long instance_size; + + if (Src == NULL) + return duplicate_device_path(Instance); + + src_size = device_path_size(Src); + instance_size = device_path_size(Instance); + Ptr = malloc(src_size + instance_size); + dev_path = (struct efi_device_path *) Ptr; + + memcpy(Ptr, Src, src_size); + + while (!is_device_path_end(dev_path)) + dev_path = next_device_path_node(dev_path); + + /* + * Convert the End to an End Instance, since we are + * appending another instacne after this one its a good + * idea. + */ + dev_path->sub_type = END_INSTANCE_DEVICE_PATH_SUBTYPE; + + dev_path = next_device_path_node(dev_path); + memcpy(dev_path, Instance, instance_size); + + return (struct efi_device_path *) Ptr; +} + +efi_status_t +lib_device_path_to_interface(efi_guid_t * Protocol, + struct efi_device_path *file_path, + void **Interface) +{ + efi_status_t Status; + efi_handle_t Device; + + Status = BS->locate_device_path(Protocol, &file_path, &Device); + + if (!EFI_ERROR(Status)) { + + /* If we didn't get a direct match return not found */ + Status = EFI_NOT_FOUND; + + if (is_device_path_end(file_path)) { + + /* It was a direct match, lookup the protocol interface */ + + Status = + BS->handle_protocol(Device, Protocol, Interface); + } + } + + if (EFI_ERROR(Status)) + *Interface = NULL; + + return Status; +} + +static void +dev_path_pci(struct string *str, void *dev_path) +{ + struct pci_device_path *Pci; + + Pci = dev_path; + cprintf(str, "Pci(0x%x,0x%x)", Pci->Device, Pci->Function); +} + +static void +dev_path_pccard(struct string *str, void *dev_path) +{ + struct pccard_device_path *Pccard; + + Pccard = dev_path; + cprintf(str, "Pccard(0x%x)", Pccard->function_number); +} + +static void +dev_path_mem_map(struct string *str, void *dev_path) +{ + struct memmap_device_path *mem_map; + + mem_map = dev_path; + cprintf(str, "mem_map(%d,0x%llx,0x%llx)", + mem_map->memory_type, + mem_map->starting_address, mem_map->ending_address); +} + +static void +dev_path_controller(struct string *str, void *dev_path) +{ + struct controller_device_path *Controller; + + Controller = dev_path; + cprintf(str, "Ctrl(%d)", Controller->Controller); +} + +static void +dev_path_vendor(struct string *str, void *dev_path) +{ + struct vendor_device_path *Vendor; + char *type; + struct unknown_device_vendor_device_path *unknown_dev_path; + + Vendor = dev_path; + switch (device_path_type(&Vendor->header)) { + case HARDWARE_DEVICE_PATH: + type = "Hw"; + break; + case MESSAGING_DEVICE_PATH: + type = "Msg"; + break; + case MEDIA_DEVICE_PATH: + type = "Media"; + break; + default: + type = "?"; + break; + } + + cprintf(str, "Ven%s(%pU", type, &Vendor->Guid); + if (efi_compare_guid(&Vendor->Guid, &efi_unknown_device_guid) == 0) { + /* GUID used by EFI to enumerate an EDD 1.1 device */ + unknown_dev_path = + (struct unknown_device_vendor_device_path *) Vendor; + cprintf(str, ":%02x)", unknown_dev_path->legacy_drive_letter); + } else { + cprintf(str, ")"); + } +} + +/* + type: 2 (ACPI Device Path) sub_type: 1 (ACPI Device Path) + */ +static void +dev_path_acpi(struct string *str, void *dev_path) +{ + struct acpi_hid_device_path *Acpi; + + Acpi = dev_path; + if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + switch (EISA_ID_TO_NUM(Acpi->HID)) { + case 0x301: + cprintf(str, "Keyboard(%d)", Acpi->UID); + break; + + case 0x401: + cprintf(str, "parallel_port(%d)", Acpi->UID); + break; + case 0x501: + cprintf(str, "Serial(%d)", Acpi->UID); + break; + case 0x604: + cprintf(str, "Floppy(%d)", Acpi->UID); + break; + case 0xa03: + cprintf(str, "pci_root(%d)", Acpi->UID); + break; + case 0xa08: + cprintf(str, "pcie_root(%d)", Acpi->UID); + break; + default: + cprintf(str, "Acpi(PNP%04x", + EISA_ID_TO_NUM(Acpi->HID)); + if (Acpi->UID) + cprintf(str, ",%d", Acpi->UID); + cprintf(str, ")"); + break; + } + } else { + cprintf(str, "Acpi(0x%X", Acpi->HID); + if (Acpi->UID) + cprintf(str, ",%d", Acpi->UID); + cprintf(str, ")"); + } +} + +static void +dev_path_atapi(struct string *str, void *dev_path) +{ + struct atapi_device_path *Atapi; + + Atapi = dev_path; + cprintf(str, "Ata(%s,%s)", + Atapi->primary_secondary ? "Secondary" : "Primary", + Atapi->slave_master ? "Slave" : "Master"); +} + +static void +dev_path_scsi(struct string *str, void *dev_path) +{ + struct scsi_device_path *Scsi; + + Scsi = dev_path; + cprintf(str, "Scsi(%d,%d)", Scsi->Pun, Scsi->Lun); +} + +static void +dev_path_fibre(struct string *str, void *dev_path) +{ + struct fibrechannel_device_path *Fibre; + + Fibre = dev_path; + cprintf(str, "Fibre%s(0x%016llx,0x%016llx)", + device_path_type(&Fibre->header) == + MSG_FIBRECHANNEL_DP ? "" : "Ex", Fibre->WWN, Fibre->Lun); +} + +static void +dev_path1394(struct string *str, void *dev_path) +{ + struct f1394_device_path *F1394; + + F1394 = dev_path; + cprintf(str, "1394(%pU)", &F1394->Guid); +} + +static void +dev_path_usb(struct string *str, void *dev_path) +{ + struct usb_device_path *Usb; + + Usb = dev_path; + cprintf(str, "Usb(0x%x,0x%x)", Usb->Port, Usb->Endpoint); +} + +static void +dev_path_i2_o(struct string *str, void *dev_path) +{ + struct i2_o_device_path *i2_o; + + i2_o = dev_path; + cprintf(str, "i2_o(0x%X)", i2_o->Tid); +} + +static void +dev_path_mac_addr(struct string *str, void *dev_path) +{ + struct mac_addr_device_path *MAC; + unsigned long hw_address_size; + unsigned long Index; + + MAC = dev_path; + + /* hw_address_size = sizeof(EFI_MAC_ADDRESS); */ + hw_address_size = MAC->header.length; + hw_address_size -= sizeof (MAC->header); + hw_address_size -= sizeof (MAC->if_type); + if (MAC->if_type == 0x01 || MAC->if_type == 0x00) + hw_address_size = 6; + + cprintf(str, "Mac("); + + for (Index = 0; Index < hw_address_size; Index++) + cprintf(str, "%02x", MAC->mac_address.Addr[Index]); + + if (MAC->if_type != 0) + cprintf(str, ",%d", MAC->if_type); + + cprintf(str, ")"); +} + +static void +cat_print_iPv4(struct string *str, efi_ipv4_address * address) +{ + cprintf(str, "%d.%d.%d.%d", address->Addr[0], address->Addr[1], + address->Addr[2], address->Addr[3]); +} + +static bool +is_not_null_iPv4(efi_ipv4_address * address) +{ + u8 val; + + val = address->Addr[0] | address->Addr[1]; + val |= address->Addr[2] | address->Addr[3]; + + return val != 0; +} + +static void +cat_print_network_protocol(struct string *str, u16 Proto) +{ + if (Proto == 6) + cprintf(str, "TCP"); + else if (Proto == 17) + cprintf(str, "UDP"); + else + cprintf(str, "%d", Proto); +} + +static void +dev_path_iPv4(struct string *str, void *dev_path) +{ + struct ipv4_device_path *ip; + bool show; + + ip = dev_path; + cprintf(str, "IPv4("); + cat_print_iPv4(str, &ip->remote_ip_address); + cprintf(str, ","); + cat_print_network_protocol(str, ip->Protocol); + cprintf(str, ",%s", ip->static_ip_address ? "Static" : "DHCP"); + show = is_not_null_iPv4(&ip->local_ip_address); + if (!show + && ip->header.length == + sizeof (struct ipv4_device_path)) { + /* only version 2 includes gateway and netmask */ + show |= is_not_null_iPv4(&ip->gateway_ip_address); + show |= is_not_null_iPv4(&ip->subnet_mask); + } + if (show) { + cprintf(str, ","); + cat_print_iPv4(str, &ip->local_ip_address); + if (ip->header.length == + sizeof (struct ipv4_device_path)) { + /* only version 2 includes gateway and netmask */ + show = is_not_null_iPv4(&ip->gateway_ip_address); + show |= is_not_null_iPv4(&ip->subnet_mask); + if (show) { + cprintf(str, ","); + cat_print_iPv4(str, &ip->gateway_ip_address); + if (is_not_null_iPv4(&ip->subnet_mask)) { + cprintf(str, ","); + cat_print_iPv4(str, &ip->subnet_mask); + } + } + } + } + cprintf(str, ")"); +} + +#define cat_print_iPv6_ADD( x , y ) ( ( (u16) ( x ) ) << 8 | ( y ) ) +static void +cat_print_ipv6(struct string *str, efi_ipv6_address * address) +{ + cprintf(str, "%x:%x:%x:%x:%x:%x:%x:%x", + cat_print_iPv6_ADD(address->Addr[0], address->Addr[1]), + cat_print_iPv6_ADD(address->Addr[2], address->Addr[3]), + cat_print_iPv6_ADD(address->Addr[4], address->Addr[5]), + cat_print_iPv6_ADD(address->Addr[6], address->Addr[7]), + cat_print_iPv6_ADD(address->Addr[8], address->Addr[9]), + cat_print_iPv6_ADD(address->Addr[10], address->Addr[11]), + cat_print_iPv6_ADD(address->Addr[12], address->Addr[13]), + cat_print_iPv6_ADD(address->Addr[14], address->Addr[15])); +} + +static void +dev_path_iPv6(struct string *str, void *dev_path) +{ + struct ipv6_device_path *ip; + + ip = dev_path; + cprintf(str, "IPv6("); + cat_print_ipv6(str, &ip->remote_ip_address); + cprintf(str, ","); + cat_print_network_protocol(str, ip->Protocol); + cprintf(str, ",%s,", ip->IPAddress_origin ? + (ip->IPAddress_origin == 1 ? "stateless_auto_configure" : + "stateful_auto_configure") : "Static"); + cat_print_ipv6(str, &ip->local_ip_address); + if (ip->header.length == + sizeof (struct ipv6_device_path)) { + cprintf(str, ","); + cat_print_ipv6(str, &ip->gateway_ip_address); + cprintf(str, ","); + cprintf(str, "%d", ip->prefix_length); + } + cprintf(str, ")"); +} + +static void +dev_path_infini_band(struct string *str, void *dev_path) +{ + struct infiniband_device_path *infini_band; + + infini_band = dev_path; + cprintf(str, "Infiniband(0x%x,%pU,0x%llx,0x%llx,0x%llx)", + infini_band->resource_flags, &infini_band->port_gid, + infini_band->service_id, infini_band->target_port_id, + infini_band->device_id); +} + +static void +dev_path_uart(struct string *str, void *dev_path) +{ + struct uart_device_path *Uart; + s8 Parity; + + Uart = dev_path; + switch (Uart->Parity) { + case 0: + Parity = 'D'; + break; + case 1: + Parity = 'N'; + break; + case 2: + Parity = 'E'; + break; + case 3: + Parity = 'O'; + break; + case 4: + Parity = 'M'; + break; + case 5: + Parity = 'S'; + break; + default: + Parity = 'x'; + break; + } + + if (Uart->baud_rate == 0) + cprintf(str, "Uart(DEFAULT %c", Parity); + else + cprintf(str, "Uart(%lld %c", Uart->baud_rate, Parity); + + if (Uart->data_bits == 0) + cprintf(str, "D"); + else + cprintf(str, "%d", Uart->data_bits); + + switch (Uart->stop_bits) { + case 0: + cprintf(str, "D)"); + break; + case 1: + cprintf(str, "1)"); + break; + case 2: + cprintf(str, "1.5)"); + break; + case 3: + cprintf(str, "2)"); + break; + default: + cprintf(str, "x)"); + break; + } +} + +static void +dev_path_sata(struct string *str, void *dev_path) +{ + struct sata_device_path *sata; + + sata = dev_path; + cprintf(str, "Sata(0x%x,0x%x,0x%x)", sata->HBAPort_number, + sata->port_multiplier_port_number, sata->Lun); +} + +static void +dev_path_hard_drive(struct string *str, void *dev_path) +{ + struct harddrive_device_path *hd; + + hd = dev_path; + switch (hd->signature_type) { + case SIGNATURE_TYPE_MBR: + cprintf(str, "HD(Part%d,Sig%08x)", + hd->partition_number, *((u32 *) (&(hd->signature[0]))) + ); + break; + case SIGNATURE_TYPE_GUID: + cprintf(str, "HD(Part%d,Sig%pU)", + hd->partition_number, + (efi_guid_t *) & (hd->signature[0]) + ); + break; + default: + cprintf(str, "HD(Part%d,mbr_type=%02x,sig_type=%02x)", + hd->partition_number, hd->mbr_type, hd->signature_type); + break; + } +} + +static void +dev_path_cdrom(struct string *str, void *dev_path) +{ + struct cdrom_device_path *cd; + + cd = dev_path; + cprintf(str, "CDROM(0x%x)", cd->boot_entry); +} + +static void +dev_path_file_path(struct string *str, void *dev_path) +{ + struct filepath_device_path *Fp; + char *dst; + + Fp = dev_path; + + dst = strdup_wchar_to_char(Fp->path_name); + + cprintf(str, "%s", dst); + + free(dst); +} + +static void +dev_path_media_protocol(struct string *str, void *dev_path) +{ + struct media_protocol_device_path *media_prot; + + media_prot = dev_path; + cprintf(str, "%pU", &media_prot->Protocol); +} + +static void +dev_path_bss_bss(struct string *str, void *dev_path) +{ + struct bbs_bbs_device_path *Bss; + char *type; + + Bss = dev_path; + switch (Bss->device_type) { + case BBS_TYPE_FLOPPY: + type = "Floppy"; + break; + case BBS_TYPE_HARDDRIVE: + type = "Harddrive"; + break; + case BBS_TYPE_CDROM: + type = "CDROM"; + break; + case BBS_TYPE_PCMCIA: + type = "PCMCIA"; + break; + case BBS_TYPE_USB: + type = "Usb"; + break; + case BBS_TYPE_EMBEDDED_NETWORK: + type = "Net"; + break; + default: + type = "?"; + break; + } + + cprintf(str, "Bss-%s(%s)", type, Bss->String); +} + +static void +dev_path_end_instance(struct string *str, void *dev_path) +{ + cprintf(str, ","); +} + +/** + * Print unknown device node. + * UEFI 2.4 § 9.6.1.6 table 89. + */ + +static void +dev_path_node_unknown(struct string *str, void *dev_path) +{ + struct efi_device_path *Path; + u8 *value; + int length, index; + Path = dev_path; + value = dev_path; + value += 4; + switch (Path->type) { + case HARDWARE_DEVICE_PATH:{ + /* Unknown Hardware Device Path */ + cprintf(str, "hardware_path(%d", Path->sub_type); + break; + } + case ACPI_DEVICE_PATH:{/* Unknown ACPI Device Path */ + cprintf(str, "acpi_path(%d", Path->sub_type); + break; + } + case MESSAGING_DEVICE_PATH:{ + /* Unknown Messaging Device Path */ + cprintf(str, "Msg(%d", Path->sub_type); + break; + } + case MEDIA_DEVICE_PATH:{ + /* Unknown Media Device Path */ + cprintf(str, "media_path(%d", Path->sub_type); + break; + } + case BBS_DEVICE_PATH:{ /* Unknown BIOS Boot Specification Device Path */ + cprintf(str, "bbs_path(%d", Path->sub_type); + break; + } + default:{ /* Unknown Device Path */ + cprintf(str, "Path(%d,%d", Path->type, Path->sub_type); + break; + } + } + length = Path->length; + for (index = 0; index < length; index++) { + if (index == 0) + cprintf(str, ",0x"); + cprintf(str, "%02x", *value); + value++; + } + cprintf(str, ")"); +} + +/* + * Table to convert "type" and "sub_type" to a "convert to text" function/ + * Entries hold "type" and "sub_type" for know values. + * Special "sub_type" 0 is used as default for known type with unknown subtype. + */ +struct { + u8 type; + u8 sub_type; + void (*Function) (struct string *, void *); +} dev_path_table[] = { + { + HARDWARE_DEVICE_PATH, HW_PCI_DP, dev_path_pci}, { + HARDWARE_DEVICE_PATH, HW_PCCARD_DP, dev_path_pccard}, { + HARDWARE_DEVICE_PATH, HW_MEMMAP_DP, dev_path_mem_map}, { + HARDWARE_DEVICE_PATH, HW_VENDOR_DP, dev_path_vendor}, { + HARDWARE_DEVICE_PATH, HW_CONTROLLER_DP, dev_path_controller}, { + ACPI_DEVICE_PATH, ACPI_DP, dev_path_acpi}, { + MESSAGING_DEVICE_PATH, MSG_ATAPI_DP, dev_path_atapi}, { + MESSAGING_DEVICE_PATH, MSG_SCSI_DP, dev_path_scsi}, { + MESSAGING_DEVICE_PATH, MSG_FIBRECHANNEL_DP, dev_path_fibre}, { + MESSAGING_DEVICE_PATH, MSG_1394_DP, dev_path1394}, { + MESSAGING_DEVICE_PATH, MSG_USB_DP, dev_path_usb}, { + MESSAGING_DEVICE_PATH, MSG_I2_o_DP, dev_path_i2_o}, { + MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, dev_path_mac_addr}, { + MESSAGING_DEVICE_PATH, MSG_IPv4_DP, dev_path_iPv4}, { + MESSAGING_DEVICE_PATH, MSG_IPv6_DP, dev_path_iPv6}, { + MESSAGING_DEVICE_PATH, MSG_INFINIBAND_DP, dev_path_infini_band}, { + MESSAGING_DEVICE_PATH, MSG_UART_DP, dev_path_uart}, { + MESSAGING_DEVICE_PATH, MSG_SATA_DP, dev_path_sata}, { + MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, dev_path_vendor}, { + MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, dev_path_hard_drive}, { + MEDIA_DEVICE_PATH, MEDIA_CDROM_DP, dev_path_cdrom}, { + MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, dev_path_vendor}, { + MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP, dev_path_file_path}, { + MEDIA_DEVICE_PATH, MEDIA_PROTOCOL_DP, dev_path_media_protocol}, { + BBS_DEVICE_PATH, BBS_BBS_DP, dev_path_bss_bss}, { + END_DEVICE_PATH_TYPE, END_INSTANCE_DEVICE_PATH_SUBTYPE, + dev_path_end_instance}, { + 0, 0, NULL} +}; + +static int __device_path_to_str(struct string *str, struct efi_device_path *dev_path) +{ + struct efi_device_path *dev_path_node; + void (*dump_node) (struct string *, void *); + int i; + + dev_path = unpack_device_path(dev_path); + + dev_path_node = dev_path; + while (!is_device_path_end(dev_path_node)) { + dump_node = NULL; + for (i = 0; dev_path_table[i].Function; i += 1) { + + if (device_path_type(dev_path_node) == + dev_path_table[i].type + && dev_path_node->sub_type == + dev_path_table[i].sub_type) { + dump_node = dev_path_table[i].Function; + break; + } + } + + if (!dump_node) + dump_node = dev_path_node_unknown; + + if (str->len && dump_node != dev_path_end_instance) + cprintf(str, "/"); + + dump_node(str, dev_path_node); + + dev_path_node = next_device_path_node(dev_path_node); + } + + return 0; +} + +char *device_path_to_str(struct efi_device_path *dev_path) +{ + struct string str = {}; + + __device_path_to_str(&str, dev_path); + + str.str = malloc(str.len + 1); + if (!str.str) + return NULL; + + str.len = 0; + + __device_path_to_str(&str, dev_path); + + return str.str; +} diff --git a/common/efi-guid.c b/common/efi-guid.c new file mode 100644 index 0000000000..5109b5da04 --- /dev/null +++ b/common/efi-guid.c @@ -0,0 +1,11 @@ +#include +#include + +efi_guid_t efi_file_info_id = EFI_FILE_INFO_GUID; +efi_guid_t efi_simple_file_system_protocol_guid = EFI_SIMPLE_FILE_SYSTEM_GUID; +efi_guid_t efi_device_path_protocol_guid = EFI_DEVICE_PATH_PROTOCOL_GUID; +efi_guid_t efi_loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; +efi_guid_t efi_unknown_device_guid = EFI_UNKNOWN_DEVICE_GUID; +efi_guid_t efi_null_guid = EFI_NULL_GUID; +efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID; +efi_guid_t efi_block_io_protocol_guid = EFI_BLOCK_IO_PROTOCOL_GUID; diff --git a/common/memory.c b/common/memory.c index 7dbd7f4399..4a8fe283f2 100644 --- a/common/memory.c +++ b/common/memory.c @@ -58,7 +58,7 @@ void mem_malloc_init(void *start, void *end) #endif } -#ifndef __SANDBOX__ +#if !defined __SANDBOX__ && !defined CONFIG_ARCH_EFI static int mem_malloc_resource(void) { /* diff --git a/common/partitions/efi.c b/common/partitions/efi.c index ee1326e622..dcb95414f6 100644 --- a/common/partitions/efi.c +++ b/common/partitions/efi.c @@ -232,7 +232,7 @@ static int is_gpt_valid(struct block_device *blk, u64 lba, static inline int is_pte_valid(const gpt_entry *pte, const u64 lastlba) { - if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) || + if ((!efi_guidcmp(pte->partition_type_guid, EFI_NULL_GUID)) || le64_to_cpu(pte->starting_lba) > lastlba || le64_to_cpu(pte->ending_lba) > lastlba) return 0; diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 45f77a759f..2b28cf3fb4 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -4,7 +4,7 @@ config OFTREE config OFTREE_MEM_GENERIC depends on OFTREE - depends on PPC || ARM + depends on PPC || ARM || ARCH_EFI def_bool y config DTC diff --git a/include/efi.h b/include/efi.h index 9911fa1e8c..f027712cd3 100644 --- a/include/efi.h +++ b/include/efi.h @@ -14,6 +14,14 @@ #include #include +#ifdef CONFIG_ARCH_EFI +#define EFIAPI __attribute__((ms_abi)) +#else +#define EFIAPI +#endif + +struct efi_device_path; + #define EFI_SUCCESS 0 #define EFI_LOAD_ERROR ( 1 | (1UL << (BITS_PER_LONG-1))) #define EFI_INVALID_PARAMETER ( 2 | (1UL << (BITS_PER_LONG-1))) @@ -52,13 +60,15 @@ typedef unsigned long efi_status_t; typedef u8 efi_bool_t; typedef u16 efi_char16_t; /* UNICODE character */ +typedef u64 efi_physical_addr_t; +typedef void *efi_handle_t; typedef struct { u8 b[16]; } efi_guid_t; -#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ +#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ ((efi_guid_t) \ {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ (b) & 0xff, ((b) >> 8) & 0xff, \ @@ -109,22 +119,7 @@ typedef struct { #define EFI_MEMORY_DESCRIPTOR_VERSION 1 #define EFI_PAGE_SHIFT 12 - -typedef struct { - u32 type; - u32 pad; - u64 phys_addr; - u64 virt_addr; - u64 num_pages; - u64 attribute; -} efi_memory_desc_t; - -typedef struct { - efi_guid_t guid; - u32 headersize; - u32 flags; - u32 imagesize; -} efi_capsule_header_t; +#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT) /* * Allocation types for calls to boottime->allocate_pages. @@ -163,6 +158,19 @@ typedef struct { u8 sets_to_zero; } efi_time_cap_t; +enum efi_locate_search_type { + all_handles, + by_register_notify, + by_protocol +}; + +struct efi_open_protocol_information_entry { + efi_handle_t agent_handle; + efi_handle_t controller_handle; + u32 attributes; + u32 open_count; +}; + /* * EFI Boot Services table */ @@ -170,41 +178,69 @@ typedef struct { efi_table_hdr_t hdr; void *raise_tpl; void *restore_tpl; - void *allocate_pages; - void *free_pages; - void *get_memory_map; - void *allocate_pool; - void *free_pool; + efi_status_t (EFIAPI *allocate_pages)(int, int, unsigned long, + efi_physical_addr_t *); + efi_status_t (EFIAPI *free_pages)(efi_physical_addr_t, unsigned long); + efi_status_t (EFIAPI *get_memory_map)(unsigned long *, void *, unsigned long *, + unsigned long *, u32 *); + efi_status_t (EFIAPI *allocate_pool)(int, unsigned long, void **); + efi_status_t (EFIAPI *free_pool)(void *); void *create_event; void *set_timer; - void *wait_for_event; + efi_status_t(EFIAPI *wait_for_event)(unsigned long number_of_events, void *event, + unsigned long *index); void *signal_event; void *close_event; void *check_event; void *install_protocol_interface; void *reinstall_protocol_interface; void *uninstall_protocol_interface; - void *handle_protocol; + efi_status_t (EFIAPI *handle_protocol)(efi_handle_t, efi_guid_t *, void **); void *__reserved; void *register_protocol_notify; - void *locate_handle; - void *locate_device_path; + efi_status_t (EFIAPI *locate_handle) (enum efi_locate_search_type search_type, + efi_guid_t *protocol, void *search_key, + unsigned long *buffer_size, efi_handle_t *buffer); + efi_status_t (EFIAPI *locate_device_path)(efi_guid_t *protocol, + struct efi_device_path **device_path, efi_handle_t *device); void *install_configuration_table; - void *load_image; - void *start_image; - void *exit; + efi_status_t (EFIAPI *load_image)(bool boot_policiy, efi_handle_t parent_image, + struct efi_device_path *file_path, void *source_buffer, + unsigned long source_size, efi_handle_t *image); + efi_status_t (EFIAPI *start_image)(efi_handle_t handle, + unsigned long *exitdata_size, s16 **exitdata); + efi_status_t(EFIAPI *exit)(efi_handle_t handle, efi_status_t exit_status, + unsigned long exitdata_size, s16 *exitdata); void *unload_image; - void *exit_boot_services; + efi_status_t (EFIAPI *exit_boot_services)(efi_handle_t, unsigned long); void *get_next_monotonic_count; - void *stall; + efi_status_t (EFIAPI *stall)(unsigned long usecs); void *set_watchdog_timer; - void *connect_controller; + efi_status_t(EFIAPI *connect_controller)(efi_handle_t controller_handle, + efi_handle_t *driver_image_handle, + struct efi_device_path *remaining_device_path, + bool Recursive); void *disconnect_controller; - void *open_protocol; +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + efi_status_t (EFIAPI *open_protocol)(efi_handle_t handle, efi_guid_t *protocol, + void ** interface, efi_handle_t agent_handle, + efi_handle_t controller_handle, u32 attributes); void *close_protocol; - void *open_protocol_information; - void *protocols_per_handle; - void *locate_handle_buffer; + efi_status_t(EFIAPI *open_protocol_information)(efi_handle_t handle, efi_guid_t *Protocol, + struct efi_open_protocol_information_entry **entry_buffer, + unsigned long *entry_count); + efi_status_t (EFIAPI *protocols_per_handle)(efi_handle_t handle, + efi_guid_t ***protocol_buffer, + unsigned long *protocols_buffer_count); + efi_status_t (EFIAPI *locate_handle_buffer) ( + enum efi_locate_search_type search_type, + efi_guid_t *protocol, void *search_key, + unsigned long *no_handles, efi_handle_t **buffer); void *locate_protocol; void *install_multiple_protocol_interfaces; void *uninstall_multiple_protocol_interfaces; @@ -214,6 +250,8 @@ typedef struct { void *create_event_ex; } efi_boot_services_t; +extern efi_boot_services_t *BS; + /* * Types and defines for EFI ResetSystem */ @@ -229,90 +267,63 @@ typedef struct { typedef struct { efi_table_hdr_t hdr; - unsigned long get_time; - unsigned long set_time; - unsigned long get_wakeup_time; - unsigned long set_wakeup_time; - unsigned long set_virtual_address_map; - unsigned long convert_pointer; - unsigned long get_variable; - unsigned long get_next_variable; - unsigned long set_variable; - unsigned long get_next_high_mono_count; - unsigned long reset_system; - unsigned long update_capsule; - unsigned long query_capsule_caps; - unsigned long query_variable_info; + void *get_time; + void *set_time; + void *get_wakeup_time; + void *set_wakeup_time; + void *set_virtual_address_map; + void *convert_pointer; + efi_status_t (EFIAPI *get_variable)(s16 *variable_name, efi_guid_t *vendor, + u32 *Attributes, unsigned long *data_size, void *data); + efi_status_t (EFIAPI *get_next_variable)(unsigned long *variable_name_size, + s16 *variable_name, efi_guid_t *vendor); + void *set_variable; + void *get_next_high_mono_count; + void *reset_system; + void *update_capsule; + void *query_capsule_caps; + void *query_variable_info; } efi_runtime_services_t; -typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc); -typedef efi_status_t efi_set_time_t (efi_time_t *tm); -typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending, - efi_time_t *tm); -typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm); -typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, - unsigned long *data_size, void *data); -typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name, - efi_guid_t *vendor); -typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, - u32 attr, unsigned long data_size, - void *data); -typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count); -typedef void efi_reset_system_t (int reset_type, efi_status_t status, - unsigned long data_size, efi_char16_t *data); -typedef efi_status_t efi_set_virtual_address_map_t (unsigned long memory_map_size, - unsigned long descriptor_size, - u32 descriptor_version, - efi_memory_desc_t *virtual_map); -typedef efi_status_t efi_query_variable_info_t(u32 attr, - u64 *storage_space, - u64 *remaining_space, - u64 *max_variable_size); -typedef efi_status_t efi_update_capsule_t(efi_capsule_header_t **capsules, - unsigned long count, - unsigned long sg_list); -typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules, - unsigned long count, - u64 *max_size, - int *reset_type); +extern efi_runtime_services_t *RT; /* * EFI Configuration Table and GUID definitions */ -#define NULL_GUID \ +#define EFI_NULL_GUID \ EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) -#define MPS_TABLE_GUID \ +#define EFI_MPS_TABLE_GUID \ EFI_GUID( 0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) -#define ACPI_TABLE_GUID \ +#define EFI_ACPI_TABLE_GUID \ EFI_GUID( 0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) -#define ACPI_20_TABLE_GUID \ +#define EFI_ACPI_20_TABLE_GUID \ EFI_GUID( 0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 ) -#define SMBIOS_TABLE_GUID \ +#define EFI_SMBIOS_TABLE_GUID \ EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) -#define SAL_SYSTEM_TABLE_GUID \ +#define EFI_SAL_SYSTEM_TABLE_GUID \ EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) -#define HCDP_TABLE_GUID \ +#define EFI_HCDP_TABLE_GUID \ EFI_GUID( 0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 ) -#define UGA_IO_PROTOCOL_GUID \ +#define EFI_UGA_IO_PROTOCOL_GUID \ EFI_GUID( 0x61a4d49e, 0x6f68, 0x4f1b, 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0xb, 0x7, 0xa2 ) #define EFI_GLOBAL_VARIABLE_GUID \ EFI_GUID( 0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c ) -#define UV_SYSTEM_TABLE_GUID \ +#define EFI_UV_SYSTEM_TABLE_GUID \ EFI_GUID( 0x3b13a7d4, 0x633e, 0x11dd, 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93 ) -#define LINUX_EFI_CRASH_GUID \ +#define EFI_LINUX_EFI_CRASH_GUID \ EFI_GUID( 0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0 ) -#define LOADED_IMAGE_PROTOCOL_GUID \ +#define EFI_LOADED_IMAGE_PROTOCOL_GUID \ EFI_GUID( 0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b ) #define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ @@ -324,26 +335,38 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules, #define EFI_PCI_IO_PROTOCOL_GUID \ EFI_GUID( 0x4cf5b200, 0x68b8, 0x4ca5, 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a ) -#define EFI_FILE_INFO_ID \ +#define EFI_FILE_INFO_GUID \ EFI_GUID( 0x9576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b ) -#define EFI_FILE_SYSTEM_GUID \ +#define EFI_SIMPLE_FILE_SYSTEM_GUID \ EFI_GUID( 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b ) -typedef struct { - efi_guid_t guid; - u64 table; -} efi_config_table_64_t; +#define EFI_DEVICE_TREE_GUID \ + EFI_GUID( 0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 ) -typedef struct { - efi_guid_t guid; - u32 table; -} efi_config_table_32_t; +#define EFI_DEVICE_PATH_PROTOCOL_GUID \ + EFI_GUID( 0x9576e91, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b ) -typedef struct { - efi_guid_t guid; - unsigned long table; -} efi_config_table_t; +#define EFI_SIMPLE_NETWORK_PROTOCOL_GUID \ + EFI_GUID( 0xA19832B9, 0xAC25, 0x11D3, 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D ) + +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ + EFI_GUID(0x0964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + +#define EFI_UNKNOWN_DEVICE_GUID \ + EFI_GUID(0xcf31fac5, 0xc24e, 0x11d2, 0x85, 0xf3, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b) + +#define EFI_BLOCK_IO_PROTOCOL_GUID \ + EFI_GUID(0x964e5b21, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + +extern efi_guid_t efi_file_info_id; +extern efi_guid_t efi_simple_file_system_protocol_guid; +extern efi_guid_t efi_device_path_protocol_guid; +extern efi_guid_t efi_loaded_image_protocol_guid; +extern efi_guid_t efi_unknown_device_guid; +extern efi_guid_t efi_null_guid; +extern efi_guid_t efi_global_variable_guid; +extern efi_guid_t efi_block_io_protocol_guid; #define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL) @@ -354,65 +377,22 @@ typedef struct { #define EFI_1_10_SYSTEM_TABLE_REVISION ((1 << 16) | (10)) #define EFI_1_02_SYSTEM_TABLE_REVISION ((1 << 16) | (02)) -typedef struct { - efi_table_hdr_t hdr; - u64 fw_vendor; /* physical addr of CHAR16 vendor string */ - u32 fw_revision; - u32 __pad1; - u64 con_in_handle; - u64 con_in; - u64 con_out_handle; - u64 con_out; - u64 stderr_handle; - u64 _stderr; - u64 runtime; - u64 boottime; - u32 nr_tables; - u32 __pad2; - u64 tables; -} efi_system_table_64_t; - -typedef struct { - efi_table_hdr_t hdr; - u32 fw_vendor; /* physical addr of CHAR16 vendor string */ - u32 fw_revision; - u32 con_in_handle; - u32 con_in; - u32 con_out_handle; - u32 con_out; - u32 stderr_handle; - u32 _stderr; - u32 runtime; - u32 boottime; - u32 nr_tables; - u32 tables; -} efi_system_table_32_t; - typedef struct { efi_table_hdr_t hdr; unsigned long fw_vendor; /* physical addr of CHAR16 vendor string */ u32 fw_revision; unsigned long con_in_handle; - unsigned long con_in; + struct efi_simple_input_interface *con_in; unsigned long con_out_handle; - unsigned long con_out; + struct efi_simple_text_output_protocol *con_out; unsigned long stderr_handle; - unsigned long _stderr; + unsigned long std_err; efi_runtime_services_t *runtime; efi_boot_services_t *boottime; unsigned long nr_tables; unsigned long tables; } efi_system_table_t; -struct efi_memory_map { - void *phys_map; - void *map; - void *map_end; - int nr_map; - unsigned long desc_version; - unsigned long desc_size; -}; - typedef struct { u32 revision; void *parent_handle; @@ -429,85 +409,12 @@ typedef struct { unsigned long unload; } efi_loaded_image_t; -typedef struct { - u64 revision; - void *open_volume; -} efi_file_io_interface_t; - -typedef struct { - u64 size; - u64 file_size; - u64 phys_size; - efi_time_t create_time; - efi_time_t last_access_time; - efi_time_t modification_time; - __aligned_u64 attribute; - efi_char16_t filename[1]; -} efi_file_info_t; - -typedef struct { - u64 revision; - void *open; - void *close; - void *delete; - void *read; - void *write; - void *get_position; - void *set_position; - void *get_info; - void *set_info; - void *flush; -} efi_file_handle_t; - -#define EFI_FILE_MODE_READ 0x0000000000000001 -#define EFI_FILE_MODE_WRITE 0x0000000000000002 -#define EFI_FILE_MODE_CREATE 0x8000000000000000 - -#define EFI_INVALID_TABLE_ADDR (~0UL) - -/* - * All runtime access to EFI goes through this structure: - */ -extern struct efi { - efi_system_table_t *systab; /* EFI system table */ - unsigned int runtime_version; /* Runtime services version */ - unsigned long mps; /* MPS table */ - unsigned long acpi; /* ACPI table (IA64 ext 0.71) */ - unsigned long acpi20; /* ACPI table (ACPI 2.0) */ - unsigned long smbios; /* SM BIOS table */ - unsigned long sal_systab; /* SAL system table */ - unsigned long boot_info; /* boot info table */ - unsigned long hcdp; /* HCDP table */ - unsigned long uga; /* UGA table */ - unsigned long uv_systab; /* UV system table */ - efi_get_time_t *get_time; - efi_set_time_t *set_time; - efi_get_wakeup_time_t *get_wakeup_time; - efi_set_wakeup_time_t *set_wakeup_time; - efi_get_variable_t *get_variable; - efi_get_next_variable_t *get_next_variable; - efi_set_variable_t *set_variable; - efi_query_variable_info_t *query_variable_info; - efi_update_capsule_t *update_capsule; - efi_query_capsule_caps_t *query_capsule_caps; - efi_get_next_high_mono_count_t *get_next_high_mono_count; - efi_reset_system_t *reset_system; - efi_set_virtual_address_map_t *set_virtual_address_map; -} efi; - static inline int efi_guidcmp (efi_guid_t left, efi_guid_t right) { return memcmp(&left, &right, sizeof (efi_guid_t)); } -static inline char * -efi_guid_unparse(efi_guid_t *guid, char *out) -{ - sprintf(out, "%pUl", guid->b); - return out; -} - /* * Variable Attributes */ @@ -527,48 +434,80 @@ efi_guid_unparse(efi_guid_t *guid, char *out) EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ EFI_VARIABLE_APPEND_WRITE) /* - * The type of search to perform when calling boottime->locate_handle + * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")) + * not including trailing NUL */ -#define EFI_LOCATE_ALL_HANDLES 0 -#define EFI_LOCATE_BY_REGISTER_NOTIFY 1 -#define EFI_LOCATE_BY_PROTOCOL 2 +#define EFI_VARIABLE_GUID_LEN 36 + +struct efi_device_path { + u8 type; + u8 sub_type; + u16 length; +} __attribute ((packed)); + +struct simple_text_output_mode { + s32 max_mode; + s32 mode; + s32 attribute; + s32 cursor_column; + s32 cursor_row; + bool cursor_visible; +}; -/* - * EFI Device Path information - */ -#define EFI_DEV_HW 0x01 -#define EFI_DEV_PCI 1 -#define EFI_DEV_PCCARD 2 -#define EFI_DEV_MEM_MAPPED 3 -#define EFI_DEV_VENDOR 4 -#define EFI_DEV_CONTROLLER 5 -#define EFI_DEV_ACPI 0x02 -#define EFI_DEV_BASIC_ACPI 1 -#define EFI_DEV_EXPANDED_ACPI 2 -#define EFI_DEV_MSG 0x03 -#define EFI_DEV_MSG_ATAPI 1 -#define EFI_DEV_MSG_SCSI 2 -#define EFI_DEV_MSG_FC 3 -#define EFI_DEV_MSG_1394 4 -#define EFI_DEV_MSG_USB 5 -#define EFI_DEV_MSG_USB_CLASS 15 -#define EFI_DEV_MSG_I20 6 -#define EFI_DEV_MSG_MAC 11 -#define EFI_DEV_MSG_IPV4 12 -#define EFI_DEV_MSG_IPV6 13 -#define EFI_DEV_MSG_INFINIBAND 9 -#define EFI_DEV_MSG_UART 14 -#define EFI_DEV_MSG_VENDOR 10 -#define EFI_DEV_MEDIA 0x04 -#define EFI_DEV_MEDIA_HARD_DRIVE 1 -#define EFI_DEV_MEDIA_CDROM 2 -#define EFI_DEV_MEDIA_VENDOR 3 -#define EFI_DEV_MEDIA_FILE 4 -#define EFI_DEV_MEDIA_PROTOCOL 5 -#define EFI_DEV_BIOS_BOOT 0x05 -#define EFI_DEV_END_PATH 0x7F -#define EFI_DEV_END_PATH2 0xFF -#define EFI_DEV_END_INSTANCE 0x01 -#define EFI_DEV_END_ENTIRE 0xFF +struct efi_simple_text_output_protocol { + void *reset; + efi_status_t (EFIAPI *output_string)(void *, void *); + void *test_string; + + efi_status_t(EFIAPI *query_mode)(struct efi_simple_text_output_protocol *this, + unsigned long mode_number, unsigned long *columns, unsigned long *rows); + efi_status_t(EFIAPI *set_mode)(struct efi_simple_text_output_protocol *this, + unsigned long mode_number); + efi_status_t(EFIAPI *set_attribute)(struct efi_simple_text_output_protocol *this, + unsigned long attribute); + efi_status_t(EFIAPI *clear_screen) (struct efi_simple_text_output_protocol *this); + efi_status_t(EFIAPI *set_cursor_position) (struct efi_simple_text_output_protocol *this, + unsigned long column, unsigned long row); + efi_status_t(EFIAPI *enable_cursor)(void *, bool enable); + struct simple_text_output_mode *mode; +}; + +struct efi_input_key { + u16 scan_code; + s16 unicode_char; +}; + +struct efi_simple_input_interface { + efi_status_t(EFIAPI *reset)(struct efi_simple_input_interface *this, + bool ExtendedVerification); + efi_status_t(EFIAPI *read_key_stroke)(struct efi_simple_input_interface *this, + struct efi_input_key *key); + void *wait_for_key; +}; + +typedef struct { + uint8_t Addr[32]; +} efi_mac_address; + +typedef struct { + uint8_t Addr[4]; +} efi_ipv4_address; + +typedef struct { + uint8_t Addr[16]; +} efi_ipv6_address; + +typedef union { + uint32_t Addr[4]; + efi_ipv4_address v4; + efi_ipv6_address v6; +} efi_ip_address; + +static inline int efi_compare_guid(efi_guid_t *a, efi_guid_t *b) +{ + return memcmp(a, b, sizeof(efi_guid_t)); +} + +char *device_path_to_str(struct efi_device_path *dev_path); #endif /* _LINUX_EFI_H */ -- cgit v1.2.3