diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..90f9ff4 --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +IndentWidth: 4 +ColumnLimit: 140 +AlignEscapedNewlinesLeft: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d4feb2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +bootloader.efi +bootloader.so +*.o +boot.img diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2b22933 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright 2018 Anatol Pomazau. All rights reserved. +Copyright 2017 The Fuchsia Authors. 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 Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a490d3c --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +ARCH = x86_64 + +LD=$(TOOLCHAIN_PATH)ld +NM=$(TOOLCHAIN_PATH)nm +OBJCOPY=$(TOOLCHAIN_PATH)objcopy +CC?=$(TOOLCHAIN_PATH)gcc + +CFLAGS = -Ixefi -Iinclude -flto -W -Wall -Wextra -O3 -fno-stack-protector -fno-math-errno -fno-trapping-math -fno-common -fshort-wchar -nostdlib -ffreestanding -std=c11 -m64 +ifeq ($(ARCH),x86_64) +CFLAGS += -mno-red-zone +endif + +EFI_SECTIONS = -j .text -j .data -j .reloc + +ifeq ($(CC),clang) + CFLAGS += --target=$(ARCH)-windows-msvc + LDFLAGS += /subsystem:efi_application /entry:efi_main +else + CFLAGS += -fPIE + LDFLAGS += -Wl,-T xefi/efi-x86-64.lds -Wl,--gc-sections +endif + +TARGET = bootloader.efi + +OBJS = bootloader.o \ + config.o \ + netboot.o \ + loadelf.o \ + bootinfo.o \ + framebuffer.o \ + inet.o \ + inet6.o \ + netifc.o \ + device_id.o \ + tftp/tftp.o \ + xefi/xefi.o \ + xefi/guids.o \ + xefi/printf.o \ + xefi/console-printf.o \ + xefi/ctype.o \ + xefi/string.o \ + xefi/strings.o \ + xefi/stdlib.o \ + xefi/loadfile.o + +all: $(TARGET) + +ifeq ($(CC),clang) + +bootloader.efi: $(OBJS) + lld-link $(LDFLAGS) $^ /out:$@ + if [ "`$(NM) $< | grep ' U '`" != "" ]; then echo "error: $<: undefined symbols"; $(NM) $< | grep ' U '; rm $<; exit 1; fi + +else + +bootloader.so: $(OBJS) + $(CC) $(LDFLAGS) $^ -o $@ + +%.efi: %.so + $(OBJCOPY) $(EFI_SECTIONS) --target=efi-app-$(ARCH) $^ $@ + if [ "`$(NM) $< | grep ' U '`" != "" ]; then echo "error: $<: undefined symbols"; $(NM) $< | grep ' U '; rm $<; exit 1; fi + +endif diff --git a/README.md b/README.md new file mode 100644 index 0000000..adfa2cb --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# UEFI-based bootloader for Unicycle applications + +UEFI bootloader that allows to load Unicycle application directly, without any support from operating system like +Linux. This bootloader implements [Uniboot](https://github.com/libunicycle/uniboot-spec) protocol on top of UEFI specification. + +The bootloader supports booting from the same bootable device where bootloader.efi is located or loading from network using TFTP protocol. + +## Booting Unicycle applications over the network +While booting from the disk is one of the possible options it requires generating and reflashing images to disk/USB stick every time +the Unicycle application is modified. Such workflow makes it harder to do quick iterative development. + +To help to increase development speed this bootloader supports booting over the network. +The idea is derived from [Zircon](https://fuchsia.googlesource.com/zircon/+/refs/heads/master/bootloader/) project and shares many implementation details. +Once the device boots it sends a multicast request to check whether the network has a [bootserver](https://github.com/libunicycle/bootserver) running. +And if it has one it downloads the application binary file over TFTP and loads it into the device memory. + +To enable network-based boot process one needs to make sure the test device UEFI configured with network enabled +then [bootserver](https://github.com/libunicycle/bootserver) need to be run at the host. + +## Build project +To build UEFI bootloader binary please run +`make` + +## Create bootable image +To create a bootable image please build bootloader using instructions above. +Then update bootloader config file `bootloader.cfg` to choose whether you prefer over-the-network or from-disk application boot. +Once you completed please run: + +`sudo image_generate.sh` + +At the end you'll get `boot.img` that is suitable for flashing to a disk or USB flash stick: + +`sudo dd if=boot.img of=/dev/sdXXXX` + +sdXXXX - device disk for your bootable device. You can find the name using `lsblk` tool. diff --git a/bootinfo.c b/bootinfo.c new file mode 100644 index 0000000..cd92dfa --- /dev/null +++ b/bootinfo.c @@ -0,0 +1,73 @@ +#include "bootinfo.h" + +#include "uniboot.h" + +#ifndef UNIBOOT_NO_BUILTIN +#include +#include "xefi.h" +#include +#endif + +void *buffer; +void *ptr; +size_t available; +size_t total_size; + +#ifdef UNIBOOT_NO_BUILTIN +static void memset(uint8_t *p, uint8_t c, size_t n) { + for (size_t i = 0; i < n; i++) { + *p++ = c; + } +} +#endif + +void bootinfo_init(void *b, size_t size) { + buffer = b; + available = size; + total_size = size; + ptr = buffer; + memset(ptr, 0, size); + + if (available < sizeof(struct uniboot_info)) { + xefi_fatal("init_boot_info: provided buffer is too small for uniboot_info", EFI_BUFFER_TOO_SMALL); + } + + struct uniboot_info *hdr = ptr; + hdr->magic = UNIBOOT_MAGIC; + hdr->version = 1; + hdr->length = sizeof(struct uniboot_info); + + ptr += sizeof(struct uniboot_info); +} + +void bootinfo_reinit(void *b, size_t size) { + buffer = b; + struct uniboot_info *hdr = buffer; + total_size = size; + ptr = buffer + hdr->length; + available = size - hdr->length; + memset(ptr, 0, size - hdr->length); +} + +void *bootinfo_finalize(void) { + return buffer; +} + +void *bootinfo_alloc_size(size_t size) { + if (size > available) { + xefi_fatal("boot_info buffer is too small", EFI_BUFFER_TOO_SMALL); + } + + void *p = ptr; + ptr += size; + available -= size; + + struct uniboot_info *hdr = buffer; + hdr->length += size; + + return p; +} + +size_t bootinfo_size_available(void) { return available; } + +size_t bootinfo_size_consumed(void) { return total_size - available; } diff --git a/bootinfo.h b/bootinfo.h new file mode 100644 index 0000000..4156233 --- /dev/null +++ b/bootinfo.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +void bootinfo_init(void *buffer, size_t size); +void bootinfo_reinit(void *b, size_t size); + +void *bootinfo_finalize(void); + +void *bootinfo_alloc_size(size_t size); + +#define bootinfo_alloc(type) ({ (type *)bootinfo_alloc_size(sizeof(type)); }) + +size_t bootinfo_size_available(void); + +size_t bootinfo_size_consumed(void); \ No newline at end of file diff --git a/bootloader.c b/bootloader.c new file mode 100644 index 0000000..2bcf91a --- /dev/null +++ b/bootloader.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: MIT +// Some part of this code is based on Zircon bootloader + +#include "bootinfo.h" +#include "compiler.h" +#include "config.h" +#include "framebuffer.h" +#include "loadelf.h" +#include "netboot.h" +#include "printf.h" +#include "string.h" +#include "uniboot.h" +#include + +static efi_guid AcpiTableGUID = ACPI_TABLE_GUID; +static efi_guid Acpi2TableGUID = ACPI_20_TABLE_GUID; +static uint8_t ACPI_RSD_PTR[8] = "RSD PTR "; + +#define MSR_EXT_FEATURES 0xc0000080 + +// flags for MSR_EXT_FEATURES +#define MSR_EXT_FEATURES_LONG_MODE BIT(8) // Long mode (64 bits) +#define MSR_EXT_FEATURES_NO_EXECUTE BIT(11) // enables NXE paging bit + +static uint64_t x86_rdmsr(uint32_t id) { + uint32_t eax, edx; + __asm__ volatile("rdmsr" : "=a"(eax), "=d"(edx) : "c"(id)); + + uint64_t ret = edx; + ret <<= 32; + ret |= eax; + + return ret; +} + +// write model specific register, set value into edx:eax +static void x86_wrmsr(uint32_t id, uint64_t val) { + uint32_t eax = (uint32_t)val; + uint32_t edx = (uint32_t)(val >> 32); + __asm__ volatile("wrmsr" ::"c"(id), "a"(eax), "d"(edx)); +} + +static uint64_t find_acpi_root(efi_system_table *sys) { + efi_configuration_table *cfgtab = sys->ConfigurationTable; + + for (size_t i = 0; i < sys->NumberOfTableEntries; i++) { + if (xefi_cmp_guid(&cfgtab[i].VendorGuid, &AcpiTableGUID) && xefi_cmp_guid(&cfgtab[i].VendorGuid, &Acpi2TableGUID)) { + // not an ACPI table + continue; + } + if (memcmp(cfgtab[i].VendorTable, ACPI_RSD_PTR, 8)) { + // not the Root Description Pointer + continue; + } + return (uint64_t)cfgtab[i].VendorTable; + } + return 0; +} + +static void read_acpi_root(efi_system_table *sys) { + uint64_t acpi_root = find_acpi_root(sys); + + if (!acpi_root) { + // Firmware does not provide ACPI root information + return; + } + + struct uniboot_entry *entry = bootinfo_alloc(struct uniboot_entry); + entry->type = UNIBOOT_ENTRY_ACPI_INFO; + entry->length = sizeof(struct uniboot_acpi_info); + + struct uniboot_acpi_info *acpi = bootinfo_alloc(struct uniboot_acpi_info); + acpi->acpi_root = acpi_root; +} + +// This functions exits BootServices and thus it should go last, right before jumping to OS +static void read_memory_map(void) { + struct uniboot_entry *entry = bootinfo_alloc(struct uniboot_entry); + entry->type = UNIBOOT_ENTRY_MEMORY_MAP; + + struct uniboot_memory_map *mmap = bootinfo_alloc(struct uniboot_memory_map); + + void *mmap_begin = mmap + 1; + size_t mmap_size = bootinfo_size_available(); + size_t mmap_key = 0; + size_t desc_size = 0; + uint32_t desc_version = 0; + efi_status r = gBS->GetMemoryMap(&mmap_size, (efi_memory_descriptor *)mmap_begin, &mmap_key, &desc_size, &desc_version); + if (r) { + xefi_fatal("GetMemoryMap", r); + } + if (desc_version != EFI_MEMORY_DESCRIPTOR_VERSION) { + xefi_fatal("init_memory_map: only descriptor version 1 is supported for GetMemoryMap()", r); + } + + size_t areas_num = mmap_size / desc_size; + size_t areas_num_counter = 0; + struct uniboot_memory_area *area = bootinfo_alloc_size(areas_num * sizeof(struct uniboot_memory_area)); + entry->length = sizeof(struct uniboot_memory_map) + areas_num * sizeof(struct uniboot_memory_area); + + for (void *ptr = mmap_begin; ptr < mmap_begin + mmap_size; ptr += desc_size) { + efi_memory_descriptor *desc = (efi_memory_descriptor *)ptr; + + uint64_t type = 0; + switch (desc->Type) { + case EfiReservedMemoryType: + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + case EfiMemoryMappedIO: + case EfiMemoryMappedIOPortSpace: + case EfiPalCode: + type = UNIBOOT_MEM_RESERVED; + break; + + case EfiUnusableMemory: + type = UNIBOOT_MEM_UNUSABLE; + break; + + case EfiACPIReclaimMemory: + type = UNIBOOT_MEM_ACPI; + break; + + case EfiLoaderCode: + case EfiLoaderData: + case EfiBootServicesCode: + case EfiBootServicesData: + case EfiConventionalMemory: + type = UNIBOOT_MEM_RAM; + break; + + case EfiACPIMemoryNVS: + type = UNIBOOT_MEM_NVS; + break; + + default: + printf("Invalid EFI memory descriptor type (0x%x)!\n", desc->Type); + continue; + } + + // check if memory areas are adjusted, merge it in this case + if (areas_num_counter && (area - 1)->type == type && ((area - 1)->start + (area - 1)->length) == desc->PhysicalStart) { + (area - 1)->length += desc->NumberOfPages * PAGE_SIZE; + } else { + area->type = type; + area->start = desc->PhysicalStart; + area->length = desc->NumberOfPages * PAGE_SIZE; + area++; + areas_num_counter++; + } + } + mmap->num = areas_num_counter; + + r = gBS->ExitBootServices(gImg, mmap_key); + if (r) { + xefi_fatal("ExitBootServices", r); + } +} + +static __attribute__((noreturn)) void jump_to_app(uniboot_entry_point_t start_app, void *boot_info) { +#if __x86_64__ + __asm__ volatile("mov $0, %%rbp; " + "cli; " :: + : "rbp"); +#else +#error "jump function is not defined" +#endif + + start_app(boot_info); + + __builtin_unreachable(); +} + +#define KBUFSIZE (32 * 1024 * 1024) +#define RBUFSIZE (512 * 1024 * 1024) + +static nbfile nbapp; +nbfile *netboot_get_buffer(const char *name, size_t size) { + if (!strcmp(name, NB_APP_FILENAME)) { + return &nbapp; + } + return NULL; +} + +void do_netboot() { + efi_physical_addr mem = 0xFFFFFFFF; + if (gBS->AllocatePages(AllocateMaxAddress, EfiLoaderData, KBUFSIZE / 4096, &mem)) { + printf("Failed to allocate network io buffer\n"); + return; + } + nbapp.data = (void *)mem; + nbapp.size = KBUFSIZE; + + printf("\nNetBoot Server Started...\n\n"); + efi_tpl prev_tpl = gBS->RaiseTPL(TPL_NOTIFY); + while (true) { + int n = netboot_poll(); + if (n < 1) { + continue; + } + if (nbapp.offset < 4096) { + // too small to be a kernel + continue; + } + + // make sure network traffic is not in flight, etc + netboot_close(); + + // Restore the TPL before booting the kernel, or failing to netboot + gBS->RestoreTPL(prev_tpl); + + break; + } +} + +EFIAPI efi_status efi_main(efi_handle img, efi_system_table *sys) { + xefi_init(img, sys); + gConOut->ClearScreen(gConOut); +#ifdef OUTPUT_SERIAL + xefi_init_serial(); +#endif + + uint8_t bootinfo_buff[10240]; + bootinfo_init(bootinfo_buff, sizeof(bootinfo_buff)); + + size_t cfg_size; + char *cfg_file = xefi_load_file(L"bootloader.cfg", &cfg_size, 0); + if (cfg_file) { + config_init(cfg_file, cfg_size); + xefi_free(cfg_file, cfg_size); + } + + size_t elf_size = 0; + void *elf_data = NULL; + const char *boot = config_get("boot", "file"); + if (strcmp(boot, "network") == 0) { + // See if there's a network interface + const char *nodename = config_get("nodename", NULL); + bool have_network = netboot_init(nodename) == 0; + if (have_network) { + printf("Nodename: %s\n", netboot_nodename()); + + do_netboot(); + + elf_data = nbapp.data; + elf_size = nbapp.size; + } else { + printf("Network is not available, trying to load application from disk\n"); + } + } + if (!elf_data) { + // local disk boot + elf_data = xefi_load_file(L"app.elf", &elf_size, 0); + if (!elf_data) + xefi_fatal("Cannot load ap.elf", EFI_LOAD_ERROR); + } + uniboot_entry_point_t entry = elf_load(elf_data, elf_size); + + read_acpi_root(sys); + read_framebuffer_info(); + read_memory_map(); + + void *boot_info = bootinfo_finalize(); + + uint64_t mode_msr = x86_rdmsr(MSR_EXT_FEATURES); + mode_msr |= MSR_EXT_FEATURES_NO_EXECUTE; + x86_wrmsr(MSR_EXT_FEATURES, mode_msr); + + + jump_to_app(entry, boot_info); + + __builtin_unreachable(); +} diff --git a/bootloader.cfg b/bootloader.cfg new file mode 100644 index 0000000..5eeb1d5 --- /dev/null +++ b/bootloader.cfg @@ -0,0 +1,2 @@ +boot=network +nodename=unicycle-dev diff --git a/compiler.h b/compiler.h new file mode 100644 index 0000000..d110fa9 --- /dev/null +++ b/compiler.h @@ -0,0 +1,8 @@ +#pragma once + +#define PAGE_SIZE 4096 + +#define ROUND_UP(n, d) ((n + (__typeof__(n))d - 1) & ~((__typeof__(n))d - 1)) +#define ROUND_DOWN(n, d) ((n) & ~((__typeof__(n))d - 1)) + +#define BIT(x) ((uint64_t)1 << (x)) \ No newline at end of file diff --git a/config.c b/config.c new file mode 100644 index 0000000..f5b427b --- /dev/null +++ b/config.c @@ -0,0 +1,157 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" + +#include +#include +#include +#include + +#define CONFIG_MAX_ITEMS 128 +#define CONFIG_MAX_STRINGDATA (4096 * 3) + +static char buffer[CONFIG_MAX_STRINGDATA]; +static size_t buffer_next = 0; + +typedef struct { + char *key; + char *val; + size_t klen; + size_t vlen; +} kv_t; + +static kv_t entry[CONFIG_MAX_ITEMS]; +static size_t entry_count; + +size_t config_to_string(char *ptr, size_t max) { + char *start = ptr; + + if (max == 0) { + return 0; + } + + for (size_t n = 0; n < entry_count; n++) { + if ((entry[n].klen + entry[n].vlen + 3) > max) { + // require space for: space + key + equal + value + null + break; + } + if (n > 0) { + *ptr++ = ' '; + max--; + } + memcpy(ptr, entry[n].key, entry[n].klen); + ptr += entry[n].klen; + max -= entry[n].klen; + if (entry[n].vlen) { + *ptr++ = '='; + max--; + memcpy(ptr, entry[n].val, entry[n].vlen); + ptr += entry[n].vlen; + max -= entry[n].vlen; + } + } + *ptr++ = 0; + return ptr - start; +} + +static void entry_add(const char *key, size_t klen, const char *val, size_t vlen) { + if (klen == 0) { + // empty keys are not allowed + return; + } + + if ((klen > 1024) || (vlen > 1024)) { + // huge keys and values are not allowed + return; + } + + if ((sizeof(buffer) - buffer_next) < (klen + vlen + 2)) { + // give up if it won't fit + return; + } + + size_t n; + for (n = 0; n < entry_count; n++) { + if ((entry[n].klen == klen) && !memcmp(key, entry[n].key, klen)) { + goto write_value; + } + } + if (n == CONFIG_MAX_ITEMS) { + // no space in table + return; + } + + // new entry + entry_count++; + entry[n].key = buffer + buffer_next; + entry[n].klen = klen; + memcpy(entry[n].key, key, klen); + entry[n].key[klen] = 0; + buffer_next += klen + 1; + +write_value: + entry[n].val = buffer + buffer_next; + entry[n].vlen = vlen; + memcpy(entry[n].val, val, vlen); + entry[n].val[vlen] = 0; + buffer_next += vlen + 1; +} + +void config_set(const char *key, const char *val) { entry_add(key, strlen(key), val, strlen(val)); } + +void config_init(const char *ptr, size_t len) { + const char *key; + const char *val; + +restart: + while (len > 0) { + if (isspace(*ptr)) { + ptr++; + len--; + continue; + } + key = ptr; + while (len > 0) { + if (*ptr == '=') { + size_t klen = ptr - key; + ptr++; + len--; + val = ptr; + while ((len > 0) && !isspace(*ptr)) { + len--; + ptr++; + } + size_t vlen = ptr - val; + entry_add(key, klen, val, vlen); + goto restart; + } + if (isspace(*ptr)) { + break; + } + ptr++; + len--; + } + size_t klen = ptr - key; + entry_add(key, klen, NULL, 0); + } +} + +const char *config_get(const char *key, const char *_default) { + size_t klen = strlen(key); + for (size_t n = 0; n < entry_count; n++) { + if ((entry[n].klen == klen) && !memcmp(key, entry[n].key, klen)) { + return entry[n].val; + } + } + return _default; +} + +uint32_t config_get_uint32(const char *key, uint32_t _default) { + const char *val = config_get(key, NULL); + if (val == NULL) { + return _default; + } + return atol(val); +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..f7a74c6 --- /dev/null +++ b/config.h @@ -0,0 +1,7 @@ +#include +#include "stdlib.h" + +size_t config_to_string(char *ptr, size_t max); +void config_init(const char *ptr, size_t len); +const char *config_get(const char *key, const char *_default); +uint32_t config_get_uint32(const char *key, uint32_t _default); \ No newline at end of file diff --git a/device_id.c b/device_id.c new file mode 100644 index 0000000..e213b6c --- /dev/null +++ b/device_id.c @@ -0,0 +1,26 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device_id.h" + +#include +#include + +#include "eff_short_wordlist_1.h" + +#define APPEND_WORD(NUM, SEP) \ + word = dictionary[(NUM) % 1296]; \ + memcpy(dest, word, strlen(word)); \ + dest += strlen(word); \ + *dest = SEP; \ + dest++; + +void device_id(mac_addr addr, char out[DEVICE_ID_MAX]) { + const char* word; + char* dest = out; + APPEND_WORD(addr.x[0] | ((addr.x[4] << 8) & 0xF00), '-'); + APPEND_WORD(addr.x[1] | ((addr.x[5] << 8) & 0xF00), '-'); + APPEND_WORD(addr.x[2] | ((addr.x[4] << 4) & 0xF00), '-'); + APPEND_WORD(addr.x[3] | ((addr.x[5] << 4) & 0xF00), 0); +} diff --git a/device_id.h b/device_id.h new file mode 100644 index 0000000..3eb6a4b --- /dev/null +++ b/device_id.h @@ -0,0 +1,11 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "inet6.h" + +#define DEVICE_ID_MAX 24 + +void device_id(mac_addr addr, char out[DEVICE_ID_MAX]); diff --git a/eff_short_wordlist_1.h b/eff_short_wordlist_1.h new file mode 100644 index 0000000..d0592f6 --- /dev/null +++ b/eff_short_wordlist_1.h @@ -0,0 +1,1302 @@ +#pragma once + +// This list must be consistent with +// garnet/go/src/netstack/deviceid/eff_short_wordlist.go. +const char dictionary[1296][6] = { + "acid", + "acorn", + "acre", + "acts", + "afar", + "affix", + "aged", + "agent", + "agile", + "aging", + "agony", + "ahead", + "aide", + "aids", + "aim", + "ajar", + "alarm", + "alias", + "alibi", + "alien", + "alike", + "alive", + "aloe", + "aloft", + "aloha", + "alone", + "amend", + "amino", + "ample", + "amuse", + "angel", + "anger", + "angle", + "ankle", + "apple", + "april", + "apron", + "aqua", + "area", + "arena", + "argue", + "arise", + "armed", + "armor", + "army", + "aroma", + "array", + "arson", + "art", + "ashen", + "ashes", + "atlas", + "atom", + "attic", + "audio", + "avert", + "avoid", + "awake", + "award", + "awoke", + "axis", + "bacon", + "badge", + "bagel", + "baggy", + "baked", + "baker", + "balmy", + "banjo", + "barge", + "barn", + "bash", + "basil", + "bask", + "batch", + "bath", + "baton", + "bats", + "blade", + "blank", + "blast", + "blaze", + "bleak", + "blend", + "bless", + "blimp", + "blink", + "bloat", + "blob", + "blog", + "blot", + "blunt", + "blurt", + "blush", + "boast", + "boat", + "body", + "boil", + "bok", + "bolt", + "boned", + "boney", + "bonus", + "bony", + "book", + "booth", + "boots", + "boss", + "botch", + "both", + "boxer", + "breed", + "bribe", + "brick", + "bride", + "brim", + "bring", + "brink", + "brisk", + "broad", + "broil", + "broke", + "brook", + "broom", + "brush", + "buck", + "bud", + "buggy", + "bulge", + "bulk", + "bully", + "bunch", + "bunny", + "bunt", + "bush", + "bust", + "busy", + "buzz", + "cable", + "cache", + "cadet", + "cage", + "cake", + "calm", + "cameo", + "canal", + "candy", + "cane", + "canon", + "cape", + "card", + "cargo", + "carol", + "carry", + "carve", + "case", + "cash", + "cause", + "cedar", + "chain", + "chair", + "chant", + "chaos", + "charm", + "chase", + "cheek", + "cheer", + "chef", + "chess", + "chest", + "chew", + "chief", + "chili", + "chill", + "chip", + "chomp", + "chop", + "chow", + "chuck", + "chump", + "chunk", + "churn", + "chute", + "cider", + "cinch", + "city", + "civic", + "civil", + "clad", + "claim", + "clamp", + "clap", + "clash", + "clasp", + "class", + "claw", + "clay", + "clean", + "clear", + "cleat", + "cleft", + "clerk", + "click", + "cling", + "clink", + "clip", + "cloak", + "clock", + "clone", + "cloth", + "cloud", + "clump", + "coach", + "coast", + "coat", + "cod", + "coil", + "coke", + "cola", + "cold", + "colt", + "coma", + "come", + "comic", + "comma", + "cone", + "cope", + "copy", + "coral", + "cork", + "cost", + "cot", + "couch", + "cough", + "cover", + "cozy", + "craft", + "cramp", + "crane", + "crank", + "crate", + "crave", + "crawl", + "crazy", + "creme", + "crepe", + "crept", + "crib", + "cried", + "crisp", + "crook", + "crop", + "cross", + "crowd", + "crown", + "crumb", + "crush", + "crust", + "cub", + "cult", + "cupid", + "cure", + "curl", + "curry", + "curse", + "curve", + "curvy", + "cushy", + "cut", + "cycle", + "dab", + "dad", + "daily", + "dairy", + "daisy", + "dance", + "dandy", + "darn", + "dart", + "dash", + "data", + "date", + "dawn", + "deaf", + "deal", + "dean", + "debit", + "debt", + "debug", + "decaf", + "decal", + "decay", + "deck", + "decor", + "decoy", + "deed", + "delay", + "denim", + "dense", + "dent", + "depth", + "derby", + "desk", + "dial", + "diary", + "dice", + "dig", + "dill", + "dime", + "dimly", + "diner", + "dingy", + "disco", + "dish", + "disk", + "ditch", + "ditzy", + "dizzy", + "dock", + "dodge", + "doing", + "doll", + "dome", + "donor", + "donut", + "dose", + "dot", + "dove", + "down", + "dowry", + "doze", + "drab", + "drama", + "drank", + "draw", + "dress", + "dried", + "drift", + "drill", + "drive", + "drone", + "droop", + "drove", + "drown", + "drum", + "dry", + "duck", + "duct", + "dude", + "dug", + "duke", + "duo", + "dusk", + "dust", + "duty", + "dwarf", + "dwell", + "eagle", + "early", + "earth", + "easel", + "east", + "eaten", + "eats", + "ebay", + "ebony", + "ebook", + "echo", + "edge", + "eel", + "eject", + "elbow", + "elder", + "elf", + "elk", + "elm", + "elope", + "elude", + "elves", + "email", + "emit", + "empty", + "emu", + "enter", + "entry", + "envoy", + "equal", + "erase", + "error", + "erupt", + "essay", + "etch", + "evade", + "even", + "evict", + "evil", + "evoke", + "exact", + "exit", + "fable", + "faced", + "fact", + "fade", + "fall", + "false", + "fancy", + "fang", + "fax", + "feast", + "feed", + "femur", + "fence", + "fend", + "ferry", + "feta", + "fetch", + "fever", + "fiber", + "fifth", + "fifty", + "film", + "filth", + "final", + "finch", + "fit", + "five", + "flag", + "flaky", + "flame", + "flap", + "flask", + "fled", + "flick", + "fling", + "flint", + "flip", + "flirt", + "float", + "flock", + "flop", + "floss", + "flyer", + "foam", + "foe", + "fog", + "foil", + "folic", + "folk", + "food", + "fool", + "found", + "fox", + "foyer", + "frail", + "frame", + "fray", + "fresh", + "fried", + "frill", + "frisk", + "from", + "front", + "frost", + "froth", + "frown", + "froze", + "fruit", + "gag", + "gains", + "gala", + "game", + "gap", + "gas", + "gave", + "gear", + "gecko", + "geek", + "gem", + "genre", + "gift", + "gig", + "gills", + "given", + "giver", + "glad", + "glass", + "glide", + "gloss", + "glove", + "glow", + "glue", + "goal", + "going", + "golf", + "gong", + "good", + "gooey", + "goofy", + "gore", + "gown", + "grab", + "grain", + "grant", + "grape", + "graph", + "grasp", + "grass", + "grave", + "gravy", + "gray", + "green", + "greet", + "grew", + "grid", + "grief", + "grill", + "grip", + "grit", + "groom", + "grope", + "growl", + "grub", + "grunt", + "guide", + "gulf", + "gulp", + "gummy", + "guru", + "gush", + "gut", + "guy", + "habit", + "half", + "halo", + "halt", + "happy", + "harm", + "hash", + "hasty", + "hatch", + "hate", + "haven", + "hazel", + "hazy", + "heap", + "heat", + "heave", + "hedge", + "hefty", + "help", + "herbs", + "hers", + "hub", + "hug", + "hula", + "hull", + "human", + "humid", + "hump", + "hung", + "hunk", + "hunt", + "hurry", + "hurt", + "hush", + "hut", + "ice", + "icing", + "icon", + "icy", + "igloo", + "image", + "ion", + "iron", + "islam", + "issue", + "item", + "ivory", + "ivy", + "jab", + "jam", + "jaws", + "jazz", + "jeep", + "jelly", + "jet", + "jiffy", + "job", + "jog", + "jolly", + "jolt", + "jot", + "joy", + "judge", + "juice", + "juicy", + "july", + "jumbo", + "jump", + "junky", + "juror", + "jury", + "keep", + "keg", + "kept", + "kick", + "kilt", + "king", + "kite", + "kitty", + "kiwi", + "knee", + "knelt", + "koala", + "kung", + "ladle", + "lady", + "lair", + "lake", + "lance", + "land", + "lapel", + "large", + "lash", + "lasso", + "last", + "latch", + "late", + "lazy", + "left", + "legal", + "lemon", + "lend", + "lens", + "lent", + "level", + "lever", + "lid", + "life", + "lift", + "lilac", + "lily", + "limb", + "limes", + "line", + "lint", + "lion", + "lip", + "list", + "lived", + "liver", + "lunar", + "lunch", + "lung", + "lurch", + "lure", + "lurk", + "lying", + "lyric", + "mace", + "maker", + "malt", + "mama", + "mango", + "manor", + "many", + "map", + "march", + "mardi", + "marry", + "mash", + "match", + "mate", + "math", + "moan", + "mocha", + "moist", + "mold", + "mom", + "moody", + "mop", + "morse", + "most", + "motor", + "motto", + "mount", + "mouse", + "mousy", + "mouth", + "move", + "movie", + "mower", + "mud", + "mug", + "mulch", + "mule", + "mull", + "mumbo", + "mummy", + "mural", + "muse", + "music", + "musky", + "mute", + "nacho", + "nag", + "nail", + "name", + "nanny", + "nap", + "navy", + "near", + "neat", + "neon", + "nerd", + "nest", + "net", + "next", + "niece", + "ninth", + "nutty", + "oak", + "oasis", + "oat", + "ocean", + "oil", + "old", + "olive", + "omen", + "onion", + "only", + "ooze", + "opal", + "open", + "opera", + "opt", + "otter", + "ouch", + "ounce", + "outer", + "oval", + "oven", + "owl", + "ozone", + "pace", + "pagan", + "pager", + "palm", + "panda", + "panic", + "pants", + "panty", + "paper", + "park", + "party", + "pasta", + "patch", + "path", + "patio", + "payer", + "pecan", + "penny", + "pep", + "perch", + "perky", + "perm", + "pest", + "petal", + "petri", + "petty", + "photo", + "plank", + "plant", + "plaza", + "plead", + "plot", + "plow", + "pluck", + "plug", + "plus", + "poach", + "pod", + "poem", + "poet", + "pogo", + "point", + "poise", + "poker", + "polar", + "polio", + "polka", + "polo", + "pond", + "pony", + "poppy", + "pork", + "poser", + "pouch", + "pound", + "pout", + "power", + "prank", + "press", + "print", + "prior", + "prism", + "prize", + "probe", + "prong", + "proof", + "props", + "prude", + "prune", + "pry", + "pug", + "pull", + "pulp", + "pulse", + "puma", + "punch", + "punk", + "pupil", + "puppy", + "purr", + "purse", + "push", + "putt", + "quack", + "quake", + "query", + "quiet", + "quill", + "quilt", + "quit", + "quota", + "quote", + "rabid", + "race", + "rack", + "radar", + "radio", + "raft", + "rage", + "raid", + "rail", + "rake", + "rally", + "ramp", + "ranch", + "range", + "rank", + "rant", + "rash", + "raven", + "reach", + "react", + "ream", + "rebel", + "recap", + "relax", + "relay", + "relic", + "remix", + "repay", + "repel", + "reply", + "rerun", + "reset", + "rhyme", + "rice", + "rich", + "ride", + "rigid", + "rigor", + "rinse", + "riot", + "ripen", + "rise", + "risk", + "ritzy", + "rival", + "river", + "roast", + "robe", + "robin", + "rock", + "rogue", + "roman", + "romp", + "rope", + "rover", + "royal", + "ruby", + "rug", + "ruin", + "rule", + "runny", + "rush", + "rust", + "rut", + "sadly", + "sage", + "said", + "saint", + "salad", + "salon", + "salsa", + "salt", + "same", + "sandy", + "santa", + "satin", + "sauna", + "saved", + "savor", + "sax", + "say", + "scale", + "scam", + "scan", + "scare", + "scarf", + "scary", + "scoff", + "scold", + "scoop", + "scoot", + "scope", + "score", + "scorn", + "scout", + "scowl", + "scrap", + "scrub", + "scuba", + "scuff", + "sect", + "sedan", + "self", + "send", + "sepia", + "serve", + "set", + "seven", + "shack", + "shade", + "shady", + "shaft", + "shaky", + "sham", + "shape", + "share", + "sharp", + "shed", + "sheep", + "sheet", + "shelf", + "shell", + "shine", + "shiny", + "ship", + "shirt", + "shock", + "shop", + "shore", + "shout", + "shove", + "shown", + "showy", + "shred", + "shrug", + "shun", + "shush", + "shut", + "shy", + "sift", + "silk", + "silly", + "silo", + "sip", + "siren", + "sixth", + "size", + "skate", + "skew", + "skid", + "skier", + "skies", + "skip", + "skirt", + "skit", + "sky", + "slab", + "slack", + "slain", + "slam", + "slang", + "slash", + "slate", + "slaw", + "sled", + "sleek", + "sleep", + "sleet", + "slept", + "slice", + "slick", + "slimy", + "sling", + "slip", + "slit", + "slob", + "slot", + "slug", + "slum", + "slurp", + "slush", + "small", + "smash", + "smell", + "smile", + "smirk", + "smog", + "snack", + "snap", + "snare", + "snarl", + "sneak", + "sneer", + "sniff", + "snore", + "snort", + "snout", + "snowy", + "snub", + "snuff", + "speak", + "speed", + "spend", + "spent", + "spew", + "spied", + "spill", + "spiny", + "spoil", + "spoke", + "spoof", + "spool", + "spoon", + "sport", + "spot", + "spout", + "spray", + "spree", + "spur", + "squad", + "squat", + "squid", + "stack", + "staff", + "stage", + "stain", + "stall", + "stamp", + "stand", + "stank", + "stark", + "start", + "stash", + "state", + "stays", + "steam", + "steep", + "stem", + "step", + "stew", + "stick", + "sting", + "stir", + "stock", + "stole", + "stomp", + "stony", + "stood", + "stool", + "stoop", + "stop", + "storm", + "stout", + "stove", + "straw", + "stray", + "strut", + "stuck", + "stud", + "stuff", + "stump", + "stung", + "stunt", + "suds", + "sugar", + "sulk", + "surf", + "sushi", + "swab", + "swan", + "swarm", + "sway", + "swear", + "sweat", + "sweep", + "swell", + "swept", + "swim", + "swing", + "swipe", + "swirl", + "swoop", + "swore", + "syrup", + "tacky", + "taco", + "tag", + "take", + "tall", + "talon", + "tamer", + "tank", + "taper", + "taps", + "tarot", + "tart", + "task", + "taste", + "tasty", + "taunt", + "thank", + "thaw", + "theft", + "theme", + "thigh", + "thing", + "think", + "third", + "thorn", + "those", + "throb", + "thud", + "thumb", + "thump", + "thus", + "tiara", + "tidal", + "tidy", + "tiger", + "tile", + "tilt", + "tint", + "tiny", + "trace", + "track", + "trade", + "train", + "trait", + "trap", + "trash", + "tray", + "treat", + "tree", + "trek", + "trend", + "trial", + "tribe", + "trick", + "trio", + "trout", + "truce", + "truck", + "trump", + "trunk", + "try", + "tug", + "tulip", + "tummy", + "turf", + "tusk", + "tutor", + "tutu", + "tux", + "tweak", + "tweet", + "twice", + "twine", + "twins", + "twirl", + "twist", + "uncle", + "uncut", + "undo", + "unify", + "union", + "unit", + "untie", + "upon", + "upper", + "urban", + "used", + "user", + "usher", + "utter", + "value", + "vapor", + "vegan", + "venue", + "verse", + "vest", + "veto", + "vice", + "video", + "view", + "viral", + "virus", + "visa", + "visor", + "vixen", + "vocal", + "voice", + "void", + "volt", + "voter", + "vowel", + "wad", + "wafer", + "wager", + "wages", + "wagon", + "wake", + "walk", + "wand", + "wasp", + "watch", + "water", + "wavy", + "wheat", + "whiff", + "whole", + "whoop", + "wick", + "widen", + "widow", + "width", + "wife", + "wifi", + "wilt", + "wimp", + "wind", + "wing", + "wink", + "wipe", + "wired", + "wiry", + "wise", + "wish", + "wispy", + "wok", + "wolf", + "womb", + "wool", + "woozy", + "word", + "work", + "worry", + "wound", + "woven", + "wrath", + "wreck", + "wrist", + "xerox", + "yahoo", + "yam", + "yard", + "year", + "yeast", + "yelp", + "yield", + "yo-yo", + "yodel", + "yoga", + "yoyo", + "yummy", + "zebra", + "zero", + "zesty", + "zippy", + "zone", + "zoom", +}; diff --git a/elf.h b/elf.h new file mode 100644 index 0000000..23b50aa --- /dev/null +++ b/elf.h @@ -0,0 +1,2410 @@ +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-1999,2000,2001,2002,2008,2009 Free Software Foundation, Inc. + This file was part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#pragma once + +#include + +/* Standard ELF types. */ + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ +/* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_LINUX 3 /* Linux. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embedded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronics ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STMicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_AT19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_NUM 95 +#define EM_AARCH64 183 /* ARM 64-bit architecture */ + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct { + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct { + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct { + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct { + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy loaded */ + +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char)(val)) >> 4) +#define ELF32_ST_TYPE(val) ((val)&0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND(val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE(val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ +#define STN_ABS 65521 + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o)&0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct { + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct { + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct { + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct { + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val)&0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type)&0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i)&0xffffffff) +#define ELF64_R_INFO(sym, type) ((((Elf64_Xword)(sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct { + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct { + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* GCC stack segment */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + +/* Dynamic section entry. */ + +typedef struct { + Elf32_Sword d_tag; /* Dynamic entry type */ + union { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; /* Dynamic entry type */ + union { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 10 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word) - ((Elf32_Sword)(tag) << 1 >> 1) - 1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not generally available. */ + +/* Version definition sections. */ + +typedef struct { + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef entry */ +} Elf32_Verdef; + +typedef struct { + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef entry */ +} Elf64_Verdef; + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxiliary version information. */ + +typedef struct { + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct { + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + +/* Version dependency section. */ + +typedef struct { + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed entry */ +} Elf32_Verneed; + +typedef struct { + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed entry */ +} Elf64_Verneed; + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct { + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct { + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux entry */ +} Elf64_Vernaux; + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct { + int a_type; /* Entry type */ + union { + long int a_val; /* Integer value */ + void *a_ptr; /* Pointer value */ + void (*a_fcn)(void); /* Function pointer value */ + } a_un; +} Elf32_auxv_t; + +typedef struct { + long int a_type; /* Entry type */ + union { + long int a_val; /* Integer value */ + void *a_ptr; /* Pointer value */ + void (*a_fcn)(void); /* Function pointer value */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine dependent hints about processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored */ + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct { + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define ELF_NOTE_ABI 1 + +/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI + note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 + +/* Move records. */ +typedef struct { + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct { + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char)(info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM(info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE(info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO(sym, size) + +/* Motorola 68k specific definitions. */ + +/* Values for Elf32_Ehdr.e_flags. */ +#define EF_CPU32 0x00810000 + +/* m68k relocs. */ + +#define R_68K_NONE 0 /* No reloc */ +#define R_68K_32 1 /* Direct 32 bit */ +#define R_68K_16 2 /* Direct 16 bit */ +#define R_68K_8 3 /* Direct 8 bit */ +#define R_68K_PC32 4 /* PC relative 32 bit */ +#define R_68K_PC16 5 /* PC relative 16 bit */ +#define R_68K_PC8 6 /* PC relative 8 bit */ +#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ +#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ +#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ +#define R_68K_GOT32O 10 /* 32 bit GOT offset */ +#define R_68K_GOT16O 11 /* 16 bit GOT offset */ +#define R_68K_GOT8O 12 /* 8 bit GOT offset */ +#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ +#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ +#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ +#define R_68K_PLT32O 16 /* 32 bit PLT offset */ +#define R_68K_PLT16O 17 /* 16 bit PLT offset */ +#define R_68K_PLT8O 18 /* 8 bit PLT offset */ +#define R_68K_COPY 19 /* Copy symbol at runtime */ +#define R_68K_GLOB_DAT 20 /* Create GOT entry */ +#define R_68K_JMP_SLOT 21 /* Create PLT entry */ +#define R_68K_RELATIVE 22 /* Adjust by program base */ +/* Keep this the last entry. */ +#define R_68K_NUM 23 + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE15 /* Address of GOT entry for static TLS block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of local dynamic thread local data in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* Keep this the last entry. */ +#define R_386_NUM 38 + +/* SUN SPARC specific definitions. */ + +/* x86_64 specific definitions. */ +#define R_X86_64_NONE 0 +#define R_X86_64_64 1 +#define R_X86_64_PC32 2 +#define R_X86_64_GOT32 3 +#define R_X86_64_PLT32 4 +#define R_X86_64_COPY 5 +#define R_X86_64_GLOB_DAT 6 +#define R_X86_64_JUMP_SLOT 7 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_GOTPCREL 9 +#define R_X86_64_32 10 +#define R_X86_64_32S 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 +#define R_X86_64_PC64 24 + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_REGISTER 13 /* Global register reserved to app. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* Additional Sparc64 relocs. */ + +#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ +#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ +#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ +#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ +#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ +#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ +#define R_SPARC_10 30 /* Direct 10 bit */ +#define R_SPARC_11 31 /* Direct 11 bit */ +#define R_SPARC_64 32 /* Direct 64 bit */ +#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ +#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ +#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ +#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ +#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ +#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ +#define R_SPARC_PC_LM22 39 /* Low middle 22 bits of ... */ +#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ +#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ +#define R_SPARC_7 43 /* Direct 7 bit */ +#define R_SPARC_5 44 /* Direct 5 bit */ +#define R_SPARC_6 45 /* Direct 6 bit */ +#define R_SPARC_DISP64 46 /* PC relative 64 bit */ +#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ +#define R_SPARC_HIX22 48 /* High 22 bit complemented */ +#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ +#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ +#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ +#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ +#define R_SPARC_REGISTER 53 /* Global register usage */ +#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ +#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +/* Keep this the last entry. */ +#define R_SPARC_NUM 80 + +/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */ +#define HWCAP_SPARC_ULTRA3 32 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* The following are non-official names and should not be used. */ + +#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_ip4if 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union { + struct { + Elf32_Word gt_current_g_value; /* -G value used for compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct { + Elf32_Word gt_g_value; /* If this value were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct { + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + +/* Entries found in sections of type SHT_MIPS_OPTIONS. */ + +typedef struct { + unsigned char kind; /* Determines interpretation of the + variable part of descriptor. */ + unsigned char size; /* Size of descriptor, including header. */ + Elf32_Section section; /* Section header index of section affected, 0 for global options. */ + Elf32_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* Values for `kind' field in Elf_Options. */ + +#define ODK_NULL 0 /* Undefined. */ +#define ODK_REGINFO 1 /* Register usage information. */ +#define ODK_EXCEPTIONS 2 /* Exception processing options. */ +#define ODK_PAD 3 /* Section padding options. */ +#define ODK_HWPATCH 4 /* Hardware workarounds performed */ +#define ODK_FILL 5 /* record the fill value used by the linker. */ +#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ +#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ +#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ + +/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ + +#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ +#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode? */ +#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ + +#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +/* Entry found in `.options' section. */ + +typedef struct { + Elf32_Word hwp_flags1; /* Extra flags. */ + Elf32_Word hwp_flags2; /* Extra flags. */ +} Elf_Options_Hw; + +/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +/* Keep this the last entry. */ +#define R_MIPS_NUM 38 + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta relocations refer to. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the class declaration. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ +#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve function stored in GOT. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added by rld on dlopen() calls. */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ +#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ +#define DT_MIPS_NUM 0x32 + +/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct { + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +typedef struct { + Elf64_Word l_name; /* Name (string table index) */ + Elf64_Word l_time_stamp; /* Timestamp */ + Elf64_Word l_checksum; /* Checksum */ + Elf64_Word l_version; /* Interface version */ + Elf64_Word l_flags; /* Flags */ +} Elf64_Lib; + +/* Legal values for l_flags. */ + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indices. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tentatively declared symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + +/* Legal values for sh_type field of Elf64_Shdr. */ + +/* These two are primarily concerned with ECOFF debugging info. */ +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +/* Legal values for sh_flags field of Elf64_Shdr. */ + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for st_other field of Elf64_Sym. */ +#define STO_ALPHA_NOPV 0x80 /* No PV required. */ +#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ + +/* Alpha relocs. */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 +/* Keep this the last entry. */ +#define R_ALPHA_NUM 46 + +/* Magic values of the LITUSE relocation addend. */ +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + +/* PowerPC specific declarations */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib flag */ + +/* PowerPC relocations defined by the ABIs */ +#define ELF_R_PPC_NONE 0 +#define ELF_R_PPC_ADDR32 1 /* 32bit absolute address */ +#define ELF_R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define ELF_R_PPC_ADDR16 3 /* 16bit absolute address */ +#define ELF_R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define ELF_R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define ELF_R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define ELF_R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define ELF_R_PPC_ADDR14_BRTAKEN 8 +#define ELF_R_PPC_ADDR14_BRNTAKEN 9 +#define ELF_R_PPC_REL24 10 /* PC relative 26 bit */ +#define ELF_R_PPC_REL14 11 /* PC relative 16 bit */ +#define ELF_R_PPC_REL14_BRTAKEN 12 +#define ELF_R_PPC_REL14_BRNTAKEN 13 +#define ELF_R_PPC_GOT16 14 +#define ELF_R_PPC_GOT16_LO 15 +#define ELF_R_PPC_GOT16_HI 16 +#define ELF_R_PPC_GOT16_HA 17 +#define ELF_R_PPC_PLTREL24 18 +#define ELF_R_PPC_COPY 19 +#define ELF_R_PPC_GLOB_DAT 20 +#define ELF_R_PPC_JMP_SLOT 21 +#define ELF_R_PPC_RELATIVE 22 +#define ELF_R_PPC_LOCAL24PC 23 +#define ELF_R_PPC_UADDR32 24 +#define ELF_R_PPC_UADDR16 25 +#define ELF_R_PPC_REL32 26 +#define ELF_R_PPC_PLT32 27 +#define ELF_R_PPC_PLTREL32 28 +#define ELF_R_PPC_PLT16_LO 29 +#define ELF_R_PPC_PLT16_HI 30 +#define ELF_R_PPC_PLT16_HA 31 +#define ELF_R_PPC_SDAREL16 32 +#define ELF_R_PPC_SECTOFF 33 +#define ELF_R_PPC_SECTOFF_LO 34 +#define ELF_R_PPC_SECTOFF_HI 35 +#define ELF_R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#define ELF_R_PPC_NUM 37 + +/* PowerPC64 relocations defined by the ABIs */ +#define ELF_R_PPC64_NONE ELF_R_PPC_NONE +#define ELF_R_PPC64_ADDR32 ELF_R_PPC_ADDR32 /* 32bit absolute address. */ +#define ELF_R_PPC64_ADDR24 ELF_R_PPC_ADDR24 /* 26bit address, word aligned. */ +#define ELF_R_PPC64_ADDR16 ELF_R_PPC_ADDR16 /* 16bit absolute address. */ +#define ELF_R_PPC64_ADDR16_LO ELF_R_PPC_ADDR16_LO /* lower 16bits of abs. address. */ +#define ELF_R_PPC64_ADDR16_HI ELF_R_PPC_ADDR16_HI /* high 16bits of abs. address. */ +#define ELF_R_PPC64_ADDR16_HA ELF_R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define ELF_R_PPC64_ADDR14 ELF_R_PPC_ADDR14 /* 16bit address, word aligned. */ +#define ELF_R_PPC64_ADDR14_BRTAKEN ELF_R_PPC_ADDR14_BRTAKEN +#define ELF_R_PPC64_ADDR14_BRNTAKEN ELF_R_PPC_ADDR14_BRNTAKEN +#define ELF_R_PPC64_REL24 ELF_R_PPC_REL24 /* PC relative 26 bit, word aligned. */ +#define ELF_R_PPC64_REL14 ELF_R_PPC_REL14 /* PC relative 16 bit. */ +#define ELF_R_PPC64_REL14_BRTAKEN ELF_R_PPC_REL14_BRTAKEN +#define ELF_R_PPC64_REL14_BRNTAKEN ELF_R_PPC_REL14_BRNTAKEN +#define ELF_R_PPC64_GOT16 ELF_R_PPC_GOT16 +#define ELF_R_PPC64_GOT16_LO ELF_R_PPC_GOT16_LO +#define ELF_R_PPC64_GOT16_HI ELF_R_PPC_GOT16_HI +#define ELF_R_PPC64_GOT16_HA ELF_R_PPC_GOT16_HA + +#define ELF_R_PPC64_COPY ELF_R_PPC_COPY +#define ELF_R_PPC64_GLOB_DAT ELF_R_PPC_GLOB_DAT +#define ELF_R_PPC64_JMP_SLOT ELF_R_PPC_JMP_SLOT +#define ELF_R_PPC64_RELATIVE ELF_R_PPC_RELATIVE + +#define ELF_R_PPC64_UADDR32 ELF_R_PPC_UADDR32 +#define ELF_R_PPC64_UADDR16 ELF_R_PPC_UADDR16 +#define ELF_R_PPC64_REL32 ELF_R_PPC_REL32 +#define ELF_R_PPC64_PLT32 ELF_R_PPC_PLT32 +#define ELF_R_PPC64_PLTREL32 ELF_R_PPC_PLTREL32 +#define ELF_R_PPC64_PLT16_LO ELF_R_PPC_PLT16_LO +#define ELF_R_PPC64_PLT16_HI ELF_R_PPC_PLT16_HI +#define ELF_R_PPC64_PLT16_HA ELF_R_PPC_PLT16_HA + +#define ELF_R_PPC64_SECTOFF ELF_R_PPC_SECTOFF +#define ELF_R_PPC64_SECTOFF_LO ELF_R_PPC_SECTOFF_LO +#define ELF_R_PPC64_SECTOFF_HI ELF_R_PPC_SECTOFF_HI +#define ELF_R_PPC64_SECTOFF_HA ELF_R_PPC_SECTOFF_HA +#define ELF_R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2. */ +#define ELF_R_PPC64_ADDR64 38 /* doubleword64 S + A. */ +#define ELF_R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A). */ +#define ELF_R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A). */ +#define ELF_R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A). */ +#define ELF_R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A). */ +#define ELF_R_PPC64_UADDR64 43 /* doubleword64 S + A. */ +#define ELF_R_PPC64_REL64 44 /* doubleword64 S + A - P. */ +#define ELF_R_PPC64_PLT64 45 /* doubleword64 L + A. */ +#define ELF_R_PPC64_PLTREL64 46 /* doubleword64 L + A - P. */ +#define ELF_R_PPC64_TOC16 47 /* half16* S + A - .TOC. */ +#define ELF_R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.). */ +#define ELF_R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.). */ +#define ELF_R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.). */ +#define ELF_R_PPC64_TOC 51 /* doubleword64 .TOC. */ +#define ELF_R_PPC64_PLTGOT16 52 /* half16* M + A. */ +#define ELF_R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A). */ +#define ELF_R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A). */ +#define ELF_R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A). */ + +#define ELF_R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2. */ +#define ELF_R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2. */ +#define ELF_R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2. */ +#define ELF_R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2. */ +#define ELF_R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2. */ +#define ELF_R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2. */ +#define ELF_R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2. */ +#define ELF_R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2. */ +#define ELF_R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2. */ +#define ELF_R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2. */ +#define ELF_R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2. */ +/* Keep this the last entry. */ +#define ELF_R_PPC64_NUM 67 + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define ELF_R_PPC_EMB_NADDR32 101 +#define ELF_R_PPC_EMB_NADDR16 102 +#define ELF_R_PPC_EMB_NADDR16_LO 103 +#define ELF_R_PPC_EMB_NADDR16_HI 104 +#define ELF_R_PPC_EMB_NADDR16_HA 105 +#define ELF_R_PPC_EMB_SDAI16 106 +#define ELF_R_PPC_EMB_SDA2I16 107 +#define ELF_R_PPC_EMB_SDA2REL 108 +#define ELF_R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define ELF_R_PPC_EMB_MRKREF 110 +#define ELF_R_PPC_EMB_RELSEC16 111 +#define ELF_R_PPC_EMB_RELST_LO 112 +#define ELF_R_PPC_EMB_RELST_HI 113 +#define ELF_R_PPC_EMB_RELST_HA 114 +#define ELF_R_PPC_EMB_BIT_FLD 115 +#define ELF_R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define ELF_R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define ELF_R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define ELF_R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define ELF_R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define ELF_R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define ELF_R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define ELF_R_PPC_TOC16 255 + +/* PowerPC64 specific values for the Dyn d_tag field. */ +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_NUM 1 + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 +#define EF_ARM_SOFT_FLOAT 0x200 +#define EF_ARM_VFP_FLOAT 0x400 +#define EF_ARM_MAVERICK_FLOAT 0x800 + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +/* Constants defined in AAELF. */ +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_LE8 0x00400000 + +#define EF_ARM_EABI_VERSION(flags) ((flags)&EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + +/* Additional symbol types for Thumb */ +#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ +#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined in the input to a link step */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location addressed by the static base */ +#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ +#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ +#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ +#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ + +/* AArch64 relocs. */ +#define R_AARCH64_NONE 0 /* No relocation. */ +#define R_AARCH64_ABS64 257 /* Direct 64 bit. */ +#define R_AARCH64_ABS32 258 /* Direct 32 bit. */ +#define R_AARCH64_PREL32 261 +#define R_AARCH64_ADR_PREL_PG_HI21 275 +#define R_AARCH64_ADD_ABS_LO12_NC 277 +#define R_AARCH64_LDST64_ABS_LO12_NC 286 +#define R_AARCH64_JUMP26 282 /* 26-bit relative. */ +#define R_AARCH64_CALL26 283 /* 26-bit relative. */ +#define R_AARCH64_ADR_GOT_PAGE 311 +#define R_AARCH64_LD64_GOT_LO12_NC 312 +#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ +#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ +#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ +#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */ +#define R_AARCH64_TLS_DTPMOD64 1028 /* Module number, 64 bit. */ +#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ +#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ +#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ + +/* ARM relocs. */ +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_LDR_PC_G0 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_CALL 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_BREL_ADJ 12 +#define R_ARM_TLS_DESC 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_TLS_DTPMOD32 17 +#define R_ARM_TLS_DTPOFF32 18 +#define R_ARM_TLS_TPOFF32 19 +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF32 24 /* 32 bit offset to GOT */ +#define R_ARM_BASE_PREL 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT_BREL 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_THM_JUMP24 30 +#define R_ARM_BASE_ABS 31 +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_TARGET1 38 +#define R_ARM_SBREL31 39 +#define R_ARM_V4BX 40 +#define R_ARM_TARGET2 41 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 +#define R_ARM_MOVW_PREL_NC 45 +#define R_ARM_MOVT_PREL 46 +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 +#define R_ARM_THM_MOVW_PREL_NC 49 +#define R_ARM_THM_MOVT_PREL 50 +#define R_ARM_THM_JUMP19 51 +#define R_ARM_THM_JUMP6 52 +#define R_ARM_THM_ALU_PREL_11_0 53 +#define R_ARM_THM_PC12 54 +#define R_ARM_ABS32_NOI 55 +#define R_ARM_REL32_NOI 56 +#define R_ARM_ALU_PC_G0_NC 57 +#define R_ARM_ALU_PC_G0 58 +#define R_ARM_ALU_PC_G1_NC 59 +#define R_ARM_ALU_PC_G1 60 +#define R_ARM_ALU_PC_G2 61 +#define R_ARM_LDR_PC_G1 62 +#define R_ARM_LDR_PC_G2 63 +#define R_ARM_LDRS_PC_G0 64 +#define R_ARM_LDRS_PC_G1 65 +#define R_ARM_LDRS_PC_G2 66 +#define R_ARM_LDC_PC_G0 67 +#define R_ARM_LDC_PC_G1 68 +#define R_ARM_LDC_PC_G2 69 +#define R_ARM_ALU_SB_G0_NC 70 +#define R_ARM_ALU_SB_G0 71 +#define R_ARM_ALU_SB_G1_NC 72 +#define R_ARM_ALU_SB_G1 73 +#define R_ARM_ALU_SB_G2 74 +#define R_ARM_LDR_SB_G0 75 +#define R_ARM_LDR_SB_G1 76 +#define R_ARM_LDR_SB_G2 77 +#define R_ARM_LDRS_SB_G0 78 +#define R_ARM_LDRS_SB_G1 79 +#define R_ARM_LDRS_SB_G2 80 +#define R_ARM_LDC_SB_G0 81 +#define R_ARM_LDC_SB_G1 82 +#define R_ARM_LDC_SB_G2 83 +#define R_ARM_MOVW_BREL_NC 84 +#define R_ARM_MOVT_BREL 85 +#define R_ARM_MOVW_BREL 86 +#define R_ARM_THM_MOVW_BREL_NC 87 +#define R_ARM_THM_MOVT_BREL 88 +#define R_ARM_THM_MOVW_BREL 89 +#define R_ARM_TLS_GOTDESC 90 +#define R_ARM_TLS_CALL 91 +#define R_ARM_TLS_DESCSEQ 92 +#define R_ARM_THM_TLS_CALL 93 +#define R_ARM_PLT32_ABS 94 +#define R_ARM_GOT_ABS 95 +#define R_ARM_GOT_PREL 96 +#define R_ARM_GOT_BREL12 97 +#define R_ARM_GOTOFF12 98 +#define R_ARM_GOTRELAX 99 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_JUMP11 102 /* thumb unconditional branch */ +#define R_ARM_THM_JUMP8 103 /* thumb conditional branch */ +#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic thread local data */ +#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic thread local data */ +#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS block */ +#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of static TLS block offset */ +#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static TLS block */ +#define R_ARM_TLS_LDO12 109 +#define R_ARM_TLS_LE12 110 +#define R_ARM_IE12GP 111 +#define R_ARM_PRIVATE_0 112 +#define R_ARM_PRIVATE_1 113 +#define R_ARM_PRIVATE_2 114 +#define R_ARM_PRIVATE_3 115 +#define R_ARM_PRIVATE_4 116 +#define R_ARM_PRIVATE_5 117 +#define R_ARM_PRIVATE_6 118 +#define R_ARM_PRIVATE_7 119 +#define R_ARM_PRIVATE_8 120 +#define R_ARM_PRIVATE_9 121 +#define R_ARM_PRIVATE_10 122 +#define R_ARM_PRIVATE_11 123 +#define R_ARM_PRIVATE_12 124 +#define R_ARM_PRIVATE_13 125 +#define R_ARM_PRIVATE_14 126 +#define R_ARM_PRIVATE_15 127 +#define R_ARM_ME_TOO 128 +#define R_ARM_THM_TLS_DESCSEQ16 129 +#define R_ARM_THM_TLS_DESCSEQ32 130 +#define R_ARM_THM_GOT_BREL12 131 +#define R_ARM_IRELATIVE 140 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* SH specific declarations */ + +/* SH relocs. */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_TLS_GD_MOV 152 +#define R_SH_TLS_LDM_MOV 153 +#define R_SH_TLS_LDO_MOV 154 +#define R_SH_TLS_IE_MOV 155 +#define R_SH_TLS_LE_MOV 156 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* Additional s390 relocs */ + +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ + +/* Keep this the last entry. */ +#define R_390_NUM 27 + +/* CRIS relocations. */ +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + +/* AMD x86-64 relocations. */ +#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_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ +#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset to two GOT entries for GD symbol */ +#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset to two GOT entries for LD symbol */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define r_x86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset to GOT entry for IE symbol */ +#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ + +#define R_X86_64_NUM 24 + +#ifdef __LP64__ + +typedef Elf64_Addr Elf_Addr; +typedef Elf64_Nhdr Elf_Nhdr; +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Half Elf_Half; +typedef Elf64_Off Elf_Off; +typedef Elf64_Rel Elf_Rel; +typedef Elf64_Rela Elf_Rela; +typedef Elf64_Section Elf_Section; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Sword Elf_Sword; +typedef Elf64_Sym Elf_Sym; +typedef Elf64_Word Elf_Word; +typedef Elf64_Xword Elf_Xword; + +#define ELF_ST_BIND(val) ELF64_ST_BIND(val) +#define ELF_ST_TYPE(val) ELF64_ST_TYPE(val) +#define ELF_ST_INFO(a, b) ELF64_ST_INFO(a, b) +#define ELF_R_SYM(val) ELF64_R_SYM(val) +#define ELF_R_TYPE(val) ELF64_R_TYPE(val) +#define ELF_R_INFO(sym, type) ELF64_R_INFO(sym, type) + +#else /* __LP64__ */ + +typedef Elf32_Addr Elf_Addr; +typedef Elf32_Nhdr Elf_Nhdr; +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Half Elf_Half; +typedef Elf32_Off Elf_Off; +typedef Elf32_Rel Elf_Rel; +typedef Elf32_Rela Elf_Rela; +typedef Elf32_Section Elf_Section; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Sword Elf_Sword; +typedef Elf32_Sym Elf_Sym; +typedef Elf32_Word Elf_Word; +typedef Elf32_Xword Elf_Xword; + +#define ELF_ST_BIND(val) ELF32_ST_BIND(val) +#define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) +#define ELF_ST_INFO(a, b) ELF32_ST_INFO(a, b) + +#define ELF_R_SYM(val) ELF32_R_SYM(val) +#define ELF_R_TYPE(val) ELF32_R_TYPE(val) +#define ELF_R_INFO(sym, type) ELF32_R_INFO(sym, type) + +#endif /* __LP64__ */ \ No newline at end of file diff --git a/framebuffer.c b/framebuffer.c new file mode 100644 index 0000000..ddf904c --- /dev/null +++ b/framebuffer.c @@ -0,0 +1,82 @@ +#include "framebuffer.h" + +#include "bootinfo.h" +#include "printf.h" +#include "uniboot.h" +#include +#include + +static void get_bit_range(uint32_t mask, int *high, int *low) { + *high = -1; + *low = -1; + int idx = 0; + while (mask) { + if (*low < 0 && (mask & 1)) + *low = idx; + idx++; + mask >>= 1; + } + *high = idx - 1; +} + +static int fb_pixel_format_from_bitmask(efi_pixel_bitmask bitmask) { + int r_hi = -1, r_lo = -1, g_hi = -1, g_lo = -1, b_hi = -1, b_lo = -1; + + get_bit_range(bitmask.RedMask, &r_hi, &r_lo); + get_bit_range(bitmask.GreenMask, &g_hi, &g_lo); + get_bit_range(bitmask.BlueMask, &b_hi, &b_lo); + + if (r_lo < 0 || g_lo < 0 || b_lo < 0) { + goto unknown; + } + + if ((r_hi == 23 && r_lo == 16) && (g_hi == 15 && g_lo == 8) && (b_hi == 7 && b_lo == 0)) { + return UNIBOOT_PIXEL_FORMAT_RGB_x888; + } + + if ((r_hi == 7 && r_lo == 5) && (g_hi == 4 && g_lo == 2) && (b_hi == 1 && b_lo == 0)) { + return UNIBOOT_PIXEL_FORMAT_RGB_332; + } + + if ((r_hi == 15 && r_lo == 11) && (g_hi == 10 && g_lo == 5) && (b_hi == 4 && b_lo == 0)) { + return UNIBOOT_PIXEL_FORMAT_RGB_565; + } + + if ((r_hi == 7 && r_lo == 6) && (g_hi == 5 && g_lo == 4) && (b_hi == 3 && b_lo == 2)) { + return UNIBOOT_PIXEL_FORMAT_RGB_2220; + } + +unknown: + printf("unknown pixel format bitmask: r %08x / g %08x / b %08x\n", bitmask.RedMask, bitmask.GreenMask, bitmask.BlueMask); + return UNIBOOT_PIXEL_FORMAT_UNKNOWN; +} + +static uint32_t fb_pixel_format(efi_graphics_output_protocol *gop) { + efi_graphics_pixel_format efi_fmt = gop->Mode->Info->PixelFormat; + switch (efi_fmt) { + case PixelBlueGreenRedReserved8BitPerColor: + return UNIBOOT_PIXEL_FORMAT_RGB_x888; + case PixelBitMask: + return fb_pixel_format_from_bitmask(gop->Mode->Info->PixelInformation); + default: + printf("unknown pixel format: %d\n", efi_fmt); + return UNIBOOT_PIXEL_FORMAT_UNKNOWN; + } +} + +void read_framebuffer_info(void) { + efi_graphics_output_protocol *gop = NULL; + gBS->LocateProtocol(&GraphicsOutputProtocol, NULL, (void **)&gop); + if (gop) { + struct uniboot_entry *entry = bootinfo_alloc(struct uniboot_entry); + entry->type = UNIBOOT_ENTRY_FRAMEBUFFER; + entry->length = sizeof(struct uniboot_framebuffer); + + struct uniboot_framebuffer *fb = bootinfo_alloc(struct uniboot_framebuffer); + fb->base = gop->Mode->FrameBufferBase; + fb->width = gop->Mode->Info->HorizontalResolution; + fb->height = gop->Mode->Info->VerticalResolution; + fb->stride = gop->Mode->Info->PixelsPerScanLine; + fb->format = fb_pixel_format(gop); + } +} diff --git a/framebuffer.h b/framebuffer.h new file mode 100644 index 0000000..ed44519 --- /dev/null +++ b/framebuffer.h @@ -0,0 +1,3 @@ +#pragma once + +void read_framebuffer_info(void); \ No newline at end of file diff --git a/image_generate.sh b/image_generate.sh new file mode 100755 index 0000000..e270b48 --- /dev/null +++ b/image_generate.sh @@ -0,0 +1,35 @@ +#/bin/sh + +set -e + +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" + exit 1 +fi + +OUTPUT=boot.img + +truncate --size 100M $OUTPUT +sgdisk --clear \ + --new 1:: --typecode=1:ef00 --change-name=1:'EFI System' \ + $OUTPUT + + # Loop sparse file +LOOPDEV=$(losetup --find --show $OUTPUT) +partprobe ${LOOPDEV} + +mkfs.fat -F32 ${LOOPDEV}p1 + +umount hda/ || true +rm -rf hda/ +mkdir hda +mount ${LOOPDEV}p1 hda/ +mkdir -p hda/EFI/BOOT/ +cp bootloader.efi hda/EFI/BOOT/BOOTX64.EFI +cp bootloader.cfg hda/ +umount hda/ + +losetup -d ${LOOPDEV} +rm -rf hda/ + +chown $SUDO_USER $OUTPUT diff --git a/include/arpa/inet.h b/include/arpa/inet.h new file mode 100644 index 0000000..5fd0085 --- /dev/null +++ b/include/arpa/inet.h @@ -0,0 +1,13 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +uint16_t htons(uint16_t val); +uint16_t ntohs(uint16_t val); +uint32_t htonl(uint32_t val); +uint32_t ntohl(uint32_t val); + diff --git a/include/assert.h b/include/assert.h new file mode 100644 index 0000000..9e00561 --- /dev/null +++ b/include/assert.h @@ -0,0 +1,8 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#define static_assert(e, msg) _Static_assert(e, msg) + diff --git a/include/ctype.h b/include/ctype.h new file mode 100644 index 0000000..7772ce5 --- /dev/null +++ b/include/ctype.h @@ -0,0 +1,9 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +int isdigit(int c); +int isspace(int c); +int tolower(int c); diff --git a/include/inttypes.h b/include/inttypes.h new file mode 100644 index 0000000..36ae92d --- /dev/null +++ b/include/inttypes.h @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" + +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "u" + +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" + +#ifdef __clang__ +#define PRIx64 "llx" +#else +#define PRIx64 "lx" +#endif diff --git a/include/printf.h b/include/printf.h new file mode 100644 index 0000000..fa58d72 --- /dev/null +++ b/include/printf.h @@ -0,0 +1,36 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +typedef __CHAR16_TYPE__ char16_t; +typedef signed long int ssize_t; + +#define __PRINTFLIKE(__fmt,__varargs) __attribute__((__format__ (__printf__, __fmt, __varargs))) + +int printf(const char *fmt, ...) __PRINTFLIKE(1, 2); +int sprintf(char *str, const char *fmt, ...) __PRINTFLIKE(2, 3); +int snprintf(char *str, size_t len, const char *fmt, ...) __PRINTFLIKE(3, 4); +int vsprintf(char *str, const char *fmt, va_list ap); +int vsnprintf(char *str, size_t len, const char *fmt, va_list ap); + +/* printf engine that parses the format string and generates output */ + +/* function pointer to pass the printf engine, called back during the formatting. + * input is a string to output, length bytes to output (or null on string), + * return code is number of characters that would have been written, or error code (if negative) + */ +typedef int (*_printf_engine_output_func)(const char *str, size_t len, void *state); + +int _printf_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap); + +// Print a wide string to console +int puts16(char16_t *str); diff --git a/include/reg.h b/include/reg.h new file mode 100644 index 0000000..9b00a79 --- /dev/null +++ b/include/reg.h @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#define REG8(addr) ((volatile uint8_t *)(uintptr_t)(addr)) +#define REG16(addr) ((volatile uint16_t *)(uintptr_t)(addr)) +#define REG32(addr) ((volatile uint32_t *)(uintptr_t)(addr)) +#define REG64(addr) ((volatile uint64_t *)(uintptr_t)(addr)) + +#define writeb(v, a) (*REG8(a) = (v)) +#define readb(a) (*REG8(a)) +#define writew(v, a) (*REG16(a) = (v)) +#define readw(a) (*REG16(a)) +#define writel(v, a) (*REG32(a) = (v)) +#define readl(a) (*REG32(a)) +#define writell(v, a) (*REG64(a) = (v)) +#define readll(a) (*REG64(a)) + diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..250a303 --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,8 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include diff --git a/include/stdlib.h b/include/stdlib.h new file mode 100644 index 0000000..f42ab4a --- /dev/null +++ b/include/stdlib.h @@ -0,0 +1,11 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +int atoi(const char* nptr); +long atol(const char* nptr); +long long atoll(const char* nptr); diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..9832742 --- /dev/null +++ b/include/string.h @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#ifndef NULL +#define NULL ((void*)0) +#endif + +void* memset(void* dst, int c, size_t n); +void* memcpy(void* dst, const void* src, size_t n); +int memcmp(const void* a, const void* b, size_t n); +size_t strlen(const char* s); +size_t wcslen(const char16_t* s); +size_t strnlen(const char* s, size_t max); +char* strchr(const char* s, int c); +char* strcpy(char* dst, const char* src); +char* strncpy(char* dst, const char* src, size_t len); +int strcmp(const char* s1, const char* s2); +int strncmp(const char* s1, const char* s2, size_t len); diff --git a/include/strings.h b/include/strings.h new file mode 100644 index 0000000..d48a5c3 --- /dev/null +++ b/include/strings.h @@ -0,0 +1,10 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +int strcasecmp(const char* s1, const char* s2); +int strncasecmp(const char* s1, const char* s2, size_t len); diff --git a/include/sys/types.h b/include/sys/types.h new file mode 100644 index 0000000..b682f80 --- /dev/null +++ b/include/sys/types.h @@ -0,0 +1,9 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +typedef size_t off_t; diff --git a/include/uchar.h b/include/uchar.h new file mode 100644 index 0000000..ed275d7 --- /dev/null +++ b/include/uchar.h @@ -0,0 +1,7 @@ +// Copyright 2018 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +typedef __CHAR16_TYPE__ char16_t; diff --git a/include/unistd.h b/include/unistd.h new file mode 100644 index 0000000..9f9266e --- /dev/null +++ b/include/unistd.h @@ -0,0 +1,8 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + diff --git a/include/xefi.h b/include/xefi.h new file mode 100644 index 0000000..06a17c0 --- /dev/null +++ b/include/xefi.h @@ -0,0 +1,64 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#define VERBOSE + +#include +#include +#include +#include +#include +#include +#include + +void xefi_init(efi_handle img, efi_system_table* sys); +void xefi_init_serial(void); + +void xefi_wait_any_key(void); +void xefi_fatal(const char* msg, efi_status status); +char16_t* xefi_handle_to_str(efi_handle handle); +const char *xefi_strerror(efi_status status); +const char16_t* xefi_wstrerror(efi_status status); +size_t strlen_16(char16_t* str); + +char16_t* xefi_devpath_to_str(efi_device_path_protocol* path); + +int xefi_cmp_guid(efi_guid* guid1, efi_guid* guid2); + +// Convenience wrappers for Open/Close protocol for use by +// UEFI app code that's not a driver model participant +efi_status xefi_open_protocol(efi_handle h, efi_guid* guid, void** ifc); +efi_status xefi_close_protocol(efi_handle h, efi_guid* guid); + +efi_file_protocol* xefi_open_file(const char16_t* filename); +void* xefi_read_file(efi_file_protocol* file, size_t* _sz, size_t front_bytes); +void* xefi_load_file(const char16_t* filename, size_t* size_out, size_t front_bytes); +void xefi_free(void* data, size_t size); + +efi_status xefi_find_pci_mmio(efi_boot_services* bs, uint8_t cls, uint8_t sub, uint8_t ifc, uint64_t* mmio); + +// GUIDs +extern efi_guid SimpleFileSystemProtocol; +extern efi_guid FileInfoGUID; + +typedef struct { + efi_handle img; + efi_system_table* sys; + efi_boot_services* bs; + efi_simple_text_output_protocol* conout; + efi_serial_io_protocol* serialout; +} xefi_global; + +extern xefi_global xefi_global_state; + +// Global Context +#define gImg (xefi_global_state.img) +#define gSys (xefi_global_state.sys) +#define gBS (xefi_global_state.bs) +#define gConOut (xefi_global_state.conout) +#define gSerialOut (xefi_global_state.serialout) + + diff --git a/inet.c b/inet.c new file mode 100644 index 0000000..83fc2de --- /dev/null +++ b/inet.c @@ -0,0 +1,38 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#ifndef __BYTE_ORDER__ +#error __BYTE_ORDER__ not defined! +#endif + +#ifndef __ORDER_LITTLE_ENDIAN__ +#error __ORDER_LITTLE_ENDIAN__ not defined! +#endif + +uint16_t htons(uint16_t val) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return __builtin_bswap16(val); +#else + return val; +#endif +} + +uint16_t ntohs(uint16_t val) { + return htons(val); +} + +uint32_t htonl(uint32_t val) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return __builtin_bswap32(val); +#else + return val; +#endif +} + +uint32_t ntohl(uint32_t val) { + return htonl(val); +} + diff --git a/inet6.c b/inet6.c new file mode 100644 index 0000000..48cda9b --- /dev/null +++ b/inet6.c @@ -0,0 +1,465 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include + +#include "inet6.h" +#include "netboot.h" + +// Enable at your own risk. Some of these packet errors can be fairly +// common when the buffers start to overflow. +#if 0 +#define BAD(n, ...) \ + do { \ + printf("error: "); \ + printf(n, ##__VA_ARGS__); \ + printf("\n"); \ + return; \ + } while (0) +#else +#define BAD(n, ...) \ + do { \ + return; \ + } while (0) +#endif + +// useful addresses +const ip6_addr ip6_ll_all_nodes = { + .x = {0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, +}; +const ip6_addr ip6_ll_all_routers = { + .x = {0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}, +}; + +// Convert MAC Address to IPv6 Link Local Address +// aa:bb:cc:dd:ee:ff => FF80::aabb:ccFF:FEdd:eeff +// bit 2 (U/L) of the mac is inverted +void ll6addr_from_mac(ip6_addr* _ip, const mac_addr* _mac) { + uint8_t* ip = _ip->x; + const uint8_t* mac = _mac->x; + memset(ip, 0, IP6_ADDR_LEN); + ip[0] = 0xFE; + ip[1] = 0x80; + memset(ip + 2, 0, 6); + ip[8] = mac[0] ^ 2; + ip[9] = mac[1]; + ip[10] = mac[2]; + ip[11] = 0xFF; + ip[12] = 0xFE; + ip[13] = mac[3]; + ip[14] = mac[4]; + ip[15] = mac[5]; +} + +// Convert MAC Address to IPv6 Solicit Neighbor Multicast Address +// aa:bb:cc:dd:ee:ff -> FF02::1:FFdd:eeff +void snmaddr_from_mac(ip6_addr* _ip, const mac_addr* _mac) { + uint8_t* ip = _ip->x; + const uint8_t* mac = _mac->x; + ip[0] = 0xFF; + ip[1] = 0x02; + memset(ip + 2, 0, 9); + ip[11] = 0x01; + ip[12] = 0xFF; + ip[13] = mac[3]; + ip[14] = mac[4]; + ip[15] = mac[5]; +} + +// Convert IPv6 Multicast Address to Ethernet Multicast Address +void multicast_from_ip6(mac_addr* _mac, const ip6_addr* _ip6) { + const uint8_t* ip = _ip6->x; + uint8_t* mac = _mac->x; + mac[0] = 0x33; + mac[1] = 0x33; + mac[2] = ip[12]; + mac[3] = ip[13]; + mac[4] = ip[14]; + mac[5] = ip[15]; +} + +// ip6 stack configuration +mac_addr ll_mac_addr; +ip6_addr ll_ip6_addr; +mac_addr snm_mac_addr; +ip6_addr snm_ip6_addr; + +// cache for the last source addresses we've seen +static mac_addr rx_mac_addr; +static ip6_addr rx_ip6_addr; + +void ip6_init(void* macaddr) { + char tmp[IP6TOAMAX]; + mac_addr all; + + // save our ethernet MAC and synthesize link layer addresses + memcpy(&ll_mac_addr, macaddr, 6); + ll6addr_from_mac(&ll_ip6_addr, &ll_mac_addr); + snmaddr_from_mac(&snm_ip6_addr, &ll_mac_addr); + multicast_from_ip6(&snm_mac_addr, &snm_ip6_addr); + + eth_add_mcast_filter(&snm_mac_addr); + + multicast_from_ip6(&all, &ip6_ll_all_nodes); + eth_add_mcast_filter(&all); + + printf("macaddr: %02x:%02x:%02x:%02x:%02x:%02x\n", + ll_mac_addr.x[0], ll_mac_addr.x[1], ll_mac_addr.x[2], + ll_mac_addr.x[3], ll_mac_addr.x[4], ll_mac_addr.x[5]); + printf("ip6addr: %s\n", ip6toa(tmp, &ll_ip6_addr)); + printf("snmaddr: %s\n", ip6toa(tmp, &snm_ip6_addr)); +} + +mac_addr eth_addr(void) { + return ll_mac_addr; +} + +static int resolve_ip6(mac_addr* _mac, const ip6_addr* _ip) { + const uint8_t* ip = _ip->x; + + // Multicast addresses are a simple transform + if (ip[0] == 0xFF) { + multicast_from_ip6(_mac, _ip); + return 0; + } + + // Trying to send to the IP that we last received a packet from? + // Assume their mac address has not changed + if (memcmp(_ip, &rx_ip6_addr, sizeof(rx_ip6_addr)) == 0) { + memcpy(_mac, &rx_mac_addr, sizeof(rx_mac_addr)); + return 0; + } + + // We don't know how to find peers or routers yet, so give up... + return -1; +} + +static uint16_t checksum(const void* _data, size_t len, uint16_t _sum) { + uint32_t sum = _sum; + const uint16_t* data = _data; + while (len > 1) { + sum += *data++; + len -= 2; + } + if (len) { + sum += (*data & 0xFF); + } + while (sum > 0xFFFF) { + sum = (sum & 0xFFFF) + (sum >> 16); + } + return sum; +} + +typedef struct { + uint8_t eth[16]; + ip6_hdr ip6; + uint8_t data[0]; +} ip6_pkt; + +typedef struct { + uint8_t eth[16]; + ip6_hdr ip6; + udp_hdr udp; + uint8_t data[0]; +} udp_pkt; + +static unsigned ip6_checksum(ip6_hdr* ip, unsigned type, size_t length) { + uint16_t sum; + + // length and protocol field for pseudo-header + sum = checksum(&ip->length, 2, htons(type)); + // src/dst for pseudo-header + payload + sum = checksum(ip->src, 32 + length, sum); + + // 0 is illegal, so 0xffff remains 0xffff + if (sum != 0xffff) { + return ~sum; + } else { + return sum; + } +} + +static int ip6_setup(ip6_pkt* p, const ip6_addr* daddr, size_t length, uint8_t type) { + mac_addr dmac; + + if (resolve_ip6(&dmac, daddr)) + return -1; + + // ethernet header + memcpy(p->eth + 2, &dmac, ETH_ADDR_LEN); + memcpy(p->eth + 8, &ll_mac_addr, ETH_ADDR_LEN); + p->eth[14] = (ETH_IP6 >> 8) & 0xFF; + p->eth[15] = ETH_IP6 & 0xFF; + + // ip6 header + p->ip6.ver_tc_flow = 0x60; // v=6, tc=0, flow=0 + p->ip6.length = htons(length); + p->ip6.next_header = type; + p->ip6.hop_limit = 255; + memcpy(p->ip6.src, &ll_ip6_addr, sizeof(ip6_addr)); + memcpy(p->ip6.dst, daddr, sizeof(ip6_addr)); + + return 0; +} + +#define UDP6_MAX_PAYLOAD (ETH_MTU - ETH_HDR_LEN - IP6_HDR_LEN - UDP_HDR_LEN) + +int udp6_send(const void* data, size_t dlen, const ip6_addr* daddr, uint16_t dport, uint16_t sport) { + size_t length = dlen + UDP_HDR_LEN; + udp_pkt* p = eth_get_buffer(ETH_MTU + 2); + + if (p == NULL) + return -1; + if (dlen > UDP6_MAX_PAYLOAD) { + printf("Internal error: UDP write request is too long\n"); + goto fail; + } + if (ip6_setup((void*)p, daddr, length, HDR_UDP)) { + printf("Error: ip6_setup failed!\n"); + goto fail; + } + + // udp header + p->udp.src_port = htons(sport); + p->udp.dst_port = htons(dport); + p->udp.length = htons(length); + p->udp.checksum = 0; + + memcpy(p->data, data, dlen); + p->udp.checksum = ip6_checksum(&p->ip6, HDR_UDP, length); + return eth_send(p->eth + 2, ETH_HDR_LEN + IP6_HDR_LEN + length); + +fail: + eth_put_buffer(p); + return -1; +} + +#define ICMP6_MAX_PAYLOAD (ETH_MTU - ETH_HDR_LEN - IP6_HDR_LEN) + +static int icmp6_send(const void* data, size_t length, const ip6_addr* daddr) { + ip6_pkt* p; + icmp6_hdr* icmp; + + p = eth_get_buffer(ETH_MTU + 2); + if (p == NULL) + return -1; + if (length > ICMP6_MAX_PAYLOAD) { + printf("Internal error: ICMP write request is too long\n"); + goto fail; + } + if (ip6_setup(p, daddr, length, HDR_ICMP6)) { + printf("Error: ip6_setup failed!\n"); + goto fail; + } + + icmp = (void*)p->data; + memcpy(icmp, data, length); + icmp->checksum = ip6_checksum(&p->ip6, HDR_ICMP6, length); + return eth_send(p->eth + 2, ETH_HDR_LEN + IP6_HDR_LEN + length); + +fail: + eth_put_buffer(p); + return -1; +} + +void udp6_recv(ip6_hdr* ip, void* _data, size_t len) { + udp_hdr* udp = _data; + uint16_t sum, n; + + if (len < UDP_HDR_LEN) + BAD("Bogus Header Len"); + + if (udp->checksum == 0) + BAD("Missing checksum"); + + if (udp->checksum == 0xFFFF) + udp->checksum = 0; + + sum = checksum(&ip->length, 2, htons(HDR_UDP)); + sum = checksum(ip->src, 32 + len, sum); + if (sum != 0xFFFF) + BAD("Checksum Incorrect"); + + n = ntohs(udp->length); + if (n < UDP_HDR_LEN) + BAD("Bogus Header Len"); + if (n > len) + BAD("Packet Too Short"); + len = n - UDP_HDR_LEN; + + uint16_t dport = ntohs(udp->dst_port); + uint16_t sport = ntohs(udp->src_port); + + switch (dport) { + case NB_SERVER_PORT: + netboot_recv((uint8_t*)_data + UDP_HDR_LEN, len, (void*)ip->src, sport); + break; + case NB_TFTP_INCOMING_PORT: + case NB_TFTP_OUTGOING_PORT: + tftp_recv((uint8_t*)_data + UDP_HDR_LEN, len, (void*)ip->dst, dport, (void*)ip->src, sport); + break; + default: + // Ignore + return; + } +} + +void icmp6_recv(ip6_hdr* ip, void* _data, size_t len) { + icmp6_hdr* icmp = _data; + uint16_t sum; + + if (icmp->checksum == 0) + BAD("Checksum Invalid"); + if (icmp->checksum == 0xFFFF) + icmp->checksum = 0; + + sum = checksum(&ip->length, 2, htons(HDR_ICMP6)); + sum = checksum(ip->src, 32 + len, sum); + if (sum != 0xFFFF) + BAD("Checksum Incorrect"); + + if (icmp->type == ICMP6_NDP_N_SOLICIT) { + ndp_n_hdr* ndp = _data; + struct { + ndp_n_hdr hdr; + uint8_t opt[8]; + } msg; + + if (len < sizeof(ndp_n_hdr)) + BAD("Bogus NDP Message"); + if (ndp->code != 0) + BAD("Bogus NDP Code"); + if (memcmp(ndp->target, &ll_ip6_addr, IP6_ADDR_LEN)) + BAD("NDP Not For Me"); + + msg.hdr.type = ICMP6_NDP_N_ADVERTISE; + msg.hdr.code = 0; + msg.hdr.checksum = 0; + msg.hdr.flags = 0x60; // (S)olicited and (O)verride flags + memcpy(msg.hdr.target, &ll_ip6_addr, IP6_ADDR_LEN); + msg.opt[0] = NDP_N_TGT_LL_ADDR; + msg.opt[1] = 1; + memcpy(msg.opt + 2, &ll_mac_addr, ETH_ADDR_LEN); + + icmp6_send(&msg, sizeof(msg), (void*)ip->src); + return; + } + + if (icmp->type == ICMP6_ECHO_REQUEST) { + icmp->checksum = 0; + icmp->type = ICMP6_ECHO_REPLY; + icmp6_send(_data, len, (void*)ip->src); + return; + } + + BAD("ICMP6 Unhandled %d", icmp->type); +} + +void eth_recv(void* _data, size_t len) { + uint8_t* data = _data; + ip6_hdr* ip; + uint32_t n; + + if (len < (ETH_HDR_LEN + IP6_HDR_LEN)) + BAD("Bogus Header Len"); + if (data[12] != (ETH_IP6 >> 8) || data[13] != (ETH_IP6 & 0xFF)) + BAD("Not IP6"); + + ip = (void*)(data + ETH_HDR_LEN); + data += (ETH_HDR_LEN + IP6_HDR_LEN); + len -= (ETH_HDR_LEN + IP6_HDR_LEN); + + // require v6 + if ((ip->ver_tc_flow & 0xF0) != 0x60) + BAD("Unknown IP6 Version"); + + // ensure length is sane + n = ntohs(ip->length); + if (n > len) + BAD("IP6 Length Mismatch %d %zu", n, len); + + // ignore any trailing data in the ethernet frame + len = n; + + // require that we are the destination + if (memcmp(&ll_ip6_addr, ip->dst, IP6_ADDR_LEN) && + memcmp(&snm_ip6_addr, ip->dst, IP6_ADDR_LEN) && + memcmp(&ip6_ll_all_nodes, ip->dst, IP6_ADDR_LEN)) { + return; + } + + // stash the sender's info to simplify replies + memcpy(&rx_mac_addr, (uint8_t*)_data + 6, ETH_ADDR_LEN); + memcpy(&rx_ip6_addr, ip->src, IP6_ADDR_LEN); + + if (ip->next_header == HDR_ICMP6) { + icmp6_recv(ip, data, len); + return; + } + + if (ip->next_header == HDR_UDP) { + udp6_recv(ip, data, len); + return; + } + + BAD("Unhandled IP6 %d", ip->next_header); +} + +char* ip6toa(char* _out, void* ip6addr) { + const uint8_t* x = ip6addr; + const uint8_t* end = x + 16; + char* out = _out; + uint16_t n; + + n = (x[0] << 8) | x[1]; + while ((n == 0) && (x < end)) { + x += 2; + n = (x[0] << 8) | x[1]; + } + + if ((end - x) < 16) { + if (end == x) { + // all 0s - special case + sprintf(out, "::"); + return _out; + } + // we consumed some number of leading 0s + out += sprintf(out, ":"); + while (x < end) { + out += sprintf(out, ":%x", n); + x += 2; + n = (x[0] << 8) | x[1]; + } + return _out; + } + + while (x < (end - 2)) { + out += sprintf(out, "%x:", n); + x += 2; + n = (x[0] << 8) | x[1]; + if (n == 0) + goto middle_zeros; + } + out += sprintf(out, "%x", n); + return _out; + +middle_zeros: + while ((n == 0) && (x < end)) { + x += 2; + n = (x[0] << 8) | x[1]; + } + if (x == end) { + out += sprintf(out, ":"); + return _out; + } + out += sprintf(out, ":%x", n); + while (x < (end - 2)) { + x += 2; + n = (x[0] << 8) | x[1]; + out += sprintf(out, ":%x", n); + } + return _out; +} diff --git a/inet6.h b/inet6.h new file mode 100644 index 0000000..43de05e --- /dev/null +++ b/inet6.h @@ -0,0 +1,171 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +typedef struct mac_addr_t mac_addr; +typedef struct ip6_addr_t ip6_addr; +typedef struct ip6_hdr_t ip6_hdr; +typedef struct udp_hdr_t udp_hdr; +typedef struct icmp6_hdr_t icmp6_hdr; +typedef struct ndp_n_hdr_t ndp_n_hdr; + +#define ETH_ADDR_LEN 6 +#define ETH_HDR_LEN 14 +#define ETH_MTU 1514 + +#define IP6_ADDR_LEN 16 +#define IP6_HDR_LEN 40 + +#define IP6_MIN_MTU 1280 + +#define UDP_HDR_LEN 8 + +struct mac_addr_t { + uint8_t x[ETH_ADDR_LEN]; +} __attribute__((packed)); + +struct ip6_addr_t { + uint8_t x[IP6_ADDR_LEN]; +} __attribute__((packed)); + +extern const ip6_addr ip6_ll_all_nodes; +extern const ip6_addr ip6_ll_all_routers; + +#define ETH_IP4 0x0800 +#define ETH_ARP 0x0806 +#define ETH_IP6 0x86DD + +#define HDR_HNH_OPT 0 +#define HDR_TCP 6 +#define HDR_UDP 17 +#define HDR_ROUTING 43 +#define HDR_FRAGMENT 44 +#define HDR_ICMP6 58 +#define HDR_NONE 59 +#define HDR_DST_OPT 60 + +struct ip6_hdr_t { + uint32_t ver_tc_flow; + uint16_t length; + uint8_t next_header; + uint8_t hop_limit; + uint8_t src[IP6_ADDR_LEN]; + uint8_t dst[IP6_ADDR_LEN]; +} __attribute__((packed)); + +struct udp_hdr_t { + uint16_t src_port; + uint16_t dst_port; + uint16_t length; + uint16_t checksum; +} __attribute__((packed)); + +#define ICMP6_DEST_UNREACHABLE 1 +#define ICMP6_PACKET_TOO_BIG 2 +#define ICMP6_TIME_EXCEEDED 3 +#define ICMP6_PARAMETER_PROBLEM 4 + +#define ICMP6_ECHO_REQUEST 128 +#define ICMP6_ECHO_REPLY 129 + +#define ICMP6_NDP_N_SOLICIT 135 +#define ICMP6_NDP_N_ADVERTISE 136 + +struct icmp6_hdr_t { + uint8_t type; + uint8_t code; + uint16_t checksum; +} __attribute__((packed)); + +struct ndp_n_hdr_t { + uint8_t type; + uint8_t code; + uint16_t checksum; + uint32_t flags; + uint8_t target[IP6_ADDR_LEN]; + uint8_t options[0]; +} __attribute__((packed)); + +#define NDP_N_SRC_LL_ADDR 1 +#define NDP_N_TGT_LL_ADDR 2 +#define NDP_N_PREFIX_INFO 3 +#define NDP_N_REDIRECTED_HDR 4 +#define NDP_N_MTU 5 + +#ifndef ntohs +#define ntohs(n) _swap16(n) +#define htons(n) _swap16(n) +static inline uint16_t _swap16(uint16_t n) { + return (n >> 8) | (n << 8); +} +#endif + +#ifndef ntohl +#define ntohl(n) _swap32(n) +#define htonl(n) _swap32(n) +static inline uint32_t _swap32(uint32_t n) { + return (n >> 24) | ((n >> 8) & 0xFF00) | + ((n & 0xFF00) << 8) | (n << 24); +} +#endif + +// Formats an IP6 address into the provided buffer (which must be +// at least IP6TOAMAX bytes in size), and returns the buffer address. +char* ip6toa(char* _out, void* ip6addr); +#define IP6TOAMAX 40 + +// provided by inet6.c +void ip6_init(void* macaddr); +void eth_recv(void* data, size_t len); +mac_addr eth_addr(void); + +// provided by interface driver +void* eth_get_buffer(size_t len); +void eth_put_buffer(void* ptr); +int eth_send(void* data, size_t len); +int eth_add_mcast_filter(const mac_addr* addr); + +// call to transmit a UDP packet +int udp6_send(const void* data, size_t len, + const ip6_addr* daddr, uint16_t dport, + uint16_t sport); + +// handle a netboot UDP packet +void netboot_recv(void* data, size_t len, const ip6_addr* saddr, uint16_t sport); + +// handle a TFTP (over UDP) packet +void tftp_recv (void* data, size_t len, const ip6_addr* daddr, uint16_t dport, + const ip6_addr* saddr, uint16_t sport); + +// NOTES +// +// This is an extremely minimal IPv6 stack, supporting just enough +// functionality to talk to link local hosts over UDP. +// +// It responds to ICMPv6 Neighbor Solicitations for its link local +// address, which is computed from the mac address provided by the +// ethernet interface driver. +// +// It responds to PINGs. +// +// It can only transmit to multicast addresses or to the address it +// last received a packet from (general usecase is to reply to a UDP +// packet from the UDP callback, which this supports) +// +// It does not currently do duplicate address detection, which is +// probably the most severe bug. +// +// It does not support any IPv6 options and will drop packets with +// options. +// +// It expects the network stack to provide transmit buffer allocation +// and free functionality. It will allocate a single transmit buffer +// from udp6_send() or icmp6_send() to fill out and either pass to the +// network stack via eth_send() or, in the event of an error, release +// via eth_put_buffer(). +// diff --git a/loadelf.c b/loadelf.c new file mode 100644 index 0000000..99d30e9 --- /dev/null +++ b/loadelf.c @@ -0,0 +1,136 @@ +#include "loadelf.h" + +#include "bootinfo.h" +#include "compiler.h" +#include "elf.h" +#include "string.h" +#include "uniboot.h" +#include "xefi.h" + +static void elf_check_header(Elf64_Ehdr *hdr) { + if (strncmp((char *)hdr->e_ident, ELFMAG, SELFMAG)) { + xefi_fatal("app.elf: invalid ELF header magic value", EFI_LOAD_ERROR); + } + if (hdr->e_ident[EI_CLASS] != ELFCLASS64) { + xefi_fatal("app.elf: only 64-bit ELF booting is supported", EFI_LOAD_ERROR); + } + if (hdr->e_type != ET_EXEC) { + xefi_fatal("app.elf: only ELF executable file booting is supported", EFI_LOAD_ERROR); + } +} + +static void elf_load_segments(void *data) { + Elf64_Ehdr *hdr = data; + void *phdr_p = data + hdr->e_phoff; + efi_physical_addr previous_end = 0; // we use it to track adjusted PT_LOAD segments that share the same page + for (int i = 0; i < hdr->e_phnum; i++) { + Elf64_Phdr *phdr = phdr_p; + + if (phdr->p_type != PT_LOAD) + continue; + + efi_physical_addr addr = phdr->p_paddr; + efi_physical_addr start = ROUND_DOWN(addr, PAGE_SIZE); + efi_physical_addr end = ROUND_UP(addr + phdr->p_memsz, PAGE_SIZE); + + if (previous_end > start) + start = previous_end; + previous_end = end; + + size_t pages = (end - start) / PAGE_SIZE; + if (pages) { + efi_status r = gBS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &start); + if (r) { + xefi_fatal("load_elf: Cannot allocate buffer", r); + } + } + + // copy ELF segment data + memcpy((void *)addr, data + phdr->p_offset, phdr->p_filesz); + + // the end of segment is zero-outed area (e.g. BSS) + memset((void *)addr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + + phdr_p += hdr->e_phentsize; + } +} + +static void uniboot_populate_segments(void *data) { + Elf64_Ehdr *hdr = data; + + size_t segment_list_size = sizeof(struct uniboot_segment_list) + hdr->e_phnum * sizeof(struct uniboot_segment); + + struct uniboot_entry *entry = bootinfo_alloc(struct uniboot_entry); + entry->type = UNIBOOT_ENTRY_SEGMENT_LIST; + entry->length = segment_list_size; + + struct uniboot_segment_list *segs = bootinfo_alloc_size(segment_list_size); + segs->num = hdr->e_phnum; + + void *phdr_p = data + hdr->e_phoff; + for (int i = 0; i < hdr->e_phnum; i++) { + Elf64_Phdr *phdr = phdr_p; + + segs->segments[i].type = phdr->p_type; + segs->segments[i].flags = phdr->p_flags; + segs->segments[i].offset = phdr->p_offset; + segs->segments[i].vaddr = phdr->p_vaddr; + segs->segments[i].paddr = phdr->p_paddr; + segs->segments[i].filesz = phdr->p_filesz; + segs->segments[i].memsz = phdr->p_memsz; + segs->segments[i].align = phdr->p_align; + + phdr_p += hdr->e_phentsize; + } +} + +static void uniboot_populate_sections(void *data) { + Elf64_Ehdr *hdr = data; + + size_t section_list_size = sizeof(struct uniboot_section_list) + hdr->e_shnum * sizeof(struct uniboot_section); + + struct uniboot_entry *entry = bootinfo_alloc(struct uniboot_entry); + entry->type = UNIBOOT_ENTRY_SECTION_LIST; + entry->length = section_list_size; + + struct uniboot_section_list *list = bootinfo_alloc_size(section_list_size); + list->num = hdr->e_shnum; + struct uniboot_section *sec = list->sections; + + void *shdr_p = data + hdr->e_shoff; + for (int i = 0; i < hdr->e_shnum; i++) { + Elf64_Shdr *shdr = shdr_p; + + sec[i].name = shdr->sh_name; + sec[i].type = shdr->sh_type; + sec[i].flags = shdr->sh_flags; + sec[i].addr = shdr->sh_addr; + sec[i].size = shdr->sh_size; + sec[i].addralign = shdr->sh_addralign; + sec[i].entsize = shdr->sh_entsize; + + + shdr_p += hdr->e_shentsize; + } +} + +void *elf_load(void *data, size_t size) { + if (!data) { + xefi_fatal("xefi_load_file", EFI_LOAD_ERROR); + } + if (size < sizeof(Elf64_Ehdr)) { + xefi_fatal("app.elf size is too small", EFI_LOAD_ERROR); + } + + Elf64_Ehdr *hdr = (Elf64_Ehdr *)data; + elf_check_header(hdr); + + void *entry = (void *)hdr->e_entry; + elf_load_segments(data); + uniboot_populate_segments(data); + uniboot_populate_sections(data); + + xefi_free(data, size); + + return entry; +} diff --git a/loadelf.h b/loadelf.h new file mode 100644 index 0000000..1f436b8 --- /dev/null +++ b/loadelf.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +// Loads ELF segments into memory and returns pointer to entry point +void *elf_load(void *data, size_t size); \ No newline at end of file diff --git a/netboot.c b/netboot.c new file mode 100644 index 0000000..a5727da --- /dev/null +++ b/netboot.c @@ -0,0 +1,379 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "device_id.h" +#include "inet6.h" +#include "netifc.h" +#include + +#include "netboot.h" +#include "tftp/tftp.h" + +#define TFTP_BUF_SZ 2048 +char tftp_session_scratch[TFTP_BUF_SZ]; +char tftp_out_scratch[TFTP_BUF_SZ]; + +// item being downloaded +static nbfile* item; + +// TFTP file state +typedef struct { + nbfile* netboot_file_data; + size_t file_size; + unsigned int progress_reported; +} file_info_t; + +// TFTP transport state +typedef struct { + struct ip6_addr_t dest_addr; + uint16_t dest_port; +} transport_info_t; + +static uint32_t last_cookie = 0; +static uint32_t last_cmd = 0; +static uint32_t last_arg = 0; +static uint32_t last_ack_cmd = 0; +static uint32_t last_ack_arg = 0; + +static int nb_boot_now = 0; +static int nb_active = 0; + +static char advertise_nodename[64] = ""; +static char advertise_data[256] = "nodename=unicycle"; + +static void send_query_ack(const ip6_addr* addr, uint16_t port, + uint32_t cookie) { + uint8_t buffer[256]; + nbmsg* msg = (void*)buffer; + msg->magic = NB_MAGIC; + msg->cookie = cookie; + msg->cmd = NB_ACK; + msg->arg = NB_VERSION_CURRENT; + memcpy(msg->data, advertise_nodename, sizeof(advertise_nodename)); + udp6_send(buffer, sizeof(nbmsg) + strlen(advertise_nodename) + 1, + addr, port, NB_SERVER_PORT); +} + +static void advertise(void) { + uint8_t buffer[sizeof(nbmsg) + sizeof(advertise_data)]; + nbmsg* msg = (void*)buffer; + msg->magic = NB_MAGIC; + msg->cookie = 0; + msg->cmd = NB_ADVERTISE; + msg->arg = NB_VERSION_CURRENT; + size_t data_len = strlen(advertise_data) + 1; + memcpy(msg->data, advertise_data, data_len); + udp6_send(buffer, sizeof(nbmsg) + data_len, &ip6_ll_all_nodes, + NB_ADVERT_PORT, NB_SERVER_PORT); +} + +void netboot_recv(void* data, size_t len, const ip6_addr* saddr, uint16_t sport) { + nbmsg* msg = data; + nbmsg ack; + int do_transmit = 1; + + if (len < sizeof(nbmsg)) + return; + len -= sizeof(nbmsg); + + // printf("netboot: MSG %08x %08x %08x %08x datalen %zu\n", + // msg->magic, msg->cookie, msg->cmd, msg->arg, len); + + if ((last_cookie == msg->cookie) && + (last_cmd == msg->cmd) && (last_arg == msg->arg)) { + // host must have missed the ack. resend + ack.magic = NB_MAGIC; + ack.cookie = last_cookie; + ack.cmd = last_ack_cmd; + ack.arg = last_ack_arg; + goto transmit; + } + + ack.cmd = NB_ACK; + ack.arg = 0; + + switch (msg->cmd) { + case NB_COMMAND: + if (len == 0) + return; + msg->data[len - 1] = 0; + break; + case NB_SEND_FILE: + if (len == 0) + return; + msg->data[len - 1] = 0; + for (size_t i = 0; i < (len - 1); i++) { + if ((msg->data[i] < ' ') || (msg->data[i] > 127)) { + msg->data[i] = '.'; + } + } + item = netboot_get_buffer((const char*)msg->data, msg->arg); + if (item) { + item->offset = 0; + ack.arg = msg->arg; + size_t prefix_len = strlen(NB_FILENAME_PREFIX); + const char* filename; + if (!strncmp((char*)msg->data, NB_FILENAME_PREFIX, prefix_len)) { + filename = &((const char*)msg->data)[prefix_len]; + } else { + filename = (const char*)msg->data; + } + printf("netboot: Receive File '%s'...\n", filename); + } else { + printf("netboot: Rejected File '%s'...\n", (char*) msg->data); + ack.cmd = NB_ERROR_BAD_FILE; + } + break; + + case NB_DATA: + case NB_LAST_DATA: + if (item == 0) { + printf("netboot: > received chunk before NB_FILE\n"); + return; + } + if (msg->arg != item->offset) { + // printf("netboot: < received chunk at offset %d but current offset is %zu\n", msg->arg, item->offset); + ack.arg = item->offset; + ack.cmd = NB_ACK; + } else if ((item->offset + len) > item->size) { + ack.cmd = NB_ERROR_TOO_LARGE; + ack.arg = msg->arg; + } else { + memcpy(item->data + item->offset, msg->data, len); + item->offset += len; + ack.cmd = msg->cmd == NB_LAST_DATA ? NB_FILE_RECEIVED : NB_ACK; + if (msg->cmd != NB_LAST_DATA) { + do_transmit = 0; + } + } + break; + case NB_BOOT: + nb_boot_now = 1; + printf("netboot: Boot Unicycle Application...\n"); + break; + case NB_QUERY: + // Send reply and return w/o getting the netboot state out of sync. + send_query_ack(saddr, sport, msg->cookie); + return; + default: + ack.cmd = NB_ERROR_BAD_CMD; + ack.arg = 0; + } + + last_cookie = msg->cookie; + last_cmd = msg->cmd; + last_arg = msg->arg; + last_ack_cmd = ack.cmd; + last_ack_arg = ack.arg; + + ack.cookie = msg->cookie; + ack.magic = NB_MAGIC; +transmit: + nb_active = 1; + if (do_transmit) { + // printf("netboot: MSG %08x %08x %08x %08x\n", + // ack.magic, ack.cookie, ack.cmd, ack.arg); + + udp6_send(&ack, sizeof(ack), saddr, sport, NB_SERVER_PORT); + } +} + +static tftp_status buffer_open(const char* filename, size_t size, void* cookie) { + file_info_t* file_info = cookie; + file_info->netboot_file_data = netboot_get_buffer(filename, size); + if (file_info->netboot_file_data == NULL) { + printf("netboot: unrecognized file %s - rejecting\n", filename); + return TFTP_ERR_INVALID_ARGS; + } + file_info->netboot_file_data->offset = 0; + const char* base_filename; + size_t prefix_len = strlen(NB_FILENAME_PREFIX); + if (!strncmp(filename, NB_FILENAME_PREFIX, prefix_len)) { + base_filename = &filename[prefix_len]; + } else { + base_filename = filename; + } + printf("Receiving %s [%lu bytes]... ", base_filename, (unsigned long)size); + file_info->file_size = size; + file_info->progress_reported = 0; + return TFTP_NO_ERROR; +} + +static tftp_status buffer_write(const void* data, size_t* len, off_t offset, void* cookie) { + file_info_t* file_info = cookie; + nbfile* nb_buf_info = file_info->netboot_file_data; + if (offset > nb_buf_info->size || (offset + *len) > nb_buf_info->size) { + printf("netboot: attempt to write past end of buffer\n"); + return TFTP_ERR_INVALID_ARGS; + } + memcpy(&nb_buf_info->data[offset], data, *len); + nb_buf_info->offset = offset + *len; + if (file_info->file_size >= 100) { + unsigned int progress_pct = offset / (file_info->file_size / 100); + if ((progress_pct > file_info->progress_reported) && + (progress_pct - file_info->progress_reported >= 5)) { + printf("%u%%... ", progress_pct); + file_info->progress_reported = progress_pct; + } + } + return TFTP_NO_ERROR; +} + +static void buffer_close(void* cookie) { + file_info_t* file_info = cookie; + file_info->netboot_file_data = NULL; + printf("Done\n"); +} + +static tftp_status udp_send(void* data, size_t len, void* cookie) { + transport_info_t* transport_info = cookie; + int bytes_sent = udp6_send(data, len, &transport_info->dest_addr, transport_info->dest_port, + NB_TFTP_OUTGOING_PORT); + return bytes_sent < 0 ? TFTP_ERR_IO : TFTP_NO_ERROR; +} + +static int udp_timeout_set(uint32_t timeout_ms, void* cookie) { + // TODO + return 0; +} + +static int strcmp8to16(const char* str8, const char16_t* str16) { + while (*str8 != '\0' && *str8 == *str16) { + str8++; + str16++; + } + return *str8 - *str16; +} + +void tftp_recv(void* data, size_t len, const ip6_addr* daddr, uint16_t dport, + const ip6_addr* saddr, uint16_t sport) { + static tftp_session* session = NULL; + static file_info_t file_info = {.netboot_file_data = NULL}; + static transport_info_t transport_info = {}; + + if (dport == NB_TFTP_INCOMING_PORT) { + if (session != NULL) { + printf("Aborting to service new connection\n"); + } + // Start TFTP session + int ret = tftp_init(&session, tftp_session_scratch, sizeof(tftp_session_scratch)); + if (ret != TFTP_NO_ERROR) { + printf("netboot: failed to initiate tftp session\n"); + session = NULL; + return; + } + + // Override our window size on the Acer tablet + if (!strcmp8to16("INSYDE Corp.", gSys->FirmwareVendor)) { + uint16_t window_size = 8; + tftp_set_options(session, NULL, NULL, &window_size); + } + + // Initialize file interface + tftp_file_interface file_ifc = {NULL, buffer_open, NULL, buffer_write, buffer_close}; + tftp_session_set_file_interface(session, &file_ifc); + + // Initialize transport interface + memcpy(&transport_info.dest_addr, saddr, sizeof(struct ip6_addr_t)); + transport_info.dest_port = sport; + tftp_transport_interface transport_ifc = {udp_send, NULL, udp_timeout_set}; + tftp_session_set_transport_interface(session, &transport_ifc); + } else if (!session) { + // Ignore anything sent to the outgoing port unless we've already established a connection + return; + } + + size_t outlen = sizeof(tftp_out_scratch); + + char err_msg[128]; + tftp_handler_opts handler_opts = {.inbuf = data, + .inbuf_sz = len, + .outbuf = tftp_out_scratch, + .outbuf_sz = &outlen, + .err_msg = err_msg, + .err_msg_sz = sizeof(err_msg)}; + tftp_status status = tftp_handle_msg(session, &transport_info, &file_info, &handler_opts); + if (status < 0) { + printf("netboot: tftp protocol error: %s\n", err_msg); + session = NULL; + } else if (status == TFTP_TRANSFER_COMPLETED) { + session = NULL; + } +} + +#define FAST_TICK 100 +#define SLOW_TICK 1000 + +int netboot_init(const char* nodename) { + if (netifc_open()) { + printf("netboot: Failed to open network interface\n"); + return -1; + } + char buf[DEVICE_ID_MAX]; + if (!nodename || (nodename[0] == 0)) { + device_id(eth_addr(), buf); + nodename = buf; + } + if (nodename) { + strncpy(advertise_nodename, nodename, sizeof(advertise_nodename) - 1); + snprintf(advertise_data, sizeof(advertise_data), + "version=%s;nodename=%s", BOOTLOADER_VERSION, nodename); + } + return 0; +} + +const char* netboot_nodename() { + return advertise_nodename; +} + +static int nb_fastcount = 0; +static int nb_online = 0; + +int netboot_poll(void) { + if (netifc_active()) { + if (nb_online == 0) { + printf("netboot: interface online\n"); + nb_online = 1; + nb_fastcount = 20; + netifc_set_timer(FAST_TICK); + advertise(); + } + } else { + if (nb_online == 1) { + printf("netboot: interface offline\n"); + nb_online = 0; + } + return 0; + } + if (netifc_timer_expired()) { + if (nb_fastcount) { + nb_fastcount--; + netifc_set_timer(FAST_TICK); + } else { + netifc_set_timer(SLOW_TICK); + } + if (nb_active) { + // don't advertise if we're in a transfer + nb_active = 0; + } else { + advertise(); + } + } + + netifc_poll(); + + if (nb_boot_now) { + nb_boot_now = 0; + return 1; + } else { + return 0; + } +} + +void netboot_close(void) { + netifc_close(); +} diff --git a/netboot.h b/netboot.h new file mode 100644 index 0000000..a5486cd --- /dev/null +++ b/netboot.h @@ -0,0 +1,92 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +// clang-format off + +#define BOOTLOADER_VERSION "0.7.9" + +#define NB_MAGIC 0xAA774217 +#define NB_DEBUGLOG_MAGIC 0xAEAE1123 + +#define NB_SERVER_PORT 33330 +#define NB_ADVERT_PORT 33331 +#define NB_CMD_PORT_START 33332 +#define NB_CMD_PORT_END 33339 +#define NB_TFTP_OUTGOING_PORT 33340 +#define NB_TFTP_INCOMING_PORT 33341 + + +#define NB_COMMAND 1 // arg=0, data=command +#define NB_SEND_FILE 2 // arg=size, data=filename +#define NB_DATA 3 // arg=offset, data=data +#define NB_BOOT 4 // arg=0 +#define NB_QUERY 5 // arg=0, data=hostname (or "*") +#define NB_SHELL_CMD 6 // arg=0, data=command string +#define NB_OPEN 7 // arg=O_RDONLY|O_WRONLY, data=filename +#define NB_READ 8 // arg=blocknum +#define NB_WRITE 9 // arg=blocknum, data=data +#define NB_CLOSE 10 // arg=0 +#define NB_LAST_DATA 11 // arg=offset, data=data +#define NB_REBOOT 12 // arg=0 + +#define NB_ACK 0 // arg=0 or -err, NB_READ: data=data +#define NB_FILE_RECEIVED 0x70000001 // arg=size + +#define NB_ADVERTISE 0x77777777 + +#define NB_ERROR 0x80000000 +#define NB_ERROR_BAD_CMD 0x80000001 +#define NB_ERROR_BAD_PARAM 0x80000002 +#define NB_ERROR_TOO_LARGE 0x80000003 +#define NB_ERROR_BAD_FILE 0x80000004 + +#define NB_VERSION_1_0 0x0001000 +#define NB_VERSION_1_1 0x0001010 +#define NB_VERSION_1_2 0x0001020 +#define NB_VERSION_1_3 0x0001030 +#define NB_VERSION_CURRENT NB_VERSION_1_3 + +#define NB_FILENAME_PREFIX "<>" +#define NB_APP_FILENAME NB_FILENAME_PREFIX "app.elf" + +typedef struct nbmsg_t { + uint32_t magic; + uint32_t cookie; + uint32_t cmd; + uint32_t arg; + uint8_t data[0]; +} nbmsg; + +typedef struct nbfile_t { + uint8_t* data; + size_t size; // max size of buffer + size_t offset; // write pointer +} nbfile; + +int netboot_init(const char* nodename); +const char* netboot_nodename(void); +int netboot_poll(void); +void netboot_close(void); + +// Ask for a buffer suitable to put the file /name/ in +// Return NULL to indicate /name/ is not wanted. +nbfile* netboot_get_buffer(const char* name, size_t size); + +#define DEBUGLOG_PORT 33337 +#define DEBUGLOG_ACK_PORT 33338 + +#define MAX_LOG_DATA 1216 +#define MAX_NODENAME_LENGTH 64 + +typedef struct logpacket { + uint32_t magic; + uint32_t seqno; + char nodename[MAX_NODENAME_LENGTH]; + char data[MAX_LOG_DATA]; +} logpacket_t; diff --git a/netifc.c b/netifc.c new file mode 100644 index 0000000..7dafb6f --- /dev/null +++ b/netifc.c @@ -0,0 +1,391 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include +#include +#include + +#include +#include "printf.h" + +#include "inet6.h" +#include "netifc.h" + +static efi_simple_network_protocol* snp; + +#define PAGE_SIZE 4096 + +#define MAX_FILTER 8 +static efi_mac_addr mcast_filters[MAX_FILTER]; +static unsigned mcast_filter_count = 0; + +// if nonzero, drop 1 in DROP_PACKETS packets at random +#define DROP_PACKETS 0 + +#if DROP_PACKETS > 0 + +//TODO: use libc random() once it's actually random + +// Xorshift32 prng +typedef struct { + uint32_t n; +} rand32_t; + +static inline uint32_t rand32(rand32_t* state) { + uint32_t n = state->n; + n ^= (n << 13); + n ^= (n >> 17); + n ^= (n << 5); + return (state->n = n); +} + +rand32_t rstate = {.n = 0x8716253}; +#define random() rand32(&rstate) + +static int txc; +static int rxc; +#endif + +#define NUM_BUFFER_PAGES 8 +#define ETH_BUFFER_SIZE 1516 +#define ETH_HEADER_SIZE 16 +#define ETH_BUFFER_MAGIC 0x424201020304A7A7UL + +typedef struct eth_buffer_t eth_buffer; +struct eth_buffer_t { + uint64_t magic; + eth_buffer* next; + uint8_t data[0]; +}; + +static efi_physical_addr eth_buffers_base = 0; +static eth_buffer* eth_buffers = NULL; +static int num_eth_buffers = 0; +static int eth_buffers_avail = 0; + +void* eth_get_buffer(size_t sz) { + eth_buffer* buf; + if (sz > ETH_BUFFER_SIZE) { + return NULL; + } + if (eth_buffers == NULL) { + return NULL; + } + buf = eth_buffers; + eth_buffers = buf->next; + buf->next = NULL; + eth_buffers_avail--; + return buf->data; +} + +void eth_put_buffer(void* data) { + efi_physical_addr buf_paddr = (efi_physical_addr)data; + if ((buf_paddr < eth_buffers_base) + || (buf_paddr >= (eth_buffers_base + (NUM_BUFFER_PAGES * PAGE_SIZE)))) { + printf("fatal: attempt to use buffer outside of allocated range\n"); + for (;;) + ; + } + + eth_buffer* buf = (void*)(buf_paddr & (~2047)); + if (buf->magic != ETH_BUFFER_MAGIC) { + printf("fatal: eth buffer %p (from %p) bad magic %" PRIx64 "\n", + buf, data, buf->magic); + for (;;) + ; + } + + buf->next = eth_buffers; + eth_buffers_avail++; + eth_buffers = buf; +} + +int eth_send(void* data, size_t len) { +#if DROP_PACKETS + txc++; + if ((random() % DROP_PACKETS) == 0) { + printf("tx drop %d\n", txc); + eth_put_buffer(data); + return 0; + } +#endif + efi_status r; + if ((r = snp->Transmit(snp, 0, len, (void*)data, NULL, NULL, NULL))) { + eth_put_buffer(data); + return -1; + } else { + return 0; + } +} + +void eth_dump_status(void) { +#ifdef VERBOSE + printf("State/HwAdSz/HdrSz/MaxSz %d %d %d %d\n", + snp->Mode->State, snp->Mode->HwAddressSize, + snp->Mode->MediaHeaderSize, snp->Mode->MaxPacketSize); + printf("RcvMask/RcvCfg/MaxMcast/NumMcast %d %d %d %d\n", + snp->Mode->ReceiveFilterMask, snp->Mode->ReceiveFilterSetting, + snp->Mode->MaxMCastFilterCount, snp->Mode->MCastFilterCount); + uint8_t* x = snp->Mode->CurrentAddress.addr; + printf("MacAddr %02x:%02x:%02x:%02x:%02x:%02x\n", + x[0], x[1], x[2], x[3], x[4], x[5]); + printf("SetMac/MultiTx/LinkDetect/Link %d %d %d %d\n", + snp->Mode->MacAddressChangeable, snp->Mode->MultipleTxSupported, + snp->Mode->MediaPresentSupported, snp->Mode->MediaPresent); +#endif +} + +int eth_add_mcast_filter(const mac_addr* addr) { + if (mcast_filter_count >= MAX_FILTER) + return -1; + if (mcast_filter_count >= snp->Mode->MaxMCastFilterCount) + return -1; + memcpy(mcast_filters + mcast_filter_count, addr, ETH_ADDR_LEN); + mcast_filter_count++; + return 0; +} + +static efi_event net_timer = NULL; + +#define TIMER_MS(n) (((uint64_t)(n)) * 10000UL) + +void netifc_set_timer(uint32_t ms) { + if (net_timer == 0) { + return; + } + gBS->SetTimer(net_timer, TimerRelative, TIMER_MS(ms)); +} + +int netifc_timer_expired(void) { + if (net_timer == 0) { + return 0; + } + if (gBS->CheckEvent(net_timer) == EFI_SUCCESS) { + return 1; + } + return 0; +} + +/* Search the available network interfaces via SimpleNetworkProtocol handles + * and find the first valid one with a Link detected */ +efi_simple_network_protocol* netifc_find_available(void) { + efi_boot_services* bs = gSys->BootServices; + efi_status ret; + efi_simple_network_protocol* cur_snp = NULL; + efi_handle handles[32]; + char16_t *paths[32]; + size_t nic_cnt = 0; + size_t sz = sizeof(handles); + uint32_t last_parent = 0; + uint32_t int_sts; + void *tx_buf; + + /* Get the handles of all devices that provide SimpleNetworkProtocol interfaces */ + ret = bs->LocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL, &sz, handles); + if (ret != EFI_SUCCESS) { + printf("Failed to locate network interfaces (%s)\n", xefi_strerror(ret)); + return NULL; + } + + nic_cnt = sz / sizeof(efi_handle); + for (size_t i = 0; i < nic_cnt; i++) { + paths[i] = xefi_handle_to_str(handles[i]); + } + + /* Iterate over our SNP list until we find one with an established link */ + for (size_t i = 0; i < nic_cnt; i++) { + /* Check each interface once, but ignore any additional device paths a given interface + * may provide. e1000 tends to add a path for ipv4 and ipv6 configuration information + * for instance */ + if (i != last_parent) { + if (memcmp(paths[i], paths[last_parent], strlen_16(paths[last_parent])) == 0) { + continue; + } else { + last_parent = i; + } + } + + puts16(paths[i]); + printf(": "); + ret = bs->HandleProtocol(handles[i], &SimpleNetworkProtocol, (void**)&cur_snp); + if (ret) { + printf("Failed to open (%s)\n", xefi_strerror(ret)); + continue; + } + + /* If a driver is provided by the firmware then it should be started already, but check + * to make sure. This also covers the case where we're providing the AX88772 driver in-line + * during this boot itself */ + ret = cur_snp->Start(cur_snp); + if (EFI_ERROR(ret) && ret != EFI_ALREADY_STARTED) { + printf("Failed to start (%s)", xefi_strerror(ret)); + goto link_fail; + } + + if (ret != EFI_ALREADY_STARTED) { + ret = cur_snp->Initialize(cur_snp, 0, 0); + if (EFI_ERROR(ret)) { + printf("Failed to initialize (%s)\n", xefi_strerror(ret)); + goto link_fail; + } + } + + /* Prod the driver to cache its current status. We don't need the status or buffer, + * but some drivers appear to require the OPTIONAL parameters. */ + ret = cur_snp->GetStatus(cur_snp, &int_sts, &tx_buf); + if (EFI_ERROR(ret)) { + printf("Failed to read status (%s)\n", xefi_strerror(ret)); + goto link_fail; + } + + /* With status cached, do we have a Link detected on the netifc? */ + if (!cur_snp->Mode->MediaPresent) { + printf("No link detected\n"); + goto link_fail; + } + + printf("Link detected!\n"); + return cur_snp; + +link_fail: + bs->CloseProtocol(handles[i], &SimpleNetworkProtocol, gImg, NULL); + cur_snp = NULL; + } + + return NULL; +} + +int netifc_open(void) { + efi_boot_services* bs = gSys->BootServices; + efi_status ret; + + bs->CreateEvent(EVT_TIMER, TPL_CALLBACK, NULL, NULL, &net_timer); + + snp = netifc_find_available(); + if (!snp) { + printf("Failed to find a usable network interface\n"); + return -1; + } + + if (bs->AllocatePages(AllocateAnyPages, EfiLoaderData, NUM_BUFFER_PAGES, ð_buffers_base)) { + printf("Failed to allocate net buffers\n"); + return -1; + } + + num_eth_buffers = NUM_BUFFER_PAGES * 2; + uint8_t* ptr = (void*)eth_buffers_base; + for (int i = 0; i < num_eth_buffers; ++i) { + eth_buffer* buf = (void*)ptr; + buf->magic = ETH_BUFFER_MAGIC; + eth_put_buffer(buf); + ptr += 2048; + } + + ip6_init(snp->Mode->CurrentAddress.addr); + + ret = snp->ReceiveFilters(snp, + EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST, + 0, 0, mcast_filter_count, (void*)mcast_filters); + if (ret) { + printf("Failed to install multicast filters %s\n", xefi_strerror(ret)); + return -1; + } + + eth_dump_status(); + + if (snp->Mode->MCastFilterCount != mcast_filter_count) { + printf("OOPS: expected %d filters, found %d\n", + mcast_filter_count, snp->Mode->MCastFilterCount); + goto force_promisc; + } + for (size_t i = 0; i < mcast_filter_count; i++) { + //uint8_t *m = (void*) &mcast_filters[i]; + //printf("i=%d %02x %02x %02x %02x %02x %02x\n", i, m[0], m[1], m[2], m[3], m[4], m[5]); + for (size_t j = 0; j < mcast_filter_count; j++) { + //m = (void*) &snp->Mode->MCastFilter[j]; + //printf("j=%d %02x %02x %02x %02x %02x %02x\n", j, m[0], m[1], m[2], m[3], m[4], m[5]); + if (!memcmp(mcast_filters + i, &snp->Mode->MCastFilter[j], 6)) { + goto found_it; + } + } + printf("OOPS: filter #%zu missing\n", i); + goto force_promisc; + found_it:; + } + + return 0; + +force_promisc: + ret = snp->ReceiveFilters(snp, + EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST, + 0, 0, 0, NULL); + if (ret) { + printf("Failed to set promiscuous mode (%s)\n", xefi_strerror(ret)); + return -1; + } + return 0; +} + +void netifc_close(void) { + gBS->SetTimer(net_timer, TimerCancel, 0); + gBS->CloseEvent(net_timer); + snp->Shutdown(snp); + snp->Stop(snp); +} + +int netifc_active(void) { + return (snp != 0); +} + +void netifc_poll(void) { + uint8_t data[1514]; + efi_status r; + size_t hsz, bsz; + uint32_t irq; + void* txdone; + + if (eth_buffers_avail < num_eth_buffers) { + // Only check for completion if we have operations in progress. + // Otherwise, the result of GetStatus is unreliable. See ZX-759. + if ((r = snp->GetStatus(snp, &irq, &txdone))) { + return; + } + if (txdone) { + // Check to make sure this is one of our buffers (see ZX-1516) + efi_physical_addr buf_paddr = (efi_physical_addr)txdone; + if ((buf_paddr >= eth_buffers_base) + && (buf_paddr < (eth_buffers_base + (NUM_BUFFER_PAGES * PAGE_SIZE)))) { + eth_put_buffer(txdone); + } + } + } + + hsz = 0; + bsz = sizeof(data); + r = snp->Receive(snp, &hsz, &bsz, data, NULL, NULL, NULL); + if (r != EFI_SUCCESS) { + return; + } + +#if DROP_PACKETS + rxc++; + if ((random() % DROP_PACKETS) == 0) { + printf("rx drop %d\n", rxc); + return; + } +#endif + +#if TRACE + printf("RX %02x:%02x:%02x:%02x:%02x:%02x < %02x:%02x:%02x:%02x:%02x:%02x %02x%02x %d\n", + data[0], data[1], data[2], data[3], data[4], data[5], + data[6], data[7], data[8], data[9], data[10], data[11], + data[12], data[13], (int)(bsz - hsz)); +#endif + eth_recv(data, bsz); +} diff --git a/netifc.h b/netifc.h new file mode 100644 index 0000000..74f0b20 --- /dev/null +++ b/netifc.h @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +// setup networking +int netifc_open(void); + +// process inbound packet(s) +void netifc_poll(void); + +// return nonzero if interface exists +int netifc_active(void); + +// shut down networking +void netifc_close(void); + +// set a timer to expire after ms milliseconds +void netifc_set_timer(uint32_t ms); + +// returns true once the timer has expired +int netifc_timer_expired(void); diff --git a/shog.build b/shog.build new file mode 100644 index 0000000..367149c --- /dev/null +++ b/shog.build @@ -0,0 +1,11 @@ +#!/bin/sh +# SPDX-License-Identifier: MIT + +LDFLAGS=-T glue/x86_64/elf_efi.lds -Bsymbolic -shared -nostdlib -znocombreloc +CFLAGS="-m64 -mno-red-zone -I. -Iheaders -Iheaders/x86_64 -DGNU_EFI_USE_MS_ABI -fPIC -fshort-wchar -ffreestanding -fno-stack-protector -maccumulate-outgoing-args -Wall -Dx86_64 -Werror" + +gcc $CFLAGS bootloader.c -o bootloader.o + +ld $LDFLAGS bootloader.o glue/x86_64/relocation_func.o glue/x86_64/start_func.o -o bootloader.so -lefi -lgnuefi + +objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .reloc -S --target=efi-app-x86_64 bootloader.so bootloader.efi diff --git a/tftp/internal.h b/tftp/internal.h new file mode 100644 index 0000000..abfcefc --- /dev/null +++ b/tftp/internal.h @@ -0,0 +1,279 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#include "tftp.h" + +#define OPCODE_RRQ 1 +#define OPCODE_WRQ 2 +#define OPCODE_DATA 3 +#define OPCODE_ACK 4 +#define OPCODE_ERROR 5 +#define OPCODE_OACK 6 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct tftp_msg_t { + uint16_t opcode; + char data[0]; +} tftp_msg; + +typedef struct tftp_err_msg_t { + uint16_t opcode; + uint16_t err_code; + char msg[0]; +} tftp_err_msg; + +typedef struct tftp_data_msg_t { + uint16_t opcode; + uint16_t block; + uint8_t data[0]; +} tftp_data_msg; + +#define BLOCKSIZE_OPTION 0x01 // RFC 2348 +#define TIMEOUT_OPTION 0x02 // RFC 2349 +#define WINDOWSIZE_OPTION 0x04 // RFC 7440 + +#define DEFAULT_BLOCKSIZE 512 +#define DEFAULT_TIMEOUT 1 +#define DEFAULT_FILESIZE 0 +#define DEFAULT_WINDOWSIZE 1 +#define DEFAULT_MODE MODE_OCTET +#define DEFAULT_MAX_TIMEOUTS 5 +#define DEFAULT_USE_OPCODE_PREFIX true + +typedef struct tftp_options_t { + // A bitmask of the options that have been set + uint8_t mask; + + uint16_t block_size; + uint8_t timeout; + uint16_t window_size; +} tftp_options; + +/** + State transitions + + ***** READ FILE ***** + + client server + ~~~~~~ ~~~~~~ + NONE NONE + generate_request (rrq) + REQ_SENT + ---- RRQ -----> + handle_rrq + REQ_RECEIVED + <---- OACK ---- + handle_oack + FIRST_DATA + ++------+ +-----+ +| | | | +| V V | +| ---- ACK -----> | +| handle_ack | +| SENDING_DATA | +| <---- DATA ---- | | +| handle_data | | +| RECEIVING_DATA | | +| ... | | +| <---- DATA ---- | | +| handle_data | | +| | | | ++------+ +-----+ + + COMPLETED COMPLETED + + + ****** WRITE FILE ***** + + client server + ~~~~~~ ~~~~~~ + NONE NONE + generate_request (wrq) + REQ_SENT + ---- WRQ -----> + handle_wrq + REQ_RECEIVED + <---- OACK ---- + handle_oack + FIRST_DATA + ++------+ +-----+ +| | | | +| V V | +| ---- DATA ----> | +| handle_data | +| RECEIVING_DATA | +| <----- ACK ---- | | +| handle_ack | | +| SENDING_DATA | | +| | | | ++------+ +-----+ + + COMPLETED COMPLETED + +**/ + +typedef enum { + NONE = 0, + REQ_SENT, + REQ_RECEIVED, + FIRST_DATA, + SENDING_DATA, + RECEIVING_DATA, + ERROR, + COMPLETED, +} tftp_state; + +typedef enum { + SEND_FILE, + RECV_FILE +} tftp_file_direction; + +struct tftp_session_t { + + // For a client, the options we will use on a new connection. For a server, the options we + // will override, if possible, when we receive a write request. + tftp_options options; + + // Tracks the options we used on the last request, so we can compare them to the options + // we get back. + tftp_options client_sent_opts; + + // Maximum filename really is 505 including \0 + // max request size (512) - opcode (2) - shortest mode (4) - null (1) + char filename[512]; + tftp_mode mode; + + // General state values + tftp_file_direction direction; // Not valid when state is NONE, ERROR, or COMPLETED. + tftp_state state; + size_t offset; + uint32_t consecutive_timeouts; + uint8_t opcode_prefix; + uint64_t block_number; + uint32_t window_index; + + // Maximum number of times we will retransmit a single msg before aborting + uint16_t max_timeouts; + + // Add an 8-bit prefix to the opcode so that retransmissions differ from the + // original transmission. This fixes problems with checksums on asix 88179 USB + // adapters (they send 0 checksums when they should send 0xffff, which is a + // no-no in IPv6). This modification is not RFC-compatible. + bool use_opcode_prefix; + + // "Negotiated" values + size_t file_size; + uint16_t window_size; + uint16_t block_size; + uint8_t timeout; + + // Callbacks + tftp_file_interface file_interface; + tftp_transport_interface transport_interface; +}; + +// Generates a read or write request to send to a tftp server. |filename| is +// the name sent to the server. |datalen| is the size of the data (should be +// zero for read requests). If |block_size|, |timeout|, or |window_size| are +// set, those will be passed to the server in such a way that they cannot be +// negotiated (normal, negotiable settings can be set using +// tftp_set_options()). |outgoing| must point to a scratch buffer the library +// can use to assemble the request. |outlen| is the size of the outgoing +// scratch buffer, and will be set to the size of the request. |timeout_ms| is +// set to the next timeout value the user of the library should use when +// waiting for a response. +tftp_status tftp_generate_request(tftp_session* session, + tftp_file_direction direction, + const char* local_filename, + const char* remote_filename, + tftp_mode mode, + size_t datalen, + const uint16_t* block_size, + const uint8_t* timeout, + const uint16_t* window_size, + void* outgoing, + size_t* outlen, + uint32_t* timeout_ms); + +// Handle an incoming tftp packet. |incoming| must point to the packet of size +// |inlen|. |outgoing| must point to a scratch buffer the library can use to +// assemble the next packet to send. |outlen| is the size of the outgoing +// scratch buffer. |timeout_ms| is set to the next timeout value the user of the +// library should use when waiting for a response. |cookie| will be passed to +// the tftp callback functions. +tftp_status tftp_process_msg(tftp_session* session, + void* incoming, + size_t inlen, + void* outgoing, + size_t* outlen, + uint32_t* timeout_ms, + void* cookie); + +// Internal handlers +tftp_status tx_data(tftp_session* session, tftp_data_msg* resp, size_t* outlen, void* cookie); +tftp_status tftp_handle_rrq(tftp_session* session, + tftp_msg* rrq, + size_t rrq_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie); +tftp_status tftp_handle_wrq(tftp_session* session, + tftp_msg* wrq, + size_t wrq_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie); +tftp_status tftp_handle_data(tftp_session* session, + tftp_msg* msg, + size_t msg_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie); +tftp_status tftp_handle_ack(tftp_session* session, + tftp_msg* ack, + size_t ack_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie); +tftp_status tftp_handle_error(tftp_session* session, + tftp_err_msg* err, + size_t err_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie); +tftp_status tftp_handle_oack(tftp_session* session, + tftp_msg* oack, + size_t oack_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie); +tftp_status tftp_handle_oerror(tftp_session* session, + tftp_msg* oerr, + size_t oerr_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie); + +void print_hex(uint8_t* buf, size_t len); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/tftp/tftp.c b/tftp/tftp.c new file mode 100644 index 0000000..9c0637a --- /dev/null +++ b/tftp/tftp.c @@ -0,0 +1,1320 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#define _POSIX_C_SOURCE 200809L // for strnlen +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +// TODO: update this +// RRQ -> +// <- DATA or OACK or ERROR +// ACK(0) -> (to confirm reception of OACK) +// ERROR -> (on OACK with non requested options) +// <- DATA(1) +// ACK(1) -> + +// WRQ -> +// <- ACK or OACK or ERROR +// DATA(1) -> +// ERROR -> (on OACK with non requested options) +// <- DATA(2) +// ACK(2) -> + +// MODE +static const char* kNetascii = "NETASCII"; +static const char* kOctet = "OCTET"; +static const char* kMail = "MAIL"; +static const size_t kMaxMode = 9; // strlen(NETASCII) + 1 + +// TSIZE +// Limit transfer to less than 10GB +static const char* kTsize = "TSIZE"; +static const size_t kTsizeLen = 5; // strlen(kTsize) +static const size_t kMaxTsizeOpt = 17; // strlen(TSIZE) + 1 + strlen(1000000000) + 1 + +// BLKSIZE +// Max size is 65535 (max IP datagram) +static const char* kBlkSize = "BLKSIZE"; +static const size_t kBlkSizeLen = 7; // strlen(kBlkSize) +static const size_t kMaxBlkSizeOpt = 15; // kBlkSizeLen + strlen("!") + 1 + strlen(65535) + 1 + +// TIMEOUT +// Max is 255 (RFC 2349) +static const char* kTimeout = "TIMEOUT"; +static const size_t kTimeoutLen = 7; // strlen(kTimeout) +static const size_t kMaxTimeoutOpt = 13; // kTimeoutLen + strlen("!") + 1 + strlen(255) + 1; + +// WINDOWSIZE +// Max is 65535 (RFC 7440) +static const char* kWindowSize = "WINDOWSIZE"; +static const size_t kWindowSizeLen = 10; // strlen(kWindowSize); +static const size_t kMaxWindowSizeOpt = 18; // kWindowSizeLen + strlen("!") + 1 + strlen(65535) + 1; + +// Since RRQ and WRQ come before option negotation, they are limited to max TFTP +// blocksize of 512 (RFC 1350 and 2347). +static const size_t kMaxRequestSize = 512; + +#define TFTP_EFILIB + +#if defined(TFTP_HOSTLIB) +// Host (e.g., netcp, bootserver) +#include +#define DEBUG 0 +#elif defined(TFTP_USERLIB) +// Fuchsia (e.g., netsvc) +#define DEBUG 0 +#elif defined(TFTP_EFILIB) +// Bootloader: use judiciously, since the console can easily become overwhelmed and hang +#define DEBUG 0 +#else +#error unable to identify target environment +#endif + +#if DEBUG +# define xprintf(args...) fprintf(stderr, args) +#else +# define xprintf(args...) +#endif + +#define __ATTR_PRINTF(__fmt, __varargs) \ + __attribute__((__format__(__printf__, __fmt, __varargs))) +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + +static void append_option_name(char** body, size_t* left, const char* name) { + size_t offset = strlen(name); + memcpy(*body, name, offset); + offset++; + *body += offset; + *left -= offset; +} + +static void __ATTR_PRINTF(5, 6) append_option(char** body, size_t* left, const char* name, + bool force, const char* fmt, ...) { + char* bodyp = *body; + size_t leftp = *left; + + size_t offset = strlen(name); + memcpy(bodyp, name, offset); + if (force) { + bodyp[offset] = '!'; + offset++; + } + offset++; + bodyp += offset; + leftp -= offset; + va_list args; + va_start(args, fmt); + offset = vsnprintf(bodyp, leftp - 1, fmt, args); + va_end(args); + offset++; + bodyp += offset; + leftp -= offset; + + *body = bodyp; + *left = leftp; +} + +#define OPCODE(session, msg, value) \ + do { \ + if (session->use_opcode_prefix) { \ + (msg)->opcode = htons((value & 0xff) | ((uint16_t)session->opcode_prefix << 8)); \ + } else { \ + (msg)->opcode = htons(value); \ + } \ + } while (0) + +#define TRANSMIT_MORE 1 +#define TRANSMIT_WAIT_ON_ACK 2 + +static size_t next_option(char* buffer, size_t len, char** option, char** value) { + size_t left = len; + size_t option_len = strnlen(buffer, left); + if (option_len == len) { + return 0; + } + + *option = buffer; + xprintf("'%s' %ld\n", *option, option_len); + buffer += option_len + 1; + left -= option_len + 1; + size_t value_len = strnlen(buffer, left); + if (value_len == left) { + return 0; + } + *value = buffer; + xprintf("'%s' %ld\n", *value, value_len); + left -= value_len + 1; + return len - left; +} + +/* Build an err packet in resp_buf and set session state to ERROR + + 2 bytes 2 bytes string 1 byte + +--------------+----------+---------+------+ + | OPCODE_ERROR | ERR_CODE | ERR_MSG | 0 | + +--------------+----------+---------+------+ +*/ +static void set_error(tftp_session* session, uint16_t err_code, void* resp_buf, + size_t* resp_len, const char* err_msg) { + tftp_err_msg* resp = resp_buf; + OPCODE(session, resp, OPCODE_ERROR); + resp->err_code = htons(err_code); + size_t err_msg_len = strlen(err_msg); + size_t max_msg_sz = *resp_len - (sizeof(tftp_err_msg) + 1); + if (err_msg_len >= max_msg_sz) { + memcpy(resp->msg, err_msg, max_msg_sz); + resp->msg[max_msg_sz] = '\0'; + // *resp_len is unchanged - the whole buffer was used + } else { + strcpy(resp->msg, err_msg); + *resp_len = sizeof(tftp_err_msg) + err_msg_len + 1; + } + session->state = ERROR; +} + +tftp_status tx_data(tftp_session* session, tftp_data_msg* resp, size_t* outlen, void* cookie) { + session->offset = (session->block_number + session->window_index) * session->block_size; + *outlen = 0; + if (session->offset <= session->file_size) { + session->window_index++; + OPCODE(session, resp, OPCODE_DATA); + resp->block = htons(session->block_number + session->window_index); + size_t len = MIN(session->file_size - session->offset, session->block_size); + xprintf(" -> Copying block #%" PRIu64 " (size:%zu/%d) from %zu/%zu [%d/%d]\n", + session->block_number + session->window_index, len, session->block_size, + session->offset, session->file_size, session->window_index, session->window_size); + void* buf = resp->data; + size_t len_remaining = len; + size_t off = session->offset; + while (len_remaining > 0) { + // TODO(tkilbourn): assert that these function pointers are set + size_t rr = len_remaining; + tftp_status s = session->file_interface.read(buf, &rr, off, cookie); + if (s < 0) { + xprintf("Err reading: %d\n", s); + return s; + } + buf += rr; + off += rr; + len_remaining -= rr; + } + *outlen = sizeof(*resp) + len; + + if (session->window_index < session->window_size) { + xprintf(" -> TRANSMIT_MORE(%d < %d)\n", session->window_index, session->window_size); + } else { + xprintf(" -> TRANSMIT_WAIT_ON_ACK(%d >= %d)\n", session->window_index, + session->window_size); + } + } else { + xprintf(" -> TRANSMIT_WAIT_ON_ACK(completed)\n"); + } + return TFTP_NO_ERROR; +} + +size_t tftp_sizeof_session(void) { + return sizeof(tftp_session); +} + +int tftp_init(tftp_session** session, void* buffer, size_t size) { + if (buffer == NULL) { + return TFTP_ERR_INVALID_ARGS; + } + if (size < sizeof(tftp_session)) { + return TFTP_ERR_BUFFER_TOO_SMALL; + } + *session = buffer; + tftp_session* s = *session; + memset(s, 0, sizeof(tftp_session)); + + // Sensible defaults for non-negotiated values + s->file_size = DEFAULT_FILESIZE; + s->mode = DEFAULT_MODE; + s->max_timeouts = DEFAULT_MAX_TIMEOUTS; + s->use_opcode_prefix = DEFAULT_USE_OPCODE_PREFIX; + + return TFTP_NO_ERROR; +} + +tftp_status tftp_session_set_file_interface(tftp_session* session, + tftp_file_interface* callbacks) { + if (session == NULL) { + return TFTP_ERR_INVALID_ARGS; + } + + session->file_interface = *callbacks; + return TFTP_NO_ERROR; +} + +tftp_status tftp_session_set_transport_interface(tftp_session* session, + tftp_transport_interface* callbacks) { + if (session == NULL) { + return TFTP_ERR_INVALID_ARGS; + } + session->transport_interface = *callbacks; + return TFTP_NO_ERROR; +} + +bool tftp_session_has_pending(tftp_session* session) { + return session->direction == SEND_FILE && + session->window_index > 0 && + session->window_index < session->window_size && + ((session->block_number + session->window_index) * session->block_size) <= + session->file_size; +} + +tftp_status tftp_set_options(tftp_session* session, const uint16_t* block_size, + const uint8_t* timeout, const uint16_t* window_size) { + session->options.mask = 0; + if (block_size) { + session->options.block_size = *block_size; + session->options.mask |= BLOCKSIZE_OPTION; + } + if (timeout) { + session->options.timeout = *timeout; + session->options.mask |= TIMEOUT_OPTION; + } + if (window_size) { + session->options.window_size = *window_size; + session->options.mask |= WINDOWSIZE_OPTION; + } + return TFTP_NO_ERROR; +} + +tftp_status tftp_generate_request(tftp_session* session, + tftp_file_direction direction, + const char* local_filename, + const char* remote_filename, + tftp_mode mode, + size_t datalen, + const uint16_t* block_size, + const uint8_t* timeout, + const uint16_t* window_size, + void* outgoing, + size_t* outlen, + uint32_t* timeout_ms) { + if (*outlen < 2) { + xprintf("outlen too short: %zd\n", *outlen); + return TFTP_ERR_BUFFER_TOO_SMALL; + } + + // The actual options are not set until we get a confirmation OACK message. Until then, + // we have to assume the TFTP defaults. + session->block_size = DEFAULT_BLOCKSIZE; + session->timeout = DEFAULT_TIMEOUT; + session->window_size = DEFAULT_WINDOWSIZE; + + tftp_msg* ack = outgoing; + OPCODE(session, ack, (direction == SEND_FILE) ? OPCODE_WRQ : OPCODE_RRQ); + char* body = ack->data; + memset(body, 0, *outlen - sizeof(*ack)); + size_t left = *outlen - sizeof(*ack); + size_t remote_filename_len = strlen(remote_filename); + if (remote_filename_len + 1 > left - kMaxMode) { + xprintf("filename too long %zd > %zd\n", remote_filename_len, left - kMaxMode); + return TFTP_ERR_INVALID_ARGS; + } + memcpy(body, remote_filename, remote_filename_len); + body += remote_filename_len + 1; + left -= remote_filename_len + 1; + strncpy(session->filename, local_filename, sizeof(session->filename) - 1); + session->filename[sizeof(session->filename) - 1] = '\0'; + switch (mode) { + case MODE_NETASCII: + append_option_name(&body, &left, kNetascii); + break; + case MODE_OCTET: + append_option_name(&body, &left, kOctet); + break; + case MODE_MAIL: + append_option_name(&body, &left, kMail); + break; + default: + return TFTP_ERR_INVALID_ARGS; + } + session->mode = mode; + + if (left < kMaxTsizeOpt) { + return TFTP_ERR_BUFFER_TOO_SMALL; + } + append_option(&body, &left, kTsize, false, "%zu", datalen); + session->file_size = datalen; + tftp_options* sent_opts = &session->client_sent_opts; + sent_opts->mask = 0; + + if (block_size || session->options.mask & BLOCKSIZE_OPTION) { + if (left < kMaxBlkSizeOpt) { + return TFTP_ERR_BUFFER_TOO_SMALL; + } + bool force_value; + if (block_size) { + force_value = true; + sent_opts->block_size = *block_size; + } else { + force_value = false; + sent_opts->block_size = session->options.block_size; + } + append_option(&body, &left, kBlkSize, force_value, "%"PRIu16, sent_opts->block_size); + sent_opts->mask |= BLOCKSIZE_OPTION; + } + + if (timeout || session->options.mask & TIMEOUT_OPTION) { + if (left < kMaxTimeoutOpt) { + return TFTP_ERR_BUFFER_TOO_SMALL; + } + bool force_value; + if (timeout) { + force_value = true; + sent_opts->timeout = *timeout; + } else { + force_value = false; + sent_opts->timeout = session->options.timeout; + } + append_option(&body, &left, kTimeout, force_value, "%"PRIu8, sent_opts->timeout); + sent_opts->mask |= TIMEOUT_OPTION; + } + + if (window_size || session->options.mask & WINDOWSIZE_OPTION) { + if (left < kMaxWindowSizeOpt) { + return TFTP_ERR_BUFFER_TOO_SMALL; + } + bool force_value; + if (window_size) { + force_value = true; + sent_opts->window_size = *window_size; + } else { + force_value = false; + sent_opts->window_size = session->options.window_size; + } + append_option(&body, &left, kWindowSize, force_value, "%"PRIu16, sent_opts->window_size); + sent_opts->mask |= WINDOWSIZE_OPTION; + } + + *outlen = *outlen - left; + // Nothing has been negotiated yet so use default + *timeout_ms = 1000 * session->timeout; + + session->direction = direction; + session->state = REQ_SENT; + xprintf("Generated %s request, len=%zu\n", + (direction == SEND_FILE) ? "write" : "read", *outlen); + return TFTP_NO_ERROR; +} + +tftp_status tftp_handle_request(tftp_session* session, + tftp_file_direction direction, + tftp_msg* req, + size_t req_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie) { + // We could be in REQ_RECEIVED if our OACK was dropped. + if (session->state != NONE && session->state != REQ_RECEIVED) { + xprintf("Invalid state transition %d -> %d\n", session->state, REQ_RECEIVED); + set_error(session, TFTP_ERR_CODE_UNDEF, resp, resp_len, "invalid state transition"); + return TFTP_ERR_BAD_STATE; + } + // opcode, filename, 0, mode, 0, opt1, 0, value1 ... optN, 0, valueN, 0 + // Max length is 512 no matter + if (req_len > kMaxRequestSize) { + xprintf("Write request is too large\n"); + set_error(session, TFTP_ERR_CODE_UNDEF, resp, resp_len, "write request is too large"); + return TFTP_ERR_INTERNAL; + } + // Skip opcode + size_t left = req_len - sizeof(*resp); + char* cur = req->data; + char *option, *value; + // filename, 0, mode, 0 can be interpreted like option, 0, value, 0 + size_t offset = next_option(cur, left, &option, &value); + if (!offset) { + xprintf("No options\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "no options"); + return TFTP_ERR_INTERNAL; + } + left -= offset; + + xprintf("filename = '%s', mode = '%s'\n", option, value); + + strncpy(session->filename, option, sizeof(session->filename) - 1); + session->filename[sizeof(session->filename) - 1] = '\0'; + char* mode = value; + if (!strncasecmp(mode, kNetascii, strlen(kNetascii))) { + session->mode = MODE_NETASCII; + } else if (!strncasecmp(mode, kOctet, strlen(kOctet))) { + session->mode = MODE_OCTET; + } else if (!strncasecmp(mode, kMail, strlen(kMail))) { + session->mode = MODE_MAIL; + } else { + xprintf("Unknown write request mode\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "unknown write request mode"); + return TFTP_ERR_INTERNAL; + } + + // Initialize the values to TFTP defaults + session->block_size = DEFAULT_BLOCKSIZE; + session->timeout = DEFAULT_TIMEOUT; + session->window_size = DEFAULT_WINDOWSIZE; + + // TODO(tkilbourn): refactor option handling code to share with + // tftp_handle_oack + cur += offset; + bool file_size_seen = false; + tftp_options requested_options = {.mask = 0}; + tftp_options* override_opts = &session->options; + while (offset > 0 && left > 0) { + offset = next_option(cur, left, &option, &value); + if (!offset) { + xprintf("No more options\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "no more options"); + return TFTP_ERR_INTERNAL; + } + + if (!strncasecmp(option, kTsize, kTsizeLen)) { // RFC 2349 + if (direction == RECV_FILE) { + long val = atol(value); + if (val < 0) { + xprintf("invalid file size\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, + "invalid file size"); + return TFTP_ERR_INTERNAL; + } + session->file_size = val; + } + file_size_seen = true; + } else if (!strncasecmp(option, kBlkSize, kBlkSizeLen)) { // RFC 2348 + bool force_block_size = (option[kBlkSizeLen] == '!'); + // Valid values range between "8" and "65464" octets, inclusive + long val = atol(value); + // TODO(tkilbourn): with an MTU of 1500, shouldn't be more than 1428 + if (val < 8 || val > 65464) { + xprintf("invalid block size\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "invalid block size"); + return TFTP_ERR_INTERNAL; + } + requested_options.block_size = val; + requested_options.mask |= BLOCKSIZE_OPTION; + if (force_block_size || !(override_opts->mask & BLOCKSIZE_OPTION)) { + session->block_size = val; + } else { + session->block_size = override_opts->block_size; + } + } else if (!strncasecmp(option, kTimeout, kTimeoutLen)) { // RFC 2349 + bool force_timeout_val = (option[kTimeoutLen] == '!'); + // Valid values range between "1" and "255" seconds inclusive. + long val = atol(value); + if (val < 1 || val > 255) { + xprintf("invalid timeout\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "invalid timeout"); + return TFTP_ERR_INTERNAL; + } + requested_options.timeout = val; + requested_options.mask |= TIMEOUT_OPTION; + if (force_timeout_val || !(override_opts->mask & TIMEOUT_OPTION)) { + session->timeout = val; + } else { + session->timeout = override_opts->timeout; + } + } else if (!strncasecmp(option, kWindowSize, kWindowSizeLen)) { // RFC 7440 + bool force_window_size = (option[kWindowSizeLen] == '!'); + // The valid values range MUST be between 1 and 65535 blocks, inclusive. + long val = atol(value); + if (val < 1 || val > 65535) { + xprintf("invalid window size\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, + "invalid window size"); + return TFTP_ERR_INTERNAL; + } + requested_options.window_size = val; + requested_options.mask |= WINDOWSIZE_OPTION; + if (force_window_size || !(override_opts->mask & WINDOWSIZE_OPTION)) { + session->window_size = val; + } else { + session->window_size = override_opts->window_size; + } + } else { + // Options which the server does not support should be omitted from the + // OACK; they should not cause an ERROR packet to be generated. + } + + cur += offset; + left -= offset; + } + + char* body = resp->data; + memset(body, 0, *resp_len - sizeof(*resp)); + left = *resp_len - sizeof(*resp); + + OPCODE(session, resp, OPCODE_OACK); + + // Open file, if we haven't already + if (session->state == NONE) { + if (direction == RECV_FILE) { + if (!session->file_interface.open_write) { + xprintf("Unable to service write request: no open_write implementation\n"); + set_error(session, TFTP_ERR_CODE_UNDEF, resp, resp_len, "internal error"); + return TFTP_ERR_BAD_STATE; + } + switch(session->file_interface.open_write(session->filename, session->file_size, + cookie)) { + case TFTP_ERR_SHOULD_WAIT: + // The open_write() callback can return an ERR_SHOULD_WAIT response if it isn't + // prepared to service another request at the moment and the client should retry + // later. + xprintf("Denying write request received when not ready\n"); + set_error(session, TFTP_ERR_CODE_BUSY, resp, resp_len, "not ready to receive"); + session->state = NONE; + return TFTP_ERR_SHOULD_WAIT; + case TFTP_NO_ERROR: + break; + default: + xprintf("Could not open file on write request\n"); + set_error(session, TFTP_ERR_CODE_ACCESS_VIOLATION, resp, resp_len, + "could not open file for writing"); + return TFTP_ERR_BAD_STATE; + } + } else { + ssize_t file_size; + if (!session->file_interface.open_read) { + xprintf("Unable to service read request: no open_read implementation\n"); + set_error(session, TFTP_ERR_CODE_UNDEF, resp, resp_len, "internal error"); + return TFTP_ERR_BAD_STATE; + } + + file_size = session->file_interface.open_read(session->filename, cookie); + if (file_size == TFTP_ERR_SHOULD_WAIT) { + // The open_read() callback can return an ERR_SHOULD_WAIT response if it isn't + // prepared to service another request at the moment and the client should retry + // later. + xprintf("Denying read request received when not ready\n"); + set_error(session, TFTP_ERR_CODE_BUSY, resp, resp_len, "not ready to send"); + session->state = NONE; + return TFTP_ERR_SHOULD_WAIT; + } + if (file_size < 0) { + xprintf("Unable to open file %s for reading\n", session->filename); + set_error(session, TFTP_ERR_CODE_FILE_NOT_FOUND, resp, resp_len, + "could not open file for reading"); + return TFTP_ERR_BAD_STATE; + } + session->file_size = file_size; + } + } + + if (file_size_seen) { + append_option(&body, &left, kTsize, false, "%zu", session->file_size); + } else { + xprintf("No TSIZE option specified\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "no TSIZE option"); + if (session->file_interface.close) { + session->file_interface.close(cookie); + } + return TFTP_ERR_BAD_STATE; + } + if (requested_options.mask & BLOCKSIZE_OPTION) { + // TODO(jpoichet) Make sure this block size is possible. Need API upwards to + // request allocation of block size * window size memory + append_option(&body, &left, kBlkSize, false, "%d", session->block_size); + } + if (requested_options.mask & TIMEOUT_OPTION) { + // TODO(jpoichet) Make sure this timeout is possible. Need API upwards to + // request allocation of block size * window size memory + append_option(&body, &left, kTimeout, false, "%d", session->timeout); + *timeout_ms = 1000 * session->timeout; + } + if (requested_options.mask & WINDOWSIZE_OPTION) { + append_option(&body, &left, kWindowSize, false, "%d", session->window_size); + } + *resp_len = *resp_len - left; + session->state = REQ_RECEIVED; + session->direction = direction; + + xprintf("%s Request Parsed\n", (direction == SEND_FILE) ? "Read" : "Write"); + xprintf(" Mode : %s\n", session->mode == MODE_NETASCII ? "netascii" : + session->mode == MODE_OCTET ? "octet" : + session->mode == MODE_MAIL ? "mail" : + "unrecognized"); + xprintf(" File Size : %zu\n", session->file_size); + xprintf("Options requested: %08x\n", requested_options.mask); + xprintf(" Block Size : %d\n", requested_options.block_size); + xprintf(" Timeout : %d\n", requested_options.timeout); + xprintf(" Window Size: %d\n", requested_options.window_size); + xprintf("Using options\n"); + xprintf(" Block Size : %d\n", session->block_size); + xprintf(" Timeout : %d\n", session->timeout); + xprintf(" Window Size: %d\n", session->window_size); + + return TFTP_NO_ERROR; +} + +tftp_status tftp_handle_wrq(tftp_session* session, + tftp_msg* wrq, + size_t wrq_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie) { + return tftp_handle_request(session, RECV_FILE, wrq, wrq_len, resp, resp_len, timeout_ms, + cookie); +} + +tftp_status tftp_handle_rrq(tftp_session* session, + tftp_msg* rrq, + size_t rrq_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie) { + return tftp_handle_request(session, SEND_FILE, rrq, rrq_len, resp, resp_len, timeout_ms, + cookie); +} + +static void tftp_prepare_ack(tftp_session* session, + tftp_msg* msg, + size_t* msg_len) { + tftp_data_msg* ack_data = (tftp_data_msg*)msg; + xprintf(" -> Ack %" PRIu64 "\n", session->block_number); + session->window_index = 0; + OPCODE(session, ack_data, OPCODE_ACK); + ack_data->block = htons(session->block_number & 0xffff); + *msg_len = sizeof(*ack_data); +} + +tftp_status tftp_handle_data(tftp_session* session, + tftp_msg* msg, + size_t msg_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie) { + if ((session->direction == RECV_FILE) && + ((session->state == REQ_RECEIVED) || + (session->state == FIRST_DATA) || + (session->state == RECEIVING_DATA))) { + session->state = RECEIVING_DATA; + } else { + set_error(session, TFTP_ERR_CODE_UNDEF, resp, resp_len, "internal error: bad state"); + return TFTP_ERR_INTERNAL; + } + + tftp_data_msg* data = (tftp_data_msg*)msg; + + uint16_t block_num = ntohs(data->block); + + // The block field of the message is only 16 bits wide. To support large files + // (> 65535 * blocksize bytes), we allow the block number to wrap. We use signed modulo + // math to determine the relative location of the block to our current position. + int16_t block_delta = block_num - (uint16_t)session->block_number; + xprintf(" <- Block %" PRIu64 " (Last = %" PRIu64 ", Offset = %" PRIu64 + ", Size = %zd, Left = %" PRIu64 ")\n", + session->block_number + block_delta, session->block_number, + session->block_number * session->block_size, session->file_size, + session->file_size - session->block_number * session->block_size); + if (block_delta == 1) { + xprintf("Advancing normally + 1\n"); + void* buf = data->data; + size_t len = msg_len - sizeof(tftp_data_msg); + size_t off = session->block_number * session->block_size; + while (len > 0) { + tftp_status ret; + // TODO(tkilbourn): assert that these function pointers are set + size_t wr = len; + ret = session->file_interface.write(buf, &wr, off, cookie); + if (ret < 0) { + xprintf("Error writing: %d\n", ret); + return ret; + } + buf += wr; + off += wr; + len -= wr; + } + session->block_number++; + session->window_index++; + } else if (block_delta > 1) { + // Force sending a ACK with the last block_number we received + xprintf("Skipped: got %" PRIu64 ", expected %" PRIu64 "\n", + session->block_number + block_delta, session->block_number + 1); + session->window_index = session->window_size; + // It's possible that a previous ACK wasn't received, increment the prefix + if (session->use_opcode_prefix) { + session->opcode_prefix++; + } + } + + if (session->window_index == session->window_size || + session->block_number * session->block_size > session->file_size) { + tftp_prepare_ack(session, resp, resp_len); + if (session->block_number * session->block_size > session->file_size) { + return TFTP_TRANSFER_COMPLETED; + } + } else { + // Nothing to send + *resp_len = 0; + } + return TFTP_NO_ERROR; +} + +tftp_status tftp_handle_ack(tftp_session* session, + tftp_msg* ack, + size_t ack_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie) { + if ((session->direction != SEND_FILE) || + ((session->state != FIRST_DATA) && + (session->state != REQ_RECEIVED) && + (session->state != SENDING_DATA))) { + set_error(session, TFTP_ERR_CODE_UNDEF, resp, resp_len, "internal error: bad state"); + return TFTP_ERR_INTERNAL; + } + // Need to move forward in data and send it + tftp_data_msg* ack_data = (void*)ack; + tftp_data_msg* resp_data = (void*)resp; + + uint16_t ack_block = ntohs(ack_data->block); + xprintf(" <- Ack %d\n", ack_block); + + // Since we track blocks in 32 bits, but the packets only support 16 bits, calculate the + // signed 16 bit offset to determine the adjustment to the current position. + int16_t block_offset = ack_block - (uint16_t)session->block_number; + + if (session->state != FIRST_DATA && session->state != REQ_RECEIVED && block_offset == 0) { + // Don't acknowledge duplicate ACKs, avoiding the "Sorcerer's Apprentice Syndrome" + *resp_len = 0; + return TFTP_NO_ERROR; + } + + if (block_offset < session->window_size) { + // If it looks like some of our data might have been dropped, modify the prefix + // before resending. + if (session->use_opcode_prefix) { + session->opcode_prefix++; + } + } + session->state = SENDING_DATA; + session->block_number += block_offset; + session->window_index = 0; + + if (session->block_number * session->block_size > session->file_size) { + *resp_len = 0; + return TFTP_TRANSFER_COMPLETED; + } + + tftp_status ret = tx_data(session, resp_data, resp_len, cookie); + if (ret < 0) { + set_error(session, TFTP_ERR_CODE_UNDEF, resp, resp_len, "could not transmit data"); + } + return ret; +} + +tftp_status tftp_handle_error(tftp_session* session, + tftp_err_msg* err, + size_t err_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie) { + if (err_len < sizeof(tftp_err_msg)) { + return TFTP_ERR_BUFFER_TOO_SMALL; + } + uint16_t err_code = ntohs(err->err_code); + + // There's no need to respond to an error + *resp_len = 0; + + if (err_code == TFTP_ERR_CODE_BUSY) { + xprintf("Target busy\n"); + session->state = NONE; + return TFTP_ERR_SHOULD_WAIT; + } + xprintf("Target sent error %d\n", err_code); + session->state = ERROR; + return TFTP_ERR_INTERNAL; +} + +tftp_status tftp_handle_oack(tftp_session* session, + tftp_msg* oack, + size_t oack_len, + tftp_msg* resp, + size_t* resp_len, + uint32_t* timeout_ms, + void* cookie) { + xprintf("Option Ack\n"); + if (session->state == REQ_SENT || session->state == FIRST_DATA) { + session->state = FIRST_DATA; + } + + size_t left = oack_len - sizeof(*oack); + char* cur = oack->data; + size_t offset; + char *option, *value; + + while (left > 0) { + offset = next_option(cur, left, &option, &value); + if (!offset) { + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "invalid option format"); + return TFTP_ERR_INTERNAL; + } + + if (!strncasecmp(option, kTsize, kTsizeLen)) { // RFC 2349 + if (session->direction == RECV_FILE) { + session->file_size = atol(value); + } + // If we are sending the file, we don't care what value the server wrote in here + } else if (!strncasecmp(option, kBlkSize, kBlkSizeLen)) { // RFC 2348 + if (!(session->client_sent_opts.mask & BLOCKSIZE_OPTION)) { + xprintf("block size not requested\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "no block size"); + return TFTP_ERR_INTERNAL; + } + // Valid values range between "8" and "65464" octets, inclusive + long val = atol(value); + if (val < 8 || val > 65464) { + xprintf("invalid block size\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "invalid block size"); + return TFTP_ERR_INTERNAL; + } + // TODO(tkilbourn): with an MTU of 1500, shouldn't be more than 1428 + session->block_size = val; + } else if (!strncasecmp(option, kTimeout, kTimeoutLen)) { // RFC 2349 + if (!(session->client_sent_opts.mask & TIMEOUT_OPTION)) { + xprintf("timeout not requested\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "no timeout"); + return TFTP_ERR_INTERNAL; + } + // Valid values range between "1" and "255" seconds inclusive. + long val = atol(value); + if (val < 1 || val > 255) { + xprintf("invalid timeout\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "invalid timeout"); + return TFTP_ERR_INTERNAL; + } + session->timeout = val; + } else if (!strncasecmp(option, kWindowSize, kWindowSizeLen)) { // RFC 7440 + if (!(session->client_sent_opts.mask & WINDOWSIZE_OPTION)) { + xprintf("window size not requested\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, "no window size"); + return TFTP_ERR_INTERNAL; + } + // The valid values range MUST be between 1 and 65535 blocks, inclusive. + long val = atol(value); + if (val < 1 || val > 65535) { + xprintf("invalid window size\n"); + set_error(session, TFTP_ERR_CODE_BAD_OPTIONS, resp, resp_len, + "invalid window size"); + return TFTP_ERR_INTERNAL; + } + session->window_size = val; + } else { + // Options which the server does not support should be omitted from the + // OACK; they should not cause an ERROR packet to be generated. + } + + cur += offset; + left -= offset; + } + *timeout_ms = 1000 * session->timeout; + + xprintf("Options negotiated\n"); + xprintf(" File Size : %zu\n", session->file_size); + xprintf(" Block Size : %d\n", session->block_size); + xprintf(" Timeout : %d\n", session->timeout); + xprintf(" Window Size: %d\n", session->window_size); + + session->offset = 0; + session->block_number = 0; + session->window_index = 0; + + if (session->direction == SEND_FILE) { + tftp_data_msg* resp_data = (void*)resp; + tftp_status ret = tx_data(session, resp_data, resp_len, cookie); + if (ret < 0) { + set_error(session, TFTP_ERR_CODE_UNDEF, resp, resp_len, "failure to transmit data"); + } + return ret; + } else { + if (!session->file_interface.open_write || + session->file_interface.open_write(session->filename, session->file_size, + cookie)) { + xprintf("Could not open file on write request\n"); + set_error(session, TFTP_ERR_CODE_UNDEF, resp, resp_len, "could not open file for writing"); + return TFTP_ERR_BAD_STATE; + } + tftp_prepare_ack(session, resp, resp_len); + return TFTP_NO_ERROR; + } +} + +tftp_status tftp_process_msg(tftp_session* session, + void* incoming, + size_t inlen, + void* outgoing, + size_t* outlen, + uint32_t* timeout_ms, + void* cookie) { + if (inlen < sizeof(tftp_msg)) { + return TFTP_ERR_BUFFER_TOO_SMALL; + } + + tftp_msg* msg = incoming; + tftp_msg* resp = outgoing; + + // Decode opcode + uint16_t opcode = ntohs(msg->opcode) & 0xff; + xprintf("handle_msg opcode=%u length=%d\n", opcode, (int)inlen); + + // Set default timeout + *timeout_ms = 1000 * session->timeout; + + // Reset timeout count + session->consecutive_timeouts = 0; + + switch (opcode) { + case OPCODE_RRQ: + return tftp_handle_rrq(session, incoming, inlen, resp, outlen, timeout_ms, cookie); + case OPCODE_WRQ: + return tftp_handle_wrq(session, incoming, inlen, resp, outlen, timeout_ms, cookie); + case OPCODE_DATA: + return tftp_handle_data(session, incoming, inlen, resp, outlen, timeout_ms, cookie); + case OPCODE_ACK: + return tftp_handle_ack(session, incoming, inlen, resp, outlen, timeout_ms, cookie); + case OPCODE_ERROR: + return tftp_handle_error(session, incoming, inlen, resp, outlen, timeout_ms, cookie); + case OPCODE_OACK: + return tftp_handle_oack(session, incoming, inlen, resp, outlen, timeout_ms, cookie); + default: + xprintf("Unknown opcode\n"); + session->state = ERROR; + return TFTP_ERR_INTERNAL; + } +} + +tftp_status tftp_prepare_data(tftp_session* session, + void* outgoing, + size_t* outlen, + uint32_t* timeout_ms, + void* cookie) { + tftp_data_msg* resp_data = outgoing; + + if ((session->block_number + session->window_index) * session->block_size > session->file_size) { + *outlen = 0; + return TFTP_TRANSFER_COMPLETED; + } + + tftp_status ret = tx_data(session, resp_data, outlen, cookie); + if (ret < 0) { + set_error(session, TFTP_ERR_CODE_UNDEF, outgoing, outlen, "failure to transmit data"); + } + return ret; +} + +void tftp_session_set_max_timeouts(tftp_session* session, + uint16_t max_timeouts) { + session->max_timeouts = max_timeouts; +} + +void tftp_session_set_opcode_prefix_use(tftp_session* session, + bool enable) { + session->use_opcode_prefix = enable; +} + +tftp_status tftp_timeout(tftp_session* session, + void* msg_buf, + size_t* msg_len, + size_t buf_sz, + uint32_t* timeout_ms, + void* file_cookie) { + xprintf("Timeout\n"); + if (++session->consecutive_timeouts > session->max_timeouts) { + return TFTP_ERR_TIMED_OUT; + } + // It's possible our previous transmission was dropped because of checksum errors. + // Use a different opcode prefix when we resend. + if (session->use_opcode_prefix) { + session->opcode_prefix++; + } + if (session->state == REQ_SENT || session->state == REQ_RECEIVED) { + // Resend previous message + return TFTP_NO_ERROR; + } + *msg_len = buf_sz; + if (session->direction == SEND_FILE) { + // Reset back to the last-acknowledged block + session->window_index = 0; + return tftp_prepare_data(session, msg_buf, msg_len, timeout_ms, file_cookie); + } else { + // ACK up to the last block read + tftp_prepare_ack(session, msg_buf, msg_len); + return TFTP_NO_ERROR; + } +} + +#define REPORT_ERR(opts,...) \ + if (opts->err_msg) { \ + snprintf(opts->err_msg, opts->err_msg_sz, __VA_ARGS__); \ + } + +typedef struct { + void* incoming; + size_t in_buf_sz; + void* outgoing; + size_t out_buf_sz; + char* err_msg; + size_t err_msg_sz; +} tftp_msg_loop_opts; + +static tftp_status tftp_msg_loop(tftp_session* session, + void* transport_cookie, + void* file_cookie, + tftp_msg_loop_opts* opts, + uint32_t timeout_ms) { + tftp_status ret; + size_t out_sz = 0; + + do { + tftp_status send_status; + int result = session->transport_interface.timeout_set(timeout_ms, transport_cookie); + if (result < 0) { + REPORT_ERR(opts, "failed during transport timeout set callback"); + return TFTP_ERR_INTERNAL; + } + + bool pending = tftp_session_has_pending(session); + int n = session->transport_interface.recv(opts->incoming, opts->in_buf_sz, !pending, + transport_cookie); + if (n == TFTP_ERR_TIMED_OUT) { + if (pending) { + out_sz = opts->out_buf_sz; + ret = tftp_prepare_data(session, + opts->outgoing, + &out_sz, + &timeout_ms, + file_cookie); + if (out_sz) { + send_status = session->transport_interface.send(opts->outgoing, out_sz, + transport_cookie); + if (send_status != TFTP_NO_ERROR) { + REPORT_ERR(opts, "failed during transport send callback"); + return send_status; + } + } + if (ret < 0) { + REPORT_ERR(opts, "failed to prepare data to send"); + return ret; + } + } else if (session->state != NONE) { + ret = tftp_timeout(session, + opts->outgoing, + &out_sz, + opts->out_buf_sz, + &timeout_ms, + file_cookie); + if (ret == TFTP_ERR_TIMED_OUT) { + REPORT_ERR(opts, "too many consecutive timeouts, aborting"); + return ret; + } + if (ret < 0) { + REPORT_ERR(opts, "failed during timeout processing"); + return ret; + } + if (out_sz) { + send_status = session->transport_interface.send(opts->outgoing, out_sz, + transport_cookie); + if (send_status != TFTP_NO_ERROR) { + REPORT_ERR(opts, "failed during transport send callback"); + return n; + } + } + } + continue; + } else if (n < 0) { + REPORT_ERR(opts, "failed during transport recv callback"); + return n; + } + + out_sz = opts->out_buf_sz; + ret = tftp_process_msg(session, + opts->incoming, + n, + opts->outgoing, + &out_sz, + &timeout_ms, + file_cookie); + if (out_sz) { + send_status = session->transport_interface.send(opts->outgoing, out_sz, + transport_cookie); + if (send_status != TFTP_NO_ERROR) { + REPORT_ERR(opts, "failed during transport send callback"); + return send_status; + } + } + if (ret < 0) { + REPORT_ERR(opts, "failed to handle message"); + return ret; + } else if (ret == TFTP_TRANSFER_COMPLETED) { + return ret; + } + } while (1); +} + +static tftp_status transfer_file(tftp_session* session, + void* transport_cookie, + void* file_cookie, + tftp_file_direction xfer_direction, + const char* local_filename, + const char* remote_filename, + tftp_request_opts* opts) { + if (!opts || !opts->inbuf || !opts->inbuf_sz || !opts->outbuf || !opts->outbuf_sz) { + return TFTP_ERR_INVALID_ARGS; + } + + tftp_status status; + + ssize_t file_size = 0; + if (xfer_direction == SEND_FILE) { + file_size = session->file_interface.open_read(local_filename, file_cookie); + if (file_size < 0) { + REPORT_ERR(opts, "failed during file open callback"); + return file_size; + } + } + + tftp_mode mode = opts->mode ? *opts->mode : TFTP_DEFAULT_CLIENT_MODE; + + size_t out_sz = opts->outbuf_sz; + uint32_t timeout_ms; + status = tftp_generate_request(session, + xfer_direction, + local_filename, + remote_filename, + mode, + file_size, + opts->block_size, + opts->timeout, + opts->window_size, + opts->outbuf, + &out_sz, + &timeout_ms); + + const char* xfer_direction_str = (xfer_direction == SEND_FILE) ? "write" : "read"; + if (status < 0) { + REPORT_ERR(opts, "failed to generate %s request", xfer_direction_str); + goto done; + } + if (!out_sz) { + REPORT_ERR(opts, "no %s request generated", xfer_direction_str); + status = TFTP_ERR_INTERNAL; + goto done; + } + + status = session->transport_interface.send(opts->outbuf, out_sz, transport_cookie); + if (status != TFTP_NO_ERROR) { + REPORT_ERR(opts, "failed during transport send callback"); + goto done; + } + + tftp_msg_loop_opts msg_loop_opts = {.incoming = opts->inbuf, + .in_buf_sz = opts->inbuf_sz, + .outgoing = opts->outbuf, + .out_buf_sz = opts->outbuf_sz, + .err_msg = opts->err_msg, + .err_msg_sz = opts->err_msg_sz}; + status = tftp_msg_loop(session, transport_cookie, file_cookie, &msg_loop_opts, timeout_ms); + +done: + if ((xfer_direction == SEND_FILE) || (session->state != NONE)) { + if (session->file_interface.close) { + session->file_interface.close(file_cookie); + } + } + return status; +} + +tftp_status tftp_push_file(tftp_session* session, + void* transport_cookie, + void* file_cookie, + const char* local_filename, + const char* remote_filename, + tftp_request_opts* opts) { + return transfer_file(session, transport_cookie, file_cookie, SEND_FILE, + local_filename, remote_filename, opts); +} + +tftp_status tftp_pull_file(tftp_session* session, + void* transport_cookie, + void* file_cookie, + const char* local_filename, + const char* remote_filename, + tftp_request_opts* opts) { + return transfer_file(session, transport_cookie, file_cookie, RECV_FILE, + local_filename, remote_filename, opts); +} + +tftp_status tftp_service_request(tftp_session* session, + void* transport_cookie, + void* file_cookie, + tftp_handler_opts* opts) { + if (!opts || !opts->inbuf || !opts->outbuf || !opts->outbuf_sz) { + return TFTP_ERR_INVALID_ARGS; + } + tftp_msg_loop_opts msg_loop_opts = {.incoming = opts->inbuf, + .in_buf_sz = opts->inbuf_sz, + .outgoing = opts->outbuf, + .out_buf_sz = *opts->outbuf_sz, + .err_msg = opts->err_msg, + .err_msg_sz = opts->err_msg_sz}; + uint32_t timeout_ms = session->timeout * 1000; + tftp_status status = tftp_msg_loop(session, transport_cookie, file_cookie, &msg_loop_opts, + timeout_ms); + if ((session->state != NONE) && session->file_interface.close) { + session->file_interface.close(file_cookie); + } + return status; +} + +tftp_status tftp_handle_msg(tftp_session* session, + void* transport_cookie, + void* file_cookie, + tftp_handler_opts* opts) { + if (!opts || !opts->inbuf || !opts->outbuf || !opts->outbuf_sz) { + return TFTP_ERR_INVALID_ARGS; + } + uint32_t timeout_ms; + tftp_status ret; + ret = tftp_process_msg(session, opts->inbuf, opts->inbuf_sz, + opts->outbuf, opts->outbuf_sz, &timeout_ms, file_cookie); + if (*opts->outbuf_sz) { + tftp_status send_status = session->transport_interface.send(opts->outbuf, *opts->outbuf_sz, + transport_cookie); + if (send_status != TFTP_NO_ERROR) { + REPORT_ERR(opts, "failed during transport send callback"); + return send_status; + } + } + if (ret == TFTP_ERR_SHOULD_WAIT) { + REPORT_ERR(opts, "request received, host is busy"); + } else if (ret < 0) { + REPORT_ERR(opts, "handling tftp request failed (file might not exist)"); + } else if (ret == TFTP_TRANSFER_COMPLETED) { + if (session->file_interface.close) { + session->file_interface.close(file_cookie); + } + } else { + ret = session->transport_interface.timeout_set(timeout_ms, transport_cookie); + if (ret < 0) { + REPORT_ERR(opts, "failed during transport timeout set callback"); + } + } + return ret; +} diff --git a/tftp/tftp.h b/tftp/tftp.h new file mode 100644 index 0000000..e4cd36d --- /dev/null +++ b/tftp/tftp.h @@ -0,0 +1,329 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include +#include + +/** + * This is a library that implements TFTP (RFC 1350) with support for the + * option extension (RFC 2347) the block size (RFC 2348) timeout interval, + * transfer size (RFC 2349) and the window size (RFC 7440) options. + * + * It also supports block count rollover, which allows us to transfer files + * larger than 65536 * block size bytes. This is purported to be a common + * extension of the TFTP protocol. + * + * This library does not deal with the transport of the protocol itself and + * should be able to be plugged into an existing client or server program. + * + * Memory management is the responsibility of the client of the library, + * allowing its use in more restricted environments like bootloaders. + * + * To use this library, one should initialize a TFTP Session and generate + * a request if the transfer needs to be triggered by the consumer of this + * library. + * + * Once a transfer has been successfully started, repeated calls to the receive + * method should be made with the incoming data. Outgoing packets will be + * generated in the outgoing buffer parameters to each method call. + * + * In the case of the passive side of the connection, the receive method should + * be called repeatedly as well. Upon reception of the first packet the + * |tftp_file_open_cb| callback will be called to prepare for receiving the + * file. + * + * A timeout value is returned when calling |tftp_generate_request| and + * |tftp_process_msg| and should be used to notify the library that the + * expected packet was not receive within the value returned. + **/ + +enum { + TFTP_NO_ERROR = 0, + TFTP_TRANSFER_COMPLETED = 1, + + TFTP_ERR_INTERNAL = -1, + TFTP_ERR_NOT_SUPPORTED = -2, + TFTP_ERR_NOT_FOUND = -3, + TFTP_ERR_INVALID_ARGS = -10, + TFTP_ERR_BUFFER_TOO_SMALL = -15, + TFTP_ERR_BAD_STATE = -20, + TFTP_ERR_TIMED_OUT = -21, + TFTP_ERR_SHOULD_WAIT = -22, + TFTP_ERR_IO = -40, +}; + +enum { + TFTP_ERR_CODE_UNDEF = 0, + TFTP_ERR_CODE_FILE_NOT_FOUND = 1, + TFTP_ERR_CODE_ACCESS_VIOLATION = 2, + TFTP_ERR_CODE_DISK_FULL = 3, + TFTP_ERR_CODE_ILLEGAL_OP = 4, + TFTP_ERR_CODE_UNKNOWN_ID = 5, + TFTP_ERR_CODE_FILE_EXISTS = 6, + TFTP_ERR_CODE_NO_USER = 7, + TFTP_ERR_CODE_BAD_OPTIONS = 8, + + // Fuchsia-specific error code + // BUSY is sent by a server as a response to a RRQ or WRQ, and indicates + // that the server is unavailable to process the request at the moment + // (but expects to be able to handle it at some time in the future). + // A server will send an ERR_CODE_BUSY response if its open callback + // (open_read or open_write) returns TFTP_ERR_SHOULD_WAIT. + TFTP_ERR_CODE_BUSY = 0x143, /* 'B' + 'U' + 'S' + 'Y' */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +// Opaque structure +typedef struct tftp_session_t tftp_session; + +typedef int32_t tftp_status; + +typedef enum { + MODE_NETASCII, + MODE_OCTET, + MODE_MAIL, +} tftp_mode; + +// These are the default values used when sending a tftp request +#define TFTP_DEFAULT_CLIENT_MODE MODE_OCTET + +typedef struct { + char* inbuf; // required - buffer for assembling incoming msgs + size_t inbuf_sz; // required + char* outbuf; // required - buffer for assembling outgoing msgs + size_t outbuf_sz; // required + tftp_mode* mode; + uint16_t* block_size; + uint16_t* window_size; + uint8_t* timeout; + char* err_msg; + size_t err_msg_sz; +} tftp_request_opts; + +typedef struct { + char* inbuf; // required - buffer for assembling incoming msgs + size_t inbuf_sz; // required + char* outbuf; // required - buffer for assembling outgoing msgs + size_t* outbuf_sz; // required + char* err_msg; + size_t err_msg_sz; +} tftp_handler_opts; + +// tftp_file_open_read_cb is called by the library to prepare for reading. +// |file_cookie| will be passed to this function from the argument to +// tftp_process_msg. +// +// This function should return the size of the file on success, or a TFTP_ERR_* +// error code on failure. +typedef ssize_t (*tftp_file_open_read_cb)(const char* filename, + void* file_cookie); + +// tftp_file_open_write_cb is called by the library to prepare a file for +// writing. |file_cookie| will be passed to this function from the argument to +// tftp_process_msg. |size| indicates the size of the file that will be +// created (it may be ignored if this information is not needed on opening). +typedef tftp_status (*tftp_file_open_write_cb)(const char* filename, + size_t size, + void* file_cookie); + +// tftp_file_read_cb is called by the library to read |length| bytes, starting +// at |offset|, into |data|. |file_cookie| will be passed to this function from +// the argument to tftp_process_msg. +// +// |length| is both an input and output parameter, and may be set as a value +// less than or equal to the original value to indicate a partial read. +// |length| is only used as an output parameter if the returned status is +// TFTP_NO_ERROR. +typedef tftp_status (*tftp_file_read_cb)(void* data, + size_t* length, + off_t offset, + void* file_cookie); + +// tftp_file_write_cb is called by the library to write |length| bytes, +// starting at |offset|, into the destination. |file_cookie| will be passed to +// this function from the argument to tftp_process_msg. +// +// |length| is both an input and output parameter, and may be set as a value +// less than or equal to the original value to indicate a partial write. +// |length| is only used as an output parameter if the returned status is +// TFTP_NO_ERROR. +typedef tftp_status (*tftp_file_write_cb)(const void* data, + size_t* length, + off_t offset, + void* file_cookie); + +// tftp_file_close_cb is called by the library to finish a file read or write +// operation. |file_cookie| will be passed to this function from the argument to +// tftp_process_msg. +typedef void (*tftp_file_close_cb)(void* file_cookie); + +typedef struct { + tftp_file_open_read_cb open_read; + tftp_file_open_write_cb open_write; + tftp_file_read_cb read; + tftp_file_write_cb write; + tftp_file_close_cb close; +} tftp_file_interface; + +// tftp_transport_send_cb is called by the library to send |len| bytes from +// |data| over a previously-established connection. +typedef tftp_status (*tftp_transport_send_cb)(void* data, + size_t len, + void* transport_cookie); + +// tftp_transport_recv_cb is called by the library to read from the transport +// interface. It will read values into |data|, up to |len| bytes. If |block| is +// set, the operation will block until data is received or a timeout happens. +// (For starting communication, the timeout should be set by the user if +// desired. Once communication has been established, the timeout is set by the +// tftp library using the timeout_set callback). +// On success, the function should return the number of bytes received. On +// failure it should return a tftp_status error code. +typedef int (*tftp_transport_recv_cb)(void* data, + size_t len, + bool block, + void* transport_cookie); + +// tftp_transport_timeout_set_cb is called by the library to set the timeout +// length of the transport interface. This function should return 0 on success +// or -1 on failure. +typedef int (*tftp_transport_timeout_set_cb)(uint32_t timeout_ms, + void* transport_cookie); + +typedef struct { + tftp_transport_send_cb send; + tftp_transport_recv_cb recv; + tftp_transport_timeout_set_cb timeout_set; +} tftp_transport_interface; + +// Returns the number of bytes needed to hold a tftp_session. +size_t tftp_sizeof_session(void); + +// Initialize the tftp_session pointer using the memory in |buffer| of size +// |size|. Returns TFTP_ERR_BUFFER_TOO_SMALL if |size| is too small. +tftp_status tftp_init(tftp_session** session, void* buffer, size_t size); + +// Specifies the callback functions to use when reading or writing files. +tftp_status tftp_session_set_file_interface(tftp_session* session, + tftp_file_interface* callbacks); + +// Specifies the callback functions to use for the network interface. Note that +// setting up the transport must be performed outside of the purview of the +// library, since the initial configuration options are highly interface- +// dependent. +tftp_status tftp_session_set_transport_interface(tftp_session* session, + tftp_transport_interface* callbacks); + +// Specifies how many consecutive timeouts we will endure before terminating +// a session. +void tftp_session_set_max_timeouts(tftp_session* session, + uint16_t max_timeouts); + +// Specify whether to use the upper 8 bits of the opcode field as a pseudo +// retransmission count. When enabled, this tweaks the contents of a +// retransmitted packet just enough that it will have a different checksum, +// avoiding the problem we have on ASIX 88179 adapters that (reliably) +// generate incorrect checksums for certain packets. +void tftp_session_set_opcode_prefix_use(tftp_session* session, + bool enable); + +// When acting as a server, the options that will be overridden when a +// value is requested by the client. Note that if the client does not +// specify a setting, the default will be used regardless of server +// setting. +// When acting as a client, the default options that will be used when +// initiating a transfer. If any of the values are not set, it will not be +// specified in the request packet, and so the tftp defaults will be used. +tftp_status tftp_set_options(tftp_session* session, + const uint16_t* block_size, + const uint8_t* timeout, + const uint16_t* window_size); + +// tftp_session_has_pending returns true if the tftp_session has more data to +// send before waiting for an ack. It is recommended that the caller do a +// non-blocking read to see if an out-of-order ACK was sent by the remote host +// before sending additional data packets. +bool tftp_session_has_pending(tftp_session* session); + +// Prepare a DATA packet to send to the remote host. This is only required when +// tftp_session_has_pending(session) returns true, as tftp_process_msg() will +// prepare the first DATA message in each window. +tftp_status tftp_prepare_data(tftp_session* session, + void* outgoing, + size_t* outlen, + uint32_t* timeout_ms, + void* cookie); + +// If no response from the peer is received before the most recent timeout_ms +// value, this function should be called to take the next appropriate action +// (e.g., retransmit or cancel). |msg_buf| must point to the last message sent, +// which is |msg_len| bytes long. |buf_sz| represents the total size of +// |msg_buf|, which may be used to assemble the next packet to send. +// |timeout_ms| is set to the next timeout value the user of the library should +// use when waiting for a response. |file_cookie| will be passed to the tftp +// callback functions. On return, TFTP_ERR_TIMED out is returned if the maximum +// number of timeouts has been exceeded. If a message should be sent out, +// |msg_len| will be set to the size of the message. +tftp_status tftp_timeout(tftp_session* session, + void* msg_buf, + size_t* msg_len, + size_t buf_sz, + uint32_t* timeout_ms, + void* file_cookie); + +// Request to send the file |local_filename| across an existing session to +// |remote_filename| on the target. |options| are required for the input and +// output buffers, but other options can be left as NULL to use the session +// defaults. Before calling this function, the client transport interface +// should be configured as needed. +tftp_status tftp_push_file(tftp_session* session, + void* transport_cookie, + void* file_cookie, + const char* local_filename, + const char* remote_filename, + tftp_request_opts* options); + +// Request to retrieve the target file |remote_filename| across an existing +// session to |local_filename| on the host. |options| are required for the +// input and output buffers, but other options can be left as NULL to use the +// session defaults. Before calling this function, the client transport +// interface should be configured as needed. +tftp_status tftp_pull_file(tftp_session* session, + void* transport_cookie, + void* file_cookie, + const char* remote_filename, + const char* local_filename, + tftp_request_opts* options); + +// Wait for a client to request an operation, then service that request. +// Returns (with TFTP_TRANSFER_COMPLETED) after each successful operation, or +// on error. This function will call the transport send, recv, and timeout_set +// operations as needed to facilitate communication with the requestor. +tftp_status tftp_service_request(tftp_session* session, + void* transport_cookie, + void* file_cookie, + tftp_handler_opts* opts); + +// Processes a single message from the requestor, which is passed in as the +// inbuf component of |opts|. Responds to the request and updates the +// connection timeout using the appropriate transport send and timeout_set +// functions. Also, sets the value of outbuf_sz in |opts| to the size of +// the message sent (or 0 if no message was sent). +tftp_status tftp_handle_msg(tftp_session* session, + void* transport_cookie, + void* file_cookie, + tftp_handler_opts* opts); + +// TODO: tftp_error() for client errors that need to be sent to the remote host + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/uniboot.h b/uniboot.h new file mode 100644 index 0000000..283fef6 --- /dev/null +++ b/uniboot.h @@ -0,0 +1,134 @@ +#pragma once + +#include +#include + +struct __attribute__((packed)) uniboot_info { + uint64_t magic; // have to be UNIBOOT_MAGIC + uint32_t version; // version of the boot info + uint32_t length; // total length of the info struct + // entries data starts here +}; + +#define UNIBOOT_MAGIC 0x554e4943594b4cULL // 'UNICYKL' + +// The struct is aligned by 8-bytes +struct __attribute__((packed)) uniboot_entry { + uint32_t type; // UNIBOOT_ENTRY_* + uint32_t length; // length of the entry including this struct and following data + // entry data starts here +}; + +#define UNIBOOT_ENTRY_MEMORY_MAP 1 +#define UNIBOOT_ENTRY_SEGMENT_LIST 2 +#define UNIBOOT_ENTRY_SECTION_LIST 3 +#define UNIBOOT_ENTRY_FRAMEBUFFER 4 +#define UNIBOOT_ENTRY_ACPI_INFO 5 + +#define UNIBOOT_MEM_RESERVED 1 +#define UNIBOOT_MEM_UNUSABLE 2 +#define UNIBOOT_MEM_ACPI 3 +#define UNIBOOT_MEM_RAM 4 +#define UNIBOOT_MEM_NVS 5 + +struct __attribute__((packed)) uniboot_memory_area { + uint64_t type; // UNIBOOT_MEM_* + uint64_t start; // memory area start address + uint64_t length; // memory area length +}; + +struct __attribute__((packed)) uniboot_memory_map { + uint32_t num; // number of areas in the map + struct uniboot_memory_area areas[]; +}; + +#define UNIBOOT_SEG_NULL 0 /* Program header table entry unused */ +#define UNIBOOT_SEG_LOAD 1 /* Loadable program segment */ +#define UNIBOOT_SEG_DYNAMIC 2 /* Dynamic linking information */ +#define UNIBOOT_SEG_INTERP 3 /* Program interpreter */ +#define UNIBOOT_SEG_NOTE 4 /* Auxiliary information */ +#define UNIBOOT_SEG_SHLIB 5 /* Reserved */ +#define UNIBOOT_SEG_PHDR 6 /* Entry for header table itself */ +#define UNIBOOT_SEG_TLS 7 /* Thread-local storage segment */ + +struct __attribute__((packed)) uniboot_segment { + uint32_t type; /* Segment type */ + uint32_t flags; /* Segment flags */ + uint64_t offset; /* Segment file offset */ + uint64_t vaddr; /* Segment virtual address */ + uint64_t paddr; /* Segment physical address */ + uint64_t filesz; /* Segment size in file */ + uint64_t memsz; /* Segment size in memory */ + uint64_t align; /* Segment alignment */ +}; + +struct __attribute__((packed)) uniboot_segment_list { + uint16_t num; // number of segments + struct uniboot_segment segments[]; +}; + +#define UNIBOOT_SECTTYPE_NULL 0 /* Section header table entry unused */ +#define UNIBOOT_SECTTYPE_PROGBITS 1 /* Program data */ +#define UNIBOOT_SECTTYPE_SYMTAB 2 /* Symbol table */ +#define UNIBOOT_SECTTYPE_STRTAB 3 /* String table */ +#define UNIBOOT_SECTTYPE_RELA 4 /* Relocation entries with addends */ +#define UNIBOOT_SECTTYPE_HASH 5 /* Symbol hash table */ +#define UNIBOOT_SECTTYPE_DYNAMIC 6 /* Dynamic linking information */ +#define UNIBOOT_SECTTYPE_NOTE 7 /* Notes */ +#define UNIBOOT_SECTTYPE_NOBITS 8 /* Program space with no data (bss) */ +#define UNIBOOT_SECTTYPE_REL 9 /* Relocation entries, no addends */ +#define UNIBOOT_SECTTYPE_SHLIB 10 /* Reserved */ +#define UNIBOOT_SECTTYPE_DYNSYM 11 /* Dynamic linker symbol table */ +#define UNIBOOT_SECTTYPE_INIT_ARRAY 14 /* Array of constructors */ +#define UNIBOOT_SECTTYPE_FINI_ARRAY 15 /* Array of destructors */ +#define UNIBOOT_SECTTYPE_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define UNIBOOT_SECTTYPE_GROUP 17 /* Section group */ +#define UNIBOOT_SECTTYPE_SYMTAB_SHNDX 18 /* Extended section indices */ +#define UNIBOOT_SECTTYPE_NUM 19 /* Number of defined types. */ + +#define UNIBOOT_SECTFLAG_WRITE (1 << 0) /* Writable */ +#define UNIBOOT_SECTFLAG_ALLOC (1 << 1) /* Occupies memory during execution */ +#define UNIBOOT_SECTFLAG_EXECINSTR (1 << 2) /* Executable */ +#define UNIBOOT_SECTFLAG_MERGE (1 << 4) /* Might be merged */ +#define UNIBOOT_SECTFLAG_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define UNIBOOT_SECTFLAG_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define UNIBOOT_SECTFLAG_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define UNIBOOT_SECTFLAG_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling required */ +#define UNIBOOT_SECTFLAG_GROUP (1 << 9) /* Section is member of a group. */ +#define UNIBOOT_SECTFLAG_TLS (1 << 10) /* Section hold thread-local data. */ + +struct __attribute__((packed)) uniboot_section { + uint32_t name; /* Section name (string tbl index) */ + uint32_t type; /* Section type UNIBOOT_SECTTYPE_* */ + uint64_t flags; /* Section flags UNIBOOT_SECTFLAG_* */ + uint64_t addr; /* Section virtual addr at execution */ + uint64_t size; /* Section size in bytes */ + uint64_t addralign; /* Section alignment */ + uint64_t entsize; /* Entry size if section holds table */ +}; + +struct __attribute__((packed)) uniboot_section_list { + uint16_t num; // number of ELF sections + struct uniboot_section sections[]; +}; + +struct __attribute__((packed)) uniboot_framebuffer { + uint64_t base; // physical base addr + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; +}; + +// Framebuffer pixel format +#define UNIBOOT_PIXEL_FORMAT_UNKNOWN 0 +#define UNIBOOT_PIXEL_FORMAT_RGB_x888 1 +#define UNIBOOT_PIXEL_FORMAT_RGB_332 2 +#define UNIBOOT_PIXEL_FORMAT_RGB_565 3 +#define UNIBOOT_PIXEL_FORMAT_RGB_2220 4 + +struct __attribute__((packed)) uniboot_acpi_info { + uint64_t acpi_root; // ACPI structure address +}; + +typedef __attribute__((noreturn)) void (*uniboot_entry_point_t)(struct uniboot_info *info); diff --git a/xefi/console-printf.c b/xefi/console-printf.c new file mode 100644 index 0000000..53ee1a2 --- /dev/null +++ b/xefi/console-printf.c @@ -0,0 +1,85 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#define PCBUFMAX 126 +// buffer is two larger to leave room for a \0 and room +// for a \r that may be added after a \n + +#ifdef OUTPUT_SERIAL +#define PRINTTYPE char +#else +#define PRINTTYPE char16_t +#endif + + +typedef struct { + size_t off; + PRINTTYPE buf[PCBUFMAX + 2]; +} _pcstate; + +static int _printf_console_out(const char* str, size_t len, void* _state) { + _pcstate* state = _state; + PRINTTYPE* buf = state->buf; + size_t i = state->off; + int n = len; + while (n > 0) { + if (*str == '\n') { + buf[i++] = '\r'; + } + buf[i++] = *str++; + if (i >= PCBUFMAX) { +#ifdef OUTPUT_SERIAL + gSerialOut->Write(gSerialOut, &i, buf); +#else + buf[i] = 0; + gConOut->OutputString(gConOut, buf); +#endif + i = 0; + } + n--; + } + state->off = i; + return len; +} + +int printf(const char* fmt, ...) { + va_list ap; + _pcstate state; + int r; + state.off = 0; + va_start(ap, fmt); + r = _printf_engine(_printf_console_out, &state, fmt, ap); + va_end(ap); + if (state.off) { +#ifdef OUTPUT_SERIAL + gSerialOut->Write(gSerialOut, &state.off, state.buf); +#else + state.buf[state.off] = 0; + gConOut->OutputString(gConOut, state.buf); +#endif + } + return r; +} + +int puts16(char16_t* str) { +#ifdef OUTPUT_SERIAL + _pcstate state; + state.off = 0; + // convert wide char to regular chars + for (; *str; str++) { + state.buf[state.off++] = *str; + } + int r = 0; + if (state.off) { + efi_status s = gSerialOut->Write(gSerialOut, &state.off, state.buf); + r = (s == EFI_SUCCESS) ? 0 : -1; + } + return r; +#else + return gConOut->OutputString(gConOut, str) == EFI_SUCCESS ? 0 : -1; +#endif +} diff --git a/xefi/ctype.c b/xefi/ctype.c new file mode 100644 index 0000000..2035daf --- /dev/null +++ b/xefi/ctype.c @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +int isdigit(int c) { + return (c >= '0') && (c <= '9'); +} + +int isspace(int c) { + return (c == ' ') || + (c == '\f') || + (c == '\n') || + (c == '\r') || + (c == '\t') || + (c == '\v'); +} + +int tolower(int c) { + if (c >= 'A' && c <= 'Z') { + return c + ('a' - 'A'); + } + return c; +} + diff --git a/xefi/efi-x86-64.lds b/xefi/efi-x86-64.lds new file mode 100644 index 0000000..7d25bb2 --- /dev/null +++ b/xefi/efi-x86-64.lds @@ -0,0 +1,51 @@ +/* Copyright 2016 The Fuchsia Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(efi_main) +SECTIONS +{ + . = 0x2000; + . = ALIGN(4096); + .text : + { + *(.text) + *(.text.*) + . = ALIGN(16); + } + + . = ALIGN(4096); + .data : + { + *(.rodata*) + *(.got.plt) + *(.got) + *(.data*) + *(.sdata) + /* TODO: figure out how to move .bss in such a way that the PE32+ loader + * doesn't complain. + */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + *(.rel.local) + } + + . = ALIGN(4096); + + /* A .reloc section is required to flag the final PE32+ file as relocatable. + * Here we hardcode one block with one entry to keep the PE32+ loader happy. + */ + _a = .; + . = ALIGN(4096); + .reloc : + { + LONG(. - _a); + LONG(10); + SHORT(0); + } +} diff --git a/xefi/efi/boot-services.h b/xefi/efi/boot-services.h new file mode 100644 index 0000000..8cc5f44 --- /dev/null +++ b/xefi/efi/boot-services.h @@ -0,0 +1,205 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 +#define EFI_BOOT_SERVICES_REVISION EFI_SPECIFICATION_VERSION + +typedef size_t efi_tpl; + +#define TPL_APPLICATION 4 +#define TPL_CALLBACK 8 +#define TPL_NOTIFY 16 +#define TPL_HIGH_LEVEL 31 + +typedef enum { + AllocateAnyPages, + AllocateMaxAddress, + AllocateAddress, + MaxAllocateType +} efi_allocate_type; + +typedef struct { + uint32_t Type; + efi_physical_addr PhysicalStart; + efi_virtual_addr VirtualStart; + uint64_t NumberOfPages; + uint64_t Attribute; +} efi_memory_descriptor; + +#define EFI_MEMORY_UC 0x0000000000000001 +#define EFI_MEMORY_WC 0x0000000000000002 +#define EFI_MEMORY_WT 0x0000000000000004 +#define EFI_MEMORY_WB 0x0000000000000008 +#define EFI_MEMORY_UCE 0x0000000000000010 +#define EFI_MEMORY_WP 0x0000000000001000 +#define EFI_MEMORY_RP 0x0000000000002000 +#define EFI_MEMORY_XP 0x0000000000004000 +#define EFI_MEMORY_NV 0x0000000000008000 +#define EFI_MEMORY_MORE_RELIABLE 0x0000000000010000 +#define EFI_MEMORY_RO 0x0000000000020000 +#define EFI_MEMORY_RUNTIME 0x8000000000000000 + +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 + +typedef enum { + EFI_NATIVE_INTERFACE +} efi_interface_type; + +typedef enum { + AllHandles, + ByRegisterNotify, + ByProtocol +} efi_locate_search_type; + +#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 + +typedef struct { + efi_handle agent_handle; + efi_handle controller_handle; + uint32_t attributes; + uint32_t open_count; +} efi_open_protocol_information_entry; + +#define EFI_HII_PACKAGE_LIST_PROTOCOL_GUID \ + {0x6a1ee763, 0xd47a, 0x43b4, {0xaa, 0xbe, 0xef, 0x1d, 0xe2, 0xab, 0x56, 0xfc}} + +typedef struct efi_hii_package_list_header efi_hii_package_list_header; +typedef efi_hii_package_list_header* efi_hii_package_list_protocol; + +// fwd declare efi_system_table to break circular dependencies +typedef struct efi_system_table efi_system_table; +typedef efi_status (*efi_image_entry_point) (efi_handle img, efi_system_table* sys) EFIAPI; + +typedef struct { + efi_table_header Hdr; + + efi_tpl (*RaiseTPL) (efi_tpl new_tpl) EFIAPI; + + void (*RestoreTPL) (efi_tpl old_tpl) EFIAPI; + + efi_status (*AllocatePages) (efi_allocate_type type, efi_memory_type memory_type, + size_t pages, efi_physical_addr* memory) EFIAPI; + + efi_status (*FreePages) (efi_physical_addr memory, size_t pages) EFIAPI; + + efi_status (*GetMemoryMap) (size_t* memory_map_size, efi_memory_descriptor* memory_map, + size_t* map_key, size_t* desc_size, uint32_t* desc_version) EFIAPI; + + efi_status (*AllocatePool) (efi_memory_type pool_type, size_t size, void** buf) EFIAPI; + + efi_status (*FreePool) (void* buf) EFIAPI; + + efi_status (*CreateEvent) (uint32_t type, efi_tpl notify_tpl, + efi_event_notify notify_fn, void* notify_ctx, + efi_event* event) EFIAPI; + + efi_status (*SetTimer) (efi_event event, efi_timer_delay type, uint64_t trigger_time) EFIAPI; + + efi_status (*WaitForEvent) (size_t num_events, efi_event* event, size_t* index) EFIAPI; + + efi_status (*SignalEvent) (efi_event event) EFIAPI; + + efi_status (*CloseEvent) (efi_event event) EFIAPI; + + efi_status (*CheckEvent) (efi_event event) EFIAPI; + + efi_status (*InstallProtocolInterface) (efi_handle* handle, efi_guid* protocol, + efi_interface_type intf_type, void* intf) EFIAPI; + + efi_status (*ReinstallProtocolInterface) (efi_handle hadle, efi_guid* protocol, + void* old_intf, void* new_intf) EFIAPI; + + efi_status (*UninstallProtocolInterface) (efi_handle handle, efi_guid* protocol, + void* intf) EFIAPI; + + efi_status (*HandleProtocol) (efi_handle handle, efi_guid* protocol, void** intf) EFIAPI; + + void* Reserved; + + efi_status (*RegisterProtocolNotify) (efi_guid* protocol, efi_event event, + void** registration) EFIAPI; + + efi_status (*LocateHandle) (efi_locate_search_type search_type, efi_guid* protocol, + void* search_key, size_t* buf_size, efi_handle* buf) EFIAPI; + + efi_status (*LocateDevicePath) (efi_guid* protocol, efi_device_path_protocol** path, + efi_handle* device) EFIAPI; + + efi_status (*InstallConfigurationTable) (efi_guid* guid, void* table) EFIAPI; + + efi_status (*LoadImage) (bool boot_policy, efi_handle parent_image_handle, + efi_device_path_protocol* path, void* src, size_t src_size, + efi_handle* image_handle) EFIAPI; + + efi_status (*StartImage) (efi_handle image_handle, size_t* exit_data_size, + char16_t** exit_data) EFIAPI; + + efi_status (*Exit) (efi_handle image_handle, efi_status exit_status, + size_t exit_data_size, char16_t* exit_data) EFIAPI; + + efi_status (*UnloadImage) (efi_handle image_handle) EFIAPI; + + efi_status (*ExitBootServices) (efi_handle image_handle, size_t map_key) EFIAPI; + + efi_status (*GetNextMonotonicCount) (uint64_t* count) EFIAPI; + + efi_status (*Stall) (size_t microseconds) EFIAPI; + + efi_status (*SetWatchdogTimer) (size_t timeout, uint64_t watchdog_code, + size_t data_size, char16_t* watchdog_data) EFIAPI; + + efi_status (*ConnectController) (efi_handle controller_handle, + efi_handle* driver_image_handle, + efi_device_path_protocol* remaining_path, + bool recursive) EFIAPI; + + efi_status (*DisconnectController) (efi_handle controller_handle, + efi_handle driver_image_handle, + efi_handle child_handle) EFIAPI; + + efi_status (*OpenProtocol) (efi_handle handle, efi_guid* protocol, void** intf, + efi_handle agent_handle, efi_handle controller_handle, + uint32_t attributes) EFIAPI; + + efi_status (*CloseProtocol) (efi_handle handle, efi_guid* protocol, + efi_handle agent_handle, efi_handle controller_handle) EFIAPI; + + efi_status (*OpenProtocolInformation) (efi_handle handle, efi_guid* protocol, + efi_open_protocol_information_entry** entry_buf, + size_t* entry_count) EFIAPI; + + efi_status (*ProtocolsPerHandle) (efi_handle handle, efi_guid*** protocol_buf, + size_t* protocol_buf_count) EFIAPI; + + efi_status (*LocateHandleBuffer) (efi_locate_search_type search_type, + efi_guid* protocol, void* search_key, + size_t* num_handles, efi_handle** buf) EFIAPI; + + efi_status (*LocateProtocol) (efi_guid* protocol, void* registration, void** intf) EFIAPI; + + efi_status (*InstallMultipleProtocolInterfaces) (efi_handle* handle, ...) EFIAPI; + + efi_status (*UninstallMultipleProtocolInterfaces) (efi_handle handle, ...) EFIAPI; + + efi_status (*CalculateCrc32) (void* data, size_t len, uint32_t* crc32) EFIAPI; + + void (*CopyMem) (void* dest, const void* src, size_t len) EFIAPI; + + void (*SetMem) (void* buf, size_t len, uint8_t val) EFIAPI; + + efi_status (*CreateEventEx) (uint32_t type, efi_tpl notify_tpl, + efi_event_notify notify_fn, const void* notify_ctx, + const efi_guid* event_group, efi_event* event) EFIAPI; +} efi_boot_services; diff --git a/xefi/efi/protocol/block-io.h b/xefi/efi/protocol/block-io.h new file mode 100644 index 0000000..cf53e6b --- /dev/null +++ b/xefi/efi/protocol/block-io.h @@ -0,0 +1,56 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#define EFI_BLOCK_IO_PROTOCOL_GUID \ + {0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} + +extern efi_guid BlockIoProtocol; + +#define EFI_BLOCK_IO_PROTOCOL_REVISION2 0x00020001 +#define EFI_BLOCK_IO_PROTOCOL_REVISION3 0x00020031 + +typedef struct efi_block_io_media efi_block_io_media; +typedef struct efi_block_io_protocol efi_block_io_protocol; + +struct efi_block_io_protocol { + uint64_t Revision; + efi_block_io_media* Media; + efi_status (*Reset)(efi_block_io_protocol* self, + bool ExtendedVerification) EFIAPI; + efi_status (*ReadBlocks)(efi_block_io_protocol* self, + uint32_t MediaId, uint64_t LBA, + uint64_t BufferSize, void* Buffer) EFIAPI; + efi_status (*WriteBlocks)(efi_block_io_protocol* self, + uint32_t MediaId, uint64_t LBA, + uint64_t BufferSize, const void* Buffer) EFIAPI; + efi_status (*FlushBlocks)(efi_block_io_protocol* self); + + +}; + +struct efi_block_io_media { + // present in rev1 + uint32_t MediaId; + bool RemovableMedia; + bool MediaPresent; + bool LogicalPartition; + bool ReadOnly; + bool WriteCaching; + uint32_t BlockSize; + uint32_t IoAlign; + uint64_t LastBlock; + + // present in rev2 + uint64_t LowestAlignedLba; + uint32_t LogicalBlocksPerPhysicalBlock; + + // present in rev3 + uint32_t OptimalTransferLengthGranularity; +}; diff --git a/xefi/efi/protocol/device-path-to-text.h b/xefi/efi/protocol/device-path-to-text.h new file mode 100644 index 0000000..119d669 --- /dev/null +++ b/xefi/efi/protocol/device-path-to-text.h @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + {0x8b843e20, 0x8132, 0x4852, {0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c}} +extern efi_guid DevicePathToTextProtocol; + +typedef struct efi_device_path_to_text_protocol { + char16_t* (*ConvertDeviceNodeToText) (const efi_device_path_protocol* dev_node, + bool display_only, bool allow_shortcuts) EFIAPI; + + char16_t* (*ConvertDevicePathToText) (const efi_device_path_protocol* dev_path, + bool display_only, bool allow_shortcuts) EFIAPI; +} efi_device_path_to_text_protocol; diff --git a/xefi/efi/protocol/device-path.h b/xefi/efi/protocol/device-path.h new file mode 100644 index 0000000..8356c28 --- /dev/null +++ b/xefi/efi/protocol/device-path.h @@ -0,0 +1,45 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#define EFI_DEVICE_PATH_PROTOCOL_GUID \ + {0x09576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +extern efi_guid DevicePathProtocol; + +typedef struct efi_device_path_protocol { + uint8_t Type; + uint8_t SubType; + uint8_t Length[2]; +} efi_device_path_protocol; + +#define DEVICE_PATH_HARDWARE 0x01 +#define DEVICE_PATH_ACPI 0x02 +#define DEVICE_PATH_MESSAGING 0x03 +#define DEVICE_PATH_MEDIA 0x04 +#define DEVICE_PATH_BIOS_BOOT_SPEC 0x05 +#define DEVICE_PATH_END 0x7f + +#define DEVICE_PATH_INSTANCE_END 0x01 +#define DEVICE_PATH_ENTIRE_END 0xff + +#define DEVICE_PATH_HW_PCI 0x01 +#define DEVICE_PATH_HW_PCCARD 0x02 +#define DEVICE_PATH_HW_MEMMAP 0x03 +#define DEVICE_PATH_HW_VENDOR 0x04 +#define DEVICE_PATH_HW_CONTROLLER 0x05 +#define DEVICE_PATH_HW_BMC 0x06 + +// TODO: sub-types for other types (ACPI, etc) + +// TODO: move this to another header? would break circular dependencies between +// boot-services.h and this header, for efi_memory_type +typedef struct { + efi_device_path_protocol Header; + efi_memory_type MemoryType; + efi_physical_addr StartAddress; + efi_physical_addr EndAddress; +} efi_device_path_hw_memmap; diff --git a/xefi/efi/protocol/disk-io.h b/xefi/efi/protocol/disk-io.h new file mode 100644 index 0000000..455fd88 --- /dev/null +++ b/xefi/efi/protocol/disk-io.h @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#define EFI_DISK_IO_PROTOCOL_GUID \ + {0xCE345171, 0xBA0B, 0x11d2, {0x8e, 0x4F, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} + +extern efi_guid DiskIoProtocol; + +#define EFI_DISK_IO_PROTOCOL_REVISION 0x00010000 + +typedef struct efi_disk_io_protocol efi_disk_io_protocol; + +struct efi_disk_io_protocol { + uint64_t Revision; + efi_status (*ReadDisk)(efi_disk_io_protocol* self, + uint32_t MediaId, uint64_t Offset, + uint64_t BufferSize, void* Buffer) EFIAPI; + efi_status (*WriteDisk)(efi_disk_io_protocol* self, + uint32_t MediaId, uint64_t Offset, + uint64_t BufferSize, const void* Buffer) EFIAPI; +}; \ No newline at end of file diff --git a/xefi/efi/protocol/driver-binding.h b/xefi/efi/protocol/driver-binding.h new file mode 100644 index 0000000..bd928ac --- /dev/null +++ b/xefi/efi/protocol/driver-binding.h @@ -0,0 +1,30 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#define EFI_DRIVER_BINDING_PROTOCOL_GUID \ + {0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71}} +extern efi_guid DriverBindingProtocol; + +typedef struct efi_driver_binding_protocol { + efi_status (*Supported) (struct efi_driver_binding_protocol* self, + efi_handle controller_handle, + efi_device_path_protocol* remaining_path) EFIAPI; + + efi_status (*Start) (struct efi_driver_binding_protocol* self, + efi_handle controller_handle, + efi_device_path_protocol* remaining_path) EFIAPI; + + efi_status (*Stop) (struct efi_driver_binding_protocol* self, + efi_handle controller_handle, + size_t num_children, efi_handle* child_handle_buf) EFIAPI; + + uint32_t Version; + efi_handle ImageHandle; + efi_handle DriverBindingHandle; +} efi_driver_binding_protocol; diff --git a/xefi/efi/protocol/file.h b/xefi/efi/protocol/file.h new file mode 100644 index 0000000..394c13e --- /dev/null +++ b/xefi/efi/protocol/file.h @@ -0,0 +1,97 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#define EFI_FILE_PROTOCOL_REVISION 0x00010000 +#define EFI_FILE_PROTOCOL_REVISION2 0x00020000 +#define EFI_FILE_PROTOCOL_LATEST_REVISION EFI_FILE_PROTOCOL_REVISION2 + +#define EFI_FILE_MODE_READ 0x0000000000000001 +#define EFI_FILE_MODE_WRITE 0x0000000000000002 +#define EFI_FILE_MODE_CREATE 0x8000000000000000 + +#define EFI_FILE_READ_ONLY 0x0000000000000001 +#define EFI_FILE_HIDDEN 0x0000000000000002 +#define EFI_FILE_SYSTEM 0x0000000000000004 +#define EFI_FILE_RESERVED 0x0000000000000008 +#define EFI_FILE_DIRECTORY 0x0000000000000010 +#define EFI_FILE_ARCHIVE 0x0000000000000020 +#define EFI_FILE_VALID_ATTR 0x0000000000000037 + +typedef struct { + efi_event Event; + efi_status Status; + size_t BufferSize; + void* Buffer; +} efi_file_io_token; + +#define EFI_FILE_INFO_GUID \ + {0x09576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +extern efi_guid FileInfoGuid; + +typedef struct { + uint64_t Size; + uint64_t FileSize; + uint64_t PhysicalSize; + efi_time CreateTime; + efi_time LastAccessTime; + efi_time ModificationTime; + uint64_t Attribute; + char16_t FileName[]; +} efi_file_info; + +#define EFI_FILE_SYSTEM_INFO_GUID \ + {0x09576e93, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +extern efi_guid FileSystemInfoGuid; + +typedef struct { + uint64_t Size; + bool ReadOnly; + uint64_t VolumeSize; + uint64_t FreeSpace; + uint32_t BlockSize; + char16_t* VolumeLabel[]; +} efi_file_system_info; + +typedef struct efi_file_protocol { + uint64_t Revision; + + efi_status (*Open) (struct efi_file_protocol* self, struct efi_file_protocol** new_handle, + const char16_t* filename, uint64_t open_mode, uint64_t attributes) EFIAPI; + + efi_status (*Close) (struct efi_file_protocol* self) EFIAPI; + + efi_status (*Delete) (struct efi_file_protocol* self) EFIAPI; + + efi_status (*Read) (struct efi_file_protocol* self, size_t* len, void* buf) EFIAPI; + + efi_status (*Write) (struct efi_file_protocol* self, size_t* len, void* buf) EFIAPI; + + efi_status (*GetPosition) (struct efi_file_protocol* self, uint64_t* position) EFIAPI; + + efi_status (*SetPosition) (struct efi_file_protocol* self, uint64_t position) EFIAPI; + + efi_status (*GetInfo) (struct efi_file_protocol* self, efi_guid* info_type, + size_t* buf_size, void* buf) EFIAPI; + + efi_status (*SetInfo) (struct efi_file_protocol* self, efi_guid* info_type, + size_t buf_size, void* buf) EFIAPI; + + efi_status (*Flush) (struct efi_file_protocol* self) EFIAPI; + + efi_status (*OpenEx) (struct efi_file_protocol* self, struct efi_file_protocol* new_handle, + char16_t* filename, uint64_t open_mode, uint64_t attributes, + efi_file_io_token* token) EFIAPI; + + efi_status (*ReadEx) (struct efi_file_protocol* self, efi_file_io_token* token) EFIAPI; + + efi_status (*WriteEx) (struct efi_file_protocol* self, efi_file_io_token* token) EFIAPI; + + efi_status (*FlushEx) (struct efi_file_protocol* self, efi_file_io_token* token) EFIAPI; +} efi_file_protocol; diff --git a/xefi/efi/protocol/graphics-output.h b/xefi/efi/protocol/graphics-output.h new file mode 100644 index 0000000..772cf06 --- /dev/null +++ b/xefi/efi/protocol/graphics-output.h @@ -0,0 +1,76 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ + {0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a}} +extern efi_guid GraphicsOutputProtocol; + +typedef struct { + uint32_t RedMask; + uint32_t GreenMask; + uint32_t BlueMask; + uint32_t ReservedMask; +} efi_pixel_bitmask; + +typedef enum { + PixelRedGreenBlueReserved8BitPerColor, + PixelBlueGreenRedReserved8BitPerColor, + PixelBitMask, + PixelBltOnly, + PixelFormatMax +} efi_graphics_pixel_format; + +typedef struct { + uint32_t Version; + uint32_t HorizontalResolution; + uint32_t VerticalResolution; + efi_graphics_pixel_format PixelFormat; + efi_pixel_bitmask PixelInformation; + uint32_t PixelsPerScanLine; +} efi_graphics_output_mode_information; + +typedef struct { + uint32_t MaxMode; + uint32_t Mode; + efi_graphics_output_mode_information* Info; + size_t SizeOfInfo; + efi_physical_addr FrameBufferBase; + size_t FrameBufferSize; +} efi_graphics_output_mode; + +typedef struct { + uint8_t Blue; + uint8_t Green; + uint8_t Red; + uint8_t Reserved; +} efi_graphics_output_blt_pixel; + +typedef enum { + EfiBltVideoFill, + EfiBltVideoToBltBuffer, + EfiBltBufferToVideo, + EfiBltVideoToVideo, + EfiGraphicsOutputBltOperationMax +} efi_graphics_output_blt_operation; + +typedef struct efi_graphics_output_protocol { + efi_status (*QueryMode) (struct efi_graphics_output_protocol* self, + uint32_t mode_num, size_t* info_len, + efi_graphics_output_mode_information** info) EFIAPI; + + efi_status (*SetMode) (struct efi_graphics_output_protocol* self, + uint32_t mode_num) EFIAPI; + + efi_status (*Blt) (struct efi_graphics_output_protocol* self, + efi_graphics_output_blt_pixel* blt_buf, + efi_graphics_output_blt_operation blt_operation, + size_t src_x, size_t src_y, size_t dest_x, size_t dest_y, + size_t width, size_t height, size_t delta) EFIAPI; + + efi_graphics_output_mode* Mode; +} efi_graphics_output_protocol; diff --git a/xefi/efi/protocol/loaded-image.h b/xefi/efi/protocol/loaded-image.h new file mode 100644 index 0000000..800d269 --- /dev/null +++ b/xefi/efi/protocol/loaded-image.h @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#define EFI_LOADED_IMAGE_PROTOCOL_GUID \ + {0x5b1b31a1, 0x9562, 0x11d2, {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +extern efi_guid LoadedImageProtocol; + +#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000 + +typedef struct { + uint32_t Revision; + efi_handle ParentHandle; + efi_system_table* SystemTable; + efi_handle DeviceHandle; + efi_device_path_protocol* FilePath; + void* Reserved; + uint32_t LoadOptionsSize; + void* LoadOptions; + void* ImageBase; + uint64_t ImageSize; + efi_memory_type ImageCodeType; + efi_memory_type ImageDataType; + + efi_status (*Unload) (efi_handle img) EFIAPI; +} efi_loaded_image_protocol; diff --git a/xefi/efi/protocol/managed-network.h b/xefi/efi/protocol/managed-network.h new file mode 100644 index 0000000..b2d65e3 --- /dev/null +++ b/xefi/efi/protocol/managed-network.h @@ -0,0 +1,92 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#define EFI_MANAGED_NETWORK_PROTOCOL_GUID \ + {0x7ab33a91, 0xace5, 0x4326,{0xb5, 0x72, 0xe7, 0xee, 0x33, 0xd3, 0x9f, 0x16}} +extern efi_guid ManagedNetworkProtocol; + +typedef struct { + efi_time Timestamp; + efi_event RecycleEvent; + uint32_t PacketLength; + uint32_t HeaderLength; + uint32_t AddressLength; + uint32_t DataLength; + bool BroadcastFlag; + bool MulticastFlag; + bool PromiscuousFlag; + uint16_t ProtocolType; + void* DestinationAddress; + void* SourceAddress; + void* MediaHeader; + void* PacketData; +} efi_managed_network_receive_data; + +typedef struct { + uint32_t FragmentLength; + void* FragmentBuffer; +} efi_managed_network_fragment_data; + +typedef struct { + efi_mac_addr* DestinationAddress; + efi_mac_addr* SourceAddress; + uint16_t ProtocolType; + uint32_t DataLength; + uint16_t HeaderLength; + uint16_t FragmentCount; + efi_managed_network_fragment_data FragmentTable[1]; +} efi_managed_network_transmit_data; + +typedef struct { + uint32_t ReceivedQueueTimeoutValue; + uint32_t TransmitQueueTimeoutValue; + uint16_t ProtocolTypeFilter; + bool EnableUnicastReceive; + bool EnableMulticastReceive; + bool EnableBroadcastReceive; + bool EnablePromiscuousReceive; + bool FlushQueuesOnReset; + bool EnableReceiveTimestamps; + bool DisableBackgroundPolling; +} efi_managed_network_config_data; + +typedef struct { + efi_event Event; + efi_status Status; + union { + efi_managed_network_receive_data* RxData; + efi_managed_network_transmit_data* TxData; + } Packet; +} efi_managed_network_sync_completion_token; + +typedef struct efi_managed_network_protocol { + efi_status (*GetModeData) (struct efi_managed_network_protocol* self, + efi_managed_network_config_data* mnp_config_data, + efi_simple_network_mode* snp_mode_data) EFIAPI; + + efi_status (*Configure) (struct efi_managed_network_protocol* self, + efi_managed_network_config_data* mnp_config_data) EFIAPI; + + efi_status (*McastIpToMac) (struct efi_managed_network_protocol* self, + bool ipv6_flag, efi_ip_addr* ip_addr, efi_mac_addr* mac_addr) EFIAPI; + + efi_status (*Groups) (struct efi_managed_network_protocol* self, bool join_flag, + efi_mac_addr* mac_addr) EFIAPI; + + efi_status (*Transmit) (struct efi_managed_network_protocol* self, + efi_managed_network_sync_completion_token* token) EFIAPI; + + efi_status (*Receive) (struct efi_managed_network_protocol* self, + efi_managed_network_sync_completion_token* token) EFIAPI; + + efi_status (*Cancel) (struct efi_managed_network_protocol* self, + efi_managed_network_sync_completion_token* token) EFIAPI; + + efi_status (*Poll) (struct efi_managed_network_protocol* self) EFIAPI; +} efi_managed_network_protocol; diff --git a/xefi/efi/protocol/pci-root-bridge-io.h b/xefi/efi/protocol/pci-root-bridge-io.h new file mode 100644 index 0000000..1e54f89 --- /dev/null +++ b/xefi/efi/protocol/pci-root-bridge-io.h @@ -0,0 +1,115 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \ + {0x2f707ebb, 0x4a1a, 0x11D4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d}} +extern efi_guid PciRootBridgeIoProtocol; + +typedef enum { + EfiPciWidthUint8, + EfiPciWidthUint16, + EfiPciWidthUint32, + EfiPciWidthUint64, + EfiPciWidthFifoUint8, + EfiPciWidthFifoUint16, + EfiPciWidthFifoUint32, + EfiPciWidthFifoUint64, + EfiPciWidthFillUint8, + EfiPciWidthFillUint16, + EfiPciWidthFillUint32, + EfiPciWidthFillUint64, + EfiPciWidthMaximum, +} efi_pci_root_bridge_io_width; + +struct efi_pci_root_bridge_io_protocol; + +typedef struct { + efi_status (*Read) (struct efi_pci_root_bridge_io_protocol* self, + efi_pci_root_bridge_io_width width, + uint64_t addr, size_t count, void* buffer) EFIAPI; + efi_status (*Write) (struct efi_pci_root_bridge_io_protocol* self, + efi_pci_root_bridge_io_width width, + uint64_t addr, size_t count, void* buffer) EFIAPI; +} efi_pci_root_bridge_io_access; + +#define EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 +#define EFI_PCI_ATTRIBUTE_ISA_IO 0x0002 +#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO 0x0004 +#define EFI_PCI_ATTRIBUTE_VGA_MEMORY 0x0008 +#define EFI_PCI_ATTRIBUTE_VGA_IO 0x0010 +#define EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 +#define EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 +#define EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 +#define EFI_PCI_ATTRIBUTE_MEMORY_CACHED 0x0800 +#define EFI_PCI_ATTRIBUTE_MEMORY_DISABLE 0x1000 +#define EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 +#define EFI_PCI_ATTRIBUTE_ISA_IO_16 0x10000 +#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 +#define EFI_PCI_ATTRIBUTE_VGA_IO_16 0x40000 + +typedef enum { + EfiPciOperationBusMasterRead, + EfiPciOperationBusMasterWrite, + EfiPciOperationBusMasterCommonBuffer, + EfiPciOperationBusMasterRead64, + EfiPciOperationBusMasterWrite64, + EfiPciOperationBusMasterCommonBuffer64, + EfiPciOperationMaximum, +} efi_pci_root_bridge_io_operation; + +typedef struct efi_pci_root_bridge_io_protocol { + efi_handle ParentHandle; + + efi_status (*PollMem) (struct efi_pci_root_bridge_io_protocol *self, + efi_pci_root_bridge_io_width width, + uint64_t addr, uint64_t mask, uint64_t value, uint64_t delay, + uint64_t* result) EFIAPI; + + efi_status (*PollIo) (struct efi_pci_root_bridge_io_protocol *self, + efi_pci_root_bridge_io_width width, + uint64_t addr, uint64_t mask, uint64_t value, uint64_t delay, + uint64_t* result) EFIAPI; + + efi_pci_root_bridge_io_access Mem; + efi_pci_root_bridge_io_access Io; + efi_pci_root_bridge_io_access Pci; + + efi_status (*CopyMem) (struct efi_pci_root_bridge_io_protocol* self, + efi_pci_root_bridge_io_width width, + uint64_t dest_addr, uint64_t src_addr, size_t count) EFIAPI; + + efi_status (*Map) (struct efi_pci_root_bridge_io_protocol* self, + efi_pci_root_bridge_io_operation operation, + void* host_addr, size_t* num_bytes, + efi_physical_addr* device_addr, void** mapping) EFIAPI; + + efi_status (*Unmap) (struct efi_pci_root_bridge_io_protocol* self, + void* mapping) EFIAPI; + + efi_status (*AllocateBuffer) (struct efi_pci_root_bridge_io_protocol* self, + efi_allocate_type type, efi_memory_type memory_type, + size_t pages, void** host_addr, uint64_t attributes) EFIAPI; + + efi_status (*FreeBuffer) (struct efi_pci_root_bridge_io_protocol* self, + size_t pages, void* host_addr) EFIAPI; + + efi_status (*Flush) (struct efi_pci_root_bridge_io_protocol* self) EFIAPI; + + efi_status (*GetAttributes) (struct efi_pci_root_bridge_io_protocol* self, + uint64_t* supports, uint64_t* attributes) EFIAPI; + + efi_status (*SetAttributes) (struct efi_pci_root_bridge_io_protocol* self, + uint64_t attributes, uint64_t* resource_base, + uint64_t* resource_len) EFIAPI; + + efi_status (*Configuration) (struct efi_pci_root_bridge_io_protocol* self, + void** resources) EFIAPI; + + uint32_t SegmentNumber; +} efi_pci_root_bridge_io_protocol; diff --git a/xefi/efi/protocol/serial-io.h b/xefi/efi/protocol/serial-io.h new file mode 100644 index 0000000..53f9a99 --- /dev/null +++ b/xefi/efi/protocol/serial-io.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include + +#define EFI_SERIAL_IO_PROTOCOL_GUID \ + {0xbb25cf6f, 0xf1d4, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0xfd}} +extern efi_guid SerialIoProtocol; + +#define EFI_SERIAL_IO_PROTOCOL_REVISION 0x00010000 + +typedef struct efi_serial_io_mode { + uint32_t ControlMask; + // current Attributes + uint32_t Timeout; + uint64_t BaudRate; + uint32_t ReceiveFifoDepth; + uint32_t DataBits; + uint32_t Parity; + uint32_t StopBits; +} efi_serial_io_mode; + +// Control bits +#define EFI_SERIAL_CLEAR_TO_SEND 0x0010 +#define EFI_SERIAL_DATA_SET_READY 0x0020 +#define EFI_SERIAL_RING_INDICATE 0x0040 +#define EFI_SERIAL_CARRIER_DETECT 0x0080 +#define EFI_SERIAL_REQUEST_TO_SEND 0x0002 +#define EFI_SERIAL_DATA_TERMINAL_READY 0x0001 +#define EFI_SERIAL_INPUT_BUFFER_EMPTY 0x0100 +#define EFI_SERIAL_OUTPUT_BUFFER_EMPTY 0x0200 +#define EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE 0x1000 +#define EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE 0x2000 +#define EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE 0x4000 + +typedef enum { + DefaultParity, + NoParity, + EvenParity, + OddParity, + MarkParity, + SpaceParity +} efi_serial_io_parity_type; + +typedef enum { + DefaultStopBits, + OneStopBit, // 1 stop bit + OneFiveStopBits, // 1.5 stop bits + TwoStopBits // 2 stop bits +} efi_serial_io_stop_bits_type; + +typedef struct efi_serial_io_protocol { + uint64_t Revision; + + efi_status (*Reset) (struct efi_serial_io_protocol* self) EFIAPI; + efi_status (*SetAttributes) (struct efi_serial_io_protocol* self, + uint64_t baud_rate, uint32_t receive_fifo_depth, uint32_t timeout, + efi_serial_io_parity_type parity, uint8_t data_bits, efi_serial_io_stop_bits_type stop_bits) + EFIAPI; + efi_status (*SetControl) (struct efi_serial_io_protocol* self, + uint32_t control) EFIAPI; + efi_status (*GetControl) (struct efi_serial_io_protocol* self, + uint32_t *control) EFIAPI; + efi_status (*Write) (struct efi_serial_io_protocol* self, + size_t *bufferSize, void *buffer) EFIAPI; + efi_status (*Read) (struct efi_serial_io_protocol* self, + size_t *bufferSize, void *buffer) EFIAPI; + efi_serial_io_mode *Mode; +} efi_serial_io_protocol; diff --git a/xefi/efi/protocol/simple-file-system.h b/xefi/efi/protocol/simple-file-system.h new file mode 100644 index 0000000..ad7c42a --- /dev/null +++ b/xefi/efi/protocol/simple-file-system.h @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ + {0x0964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +extern efi_guid SimpleFileSystemProtocol; + +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION 0x00010000 + +typedef struct efi_simple_file_system_protocol { + uint64_t Revision; + + efi_status (*OpenVolume) (struct efi_simple_file_system_protocol* self, + efi_file_protocol** root) EFIAPI; +} efi_simple_file_system_protocol; diff --git a/xefi/efi/protocol/simple-network.h b/xefi/efi/protocol/simple-network.h new file mode 100644 index 0000000..745bf41 --- /dev/null +++ b/xefi/efi/protocol/simple-network.h @@ -0,0 +1,132 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#define EFI_SIMPLE_NETWORK_PROTOCOL_GUID \ + {0xa19832b9, 0xac25, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d}} +extern efi_guid SimpleNetworkProtocol; + +#define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION 0x00010000 + +#define MAX_MCAST_FILTER_CNT 16 +typedef struct { + uint32_t State; + uint32_t HwAddressSize; + uint32_t MediaHeaderSize; + uint32_t MaxPacketSize; + uint32_t NvRamSize; + uint32_t NvRamAccessSize; + uint32_t ReceiveFilterMask; + uint32_t ReceiveFilterSetting; + uint32_t MaxMCastFilterCount; + uint32_t MCastFilterCount; + efi_mac_addr MCastFilter[MAX_MCAST_FILTER_CNT]; + efi_mac_addr CurrentAddress; + efi_mac_addr BroadcastAddress; + efi_mac_addr PermanentAddress; + uint8_t IfType; + bool MacAddressChangeable; + bool MultipleTxSupported; + bool MediaPresentSupported; + bool MediaPresent; +} efi_simple_network_mode; + +typedef enum { + EfiSimpleNetworkStopped, + EfiSimpleNetworkStarted, + EfiSimpleNetworkInitialized, + EfiSimpleNetworkMaxState +} efi_simple_network_state; + +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01 +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02 +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10 + +typedef struct { + uint64_t RxTotalFrames; + uint64_t RxGoodFrames; + uint64_t RxUndersizeFrames; + uint64_t RxOversizeFrames; + uint64_t RxDroppedFrames; + uint64_t RxUnicastFrames; + uint64_t RxBroadcastFrames; + uint64_t RxMulticastFrames; + uint64_t RxCrcErrorFrames; + uint64_t RxTotalBytes; + uint64_t TxTotalFrames; + uint64_t TxGoodFrames; + uint64_t TxUndersizeFrames; + uint64_t TxOversizeFrames; + uint64_t TxDroppedFrames; + uint64_t TxUnicastFrames; + uint64_t TxBroadcastFrames; + uint64_t TxMulticastFrames; + uint64_t TxCrcErrorFrames; + uint64_t TxTotalBytes; + uint64_t Collisions; + uint64_t UnsupportedProtocol; + uint64_t RxDuplicatedFrames; + uint64_t RxDecryptErrorFrames; + uint64_t TxErrorFrames; + uint64_t TxRetryFrames; +} efi_network_statistics; + +#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01 +#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02 +#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04 +#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08 + +typedef struct efi_simple_network_protocol { + uint64_t Revision; + + efi_status (*Start) (struct efi_simple_network_protocol* self) EFIAPI; + + efi_status (*Stop) (struct efi_simple_network_protocol* self) EFIAPI; + + efi_status (*Initialize) (struct efi_simple_network_protocol* self, + size_t extra_rx_buf_size, size_t extra_tx_buf_size) EFIAPI; + + efi_status (*Reset) (struct efi_simple_network_protocol* self, + bool extended_verification) EFIAPI; + + efi_status (*Shutdown) (struct efi_simple_network_protocol* self) EFIAPI; + + efi_status (*ReceiveFilters) (struct efi_simple_network_protocol* self, + uint32_t enable, uint32_t disable, + bool reset_mcast_filter, size_t mcast_filter_count, + efi_mac_addr* mcast_filter) EFIAPI; + + efi_status (*StationAddress) (struct efi_simple_network_protocol* self, + bool reset, efi_mac_addr* new_addr) EFIAPI; + + efi_status (*Statistics) (struct efi_simple_network_protocol* self, + bool reset, size_t* stats_size, + efi_network_statistics* stats_table) EFIAPI; + + efi_status (*MCastIpToMac) (struct efi_simple_network_protocol* self, + bool ipv6, efi_ip_addr* ip, efi_mac_addr* mac) EFIAPI; + + efi_status (*NvData) (struct efi_simple_network_protocol* self, + bool read_write, size_t offset, size_t buf_size, void* buf) EFIAPI; + + efi_status (*GetStatus) (struct efi_simple_network_protocol* self, + uint32_t* interrupt_status, void** tx_buf) EFIAPI; + + efi_status (*Transmit) (struct efi_simple_network_protocol* self, + size_t header_size, size_t buf_size, void* buf, + efi_mac_addr* src, efi_mac_addr* dest, uint16_t* protocol) EFIAPI; + + efi_status (*Receive) (struct efi_simple_network_protocol* self, + size_t* header_size, size_t* buf_size, void* buf, + efi_mac_addr* src, efi_mac_addr* dest, uint16_t* protocol) EFIAPI; + + efi_event WaitForPacket; + efi_simple_network_mode* Mode; +} efi_simple_network_protocol; diff --git a/xefi/efi/protocol/simple-text-input.h b/xefi/efi/protocol/simple-text-input.h new file mode 100644 index 0000000..ee6bf68 --- /dev/null +++ b/xefi/efi/protocol/simple-text-input.h @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \ + {0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +extern efi_guid SimpleTextInputProtocol; + +typedef struct { + uint16_t ScanCode; + char16_t UnicodeChar; +} efi_input_key; + +typedef struct efi_simple_text_input_protocol { + efi_status (*Reset) (struct efi_simple_text_input_protocol* self, + bool extendend_verification) EFIAPI; + + efi_status (*ReadKeyStroke) (struct efi_simple_text_input_protocol* self, + efi_input_key* key) EFIAPI; + + efi_event WaitForKey; +} efi_simple_text_input_protocol; diff --git a/xefi/efi/protocol/simple-text-output.h b/xefi/efi/protocol/simple-text-output.h new file mode 100644 index 0000000..6ff0816 --- /dev/null +++ b/xefi/efi/protocol/simple-text-output.h @@ -0,0 +1,143 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \ + {0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +extern efi_guid SimpleTextOutputProtocol; + +typedef struct { + int32_t MaxMode; + int32_t Mode; + int32_t Attribute; + int32_t CursorColumn; + int32_t CursorRow; + bool CursorVisible; +} simple_text_output_mode; + +//******************************************************* +// UNICODE DRAWING CHARACTERS +//******************************************************* +#define BOXDRAW_HORIZONTAL 0x2500 +#define BOXDRAW_VERTICAL 0x2502 +#define BOXDRAW_DOWN_RIGHT 0x250c +#define BOXDRAW_DOWN_LEFT 0x2510 +#define BOXDRAW_UP_RIGHT 0x2514 +#define BOXDRAW_UP_LEFT 0x2518 +#define BOXDRAW_VERTICAL_RIGHT 0x251c +#define BOXDRAW_VERTICAL_LEFT 0x2524 +#define BOXDRAW_DOWN_HORIZONTAL 0x252c +#define BOXDRAW_UP_HORIZONTAL 0x2534 +#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c +#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550 +#define BOXDRAW_DOUBLE_VERTICAL 0x2551 +#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552 +#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553 +#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554 +#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555 +#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556 +#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557 +#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558 +#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559 +#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a +#define BOXDRAW_UP_LEFT_DOUBLE 0x255b +#define BOXDRAW_UP_DOUBLE_LEFT 0x255c +#define BOXDRAW_DOUBLE_UP_LEFT 0x255d +#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e +#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f +#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560 +#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561 +#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562 +#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563 +#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564 +#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565 +#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566 +#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567 +#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568 +#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569 +#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a +#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b +#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c + +//******************************************************* +// EFI Required Block Elements Code Chart +//******************************************************* +#define BLOCKELEMENT_FULL_BLOCK 0x2588 +#define BLOCKELEMENT_LIGHT_SHADE 0x2591 + +//******************************************************* +// EFI Required Geometric Shapes Code Chart +//******************************************************* +#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2 +#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba +#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc +#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4 + +//******************************************************* +// EFI Required Arrow shapes +//******************************************************* +#define ARROW_UP 0x2191 +#define ARROW_DOWN 0x2193 + +//******************************************************* +// Attributes +//******************************************************* +#define EFI_BLACK 0x00 +#define EFI_BLUE 0x01 +#define EFI_GREEN 0x02 +#define EFI_CYAN 0x03 +#define EFI_RED 0x04 +#define EFI_ZIRCON 0x05 +#define EFI_BROWN 0x06 +#define EFI_LIGHTGRAY 0x07 +#define EFI_BRIGHT 0x08 +#define EFI_DARKGRAY 0x08 +#define EFI_LIGHTBLUE 0x09 +#define EFI_LIGHTGREEN 0x0A +#define EFI_LIGHTCYAN 0x0B +#define EFI_LIGHTRED 0x0C +#define EFI_LIGHTZIRCON 0x0D +#define EFI_YELLOW 0x0E +#define EFI_WHITE 0x0F +#define EFI_BACKGROUND_BLACK 0x00 +#define EFI_BACKGROUND_BLUE 0x10 +#define EFI_BACKGROUND_GREEN 0x20 +#define EFI_BACKGROUND_CYAN 0x30 +#define EFI_BACKGROUND_RED 0x40 +#define EFI_BACKGROUND_ZIRCON 0x50 +#define EFI_BACKGROUND_BROWN 0x60 +#define EFI_BACKGROUND_LIGHTGRAY 0x70 + +typedef struct efi_simple_text_output_protocol { + efi_status (*Reset) (struct efi_simple_text_output_protocol* self, + bool extended_verification) EFIAPI; + + efi_status (*OutputString) (struct efi_simple_text_output_protocol* self, + char16_t* string) EFIAPI; + + efi_status (*TestString) (struct efi_simple_text_output_protocol* self, + char16_t* string) EFIAPI; + + efi_status (*QueryMode) (struct efi_simple_text_output_protocol* self, + size_t mode_num, size_t* cols, size_t* rows) EFIAPI; + + efi_status (*SetMode) (struct efi_simple_text_output_protocol* self, + size_t mode_num) EFIAPI; + + efi_status (*SetAttribute) (struct efi_simple_text_output_protocol* self, + size_t attribute) EFIAPI; + + efi_status (*ClearScreen) (struct efi_simple_text_output_protocol* self) EFIAPI; + + efi_status (*SetCursorPosition) (struct efi_simple_text_output_protocol* self, + size_t col, size_t row) EFIAPI; + + efi_status (*EnableCursor) (struct efi_simple_text_output_protocol* self, + bool visible) EFIAPI; + + simple_text_output_mode* Mode; +} efi_simple_text_output_protocol; diff --git a/xefi/efi/protocol/usb-io.h b/xefi/efi/protocol/usb-io.h new file mode 100644 index 0000000..721ce92 --- /dev/null +++ b/xefi/efi/protocol/usb-io.h @@ -0,0 +1,147 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#define EFI_USB_IO_PROTOCOL_GUID \ + {0x2b2f68d6, 0x0cd2, 0x44cf, {0x8e, 0x8b, 0xbb, 0xa2, 0x0b, 0x1b, 0x5b, 0x75}} +extern efi_guid UsbIoProtocol; + +typedef enum { + EfiUsbDataIn, + EfiUsbDataOut, + EfiUsbNoData +} efi_usb_data_direction; + +#define EFI_USB_NOERROR 0x0000 +#define EFI_USB_ERR_NOTEXECUTE 0x0001 +#define EFI_USB_ERR_STALL 0x0002 +#define EFI_USB_ERR_BUFFER 0x0004 +#define EFI_USB_ERR_BABBLE 0x0008 +#define EFI_USB_ERR_NAK 0x0010 +#define EFI_USB_ERR_CRC 0x0020 +#define EFI_USB_ERR_TIMEOUT 0x0040 +#define EFI_USB_ERR_BITSTUFF 0x0080 +#define EFI_USB_ERR_SYSTEM 0x0100 + +typedef struct { + uint8_t RequestType; + uint8_t Request; + uint16_t Value; + uint16_t Index; + uint16_t Length; +} efi_usb_device_request; + +typedef efi_status (*efi_async_usb_transfer_callback) ( + void* Data, size_t DataLength, void* Context, uint32_t Status) EFIAPI; + +typedef struct { + uint8_t Length; + uint8_t DescriptorType; + uint16_t BcdUSB; + uint8_t DeviceClass; + uint8_t DeviceSubClass; + uint8_t DeviceProtocol; + uint8_t MaxPacketSize0; + uint16_t IdVendor; + uint16_t IdProduct; + uint16_t BcdDevice; + uint8_t StrManufacturer; + uint8_t StrProduct; + uint8_t StrSerialNumber; + uint8_t NumConfigurations; +} efi_usb_device_descriptor; + +typedef struct { + uint8_t Length; + uint8_t DescriptorType; + uint16_t TotalLength; + uint8_t NumInterfaces; + uint8_t ConfigurationValue; + uint8_t Configuration; + uint8_t Attributes; + uint8_t MaxPower; +} efi_usb_config_descriptor; + +typedef struct { + uint8_t Length; + uint8_t DescriptorType; + uint8_t InterfaceNumber; + uint8_t AlternateSetting; + uint8_t NumEndpoints; + uint8_t InterfaceClass; + uint8_t InterfaceSubClass; + uint8_t InterfaceProtocol; + uint8_t Interface; +} efi_usb_interface_descriptor; + +typedef struct { + uint8_t Length; + uint8_t DescriptorType; + uint8_t EndpointAddress; + uint8_t Attributes; + uint16_t MaxPacketSize; + uint8_t Interval; +} efi_usb_endpoint_descriptor; + +typedef struct efi_usb_io_protocol { + efi_status (*UsbControlTransfer) (struct efi_usb_io_protocol* self, + efi_usb_device_request* request, + efi_usb_data_direction direction, + uint32_t timeout, void* data, + size_t data_len, uint32_t* status) EFIAPI; + + efi_status (*UsbBulkTransfer) (struct efi_usb_io_protocol* self, + uint8_t endpoint, void* data, + size_t data_len, size_t timeout, + uint32_t* status) EFIAPI; + + efi_status (*UsbAsyncInterruptTransfer) (struct efi_usb_io_protocol* self, + uint8_t endpoint, bool is_new_transfer, + size_t polling_interval, + size_t data_len, + efi_async_usb_transfer_callback interrupt_cb, + void* context) EFIAPI; + + efi_status (*UsbSyncInterruptTransfer) (struct efi_usb_io_protocol* self, + uint8_t endpoint, void* data, + size_t* data_len, size_t timeout, + uint32_t* status) EFIAPI; + + efi_status (*UsbIsochronousTransfer) (struct efi_usb_io_protocol* self, + uint8_t endpoint, + void* data, size_t data_len, + uint32_t* status) EFIAPI; + + efi_status (*UsbAsyncIsochronousTransfer) (struct efi_usb_io_protocol* self, + uint8_t endpoint, + void* data, size_t data_len, + efi_async_usb_transfer_callback isoc_cb, + void* context) EFIAPI; + + efi_status (*UsbGetDeviceDescriptor) (struct efi_usb_io_protocol* self, + efi_usb_device_descriptor* descriptor) EFIAPI; + + efi_status (*UsbGetConfigDescriptor) (struct efi_usb_io_protocol* self, + efi_usb_config_descriptor* descriptor) EFIAPI; + + efi_status (*UsbGetInterfaceDescriptor) (struct efi_usb_io_protocol* self, + efi_usb_interface_descriptor* descriptor) EFIAPI; + + efi_status (*UsbGetEndpointDescriptor) (struct efi_usb_io_protocol* self, + uint8_t endpt_index, + efi_usb_endpoint_descriptor* descriptor) EFIAPI; + + efi_status (*UsbGetStringDescriptor) (struct efi_usb_io_protocol* self, + uint16_t langid, uint8_t stringid, + char16_t** str) EFIAPI; + + efi_status (*UsbGetSupportedLanguages) (struct efi_usb_io_protocol* self, + uint16_t** langid_table, + uint16_t* table_size) EFIAPI; + + efi_status (*UsbPortReset) (struct efi_usb_io_protocol* self) EFIAPI; +} efi_usb_io_protocol; diff --git a/xefi/efi/runtime-services.h b/xefi/efi/runtime-services.h new file mode 100644 index 0000000..613b34f --- /dev/null +++ b/xefi/efi/runtime-services.h @@ -0,0 +1,151 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552 +#define EFI_RUNTIME_SERVICES_REVISION EFI_SPECIFICATION_VERSION + +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 +#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 +#define EFI_VARIABLE_APPEND_WRITE 0x00000040 + +// TODO: implement the win_certificate structs if we need them +//typedef struct { +// uint64_t MonotonicCount; +// win_certificate_uefi_guid AuthInfo; +//} efi_variable_authentication; +// +//typedef struct { +// efi_time TimeStamp; +// win_certificate_uefi_guid AuthInfo; +//} efi_variable_authentication_2; + +#define EFI_HARDWARE_ERROR_VARIABLE \ + {0x414e6bdd, 0xe47b, 0x47cc, {0xb2, 0x44, 0xbb, 0x61, 0x02, 0x0c, 0xf5, 0x16}} + +typedef struct { + uint16_t Year; + uint8_t Month; + uint8_t Day; + uint8_t Hour; + uint8_t Minute; + uint8_t Second; + uint8_t Pad1; + uint32_t Nanosecond; + int16_t TimeZone; + uint8_t Daylight; + uint8_t Pad2; +} efi_time; + +#define EFI_TIME_ADJUST_DAYLIGHT 0x01 +#define EFI_TIME_IN_DAYLIGHT 0x02 + +#define EFI_UNSPECIFIED_TIMEZONE 0x07FF + +typedef struct { + uint32_t Resolution; + uint32_t Accuracy; + bool SetsToZero; +} efi_time_capabilities; + +#define EFI_OPTIONAL_PTR 0x00000001 + +typedef enum { + EfiResetCold, + EfiResetWarm, + EfiResetShutdown, + EfiResetPlatformSpecific +} efi_reset_type; + +typedef struct { + uint64_t Length; + union { + efi_physical_addr DataBlock; + efi_physical_addr ContinuationPointer; + } Union; +} efi_capsule_block_descriptor; + +typedef struct { + efi_guid CapsuleGuid; + uint32_t HeaderSize; + uint32_t Flags; + uint32_t CapsuleImageSize; +} efi_capsule_header; + +#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 +#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 +#define CAPSULE_FLAGS_INITIATE_RESET 0x00040000 + +#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001 +#define EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION 0x0000000000000002 +#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED 0x0000000000000004 +#define EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED 0x0000000000000008 +#define EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED 0x0000000000000010 +#define EFI_OS_INDICATIONS_START_OS_RECOVERY 0x0000000000000020 +#define EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY 0x0000000000000040 + +#define EFI_CAPSULE_REPORT_GUID \ + {0x39b68c46, 0xf7fb, 0x441b, {0xb6, 0xec, 0x16, 0xb0, 0xf6, 0x98, 0x21, 0xf3}} + +typedef struct { + uint32_t VariableTotalSize; + uint32_t Reserved; + efi_guid CapsuleGuid; + efi_time CapsuleProcessed; + efi_status CapsuleStatus; +} efi_capsule_result_variable_header; + +typedef struct { + efi_table_header Hdr; + + efi_status (*GetTime) (efi_time* time, efi_time_capabilities* capabilities) EFIAPI; + + efi_status (*SetTime) (efi_time* time) EFIAPI; + + efi_status (*GetWakeupTime) (bool* enabled, bool* pending, efi_time* time) EFIAPI; + + efi_status (*SetWakeupTime) (bool enable, efi_time* time) EFIAPI; + + efi_status (*SetVirtualAddressMap) (size_t memory_map_size, size_t desc_size, + uint32_t desc_version, + efi_memory_descriptor* virtual_map) EFIAPI; + + efi_status (*ConvertPointer) (size_t debug_disposition, void** addr) EFIAPI; + + efi_status (*GetVariable) (char16_t* var_name, efi_guid* vendor_guid, + uint32_t* attributes, size_t* data_size, void* data) EFIAPI; + + efi_status (*GetNextVariableName) (size_t* var_name_size, char16_t* var_name, + efi_guid* vendor_guid) EFIAPI; + + efi_status (*SetVariable) (char16_t* var_name, efi_guid* vendor_guid, + uint32_t attributes, size_t data_size, void* data) EFIAPI; + + efi_status (*GetNextHighMonotonicCount) (uint32_t* high_count) EFIAPI; + + efi_status (*ResetSystem) (efi_reset_type reset_type, efi_status reset_status, + size_t data_size, void* reset_data) EFIAPI; + + efi_status (*UpdateCapsule) (efi_capsule_header** capsule_header_array, + size_t capsule_count, + efi_physical_addr scatter_gather_list) EFIAPI; + + efi_status (*QueryCapsuleCapabilities) (efi_capsule_header** capsule_header_array, + size_t capsule_count, + uint64_t* max_capsule_size, + efi_reset_type* reset_type) EFIAPI; + + efi_status (*QueryVariableInfo) (uint32_t attributes, + uint64_t* max_var_storage_size, + uint64_t* remaining_var_storage_size, + uint64_t* max_var_size) EFIAPI; +} efi_runtime_services; diff --git a/xefi/efi/system-table.h b/xefi/efi/system-table.h new file mode 100644 index 0000000..3f145af --- /dev/null +++ b/xefi/efi/system-table.h @@ -0,0 +1,48 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#include +#include +#include +#include +#include + +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 +#define EFI_2_60_SYSTEM_TABLE_REVISION ((2<<16) | (60)) +#define EFI_2_50_SYSTEM_TABLE_REVISION ((2<<16) | (50)) +#define EFI_2_40_SYSTEM_TABLE_REVISION ((2<<16) | (40)) +#define EFI_2_31_SYSTEM_TABLE_REVISION ((2<<16) | (31)) +#define EFI_2_30_SYSTEM_TABLE_REVISION ((2<<16) | (30)) +#define EFI_2_20_SYSTEM_TABLE_REVISION ((2<<16) | (20)) +#define EFI_2_10_SYSTEM_TABLE_REVISION ((2<<16) | (10)) +#define EFI_2_00_SYSTEM_TABLE_REVISION ((2<<16) | (00)) +#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | (10)) +#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | (02)) +#define EFI_SPECIFICATION_VERSION EFI_SYSTEM_TABLE_REVISION +#define EFI_SYSTEM_TABLE_REVISION EFI_2_60_SYSTEM_TABLE_REVISION + +typedef struct { + efi_guid VendorGuid; + void* VendorTable; +} efi_configuration_table; + +typedef struct efi_system_table { + efi_table_header Hdr; + char16_t* FirmwareVendor; + uint32_t FirmwareRevision; + efi_handle ConsoleInHandle; + efi_simple_text_input_protocol* ConIn; + efi_handle ConsoleOutHandle; + efi_simple_text_output_protocol* ConOut; + efi_handle StandardErrorHandle; + efi_simple_text_output_protocol* StdErr; + efi_runtime_services *RuntimeServices; + efi_boot_services* BootServices; + size_t NumberOfTableEntries; + efi_configuration_table *ConfigurationTable; +} efi_system_table; diff --git a/xefi/efi/types.h b/xefi/efi/types.h new file mode 100644 index 0000000..3ccb671 --- /dev/null +++ b/xefi/efi/types.h @@ -0,0 +1,150 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#define EFIAPI __attribute__((ms_abi)) + +#define EFI_ERROR_MASK 0x8000000000000000 +#define EFI_ERR(x) (EFI_ERROR_MASK | x) +#define EFI_ERROR(x) (((int64_t)x) < 0) + +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR EFI_ERR(1) +#define EFI_INVALID_PARAMETER EFI_ERR(2) +#define EFI_UNSUPPORTED EFI_ERR(3) +#define EFI_BAD_BUFFER_SIZE EFI_ERR(4) +#define EFI_BUFFER_TOO_SMALL EFI_ERR(5) +#define EFI_NOT_READY EFI_ERR(6) +#define EFI_DEVICE_ERROR EFI_ERR(7) +#define EFI_WRITE_PROTECTED EFI_ERR(8) +#define EFI_OUT_OF_RESOURCES EFI_ERR(9) +#define EFI_VOLUME_CORRUPTED EFI_ERR(10) +#define EFI_VOLUME_FULL EFI_ERR(11) +#define EFI_NO_MEDIA EFI_ERR(12) +#define EFI_MEDIA_CHANGED EFI_ERR(13) +#define EFI_NOT_FOUND EFI_ERR(14) +#define EFI_ACCESS_DENIED EFI_ERR(15) +#define EFI_NO_RESPONSE EFI_ERR(16) +#define EFI_NO_MAPPING EFI_ERR(17) +#define EFI_TIMEOUT EFI_ERR(18) +#define EFI_NOT_STARTED EFI_ERR(19) +#define EFI_ALREADY_STARTED EFI_ERR(20) +#define EFI_ABORTED EFI_ERR(21) +#define EFI_ICMP_ERROR EFI_ERR(22) +#define EFI_TFTP_ERROR EFI_ERR(23) +#define EFI_PROTOCOL_ERROR EFI_ERR(24) +#define EFI_INCOMPATIBLE_VERSION EFI_ERR(25) +#define EFI_SECURITY_VIOLATION EFI_ERR(26) +#define EFI_CRC_ERROR EFI_ERR(27) +#define EFI_END_OF_MEDIA EFI_ERR(28) +#define EFI_END_OF_FILE EFI_ERR(31) +#define EFI_INVALID_LANGUAGE EFI_ERR(32) +#define EFI_COMPROMISED_DATA EFI_ERR(33) +#define EFI_IP_ADDRESS_CONFLICT EFI_ERR(34) +#define EFI_HTTP_ERROR EFI_ERR(35) + +// TODO: figure out where to put these. They're just mentioned in passing in the +// spec as some of many industry standard GUIDs but not part of the spec itself. +#define ACPI_TABLE_GUID \ + {0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d}} +#define ACPI_20_TABLE_GUID \ + {0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81}} +#define SMBIOS_TABLE_GUID \ + {0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d}} +#define SMBIOS3_TABLE_GUID \ + {0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94}} + +typedef struct { + uint64_t Signature; + uint32_t Revision; + uint32_t HeaderSize; + uint32_t CRC32; + uint32_t Reserved; +} efi_table_header; + +typedef struct efi_guid { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +} efi_guid; + +typedef void* efi_handle; + +typedef size_t efi_status; + +typedef struct { + uint8_t addr[32]; +} efi_mac_addr; + +typedef struct { + uint8_t addr[4]; +} efi_ipv4_addr; + +typedef struct { + uint8_t addr[16]; +} efi_ipv6_addr; + +typedef union { + efi_ipv4_addr v4; + efi_ipv6_addr v6; +} efi_ip_addr; + +// This really belongs in boot-services.h, but causes circular dependencies with +// device-path.h. +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiPersistentMemory, + EfiMaxMemoryType +} efi_memory_type; + +typedef uint64_t efi_physical_addr; +typedef uint64_t efi_virtual_addr; + +typedef void* efi_event; + +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +#define EFI_EVENT_GROUP_EXIT_BOOT_SERVICES \ + {0x27abf055, 0xb1b8, 0x4c26, {0x80, 0x48, 0x74, 0x8f, 0x37, 0xba, 0xa2, 0xdf}} +#define EFI_EVENT_GROUP_VIRTUAL_ADDRESS_CHANGE \ + {0x13fa7698, 0xc831, 0x49c7, {0x87, 0xea, 0x8f, 0x43, 0xfc, 0xc2, 0x51, 0x96}} +#define EFI_EVENT_GROUP_MEMORY_MAP_CHANGE \ + {0x78bee926, 0x692f, 0x48fd, {0x9e, 0xdb, 0x01, 0x42, 0x2e, 0xf0, 0xd7, 0xab}} +#define EFI_EVENT_GROUP_READY_TO_BOOT \ + {0x7ce88fb3, 0x4bd7, 0x4679, {0x87, 0xa8, 0xa8, 0xd8, 0xde, 0xe5, 0x0d, 0x2b}} + +typedef void (*efi_event_notify) (efi_event event, void* ctx) EFIAPI; + +typedef enum { + TimerCancel, + TimerPeriodic, + TimerRelative +} efi_timer_delay; + +#ifndef __cplusplus +typedef unsigned short char16_t; +#endif diff --git a/xefi/guids.c b/xefi/guids.c new file mode 100644 index 0000000..e2b60b5 --- /dev/null +++ b/xefi/guids.c @@ -0,0 +1,38 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +efi_guid BlockIoProtocol = EFI_BLOCK_IO_PROTOCOL_GUID; +efi_guid DevicePathProtocol = EFI_DEVICE_PATH_PROTOCOL_GUID; +efi_guid DevicePathToTextProtocol = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; +efi_guid DiskIoProtocol = EFI_DISK_IO_PROTOCOL_GUID; +efi_guid DriverBindingProtocol = EFI_DRIVER_BINDING_PROTOCOL_GUID; +efi_guid FileInfoGuid = EFI_FILE_INFO_GUID; +efi_guid FileSystemInfoGuid = EFI_FILE_SYSTEM_INFO_GUID; +efi_guid GraphicsOutputProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +efi_guid LoadedImageProtocol = EFI_LOADED_IMAGE_PROTOCOL_GUID; +efi_guid ManagedNetworkProtocol = EFI_MANAGED_NETWORK_PROTOCOL_GUID; +efi_guid PciRootBridgeIoProtocol = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID; +efi_guid SimpleFileSystemProtocol = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +efi_guid SimpleNetworkProtocol = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; +efi_guid SimpleTextInputProtocol = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID; +efi_guid SimpleTextOutputProtocol = EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID; +efi_guid UsbIoProtocol = EFI_USB_IO_PROTOCOL_GUID; +efi_guid SerialIoProtocol = EFI_SERIAL_IO_PROTOCOL_GUID; diff --git a/xefi/loadfile.c b/xefi/loadfile.c new file mode 100644 index 0000000..f8cea30 --- /dev/null +++ b/xefi/loadfile.c @@ -0,0 +1,110 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include +#include "printf.h" + +#ifndef VERBOSE +#define xprintf(...) do {} while (0); +#else +#define xprintf(fmt...) printf(fmt) +#endif + +efi_file_protocol* xefi_open_file(const char16_t* filename) { + efi_loaded_image_protocol* loaded; + efi_status r; + efi_file_protocol* file = NULL; + + r = xefi_open_protocol(gImg, &LoadedImageProtocol, (void**)&loaded); + if (r) { + xprintf("LoadFile: Cannot open LoadedImageProtocol (%s)\n", xefi_strerror(r)); + goto exit0; + } + +#if 0 + printf("Img DeviceHandle='%s'\n", HandleToString(loaded->DeviceHandle)); + printf("Img FilePath='%s'\n", DevicePathToStr(loaded->FilePath)); + printf("Img Base=%lx Size=%lx\n", loaded->ImageBase, loaded->ImageSize); +#endif + + efi_simple_file_system_protocol* sfs; + r = xefi_open_protocol(loaded->DeviceHandle, &SimpleFileSystemProtocol, (void**)&sfs); + if (r) { + xprintf("LoadFile: Cannot open SimpleFileSystemProtocol (%s)\n", xefi_strerror(r)); + goto exit1; + } + + efi_file_protocol* root; + r = sfs->OpenVolume(sfs, &root); + if (r) { + xprintf("LoadFile: Cannot open root volume (%s)\n", xefi_strerror(r)); + goto exit2; + } + + r = root->Open(root, &file, filename, EFI_FILE_MODE_READ, 0); + if (r) { + goto exit3; + } + +exit3: + root->Close(root); +exit2: + xefi_close_protocol(loaded->DeviceHandle, &SimpleFileSystemProtocol); +exit1: + xefi_close_protocol(gImg, &LoadedImageProtocol); +exit0: + return file; +} + +void* xefi_read_file(efi_file_protocol* file, size_t* _sz, size_t front_bytes) { + efi_status r; + size_t pages = 0; + void* data = NULL; + + char buf[512]; + size_t sz = sizeof(buf); + efi_file_info* finfo = (void*)buf; + r = file->GetInfo(file, &FileInfoGuid, &sz, finfo); + if (r) { + xprintf("LoadFile: Cannot get FileInfo (%s)\n", xefi_strerror(r)); + return NULL; + } + + pages = (finfo->FileSize + front_bytes + 4095) / 4096; + r = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages, (efi_physical_addr *)&data); + if (r) { + xprintf("LoadFile: Cannot allocate buffer (%s)\n", xefi_strerror(r)); + return NULL; + } + + sz = finfo->FileSize; + r = file->Read(file, &sz, data + front_bytes); + if (r) { + xprintf("LoadFile: Error reading file (%s)\n", xefi_strerror(r)); + gBS->FreePages((efi_physical_addr)data, pages); + return NULL; + } + if (sz != finfo->FileSize) { + xprintf("LoadFile: Short read\n"); + gBS->FreePages((efi_physical_addr)data, pages); + return NULL; + } + *_sz = finfo->FileSize; + + return data + front_bytes; +} + +void* xefi_load_file(const char16_t* filename, size_t* _sz, + size_t front_bytes) { + efi_file_protocol* file = xefi_open_file(filename); + if (!file) { + return NULL; + } + void* data = xefi_read_file(file, _sz, front_bytes); + file->Close(file); + return data; +} diff --git a/xefi/printf.c b/xefi/printf.c new file mode 100644 index 0000000..1206ccc --- /dev/null +++ b/xefi/printf.c @@ -0,0 +1,367 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include + +#define __NO_INLINE __attribute__((__noinline__)) + +int sprintf(char *str, const char *fmt, ...) +{ + int err; + + va_list ap; + va_start(ap, fmt); + err = vsprintf(str, fmt, ap); + va_end(ap); + + return err; +} + +int snprintf(char *str, size_t len, const char *fmt, ...) +{ + int err; + + va_list ap; + va_start(ap, fmt); + err = vsnprintf(str, len, fmt, ap); + va_end(ap); + + return err; +} + + +#define LONGFLAG 0x00000001 +#define LONGLONGFLAG 0x00000002 +#define HALFFLAG 0x00000004 +#define HALFHALFFLAG 0x00000008 +#define SIZETFLAG 0x00000010 +#define INTMAXFLAG 0x00000020 +#define PTRDIFFFLAG 0x00000040 +#define ALTFLAG 0x00000080 +#define CAPSFLAG 0x00000100 +#define SHOWSIGNFLAG 0x00000200 +#define SIGNEDFLAG 0x00000400 +#define LEFTFORMATFLAG 0x00000800 +#define LEADZEROFLAG 0x00001000 +#define BLANKPOSFLAG 0x00002000 + +__NO_INLINE static char *longlong_to_string(char *buf, unsigned long long n, size_t len, unsigned int flag, char *signchar) +{ + size_t pos = len; + int negative = 0; + + if ((flag & SIGNEDFLAG) && (long long)n < 0) { + negative = 1; + n = -n; + } + + buf[--pos] = 0; + + /* only do the math if the number is >= 10 */ + while (n >= 10) { + int digit = n % 10; + + n /= 10; + + buf[--pos] = digit + '0'; + } + buf[--pos] = n + '0'; + + if (negative) + *signchar = '-'; + else if ((flag & SHOWSIGNFLAG)) + *signchar = '+'; + else if ((flag & BLANKPOSFLAG)) + *signchar = ' '; + else + *signchar = '\0'; + + return &buf[pos]; +} + +static const char hextable[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; +static const char hextable_caps[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +__NO_INLINE static char *longlong_to_hexstring(char *buf, unsigned long long u, size_t len, unsigned int flag) +{ + size_t pos = len; + const char *table = (flag & CAPSFLAG) ? hextable_caps : hextable; + + buf[--pos] = 0; + do { + unsigned int digit = u % 16; + u /= 16; + + buf[--pos] = table[digit]; + } while (u != 0); + + return &buf[pos]; +} + +int vsprintf(char *str, const char *fmt, va_list ap) +{ + return vsnprintf(str, INT_MAX, fmt, ap); +} + +struct _output_args { + char *outstr; + size_t len; + size_t pos; +}; + +static int _vsnprintf_output(const char *str, size_t len, void *state) +{ + struct _output_args *args = state; + + size_t count = 0; + while (count < len) { + if (args->pos < args->len) { + args->outstr[args->pos++] = *str; + } + + str++; + count++; + } + + return count; +} + +int vsnprintf(char *str, size_t len, const char *fmt, va_list ap) +{ + struct _output_args args; + int wlen; + + args.outstr = str; + args.len = len; + args.pos = 0; + + wlen = _printf_engine(&_vsnprintf_output, (void *)&args, fmt, ap); + if (args.pos >= len) + str[len-1] = '\0'; + else + str[wlen] = '\0'; + return wlen; +} + +int _printf_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap) +{ + int err = 0; + char c; + unsigned char uc; + const char *s; + size_t string_len; + unsigned long long n; + void *ptr; + int flags; + unsigned int format_num; + char signchar; + size_t chars_written = 0; + char num_buffer[32]; + +#define OUTPUT_STRING(str, len) do { err = out(str, len, state); if (err < 0) { goto exit; } else { chars_written += err; } } while(0) +#define OUTPUT_CHAR(c) do { char __temp[1] = { c }; OUTPUT_STRING(__temp, 1); } while (0) + + for (;;) { + /* reset the format state */ + flags = 0; + format_num = 0; + signchar = '\0'; + + /* handle regular chars that aren't format related */ + s = fmt; + string_len = 0; + while ((c = *fmt++) != 0) { + if (c == '%') + break; /* we saw a '%', break and start parsing format */ + string_len++; + } + + /* output the string we've accumulated */ + OUTPUT_STRING(s, string_len); + + /* make sure we haven't just hit the end of the string */ + if (c == 0) + break; + +next_format: + /* grab the next format character */ + c = *fmt++; + if (c == 0) + break; + + switch (c) { + case '0'...'9': + if (c == '0' && format_num == 0) + flags |= LEADZEROFLAG; + format_num *= 10; + format_num += c - '0'; + goto next_format; + case '.': + /* XXX for now eat numeric formatting */ + goto next_format; + case '%': + OUTPUT_CHAR('%'); + break; + case 'c': + uc = va_arg(ap, unsigned int); + OUTPUT_CHAR(uc); + break; + case 's': + s = va_arg(ap, const char *); + if (s == 0) + s = ""; + flags &= ~LEADZEROFLAG; /* doesn't make sense for strings */ + goto _output_string; + case '-': + flags |= LEFTFORMATFLAG; + goto next_format; + case '+': + flags |= SHOWSIGNFLAG; + goto next_format; + case ' ': + flags |= BLANKPOSFLAG; + goto next_format; + case '#': + flags |= ALTFLAG; + goto next_format; + case 'l': + if (flags & LONGFLAG) + flags |= LONGLONGFLAG; + flags |= LONGFLAG; + goto next_format; + case 'h': + if (flags & HALFFLAG) + flags |= HALFHALFFLAG; + flags |= HALFFLAG; + goto next_format; + case 'z': + flags |= SIZETFLAG; + goto next_format; + case 'j': + flags |= INTMAXFLAG; + goto next_format; + case 't': + flags |= PTRDIFFFLAG; + goto next_format; + case 'i': + case 'd': + n = (flags & LONGLONGFLAG) ? va_arg(ap, long long) : + (flags & LONGFLAG) ? va_arg(ap, long) : + (flags & HALFHALFFLAG) ? (signed char)va_arg(ap, int) : + (flags & HALFFLAG) ? (short)va_arg(ap, int) : + (flags & SIZETFLAG) ? va_arg(ap, ssize_t) : + (flags & INTMAXFLAG) ? va_arg(ap, intmax_t) : + (flags & PTRDIFFFLAG) ? va_arg(ap, ptrdiff_t) : + va_arg(ap, int); + flags |= SIGNEDFLAG; + s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar); + goto _output_string; + case 'u': + n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) : + (flags & LONGFLAG) ? va_arg(ap, unsigned long) : + (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) : + (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) : + (flags & SIZETFLAG) ? va_arg(ap, size_t) : + (flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) : + (flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) : + va_arg(ap, unsigned int); + s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar); + goto _output_string; + case 'p': + flags |= LONGFLAG | ALTFLAG; + goto hex; + case 'X': + flags |= CAPSFLAG; + /* fallthrough */ +hex: + case 'x': + n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) : + (flags & LONGFLAG) ? va_arg(ap, unsigned long) : + (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) : + (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) : + (flags & SIZETFLAG) ? va_arg(ap, size_t) : + (flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) : + (flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) : + va_arg(ap, unsigned int); + s = longlong_to_hexstring(num_buffer, n, sizeof(num_buffer), flags); + if (flags & ALTFLAG) { + OUTPUT_CHAR('0'); + OUTPUT_CHAR((flags & CAPSFLAG) ? 'X': 'x'); + } + goto _output_string; + case 'n': + ptr = va_arg(ap, void *); + if (flags & LONGLONGFLAG) + *(long long *)ptr = chars_written; + else if (flags & LONGFLAG) + *(long *)ptr = chars_written; + else if (flags & HALFHALFFLAG) + *(signed char *)ptr = chars_written; + else if (flags & HALFFLAG) + *(short *)ptr = chars_written; + else if (flags & SIZETFLAG) + *(size_t *)ptr = chars_written; + else + *(int *)ptr = chars_written; + break; + default: + OUTPUT_CHAR('%'); + OUTPUT_CHAR(c); + break; + } + + /* move on to the next field */ + continue; + + /* shared output code */ +_output_string: + string_len = strlen(s); + + if (flags & LEFTFORMATFLAG) { + /* left justify the text */ + OUTPUT_STRING(s, string_len); + unsigned int written = err; + + /* pad to the right (if necessary) */ + for (; format_num > written; format_num--) + OUTPUT_CHAR(' '); + } else { + /* right justify the text (digits) */ + + /* if we're going to print a sign digit, + it'll chew up one byte of the format size */ + if (signchar != '\0' && format_num > 0) + format_num--; + + /* output the sign char before the leading zeros */ + if (flags & LEADZEROFLAG && signchar != '\0') + OUTPUT_CHAR(signchar); + + /* pad according to the format string */ + for (; format_num > string_len; format_num--) + OUTPUT_CHAR(flags & LEADZEROFLAG ? '0' : ' '); + + /* if not leading zeros, output the sign char just before the number */ + if (!(flags & LEADZEROFLAG) && signchar != '\0') + OUTPUT_CHAR(signchar); + + /* output the string */ + OUTPUT_STRING(s, string_len); + } + continue; + } + +#undef OUTPUT_STRING +#undef OUTPUT_CHAR + +exit: + return (err < 0) ? err : (int)chars_written; +} diff --git a/xefi/stdlib.c b/xefi/stdlib.c new file mode 100644 index 0000000..89a6fe6 --- /dev/null +++ b/xefi/stdlib.c @@ -0,0 +1,36 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include +#include +#include + +#define ATOx(T, fn) \ +T fn(const char* nptr) { \ + while (nptr && isspace(*nptr)) { \ + nptr++; \ + } \ + \ + bool neg = false; \ + if (*nptr == '-') { \ + neg = true; \ + nptr++; \ + } \ + \ + T ret = 0; \ + for (; nptr; nptr++) { \ + if (!isdigit(*nptr)) break; \ + ret = 10*ret + (*nptr - '0'); \ + } \ + \ + if (neg) ret = -ret; \ + return ret; \ +} + + +ATOx(int, atoi) +ATOx(long, atol) +ATOx(long long, atoll) diff --git a/xefi/string.c b/xefi/string.c new file mode 100644 index 0000000..fb5ef06 --- /dev/null +++ b/xefi/string.c @@ -0,0 +1,97 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include + +void* memset(void* _dst, int c, size_t n) { + uint8_t* dst = _dst; + while (n-- > 0) { + *dst++ = c; + } + return _dst; +} + +void* memcpy(void* _dst, const void* _src, size_t n) { + uint8_t* dst = _dst; + const uint8_t* src = _src; + while (n-- > 0) { + *dst++ = *src++; + } + return _dst; +} + +int memcmp(const void* _a, const void* _b, size_t n) { + const uint8_t* a = _a; + const uint8_t* b = _b; + while (n-- > 0) { + int x = *a++ - *b++; + if (x != 0) { + return x; + } + } + return 0; +} + +size_t strlen(const char* s) { + size_t len = 0; + while (*s++) + len++; + return len; +} + +size_t wcslen(const char16_t* s) { + size_t len = 0; + while (*s++) + len++; + return len; +} + +size_t strnlen(const char* s, size_t max) { + size_t len = 0; + while (len < max && *s++) + len++; + return len; +} + +char* strchr(const char* s, int c) { + while (*s != c && *s++) ; + if (*s != c) return 0; + return (char*)s; +} + +char* strcpy(char* dst, const char* src) { + while (*src != 0) { + *dst++ = *src++; + } + return dst; +} + +char* strncpy(char* dst, const char* src, size_t len) { + while (len-- > 0 && *src != 0) { + *dst++ = *src++; + } + return dst; +} + +int strcmp(const char* s1, const char* s2) { + while (*s1 && (*s1 == *s2)) { + s1++; + s2++; + } + return *s1 - *s2; +} + +int strncmp(const char* s1, const char* s2, size_t len) { + while (len-- > 0) { + int diff = *s1 - *s2; + if (diff != 0 || *s1 == '\0') { + return diff; + } + s1++; + s2++; + } + return 0; +} diff --git a/xefi/strings.c b/xefi/strings.c new file mode 100644 index 0000000..f1d07c3 --- /dev/null +++ b/xefi/strings.c @@ -0,0 +1,29 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +int strcasecmp(const char* s1, const char* s2) { + while (1) { + int diff = tolower(*s1) - tolower(*s2); + if (diff != 0 || *s1 == '\0') { + return diff; + } + s1++; + s2++; + } +} + +int strncasecmp(const char* s1, const char* s2, size_t len) { + while (len-- > 0) { + int diff = tolower(*s1) - tolower(*s2); + if (diff != 0 || *s1 == '\0') { + return diff; + } + s1++; + s2++; + } + return 0; +} diff --git a/xefi/xefi.c b/xefi/xefi.c new file mode 100644 index 0000000..7277e7e --- /dev/null +++ b/xefi/xefi.c @@ -0,0 +1,210 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +xefi_global xefi_global_state; + +void xefi_init(efi_handle img, efi_system_table* sys) { + gSys = sys; + gImg = img; + gBS = sys->BootServices; + gConOut = sys->ConOut; +} + +void xefi_init_serial(void) { + efi_loaded_image_protocol* loaded; + + efi_status r = xefi_open_protocol(gImg, &LoadedImageProtocol, (void**)&loaded); + if (r) { + printf("LoadFile: Cannot open LoadedImageProtocol (%s)\n", xefi_strerror(r)); + goto exit0; + } + efi_serial_io_protocol* serial; + r = xefi_open_protocol(loaded->DeviceHandle, &SerialIoProtocol, (void**)&serial); + if (r) { + printf("LoadFile: Cannot open SerialIoProtocol (%s)\n", xefi_strerror(r)); + goto exit1; + } + gSerialOut = serial; +exit1: + xefi_close_protocol(gImg, &LoadedImageProtocol); +exit0: + return; +} + +void xefi_wait_any_key(void) { + efi_simple_text_input_protocol* sii = gSys->ConIn; + efi_input_key key; + while (sii->ReadKeyStroke(sii, &key) != EFI_SUCCESS) + ; +} + +void xefi_fatal(const char* msg, efi_status status) { + printf("\nERROR: %s (%s)\n", msg, xefi_strerror(status)); + xefi_wait_any_key(); + gBS->Exit(gImg, 1, 0, NULL); +} + +char16_t* xefi_devpath_to_str(efi_device_path_protocol* path) { + efi_device_path_to_text_protocol* prot; + efi_status status = gBS->LocateProtocol(&DevicePathToTextProtocol, NULL, (void**)&prot); + if (EFI_ERROR(status)) { + return NULL; + } + return prot->ConvertDevicePathToText(path, false, false); +} + +int xefi_cmp_guid(efi_guid* guid1, efi_guid* guid2) { + return memcmp(guid1, guid2, sizeof(efi_guid)); +} + +char16_t* xefi_handle_to_str(efi_handle h) { + efi_device_path_protocol* path; + efi_status status = gBS->HandleProtocol(h, &DevicePathProtocol, (void*)&path); + if (EFI_ERROR(status)) { + char16_t* err; + status = gBS->AllocatePool(EfiLoaderData, sizeof(L""), (void**)&err); + if (EFI_ERROR(status)) { + return NULL; + } + gBS->CopyMem(err, L"", sizeof(L"")); + return err; + } + char16_t* str = xefi_devpath_to_str(path); + if (str == NULL) { + char16_t* err; + status = gBS->AllocatePool(EfiLoaderData, sizeof(L""), (void**)&err); + if (EFI_ERROR(status)) { + return NULL; + } + gBS->CopyMem(err, L"", sizeof(L"")); + return err; + } + return str; +} + +efi_status xefi_open_protocol(efi_handle h, efi_guid* guid, void** ifc) { + return gBS->OpenProtocol(h, guid, ifc, gImg, NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); +} + +efi_status xefi_close_protocol(efi_handle h, efi_guid* guid) { + return gBS->CloseProtocol(h, guid, gImg, NULL); +} + +const char *xefi_strerror(efi_status status) { + switch (status) { +#define ERR_ENTRY(x) \ + case x: { \ + return #x; \ + } + ERR_ENTRY(EFI_SUCCESS); + ERR_ENTRY(EFI_LOAD_ERROR); + ERR_ENTRY(EFI_INVALID_PARAMETER); + ERR_ENTRY(EFI_UNSUPPORTED); + ERR_ENTRY(EFI_BAD_BUFFER_SIZE); + ERR_ENTRY(EFI_BUFFER_TOO_SMALL); + ERR_ENTRY(EFI_NOT_READY); + ERR_ENTRY(EFI_DEVICE_ERROR); + ERR_ENTRY(EFI_WRITE_PROTECTED); + ERR_ENTRY(EFI_OUT_OF_RESOURCES); + ERR_ENTRY(EFI_VOLUME_CORRUPTED); + ERR_ENTRY(EFI_VOLUME_FULL); + ERR_ENTRY(EFI_NO_MEDIA); + ERR_ENTRY(EFI_MEDIA_CHANGED); + ERR_ENTRY(EFI_NOT_FOUND); + ERR_ENTRY(EFI_ACCESS_DENIED); + ERR_ENTRY(EFI_NO_RESPONSE); + ERR_ENTRY(EFI_NO_MAPPING); + ERR_ENTRY(EFI_TIMEOUT); + ERR_ENTRY(EFI_NOT_STARTED); + ERR_ENTRY(EFI_ALREADY_STARTED); + ERR_ENTRY(EFI_ABORTED); + ERR_ENTRY(EFI_ICMP_ERROR); + ERR_ENTRY(EFI_TFTP_ERROR); + ERR_ENTRY(EFI_PROTOCOL_ERROR); + ERR_ENTRY(EFI_INCOMPATIBLE_VERSION); + ERR_ENTRY(EFI_SECURITY_VIOLATION); + ERR_ENTRY(EFI_CRC_ERROR); + ERR_ENTRY(EFI_END_OF_MEDIA); + ERR_ENTRY(EFI_END_OF_FILE); + ERR_ENTRY(EFI_INVALID_LANGUAGE); + ERR_ENTRY(EFI_COMPROMISED_DATA); + ERR_ENTRY(EFI_IP_ADDRESS_CONFLICT); + ERR_ENTRY(EFI_HTTP_ERROR); +#undef ERR_ENTRY + } + + return ""; +} + +const char16_t* xefi_wstrerror(efi_status status) { + switch (status) { +#define ERR_ENTRY(x) \ + case x: { \ + return L"" #x; \ + } + ERR_ENTRY(EFI_SUCCESS); + ERR_ENTRY(EFI_LOAD_ERROR); + ERR_ENTRY(EFI_INVALID_PARAMETER); + ERR_ENTRY(EFI_UNSUPPORTED); + ERR_ENTRY(EFI_BAD_BUFFER_SIZE); + ERR_ENTRY(EFI_BUFFER_TOO_SMALL); + ERR_ENTRY(EFI_NOT_READY); + ERR_ENTRY(EFI_DEVICE_ERROR); + ERR_ENTRY(EFI_WRITE_PROTECTED); + ERR_ENTRY(EFI_OUT_OF_RESOURCES); + ERR_ENTRY(EFI_VOLUME_CORRUPTED); + ERR_ENTRY(EFI_VOLUME_FULL); + ERR_ENTRY(EFI_NO_MEDIA); + ERR_ENTRY(EFI_MEDIA_CHANGED); + ERR_ENTRY(EFI_NOT_FOUND); + ERR_ENTRY(EFI_ACCESS_DENIED); + ERR_ENTRY(EFI_NO_RESPONSE); + ERR_ENTRY(EFI_NO_MAPPING); + ERR_ENTRY(EFI_TIMEOUT); + ERR_ENTRY(EFI_NOT_STARTED); + ERR_ENTRY(EFI_ALREADY_STARTED); + ERR_ENTRY(EFI_ABORTED); + ERR_ENTRY(EFI_ICMP_ERROR); + ERR_ENTRY(EFI_TFTP_ERROR); + ERR_ENTRY(EFI_PROTOCOL_ERROR); + ERR_ENTRY(EFI_INCOMPATIBLE_VERSION); + ERR_ENTRY(EFI_SECURITY_VIOLATION); + ERR_ENTRY(EFI_CRC_ERROR); + ERR_ENTRY(EFI_END_OF_MEDIA); + ERR_ENTRY(EFI_END_OF_FILE); + ERR_ENTRY(EFI_INVALID_LANGUAGE); + ERR_ENTRY(EFI_COMPROMISED_DATA); + ERR_ENTRY(EFI_IP_ADDRESS_CONFLICT); + ERR_ENTRY(EFI_HTTP_ERROR); +#undef ERR_ENTRY + } + + return L""; +} + +size_t strlen_16(char16_t* str) { + size_t len = 0; + while (*(str + len) != '\0') { + len++; + } + + return len; +} + +void xefi_free(void *data, size_t size) { + size_t pages = (size + 4095) / 4096; + gBS->FreePages((efi_physical_addr)data, pages); +}