summaryrefslogtreecommitdiffstats
path: root/src/arch/ia64
diff options
context:
space:
mode:
authorMichael Brown2005-03-08 19:53:11 +0100
committerMichael Brown2005-03-08 19:53:11 +0100
commit3d6123e69ab879c72ff489afc5bf93ef0b7a94ce (patch)
tree9f3277569153a550fa8d81ebd61bd88f266eb8da /src/arch/ia64
downloadipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.tar.gz
ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.tar.xz
ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.zip
Initial revision
Diffstat (limited to 'src/arch/ia64')
-rw-r--r--src/arch/ia64/Config22
-rw-r--r--src/arch/ia64/Makefile125
-rw-r--r--src/arch/ia64/core/__call.S68
-rw-r--r--src/arch/ia64/core/efi.c1026
-rw-r--r--src/arch/ia64/core/etherboot.lds82
-rw-r--r--src/arch/ia64/core/ia64_timer.c89
-rw-r--r--src/arch/ia64/core/idiv32.S86
-rw-r--r--src/arch/ia64/core/idiv64.S96
-rw-r--r--src/arch/ia64/core/longjmp.S163
-rw-r--r--src/arch/ia64/core/memmove.S244
-rw-r--r--src/arch/ia64/core/memset.S133
-rw-r--r--src/arch/ia64/core/pal.c84
-rw-r--r--src/arch/ia64/core/pci_io.c62
-rw-r--r--src/arch/ia64/core/reloc.S133
-rw-r--r--src/arch/ia64/core/relocate_to.S92
-rw-r--r--src/arch/ia64/core/sal.c278
-rw-r--r--src/arch/ia64/core/setjmp.S173
-rw-r--r--src/arch/ia64/core/start.S28
-rw-r--r--src/arch/ia64/drivers/net/undi_nii.c1079
-rw-r--r--src/arch/ia64/include/bits/byteswap.h36
-rw-r--r--src/arch/ia64/include/bits/cpu.h6
-rw-r--r--src/arch/ia64/include/bits/elf.h11
-rw-r--r--src/arch/ia64/include/bits/endian.h6
-rw-r--r--src/arch/ia64/include/bits/string.h6
-rw-r--r--src/arch/ia64/include/hooks.h12
-rw-r--r--src/arch/ia64/include/io.h228
-rw-r--r--src/arch/ia64/include/latch.h11
-rw-r--r--src/arch/ia64/include/limits.h57
-rw-r--r--src/arch/ia64/include/pal.h11
-rw-r--r--src/arch/ia64/include/sal.h29
-rw-r--r--src/arch/ia64/include/setjmp.h13
-rw-r--r--src/arch/ia64/include/stdint.h16
-rwxr-xr-xsrc/arch/ia64/prefix/apply_efi_prefix.pl63
-rw-r--r--src/arch/ia64/prefix/apply_unnrv2b_prefix.pl198
-rw-r--r--src/arch/ia64/prefix/efi_prefix.S195
-rw-r--r--src/arch/ia64/prefix/efi_prefix.lds91
-rw-r--r--src/arch/ia64/prefix/unnrv2b.S196
-rw-r--r--src/arch/ia64/prefix/unnrv2b.lds28
38 files changed, 5276 insertions, 0 deletions
diff --git a/src/arch/ia64/Config b/src/arch/ia64/Config
new file mode 100644
index 000000000..6b7405f18
--- /dev/null
+++ b/src/arch/ia64/Config
@@ -0,0 +1,22 @@
+# Config for ia64 Etherboot
+#
+# Do not delete the tag OptionDescription and /OptionDescription
+# It is used to automatically generate the documentation.
+#
+# @OptionDescrition@
+#
+# BIOS interface options:
+#
+# -DCONFIG_EFI
+# Compile in support for EFI
+#
+# @/OptionDescription@
+
+CFLAGS+= -DCONSOLE_FIRMWARE
+CFLAGS+= -DCONFIG_EFI
+
+CFLAGS+= -fpic -mconstant-gp -mauto-pic
+ASFLAGS+= -mconstant-gp -mauto-pic
+
+LDFLAGS+= -static -shared -Bsymbolic --warn-multiple-gp --warn-common
+
diff --git a/src/arch/ia64/Makefile b/src/arch/ia64/Makefile
new file mode 100644
index 000000000..42e0b47be
--- /dev/null
+++ b/src/arch/ia64/Makefile
@@ -0,0 +1,125 @@
+ARCH_FORMAT= elf64-ia64-little
+
+LCONFIG+=
+
+
+BUILD_EFIS= $(patsubst %.img, %.efi, $(IMGS)) $(patsubst %.img, %.zefi, $(IMGS))
+
+START= $(BIN)/start.o $(BIN)/reloc.o
+#START+= $(BIN)/efi_main.o
+
+SRCS+= arch/ia64/prefix/efi_prefix.S arch/ia64/prefix/unnrv2b.S
+SRCS+= arch/ia64/core/__call.S
+SRCS+= arch/ia64/core/ia64_timer.c
+SRCS+= arch/ia64/core/idiv32.S
+SRCS+= arch/ia64/core/idiv64.S
+SRCS+= arch/ia64/core/longjmp.S
+SRCS+= arch/ia64/core/memmove.S
+SRCS+= arch/ia64/core/memset.S
+SRCS+= arch/ia64/core/pal.c
+SRCS+= arch/ia64/core/pci_io.c
+SRCS+= arch/ia64/core/reloc.S
+SRCS+= arch/ia64/core/relocate_to.S
+SRCS+= arch/ia64/core/sal.c
+SRCS+= arch/ia64/core/setjmp.S
+SRCS+= arch/ia64/core/start.S
+SRCS+= arch/ia64/core/efi.c
+
+ROMLIMIT:=3276800
+
+include $(BIN)/Roms
+
+# We need allefis because $(IMGS) is not defined until
+# the Makefile fragment "Roms" is read.
+allefis: $(BUILD_EFIS)
+
+
+#BOBJS+= $(BIN)/acpi.o
+BOBJS+= $(BIN)/sal.o $(BIN)/pal.o
+BOBJS+= $(BIN)/efi.o
+BOBJS+= $(BIN)/memset.o $(BIN)/memmove.o
+BOBJS+= $(BIN)/setjmp.o $(BIN)/longjmp.o
+BOBJS+= $(BIN)/relocate_to.o $(BIN)/__call.o
+BOBJS+= $(BIN)/pci_io.o $(BIN)/ia64_timer.o
+BOBJS+= $(BIN)/__divdi3.o $(BIN)/__udivdi3.o $(BIN)/__moddi3.o $(BIN)/__umoddi3.o
+BOBJS+= $(BIN)/__divsi3.o $(BIN)/__udivsi3.o $(BIN)/__modsi3.o $(BIN)/__umodsi3.o
+
+
+# IA64 Division routines
+$(BIN)/__divdi3.o: arch/ia64/core/idiv64.S
+ $(CPP) $(CFLAGS) -DASSEMBLY $< | $(AS) $(ASFLAGS) -o $@
+
+$(BIN)/__udivdi3.o: arch/ia64/core/idiv64.S
+ $(CPP) $(CFLAGS) -DASSEMBLY -DUNSIGNED $< | $(AS) $(ASFLAGS) -o $@
+
+$(BIN)/__moddi3.o: arch/ia64/core/idiv64.S
+ $(CPP) $(CFLAGS) -DASSEMBLY -DMODULO $< | $(AS) $(ASFLAGS) -o $@
+
+$(BIN)/__umoddi3.o: arch/ia64/core/idiv64.S
+ $(CPP) $(CFLAGS) -DASSEMBLY -DUNSIGNED -DMODULO $< | $(AS) $(ASFLAGS) -o $@
+
+$(BIN)/__divsi3.o: arch/ia64/core/idiv32.S
+ $(CPP) $(CFLAGS) -DASSEMBLY $< | $(AS) $(ASFLAGS) -o $@
+
+$(BIN)/__udivsi3.o: arch/ia64/core/idiv32.S
+ $(CPP) $(CFLAGS) -DASSEMBLY -DUNSIGNED $< | $(AS) $(ASFLAGS) -o $@
+
+$(BIN)/__modsi3.o: arch/ia64/core/idiv32.S
+ $(CPP) $(CFLAGS) -DASSEMBLY -DMODULO $< | $(AS) $(ASFLAGS) -o $@
+
+$(BIN)/__umodsi3.o: arch/ia64/core/idiv32.S
+ $(CPP) $(CFLAGS) -DASSEMBLY -DUNSIGNED -DMODULO $< | $(AS) $(ASFLAGS) -o $@
+
+
+
+# Utilities
+$(BIN)/nrv2b: util/nrv2b.c
+ $(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG -DBITSIZE=64 -DENDIAN=0 -o $@ $<
+
+# Pattern Rules
+
+# General for compiling assembly source files
+$(BIN)/%.o: arch/ia64/core/%.c $(MAKEDEPS)
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+$(BIN)/%.o: arch/ia64/prefix/%.S $(MAKEDEPS)
+ $(CPP) $(CFLAGS) -DASSEMBLY $< | $(AS) $(ASFLAGS) -o $@
+
+$(BIN)/%.o: arch/ia64/core/%.S $(MAKEDEPS)
+ $(CPP) $(CFLAGS) -DASSEMBLY $< | $(AS) $(ASFLAGS) -o $@
+
+$(BIN)/%.o: $(BIN)/%.s
+ $(AS) $(ASFLAGS) -o $@ $<
+
+# General rules for bootable images
+
+# Rules for nrv2b compressed images
+$(BIN)/unnrv2b.tmp: $(BIN)/unnrv2b.o arch/ia64/prefix/unnrv2b.lds $(MAKEDEPS)
+ $(LD) -T arch/ia64/prefix/unnrv2b.lds $< -o $@
+
+$(BIN)/unnrv2b: $(BIN)/unnrv2b.tmp $(MAKEDEPS)
+ $(OBJCOPY) -O binary $< $@
+
+$(BIN)/%.zimg: $(BIN)/%.z $(BIN)/unnrv2b arch/ia64/prefix/apply_unnrv2b_prefix.pl $(MAKEDEPS)
+ $(PERL) arch/ia64/prefix/apply_unnrv2b_prefix.pl $(BIN)/unnrv2b $< > $@
+
+# Placeholder; add no extra symbols to %.sym
+$(BIN)/%.zsym: $(BIN)/%.sym $(MAKEDEPS)
+ cp -f $< $@
+
+# rules to generate efi loadable image
+SUFFIXES += efi zefi
+$(BIN)/efi_prefix.tmp: $(BIN)/efi_prefix.o arch/ia64/prefix/efi_prefix.lds $(MAKEDEPS)
+ $(LD) -T arch/ia64/prefix/efi_prefix.lds $< -o $@
+
+$(BIN)/efi_prefix: $(BIN)/efi_prefix.tmp $(MAKEDEPS)
+ $(OBJCOPY) -O binary $< $@
+
+$(BIN)/%.efi: $(BIN)/%.img $(BIN)/%.tmp $(BIN)/efi_prefix arch/ia64/prefix/apply_efi_prefix.pl $(MAKEDEPS)
+ @$(SIZE) $(BIN)/$(*).tmp | (read l1; read d1 d2 bss rest ; echo $$bss )
+ $(PERL) arch/ia64/prefix/apply_efi_prefix.pl $(BIN)/efi_prefix $< `$(SIZE) $(BIN)/$(*).tmp | (read l1; read d1 d2 bss rest ; echo $$bss )` > $@
+
+$(BIN)/%.zefi: $(BIN)/%.zimg $(BIN)/%.tmp $(BIN)/efi_prefix arch/ia64/prefix/apply_efi_prefix.pl $(MAKEDEPS)
+ @$(SIZE) $(BIN)/$(*).tmp | (read l1; read d1 d2 d3 size rest ; echo $$size )
+ $(PERL) arch/ia64/prefix/apply_efi_prefix.pl $(BIN)/efi_prefix $< `$(SIZE) $(BIN)/$(*).tmp | (read l1; read d1 d2 d3 size rest ; echo $$size )` > $@
+
diff --git a/src/arch/ia64/core/__call.S b/src/arch/ia64/core/__call.S
new file mode 100644
index 000000000..a11b82644
--- /dev/null
+++ b/src/arch/ia64/core/__call.S
@@ -0,0 +1,68 @@
+ /* Trampoline for calling outside of etherboot */
+
+ .text
+ .globl __call
+ .proc __call
+__call:
+ alloc loc0=ar.pfs,8,3,8,0 /* in, local, out, rotating */
+ mov loc1=rp
+ mov loc2=gp
+ ld8 r14=[in0],8
+ ;;
+ ld8 gp=[in0]
+ mov r28=in1 /* So we can use stacked pal calling conventions */
+ mov out0=in1
+ mov out1=in2
+ mov out2=in3
+ mov out3=in4
+ mov out4=in5
+ mov out5=in6
+ mov out6=in7
+ mov out7=0 /* So we can work with sal calling conventions */
+
+ mov b6=r14
+ ;;
+ br.call.sptk.few rp=b6
+ ;;
+ rsm psr.i /* disable interrupts */
+ ;;
+ mov gp=loc2
+ mov rp=loc1
+ ;;
+ mov ar.pfs=loc0
+ br.ret.sptk.many rp
+
+ .size __call, . - __call
+ .endp __call
+
+
+ .text
+ .globl pal_call
+ .proc pal_call
+pal_call:
+ alloc loc0 = ar.pfs,4,3,0,0 /* in, local, out, rotating */
+ mov loc1 = rp
+ mov loc2 = gp
+ add r8 = @gprel(pal_entry),gp
+ add r9 = @gprel(pal_ret),gp
+ ;;
+ ld8 r14 = [r8]
+ ;;
+ mov r28 = in0
+ mov r29 = in1
+ mov r30 = in2
+ mov r31 = in3
+ mov b6 = r14
+ mov rp = r9
+ rsm psr.i /* disable interrupts */
+ ;;
+ br.sptk.few b6
+ ;;
+pal_ret:
+ rsm psr.i /* disable interrupts */
+ ;;
+ mov gp=loc2
+ mov rp=loc1
+ ;;
+ mov ar.pfs=loc0
+ br.ret.sptk.many rp
diff --git a/src/arch/ia64/core/efi.c b/src/arch/ia64/core/efi.c
new file mode 100644
index 000000000..97e585fc8
--- /dev/null
+++ b/src/arch/ia64/core/efi.c
@@ -0,0 +1,1026 @@
+#include "efi/efi.h"
+#include "etherboot.h"
+#include "elf.h"
+#include "sal.h"
+#include "pal.h"
+
+#warning "Place a declaration of lookup_efi_nic somewhere useful"
+EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE *lookup_efi_nic(int index);
+
+#warning "Place the declaraction of __call someplace more appropriate\n"
+extern EFI_STATUS __call(void *,...);
+
+/* Keep 16M free in case EFI needs to allocate some memory.
+ * In the worst case this is only 1/8 the memory on an Itanium.
+ */
+#define EFI_RESERVE_LOW_PAGES ((8*1024*1024)/EFI_PAGE_SIZE)
+#define EFI_RESERVE_HIGH_PAGES ((8*1024*1024)/EFI_PAGE_SIZE)
+
+struct console_info {
+ uint16_t num_cols;
+ uint16_t num_rows;
+ uint16_t orig_x;
+ uint16_t orig_y;
+};
+
+struct efi_mem_map {
+ uint64_t map_size;
+ uint64_t map_key;
+ uint64_t descriptor_size;
+ uint32_t descriptor_version;
+ uint32_t pad;
+ EFI_MEMORY_DESCRIPTOR map[64];
+};
+
+struct efi_info {
+ int flags;
+#define READ_SYSTAB 1
+#define READ_FPSWA 2
+#define READ_MEMMAP 4
+#define READ_CONINFO 8
+ EFI_SYSTEM_TABLE *systab;
+ void *fpswa;
+ struct efi_mem_map mem_map;
+ struct console_info coninfo;
+};
+
+
+unsigned long io_base;
+
+/* local globals */
+static struct efi_info efi_info;
+static EFI_HANDLE etherboot_handle;
+static EFI_BOOT_SERVICES *boot_services;
+static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
+static SIMPLE_INPUT_INTERFACE *conin;
+static void *mps_table;
+static void *acpi20_table;
+static void *smbios_table;
+static void *nii_table;
+
+/* local functions */
+
+static EFI_STATUS efi_locate_handle(
+ EFI_LOCATE_SEARCH_TYPE search_type,
+ EFI_GUID *protocol, void *search_key,
+ UINTN *buffer_size, EFI_HANDLE *buffer)
+{
+ if (!boot_services)
+ return EFI_NOT_FOUND;
+ return __call(boot_services->LocateHandle,
+ search_type, protocol, search_key, buffer_size, buffer);
+}
+
+static EFI_STATUS efi_handle_protocol(EFI_HANDLE handle, EFI_GUID *protocol, void **interface)
+{
+ if (!boot_services)
+ return EFI_UNSUPPORTED;
+ return __call(boot_services->HandleProtocol, handle, protocol, interface);
+}
+
+static EFI_STATUS efi_locate_device_path(EFI_GUID *protocol, EFI_DEVICE_PATH **device_path,
+ EFI_HANDLE *device)
+{
+ if (!boot_services)
+ return EFI_NOT_FOUND;
+ return __call(boot_services->LocateDevicePath, protocol, device_path, device);
+}
+
+static EFI_STATUS efi_allocate_pages(EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type,
+ UINTN pages, EFI_PHYSICAL_ADDRESS *memory)
+{
+ if (!boot_services)
+ return EFI_OUT_OF_RESOURCES;
+ return __call(boot_services->AllocatePages,
+ type, memory_type, pages, memory);
+}
+
+static EFI_STATUS efi_free_pages(EFI_PHYSICAL_ADDRESS memory, UINTN pages)
+{
+ if(pages == 0)
+ return EFI_SUCCESS;
+ if (!boot_services)
+ return EFI_INVALID_PARAMETER;
+ return __call(boot_services->FreePages, memory, pages);
+}
+
+static EFI_STATUS efi_get_memory_map(UINTN *map_size, EFI_MEMORY_DESCRIPTOR *map,
+ UINTN *map_key, UINTN *descriptor_size, UINT32 *descriptor_version)
+{
+ if (!boot_services)
+ return EFI_INVALID_PARAMETER;
+ return __call(boot_services->GetMemoryMap,
+ map_size, map, map_key, descriptor_size, descriptor_version);
+}
+
+static EFI_STATUS efi_free_pool(void *buffer)
+{
+ if (!boot_services)
+ return EFI_INVALID_PARAMETER;
+ return __call(boot_services->FreePool, buffer);
+}
+static EFI_STATUS efi_stall(UINTN microseconds)
+{
+ if (!boot_services)
+ return EFI_UNSUPPORTED;
+ return __call(boot_services->Stall, microseconds);
+}
+
+static EFI_STATUS efi_set_watchdog_timer(
+ UINTN timeout, UINT64 watchdog_code, UINTN data_size, CHAR16 *watchdog_data)
+{
+ if (!boot_services)
+ return EFI_UNSUPPORTED;
+ return __call(boot_services->SetWatchdogTimer,
+ timeout, watchdog_code, data_size, watchdog_data);
+}
+
+
+static void efi_exit_boot_services(struct efi_mem_map *map)
+{
+ EFI_STATUS status;
+ if (!boot_services)
+ return;
+ status = __call(boot_services->ExitBootServices,
+ etherboot_handle, map->map_key);
+ if (status != EFI_SUCCESS) {
+ printf("ExitBootServices failed: %lx\n", status);
+ }
+ conout = 0;
+ conin = 0;
+ boot_services = 0;
+}
+
+static void efi_free_memory(struct efi_mem_map *map)
+{
+ EFI_MEMORY_DESCRIPTOR *desc, *tail;
+#define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
+ tail = next_desc(map->map, map->map_size);
+ for(desc = map->map; desc < tail; desc = next_desc(desc, map->descriptor_size)) {
+ EFI_STATUS status;
+ EFI_PHYSICAL_ADDRESS start, end;
+ UINTN pages;
+ int may_free;
+
+ start = desc->PhysicalStart;
+ pages = desc->NumberOfPages;
+ end = start + pages * EFI_PAGE_SIZE;
+
+
+ may_free = 0;
+ /* The only canidates are Loader Code and Data */
+ if ((desc->Type == EfiLoaderData) ||
+ (desc->Type == EfiLoaderCode))
+ may_free = 1;
+
+ /* Don't free anything etherboot lives in */
+ if ((may_free) &&
+ (start < virt_to_phys(_end)) &&
+ (end > virt_to_phys(_text)))
+ may_free = 0;
+
+ /* Continue if it is not memory we want to free */
+ if (!may_free)
+ continue;
+
+ status = efi_free_pages(start, pages);
+ if (status != EFI_SUCCESS) {
+ printf("free_pages: %lx\n", status);
+ }
+ }
+#undef next_desc
+}
+
+static void read_efi_mem_map(struct efi_mem_map *map)
+{
+ EFI_STATUS status;
+ map->map_size = sizeof(map->map);
+ status = efi_get_memory_map(
+ &map->map_size, map->map, &map->map_key,
+ &map->descriptor_size, &map->descriptor_version);
+ if (status != EFI_SUCCESS) {
+ printf("read_efi_mem_map failed: %lx\n", status);
+ map->map_size = 0;
+ }
+ /* map->descriptor_size should only grow larger */
+ /* map->descriptor_version should only increase and retain
+ * a backward compatible format.
+ */
+}
+
+#if 0
+static const char *efi_mem_type_name(uint32_t type)
+{
+ const char *type_name;
+ if (type == EfiReservedMemoryType)
+ type_name = "EfiReservedMemoryType ";
+ else if (type == EfiLoaderCode)
+ type_name = "EfiLoaderCode ";
+ else if (type == EfiLoaderData)
+ type_name = "EfiLoaderData ";
+ else if (type == EfiBootServicesCode)
+ type_name = "EfiBootServicesCode ";
+ else if (type == EfiBootServicesData)
+ type_name = "EfiBootServicesData ";
+ else if (type == EfiRuntimeServicesCode)
+ type_name = "EfiRuntimeServicesCode ";
+ else if (type == EfiRuntimeServicesData)
+ type_name = "EfiRuntimeServicesData ";
+ else if (type == EfiConventionalMemory)
+ type_name = "EfiConventionalMemory ";
+ else if (type == EfiUnusableMemory)
+ type_name = "EfiUnusableMemory ";
+ else if (type == EfiACPIReclaimMemory)
+ type_name = "EfiACPIReclaimMemory ";
+ else if (type == EfiACPIMemoryNVS)
+ type_name = "EfiACPIMemoryNVS ";
+ else if (type == EfiMemoryMappedIO)
+ type_name = "EfiMemoryMappedIO ";
+ else if (type == EfiMemoryMappedIOPortSpace)
+ type_name = "EfiMemoryMappedIOPortSpace";
+ else if (type == EfiPalCode)
+ type_name = "EfiPalCode ";
+ else
+ type_name = "???? ";
+ return type_name;
+}
+
+static void print_efi_mem_map(struct efi_mem_map *map)
+{
+ EFI_MEMORY_DESCRIPTOR *desc, *end;
+#define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
+ end = next_desc(map->map, map->map_size);
+ for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
+ const char *mem_type;
+ unsigned long start, end, virt, virt_end;
+ uint64_t attr;
+ mem_type = efi_mem_type_name(desc->Type);
+ start = desc->PhysicalStart;
+ end = start + desc->NumberOfPages*EFI_PAGE_SIZE;
+ virt = desc->VirtualStart;
+ virt_end = virt + desc->NumberOfPages*EFI_PAGE_SIZE;
+ attr = desc->Attribute;
+ printf( "mem: %hhx %s @ %#lx-%#lx",
+ desc->Type, mem_type, start, end);
+ if (attr & EFI_MEMORY_UC)
+ printf("UC ");
+ if (attr & EFI_MEMORY_WC)
+ printf("WC ");
+ if (attr & EFI_MEMORY_WT)
+ printf("WT ");
+ if (attr & EFI_MEMORY_WB)
+ printf("WB ");
+ if (attr & EFI_MEMORY_UCE)
+ printf("UCE ");
+
+ if (attr & EFI_MEMORY_WP)
+ printf("WP ");
+ if (attr & EFI_MEMORY_RP)
+ printf("RP ");
+ if (attr & EFI_MEMORY_XP)
+ printf("XP ");
+
+ if (attr & EFI_MEMORY_RUNTIME)
+ printf("RUNTIME ");
+
+ printf("\n");
+ }
+#undef next_desc
+}
+#endif
+
+static void efi_allocate_memory(struct efi_mem_map *map)
+{
+ EFI_MEMORY_DESCRIPTOR *desc, *end;
+ unsigned long low_free, high_free;
+
+#define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
+ end = next_desc(map->map, map->map_size);
+ /* Find out how much memory is free */
+ low_free = high_free = 0;
+ for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
+ unsigned long start, middle, end;
+ if (desc->Type != EfiConventionalMemory)
+ continue;
+ start = desc->PhysicalStart;
+ end = desc->PhysicalStart + (desc->NumberOfPages*EFI_PAGE_SIZE);
+ if (start < 0x100000000UL) {
+ if (end > 0x100000000UL) {
+ middle = 0x10000000UL;
+ } else {
+ middle = end;
+ }
+ } else {
+ middle = start;
+ }
+
+ low_free += (middle - start)/EFI_PAGE_SIZE;
+ high_free += (end - middle)/EFI_PAGE_SIZE;
+ }
+ /* O.k. Now allocate all of the conventional memory, reserving only a tiny
+ * fraction for efi.
+ */
+ for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
+ EFI_STATUS status;
+ EFI_PHYSICAL_ADDRESS address;
+ UINTN pages;
+ unsigned long start, middle, end;
+ unsigned long low_pages, high_pages;
+ if (desc->Type != EfiConventionalMemory)
+ continue;
+ start = desc->PhysicalStart;
+ end = desc->PhysicalStart + (desc->NumberOfPages*EFI_PAGE_SIZE);
+ if (start < 0x100000000UL) {
+ if (end > 0x100000000UL) {
+ middle = 0x10000000UL;
+ } else {
+ middle = end;
+ }
+ } else {
+ middle = start;
+ }
+ low_pages = (middle - start)/EFI_PAGE_SIZE;
+ high_pages = (end - middle)/EFI_PAGE_SIZE;
+ if (low_pages && (low_free > EFI_RESERVE_LOW_PAGES)) {
+ address = start;
+ pages = low_pages;
+ if ((low_free - pages) < EFI_RESERVE_LOW_PAGES) {
+ pages = low_free - EFI_RESERVE_LOW_PAGES;
+ }
+ status = efi_allocate_pages(
+ AllocateAddress, EfiLoaderData, pages, &address);
+ if (status != EFI_SUCCESS) {
+ printf("allocate_pages @%lx for %ld pages failed: %ld\n",
+ desc->PhysicalStart, pages, status);
+ }
+ low_free -= pages;
+ }
+ if (high_pages && (high_free > EFI_RESERVE_HIGH_PAGES)) {
+ address = middle;
+ pages = high_pages;
+ if ((high_free - pages) < EFI_RESERVE_HIGH_PAGES) {
+ pages = high_free - EFI_RESERVE_HIGH_PAGES;
+ }
+ status = efi_allocate_pages(
+ AllocateAddress, EfiLoaderData, pages, &address);
+ if (status != EFI_SUCCESS) {
+ printf("allocate_pages @%lx for %ld pages failed: %ld\n",
+ desc->PhysicalStart, pages, status);
+ }
+ high_free -= pages;
+ }
+ }
+#undef next_desc
+}
+
+static void set_io_base(struct efi_mem_map *map)
+{
+ EFI_MEMORY_DESCRIPTOR *desc, *end;
+
+ io_base = ia64_get_kr0(); /* Default to ar.kr0 */
+
+#define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
+ end = next_desc(map->map, map->map_size);
+
+ for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
+ if (desc->Type == EfiMemoryMappedIOPortSpace) {
+ io_base = desc->PhysicalStart;
+ break;
+ }
+ }
+#undef next_desc
+}
+
+#define MAX_EFI_DEVICES 32
+static void efi_stop_nics(void)
+{
+ static EFI_GUID simple_net_protocol = EFI_SIMPLE_NETWORK_PROTOCOL;
+ EFI_SIMPLE_NETWORK *simple;
+ EFI_STATUS status;
+ EFI_HANDLE handles[MAX_EFI_DEVICES];
+ EFI_HANDLE handle;
+ UINTN devices;
+ unsigned i;
+
+ if (!boot_services)
+ return;
+
+ devices = sizeof(handles);
+ status = efi_locate_handle(
+ ByProtocol, &simple_net_protocol, 0, &devices, handles);
+ if (status != EFI_SUCCESS)
+ return;
+ devices /= sizeof(handles[0]);
+ for(i = 0; i < devices; i++) {
+ void *that;
+ handle = handles[i];
+ status = efi_handle_protocol(handle, &simple_net_protocol, &that);
+ if (status != EFI_SUCCESS)
+ continue;
+ simple = that;
+ if ((simple->Mode->State == EfiSimpleNetworkInitialized)) {
+ status = __call(simple->Shutdown, simple);
+ status = __call(simple->Stop, simple);
+ }
+ else if (simple->Mode->State == EfiSimpleNetworkStarted) {
+ status = __call(simple->Stop, simple);
+ }
+ }
+}
+
+static void efi_get_coninfo(struct console_info *info)
+{
+ EFI_STATUS status;
+ UINTN cols, rows;
+
+ /* Initialize with some silly safe values */
+ info->num_cols = 80;
+ info->num_rows = 24;
+ info->orig_x = 0;
+ info->orig_y = 0;
+
+ status = EFI_UNSUPPORTED;
+ if (conout) {
+ status = __call(conout->QueryMode, conout, conout->Mode->Mode, &cols, &rows);
+ if (status) {
+ printf("QueryMode Failed cannout get console parameters: %ld\n", status);
+ } else {
+ info->num_cols = cols;
+ info->num_rows = rows;
+ info->orig_x = conout->Mode->CursorColumn;
+ info->orig_y = conout->Mode->CursorRow;
+ }
+ }
+}
+
+static void *efi_get_fpswa(void)
+{
+ static EFI_GUID fpswa_protocol = FPSWA_PROTOCOL;
+ EFI_STATUS status;
+ EFI_HANDLE fpswa_handle;
+ UINTN devices;
+ void *result;
+
+ /* The FPSWA is the Floating Point Software Assist driver,
+ * to some extent it makes sense but it has one large flaw.
+ * It fails to install an EFI Configuration table, so the
+ * OS does not need assistance from the bootloader to find it.
+ */
+ devices = sizeof(fpswa_handle);
+ status = efi_locate_handle(
+ ByProtocol, &fpswa_protocol, 0, &devices, &fpswa_handle);
+ if (status != EFI_SUCCESS)
+ return 0;
+
+ status = efi_handle_protocol(
+ fpswa_handle, &fpswa_protocol, &result);
+ if (status != EFI_SUCCESS)
+ return 0;
+
+ return result;
+}
+
+
+/* Exported functions */
+
+
+void arch_main(in_call_data_t *data, va_list params)
+{
+ EFI_STATUS status;
+ unsigned char *note, *end;
+
+ /* IA64 doesn't have an in_call() implementation; start.S
+ * passes in this parameter directly on the stack instead of
+ * as part of the in_call_data_t structure or the parameter
+ * list. params is unusable: don't attempt to access it.
+ */
+ struct Elf_Bhdr *ptr = (struct Elf_Bhdr *)data;
+
+ memset(&efi_info, 0, sizeof(efi_info));
+ note = ((char *)bhdr) + sizeof(*bhdr);
+ end = ((char *)bhdr) + bhdr->b_size;
+ if (bhdr->b_signature != 0x0E1FB007) {
+ printf("Bad bhdr(%lx) signature(%x)!\n",
+ (unsigned long) bhdr, bhdr->b_signature);
+ note = end = 0;
+ }
+ while(note < end) {
+ Elf_Nhdr *hdr;
+ unsigned char *n_name, *n_desc, *next;
+ hdr = (Elf_Nhdr *)note;
+ n_name = note + sizeof(*hdr);
+ n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
+ next = n_desc + ((hdr->n_descsz + 3) & ~3);
+ if (next > end)
+ break;
+#if 0
+ printf("n_type: %x n_name(%d): n_desc(%d): \n",
+ hdr->n_type, hdr->n_namesz, hdr->n_descsz);
+#endif
+ if ((hdr->n_namesz == 10) &&
+ (memcmp(n_name, "Etherboot", 10) == 0)) {
+ switch(hdr->n_type) {
+ case EB_IA64_IMAGE_HANDLE:
+ {
+ uint64_t *handlep = (void *)n_desc;
+ etherboot_handle = (EFI_HANDLE)(*handlep);
+ break;
+ }
+ case EB_IA64_SYSTAB:
+ {
+ uint64_t *systabp = (void *)n_desc;
+ efi_info.systab = (void *)(*systabp);
+ efi_info.flags |= READ_SYSTAB;
+ break;
+ }
+ case EB_IA64_FPSWA:
+ {
+ uint64_t*fpswap = (void *)n_desc;
+ efi_info.fpswa = (void *)(*fpswap);
+ efi_info.flags |= READ_FPSWA;
+ break;
+ }
+ case EB_IA64_CONINFO:
+ {
+ struct console_info *coninfop = (void *)n_desc;
+ efi_info.coninfo = *coninfop;
+ efi_info.flags |= READ_CONINFO;
+ break;
+ }
+ case EB_IA64_MEMMAP:
+ {
+ struct efi_mem_map *mem_mapp = (void *)n_desc;
+ efi_info.mem_map = *mem_mapp;
+ efi_info.flags |= READ_MEMMAP;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ note = next;
+ }
+ if (!(efi_info.flags & READ_SYSTAB)) {
+ printf("No EFI systab\n");
+ return;
+ }
+
+ /* If I have an efi memory map assume ExitBootServices has been called.
+ */
+#warning "FIXME see if there is a better test for boot services still being active "
+ printf("FIXME Develop a better test for boot services still being active\n");
+ if (!(efi_info.flags & READ_MEMMAP)) {
+ conout = efi_info.systab->ConOut;
+ conin = efi_info.systab->ConIn;
+ boot_services = efi_info.systab->BootServices;
+ }
+
+ if (!(efi_info.flags & READ_CONINFO)) {
+ efi_info.flags |= READ_CONINFO;
+ efi_get_coninfo(&efi_info.coninfo);
+ }
+ if (!(efi_info.flags & READ_FPSWA)) {
+ efi_info.flags |= READ_FPSWA;
+ efi_info.fpswa = efi_get_fpswa();
+ }
+ if (!(efi_info.flags & READ_MEMMAP)) {
+ efi_info.flags |= READ_MEMMAP;
+ read_efi_mem_map(&efi_info.mem_map);
+ /* Allocate all of the memory efi can spare */
+ efi_allocate_memory(&efi_info.mem_map);
+ /* Now refresh the memory map */
+ read_efi_mem_map(&efi_info.mem_map);
+ }
+ /* Get the io_base for legacy i/o */
+ set_io_base(&efi_info.mem_map);
+
+ /* Attempt to disable the watchdog timer..
+ * Nothing useful can be done if this fails, so ignore the return code.
+ */
+ status = efi_set_watchdog_timer(0, 1, 0, 0);
+
+ /* Shutdown efi network drivers so efi doesn't get too confused */
+ efi_stop_nics();
+
+ if (efi_info.systab) {
+ static const EFI_GUID mps_table_guid = MPS_TABLE_GUID;
+ static const EFI_GUID acpi20_table_guid = ACPI_20_TABLE_GUID;
+ static const EFI_GUID smbios_table_guid = SMBIOS_TABLE_GUID;
+ static const EFI_GUID sal_system_table_guid = SAL_SYSTEM_TABLE_GUID;
+ static const EFI_GUID nii_table_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL;
+ EFI_SYSTEM_TABLE *systab;
+ unsigned i;
+ systab = efi_info.systab;
+ for(i = 0; i < systab->NumberOfTableEntries; i++) {
+ EFI_GUID *guid;
+ void *table = systab->ConfigurationTable[i].VendorTable;
+ guid = &systab->ConfigurationTable[i].VendorGuid;
+
+#if 0
+ printf("GUID: %x-%hx-%hx-%hhx-%hhx-%hhx-%hhx-%hhx-%hhx-%hhx-%hhx Table: %lx\n",
+ guid->Data1, guid->Data2, guid->Data3,
+ guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+ guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7],
+ table);
+#endif
+
+ if (memcmp(guid, &mps_table_guid, 16) == 0) {
+ mps_table = table;
+ }
+ if (memcmp(guid, &acpi20_table_guid, 16) == 0) {
+ acpi20_table = table;
+ }
+ if (memcmp(guid, &smbios_table_guid, 16) == 0) {
+ smbios_table = table;
+ }
+ if (memcmp(guid, &sal_system_table_guid, 16) == 0) {
+ parse_sal_system_table(table);
+ }
+ if (memcmp(guid, &nii_table_guid, 16) == 0) {
+ nii_table = table;
+ }
+ }
+ }
+}
+
+void arch_on_exit(int status __unused)
+{
+ if (!boot_services)
+ return;
+ read_efi_mem_map(&efi_info.mem_map);
+ efi_free_memory(&efi_info.mem_map);
+}
+
+void arch_relocate_to(unsigned long addr)
+{
+ EFI_PHYSICAL_ADDRESS address, end;
+ UINTN pages;
+ EFI_STATUS status;
+
+ if (!boot_services)
+ return;
+
+ /* Find the efi pages where the new etherboot will sit */
+ address = addr & ~(EFI_PAGE_SIZE -1);
+ end = (addr + (_end - _text) + EFI_PAGE_SIZE -1) & ~EFI_PAGE_SIZE;
+ pages = (end - address)/EFI_PAGE_SIZE;
+
+ /* Reallocate the memory for the new copy of etherboot as LoaderCode */
+ status = efi_free_pages(address, pages);
+ if (status != EFI_SUCCESS) {
+ printf("efi_free_pages failed!: %lx\n", status);
+ return;
+ }
+ status = efi_allocate_pages(AllocateAddress, EfiLoaderCode, pages, &address);
+ if (status != EFI_SUCCESS) {
+ printf("efi_allocate_pages failed! %lx\n", status);
+ return;
+ }
+}
+
+
+struct meminfo meminfo;
+void get_memsizes(void)
+{
+ EFI_MEMORY_DESCRIPTOR *desc, *end;
+ struct efi_mem_map *map;
+#define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size)))
+
+ map = &efi_info.mem_map;
+ end = next_desc(map->map, map->map_size);
+
+ meminfo.map_count = 0;
+ for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) {
+ uint64_t start, size, end;
+ unsigned long mem_k;
+
+ start = desc->PhysicalStart;
+ size = desc->NumberOfPages*EFI_PAGE_SIZE;
+ end = start + size;
+
+ if ((desc->Type != EfiLoaderCode) &&
+ (desc->Type != EfiLoaderData)) {
+ continue;
+ }
+
+ meminfo.map[meminfo.map_count].addr = start;
+ meminfo.map[meminfo.map_count].size = size;
+ meminfo.map[meminfo.map_count].type = E820_RAM;
+ meminfo.map_count++;
+
+ end >>= 10;
+ mem_k = end;
+ if (end & 0xFFFFFFFF00000000ULL) {
+ mem_k = 0xFFFFFFFF;
+ }
+ /* Set the base basememsize */
+ if ((mem_k <= 640) && (meminfo.basememsize <= mem_k)) {
+ meminfo.basememsize = mem_k;
+ }
+ /* Set the total memsize */
+ if ((mem_k >= 1024) && (meminfo.memsize <= (mem_k - 1024))) {
+ meminfo.memsize = mem_k - 1024;
+ }
+ if (meminfo.map_count == E820MAX)
+ break;
+ }
+#undef next_desc
+}
+
+
+EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE *lookup_efi_nic(int index)
+{
+ static EFI_GUID protocol = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL;
+ EFI_HANDLE handles[MAX_EFI_DEVICES];
+ EFI_STATUS status;
+ UINTN devices;
+ void *that;
+
+ if (!boot_services)
+ return 0;
+ if (index < 0) {
+ return 0;
+ }
+ devices = sizeof(handles);
+ status = efi_locate_handle(
+ ByProtocol, &protocol, 0, &devices, handles);
+ if (status != EFI_SUCCESS)
+ return 0;
+ devices /= sizeof(handles[0]);
+ if (index >= devices)
+ return 0;
+ status = efi_handle_protocol(handles[index], &protocol, &that);
+ if (status != EFI_SUCCESS)
+ return 0;
+ return that;
+}
+
+#if defined(CONSOLE_FIRMWARE)
+void console_putc(int c)
+{
+ CHAR16 str[2];
+ if (!conout)
+ return;
+ str[0] = c;
+ str[1] = 0;
+ __call(conout->OutputString, conout, str);
+}
+
+static int efi_have_key = 0;
+static int efi_key;
+int console_ischar(void)
+{
+ EFI_STATUS status;
+ EFI_INPUT_KEY new_key;
+ if (!conin)
+ return 0;
+ if (efi_have_key) {
+ return 1;
+ }
+ status = __call(conin->ReadKeyStroke, conin, &new_key);
+ if (status == EFI_SUCCESS) {
+ if ((new_key.UnicodeChar >= 0) && (new_key.UnicodeChar < 0x7f)) {
+ efi_have_key = 1;
+ efi_key = new_key.UnicodeChar;
+ }
+ else if (new_key.ScanCode == 0x17) {
+ efi_have_key = 1;
+ efi_key = K_ESC;
+ }
+ }
+ return efi_have_key;
+}
+
+int console_getc(void)
+{
+ if (efi_have_key) {
+ efi_have_key = 0;
+ }
+
+ return efi_key;
+}
+#endif /* CONSOLE_FIRMWARE */
+
+#define NAME "Etherboot"
+#define FIRMWARE "EFI"
+
+#define SZ(X) ((sizeof(X)+3) & ~3)
+#define CP(D,S) (memcpy(&(D), &(S), sizeof(S)))
+
+
+struct elf_notes {
+ /* CAREFUL this structure is carefully arranged to avoid
+ * alignment problems.
+ */
+ /* The note header */
+ struct Elf_Bhdr hdr;
+
+ /* First the Fixed sized entries that must be well aligned */
+
+ /* Insert a nop record so the next record is 64bit aligned */
+ Elf_Nhdr nf0;
+
+ /* Pointer to bootp data */
+ Elf_Nhdr nf1;
+ char nf1_name[SZ(EB_PARAM_NOTE)];
+ uint64_t nf1_bootp_data;
+
+ /* Pointer to ELF header */
+ Elf_Nhdr nf2;
+ char nf2_name[SZ(EB_PARAM_NOTE)];
+ uint64_t nf2_header;
+
+ /* The EFI systab pointer */
+ Elf_Nhdr nf3;
+ char nf3_name[SZ(EB_PARAM_NOTE)];
+ uint64_t nf3_systab;
+
+ /* The FPSWA pointer */
+ Elf_Nhdr nf4;
+ char nf4_name[SZ(EB_PARAM_NOTE)];
+ uint64_t nf4_fpswa;
+
+ /* The memory map */
+ Elf_Nhdr nf5;
+ char nf5_name[SZ(EB_PARAM_NOTE)];
+ struct efi_mem_map nf5_map;
+
+ /* The console info, silly but elilo passes it... */
+ Elf_Nhdr nf6;
+ char nf6_name[SZ(EB_PARAM_NOTE)];
+ struct console_info nf6_coninfo;
+
+ /* Then the variable sized data string data where alignment does not matter */
+
+ /* The bootloader name */
+ Elf_Nhdr nv1;
+ char nv1_desc[SZ(NAME)];
+ /* The bootloader version */
+ Elf_Nhdr nv2;
+ char nv2_desc[SZ(VERSION)];
+ /* The firmware type */
+ Elf_Nhdr nv3;
+ char nv3_desc[SZ(FIRMWARE)];
+ /* Name of the loaded image */
+ Elf_Nhdr nv4;
+ char nv4_loaded_image[128];
+ /* An empty command line */
+ Elf_Nhdr nv5;
+ char nv5_cmdline[SZ("")];
+};
+
+#define ELF_NOTE_COUNT (6+5)
+
+static struct elf_notes notes;
+struct Elf_Bhdr *prepare_boot_params(void *header)
+{
+ /* Shutdown the boot services */
+ if (boot_services) {
+ efi_get_coninfo(&efi_info.coninfo);
+ read_efi_mem_map(&efi_info.mem_map);
+ efi_exit_boot_services(&efi_info.mem_map);
+ }
+
+ memset(&notes, 0, sizeof(notes));
+ notes.hdr.b_signature = 0x0E1FB007;
+ notes.hdr.b_size = sizeof(notes);
+ notes.hdr.b_checksum = 0;
+ notes.hdr.b_records = ELF_NOTE_COUNT;
+
+ /* Initialize the fixed length entries. */
+
+ /* Align the fixed length entries to a 64bit boundary */
+ notes.nf0.n_namesz = 0;
+ notes.nf0.n_descsz = 0;
+ notes.nf0.n_type = EBN_NOP;
+
+ notes.nf1.n_namesz = sizeof(EB_PARAM_NOTE);
+ notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
+ notes.nf1.n_type = EB_BOOTP_DATA;
+ CP(notes.nf1_name, EB_PARAM_NOTE);
+ notes.nf1_bootp_data = virt_to_phys(BOOTP_DATA_ADDR);
+
+ notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
+ notes.nf2.n_descsz = sizeof(notes.nf2_header);
+ notes.nf2.n_type = EB_HEADER;
+ CP(notes.nf2_name, EB_PARAM_NOTE);
+ notes.nf2_header = virt_to_phys(header);
+
+ notes.nf3.n_namesz = sizeof(EB_PARAM_NOTE);
+ notes.nf3.n_descsz = sizeof(notes.nf3_systab);
+ notes.nf3.n_type = EB_IA64_SYSTAB;
+ CP(notes.nf3_name, EB_PARAM_NOTE);
+ notes.nf3_systab = (unsigned long)efi_info.systab;
+
+ notes.nf4.n_namesz = sizeof(EB_PARAM_NOTE);
+ notes.nf4.n_descsz = sizeof(notes.nf4_fpswa);
+ notes.nf4.n_type = EB_IA64_FPSWA;
+ CP(notes.nf4_name, EB_PARAM_NOTE);
+ notes.nf4_fpswa = (unsigned long)efi_info.fpswa;
+
+ notes.nf5.n_namesz = sizeof(EB_PARAM_NOTE);
+ notes.nf5.n_descsz = sizeof(notes.nf5_map);
+ notes.nf5.n_type = EB_IA64_MEMMAP;
+ CP(notes.nf5_name, EB_PARAM_NOTE);
+ notes.nf5_map = efi_info.mem_map;
+
+ notes.nf6.n_namesz = sizeof(EB_PARAM_NOTE);
+ notes.nf6.n_descsz = sizeof(notes.nf6_coninfo);
+ notes.nf6.n_type = EB_IA64_CONINFO;
+ CP(notes.nf6_name, EB_PARAM_NOTE);
+ notes.nf6_coninfo = efi_info.coninfo;
+
+ /* Initialize the variable length entries */
+ notes.nv1.n_namesz = 0;
+ notes.nv1.n_descsz = sizeof(NAME);
+ notes.nv1.n_type = EBN_BOOTLOADER_NAME;
+ CP(notes.nv1_desc, NAME);
+
+ notes.nv2.n_namesz = 0;
+ notes.nv2.n_descsz = sizeof(VERSION);
+ notes.nv2.n_type = EBN_BOOTLOADER_VERSION;
+ CP(notes.nv2_desc, VERSION);
+
+ notes.nv3.n_namesz = 0;
+ notes.nv3.n_descsz = sizeof(FIRMWARE);
+ notes.nv3.n_type = EBN_FIRMWARE_TYPE;
+ CP(notes.nv3_desc, FIRMWARE);
+
+ /* Attempt to pass the name of the loaded image */
+ notes.nv4.n_namesz = 0;
+ notes.nv4.n_descsz = sizeof(notes.nv4_loaded_image);
+ notes.nv4.n_type = EBN_LOADED_IMAGE;
+ memcpy(&notes.nv4_loaded_image, KERNEL_BUF, sizeof(notes.nv4_loaded_image));
+
+ /* Pass an empty command line for now */
+ notes.nv5.n_namesz = 0;
+ notes.nv5.n_descsz = sizeof("");
+ notes.nv5.n_type = EBN_COMMAND_LINE;
+ CP(notes.nv5_cmdline, "");
+
+ notes.hdr.b_checksum = ipchksum(&notes, sizeof(notes));
+ /* Like UDP invert a 0 checksum to show that a checksum is present */
+ if (notes.hdr.b_checksum == 0) {
+ notes.hdr.b_checksum = 0xffff;
+ }
+
+ return &notes.hdr;
+}
+
+int elf_start(unsigned long machine __unused, unsigned long entry, unsigned long params)
+{
+ struct elf_notes *notes;
+ int result;
+ /* Since we can do both be polite and also pass the linux
+ * ia64_boot_param table.
+ */
+ static struct ia64_boot_param {
+ uint64_t command_line; /* physical address of command line arguments */
+ uint64_t efi_systab; /* physical address of EFI system table */
+ uint64_t efi_memmap; /* physical address of EFI memory map */
+ uint64_t efi_memmap_size; /* size of EFI memory map */
+ uint64_t efi_memdesc_size; /* size of an EFI memory map descriptor */
+ uint32_t efi_memdesc_version; /* memory descriptor version */
+ struct {
+ uint16_t num_cols; /* number of columns on console output device */
+ uint16_t num_rows; /* number of rows on console output device */
+ uint16_t orig_x; /* cursor's x position */
+ uint16_t orig_y; /* cursor's y position */
+ } console_info;
+ uint64_t fpswa; /* physical address of the fpswa interface */
+ uint64_t initrd_start;
+ uint64_t initrd_size;
+ } bp;
+
+ notes = phys_to_virt(params);
+ /* If I don't have notes don't attempt to start the image */
+ if (notes == 0) {
+ return -2;
+ }
+
+ bp.command_line = (unsigned long)&notes->nv5_cmdline;
+ bp.efi_systab = notes->nf3_systab;
+ bp.efi_memmap = (unsigned long)&notes->nf5_map.map;
+ bp.efi_memmap_size = notes->nf5_map.map_size;
+ bp.efi_memdesc_size = notes->nf5_map.descriptor_size;
+ bp.efi_memdesc_version = notes->nf5_map.descriptor_version;
+ bp.console_info.num_cols = notes->nf6_coninfo.num_cols;
+ bp.console_info.num_rows = notes->nf6_coninfo.num_rows;
+ bp.console_info.orig_x = notes->nf6_coninfo.orig_x;
+ bp.console_info.orig_y = notes->nf6_coninfo.orig_y;
+ bp.fpswa = notes->nf4_fpswa;
+ bp.initrd_start = 0;
+ bp.initrd_size = 0;
+
+
+ asm volatile(
+ ";;\n\t"
+ "mov r28=%2\n\t"
+ "mov out0=%3\n\t"
+ "br.call.sptk.few rp=%1\n\t"
+ "mov %0=r8\n\t"
+ : "=r" (result)
+ : "b"(entry), "r"(&bp),"r"(params)
+ );
+ return result;
+}
diff --git a/src/arch/ia64/core/etherboot.lds b/src/arch/ia64/core/etherboot.lds
new file mode 100644
index 000000000..216cce92a
--- /dev/null
+++ b/src/arch/ia64/core/etherboot.lds
@@ -0,0 +1,82 @@
+OUTPUT_FORMAT("elf64-ia64-little")
+
+OUTPUT_ARCH(ia64)
+
+ENTRY(_start)
+SECTIONS {
+ . = 0;
+ __gp = . + 0x200000;
+ _virt_start = .;
+ _text = . ;
+ .text : {
+ /* Start address of etherboot in the virtual address space */
+ *(.text)
+ *(.text.*)
+ _etext = . ;
+
+ _rodata = . ;
+ . = ALIGN(16);
+ *(.rodata)
+ *(.rodata.*)
+ *(.srodata)
+ . = ALIGN(16);
+ pci_drivers = . ;
+ *(.drivers.pci);
+ pci_drivers_end = . ;
+ . = ALIGN(16);
+ isa_drivers = . ;
+ *(.drivers.isa);
+ isa_drivers_end = . ;
+ . = ALIGN(16);
+
+ . = ALIGN(16);
+ _rela = . ;
+ *(.rela.text)
+ *(.rela.rodata)
+ *(.rela.drivers.pci)
+ *(.rela.drivers.isa)
+ *(.rela.drivers.efi)
+ *(.rela.data)
+ *(.rela.sdata)
+ *(.rela.got)
+ _erela = . ;
+ . = ALIGN(16);
+ _erodata = . ;
+ }
+ _rela_size = _erela - _rela ;
+ .data : {
+ _data = . ;
+ *(.data)
+ *(.got.plt)
+ *(.got)
+ *(.sdata)
+ *(.sbss)
+ *(.scommon)
+ *(.data.*)
+ *(.data1)
+ . = ALIGN(16);
+ _edata = . ;
+ }
+ _bss = . ;
+ .bss : {
+ *(.sbss)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _ebss = .;
+ _end = .;
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ *(.hash)
+ *(.dynstr)
+ *(.dynsym)
+ *(.IA_64.unwind)
+ *(.IA_64.unwind_info)
+ *(.IA64_unwind)
+ *(.IA64_unwind_info)
+ *(.dynamic)
+ }
+}
diff --git a/src/arch/ia64/core/ia64_timer.c b/src/arch/ia64/core/ia64_timer.c
new file mode 100644
index 000000000..3115714ab
--- /dev/null
+++ b/src/arch/ia64/core/ia64_timer.c
@@ -0,0 +1,89 @@
+#include "etherboot.h"
+#include "timer.h"
+#include "sal.h"
+#include "pal.h"
+
+static inline unsigned long get_cycles(void)
+{
+ unsigned long result;
+ __asm__ __volatile__(";;mov %0=ar.itc;;" : "=r"(result));
+ return result;
+}
+
+/* ------ Calibrate the TSC -------
+ * Time how long it takes to excute a loop that runs in known time.
+ * And find the convertion needed to get to CLOCK_TICK_RATE
+ */
+
+static unsigned long calibrate_cycles(void)
+{
+ unsigned long platform_ticks_per_second, drift_info;
+ struct pal_freq_ratio itc_ratio;
+ long result;
+ result = sal_freq_base(SAL_FREQ_BASE_PLATFORM, &platform_ticks_per_second, &drift_info);
+ if (result != 0) {
+ printf("sal_freq_base failed: %lx\n",result);
+ exit(1);
+ } else {
+ result = pal_freq_ratios(0,0,&itc_ratio);
+ if (result != 0) {
+ printf("pal_freq_ratios failed: %lx\n", result);
+ exit(1);
+ }
+ }
+ /* Avoid division by zero */
+ if (itc_ratio.den == 0)
+ itc_ratio.den = 1;
+
+ return (platform_ticks_per_second *itc_ratio.num)/(itc_ratio.den*TICKS_PER_SEC);
+}
+
+static unsigned long clocks_per_tick;
+void setup_timers(void)
+{
+ if (!clocks_per_tick) {
+ clocks_per_tick = calibrate_cycles();
+ /* Display the CPU Mhz to easily test if the calibration was bad */
+ printf("ITC %ld Mhz\n", (clocks_per_tick/1000 * TICKS_PER_SEC)/1000);
+ }
+}
+
+unsigned long currticks(void)
+{
+ return get_cycles()/clocks_per_tick;
+}
+
+static unsigned long timer_timeout;
+static int __timer_running(void)
+{
+ return get_cycles() < timer_timeout;
+}
+
+void udelay(unsigned int usecs)
+{
+ unsigned long now;
+ now = get_cycles();
+ timer_timeout = now + usecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000));
+ while(__timer_running());
+}
+void ndelay(unsigned int nsecs)
+{
+ unsigned long now;
+ now = get_cycles();
+ timer_timeout = now + nsecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000*1000));
+ while(__timer_running());
+}
+
+void load_timer2(unsigned int timer2_ticks)
+{
+ unsigned long now;
+ unsigned long clocks;
+ now = get_cycles();
+ clocks = timer2_ticks * ((clocks_per_tick * TICKS_PER_SEC)/CLOCK_TICK_RATE);
+ timer_timeout = now + clocks;
+}
+
+int timer2_running(void)
+{
+ return __timer_running();
+}
diff --git a/src/arch/ia64/core/idiv32.S b/src/arch/ia64/core/idiv32.S
new file mode 100644
index 000000000..283eff0e9
--- /dev/null
+++ b/src/arch/ia64/core/idiv32.S
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 32-bit integer division.
+ *
+ * This code is based on the application note entitled "Divide, Square Root
+ * and Remainder Algorithms for the IA-64 Architecture". This document
+ * is available as Intel document number 248725-002 or via the web at
+ * http://developer.intel.com/software/opensource/numerics/
+ *
+ * For more details on the theory behind these algorithms, see "IA-64
+ * and Elementary Functions" by Peter Markstein; HP Professional Books
+ * (http://www.hp.com/go/retailbooks/)
+ */
+
+#ifdef MODULO
+# define OP mod
+#else
+# define OP div
+#endif
+
+#ifdef UNSIGNED
+# define SGN u
+# define EXTEND zxt4
+# define INT_TO_FP(a,b) fcvt.xuf.s1 a=b
+# define FP_TO_INT(a,b) fcvt.fxu.trunc.s1 a=b
+#else
+# define SGN
+# define EXTEND sxt4
+# define INT_TO_FP(a,b) fcvt.xf a=b
+# define FP_TO_INT(a,b) fcvt.fx.trunc.s1 a=b
+#endif
+
+#define PASTE1(a,b) a##b
+#define PASTE(a,b) PASTE1(a,b)
+#define NAME PASTE(PASTE(__,SGN),PASTE(OP,si3))
+
+ .text
+ .global NAME
+ .proc NAME
+NAME :
+ .regstk 2,0,0,0
+ // Transfer inputs to FP registers.
+ mov r2 = 0xffdd // r2 = -34 + 65535 (fp reg format bias)
+ EXTEND in0 = in0 // in0 = a
+ EXTEND in1 = in1 // in1 = b
+ ;;
+ setf.sig f8 = in0
+ setf.sig f9 = in1
+#ifdef MODULO
+ sub in1 = r0, in1 // in1 = -b
+#endif
+ ;;
+ // Convert the inputs to FP, to avoid FP software-assist faults.
+ INT_TO_FP(f8, f8)
+ INT_TO_FP(f9, f9)
+ ;;
+ setf.exp f7 = r2 // f7 = 2^-34
+ frcpa.s1 f6, p6 = f8, f9 // y0 = frcpa(b)
+ ;;
+(p6) fmpy.s1 f8 = f8, f6 // q0 = a*y0
+(p6) fnma.s1 f6 = f9, f6, f1 // e0 = -b*y0 + 1
+ ;;
+#ifdef MODULO
+ setf.sig f9 = in1 // f9 = -b
+#endif
+(p6) fma.s1 f8 = f6, f8, f8 // q1 = e0*q0 + q0
+(p6) fma.s1 f6 = f6, f6, f7 // e1 = e0*e0 + 2^-34
+ ;;
+#ifdef MODULO
+ setf.sig f7 = in0
+#endif
+(p6) fma.s1 f6 = f6, f8, f8 // q2 = e1*q1 + q1
+ ;;
+ FP_TO_INT(f6, f6) // q = trunc(q2)
+ ;;
+#ifdef MODULO
+ xma.l f6 = f6, f9, f7 // r = q*(-b) + a
+ ;;
+#endif
+ getf.sig r8 = f6 // transfer result to result register
+ br.ret.sptk.many rp
+
+ .size NAME, . - NAME
+ .endp NAME
diff --git a/src/arch/ia64/core/idiv64.S b/src/arch/ia64/core/idiv64.S
new file mode 100644
index 000000000..d989a2f59
--- /dev/null
+++ b/src/arch/ia64/core/idiv64.S
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co
+ * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 64-bit integer division.
+ *
+ * This code is based on the application note entitled "Divide, Square Root
+ * and Remainder Algorithms for the IA-64 Architecture". This document
+ * is available as Intel document number 248725-002 or via the web at
+ * http://developer.intel.com/software/opensource/numerics/
+ *
+ * For more details on the theory behind these algorithms, see "IA-64
+ * and Elementary Functions" by Peter Markstein; HP Professional Books
+ * (http://www.hp.com/go/retailbooks/)
+ */
+
+#ifdef MODULO
+# define OP mod
+#else
+# define OP div
+#endif
+
+#ifdef UNSIGNED
+# define SGN u
+# define INT_TO_FP(a,b) fcvt.xuf.s1 a=b
+# define FP_TO_INT(a,b) fcvt.fxu.trunc.s1 a=b
+#else
+# define SGN
+# define INT_TO_FP(a,b) fcvt.xf a=b
+# define FP_TO_INT(a,b) fcvt.fx.trunc.s1 a=b
+#endif
+
+#define PASTE1(a,b) a##b
+#define PASTE(a,b) PASTE1(a,b)
+#define NAME PASTE(PASTE(__,SGN),PASTE(OP,di3))
+
+ .text
+ .global NAME
+ .proc NAME
+NAME :
+ .prologue
+ .regstk 2,0,0,0
+ // Transfer inputs to FP registers.
+ setf.sig f8 = in0
+ setf.sig f9 = in1
+ ;;
+ .fframe 16
+ .save.f 0x20
+ stf.spill [sp] = f17,-16
+
+ // Convert the inputs to FP, to avoid FP software-assist faults.
+ INT_TO_FP(f8, f8)
+ ;;
+
+ .save.f 0x10
+ stf.spill [sp] = f16
+ .body
+ INT_TO_FP(f9, f9)
+ ;;
+ frcpa.s1 f17, p6 = f8, f9 // y0 = frcpa(b)
+ ;;
+(p6) fmpy.s1 f7 = f8, f17 // q0 = a*y0
+(p6) fnma.s1 f6 = f9, f17, f1 // e0 = -b*y0 + 1
+ ;;
+(p6) fma.s1 f16 = f7, f6, f7 // q1 = q0*e0 + q0
+(p6) fmpy.s1 f7 = f6, f6 // e1 = e0*e0
+ ;;
+#ifdef MODULO
+ sub in1 = r0, in1 // in1 = -b
+#endif
+(p6) fma.s1 f16 = f16, f7, f16 // q2 = q1*e1 + q1
+(p6) fma.s1 f6 = f17, f6, f17 // y1 = y0*e0 + y0
+ ;;
+(p6) fma.s1 f6 = f6, f7, f6 // y2 = y1*e1 + y1
+(p6) fnma.s1 f7 = f9, f16, f8 // r = -b*q2 + a
+ ;;
+#ifdef MODULO
+ setf.sig f8 = in0 // f8 = a
+ setf.sig f9 = in1 // f9 = -b
+#endif
+(p6) fma.s1 f17 = f7, f6, f16 // q3 = r*y2 + q2
+ ;;
+ .restore sp
+ ldf.fill f16 = [sp], 16
+ FP_TO_INT(f17, f17) // q = trunc(q3)
+ ;;
+#ifdef MODULO
+ xma.l f17 = f17, f9, f8 // r = q*(-b) + a
+ ;;
+#endif
+ getf.sig r8 = f17 // transfer result to result register
+ ldf.fill f17 = [sp]
+ br.ret.sptk.many rp
+
+ .size NAME, . - NAME
+ .endp NAME
diff --git a/src/arch/ia64/core/longjmp.S b/src/arch/ia64/core/longjmp.S
new file mode 100644
index 000000000..d5c8e5ab5
--- /dev/null
+++ b/src/arch/ia64/core/longjmp.S
@@ -0,0 +1,163 @@
+/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
+
+ 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.
+
+ Note that __sigsetjmp() did NOT flush the register stack. Instead,
+ we do it here since __longjmp() is usually much less frequently
+ invoked than __sigsetjmp(). The only difficulty is that __sigsetjmp()
+ didn't (and wouldn't be able to) save ar.rnat either. This is a problem
+ because if we're not careful, we could end up loading random NaT bits.
+ There are two cases:
+
+ (i) ar.bsp < ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+ ar.rnat contains the desired bits---preserve ar.rnat
+ across loadrs and write to ar.bspstore
+
+ (ii) ar.bsp >= ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+ The desired ar.rnat is stored in
+ ia64_rse_rnat_addr(jmpbuf.ar_bsp). Load those
+ bits into ar.rnat after setting ar.bspstore. */
+
+
+# define pPos p6 /* is rotate count positive? */
+# define pNeg p7 /* is rotate count negative? */
+
+
+ /* longjmp(__jmp_buf buf, int val) */
+
+ .text
+ .global longjmp
+ .proc longjmp
+longjmp:
+
+ alloc r8=ar.pfs,2,1,0,0
+ mov r27=ar.rsc
+ add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr
+ ;;
+ ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr
+ mov r10=ar.bsp
+ and r11=~0x3,r27 // clear ar.rsc.mode
+ ;;
+ flushrs // flush dirty regs to backing store (must be first in insn grp)
+ ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp
+ sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf
+ ;;
+ ld8 r25=[r2] // r25 <- jmpbuf.ar_unat
+ extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f
+ ;;
+ cmp.lt pNeg,pPos=r8,r0
+ mov r2=in0
+ ;;
+(pPos) mov r16=r8
+(pNeg) add r16=64,r8
+(pPos) sub r17=64,r8
+(pNeg) sub r17=r0,r8
+ ;;
+ mov ar.rsc=r11 // put RSE in enforced lazy mode
+ shr.u r8=r25,r16
+ add r3=8,in0 // r3 <- &jmpbuf.r1
+ shl r9=r25,r17
+ ;;
+ or r25=r8,r9
+ ;;
+ mov r26=ar.rnat
+ mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12)
+ ;;
+ ld8.fill.nta sp=[r2],16 // r12 (sp)
+ ld8.fill.nta gp=[r3],16 // r1 (gp)
+ dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+ ;;
+ ld8.nta r16=[r2],16 // caller's unat
+ ld8.nta r17=[r3],16 // fpsr
+ ;;
+ ld8.fill.nta r4=[r2],16 // r4
+ ld8.fill.nta r5=[r3],16 // r5 (gp)
+ cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp)
+ ;;
+ ld8.fill.nta r6=[r2],16 // r6
+ ld8.fill.nta r7=[r3],16 // r7
+ ;;
+ mov ar.unat=r16 // restore caller's unat
+ mov ar.fpsr=r17 // restore fpsr
+ ;;
+ ld8.nta r16=[r2],16 // b0
+ ld8.nta r17=[r3],16 // b1
+ ;;
+(p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+ mov ar.bspstore=r23 // restore ar.bspstore
+ ;;
+ ld8.nta r18=[r2],16 // b2
+ ld8.nta r19=[r3],16 // b3
+ ;;
+ ld8.nta r20=[r2],16 // b4
+ ld8.nta r21=[r3],16 // b5
+ ;;
+ ld8.nta r11=[r2],16 // ar.pfs
+ ld8.nta r22=[r3],56 // ar.lc
+ ;;
+ ld8.nta r24=[r2],32 // pr
+ mov b0=r16
+ ;;
+ ldf.fill.nta f2=[r2],32
+ ldf.fill.nta f3=[r3],32
+ mov b1=r17
+ ;;
+ ldf.fill.nta f4=[r2],32
+ ldf.fill.nta f5=[r3],32
+ mov b2=r18
+ ;;
+ ldf.fill.nta f16=[r2],32
+ ldf.fill.nta f17=[r3],32
+ mov b3=r19
+ ;;
+ ldf.fill.nta f18=[r2],32
+ ldf.fill.nta f19=[r3],32
+ mov b4=r20
+ ;;
+ ldf.fill.nta f20=[r2],32
+ ldf.fill.nta f21=[r3],32
+ mov b5=r21
+ ;;
+ ldf.fill.nta f22=[r2],32
+ ldf.fill.nta f23=[r3],32
+ mov ar.lc=r22
+ ;;
+ ldf.fill.nta f24=[r2],32
+ ldf.fill.nta f25=[r3],32
+ cmp.eq p8,p9=0,in1
+ ;;
+ ldf.fill.nta f26=[r2],32
+ ldf.fill.nta f27=[r3],32
+ mov ar.pfs=r11
+ ;;
+ ldf.fill.nta f28=[r2],32
+ ldf.fill.nta f29=[r3],32
+ ;;
+ ldf.fill.nta f30=[r2]
+ ldf.fill.nta f31=[r3]
+(p8) mov r8=1
+
+ mov ar.rnat=r26 // restore ar.rnat
+ ;;
+ mov ar.rsc=r27 // restore ar.rsc
+(p9) mov r8=in1
+
+ invala // virt. -> phys. regnum mapping may change
+ mov pr=r24,-1
+ br.ret.sptk.few b0
+ .size longjmp, . - longjmp
+ .endp longjmp
diff --git a/src/arch/ia64/core/memmove.S b/src/arch/ia64/core/memmove.S
new file mode 100644
index 000000000..63e093d9c
--- /dev/null
+++ b/src/arch/ia64/core/memmove.S
@@ -0,0 +1,244 @@
+/* Optimized version of the standard memmove() function.
+ This file is part of the GNU C Library.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ Contributed by Dan Pop <Dan.Pop@cern.ch>.
+
+ 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. */
+
+/* Return: dest
+
+ Inputs:
+ in0: dest
+ in1: src
+ in2: byte count
+
+ The core of the function is the memcpy implementation used in memcpy.S.
+ When bytes have to be copied backwards, only the easy case, when
+ all arguments are multiples of 8, is optimised.
+
+ In this form, it assumes little endian mode. For big endian mode,
+ sh1 must be computed using an extra instruction: sub sh1 = 64, sh1
+ or the UM.be bit should be cleared at the beginning and set at the end. */
+
+
+#define OP_T_THRES 16
+#define OPSIZ 8
+
+#define adest r15
+#define saved_pr r17
+#define saved_lc r18
+#define dest r19
+#define src r20
+#define len r21
+#define asrc r22
+#define tmp2 r23
+#define tmp3 r24
+#define tmp4 r25
+#define ptable r26
+#define ploop56 r27
+#define loopaddr r28
+#define sh1 r29
+#define loopcnt r30
+#define value r31
+
+#define LOOP(shift) \
+ .align 32 ; \
+.loop##shift##: \
+(p[0]) ld8 r[0] = [asrc], 8 ; /* w1 */ \
+(p[MEMLAT+1]) st8 [dest] = value, 8 ; \
+(p[MEMLAT]) shrp value = r[MEMLAT], r[MEMLAT+1], shift ; \
+ nop.b 0 ; \
+ nop.b 0 ; \
+ br.ctop.sptk .loop##shift ; \
+ br.cond.sptk .cpyfew ; /* deal with the remaining bytes */
+
+#define MEMLAT 21
+#define Nrot (((2*MEMLAT+3) + 7) & ~7)
+
+ .text
+ .global memmove, memcpy
+ .proc memove
+memcpy:
+memmove:
+ .prologue
+ alloc r2 = ar.pfs, 3, Nrot - 3, 0, Nrot
+ .rotr r[MEMLAT + 2], q[MEMLAT + 1]
+ .rotp p[MEMLAT + 2]
+ mov ret0 = in0 // return value = dest
+ .save pr, saved_pr
+ mov saved_pr = pr // save the predicate registers
+ .save ar.lc, saved_lc
+ mov saved_lc = ar.lc // save the loop counter
+ .body
+ or tmp3 = in0, in1 ;; // tmp3 = dest | src
+ or tmp3 = tmp3, in2 // tmp3 = dest | src | len
+ mov dest = in0 // dest
+ mov src = in1 // src
+ mov len = in2 // len
+ sub tmp2 = r0, in0 // tmp2 = -dest
+ cmp.eq p6, p0 = in2, r0 // if (len == 0)
+(p6) br.cond.spnt .restore_and_exit;;// return dest;
+ and tmp4 = 7, tmp3 // tmp4 = (dest | src | len) & 7
+ cmp.le p6, p0 = dest, src // if dest <= src it's always safe
+(p6) br.cond.spnt .forward // to copy forward
+ add tmp3 = src, len;;
+ cmp.lt p6, p0 = dest, tmp3 // if dest > src && dest < src + len
+(p6) br.cond.spnt .backward // we have to copy backward
+
+.forward:
+ shr.u loopcnt = len, 4 ;; // loopcnt = len / 16
+ cmp.ne p6, p0 = tmp4, r0 // if ((dest | src | len) & 7 != 0)
+(p6) br.cond.sptk .next // goto next;
+
+// The optimal case, when dest, src and len are all multiples of 8
+
+ and tmp3 = 0xf, len
+ mov pr.rot = 1 << 16 // set rotating predicates
+ mov ar.ec = MEMLAT + 1 ;; // set the epilog counter
+ cmp.ne p6, p0 = tmp3, r0 // do we have to copy an extra word?
+ adds loopcnt = -1, loopcnt;; // --loopcnt
+(p6) ld8 value = [src], 8;;
+(p6) st8 [dest] = value, 8 // copy the "odd" word
+ mov ar.lc = loopcnt // set the loop counter
+ cmp.eq p6, p0 = 8, len
+(p6) br.cond.spnt .restore_and_exit;;// the one-word special case
+ adds adest = 8, dest // set adest one word ahead of dest
+ adds asrc = 8, src ;; // set asrc one word ahead of src
+ nop.b 0 // get the "golden" alignment for
+ nop.b 0 // the next loop
+.l0:
+(p[0]) ld8 r[0] = [src], 16
+(p[0]) ld8 q[0] = [asrc], 16
+(p[MEMLAT]) st8 [dest] = r[MEMLAT], 16
+(p[MEMLAT]) st8 [adest] = q[MEMLAT], 16
+ br.ctop.dptk .l0 ;;
+
+ mov pr = saved_pr, -1 // restore the predicate registers
+ mov ar.lc = saved_lc // restore the loop counter
+ br.ret.sptk.many b0
+.next:
+ cmp.ge p6, p0 = OP_T_THRES, len // is len <= OP_T_THRES
+ and loopcnt = 7, tmp2 // loopcnt = -dest % 8
+(p6) br.cond.spnt .cpyfew // copy byte by byte
+ ;;
+ cmp.eq p6, p0 = loopcnt, r0
+(p6) br.cond.sptk .dest_aligned
+ sub len = len, loopcnt // len -= -dest % 8
+ adds loopcnt = -1, loopcnt // --loopcnt
+ ;;
+ mov ar.lc = loopcnt
+.l1: // copy -dest % 8 bytes
+ ld1 value = [src], 1 // value = *src++
+ ;;
+ st1 [dest] = value, 1 // *dest++ = value
+ br.cloop.dptk .l1
+.dest_aligned:
+ and sh1 = 7, src // sh1 = src % 8
+ and tmp2 = -8, len // tmp2 = len & -OPSIZ
+ and asrc = -8, src // asrc = src & -OPSIZ -- align src
+ shr.u loopcnt = len, 3 // loopcnt = len / 8
+ and len = 7, len;; // len = len % 8
+ adds loopcnt = -1, loopcnt // --loopcnt
+ addl tmp4 = @ltoff(.table), gp
+ addl tmp3 = @ltoff(.loop56), gp
+ mov ar.ec = MEMLAT + 1 // set EC
+ mov pr.rot = 1 << 16;; // set rotating predicates
+ mov ar.lc = loopcnt // set LC
+ cmp.eq p6, p0 = sh1, r0 // is the src aligned?
+(p6) br.cond.sptk .src_aligned
+ add src = src, tmp2 // src += len & -OPSIZ
+ shl sh1 = sh1, 3 // sh1 = 8 * (src % 8)
+ ld8 ploop56 = [tmp3] // ploop56 = &loop56
+ ld8 ptable = [tmp4];; // ptable = &table
+ add tmp3 = ptable, sh1;; // tmp3 = &table + sh1
+ mov ar.ec = MEMLAT + 1 + 1 // one more pass needed
+ ld8 tmp4 = [tmp3];; // tmp4 = loop offset
+ sub loopaddr = ploop56,tmp4 // loopadd = &loop56 - loop offset
+ ld8 r[1] = [asrc], 8;; // w0
+ mov b6 = loopaddr;;
+ br b6 // jump to the appropriate loop
+
+ LOOP(8)
+ LOOP(16)
+ LOOP(24)
+ LOOP(32)
+ LOOP(40)
+ LOOP(48)
+ LOOP(56)
+
+.src_aligned:
+.l3:
+(p[0]) ld8 r[0] = [src], 8
+(p[MEMLAT]) st8 [dest] = r[MEMLAT], 8
+ br.ctop.dptk .l3
+.cpyfew:
+ cmp.eq p6, p0 = len, r0 // is len == 0 ?
+ adds len = -1, len // --len;
+(p6) br.cond.spnt .restore_and_exit ;;
+ mov ar.lc = len
+.l4:
+ ld1 value = [src], 1
+ ;;
+ st1 [dest] = value, 1
+ br.cloop.dptk .l4 ;;
+.restore_and_exit:
+ mov pr = saved_pr, -1 // restore the predicate registers
+ mov ar.lc = saved_lc // restore the loop counter
+ br.ret.sptk.many b0
+
+// In the case of a backward copy, optimise only the case when everything
+// is a multiple of 8, otherwise copy byte by byte. The backward copy is
+// used only when the blocks are overlapping and dest > src.
+
+.backward:
+ shr.u loopcnt = len, 3 // loopcnt = len / 8
+ add src = src, len // src points one byte past the end
+ add dest = dest, len ;; // dest points one byte past the end
+ mov ar.ec = MEMLAT + 1 // set the epilog counter
+ mov pr.rot = 1 << 16 // set rotating predicates
+ adds loopcnt = -1, loopcnt // --loopcnt
+ cmp.ne p6, p0 = tmp4, r0 // if ((dest | src | len) & 7 != 0)
+(p6) br.cond.sptk .bytecopy ;; // copy byte by byte backward
+ adds src = -8, src // src points to the last word
+ adds dest = -8, dest // dest points to the last word
+ mov ar.lc = loopcnt;; // set the loop counter
+.l5:
+(p[0]) ld8 r[0] = [src], -8
+(p[MEMLAT]) st8 [dest] = r[MEMLAT], -8
+ br.ctop.dptk .l5
+ br.cond.sptk .restore_and_exit
+.bytecopy:
+ adds src = -1, src // src points to the last byte
+ adds dest = -1, dest // dest points to the last byte
+ adds loopcnt = -1, len;; // loopcnt = len - 1
+ mov ar.lc = loopcnt;; // set the loop counter
+.l6:
+(p[0]) ld1 r[0] = [src], -1
+(p[MEMLAT]) st1 [dest] = r[MEMLAT], -1
+ br.ctop.dptk .l6
+ br.cond.sptk .restore_and_exit
+.table:
+ data8 0 // dummy entry
+ data8 .loop56 - .loop8
+ data8 .loop56 - .loop16
+ data8 .loop56 - .loop24
+ data8 .loop56 - .loop32
+ data8 .loop56 - .loop40
+ data8 .loop56 - .loop48
+ data8 .loop56 - .loop56
+
+ .size memmove, . - memove
+ .endp memmove
diff --git a/src/arch/ia64/core/memset.S b/src/arch/ia64/core/memset.S
new file mode 100644
index 000000000..a6cc40fcf
--- /dev/null
+++ b/src/arch/ia64/core/memset.S
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * ELILO is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * ELILO 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ELILO; see the file COPYING. If not, write to the Free
+ * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Please check out the elilo.txt for complete documentation on how
+ * to use this program.
+ *
+ * This code is derived from the Linux/ia64 source code.
+ */
+
+/*
+ *
+ * Optimized version of the standard memset() function
+ *
+ * Return: none
+ *
+ * Inputs:
+ * in0: address of buffer
+ * in1: byte value to use for storing
+ * in2: length of the buffer
+ *
+ */
+
+// arguments
+//
+#define buf r32
+#define val r33
+#define len r34
+
+//
+// local registers
+//
+#define saved_pfs r14
+#define cnt r18
+#define buf2 r19
+#define saved_lc r20
+#define tmp r21
+ .text
+ .global memset
+ .proc memset
+memset:
+ .prologue
+ .save ar.pfs, saved_pfs
+ alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here
+ cmp.eq p8,p0=r0,len // check for zero length
+ .save ar.lc, saved_lc
+ mov saved_lc=ar.lc // preserve ar.lc (slow)
+ ;;
+
+ .body
+
+ adds tmp=-1,len // br.ctop is repeat/until
+ tbit.nz p6,p0=buf,0 // odd alignment
+(p8) br.ret.spnt.few rp
+
+ cmp.lt p7,p0=16,len // if len > 16 then long memset
+ mux1 val=val,@brcst // prepare value
+(p7) br.cond.dptk.few long_memset
+ ;;
+ mov ar.lc=tmp // initialize lc for small count
+ ;; // avoid RAW and WAW on ar.lc
+1: // worst case 15 cyles, avg 8 cycles
+ st1 [buf]=val,1
+ br.cloop.dptk.few 1b
+ ;; // avoid RAW on ar.lc
+ mov ar.lc=saved_lc
+ mov ar.pfs=saved_pfs
+ br.ret.sptk.few rp // end of short memset
+
+ // at this point we know we have more than 16 bytes to copy
+ // so we focus on alignment
+long_memset:
+(p6) st1 [buf]=val,1 // 1-byte aligned
+(p6) adds len=-1,len;; // sync because buf is modified
+ tbit.nz p6,p0=buf,1
+ ;;
+(p6) st2 [buf]=val,2 // 2-byte aligned
+(p6) adds len=-2,len;;
+ tbit.nz p6,p0=buf,2
+ ;;
+(p6) st4 [buf]=val,4 // 4-byte aligned
+(p6) adds len=-4,len;;
+ tbit.nz p6,p0=buf,3
+ ;;
+(p6) st8 [buf]=val,8 // 8-byte aligned
+(p6) adds len=-8,len;;
+ shr.u cnt=len,4 // number of 128-bit (2x64bit) words
+ ;;
+ cmp.eq p6,p0=r0,cnt
+ adds tmp=-1,cnt
+(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left
+ ;;
+ adds buf2=8,buf // setup second base pointer
+ mov ar.lc=tmp
+ ;;
+2: // 16bytes/iteration
+ st8 [buf]=val,16
+ st8 [buf2]=val,16
+ br.cloop.dptk.few 2b
+ ;;
+.dotail: // tail correction based on len only
+ tbit.nz p6,p0=len,3
+ ;;
+(p6) st8 [buf]=val,8 // at least 8 bytes
+ tbit.nz p6,p0=len,2
+ ;;
+(p6) st4 [buf]=val,4 // at least 4 bytes
+ tbit.nz p6,p0=len,1
+ ;;
+(p6) st2 [buf]=val,2 // at least 2 bytes
+ tbit.nz p6,p0=len,0
+ mov ar.lc=saved_lc
+ ;;
+(p6) st1 [buf]=val // only 1 byte left
+ br.ret.dptk.few rp
+ .endp memset
diff --git a/src/arch/ia64/core/pal.c b/src/arch/ia64/core/pal.c
new file mode 100644
index 000000000..cfb518d09
--- /dev/null
+++ b/src/arch/ia64/core/pal.c
@@ -0,0 +1,84 @@
+#include "etherboot.h"
+#include "sal.h"
+#include "pal.h"
+
+struct fptr pal_entry;
+/*
+ * Note that some of these calls use a static-register only calling
+ * convention which has nothing to do with the regular calling
+ * convention.
+ */
+#define PAL_CACHE_FLUSH 1 /* flush i/d cache */
+#define PAL_CACHE_INFO 2 /* get detailed i/d cache info */
+#define PAL_CACHE_INIT 3 /* initialize i/d cache */
+#define PAL_CACHE_SUMMARY 4 /* get summary of cache heirarchy */
+#define PAL_MEM_ATTRIB 5 /* list supported memory attributes */
+#define PAL_PTCE_INFO 6 /* purge TLB info */
+#define PAL_VM_INFO 7 /* return supported virtual memory features */
+#define PAL_VM_SUMMARY 8 /* return summary on supported vm features */
+#define PAL_BUS_GET_FEATURES 9 /* return processor bus interface features settings */
+#define PAL_BUS_SET_FEATURES 10 /* set processor bus features */
+#define PAL_DEBUG_INFO 11 /* get number of debug registers */
+#define PAL_FIXED_ADDR 12 /* get fixed component of processors's directed address */
+#define PAL_FREQ_BASE 13 /* base frequency of the platform */
+#define PAL_FREQ_RATIOS 14 /* ratio of processor, bus and ITC frequency */
+#define PAL_PERF_MON_INFO 15 /* return performance monitor info */
+#define PAL_PLATFORM_ADDR 16 /* set processor interrupt block and IO port space addr */
+#define PAL_PROC_GET_FEATURES 17 /* get configurable processor features & settings */
+#define PAL_PROC_SET_FEATURES 18 /* enable/disable configurable processor features */
+#define PAL_RSE_INFO 19 /* return rse information */
+#define PAL_VERSION 20 /* return version of PAL code */
+#define PAL_MC_CLEAR_LOG 21 /* clear all processor log info */
+#define PAL_MC_DRAIN 22 /* drain operations which could result in an MCA */
+#define PAL_MC_EXPECTED 23 /* set/reset expected MCA indicator */
+#define PAL_MC_DYNAMIC_STATE 24 /* get processor dynamic state */
+#define PAL_MC_ERROR_INFO 25 /* get processor MCA info and static state */
+#define PAL_MC_RESUME 26 /* Return to interrupted process */
+#define PAL_MC_REGISTER_MEM 27 /* Register memory for PAL to use during MCAs and inits */
+#define PAL_HALT 28 /* enter the low power HALT state */
+#define PAL_HALT_LIGHT 29 /* enter the low power light halt state*/
+#define PAL_COPY_INFO 30 /* returns info needed to relocate PAL */
+#define PAL_CACHE_LINE_INIT 31 /* init tags & data of cache line */
+#define PAL_PMI_ENTRYPOINT 32 /* register PMI memory entry points with the processor */
+#define PAL_ENTER_IA_32_ENV 33 /* enter IA-32 system environment */
+#define PAL_VM_PAGE_SIZE 34 /* return vm TC and page walker page sizes */
+
+#define PAL_MEM_FOR_TEST 37 /* get amount of memory needed for late processor test */
+#define PAL_CACHE_PROT_INFO 38 /* get i/d cache protection info */
+#define PAL_REGISTER_INFO 39 /* return AR and CR register information*/
+#define PAL_SHUTDOWN 40 /* enter processor shutdown state */
+#define PAL_PREFETCH_VISIBILITY 41
+
+#define PAL_COPY_PAL 256 /* relocate PAL procedures and PAL PMI */
+#define PAL_HALT_INFO 257 /* return the low power capabilities of processor */
+#define PAL_TEST_PROC 258 /* perform late processor self-test */
+#define PAL_CACHE_READ 259 /* read tag & data of cacheline for diagnostic testing */
+#define PAL_CACHE_WRITE 260 /* write tag & data of cacheline for diagnostic testing */
+#define PAL_VM_TR_READ 261 /* read contents of translation register */
+
+
+/*
+ * Get the ratios for processor frequency, bus frequency and interval timer to
+ * to base frequency of the platform
+ */
+long pal_freq_ratios(struct pal_freq_ratio *proc_ratio,
+ struct pal_freq_ratio *bus_ratio, struct pal_freq_ratio *itc_ratio)
+{
+ struct freq_ratios {
+ long status;
+ struct pal_freq_ratio proc_ratio;
+ struct pal_freq_ratio bus_ratio;
+ struct pal_freq_ratio itc_ratio;
+ };
+ struct freq_ratios result;
+ extern struct freq_ratios pal_call(unsigned long which, ...);
+ result = pal_call(PAL_FREQ_RATIOS, 0, 0, 0);
+ if (proc_ratio)
+ *proc_ratio = result.proc_ratio;
+ if (bus_ratio)
+ *bus_ratio = result.bus_ratio;
+ if (itc_ratio)
+ *itc_ratio = result.itc_ratio;
+ return result.status;
+
+}
diff --git a/src/arch/ia64/core/pci_io.c b/src/arch/ia64/core/pci_io.c
new file mode 100644
index 000000000..f8069bb91
--- /dev/null
+++ b/src/arch/ia64/core/pci_io.c
@@ -0,0 +1,62 @@
+#include "etherboot.h"
+#include "pci.h"
+#include "sal.h"
+
+int pcibios_read_config_byte(unsigned int bus, unsigned int devfn, unsigned int reg, uint8_t *rvalue)
+{
+ unsigned long value;
+ long result;
+ result = sal_pci_config_read(PCI_SAL_ADDRESS(0,bus, 0, devfn, reg), 1, &value);
+ *rvalue = value;
+ return result;
+}
+int pcibios_read_config_word(unsigned int bus, unsigned int devfn, unsigned int reg, uint16_t *rvalue)
+{
+ unsigned long value;
+ long result;
+ result = sal_pci_config_read(PCI_SAL_ADDRESS(0,bus, 0, devfn, reg), 2, &value);
+ *rvalue = value;
+ return result;
+}
+int pcibios_read_config_dword(unsigned int bus, unsigned int devfn, unsigned int reg, uint32_t *rvalue)
+{
+ unsigned long value;
+ long result;
+ result = sal_pci_config_read(PCI_SAL_ADDRESS(0,bus, 0, devfn, reg), 4, &value);
+ *rvalue = value;
+ return result;
+}
+
+int pcibios_write_config_byte(unsigned int bus, unsigned int devfn, unsigned int reg, uint8_t value)
+{
+ return sal_pci_config_write(PCI_SAL_ADDRESS(0,bus, 0, devfn, reg), 1, value);
+}
+
+int pcibios_write_config_word(unsigned int bus, unsigned int devfn, unsigned int reg, uint16_t value)
+{
+ return sal_pci_config_write(PCI_SAL_ADDRESS(0,bus, 0, devfn, reg), 2, value);
+}
+
+int pcibios_write_config_dword(unsigned int bus, unsigned int devfn, unsigned int reg, uint32_t value)
+{
+ return sal_pci_config_write(PCI_SAL_ADDRESS(0,bus, 0, devfn, reg), 4, value);
+}
+
+/* So far I have not see a non-zero PCI_BUS_OFFSET
+ * and an AML parser to get it much to much trouble.
+ */
+#ifndef PCI_BUS_OFFSET
+#define PCI_BUS_OFFSET 0
+#endif
+
+unsigned long pcibios_bus_base(unsigned int bus)
+{
+ return PCI_BUS_OFFSET;
+}
+
+void find_pci(int type, struct pci_device *dev)
+{
+ /* Should I check for sal functions being present? */
+ return scan_pci_bus(type, dev);
+}
+
diff --git a/src/arch/ia64/core/reloc.S b/src/arch/ia64/core/reloc.S
new file mode 100644
index 000000000..31689bfbb
--- /dev/null
+++ b/src/arch/ia64/core/reloc.S
@@ -0,0 +1,133 @@
+/* reloc.S - position independent IA-64 ELF shared object relocator
+ Copyright (C) 1999 Hewlett-Packard Co.
+ Contributed by David Mosberger <davidm@hpl.hp.com>.
+ Copyright (C) 2002 Eric Biederman sponsored by Linux Networx
+
+ This file is part of etherboot.
+ This file was derived from reloc_ia64.S from GNU-EFI, the GNU EFI development environment.
+
+ GNU EFI is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU EFI 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU EFI; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+/*
+ * This is written in assembly because the entire code needs to be position
+ * independent. Note that the compiler does not generate code that's position
+ * independent by itself because it relies on the global offset table being
+ * relocated.
+ *
+ * This code assumes the code was compiled with -mconstant-gp -mauto-pic -static -shared
+ * Which generates position independent code, but not position indepedent data.
+ * This code assumes in the linker script the rela entries are bracked with:
+ * _rela, _erela and _rela_size gives the total size of the rela entries.
+ * This gives a much smaller binary than when compiled as a true shared object.
+ *
+ * This code assumes the original shared object was initially relocated,
+ * So that it only needs to apply changes for the new address the code is linked
+ * at.
+ */
+ .text
+ .psr abi64
+ .psr lsb
+ .lsb
+
+
+#define ST_VALUE_OFF 8 /* offset of st_value in elf sym */
+
+#define RET_SUCCESS 0
+#define RET_LOAD_ERROR 1
+
+#define R_IA64_NONE 0
+#define R_IA64_REL64MSB 0x6e
+#define R_IA64_REL64LSB 0x6f
+#define R_IA64_DIR64MSB 0x26
+#define R_IA64_DIR64LSB 0x27
+#define R_IA64_FPTR64MSB 0x46
+#define R_IA64_FPTR64LSB 0x47
+
+#define delta in0 /* Chaing in load address (address of .text) */
+
+#define ldbase r15
+#define target r16
+#define val r17
+#define rela r18
+#define relasz r19
+#define relaent r20
+#define addr r21
+#define r_info r22
+#define r_offset r23
+#define r_type r25
+
+#define Pmore p6
+
+#define Pnone p6
+#define Prel p7
+#define Pdir p8
+
+
+ .global _relocate
+_relocate:
+ alloc r2=ar.pfs,1,0,0,0
+ add rela=@gprel(_rela),gp
+ add ldbase=@gprel(_text),gp
+ add r3=@ltoff(_rela_size),gp
+ ;;
+ ld8 relasz = [r3]
+ mov relaent=24
+ br.sptk.few apply_relocs
+
+apply_loop:
+ ld8 r_offset = [rela]
+ add addr = 8,rela
+ sub relasz = relasz,relaent
+
+ ;;
+ ld8 r_info = [addr], 8
+ ;;
+ add target = ldbase, r_offset
+ add rela = rela,relaent
+ extr.u r_type = r_info, 0, 32
+ ;;
+ cmp.eq Pnone,p0 = R_IA64_NONE, r_type
+ cmp.eq Prel,p0 = R_IA64_REL64LSB, r_type
+ cmp.eq Pdir,p0 = R_IA64_DIR64LSB, r_type /* Needed? */
+ ;;
+(Pnone) br.cond.sptk.few apply_relocs
+(Prel) br.cond.sptk.few apply_REL64
+(Pdir) br.cond.sptk.few apply_DIR64 /* Needed? */
+ ;;
+
+apply_error:
+ mov r8 = RET_LOAD_ERROR
+ br.ret.sptk.few rp
+
+apply_REL64:
+apply_DIR64:
+ ld8 val = [target]
+ ;;
+ add val = val, delta
+ ;;
+ st8 [target] = val
+ ;;
+ /* fall through to apply_relocs */
+apply_relocs:
+ cmp.ltu Pmore,p0=0,relasz
+(Pmore) br.cond.sptk.few apply_loop
+ ;;
+
+ mov r8 = RET_SUCCESS
+ br.ret.sptk.few rp
+
+ .size _relocate, . - _relocate
+ .endp _relocate
diff --git a/src/arch/ia64/core/relocate_to.S b/src/arch/ia64/core/relocate_to.S
new file mode 100644
index 000000000..37b5c9f86
--- /dev/null
+++ b/src/arch/ia64/core/relocate_to.S
@@ -0,0 +1,92 @@
+ /* Temporarily ignore the stack, as I am still using efi's stack */
+
+#define newbase in0
+#define base loc2
+#define newgp loc3
+#define len loc4
+
+ .explicit
+ .globl relocate_to
+ .proc relocate_to
+relocate_to:
+ /* In incoming variable the new base addres of etherboot. */
+ alloc loc0=ar.pfs,1,5,3,0 /* in, local, out, rotating */
+ mov loc1=rp
+
+ /* Compute the current location of _text */
+ /* Compute the new gp value */
+ add base=@gprel(_text),gp
+ add len =@gprel(_end),gp
+ movl newgp=@gprel(_text)
+ ;;
+ sub newgp=newbase,newgp /* gp = _text - @gprel(_text) */
+ sub len=len,base
+ ;;
+
+ /* Copy etherboot to the new location */
+ mov out0=newbase
+ mov out1=base
+ mov out2=len
+ br.call.sptk.few rp=memcpy
+ ;;
+
+ /* Jump to my __relocate_to in the new location */
+ movl r14=@gprel(__relocate_to)
+ ;;
+ add r14=r14,newgp
+ ;;
+ mov b6=r14
+ ;;
+ br.cond.sptk.few b6
+ ;;
+__relocate_to:
+ /* I am at the new location set the newgp as the default */
+ mov gp=newgp
+ ;;
+ /* New apply relocations to the new copy */
+ sub out0=newbase,base
+ br.call.sptk.few rp=_relocate
+ ;;
+
+ /* Lookup restart_etherboot */
+ add out0=@gprel(restart_etherboot),gp
+ ;;
+
+ /* Adjust the gp and return address.
+ * NOTE: This only works when the setjmp can modify it's caller's gp
+ * address. Essentially this means etherboot must be compiled with
+ * compiled with -mconstant-gp, though an inline version of setjmp might work.
+ */
+ add r14=0x40,out0
+ add r16=0x08,out0
+ ;;
+ ld8 r15=[r14]
+ ld8 r17=[r16]
+ ;;
+ sub r15=r15,base
+ sub r17=r17,base
+ ;;
+ add r15=r15,newbase
+ add r17=r17,newbase
+ ;;
+ st8 [r14]=r15
+ st8 [r16]=r17
+ ;;
+ mov out1=256
+ br.call.sptk.few rp=longjmp
+
+ /* And just in case lonjmp returns... */
+
+
+ /* Adjust my return address and return */
+ sub loc1=loc1,base
+ ;;
+ add loc1=loc1,newbase
+ ;;
+ mov ar.pfs=loc0
+ mov rp=loc1
+ ;;
+ br.ret.sptk.few rp
+
+ .size relocate_to, . - relocate_to
+ .endp relocate_to
diff --git a/src/arch/ia64/core/sal.c b/src/arch/ia64/core/sal.c
new file mode 100644
index 000000000..aa040f807
--- /dev/null
+++ b/src/arch/ia64/core/sal.c
@@ -0,0 +1,278 @@
+#include "etherboot.h"
+#include "sal.h"
+
+struct sal_entry_base {
+ uint8_t entry_type;
+#define SAL_TYPE_ENTRYPOINT 0
+#define SAL_TYPE_MEMORY 1
+#define SAL_TYPE_PLATFORM_FEATURES 2
+#define SAL_TYPE_TRANSLATION_REGISTER 3
+#define SAL_TYPE_PURGE_DOMAIN 4
+#define SAL_TYPE_AP_WAKEUP 5
+};
+
+struct sal_entry_point_descriptor {
+ uint8_t entry_type;
+ uint8_t reserved[7];
+ uint64_t pal_proc;
+ uint64_t sal_proc;
+ uint64_t sal_gp;
+ uint8_t reserved2[16];
+};
+
+struct sal_memory_descriptor {
+ uint8_t entry_type;
+ uint8_t sal_needs_virt_mapping;
+ uint8_t mem_attr;
+#define MEM_ATTR_WB 0
+#define MEM_ATTR_UC 8
+#define MEM_ATTR_UCE 9
+#define MEM_ATTR_WC 10
+ uint8_t access_rights;
+ uint8_t mem_attr_support;
+#define MEM_ATTR_SUPPORTS_WB 1
+#define MEM_ATTR_SUPPORTS_UC 2
+#define MEM_ATTR_SUPPORTS_UCE 4
+#define MEM_ATTR_SUPPORTS_WC 8
+ uint8_t reserved;
+ uint8_t mem_type;
+#define MEM_TYPE_RAM 0
+#define MEM_TYPE_MIO 1
+#define MEM_TYPE_SAPIC 2
+#define MEM_TYPE_PIO 3
+#define MEM_TYPE_FIRMWARE 4
+#define MEM_TYPE_BAD_RAM 9
+#define MEM_TYPE_BLACK_HOLE 10
+ uint8_t mem_usage;
+#define MEM_USAGE_UNSPECIFIED 0
+#define MEM_USAGE_PAL_CODE 1
+#define MEM_USAGE_BOOT_SERVICES_CODE 2
+#define MEM_USAGE_BOOT_SERVICES_DATA 3
+#define MEM_USAGE_RUNTIME_SERVICES_CODE 4
+#define MEM_USAGE_RUNTIME_SERVICES_DATA 5
+#define MEM_USAGE_IA32_OPTION_ROM 6
+#define MEM_USAGE_IA32_SYSTEM_ROM 7
+#define MEM_USAGE_ACPI_RECLAIM_MEMORY 8
+#define MEM_USAGE_ACPI_NVS_MEMORY 9
+#define MEM_USAGE_SAL_PMI_CODE 10
+#define MEM_USAGE_SAL_PMI_DATA 11
+#define MEM_USAGE_FIRMWARE_RESERVED_RAM 12
+
+#define MEM_USAGE_CPU_TO_IO 0
+ uint64_t phys_address;
+ uint32_t pages; /* In 4k pages */
+ uint32_t reserved2;
+ uint8_t oem_reserved[8];
+};
+
+struct sal_platform_features {
+ uint8_t entry_type;
+ uint8_t feature_list;
+#define SAL_FEATURE_BUS_LOCK 1
+#define SAL_FEATURE_PLATFORM_REDIRECTION_HINT 2
+#define SAL_FEATURE_PROCESSOR_REDIRECTION_HINT 3
+ uint8_t reserved[14];
+};
+struct sal_translation_register {
+ uint8_t entry_type;
+ uint8_t tr_type;
+#define SAL_ITR 0
+#define SAL_DTR 1
+ uint8_t tr_number;
+ uint8_t reserved[5];
+ uint64_t virtual_address;
+ uint64_t page_size;
+ uint8_t reserved2[8];
+};
+
+struct sal_purge_translation_cache_coherency_domain {
+ uint8_t entry_type;
+ uint8_t reserved[3];
+ uint32_t coherence_domain_count;
+ uint64_t coherence_domain_addr;
+};
+
+struct sal_ap_wakeup_descriptor {
+ uint8_t entry_type;
+ uint8_t wakeup_mechanism;
+ uint8_t reserved[6];
+ uint64_t interrupt;
+};
+
+struct sal_entry {
+ union {
+ struct sal_entry_base base;
+ struct sal_entry_point_descriptor entry_point;
+ struct sal_memory_descriptor mem;
+ struct sal_platform_features features;
+ struct sal_translation_register tr;
+ struct sal_purge_translation_cache_coherency_domain purge;
+ struct sal_ap_wakeup_descriptor ap_wakeup;
+ };
+};
+
+struct sal_system_table {
+ uint8_t signature[4]; /* SST_ */
+ uint32_t table_length;
+
+ uint16_t sal_rev;
+ uint16_t entry_count;
+ uint8_t checksum;
+ uint8_t reserved1[7];
+ uint16_t sal_a_version;
+ uint16_t sal_b_version;
+
+ uint8_t oem_id[32];
+ uint8_t product_id[32];
+ uint8_t reserved2[8];
+ struct sal_entry entry[0];
+};
+
+static struct sal_system_table *sal;
+struct fptr sal_entry;
+
+int parse_sal_system_table(void *table)
+{
+ struct sal_system_table *salp = table;
+ uint8_t *ptr;
+ uint8_t checksum;
+ struct sal_entry *entry;
+ unsigned i;
+ if (memcmp(salp->signature, "SST_", 4) != 0) {
+ return 0;
+ }
+ ptr = table;
+ checksum = 0;
+ for(i = 0; i < salp->table_length; i++) {
+ checksum += ptr[i];
+ }
+ if (checksum != 0) {
+ return 0;
+ }
+#if 0
+ printf("SALA: %hx SALB: %hx\n",
+ salp->sal_a_version,
+ salp->sal_b_version);
+ printf("SAL OEM: ");
+ for(i = 0; i < sizeof(salp->oem_id); i++) {
+ uint8_t ch = salp->oem_id[i];
+ if (ch == 0)
+ break;
+ printf("%c", ch);
+ }
+ printf("\n");
+
+ printf("SAL PRODUCT: ");
+ for(i = 0; i < sizeof(salp->product_id); i++) {
+ uint8_t ch = salp->product_id[i];
+ if (ch == 0)
+ break;
+ printf("%c", ch);
+ }
+ printf("\n");
+#endif
+ sal = salp;
+ pal_entry.entry = 0;
+ pal_entry.gp = 0;
+ sal_entry.entry = 0;
+ sal_entry.gp = 0;
+ entry = sal->entry;
+ i = 0;
+ while(i < salp->entry_count) {
+ unsigned long size = 0;
+
+ switch(entry->base.entry_type) {
+ case SAL_TYPE_ENTRYPOINT:
+ size = sizeof(entry->entry_point);
+ pal_entry.entry = entry->entry_point.pal_proc;
+ sal_entry.entry = entry->entry_point.sal_proc;
+ sal_entry.gp = entry->entry_point.sal_gp;
+ break;
+ case SAL_TYPE_MEMORY:
+ size = sizeof(entry->mem);
+ break;
+ case SAL_TYPE_PLATFORM_FEATURES:
+ size = sizeof(entry->features);
+ break;
+ case SAL_TYPE_TRANSLATION_REGISTER:
+ size = sizeof(entry->tr);
+ break;
+ case SAL_TYPE_PURGE_DOMAIN:
+ size = sizeof(entry->purge);
+ break;
+ case SAL_TYPE_AP_WAKEUP:
+ size = sizeof(entry->ap_wakeup);
+ break;
+ default:
+ break;
+ }
+ entry = (struct sal_entry *)(((char *)entry) + size);
+ i++;
+ }
+ return 1;
+}
+
+#define SAL_SET_VECTORS 0x01000000
+#define SAL_GET_STATE_INFO 0x01000001
+#define SAL_GET_STATE_INFO_SIZE 0x01000002
+#define SAL_CLEAR_STATE_INFO 0x01000003
+#define SAL_MC_RENDEZ 0x01000004
+#define SAL_MC_SET_PARAMS 0x01000005
+#define SAL_REGISTER_PHYSICAL_ADDR 0x01000006
+
+#define SAL_CACHE_FLUSH 0x01000008
+#define SAL_CACHE_INIT 0x01000009
+#define SAL_PCI_CONFIG_READ 0x01000010
+#define SAL_PCI_CONFIG_WRITE 0x01000011
+#define SAL_FREQ_BASE 0x01000012
+
+#define SAL_UPDATE_PAL 0x01000020
+
+/*
+ * Now define a couple of inline functions for improved type checking
+ * and convenience.
+ */
+long sal_freq_base (unsigned long which, unsigned long *ticks_per_second,
+ unsigned long *drift_info)
+{
+ struct {
+ long status;
+ unsigned long ticks_per_second;
+ unsigned long drift_info;
+ } result, __call(void *,...);
+
+ result = __call(&sal_entry, SAL_FREQ_BASE, which, 0, 0, 0, 0, 0, 0);
+
+ *ticks_per_second = result.ticks_per_second;
+ *drift_info = result.drift_info;
+ return result.status;
+}
+
+
+
+/* Read from PCI configuration space */
+long sal_pci_config_read (
+ unsigned long pci_config_addr, unsigned long size, unsigned long *value)
+{
+ struct {
+ long status;
+ unsigned long value;
+ } result, __call(void *,...);
+
+ result = __call(&sal_entry, SAL_PCI_CONFIG_READ, pci_config_addr, size, 0, 0, 0, 0, 0);
+ if (value)
+ *value = result.value;
+ return result.status;
+}
+
+/* Write to PCI configuration space */
+long sal_pci_config_write (
+ unsigned long pci_config_addr, unsigned long size, unsigned long value)
+{
+ struct {
+ long status;
+ } result, __call(void *,...);
+
+ result = __call(&sal_entry, SAL_PCI_CONFIG_WRITE, pci_config_addr, size, value, 0, 0, 0, 0);
+ return result.status;
+}
diff --git a/src/arch/ia64/core/setjmp.S b/src/arch/ia64/core/setjmp.S
new file mode 100644
index 000000000..f3e576789
--- /dev/null
+++ b/src/arch/ia64/core/setjmp.S
@@ -0,0 +1,173 @@
+/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
+
+ 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.
+
+ The layout of the jmp_buf is as follows. This is subject to change
+ and user-code should never depend on the particular layout of
+ jmp_buf!
+
+
+ offset: description:
+ ------- ------------
+ 0x000 stack pointer (r12) ; unchangeable (see _JMPBUF_UNWINDS)
+ 0x008 r1 (gp)
+ 0x010 caller's unat
+ 0x018 fpsr
+ 0x020 r4
+ 0x028 r5
+ 0x030 r6
+ 0x038 r7
+ 0x040 rp (b0)
+ 0x048 b1
+ 0x050 b2
+ 0x058 b3
+ 0x060 b4
+ 0x068 b5
+ 0x070 ar.pfs
+ 0x078 ar.lc
+ 0x080 pr
+ 0x088 ar.bsp ; unchangeable (see __longjmp.S)
+ 0x090 ar.unat
+ 0x098 &__jmp_buf ; address of the jmpbuf (needed to locate NaT bits in unat)
+ 0x0a0 f2
+ 0x0b0 f3
+ 0x0c0 f4
+ 0x0d0 f5
+ 0x0e0 f16
+ 0x0f0 f17
+ 0x100 f18
+ 0x110 f19
+ 0x120 f20
+ 0x130 f21
+ 0x130 f22
+ 0x140 f23
+ 0x150 f24
+ 0x160 f25
+ 0x170 f26
+ 0x180 f27
+ 0x190 f28
+ 0x1a0 f29
+ 0x1b0 f30
+ 0x1c0 f31 */
+
+
+ /* The following two entry points are the traditional entry points: */
+
+ .text
+ .global setjmp
+ .proc setjmp
+setjmp:
+ alloc r8=ar.pfs,2,0,0,0
+ mov in1=1
+ br.cond.sptk.many __sigsetjmp
+ .size setjmp, . - setjmp
+ .endp setjmp
+
+ /* __sigsetjmp(__jmp_buf buf, int savemask) */
+
+__sigsetjmp:
+#if 0
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
+#endif
+ alloc loc1=ar.pfs,2,2,2,0
+ mov r16=ar.unat
+ ;;
+ mov r17=ar.fpsr
+ mov r2=in0
+ add r3=8,in0
+ ;;
+ st8.spill.nta [r2]=sp,16 // r12 (sp)
+ st8.spill.nta [r3]=gp,16 // r1 (gp)
+ ;;
+ st8.nta [r2]=r16,16 // save caller's unat
+ st8.nta [r3]=r17,16 // save fpsr
+ add r8=0xa0,in0
+ ;;
+ st8.spill.nta [r2]=r4,16 // r4
+ st8.spill.nta [r3]=r5,16 // r5
+ add r9=0xb0,in0
+ ;;
+ stf.spill.nta [r8]=f2,32
+ stf.spill.nta [r9]=f3,32
+ mov loc0=rp
+ .body
+ ;;
+ stf.spill.nta [r8]=f4,32
+ stf.spill.nta [r9]=f5,32
+ mov r17=b1
+ ;;
+ stf.spill.nta [r8]=f16,32
+ stf.spill.nta [r9]=f17,32
+ mov r18=b2
+ ;;
+ stf.spill.nta [r8]=f18,32
+ stf.spill.nta [r9]=f19,32
+ mov r19=b3
+ ;;
+ stf.spill.nta [r8]=f20,32
+ stf.spill.nta [r9]=f21,32
+ mov r20=b4
+ ;;
+ stf.spill.nta [r8]=f22,32
+ stf.spill.nta [r9]=f23,32
+ mov r21=b5
+ ;;
+ stf.spill.nta [r8]=f24,32
+ stf.spill.nta [r9]=f25,32
+ mov r22=ar.lc
+ ;;
+ stf.spill.nta [r8]=f26,32
+ stf.spill.nta [r9]=f27,32
+ mov r24=pr
+ ;;
+ stf.spill.nta [r8]=f28,32
+ stf.spill.nta [r9]=f29,32
+ ;;
+ stf.spill.nta [r8]=f30
+ stf.spill.nta [r9]=f31
+
+ st8.spill.nta [r2]=r6,16 // r6
+ st8.spill.nta [r3]=r7,16 // r7
+ ;;
+ mov r23=ar.bsp
+ mov r25=ar.unat
+ mov out0=in0
+
+ st8.nta [r2]=loc0,16 // b0
+ st8.nta [r3]=r17,16 // b1
+ mov out1=in1
+ ;;
+ st8.nta [r2]=r18,16 // b2
+ st8.nta [r3]=r19,16 // b3
+ ;;
+ st8.nta [r2]=r20,16 // b4
+ st8.nta [r3]=r21,16 // b5
+ ;;
+ st8.nta [r2]=loc1,16 // ar.pfs
+ st8.nta [r3]=r22,16 // ar.lc
+ ;;
+ st8.nta [r2]=r24,16 // pr
+ st8.nta [r3]=r23,16 // ar.bsp
+ ;;
+ st8.nta [r2]=r25 // ar.unat
+ st8.nta [r3]=in0 // &__jmp_buf
+ mov r8=0
+ mov rp=loc0
+ mov ar.pfs=loc1
+ br.ret.sptk.many rp
+
+ .endp __sigsetjmp
diff --git a/src/arch/ia64/core/start.S b/src/arch/ia64/core/start.S
new file mode 100644
index 000000000..72b94ce19
--- /dev/null
+++ b/src/arch/ia64/core/start.S
@@ -0,0 +1,28 @@
+ .text
+ .align 4
+ .proc _start
+ .globl _start
+_start:
+ {
+ alloc loc0 = ar.pfs,1,2,1,0 /* in, local, out, rotating */
+ mov loc1 = rp
+ mov r14 = ip /* Get the address of _start */
+ }
+ movl r15 = @gprel(_start)
+ ;;
+ sub gp = r14,r15
+ ;;
+ rsm psr.i /* disable interrupts */
+ ;;
+ add out0 = @gprel(_text),gp
+ br.call.sptk.few rp = _relocate
+ ;;
+ cmp.eq p6,p7 = r0,r8 /* r8 == SUCCESS? */
+ mov ar.pfs = loc0
+ mov rp = loc1
+ ;;
+(p6) br.cond.sptk.few main
+(p7) br.ret.sptk.few rp
+
+ .size _start, . - _start
+ .endp _start
diff --git a/src/arch/ia64/drivers/net/undi_nii.c b/src/arch/ia64/drivers/net/undi_nii.c
new file mode 100644
index 000000000..c1aabf001
--- /dev/null
+++ b/src/arch/ia64/drivers/net/undi_nii.c
@@ -0,0 +1,1079 @@
+#include "efi/efi.h"
+#include "etherboot.h"
+#include "isa.h"
+#include "dev.h"
+#include "nic.h"
+#include "timer.h"
+
+#warning "Place the declaraction of __call someplace more appropriate\n"
+extern EFI_STATUS __call(void *,...);
+#warning "Place a declaration of lookup_efi_nic somewhere useful"
+EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE *lookup_efi_nic(int index);
+
+struct sw_undi {
+ uint8_t signature[4];
+ uint8_t len;
+ uint8_t fudge;
+ uint8_t rev;
+ uint8_t ifcnt;
+ uint8_t major;
+ uint8_t minor;
+ uint16_t reserved1;
+ uint32_t implementation;
+#define UNDI_IMP_CMD_COMPLETE_INT_SUPPORTED 0x00000001
+#define UNDI_IMP_PACKET_RX_INT_SUPPORTED 0x00000002
+#define UNDI_IMP_TX_COMPLETE_INT_SUPPORTED 0x00000004
+#define UNDI_IMP_SOFTWARE_INT_SUPPORTED 0x00000008
+#define UNDI_IMP_FILTERED_MULTICAST_RX_SUPPORTED 0x00000010
+#define UNDI_IMP_BROADCAST_RX_SUPPORTED 0x00000020
+#define UNDI_IMP_PROMISCUOUS_RX_SUPPORTED 0x00000040
+#define UNDI_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED 0x00000080
+#define UNDI_IMP_STATION_ADDR_SETTABLE 0x00000100
+#define UNDI_IMP_STATISTICS_SUPPORTED 0x00000200
+#define UNDI_IMP_NVDATA_SUPPORT_MASK 0x00000C00
+#define UNDI_IMP_NVDATA_NOT_AVAILABLE 0x00000000
+#define UNDI_IMP_NVDATA_READ_ONLY 0x00000400
+#define UNDI_IMP_NVDATA_SPARSE_WRITEABLE 0x00000800
+#define UNDI_IMP_NVDATA_BULK_WRITEABLE 0x00000C00
+#define UNDI_IMP_MULTI_FRAME_SUPPORTED 0x00001000
+#define UNDI_IMP_CMD_QUEUE_SUPPORTED 0x00002000
+#define UNDI_IMP_CMD_LINK_SUPPORTED 0x00004000
+#define UNDI_IMP_FRAG_SUPPORTED 0x00008000
+#define UNDI_IMP_64BIT_DEVICE 0x00010000
+#define UNDI_IMP_SW_VIRT_ADDR 0x40000000
+#define UNDI_IMP_HW_UNDI 0x80000000
+ uint64_t entry_point;
+ uint8_t reserved2[3];
+ uint8_t bus_type_cnt;
+ uint32_t bus_type[0];
+};
+
+struct cdb {
+ uint16_t op_code;
+#define CDB_OP_GET_STATE 0x0000
+#define CDB_OP_START 0x0001
+#define CDB_OP_STOP 0x0002
+#define CDB_OP_GET_INIT_INFO 0x0003
+#define CDB_OP_GET_CONFIG_INFO 0x0004
+#define CDB_OP_INITIALIZE 0x0005
+#define CDB_OP_RESET 0x0006
+#define CDB_OP_SHUTDOWN 0x0007
+#define CDB_OP_INTERRUPT_ENABLES 0x0008
+#define CDB_OP_RECEIVE_FILTERS 0x0009
+#define CDB_OP_STATION_ADDRESS 0x000a
+#define CDB_OP_STATISTICS 0x000b
+#define CDB_OP_MCAST_IP_TO_MAC 0x000c
+#define CDB_OP_NVDATA 0x000d
+#define CDB_OP_GET_STATUS 0x000e
+#define CDB_OP_FILL_HEADER 0x000f
+#define CDB_OP_TRANSMIT 0x0010
+#define CDB_OP_RECEIVE 0x0011
+ uint16_t op_flags;
+#define CDB_OPFLAGS_NOT_USED 0x0000
+/* Initialize */
+#define CDB_OPFLAGS_INIT_CABLE_DETECT_MASK 0x0001
+#define CDB_OPFLAGS_INIT_DETECT_CABLE 0x0000
+#define CDB_OPFLAGS_INIT_DO_NOT_DETECT_CABLE 0x0001
+/* Reset */
+#define CDB_OPFLAGS_RESET_DISABLE_INTERRUPTS 0x0001
+#define CDB_OPFLAGS_RESET_DISABLE_FILTERS 0x0002
+/* Interrupt Enables */
+#define CDB_OPFLAGS_INTERRUPT_OPMASK 0xc000
+#define CDB_OPFLAGS_INTERRUPT_ENABLE 0x8000
+#define CDB_OPFLAGS_INTERRUPT_DISABLE 0x4000
+#define CDB_OPFLAGS_INTERRUPT_READ 0x0000
+#define CDB_OPFLAGS_INTERRUPT_RECEIVE 0x0001
+#define CDB_OPFLAGS_INTERRUPT_TRANSMIT 0x0002
+#define CDB_OPFLAGS_INTERRUPT_COMMAND 0x0004
+#define CDB_OPFLAGS_INTERRUPT_SOFTWARE 0x0008
+/* Receive Filters */
+#define CDB_OPFLAGS_RECEIVE_FILTER_OPMASK 0xc000
+#define CDB_OPFLAGS_RECEIVE_FILTER_ENABLE 0x8000
+#define CDB_OPFLAGS_RECEIVE_FILTER_DISABLE 0x4000
+#define CDB_OPFLAGS_RECEIVE_FILTER_READ 0x0000
+#define CDB_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST 0x2000
+#define CDB_OPFLAGS_RECEIVE_FILTER_UNICAST 0x0001
+#define CDB_OPFLAGS_RECEIVE_FILTER_BROADCAST 0x0002
+#define CDB_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004
+#define CDB_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008
+#define CDB_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010
+/* Station Address */
+#define CDB_OPFLAGS_STATION_ADDRESS_READ 0x0000
+#define CDB_OPFLAGS_STATION_ADDRESS_WRITE 0x0000
+#define CDB_OPFLAGS_STATION_ADDRESS_RESET 0x0001
+/* Statistics */
+#define CDB_OPFLAGS_STATISTICS_READ 0x0000
+#define CDB_OPFLAGS_STATISTICS_RESET 0x0001
+/* MCast IP to MAC */
+#define CDB_OPFLAGS_MCAST_IP_TO_MAC_OPMASK 0x0003
+#define CDB_OPFLAGS_MCAST_IPV4_TO_MAC 0x0000
+#define CDB_OPFLAGS_MCAST_IPV6_TO_MAC 0x0001
+/* NvData */
+#define CDB_OPFLAGS_NVDATA_OPMASK 0x0001
+#define CDB_OPFLAGS_NVDATA_READ 0x0000
+#define CDB_OPFLAGS_NVDATA_WRITE 0x0001
+/* Get Status */
+#define CDB_OPFLAGS_GET_INTERRUPT_STATUS 0x0001
+#define CDB_OPFLAGS_GET_TRANSMITTED_BUFFERS 0x0002
+/* Fill Header */
+#define CDB_OPFLAGS_FILL_HEADER_OPMASK 0x0001
+#define CDB_OPFLAGS_FILL_HEADER_FRAGMENTED 0x0001
+#define CDB_OPFLAGS_FILL_HEADER_WHOLE 0x0000
+/* Transmit */
+#define CDB_OPFLAGS_SWUNDI_TRANSMIT_OPMASK 0x0001
+#define CDB_OPFLAGS_TRANSMIT_BLOCK 0x0001
+#define CDB_OPFLAGS_TRANSMIT_DONT_BLOCK 0x0000
+
+#define CDB_OPFLAGS_TRANSMIT_OPMASK 0x0002
+#define CDB_OPFLAGS_TRANSMIT_FRAGMENTED 0x0002
+#define CDB_OPFLAGS_TRANSMIT_WHOLE 0x0000
+/* Receive */
+ uint16_t cpb_size;
+ uint16_t db_size;
+ uint64_t cpb_addr;
+ uint64_t db_addr;
+ uint16_t stat_code;
+#define CDB_STATCODE_INITIALIZE 0x0000
+/* Common stat_code values */
+#define CDB_STATCODE_SUCCESS 0x0000
+#define CDB_STATCODE_INVALID_CDB 0x0001
+#define CDB_STATCODE_INVALID_CPB 0x0002
+#define CDB_STATCODE_BUSY 0x0003
+#define CDB_STATCODE_QUEUE_FULL 0x0004
+#define CDB_STATCODE_ALREADY_STARTED 0x0005
+#define CDB_STATCODE_NOT_STARTED 0x0006
+#define CDB_STATCODE_NOT_SHUTDOWN 0x0007
+#define CDB_STATCODE_ALREADY_INITIALIZED 0x0008
+#define CDB_STATCODE_NOT_INITIALIZED 0x0009
+#define CDB_STATCODE_DEVICE_FAILURE 0x000A
+#define CDB_STATCODE_NVDATA_FAILURE 0x000B
+#define CDB_STATCODE_UNSUPPORTED 0x000C
+#define CDB_STATCODE_BUFFER_FULL 0x000D
+#define CDB_STATCODE_INVALID_PARAMETER 0x000E
+#define CDB_STATCODE_INVALID_UNDI 0x000F
+#define CDB_STATCODE_IPV4_NOT_SUPPORTED 0x0010
+#define CDB_STATCODE_IPV6_NOT_SUPPORTED 0x0011
+#define CDB_STATCODE_NOT_ENOUGH_MEMORY 0x0012
+#define CDB_STATCODE_NO_DATA 0x0013
+
+ uint16_t stat_flags;
+#define CDB_STATFLAGS_INITIALIZE 0x0000
+/* Common stat_flags */
+#define CDB_STATFLAGS_STATUS_MASK 0xc000
+#define CDB_STATFLAGS_COMMAND_COMPLETE 0xc000
+#define CDB_STATFLAGS_COMMAND_FAILED 0x8000
+#define CDB_STATFLAGS_COMMAND_QUEUED 0x4000
+/* Get State */
+#define CDB_STATFLAGS_GET_STATE_MASK 0x0003
+#define CDB_STATFLAGS_GET_STATE_INITIALIZED 0x0002
+#define CDB_STATFLAGS_GET_STATE_STARTED 0x0001
+#define CDB_STATFLAGS_GET_STATE_STOPPED 0x0000
+/* Start */
+/* Get Init Info */
+#define CDB_STATFLAGS_CABLE_DETECT_MASK 0x0001
+#define CDB_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED 0x0000
+#define CDB_STATFLAGS_CABLE_DETECT_SUPPORTED 0x0001
+/* Initialize */
+#define CDB_STATFLAGS_INITIALIZED_NO_MEDIA 0x0001
+/* Reset */
+#define CDB_STATFLAGS_RESET_NO_MEDIA 0x0001
+/* Shutdown */
+/* Interrupt Enables */
+#define CDB_STATFLAGS_INTERRUPT_RECEIVE 0x0001
+#define CDB_STATFLAGS_INTERRUPT_TRANSMIT 0x0002
+#define CDB_STATFLAGS_INTERRUPT_COMMAND 0x0004
+/* Receive Filters */
+#define CDB_STATFLAGS_RECEIVE_FILTER_UNICAST 0x0001
+#define CDB_STATFLAGS_RECEIVE_FILTER_BROADCAST 0x0002
+#define CDB_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004
+#define CDB_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008
+#define CDB_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010
+/* Statistics */
+/* MCast IP to MAC */
+/* NvData */
+/* Get Status */
+#define CDB_STATFLAGS_GET_STATUS_INTERRUPT_MASK 0x000F
+#define CDB_STATFLAGS_GET_STATUS_NO_INTERRUPTS 0x0000
+#define CDB_STATFLAGS_GET_STATUS_RECEIVE 0x0001
+#define CDB_STATFLAGS_GET_STATUS_TRANSMIT 0x0002
+#define CDB_STATFLAGS_GET_STATUS_COMMAND 0x0004
+#define CDB_STATFLAGS_GET_STATUS_SOFTWARE 0x0008
+#define CDB_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY 0x0010
+#define CDB_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN 0x0020
+/* Fill Header */
+/* Transmit */
+/* Receive */
+ uint16_t ifnum;
+#define CDB_IFNUM_START 0x0000
+#define CDB_IFNUM_INVALID 0x0000
+ uint16_t control;
+#define CDB_CONTROL_QUEUE_IF_BUSY 0x0002
+
+#define CDB_CONTROL_LINK 0x0001
+#define CDB_CONTROL_LAST_CDB_IN_LIST 0x0000
+};
+
+#define UNDI_MAC_LENGTH 32
+typedef uint8_t undi_mac_addr[UNDI_MAC_LENGTH];
+typedef uint16_t undi_media_protocol;
+typedef uint8_t undi_frame_type;
+#define UNDI_FRAME_TYPE_NONE 0x00
+#define UNDI_FRAME_TYPE_UNICAST 0x01
+#define UNDI_FRAME_TYPE_BROADCAST 0x02
+#define UNDI_FRAME_TYPE_MULTICAST 0x03
+#define UNDI_FRAME_TYPE_PROMISCUOUS 0x04
+
+#define UNDI_MAX_XMIT_BUFFERS 32
+#define UNDI_MAX_MCAST_ADDRESS_CNT 8
+
+#define UNDI_BUS_TYPE(a,b,c,d) \
+ ((((d) & 0xff) << 24) | \
+ (((c) & 0xff) << 16) | \
+ (((b) & 0xff) << 8) | \
+ (((a) & 0xff) << 0))
+
+#define UNDI_BUS_TYPE_PCI UNDI_BUS_TYPE('P','C','I','R')
+#define UNDI_BUS_TYPE_PCC UNDI_BUS_TYPE('P','C','C','R')
+#define UNDI_BUS_TYPE_USB UNDI_BUS_TYPE('U','S','B','R')
+#define UNDI_BUS_TYPE_1394 UNDI_BUS_TYPE('1','3','9','4')
+
+struct cpb_start {
+ void *delay;
+ void *block;
+ void *virt2phys;
+ void *mem_io;
+} PACKED;
+
+struct db_init_info {
+ uint32_t memory_required;
+ uint32_t frame_data_len;
+ uint32_t link_speeds[4];
+ uint32_t nv_count;
+ uint16_t nv_width;
+ uint16_t media_header_len;
+ uint16_t hw_addr_len;
+ uint16_t mcast_filter_cnt;
+ uint16_t tx_buf_cnt;
+ uint16_t tx_buf_size;
+ uint16_t rx_buf_cnt;
+ uint16_t rx_buf_size;
+ uint8_t if_type;
+ uint8_t duplex;
+#define UNDI_DUPLEX_ENABLE_FULL_SUPPORTED 1
+#define UNDI_DUPLEX_FORCE_FULL_SUPPORTED 2
+ uint8_t loopback;
+#define UNDI_LOOPBACK_INTERNAL_SUPPORTED 1
+#define UNDI_LOOPBACK_EXTERNAL_SUPPORTED 2
+} PACKED;
+
+
+struct db_pci_config_info {
+ uint32_t bus_type;
+ uint16_t bus;
+ uint8_t device;
+ uint8_t function;
+ uint8_t config[256];
+};
+struct db_pcc_config_info {
+ uint32_t bus_type;
+ uint16_t bus;
+ uint8_t device;
+ uint8_t function;
+ uint8_t config[256];
+};
+struct db_usb_config_info {
+ uint32_t bus_type;
+};
+struct db_iee1394_config_info {
+ uint32_t bus_type;
+};
+struct db_config_info {
+ union {
+ struct db_pci_config_info pci;
+ struct db_pcc_config_info pcc;
+ struct db_usb_config_info usb;
+ struct db_iee1394_config_info iee1394;
+ };
+};
+
+struct cpb_initialize {
+ uint64_t memory_addr;
+ uint32_t memory_length;
+ uint32_t link_speed;
+ uint16_t tx_buf_cnt;
+ uint16_t tx_buf_size;
+ uint16_t rx_buf_cnt;
+ uint16_t rx_buf_size;
+ uint8_t duplex;
+ uint8_t loopback;
+} PACKED;
+
+struct db_initialize {
+ uint32_t memory_used;
+ uint16_t tx_buf_cnt;
+ uint16_t tx_buf_size;
+ uint16_t rx_buf_cnt;
+ uint16_t rx_buf_size;
+} PACKED;
+
+struct cpb_station_address {
+ undi_mac_addr station_addr;
+} PACKED;
+
+struct db_station_address {
+ undi_mac_addr station_address;
+ undi_mac_addr broadcast_address;
+ undi_mac_addr permanent_address;
+} PACKED;
+
+struct cpb_receive_filters {
+ undi_mac_addr mcast_list[UNDI_MAX_MCAST_ADDRESS_CNT];
+} PACKED;
+
+struct db_receive_filters {
+ undi_mac_addr mcast_list[UNDI_MAX_MCAST_ADDRESS_CNT];
+} PACKED;
+
+
+struct db_get_status {
+ uint32_t rx_frame_len;
+ uint32_t reserved;
+ uint64_t tx_buffer[UNDI_MAX_XMIT_BUFFERS];
+} PACKED;
+
+struct cpb_transmit {
+ uint64_t frame_addr;
+ uint32_t data_len;
+ uint16_t media_header_len;
+ uint16_t reserved;
+} PACKED;
+
+struct cpb_receive {
+ uint64_t buffer_addr;
+ uint32_t buffer_len;
+ uint32_t reserved;
+} PACKED;
+struct db_receive {
+ undi_mac_addr src_addr;
+ undi_mac_addr dest_addr;
+ uint32_t frame_len;
+ undi_media_protocol protocol;
+ uint16_t media_header_len;
+ undi_frame_type type;
+ uint8_t reserved[7];
+} PACKED;
+struct fptr {
+ void *func;
+ void *gp;
+};
+
+extern char __gp[];
+
+/* Variables */
+static unsigned undi_ifnum;
+static void *undi_entry_point;
+static struct cdb cdb;
+static char buffer[1024*1024];
+
+/* SW UNDI callbacks */
+static void undi_udelay(uint64_t microseconds)
+{
+#if 0
+ printf("undi_udelay(%lx)\n", microseconds);
+#endif
+ if (microseconds < 10) {
+ microseconds = 10;
+ }
+ if (microseconds > 1000) {
+ mdelay(microseconds/1000);
+ microseconds%=1000;
+ }
+ udelay(microseconds);
+}
+static struct fptr fptr_undi_udelay = {
+ .func = &undi_udelay,
+ .gp = &__gp,
+};
+static void undi_block(uint32_t enable __unused)
+{
+#if 0
+ printf("undi_block(%x)\n",
+ enable);
+#endif
+ return;
+}
+static struct fptr fptr_undi_block = {
+ .func = &undi_block,
+ .gp = &__gp,
+};
+static void undi_virt2phys(uint64_t virtual, uint64_t *ptr)
+{
+#if 0
+ printf("undi_virt2phys(%lx, %lx)\n",
+ virtual, ptr);
+#endif
+ *ptr = virt_to_phys((void *)virtual);
+}
+static struct fptr fptr_undi_virt2phys = {
+ .func = &undi_virt2phys,
+ .gp = &__gp,
+};
+#define UNDI_IO_READ 0
+#define UNDI_IO_WRITE 1
+#define UNDI_MEM_READ 2
+#define UNDI_MEM_WRITE 3
+static void undi_mem_io(uint8_t read_write, uint8_t len, uint64_t port, uint64_t buf_addr)
+{
+ printf("undi_mem_io(%hhx, %hhx, %lx, %lx)\n",
+ read_write, len, port, buf_addr);
+#if 0
+ if ((read_write == UNDI_IO_READ) && (len == 1)) {
+ uint8_t *buf = (void *)buf_addr;
+ *buf = inb(port);
+ }
+ else if ((read_write == UNDI_IO_READ) && (len == 2)) {
+ uint16_t *buf = (void *)buf_addr;
+ *buf = inw(port);
+ }
+ else if ((read_write == UNDI_IO_READ) && (len == 4)) {
+ uint32_t *buf = (void *)buf_addr;
+ *buf = inl(port);
+ }
+ else if ((read_write == UNDI_IO_READ) && (len == 8)) {
+ uint64_t *buf = (void *)buf_addr;
+ *buf = inq(port);
+ }
+ else if ((read_write == UNDI_IO_WRITE) && (len == 1)) {
+ uint8_t *buf = (void *)buf_addr;
+ outb(*buf, port);
+ }
+ else if ((read_write == UNDI_IO_WRITE) && (len == 2)) {
+ uint16_t *buf = (void *)buf_addr;
+ outw(*buf, port);
+ }
+ else if ((read_write == UNDI_IO_WRITE) && (len == 4)) {
+ uint32_t *buf = (void *)buf_addr;
+ outl(*buf, port);
+ }
+ else if ((read_write == UNDI_IO_WRITE) && (len == 8)) {
+ uint64_t *buf = (void *)buf_addr;
+ outq(*buf, port);
+ }
+ else if ((read_write == UNDI_MEM_READ) && (len == 1)) {
+ uint8_t *buf = (void *)buf_addr;
+ *buf = readb(port);
+ }
+ else if ((read_write == UNDI_MEM_READ) && (len == 2)) {
+ uint16_t *buf = (void *)buf_addr;
+ *buf = readw(port);
+ }
+ else if ((read_write == UNDI_MEM_READ) && (len == 4)) {
+ uint32_t *buf = (void *)buf_addr;
+ *buf = readl(port);
+ }
+ else if ((read_write == UNDI_MEM_READ) && (len == 8)) {
+ uint64_t *buf = (void *)buf_addr;
+ *buf = readq(port);
+ }
+ else if ((read_write == UNDI_MEM_WRITE) && (len == 1)) {
+ uint8_t *buf = (void *)buf_addr;
+ writeb(*buf, port);
+ }
+ else if ((read_write == UNDI_MEM_WRITE) && (len == 2)) {
+ uint16_t *buf = (void *)buf_addr;
+ writew(*buf, port);
+ }
+ else if ((read_write == UNDI_MEM_WRITE) && (len == 4)) {
+ uint32_t *buf = (void *)buf_addr;
+ writel(*buf, port);
+ }
+ else if ((read_write == UNDI_MEM_WRITE) && (len == 8)) {
+ uint64_t *buf = (void *)buf_addr;
+ writeq(*buf, port);
+ }
+#endif
+}
+static struct fptr fptr_undi_mem_io = {
+ .func = &undi_mem_io,
+ .gp = &__gp,
+};
+
+/* static void undi_memio(this, width, address, count, buffer);??? */
+
+
+/* Wrappers to call the undi functions */
+static int undi_call(struct cdb *cdb)
+{
+ int result = 1;
+ cdb->stat_code = CDB_STATCODE_INITIALIZE;
+ cdb->stat_flags = CDB_STATFLAGS_INITIALIZE;
+ cdb->ifnum = undi_ifnum;
+ cdb->control = CDB_CONTROL_LAST_CDB_IN_LIST;
+ __call(undi_entry_point, cdb);
+ /* Wait until the command executes... */
+ while((cdb->stat_flags & CDB_STATFLAGS_STATUS_MASK) == 0)
+ ;
+ if ((cdb->stat_flags & CDB_STATFLAGS_STATUS_MASK) !=
+ CDB_STATFLAGS_COMMAND_COMPLETE)
+ result = 0;
+ if (cdb->stat_code != CDB_STATCODE_SUCCESS)
+ result = 0;
+ return result;
+}
+
+static int get_state(struct cdb *cdb)
+{
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_GET_STATE;
+ cdb->op_flags = CDB_OPFLAGS_NOT_USED;
+ return undi_call(cdb);
+}
+
+static int start(struct cdb *cdb)
+{
+ static struct cpb_start cpb;
+ memset(&cpb, 0, sizeof(cpb));
+ cpb.delay = &fptr_undi_udelay;
+ cpb.block = &fptr_undi_block;
+ cpb.virt2phys = &fptr_undi_virt2phys;
+ cpb.mem_io = &fptr_undi_mem_io;
+
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_START;
+ cdb->op_flags = CDB_OPFLAGS_NOT_USED;
+ cdb->cpb_size = sizeof(cpb);
+ cdb->cpb_addr = virt_to_phys(&cpb);
+
+ return undi_call(cdb);
+}
+static int stop(struct cdb *cdb)
+{
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_STOP;
+ cdb->op_flags = CDB_OPFLAGS_NOT_USED;
+ return undi_call(cdb);
+}
+static int get_init_info(struct cdb *cdb, struct db_init_info *info)
+{
+ memset(info, 0, sizeof(*info));
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_GET_INIT_INFO;
+ cdb->op_flags = CDB_OPFLAGS_NOT_USED;
+ cdb->db_size = sizeof(*info);
+ cdb->db_addr = virt_to_phys(info);
+ return undi_call(cdb);
+}
+
+#if 0
+/* get_config_info crashes broadcoms pxe driver */
+static int get_config_info(struct cdb *cdb, struct db_config_info *info)
+{
+ memset(info, 0, sizeof(*info));
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_GET_CONFIG_INFO;
+ cdb->op_flags = CDB_OPFLAGS_NOT_USED;
+ cdb->db_size = sizeof(*info);
+ cdb->db_addr = virt_to_phys(info);
+ return undi_call(cdb);
+}
+#endif
+static int initialize(struct cdb *cdb, int media_detect,
+ struct cpb_initialize *cpb, struct db_initialize *db)
+{
+ memset(db, 0, sizeof(*db));
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_INITIALIZE;
+ cdb->op_flags = media_detect?
+ CDB_OPFLAGS_INIT_DETECT_CABLE:CDB_OPFLAGS_INIT_DO_NOT_DETECT_CABLE;
+ cdb->cpb_size = sizeof(*cpb);
+ cdb->cpb_addr = virt_to_phys(cpb);
+ cdb->db_size = sizeof(*db);
+ cdb->db_addr = virt_to_phys(db);
+ return undi_call(cdb);
+}
+static int shutdown(struct cdb *cdb)
+{
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_SHUTDOWN;
+ cdb->op_flags = CDB_OPFLAGS_NOT_USED;
+ return undi_call(cdb);
+}
+static int station_address_read(struct cdb *cdb, struct db_station_address *db)
+{
+ memset(db, 0, sizeof(*db));
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_STATION_ADDRESS;
+ cdb->op_flags = CDB_OPFLAGS_STATION_ADDRESS_READ;
+ cdb->db_size = sizeof(*db);
+ cdb->db_addr = virt_to_phys(db);
+ return undi_call(cdb);
+}
+static int receive_filters(struct cdb *cdb, unsigned opflags)
+{
+ /* I currently do not support setting
+ * or returning the multicast filter list.
+ * So do not even attempt to pass them.
+ */
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_RECEIVE_FILTERS;
+ cdb->op_flags = opflags;
+ return undi_call(cdb);
+}
+static int get_transmitted_status(struct cdb *cdb, struct db_get_status *db)
+{
+ memset(db, 0, sizeof(*db));
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_GET_STATUS;
+ cdb->op_flags = CDB_OPFLAGS_GET_TRANSMITTED_BUFFERS;
+ cdb->db_size = sizeof(*db);
+ cdb->db_addr = virt_to_phys(db);
+ return undi_call(cdb);
+}
+
+static int transmit(struct cdb *cdb, struct cpb_transmit *cpb)
+{
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_TRANSMIT;
+ cdb->op_flags = CDB_OPFLAGS_TRANSMIT_WHOLE | CDB_OPFLAGS_TRANSMIT_DONT_BLOCK;
+ cdb->cpb_size = sizeof(*cpb);
+ cdb->cpb_addr = virt_to_phys(cpb);
+ return undi_call(cdb);
+}
+
+static int receive(struct cdb *cdb,
+ struct cpb_receive *cpb, struct db_receive *db)
+{
+ memset(db, 0, sizeof(*db));
+ memset(cdb, 0, sizeof(*cdb));
+ cdb->op_code = CDB_OP_RECEIVE;
+ cdb->op_flags = CDB_OPFLAGS_NOT_USED;
+ cdb->cpb_size = sizeof(*cpb);
+ cdb->cpb_addr = virt_to_phys(cpb);
+ cdb->db_size = sizeof(*db);
+ cdb->db_addr = virt_to_phys(db);
+ return undi_call(cdb);
+}
+
+/* The work horse functions */
+static int nic_poll(struct nic *nic )
+{
+ int result;
+ struct cpb_receive cpb;
+ struct db_receive db;
+
+ memset(&cpb, 0, sizeof(cpb));
+ cpb.buffer_addr = virt_to_phys(nic->packet);
+ cpb.buffer_len = ETH_FRAME_LEN;
+ result = receive(&cdb, &cpb, &db);
+ if (result) {
+ nic->packetlen = db.frame_len;
+ return 1;
+ }
+ else if (cdb.stat_code != CDB_STATCODE_NO_DATA) {
+ printf("Receive failed: %lx\n", cdb.stat_code);
+ }
+ return 0; /* initially as this is called to flush the input */
+}
+
+static void nic_transmit(struct nic *nic, const char *dest, unsigned int type,
+ unsigned int size, const char *data)
+{
+ int result;
+ static struct {
+ uint8_t dst_addr[ETH_ALEN];
+ uint8_t src_addr[ETH_ALEN];
+ uint16_t type;
+ uint8_t data[ETH_MAX_MTU];
+ } packet;
+ struct cpb_transmit cpb;
+ struct db_get_status db;
+ int done;
+
+ /* Build the packet to transmit in my buffer */
+ memcpy(&packet.dst_addr, dest, ETH_ALEN);
+ memcpy(&packet.src_addr, nic->node_addr, ETH_ALEN);
+ packet.type = htons(type);
+ memcpy(&packet.data, data, size);
+
+ /* send the packet to destination */
+ cpb.frame_addr = virt_to_phys(&packet);
+ cpb.data_len = ETH_HLEN + size;
+ cpb.media_header_len = ETH_HLEN;
+ result = transmit(&cdb, &cpb);
+ if (!result) {
+ printf("transmit failed: %lx\n", cdb.stat_code);
+ return;
+ }
+ /* Wait until the packet is actually transmitted,
+ * indicating it is safe to reuse my trasmit buffer.
+ */
+ done = 0;
+ while(!done) {
+ int i;
+ result = get_transmitted_status(&cdb, &db);
+ for(i = 0; i < UNDI_MAX_XMIT_BUFFERS; i++) {
+ if (db.tx_buffer[i] == virt_to_phys(&packet)) {
+ done = 1;
+ }
+ }
+ }
+}
+
+static void nic_disable(struct dev *dev)
+{
+ struct nic *nic = (struct nic *)dev;
+ int result;
+ result = shutdown(&cdb);
+ if (!result) {
+ printf("UNDI nic does not want to shutdown: %x\n", cdb.stat_code);
+ }
+ result = stop(&cdb);
+ if (!result) {
+ printf("UNDI nic does not want to stop: %x\n", cdb.stat_code);
+ }
+ undi_ifnum = 0;
+ undi_entry_point = 0;
+}
+
+static uint8_t undi_checksum(struct sw_undi *undi)
+{
+ uint8_t undi_sum, *ptr;
+ int i;
+ ptr = (uint8_t *)undi;
+ undi_sum = 0;
+ for(i = 0; i < undi->len; i++) {
+ undi_sum += ((char *)undi)[i];
+ }
+ return undi_sum;
+}
+
+#if 0
+/* Debug functions */
+void print_nii(EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE *nii)
+{
+ printf("NII Revision: %lx\n", nii->Revision);
+ printf("NII ID: %lx\n", nii->ID);
+ printf("NII ImageAddr: %lx\n", nii->ImageAddr);
+ printf("NII ImageSize: %x\n", nii->ImageSize);
+ printf("NII StringID: %c%c%c%c\n",
+ nii->StringId[0], nii->StringId[1], nii->StringId[2], nii->StringId[3]);
+ printf("NII Type: %hhx\n", nii->Type);
+ printf("NII Version: %d.%d\n", nii->MajorVer, nii->MinorVer);
+ printf("NII IfNum: %hhx\n", nii->IfNum);
+ printf("\n");
+}
+void print_sw_undi(struct sw_undi *undi)
+{
+ int i;
+ printf("UNDI signature: %c%c%c%c\n",
+ undi->signature[0], undi->signature[1], undi->signature[2], undi->signature[3]);
+ printf("UNDI len: %hhx\n", undi->len);
+ printf("UNDI fudge: %hhx\n", undi->fudge);
+ printf("UNDI rev: %hhx\n", undi->rev);
+ printf("UNDI ifcnt: %hhx\n", undi->ifcnt);
+ printf("UNDI version: %d.%d\n", undi->major, undi->minor);
+ printf("UNDI implementation: %x\n", undi->implementation);
+ printf("UNDI entry point: %lx\n", undi->entry_point);
+ printf("UNDI bus type cnt: %d\n", undi->bus_type_cnt);
+ for(i = 0; i < undi->bus_type_cnt; i++) {
+ printf("UNDI bus type: %c%c%c%c\n",
+ ((undi->bus_type[i]) >> 0) & 0xff,
+ ((undi->bus_type[i]) >> 8) & 0xff,
+ ((undi->bus_type[i]) >> 16) & 0xff,
+ ((undi->bus_type[i]) >> 24) & 0xff);
+ }
+ printf("UNDI sum: %hhx\n", undi_checksum(undi));
+ printf("\n");
+}
+void print_init_info(struct db_init_info *info)
+{
+ printf("init_info.memory_required: %d\n", info->memory_required);
+ printf("init_info.frame_data_len: %d\n", info->frame_data_len);
+ printf("init_info.link_speeds: %d %d %d %d\n",
+ info->link_speeds[0], info->link_speeds[1],
+ info->link_speeds[2], info->link_speeds[3]);
+ printf("init_info.media_header_len: %d\n", info->media_header_len);
+ printf("init_info.hw_addr_len: %d\n", info->hw_addr_len);
+ printf("init_info.mcast_filter_cnt: %d\n", info->mcast_filter_cnt);
+ printf("init_info.tx_buf_cnt: %d\n", info->tx_buf_cnt);
+ printf("init_info.tx_buf_size: %d\n", info->tx_buf_size);
+ printf("init_info.rx_buf_cnt: %d\n", info->rx_buf_cnt);
+ printf("init_info.rx_buf_size: %d\n", info->rx_buf_size);
+ printf("init_info.if_type: %hhx\n", info->if_type);
+ printf("init_info.duplex: %hhx\n", info->duplex);
+ printf("init_info.loopback: %hhx\n", info->loopback);
+ printf("\n");
+}
+void print_config_info(struct db_config_info *info)
+{
+ int i;
+ printf("config_info.bus_type: %c%c%c%c\n",
+ ((info->pci.bus_type) >> 0) & 0xff,
+ ((info->pci.bus_type) >> 8) & 0xff,
+ ((info->pci.bus_type) >> 16) & 0xff,
+ ((info->pci.bus_type) >> 24) & 0xff);
+ if (info->pci.bus_type != UNDI_BUS_TYPE_PCI) {
+ return;
+ }
+ printf("config_info.bus: %hx\n", info->pci.bus);
+ printf("config_info.device: %hhx\n", info->pci.device);
+ printf("config_info.function: %hhx\n", info->pci.function);
+ printf("config_info.config:\n");
+ for(i = 0; i < 256; i++) {
+ if ((i & 0xf) == 0) {
+ printf("[%hhx]", i);
+ }
+ printf(" %hhx", info->pci.config[i]);
+ if ((i & 0xf) == 0xf) {
+ printf("\n");
+ }
+ }
+ printf("\n");
+
+}
+void print_cdb(struct cdb *cdb)
+{
+ printf("\n");
+ printf("cdb.op_code: %hx\n", cdb->op_code);
+ printf("cdb.op_flags: %hx\n", cdb->op_flags);
+ printf("cdb.cpb_size: %d\n", cdb->cpb_size);
+ printf("cdb.db_size: %d\n", cdb->db_size);
+ printf("cdb.cpb_addr: %lx\n", cdb->cpb_addr);
+ printf("cdb.db_addr: %lx\n", cdb->db_addr);
+ printf("cdb.stat_code: %lx\n", cdb->stat_code);
+ printf("cdb.stat_flags: %lx\n", cdb->stat_flags);
+ printf("cdb.ifnum %d\n", cdb->ifnum);
+ printf("cdb.control: %hx\n", cdb->control);
+ printf("\n");
+}
+#endif
+#define ARPHRD_ETHER 1
+static int nic_setup(struct dev *dev,
+ EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE *nii)
+{
+ struct nic *nic = (struct nic *)dev;
+ int result;
+ struct sw_undi *undi;
+ struct db_init_info init_info;
+ struct cpb_initialize cpb_initialize;
+ struct db_initialize db_initialize;
+ struct db_station_address db_station_address;
+ int media_detect;
+ unsigned filter, no_filter;
+ int i;
+
+ /* Fail if I I'm not passed a valid nii */
+ if (!nii)
+ return 0;
+
+ /* Fail if this nit a SW UNDI interface */
+ if (nii->ID == 0)
+ return 0;
+
+ undi = phys_to_virt(nii->ID);
+
+ /* Verify the undi structure */
+
+ /* It must have a pxe signature */
+ if (memcmp(undi->signature, "!PXE", 4) != 0)
+ return 0;
+ /* It must have a valid checksum */
+ if (undi_checksum(undi) != 0)
+ return 0;
+ /* It must be software undi */
+ if (undi->implementation & UNDI_IMP_HW_UNDI)
+ return 0;
+
+ /* Setup to do undi calls */
+ undi_ifnum = nii->IfNum;
+ undi_entry_point = (void *)undi->entry_point;
+
+ /* Find the UNDI state... */
+ result = get_state(&cdb);
+ if (!result)
+ return 0;
+
+ /* See if the device is already initialized */
+ if ((cdb.stat_flags & CDB_STATFLAGS_GET_STATE_MASK) !=
+ CDB_STATFLAGS_GET_STATE_STOPPED) {
+
+ /* If so attempt to stop it */
+ if ((cdb.stat_flags & CDB_STATFLAGS_GET_STATE_MASK) ==
+ CDB_STATFLAGS_GET_STATE_INITIALIZED) {
+ result = shutdown(&cdb);
+ result = stop(&cdb);
+ }
+ else if ((cdb.stat_flags & CDB_STATFLAGS_GET_STATE_MASK) ==
+ CDB_STATFLAGS_GET_STATE_STARTED) {
+ result = stop(&cdb);
+ }
+
+ /* See if it did stop */
+ result = get_state(&cdb);
+ if (!result)
+ return 0;
+
+ /* If it didn't stop give up */
+ if ((cdb.stat_flags & CDB_STATFLAGS_GET_STATE_MASK) !=
+ CDB_STATFLAGS_GET_STATE_STOPPED)
+ return 0;
+
+ }
+
+ result = start(&cdb);
+ if (!result) {
+ printf("Device would not start: %x\n", cdb.stat_code);
+ return 0;
+ }
+ result = get_init_info(&cdb, &init_info);
+ if (!result) {
+ printf("Device wount not give init info: %x\n", cdb.stat_code);
+ stop(&cdb);
+ return 0;
+ }
+ /* See if the NIC can detect the presence of a cable */
+ media_detect = (cdb.stat_flags & CDB_STATFLAGS_CABLE_DETECT_MASK) ==
+ CDB_STATFLAGS_CABLE_DETECT_SUPPORTED;
+
+ if ((init_info.if_type != ARPHRD_ETHER) ||
+ (init_info.hw_addr_len != ETH_ALEN)) {
+ printf("Not ethernet\n");
+ stop(&cdb);
+ return 0;
+ }
+ if (init_info.memory_required > sizeof(buffer)) {
+ printf("NIC wants %d bytes I only have %ld bytes\n",
+ init_info.memory_required, sizeof(buffer));
+ stop(&cdb);
+ return 0;
+ }
+ /* Initialize the device */
+ memset(buffer, 0, sizeof(buffer));
+ memset(&cpb_initialize, 0, sizeof(cpb_initialize));
+ cpb_initialize.memory_addr = virt_to_phys(&buffer);
+ cpb_initialize.memory_length = init_info.memory_required;
+ cpb_initialize.link_speed = 0; /* auto detect */
+ /* UNDI nics will not take suggestions :(
+ * So let them figure out an appropriate buffer stragety on their own.
+ */
+ cpb_initialize.tx_buf_cnt = 0;
+ cpb_initialize.tx_buf_size = 0;
+ cpb_initialize.rx_buf_cnt = 0;
+ cpb_initialize.rx_buf_size = 0;
+ cpb_initialize.duplex = 0;
+ cpb_initialize.loopback = 0;
+ result = initialize(&cdb, media_detect, &cpb_initialize, &db_initialize);
+ if (!result) {
+ printf("Device would not initialize: %x\n", cdb.stat_code);
+ stop(&cdb);
+ return 0;
+ }
+#if 0
+ /* It appears the memory_used parameter is never set correctly, ignore it */
+ if (db_initialize.memory_used > sizeof(buffer)) {
+ printf("NIC is using %d bytes I only have %ld bytes\n",
+ db_initialize.memory_used, sizeof(buffer));
+ printf("tx_buf_cnt: %d\n", db_initialize.tx_buf_cnt);
+ printf("tx_buf_size: %d\n", db_initialize.tx_buf_size);
+ printf("rx_buf_cnt: %d\n", db_initialize.rx_buf_cnt);
+ printf("rx_buf_size: %d\n", db_initialize.rx_buf_size);
+ nic_disable(dev);
+ return 0;
+ }
+ printf("NIC is using %d bytes\n",
+ db_initialize.memory_used);
+#endif
+ if (media_detect && (
+ (cdb.stat_flags & ~CDB_STATFLAGS_STATUS_MASK) ==
+ CDB_STATFLAGS_INITIALIZED_NO_MEDIA)) {
+ printf("No media present\n");
+ nic_disable(dev);
+ return 0;
+ }
+
+ /* Get the mac address */
+ result = station_address_read(&cdb, &db_station_address);
+ if (!result) {
+ printf("Could not read station address: %x\n",
+ cdb.stat_code);
+ nic_disable(dev);
+ return 0;
+ }
+ for(i = 0; i < ETH_ALEN; i++) {
+ nic->node_addr[i] = db_station_address.station_address[i];
+ }
+ printf("Ethernet addr: %!\n", nic->node_addr);
+
+ filter = CDB_OPFLAGS_RECEIVE_FILTER_ENABLE |
+ CDB_OPFLAGS_RECEIVE_FILTER_UNICAST |
+ CDB_OPFLAGS_RECEIVE_FILTER_BROADCAST;
+ no_filter = CDB_OPFLAGS_RECEIVE_FILTER_DISABLE |
+ CDB_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST |
+ CDB_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+
+ if (undi->implementation & UNDI_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {
+ filter |= CDB_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+ no_filter |= CDB_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
+ }
+ else if (undi->implementation & UNDI_IMP_PROMISCUOUS_RX_SUPPORTED) {
+ filter |= CDB_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
+ }
+
+ result = receive_filters(&cdb, no_filter);
+ if (!result) {
+ printf("Could not clear receive filters: %x\n",
+ cdb.stat_code);
+ nic_disable(dev);
+ return 0;
+ }
+ result = receive_filters(&cdb, filter);
+ if (!result) {
+ printf("Could not set receive filters: %x\n",
+ cdb.stat_code);
+ nic_disable(dev);
+ return 0;
+ }
+
+ /* It would be nice to call get_config_info so I could pass
+ * the type of nic, but that crashes some efi drivers.
+ */
+ /* Everything worked! */
+ dev->disable = nic_disable;
+ nic->poll = nic_poll;
+ nic->transmit = nic_transmit;
+
+ return 1;
+}
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+static int nic_probe(struct dev *dev, unsigned short *dummy __unused)
+{
+ EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE *nii;
+ int index;
+ int result;
+
+ index = dev->index+ 1;
+ if (dev->how_probe == PROBE_AWAKE) {
+ index--;
+ }
+ for(result = 0; !result && (nii = lookup_efi_nic(index)); index++) {
+ result = nic_setup(dev, nii);
+ if (result) {
+ break;
+ }
+ }
+ dev->index = result ? index : -1;
+ return result;
+}
+
+
+
+
+static struct isa_driver nic_driver __isa_driver = {
+ .type = NIC_DRIVER,
+ .name = "undi_nii",
+ .probe = nic_probe,
+ .ioaddrs = 0,
+};
diff --git a/src/arch/ia64/include/bits/byteswap.h b/src/arch/ia64/include/bits/byteswap.h
new file mode 100644
index 000000000..a8a115850
--- /dev/null
+++ b/src/arch/ia64/include/bits/byteswap.h
@@ -0,0 +1,36 @@
+#ifndef ETHERBOOT_BITS_BYTESWAP_H
+#define ETHERBOOT_BITS_BYTESWAP_H
+
+static inline uint64_t __ia64_bswap_64(uint64_t x)
+{
+ uint64_t result;
+ __asm__ volatile(
+ "mux1 %0=%1,@rev" :
+ "=r" (result)
+ : "r" (x));
+ return result;
+}
+
+#define __bswap_constant_16(x) \
+ ((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
+ (((uint16_t)(x) & 0xff00) >> 8)))
+
+#define __bswap_constant_32(x) \
+ ((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \
+ (((uint32_t)(x) & 0x0000ff00U) << 8) | \
+ (((uint32_t)(x) & 0x00ff0000U) >> 8) | \
+ (((uint32_t)(x) & 0xff000000U) >> 24)))
+
+#define __bswap_16(x) \
+ (__builtin_constant_p(x) ? \
+ __bswap_constant_16(x) : \
+ (__ia64_bswap_64(x) >> 48))
+
+
+#define __bswap_32(x) \
+ (__builtin_constant_p(x) ? \
+ __bswap_constant_32(x) : \
+ (__ia64_bswap_64(x) >> 32))
+
+
+#endif /* ETHERBOOT_BITS_BYTESWAP_H */
diff --git a/src/arch/ia64/include/bits/cpu.h b/src/arch/ia64/include/bits/cpu.h
new file mode 100644
index 000000000..d8fe1cbbe
--- /dev/null
+++ b/src/arch/ia64/include/bits/cpu.h
@@ -0,0 +1,6 @@
+#ifndef IA64_BITS_CPU_H
+#define IA64_BITS_CPU_H
+
+#define cpu_setup() do {} while(0)
+
+#endif /* IA64_BITS_CPU_H */
diff --git a/src/arch/ia64/include/bits/elf.h b/src/arch/ia64/include/bits/elf.h
new file mode 100644
index 000000000..c68f8456f
--- /dev/null
+++ b/src/arch/ia64/include/bits/elf.h
@@ -0,0 +1,11 @@
+#ifndef IA64_BITS_ELF_H
+#define IA64_BITS_ELF_H
+
+/* ELF Defines for the current architecture */
+#define EM_CURRENT EM_IA_64
+#define ELFDATA_CURRENT ELFDATA2LSB
+
+#define ELF_CHECK_ARCH(x) \
+ ((x).e_machine == EM_CURRENT)
+
+#endif /* IA64_BITS_ELF_H */
diff --git a/src/arch/ia64/include/bits/endian.h b/src/arch/ia64/include/bits/endian.h
new file mode 100644
index 000000000..413e702db
--- /dev/null
+++ b/src/arch/ia64/include/bits/endian.h
@@ -0,0 +1,6 @@
+#ifndef ETHERBOOT_BITS_ENDIAN_H
+#define ETHERBOOT_BITS_ENDIAN_H
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#endif /* ETHERBOOT_BITS_ENDIAN_H */
diff --git a/src/arch/ia64/include/bits/string.h b/src/arch/ia64/include/bits/string.h
new file mode 100644
index 000000000..31e94b7d3
--- /dev/null
+++ b/src/arch/ia64/include/bits/string.h
@@ -0,0 +1,6 @@
+#ifndef ETHERBOOT_BITS_STRING_H
+#define ETHERBOOT_BITS_STRING_H
+
+/* define inline optimized string functions here */
+
+#endif /* ETHERBOOT_BITS_STRING_H */
diff --git a/src/arch/ia64/include/hooks.h b/src/arch/ia64/include/hooks.h
new file mode 100644
index 000000000..d8f1f06a1
--- /dev/null
+++ b/src/arch/ia64/include/hooks.h
@@ -0,0 +1,12 @@
+#ifndef ETHERBOOT_IA64_HOOKS_H
+#define ETHERBOOT_IA64_HOOKS_H
+
+#include <stdarg.h>
+
+void arch_main(in_call_data_t *data, va_list params);
+void arch_on_exit(int status);
+void arch_relocate_to(unsigned long addr);
+#define arch_relocated_from(old_addr) do {} while(0)
+
+
+#endif /* ETHERBOOT_IA64_HOOKS_H */
diff --git a/src/arch/ia64/include/io.h b/src/arch/ia64/include/io.h
new file mode 100644
index 000000000..be5a5ce16
--- /dev/null
+++ b/src/arch/ia64/include/io.h
@@ -0,0 +1,228 @@
+#ifndef ETHERBOOT_IO_H
+#define ETHERBOOT_IO_H
+
+/* Don't require identity mapped physical memory,
+ * osloader.c is the only valid user at the moment.
+ */
+static inline unsigned long virt_to_phys(volatile const void *virt_addr)
+{
+ return ((unsigned long)virt_addr);
+}
+
+static inline void *phys_to_virt(unsigned long phys_addr)
+{
+ return (void *)(phys_addr);
+}
+
+/* virt_to_bus converts an addresss inside of etherboot [_start, _end]
+ * into a memory address cards can use.
+ */
+#define virt_to_bus virt_to_phys
+
+
+/* bus_to_virt reverses virt_to_bus, the address must be output
+ * from virt_to_bus to be valid. This function does not work on
+ * all bus addresses.
+ */
+#define bus_to_virt phys_to_virt
+
+/* ioremap converts a random 32bit bus address into something
+ * etherboot can access.
+ */
+static inline void *ioremap(unsigned long bus_addr, unsigned long length __unused)
+{
+ return bus_to_virt(bus_addr);
+}
+
+/* iounmap cleans up anything ioremap had to setup */
+static inline void iounmap(void *virt_addr __unused)
+{
+ return;
+}
+
+/* In physical mode the offset of uncached pages */
+#define PHYS_BASE (0x8000000000000000UL)
+
+/* Memory mapped IO primitives, we avoid the cache... */
+static inline uint8_t readb(unsigned long addr)
+{
+ return *((volatile uint8_t *)(PHYS_BASE | addr));
+}
+
+static inline uint16_t readw(unsigned long addr)
+{
+ return *((volatile uint16_t *)(PHYS_BASE | addr));
+}
+
+static inline uint32_t readl(unsigned long addr)
+{
+ return *((volatile uint32_t *)(PHYS_BASE | addr));
+}
+
+static inline uint64_t readq(unsigned long addr)
+{
+ return *((volatile uint64_t *)(PHYS_BASE | addr));
+}
+
+
+static inline void writeb(uint8_t val, unsigned long addr)
+{
+ *((volatile uint8_t *)(PHYS_BASE | addr)) = val;
+}
+
+static inline void writew(uint16_t val, unsigned long addr)
+{
+ *((volatile uint16_t *)(PHYS_BASE | addr)) = val;
+}
+
+static inline void writel(uint32_t val, unsigned long addr)
+{
+ *((volatile uint32_t *)(PHYS_BASE | addr)) = val;
+}
+
+static inline void writeq(uint64_t val, unsigned long addr)
+{
+ *((volatile uint64_t *)(PHYS_BASE | addr)) = val;
+}
+
+
+static inline void memcpy_fromio(void *dest, unsigned long src, size_t n)
+{
+ size_t i;
+ uint8_t *dp = dest;
+ for(i = 0; i < n; i++) {
+ *dp = readb(src);
+ dp++;
+ src++;
+ }
+}
+
+static inline void memcpy_toio(unsigned long dest , const void *src, size_t n)
+{
+ size_t i;
+ const uint8_t *sp = src;
+ for(i = 0; i < n; i++) {
+ writeb(*sp, dest);
+ sp++;
+ dest++;
+ }
+}
+
+/* IO space IO primitives, Itanium has a strange architectural mapping... */
+extern unsigned long io_base;
+#define __ia64_mf_a() __asm__ __volatile__ ("mf.a" ::: "memory")
+#define __ia64_io_addr(port) ((void *)(PHYS_BASE | io_base | (((port) >> 2) << 12) | ((port) & 0xfff)))
+
+static inline uint8_t inb(unsigned long port)
+{
+ uint8_t result;
+
+ result = *((volatile uint8_t *)__ia64_io_addr(port));
+ __ia64_mf_a();
+ return result;
+}
+
+static inline uint16_t inw(unsigned long port)
+{
+ uint8_t result;
+ result = *((volatile uint16_t *)__ia64_io_addr(port));
+ __ia64_mf_a();
+ return result;
+}
+
+static inline uint32_t inl(unsigned long port)
+{
+ uint32_t result;
+ result = *((volatile uint32_t *)__ia64_io_addr(port));
+ __ia64_mf_a();
+ return result;
+}
+
+static inline void outb(uint8_t val, unsigned long port)
+{
+ *((volatile uint8_t *)__ia64_io_addr(port)) = val;
+ __ia64_mf_a();
+}
+
+static inline void outw(uint16_t val, unsigned long port)
+{
+ *((volatile uint16_t *)__ia64_io_addr(port)) = val;
+ __ia64_mf_a();
+}
+
+static inline void outl(uint32_t val, unsigned long port)
+{
+ *((volatile uint32_t *)__ia64_io_addr(port)) = val;
+ __ia64_mf_a();
+}
+
+
+
+static inline void insb(unsigned long port, void *dst, unsigned long count)
+{
+ volatile uint8_t *addr = __ia64_io_addr(port);
+ uint8_t *dp = dst;
+ __ia64_mf_a();
+ while(count--)
+ *dp++ = *addr;
+ __ia64_mf_a();
+}
+
+static inline void insw(unsigned long port, void *dst, unsigned long count)
+{
+ volatile uint16_t *addr = __ia64_io_addr(port);
+ uint16_t *dp = dst;
+ __ia64_mf_a();
+ while(count--)
+ *dp++ = *addr;
+ __ia64_mf_a();
+}
+
+static inline void insl(unsigned long port, void *dst, unsigned long count)
+{
+ volatile uint32_t *addr = __ia64_io_addr(port);
+ uint32_t *dp = dst;
+ __ia64_mf_a();
+ while(count--)
+ *dp++ = *addr;
+ __ia64_mf_a();
+}
+
+static inline void outsb(unsigned long port, void *src, unsigned long count)
+{
+ const uint8_t *sp = src;
+ volatile uint8_t *addr = __ia64_io_addr(port);
+
+ while (count--)
+ *addr = *sp++;
+ __ia64_mf_a();
+}
+
+static inline void outsw(unsigned long port, void *src, unsigned long count)
+{
+ const uint16_t *sp = src;
+ volatile uint16_t *addr = __ia64_io_addr(port);
+
+ while (count--)
+ *addr = *sp++;
+ __ia64_mf_a();
+}
+
+static inline void outsl(unsigned long port, void *src, unsigned long count)
+{
+ const uint32_t *sp = src;
+ volatile uint32_t *addr = __ia64_io_addr(port);
+
+ while (count--)
+ *addr = *sp++;
+ __ia64_mf_a();
+}
+
+static inline unsigned long ia64_get_kr0(void)
+{
+ unsigned long r;
+ asm volatile ("mov %0=ar.k0" : "=r"(r));
+ return r;
+}
+
+#endif /* ETHERBOOT_IO_H */
diff --git a/src/arch/ia64/include/latch.h b/src/arch/ia64/include/latch.h
new file mode 100644
index 000000000..87195b427
--- /dev/null
+++ b/src/arch/ia64/include/latch.h
@@ -0,0 +1,11 @@
+#ifndef LATCH_H
+#define LATCH_H
+
+#define TICKS_PER_SEC (1000UL)
+
+/* Fixed timer interval used for calibrating a more precise timer */
+#define LATCHES_PER_SEC 10
+
+void sleep_latch(void);
+
+#endif /* LATCH_H */
diff --git a/src/arch/ia64/include/limits.h b/src/arch/ia64/include/limits.h
new file mode 100644
index 000000000..0c6f21f9e
--- /dev/null
+++ b/src/arch/ia64/include/limits.h
@@ -0,0 +1,57 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 9223372036854775807L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 18446744073709551615UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/src/arch/ia64/include/pal.h b/src/arch/ia64/include/pal.h
new file mode 100644
index 000000000..6cda19d18
--- /dev/null
+++ b/src/arch/ia64/include/pal.h
@@ -0,0 +1,11 @@
+#ifndef IA64_PAL_H
+#define IA64_PAL_H
+
+struct pal_freq_ratio {
+ unsigned long den : 32, num : 32; /* numerator & denominator */
+};
+extern long pal_freq_ratios(struct pal_freq_ratio *proc_ratio,
+ struct pal_freq_ratio *bus_ratio, struct pal_freq_ratio *itc_ratio);
+
+
+#endif /* IA64_PAL_H */
diff --git a/src/arch/ia64/include/sal.h b/src/arch/ia64/include/sal.h
new file mode 100644
index 000000000..7a1b57ece
--- /dev/null
+++ b/src/arch/ia64/include/sal.h
@@ -0,0 +1,29 @@
+#ifndef IA64_SAL_H
+#define IA64_SAL_H
+
+struct fptr {
+ unsigned long entry;
+ unsigned long gp;
+};
+extern struct fptr sal_entry;
+extern struct fptr pal_entry;
+extern int parse_sal_system_table(void *table);
+
+#define SAL_FREQ_BASE_PLATFORM 0
+#define SAL_FREQ_BASE_INTERVAL_TIMER 1
+#define SAL_FREQ_BASE_REALTIME_CLOCK 2
+
+long sal_freq_base (unsigned long which, unsigned long *ticks_per_second,
+ unsigned long *drift_info);
+
+#define PCI_SAL_ADDRESS(seg, bus, dev, fn, reg) \
+ ((unsigned long)(seg << 24) | (unsigned long)(bus << 16) | \
+ (unsigned long)(dev << 11) | (unsigned long)(fn << 8) | \
+ (unsigned long)(reg))
+
+long sal_pci_config_read (
+ unsigned long pci_config_addr, unsigned long size, unsigned long *value);
+long sal_pci_config_write (
+ unsigned long pci_config_addr, unsigned long size, unsigned long value);
+
+#endif /* IA64_SAL_H */
diff --git a/src/arch/ia64/include/setjmp.h b/src/arch/ia64/include/setjmp.h
new file mode 100644
index 000000000..a1fac2dcb
--- /dev/null
+++ b/src/arch/ia64/include/setjmp.h
@@ -0,0 +1,13 @@
+#ifndef ETHERBOOT_SETJMP_H
+#define ETHERBOOT_SETJMP_H
+
+
+/* Define a type for use by setjmp and longjmp */
+#define JBLEN 70
+
+typedef long jmp_buf[JBLEN] __attribute__ ((aligned (16))); /* guarantees 128-bit alignment! */
+
+extern int setjmp (jmp_buf env);
+extern void longjmp (jmp_buf env, int val);
+
+#endif /* ETHERBOOT_SETJMP_H */
diff --git a/src/arch/ia64/include/stdint.h b/src/arch/ia64/include/stdint.h
new file mode 100644
index 000000000..2f9c592c3
--- /dev/null
+++ b/src/arch/ia64/include/stdint.h
@@ -0,0 +1,16 @@
+#ifndef STDINT_H
+#define STDINT_H
+
+typedef unsigned long size_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long int64_t;
+
+#endif /* STDINT_H */
diff --git a/src/arch/ia64/prefix/apply_efi_prefix.pl b/src/arch/ia64/prefix/apply_efi_prefix.pl
new file mode 100755
index 000000000..999c43b43
--- /dev/null
+++ b/src/arch/ia64/prefix/apply_efi_prefix.pl
@@ -0,0 +1,63 @@
+#!/usr/bin/perl -w
+#
+# Program to apply an efi header to an ia64 etherboot file.
+#
+# GPL Eric Biederman 2002
+#
+
+use strict;
+
+use bytes;
+
+main(@ARGV);
+
+sub usage
+{
+ my ($err) = @_;
+ print STDERR $err , "\n";
+ die "Usage $0 prrefix file bss_size\n";
+}
+sub main
+{
+ my ($prefix_name, $suffix_name, $bss_size) = @_;
+ usage("No prefix") unless (defined($prefix_name));
+ usage("No suffix") unless (defined($suffix_name));
+ usage("No bss size") unless (defined($bss_size));
+
+ open(PREFIX, "<$prefix_name") or die "Cannot open $prefix_name";
+ open(SUFFIX, "<$suffix_name") or die "Cannot open $suffix_name";
+
+ $/ = undef;
+ my $prefix = <PREFIX>; close(PREFIX);
+ my $suffix = <SUFFIX>; close(SUFFIX);
+
+ # Payload sizes.
+ my $payload_size = length($suffix);
+ my $payload_bss = $bss_size;
+
+ # Update the image size
+ my $hdr_off = unpack("V",substr($prefix, 0x3c, 4));
+ my $image_size_off = 0x050 + $hdr_off;
+ my $img_mem_size_off = 0x0c0 + $hdr_off;
+ my $img_size_off = 0x0c8 + $hdr_off;
+
+ my $image_size = unpack("V", substr($prefix, $image_size_off, 4));
+ my $img_mem_size = unpack("V", substr($prefix, $img_mem_size_off, 4));
+ my $img_size = unpack("V", substr($prefix, $img_size_off, 4));
+
+ $image_size += $payload_size + $payload_bss;
+ $img_mem_size += $payload_size + $payload_bss;
+ $img_size += $payload_size;
+
+ substr($prefix, $image_size_off, 4) = pack("V", $image_size);
+ substr($prefix, $img_mem_size_off, 4) = pack("V", $img_mem_size);
+ substr($prefix, $img_size_off, 4) = pack("V", $img_size);
+
+ #print(STDERR "image_size: $image_size\n");
+ #print(STDERR "img_mem_size: $img_mem_size\n");
+ #print(STDERR "img_size: $img_size\n");
+
+ print $prefix;
+ print $suffix;
+}
+
diff --git a/src/arch/ia64/prefix/apply_unnrv2b_prefix.pl b/src/arch/ia64/prefix/apply_unnrv2b_prefix.pl
new file mode 100644
index 000000000..71b2b247e
--- /dev/null
+++ b/src/arch/ia64/prefix/apply_unnrv2b_prefix.pl
@@ -0,0 +1,198 @@
+#!/usr/bin/perl -w
+#
+# Program to apply an unnrv2b decompressor header to an ia64 etherboot file.
+#
+# GPL Eric Biederman 2002
+#
+
+use strict;
+
+use bytes;
+
+main(@ARGV);
+
+sub usage
+{
+ my ($err) = @_;
+ print STDERR $err , "\n";
+ die "Usage $0 prefix file\n";
+}
+
+sub getbits
+{
+ my ($bundle, $start, $size) = @_;
+
+ # Compute the mask
+ my $mask = 0xffffffff;
+ $mask = $mask >> (32 - $size);
+
+ # Compute the substring, and shift
+ my ($first, $end, $count, $shift);
+ $first = int($start / 8);
+ $end = int(($start + $size + 7)/8);
+ $count = $end - $first;
+ $shift = $start % 8;
+
+ # Compute the unpack type
+ my $type;
+ if ($count == 1) {
+ $type = "C"
+ }
+ elsif ($count == 2) {
+ $type = "v";
+ }
+ elsif (($count >= 3) && ($count <= 4)) {
+ $type = "V";
+ }
+ else {
+ die "bad count $count";
+ }
+
+ # Now compute the value
+ my $val = (unpack($type, substr($bundle, $first, $count)) >> $shift) & $mask;
+
+ # Now return the value
+ return $val;
+}
+
+sub putbits
+{
+ my ($bundle, $start, $size, $val) = @_;
+
+
+ # Compute the mask
+ my $mask = 0xffffffff;
+ $mask >>= 32 - $size;
+
+ # Compute the substring, and shift
+ my ($first, $end, $count, $shift);
+ $first = int($start / 8);
+ $end = int(($start + $size + 7)/8);
+ $count = $end - $first;
+ $shift = $start % 8;
+
+ # Compute the unpack type
+ my $type;
+ if ($count == 1) {
+ $type = "C"
+ }
+ elsif ($count == 2) {
+ $type = "v";
+ }
+ elsif (($count >= 3) && ($count <= 4)) {
+ $type = "V";
+ }
+ else {
+ die "bad count $count";
+ }
+
+ # Adjust the mask
+ $mask <<= $shift;
+
+ # Now set the value, preserving the untouched bits
+ substr($bundle, $first, $count) =
+ pack($type,
+ ((unpack($type, substr($bundle, $first, $count)) & ~$mask) |
+ (($val << $shift) & $mask)));
+
+ # Now return the new value;
+ return $bundle;
+}
+
+sub main
+{
+ my ($prefix_name, $suffix_name) = @_;
+ usage("No prefix") unless (defined($prefix_name));
+ usage("No suffix") unless (defined($suffix_name));
+
+ open(PREFIX, "<$prefix_name") or die "Cannot open $prefix_name";
+ open(SUFFIX, "<$suffix_name") or die "Cannot open $suffix_name";
+
+ $/ = undef;
+ my $prefix = <PREFIX>; close(PREFIX);
+ my $suffix = <SUFFIX>; close(SUFFIX);
+
+ # Payload sizes
+ my $prefix_len = length($prefix);
+ my $suffix_len = length($suffix);
+ my $payload_size = $suffix_len;
+ my $uncompressed_offset = ($prefix_len + $suffix_len + 15) & ~15;
+ my $pad = $uncompressed_offset - ($prefix_len + $suffix_len);
+
+ # Itaninum instruction bundle we will be updating
+ # 0 - 4 template == 5
+ # 5 - 45 slot 0 M-Unit
+ # 46 - 86 slot 1 L-Unit
+ # 87 - 127 slot 2 X-Unit
+ # Itaninum instruction format
+ # 40 - 37 Major opcode
+ # ...
+ #
+
+ # slot 1
+ # 0 - 40 [41] imm-41
+ # 10 - 40 [31] imm-41-hi
+ # 0 - 9 [10] imm-41-lo
+
+ # slot 2
+ # 0 - 5 [6] qp
+ # 6 - 12 [7] r1
+ # 13 - 19 [7] imm-7b
+ # 20 [1] vc
+ # 21 [1] immc
+ # 22 - 26 [5] imm-5c
+ # 27 - 35 [9] imm-9d
+ # 36 [1] imm0
+ # 37 - 40 [4] major opcode
+ #
+
+ # major opcode should be 6
+
+ # Update the image size
+ my $uncompressed_offset_bundle_off = 16;
+ my $bundle = substr($prefix, $uncompressed_offset_bundle_off, 16);
+
+ my $template = getbits($bundle, 0, 5);
+ my $op1_base = 46;
+ my $op2_base = 87;
+ my $major_opcode = getbits($bundle, 37 + $op2_base, 4);
+
+ if (($template != 5) ||
+ ($major_opcode != 6)) {
+ die "unknown second bundle cannot patch";
+ }
+
+ die "uncompressed_offset to big!\n" if ($uncompressed_offset > 0xffffffff);
+ my $immhi = 0;
+ my $immlo = $uncompressed_offset;
+
+ my $imm0 = ($immhi >> 31) & ((1 << 1) - 1);
+ my $imm41_hi = ($immhi >> 0) & ((1 << 31) - 1);
+
+ my $imm41_lo = ($immlo >> 22) & ((1 << 10) - 1);
+ my $immc = ($immlo >> 21) & ((1 << 1) - 1);
+ my $imm5c = ($immlo >> 16) & ((1 << 5) - 1);
+ my $imm9d = ($immlo >> 7) & ((1 << 9) - 1);
+ my $imm7b = ($immlo >> 0) & ((1 << 7) - 1);
+
+ $bundle = putbits($bundle, 10 + $op1_base, 31, $imm41_hi);
+ $bundle = putbits($bundle, 0 + $op1_base, 10, $imm41_lo);
+ $bundle = putbits($bundle, 36 + $op2_base, 1 , $imm0);
+ $bundle = putbits($bundle, 27 + $op2_base, 9 , $imm9d);
+ $bundle = putbits($bundle, 22 + $op2_base, 5 , $imm5c);
+ $bundle = putbits($bundle, 21 + $op2_base, 1 , $immc);
+ $bundle = putbits($bundle, 13 + $op2_base, 7 , $imm7b);
+
+ substr($prefix, $uncompressed_offset_bundle_off, 16) = $bundle;
+
+ #print (STDERR "prefix: $prefix_len\n");
+ #print (STDERR "suffix: $suffix_len\n");
+ #print (STDERR "pad: $pad\n");
+ #print (STDERR "uncompressed_offset: $uncompressed_offset\n");
+
+ print $prefix;
+ print $suffix;
+ # Pad the resulting image by a few extra bytes...
+ print pack("C", 0) x $pad;
+}
+
diff --git a/src/arch/ia64/prefix/efi_prefix.S b/src/arch/ia64/prefix/efi_prefix.S
new file mode 100644
index 000000000..1fb1501f2
--- /dev/null
+++ b/src/arch/ia64/prefix/efi_prefix.S
@@ -0,0 +1,195 @@
+#include "elf.h"
+ .explicit
+
+ .section ".hdrs", "a"
+ /* First the DOS file header */
+
+
+dos_header:
+ .byte 'M', 'Z' /* Signature */
+ .short dos_program_end - dos_program /* Length of image mod 512 bytes*/
+ .short 0x0001 /* Length of image in 512 byte pages */ /* FIXME */
+ .short 0x0000 /* Number of relocation items following header */
+ .short (dos_header_end - dos_header)/16 /* Size of header in 16 byte paragraphs */
+ .short 0x0001 /* Minimum number of paragraphs needed to run image */
+ .short 0x0001 /* Maximum number of paragraphs program would like */
+ .short 0x0000 /* Initial SS */
+
+ .short 0x00b8 /* Initial SP */
+ .short 0x0000 /* Negative checksum of image */
+ .short 0x0000 /* Initial IP */
+ .short 0x0000 /* Initial CS */
+ .short 0x0010 /* Offset in EXEC of first relocation item */
+ .short 0x0000 /* Overlay number */
+
+ .balign 16
+dos_header_end:
+dos_program:
+ .byte 0xdb /* retf */
+ .balign 16
+dos_program_end:
+ .org 0x3c
+ .byte pe_signature - dos_header, 0x00, 0x00, 0x00
+ .org 0x40 /* NOTE: set this to 0x80 for debugging, 0x40 otherwise */
+pe_signature:
+ .byte 'P', 'E', 0, 0
+coff_header:
+#define IMAGE_MACHINE_IA64 0x0200
+coff_machine: .short IMAGE_MACHINE_IA64
+coff_nsections: .short (section_headers_end - section_headers)/40
+coff_timdat: .int 1038168747 /* Sun Nov 24 12:12:27 2002 */
+coff_symptr: .int 0x00000000
+
+coff_nsyms: .int 0x00000000
+coff_opthdr: .short pe_end - pe_header
+#define CF_RELOC_STRIPPED 0x0001
+#define CF_EXECUTABLE 0x0002
+#define CF_LINE_STRIPPED 0x0004
+#define CF_LOCAL_STRIPPED 0x0008
+#define CF_DEBUG_STRIPPED 0x0206
+coff_flags: .short CF_EXECUTABLE | CF_LINE_STRIPPED | CF_LOCAL_STRIPPED | CF_DEBUG_STRIPPED
+
+ /* Option header */
+pe_header:
+pe_magic: .short 0x020b /* 020b or 010b? */
+pe_linker: .byte 0x02, 0x38
+pe_text_size: .int _text_size
+pe_data_size: .int _data_size
+pe_bss_size: .int _bss_size
+pe_entry: .int _start_plabel_rva
+pe_text_base: .int _text_rva
+pe_image_base: .quad _image_base
+pe_sec_align: .int _sect_align
+pe_file_align: .int _file_align
+pe_os_major: .short 0
+pe_os_minor: .short 0
+pe_image_major: .short 0
+pe_image_minro: .short 0
+pe_sub_major: .short 0
+pe_sub_minor: .short 0
+pe_reserved: .int 0
+pe_image_size: .int _image_size
+pe_hdrs_size: .int _hdrs_size
+pe_checksum: .int 0 /* FIXME how do I compute the checksum, unnecessary */
+#define SUBSYS_EFI_APP 10
+#define SUBSYS_EFI_BOOT_SERVICE_DRIVER 11
+#define SUBSYS_EFI_RUNTIME_DRIVER 12
+pe_subsys: .short SUBSYS_EFI_APP
+pe_dll_flags: .short 0
+pe_stack_res: .quad 0
+pe_stack_commit:.quad 0
+pe_heap_res: .quad 0
+pe_heap_commit: .quad 0
+pe_ld_flags: .int 0
+pe_rvas: .int (rvas_end - rvas_start)/8
+
+rvas_start:
+rva_0_rva: .int 0
+rva_0_size: .int 0
+rva_1_rva: .int 0
+rva_1_size: .int 0
+rva_2_rva: .int 0
+rva_2_size: .int 0
+rva_3_rva: .int 0
+rva_3_size: .int 0
+rva_4_rva: .int 0
+rva_4_size: .int 0
+rva_5_rva: .int _reloc_rva
+rva_5_size: .int __reloc_size
+rvas_end:
+pe_end:
+
+section_headers:
+#define SCN_CNT_CODE 0x00000020
+#define SCN_CNT_INITIALIZED_DATA 0x00000040
+#define SCN_CNT_UNINITIALIZED_DATA 0x00000080
+#define SCN_MEM_DISCARDABLE 0x02000000
+#define SCN_MEM_SHARED 0x10000000
+#define SCN_MEM_EXECUTE 0x20000000
+#define SCN_MEM_READ 0x40000000
+#define SCN_MEM_WRITE 0x80000000
+
+sec1_name: .byte '.', 'i', 'm', 'g', 0 , 0, 0, 0
+sec1_virt_size: .int _img_mem_size
+sec1_virt_addr: .int _img_rva
+sec1_file_size: .int _img_size
+sec1_file_off: .int _img_off
+sec1_reloc_off: .int 0
+sec1_line_off: .int 0
+sec1_reloc_cnt: .short 0
+sec1_line_cnt: .short 0
+sec1_flags: .int SCN_CNT_CODE | SCN_CNT_INITIALIZED_DATA \
+ | SCN_MEM_EXECUTE | SCN_MEM_READ | SCN_MEM_WRITE
+
+section_headers_end:
+
+ .text
+ .psr abi64
+ .psr lsb
+ .global _start
+_start:
+ {
+ alloc r8=ar.pfs,2,0,0,0
+ mov gp=ip /* Get the address of _start/_text/__gp */
+ }
+ ;;
+ add r14=@gprel(n1_desc),gp
+ add r15=@gprel(n2_desc),gp
+ add r16=@gprel(bhdr),gp
+ ;;
+ st8 [r14]=in0
+ st8 [r15]=in1
+ ;;
+ mov ar.pfs=r8
+ ;;
+ mov r32=r16
+ ;;
+ br.sptk.few _payload_start
+
+ .data
+ .global _start_plabel
+ .balign 16
+_start_plabel:
+ .quad _start
+ .quad 0 /* I don't need a gp value... */
+
+ /* hand-crafted bhdr and parameters */
+ .balign 16
+bhdr:
+b_signature: .int 0x0E1FB007
+b_size: .int bhdr_end - bhdr
+b_checksum: .short 0
+b_records: .short 3
+ /* A NOP note to 64bit align later data */
+ .balign 4
+n0_namesz: .int 0
+n0_descsz: .int 0
+n0_type: .int EBN_NOP
+ .balign 4
+n1_namesz: .int 10
+n1_descsz: .int 8
+n1_type: .int EB_IA64_IMAGE_HANDLE
+n1_name: .asciz "Etherboot"
+ .balign 4
+n1_desc: .quad 0
+ .balign 4
+n2_namesz: .int 10
+n2_descsz: .int 8
+n2_type: .int EB_IA64_SYSTAB
+n2_name: .asciz "Etherboot"
+ .balign 4
+n2_desc: .quad 0
+bhdr_end:
+
+
+ /* hand-craft a .reloc section for the plabel */
+#define IMAGE_REL_BASED_ABS 0
+#define IMAGE_REL_BASED_DIR64 10
+
+ .section ".reloc", "a"
+ .int _start_plabel_rva // PAGE RVA
+ .int 12 // Block Size (2*4+2*2)
+ .short (IMAGE_REL_BASED_DIR64<<12) + 0 // reloc for plabel's entry point
+ .short (IMAGE_REL_BASED_ABS <<12) + 0 // dummy reloc for good alignment
+
+
diff --git a/src/arch/ia64/prefix/efi_prefix.lds b/src/arch/ia64/prefix/efi_prefix.lds
new file mode 100644
index 000000000..aa71ea2e7
--- /dev/null
+++ b/src/arch/ia64/prefix/efi_prefix.lds
@@ -0,0 +1,91 @@
+/* OUTPUT_FORMAT("binary") */
+OUTPUT_FORMAT("elf64-ia64-little")
+
+OUTPUT_ARCH(ia64)
+
+ENTRY(_start_plabel)
+_sect_align = 16; /* normally 512 */
+_file_align = 16; /* normally 4096 */
+/* Symbols for hardcoding the payload and _bss size, with apply_efi_prefix
+ * there is no need to set these, and in will get confused if these are not 0.
+ */
+_payload_size = 0;
+_payload_bss = 0;
+SECTIONS {
+ /* We can arbitrarily set image base to anything we want,
+ * but efi does not honor it, so it is a pointless exercise.
+ * So we just set the start address to 0.
+ */
+ . = 0;
+ _link_base = . ;
+ _image_base = . ;
+ .hdrs : {
+ _hdrs = . ;
+ *(.hdrs)
+ . = ALIGN(_file_align) ;
+ _ehdrs = . ;
+ }
+ . = ALIGN(_sect_align);
+ .img : {
+ _img = . ;
+ _text = . ;
+ __gp = . ;
+ *(.text)
+ _etext = .;
+ . = ALIGN(16);
+ _data = . ;
+ *(.data)
+ _edata = .;
+ . = ALIGN(16);
+ _reloc = . ;
+ *(.reloc)
+ __ereloc = . ;
+ _ereloc = . ;
+ . = ALIGN(16);
+ /* . = ALIGN(_file_align) ; */
+ }
+ _payload_start = . ;
+ . = . + _payload_size ;
+ _payload_end = . ;
+ _eimg = . ;
+ . = ALIGN(_sect_align) ;
+ _bss = . ;
+ .bss : {
+ *(.bss)
+ . = . + _payload_bss;
+ }
+ _ebss = . ;
+ _end = . ;
+ /DISCARD/ : {
+ *(*)
+ }
+
+ _hdrs_size = _ehdrs - _hdrs;
+ _hdrs_off = 0;
+
+ _text_size = _etext - _text ;
+ _text_rva = _text - _image_base ;
+ _text_off = _text - _link_base;
+
+ _data_size = _edata - _data ;
+ _data_rva = _data - _image_base;
+ _data_off = _data - _link_base;
+
+ __reloc_size = __ereloc - _reloc ;
+ _reloc_size = _ereloc - _reloc ;
+ _reloc_rva = _reloc - _image_base;
+ _reloc_off = _reloc - _link_base;
+
+ _bss_size = _ebss - _bss;
+ _bss_rva = _bss - _image_base;
+
+ _img_size = _eimg - _img ;
+ _img_rva = _img - _image_base;
+ _img_off = _img - _link_base;
+
+ _img_mem_size = _ebss - _img;
+
+ _image_size = _ebss - _link_base ;
+
+ _start_plabel_rva = _start_plabel - _image_base;
+}
diff --git a/src/arch/ia64/prefix/unnrv2b.S b/src/arch/ia64/prefix/unnrv2b.S
new file mode 100644
index 000000000..bd7013b2b
--- /dev/null
+++ b/src/arch/ia64/prefix/unnrv2b.S
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
+ * Copyright (C) 2002 Eric Biederman
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * Originally this code was part of ucl the data compression library
+ * for upx the ``Ultimate Packer of eXecutables''.
+ *
+ * - Converted to gas assembly, and refitted to work with etherboot.
+ * Eric Biederman 20 Aug 2002
+ *
+ * - Converted to functional ia64 assembly (Can this get smaller?)
+ * Eric Biederman 5 Dec 2002
+ */
+ .text
+ .globl _start
+_start:
+ /* See where I am running, and compute gp */
+ {
+ /* Do no call alloc here as I do not know how many argument
+ * registers are being passed through the decompressor, and if I report
+ * to few the unreported registers may get stomped.
+ *
+ * Instead just explicitly get the value of ar.pfs.
+ */
+ mov r17=0
+ mov r8=ar.pfs
+ mov gp = ip /* The linker scripts sets gp at _start */
+
+ }
+ {.mlx
+ movl r9=0x123456789abcdef0 /* Get uncompressed_offset into r9 */
+ }
+ ;;
+ {
+ add r14 = @gprel(payload + 4),gp
+ add r15 = r9,gp
+ mov r16=1 /* last_m_off = 1 */
+ }
+ {
+ mov r20 = 0xd00
+ add r21 = r9,gp
+ br.sptk.few decompr_loop_n2b
+ }
+
+/* ------------- DECOMPRESSION -------------
+
+ Input:
+ r8 - ar.pfs
+ r14 - source
+ r15 - dest
+ r16 - 1
+ r17 - (buffer) 0
+ r20 - 0xd00 (constant)
+ r21 - start address
+ Usage:
+ r9 - scratch register for memory copies
+ r18 - scratch register for getbit
+ r19 - scratch register for loads and stores
+ Output:
+ r2 - 0
+ r3 - 0
+*/
+
+getbit:
+ add r18 = r17,r17
+ ;;
+ cmp.ne p8,p0 = r0,r18
+ cmp.leu p6,p7 = r18,r17
+ ;;
+ mov r17 = r18
+(p8) br.cond.sptk.few getbit_end
+ /* Do a unaligned 64bit load */
+ ;;
+ ld1 r17 = [r14],1
+ ;;
+ ld1 r18 = [r14],1
+ ;;
+ dep r17 = r18,r17,8,8
+ ld1 r18 = [r14],1
+ ;;
+ dep r17 = r18,r17,16,8
+ ld1 r18 = [r14],1
+ ;;
+ dep r17 = r18,r17,24,8
+ ld1 r18 = [r14],1
+ ;;
+ dep r17 = r18,r17,32,8
+ ld1 r18 = [r14],1
+ ;;
+ dep r17 = r18,r17,40,8
+ ld1 r18 = [r14],1
+ ;;
+ dep r17 = r18,r17,48,8
+ ld1 r18 = [r14],1
+ ;;
+ dep r17 = r18,r17,56,8
+ ;;
+ add r18 = r17,r17,1
+ ;;
+ cmp.leu p6,p7=r18,r17
+ ;;
+ mov r17=r18
+ ;;
+getbit_end:
+ br.ret.sptk.few b6
+
+
+decompr_literals_n2b:
+ ld1 r19 = [r14],1
+ ;;
+ st1 [r15] = r19,1
+ ;;
+decompr_loop_n2b:
+ br.call.sptk.few b6 = getbit
+ ;;
+(p6) br.cond.sptk.few decompr_literals_n2b
+(p7) add r2 = 1,r0 /* m_off = 1 */
+ ;;
+loop1_n2b:
+ br.call.sptk.few b6 = getbit
+ ;;
+(p6) add r2 = r2,r2,1 /* m_off = m_off*2 + getbit() */
+(p7) add r2 = r2,r2
+ br.call.sptk.few b6 = getbit
+ ;;
+(p7) br.cond.sptk.few loop1_n2b /* while(!getbit()) */
+ ;;
+ mov r3 = r0
+ cmp.eq p6,p0 = 2,r2
+ add r2 = -3,r2
+(p6) br.cond.sptk.few decompr_ebpeax_n2b /* if (m_off == 2) goto decompr_ebpeax_n2b ? */
+ ;;
+ ld1 r19 = [r14],1
+ shl r2 = r2,8
+ ;;
+ dep r2 = r19,r2,0,8 /* m_off = (m_off - 3)*256 + src[ilen++] */
+ ;;
+ cmp4.eq p6,p0 = -1,r2 /* if (m_off == 0xffffffff) goto decomp_end_n2b */
+ ;;
+(p6) br.cond.sptk.few decompr_end_n2b
+ mov r16 = r2 /* last_m_off = m_off */
+ ;;
+decompr_ebpeax_n2b:
+ br.call.sptk.few b6 = getbit
+ ;;
+(p6) add r3 = r3,r3,1 /* m_len = getbit() */
+(p7) add r3 = r3,r3
+ br.call.sptk.few b6 = getbit
+ ;;
+(p6) add r3 = r3,r3,1 /* m_len = m_len*2 + getbit()) */
+(p7) add r3 = r3,r3
+ ;;
+ cmp.ne p6,p0 = r0,r3
+(p6) br.cond.sptk.few decompr_got_mlen_n2b /* if (m_len == 0) goto decompr_got_mlen_n2b */
+ add r3 = 1,r3 /* m_len++ */
+ ;;
+loop2_n2b:
+ br.call.sptk.few b6 = getbit
+ ;;
+(p6) add r3 = r3,r3,1 /* m_len = m_len*2 + getbit() */
+(p7) add r3 = r3,r3
+ br.call.sptk.few b6 = getbit
+ ;;
+(p7) br.cond.sptk.few loop2_n2b /* while(!getbit()) */
+ add r3 = 2, r3 /* m_len += 2 */
+ ;;
+decompr_got_mlen_n2b:
+ cmp.gtu p6,p7 = r16, r20
+ ;;
+(p6) add r3 = 2, r3 /* m_len = m_len + 1 + (last_m_off > 0xd00) */
+(p7) add r3 = 1, r3
+ sub r9 = r15, r16,1 /* m_pos = dst + olen - last_m_off - 1 */
+ ;;
+1:
+ ld1 r19 = [r9],1
+ add r3 = -1,r3
+ ;;
+ st1 [r15] = r19,1 /* dst[olen++] = *m_pos++ while(m_len > 0) */
+ cmp.ne p6,p0 = r0,r3
+(p6) br.cond.sptk.few 1b
+ ;;
+ br.cond.sptk.few decompr_loop_n2b
+decompr_end_n2b:
+ /* Branch to the start address */
+ mov ar.pfs=r8
+ ;;
+ mov b6 = r21
+ ;;
+ br.sptk.few b6
+
+payload:
diff --git a/src/arch/ia64/prefix/unnrv2b.lds b/src/arch/ia64/prefix/unnrv2b.lds
new file mode 100644
index 000000000..728f70097
--- /dev/null
+++ b/src/arch/ia64/prefix/unnrv2b.lds
@@ -0,0 +1,28 @@
+OUTPUT_FORMAT("elf64-ia64-little")
+
+OUTPUT_ARCH(ia64)
+
+ENTRY(_start)
+SECTIONS {
+ . = 0;
+ __gp = .;
+ _text = . ;
+ .text : {
+ *(.text)
+ }
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ *(.hash)
+ *(.data)
+ *(.sbss)
+ *(.bss)
+ *(.dynstr)
+ *(.dynsym)
+ *(.IA_64.unwind)
+ *(.IA_64.unwind_info)
+ *(.IA64_unwind)
+ *(.IA64_unwind_info)
+ *(.dynamic)
+ }
+}