mirror of https://github.com/ncroxon/gnu-efi
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Date: Mon, 11 Aug 2014 15:39:16 +0200 Subject: [PATCH] Add support for 32-bit ARM This adds support for 32-bit ARM using an approach similar to the one used for 64-bit ARM (AArch64), i.e., it does not rely on an objcopy that is aware of EFI or PE/COFF, but lays out the entire PE/COFF header using the assembler. In the 32-bit ARM case (which does not have a division instruction), some code has been imported from the Linux kernel to perform the division operations in software. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Nigel Croxon <nigel.croxon@hp.com>
This commit is contained in:
parent
b28143d4fb
commit
16d65c0669
|
@ -112,8 +112,18 @@ endif
|
|||
# otherwise we need to compose the PE/COFF header using the assembler
|
||||
#
|
||||
ifneq ($(ARCH),aarch64)
|
||||
ifneq ($(ARCH),arm)
|
||||
export HAVE_EFI_OBJCOPY=y
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(ARCH),arm)
|
||||
export LIBGCC=$(shell $(CC) $(ARCH3264) -print-libgcc-file-name)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
CFLAGS += -marm
|
||||
endif
|
||||
|
||||
# Generic compilation flags
|
||||
INCDIR += -I$(SRCDIR) -I$(TOPDIR)/inc -I$(TOPDIR)/inc/$(ARCH) \
|
||||
|
|
|
@ -55,7 +55,7 @@ endif
|
|||
LDFLAGS += -shared -Bsymbolic -L../lib -L../gnuefi $(CRTOBJS)
|
||||
|
||||
LOADLIBES += -lefi -lgnuefi
|
||||
LOADLIBES += $(shell $(CC) $(ARCH3264) -print-libgcc-file-name)
|
||||
LOADLIBES += $(LIBGCC)
|
||||
LOADLIBES += -T $(LDSCRIPT)
|
||||
|
||||
TARGET_APPS = t.efi t2.efi t3.efi t4.efi t5.efi t6.efi \
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* crt0-efi-arm.S - PE/COFF header for ARM EFI applications
|
||||
*
|
||||
* Copright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
.section .text.head
|
||||
|
||||
/*
|
||||
* Magic "MZ" signature for PE/COFF
|
||||
*/
|
||||
.globl ImageBase
|
||||
ImageBase:
|
||||
.ascii "MZ"
|
||||
.skip 58 // 'MZ' + pad + offset == 64
|
||||
.long pe_header - ImageBase // Offset to the PE header.
|
||||
pe_header:
|
||||
.ascii "PE"
|
||||
.short 0
|
||||
coff_header:
|
||||
.short 0x1c2 // Mixed ARM/Thumb
|
||||
.short 2 // nr_sections
|
||||
.long 0 // TimeDateStamp
|
||||
.long 0 // PointerToSymbolTable
|
||||
.long 1 // NumberOfSymbols
|
||||
.short section_table - optional_header // SizeOfOptionalHeader
|
||||
.short 0x306 // Characteristics.
|
||||
// IMAGE_FILE_32BIT_MACHINE |
|
||||
// IMAGE_FILE_DEBUG_STRIPPED |
|
||||
// IMAGE_FILE_EXECUTABLE_IMAGE |
|
||||
// IMAGE_FILE_LINE_NUMS_STRIPPED
|
||||
optional_header:
|
||||
.short 0x10b // PE32+ format
|
||||
.byte 0x02 // MajorLinkerVersion
|
||||
.byte 0x14 // MinorLinkerVersion
|
||||
.long _edata - _start // SizeOfCode
|
||||
.long 0 // SizeOfInitializedData
|
||||
.long 0 // SizeOfUninitializedData
|
||||
.long _start - ImageBase // AddressOfEntryPoint
|
||||
.long _start - ImageBase // BaseOfCode
|
||||
.long 0 // BaseOfData
|
||||
|
||||
extra_header_fields:
|
||||
.long 0 // ImageBase
|
||||
.long 0x20 // SectionAlignment
|
||||
.long 0x8 // FileAlignment
|
||||
.short 0 // MajorOperatingSystemVersion
|
||||
.short 0 // MinorOperatingSystemVersion
|
||||
.short 0 // MajorImageVersion
|
||||
.short 0 // MinorImageVersion
|
||||
.short 0 // MajorSubsystemVersion
|
||||
.short 0 // MinorSubsystemVersion
|
||||
.long 0 // Win32VersionValue
|
||||
|
||||
.long _edata - ImageBase // SizeOfImage
|
||||
|
||||
// Everything before the kernel image is considered part of the header
|
||||
.long _start - ImageBase // SizeOfHeaders
|
||||
.long 0 // CheckSum
|
||||
.short EFI_SUBSYSTEM // Subsystem
|
||||
.short 0 // DllCharacteristics
|
||||
.long 0 // SizeOfStackReserve
|
||||
.long 0 // SizeOfStackCommit
|
||||
.long 0 // SizeOfHeapReserve
|
||||
.long 0 // SizeOfHeapCommit
|
||||
.long 0 // LoaderFlags
|
||||
.long 0x6 // NumberOfRvaAndSizes
|
||||
|
||||
.quad 0 // ExportTable
|
||||
.quad 0 // ImportTable
|
||||
.quad 0 // ResourceTable
|
||||
.quad 0 // ExceptionTable
|
||||
.quad 0 // CertificationTable
|
||||
.quad 0 // BaseRelocationTable
|
||||
|
||||
// Section table
|
||||
section_table:
|
||||
|
||||
/*
|
||||
* The EFI application loader requires a relocation section
|
||||
* because EFI applications must be relocatable. This is a
|
||||
* dummy section as far as we are concerned.
|
||||
*/
|
||||
.ascii ".reloc"
|
||||
.byte 0
|
||||
.byte 0 // end of 0 padding of section name
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0 // SizeOfRawData
|
||||
.long 0 // PointerToRawData
|
||||
.long 0 // PointerToRelocations
|
||||
.long 0 // PointerToLineNumbers
|
||||
.short 0 // NumberOfRelocations
|
||||
.short 0 // NumberOfLineNumbers
|
||||
.long 0x42100040 // Characteristics (section flags)
|
||||
|
||||
|
||||
.ascii ".text"
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0 // end of 0 padding of section name
|
||||
.long _edata - _start // VirtualSize
|
||||
.long _start - ImageBase // VirtualAddress
|
||||
.long _edata - _start // SizeOfRawData
|
||||
.long _start - ImageBase // PointerToRawData
|
||||
|
||||
.long 0 // PointerToRelocations (0 for executables)
|
||||
.long 0 // PointerToLineNumbers (0 for executables)
|
||||
.short 0 // NumberOfRelocations (0 for executables)
|
||||
.short 0 // NumberOfLineNumbers (0 for executables)
|
||||
.long 0xe0500020 // Characteristics (section flags)
|
||||
|
||||
_start:
|
||||
stmfd sp!, {r0-r2, lr}
|
||||
|
||||
mov r2, r0
|
||||
mov r3, r1
|
||||
adr r1, .L_DYNAMIC
|
||||
ldr r0, [r1]
|
||||
add r1, r0, r1
|
||||
adr r0, ImageBase
|
||||
bl _relocate
|
||||
teq r0, #0
|
||||
bne 0f
|
||||
|
||||
ldmfd sp, {r0-r1}
|
||||
bl efi_main
|
||||
|
||||
0: add sp, sp, #12
|
||||
ldr pc, [sp], #4
|
||||
|
||||
.L_DYNAMIC:
|
||||
.word _DYNAMIC - .
|
|
@ -0,0 +1,57 @@
|
|||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
.text 0x0 : {
|
||||
*(.text.head)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
*(.srodata)
|
||||
*(.rodata*)
|
||||
. = ALIGN(16);
|
||||
_etext = .;
|
||||
}
|
||||
.dynamic : { *(.dynamic) }
|
||||
.data :
|
||||
{
|
||||
*(.sdata)
|
||||
*(.data)
|
||||
*(.data1)
|
||||
*(.data)
|
||||
*(.got.plt)
|
||||
*(.got)
|
||||
|
||||
/* the EFI loader doesn't seem to like a .bss section, so we stick
|
||||
it all into .data: */
|
||||
. = ALIGN(16);
|
||||
_bss = .;
|
||||
*(.sbss)
|
||||
*(.scommon)
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
. = ALIGN(16);
|
||||
_bss_end = .;
|
||||
}
|
||||
.rel.dyn : { *(.rel.dyn) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rel.data : { *(.rel.data) *(.rel.data*) }
|
||||
_edata = .;
|
||||
_data_size = . - _etext;
|
||||
|
||||
. = ALIGN(4096);
|
||||
.dynsym : { *(.dynsym) }
|
||||
. = ALIGN(4096);
|
||||
.dynstr : { *(.dynstr) }
|
||||
. = ALIGN(4096);
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.rel.reloc)
|
||||
*(.eh_frame)
|
||||
*(.note.GNU-stack)
|
||||
}
|
||||
.comment 0 : { *(.comment) }
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/* reloc_arm.c - position independent x86 ELF shared object relocator
|
||||
Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
Copyright (C) 1999 Hewlett-Packard Co.
|
||||
Contributed by David Mosberger <davidm@hpl.hp.com>.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
* Neither the name of Hewlett-Packard Co. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
EFI_STATUS _relocate (long ldbase, Elf32_Dyn *dyn, EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
|
||||
{
|
||||
long relsz = 0, relent = 0;
|
||||
Elf32_Rel *rel = 0;
|
||||
unsigned long *addr;
|
||||
int i;
|
||||
|
||||
for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
|
||||
switch (dyn[i].d_tag) {
|
||||
case DT_REL:
|
||||
rel = (Elf32_Rel*)
|
||||
((unsigned long)dyn[i].d_un.d_ptr
|
||||
+ ldbase);
|
||||
break;
|
||||
|
||||
case DT_RELSZ:
|
||||
relsz = dyn[i].d_un.d_val;
|
||||
break;
|
||||
|
||||
case DT_RELENT:
|
||||
relent = dyn[i].d_un.d_val;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rel && relent == 0)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
if (!rel || relent == 0)
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
while (relsz > 0) {
|
||||
/* apply the relocs */
|
||||
switch (ELF32_R_TYPE (rel->r_info)) {
|
||||
case R_ARM_NONE:
|
||||
break;
|
||||
|
||||
case R_ARM_RELATIVE:
|
||||
addr = (unsigned long *)
|
||||
(ldbase + rel->r_offset);
|
||||
*addr += ldbase;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rel = (Elf32_Rel*) ((char *) rel + relent);
|
||||
relsz -= relent;
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* This prevents GCC from emitting GOT based relocations, and use R_ARM_REL32
|
||||
* relative relocations instead, which are more suitable for static binaries.
|
||||
*/
|
||||
#pragma GCC visibility push (hidden)
|
||||
|
||||
//
|
||||
// Basic EFI types of various widths
|
||||
//
|
||||
|
||||
#ifndef __WCHAR_TYPE__
|
||||
# define __WCHAR_TYPE__ short
|
||||
#endif
|
||||
|
||||
typedef uint64_t UINT64;
|
||||
typedef int64_t INT64;
|
||||
|
||||
typedef uint32_t UINT32;
|
||||
typedef int32_t INT32;
|
||||
|
||||
typedef uint16_t UINT16;
|
||||
typedef int16_t INT16;
|
||||
typedef uint8_t UINT8;
|
||||
typedef int8_t INT8;
|
||||
typedef __WCHAR_TYPE__ WCHAR;
|
||||
|
||||
#undef VOID
|
||||
#define VOID void
|
||||
|
||||
typedef int32_t INTN;
|
||||
typedef uint32_t UINTN;
|
||||
|
||||
#define EFIERR(a) (0x80000000 | a)
|
||||
#define EFI_ERROR_MASK 0x80000000
|
||||
#define EFIERR_OEM(a) (0xc0000000 | a)
|
||||
|
||||
#define BAD_POINTER 0xFBFBFBFB
|
||||
#define MAX_ADDRESS 0xFFFFFFFF
|
||||
|
||||
#define BREAKPOINT() while (TRUE);
|
||||
|
||||
//
|
||||
// Pointers must be aligned to these address to function
|
||||
//
|
||||
|
||||
#define MIN_ALIGNMENT_SIZE 4
|
||||
|
||||
#define ALIGN_VARIABLE(Value ,Adjustment) \
|
||||
(UINTN)Adjustment = 0; \
|
||||
if((UINTN)Value % MIN_ALIGNMENT_SIZE) \
|
||||
(UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \
|
||||
Value = (UINTN)Value + (UINTN)Adjustment
|
||||
|
||||
|
||||
//
|
||||
// Define macros to build data structure signatures from characters.
|
||||
//
|
||||
|
||||
#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8))
|
||||
#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16))
|
||||
#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32))
|
||||
|
||||
//
|
||||
// EFIAPI - prototype calling convention for EFI function pointers
|
||||
// BOOTSERVICE - prototype for implementation of a boot service interface
|
||||
// RUNTIMESERVICE - prototype for implementation of a runtime service interface
|
||||
// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service
|
||||
// RUNTIME_CODE - pragma macro for declaring runtime code
|
||||
//
|
||||
|
||||
#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options
|
||||
#define EFIAPI // Substitute expresion to force C calling convention
|
||||
#endif
|
||||
|
||||
#define BOOTSERVICE
|
||||
#define RUNTIMESERVICE
|
||||
#define RUNTIMEFUNCTION
|
||||
|
||||
|
||||
#define RUNTIME_CODE(a) alloc_text("rtcode", a)
|
||||
#define BEGIN_RUNTIME_DATA() data_seg("rtdata")
|
||||
#define END_RUNTIME_DATA() data_seg("")
|
||||
|
||||
#define VOLATILE volatile
|
||||
|
||||
#define MEMORY_FENCE __sync_synchronize
|
||||
|
||||
//
|
||||
// When build similiar to FW, then link everything together as
|
||||
// one big module.
|
||||
//
|
||||
|
||||
#define EFI_DRIVER_ENTRY_POINT(InitFunction) \
|
||||
UINTN \
|
||||
InitializeDriver ( \
|
||||
VOID *ImageHandle, \
|
||||
VOID *SystemTable \
|
||||
) \
|
||||
{ \
|
||||
return InitFunction(ImageHandle, \
|
||||
SystemTable); \
|
||||
} \
|
||||
\
|
||||
EFI_STATUS efi_main( \
|
||||
EFI_HANDLE image, \
|
||||
EFI_SYSTEM_TABLE *systab \
|
||||
) __attribute__((weak, \
|
||||
alias ("InitializeDriver")));
|
||||
|
||||
#define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \
|
||||
(_if)->LoadInternal(type, name, entry)
|
||||
|
||||
|
||||
//
|
||||
// Some compilers don't support the forward reference construct:
|
||||
// typedef struct XXXXX
|
||||
//
|
||||
// The following macro provide a workaround for such cases.
|
||||
|
||||
#define INTERFACE_DECL(x) struct x
|
||||
|
||||
#define uefi_call_wrapper(func, va_num, ...) func(__VA_ARGS__)
|
||||
#define EFI_FUNCTION
|
||||
|
||||
extern UINT64 __DivU64x32(UINT64 Dividend, UINTN Divisor, UINTN *Remainder);
|
||||
|
||||
static inline UINT64 DivU64x32(UINT64 Dividend, UINTN Divisor, UINTN *Remainder)
|
||||
{
|
||||
if (Dividend >> 32)
|
||||
return __DivU64x32(Dividend, Divisor, Remainder);
|
||||
|
||||
/*
|
||||
* GCC turns a division into a multiplication and shift with precalculated
|
||||
* constants if the divisor is constant and the dividend fits into a 32 bit
|
||||
* variable. Otherwise, it will turn this into calls into the 32-bit div
|
||||
* library functions.
|
||||
*/
|
||||
if (Remainder)
|
||||
*Remainder = (UINTN)Dividend % Divisor;
|
||||
Dividend = (UINTN)Dividend / Divisor;
|
||||
return Dividend;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) 1998 Intel Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
efilibplat.h
|
||||
|
||||
Abstract:
|
||||
|
||||
EFI to compile bindings
|
||||
|
||||
|
||||
|
||||
|
||||
Revision History
|
||||
|
||||
--*/
|
||||
|
||||
VOID
|
||||
InitializeLibPlatform (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
);
|
||||
|
|
@ -57,6 +57,10 @@ ifeq ($(ARCH),x86_64)
|
|||
FILES += $(ARCH)/callwrap $(ARCH)/efi_stub
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
FILES += $(ARCH)/lib1funcs $(ARCH)/div64
|
||||
endif
|
||||
|
||||
OBJS = $(FILES:%=%.o)
|
||||
|
||||
SUBDIRS = ia32 x86_64 ia64 runtime
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* linux/arch/arm/lib/div64.S
|
||||
*
|
||||
* Optimized computation of 64-bit dividend / 32-bit divisor
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: Oct 5, 2003
|
||||
* Copyright: Monta Vista Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define xl r0
|
||||
#define xh r1
|
||||
#define yl r2
|
||||
#define yh r3
|
||||
|
||||
#define UNWIND(x...)
|
||||
#define ARM(x...) x
|
||||
#define THUMB(x...)
|
||||
|
||||
#define ENTRY(__f) \
|
||||
.align 3 ;\
|
||||
.globl __f ;\
|
||||
.type __f,%function ;\
|
||||
__f:
|
||||
#define ENDPROC(__f) ;\
|
||||
.size __f, . - __f
|
||||
|
||||
|
||||
/*
|
||||
UINT64
|
||||
DivU64x32 (
|
||||
IN UINT64 Dividend,
|
||||
IN UINTN Divisor,
|
||||
OUT UINTN *Remainder OPTIONAL
|
||||
)
|
||||
// divide 64bit by 32bit and get a 64bit result
|
||||
// N.B. only works for 31bit divisors!!
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
ENTRY(__DivU64x32)
|
||||
stmfd sp!, {r4-r6, lr}
|
||||
|
||||
mov r5, r4 @ preserve Remainder
|
||||
mov r4, r2 @ divisor in r4
|
||||
bl __do_div64
|
||||
|
||||
teq r5, #0
|
||||
strne xh, [r5]
|
||||
mov r0, yl
|
||||
mov r1, yh
|
||||
ldmfd sp!, {r4-r6, pc}
|
||||
ENDPROC(__DivU64x32)
|
||||
|
||||
/*
|
||||
* __do_div64: perform a division with 64-bit dividend and 32-bit divisor.
|
||||
*
|
||||
* Note: Calling convention is totally non standard for optimal code.
|
||||
* This is meant to be used by do_div() from include/asm/div64.h only.
|
||||
*
|
||||
* Input parameters:
|
||||
* xh-xl = dividend (clobbered)
|
||||
* r4 = divisor (preserved)
|
||||
*
|
||||
* Output values:
|
||||
* yh-yl = result
|
||||
* xh = remainder
|
||||
*
|
||||
* Clobbered regs: xl, ip
|
||||
*/
|
||||
|
||||
ENTRY(__do_div64)
|
||||
UNWIND(.fnstart)
|
||||
|
||||
@ Test for easy paths first.
|
||||
subs ip, r4, #1
|
||||
bls 9f @ divisor is 0 or 1
|
||||
tst ip, r4
|
||||
beq 8f @ divisor is power of 2
|
||||
|
||||
@ See if we need to handle upper 32-bit result.
|
||||
cmp xh, r4
|
||||
mov yh, #0
|
||||
blo 3f
|
||||
|
||||
@ Align divisor with upper part of dividend.
|
||||
@ The aligned divisor is stored in yl preserving the original.
|
||||
@ The bit position is stored in ip.
|
||||
|
||||
clz yl, r4
|
||||
clz ip, xh
|
||||
sub yl, yl, ip
|
||||
mov ip, #1
|
||||
mov ip, ip, lsl yl
|
||||
mov yl, r4, lsl yl
|
||||
|
||||
@ The division loop for needed upper bit positions.
|
||||
@ Break out early if dividend reaches 0.
|
||||
2: cmp xh, yl
|
||||
orrcs yh, yh, ip
|
||||
subcss xh, xh, yl
|
||||
movnes ip, ip, lsr #1
|
||||
mov yl, yl, lsr #1
|
||||
bne 2b
|
||||
|
||||
@ See if we need to handle lower 32-bit result.
|
||||
3: cmp xh, #0
|
||||
mov yl, #0
|
||||
cmpeq xl, r4
|
||||
movlo xh, xl
|
||||
movlo pc, lr
|
||||
|
||||
@ The division loop for lower bit positions.
|
||||
@ Here we shift remainer bits leftwards rather than moving the
|
||||
@ divisor for comparisons, considering the carry-out bit as well.
|
||||
mov ip, #0x80000000
|
||||
4: movs xl, xl, lsl #1
|
||||
adcs xh, xh, xh
|
||||
beq 6f
|
||||
cmpcc xh, r4
|
||||
5: orrcs yl, yl, ip
|
||||
subcs xh, xh, r4
|
||||
movs ip, ip, lsr #1
|
||||
bne 4b
|
||||
mov pc, lr
|
||||
|
||||
@ The top part of remainder became zero. If carry is set
|
||||
@ (the 33th bit) this is a false positive so resume the loop.
|
||||
@ Otherwise, if lower part is also null then we are done.
|
||||
6: bcs 5b
|
||||
cmp xl, #0
|
||||
moveq pc, lr
|
||||
|
||||
@ We still have remainer bits in the low part. Bring them up.
|
||||
|
||||
clz xh, xl @ we know xh is zero here so...
|
||||
add xh, xh, #1
|
||||
mov xl, xl, lsl xh
|
||||
mov ip, ip, lsr xh
|
||||
|
||||
@ Current remainder is now 1. It is worthless to compare with
|
||||
@ divisor at this point since divisor can not be smaller than 3 here.
|
||||
@ If possible, branch for another shift in the division loop.
|
||||
@ If no bit position left then we are done.
|
||||
movs ip, ip, lsr #1
|
||||
mov xh, #1
|
||||
bne 4b
|
||||
mov pc, lr
|
||||
|
||||
8: @ Division by a power of 2: determine what that divisor order is
|
||||
@ then simply shift values around
|
||||
|
||||
clz ip, r4
|
||||
rsb ip, ip, #31
|
||||
|
||||
mov yh, xh, lsr ip
|
||||
mov yl, xl, lsr ip
|
||||
rsb ip, ip, #32
|
||||
ARM( orr yl, yl, xh, lsl ip )
|
||||
THUMB( lsl xh, xh, ip )
|
||||
THUMB( orr yl, yl, xh )
|
||||
mov xh, xl, lsl ip
|
||||
mov xh, xh, lsr ip
|
||||
mov pc, lr
|
||||
|
||||
@ eq -> division by 1: obvious enough...
|
||||
9: moveq yl, xl
|
||||
moveq yh, xh
|
||||
moveq xh, #0
|
||||
moveq pc, lr
|
||||
UNWIND(.fnend)
|
||||
|
||||
UNWIND(.fnstart)
|
||||
UNWIND(.pad #4)
|
||||
UNWIND(.save {lr})
|
||||
Ldiv0_64:
|
||||
@ Division by 0:
|
||||
str lr, [sp, #-8]!
|
||||
bl __div0
|
||||
|
||||
@ as wrong as it could be...
|
||||
mov yl, #0
|
||||
mov yh, #0
|
||||
mov xh, #0
|
||||
ldr pc, [sp], #8
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__do_div64)
|
|
@ -0,0 +1 @@
|
|||
/* This stub is a stub to make the build happy */
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* aarch64/initplat.c
|
||||
*
|
||||
* Copright (C) 2014 Linaro Ltd.
|
||||
* Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
VOID
|
||||
InitializeLibPlatform (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls to these functions may be emitted implicitly by GCC even when
|
||||
* -ffreestanding is in effect.
|
||||
*/
|
||||
void *memset(void *s, int c, __SIZE_TYPE__ n)
|
||||
{
|
||||
unsigned char *p = s;
|
||||
|
||||
while (n--)
|
||||
*p++ = c;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void *memcpy(void *dest, const void *src, __SIZE_TYPE__ n)
|
||||
{
|
||||
unsigned char *p = dest;
|
||||
unsigned char const *q = src;
|
||||
|
||||
while (n--)
|
||||
*p++ = *q++;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void __div0(void)
|
||||
{
|
||||
// TODO handle divide by zero fault
|
||||
while (1);
|
||||
}
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines
|
||||
*
|
||||
* Author: Nicolas Pitre <nico@fluxnic.net>
|
||||
* - contributed to gcc-3.4 on Sep 30, 2003
|
||||
* - adapted for the Linux kernel on Oct 2, 2003
|
||||
*/
|
||||
|
||||
/* Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
|
||||
|
||||
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, or (at your option) any
|
||||
later version.
|
||||
|
||||
In addition to the permissions in the GNU General Public License, the
|
||||
Free Software Foundation gives you unlimited permission to link the
|
||||
compiled version of this file into combinations with other programs,
|
||||
and to distribute those combinations without any restriction coming
|
||||
from the use of this file. (The General Public License restrictions
|
||||
do apply in other respects; for example, they cover modification of
|
||||
the file, and distribution when not linked into a combine
|
||||
executable.)
|
||||
|
||||
This file 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 this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#define UNWIND(x...)
|
||||
|
||||
#define ENTRY(__f) \
|
||||
.align 3 ;\
|
||||
.globl __f ;\
|
||||
.type __f,%function ;\
|
||||
__f:
|
||||
#define ENDPROC(__f) ;\
|
||||
.size __f, . - __f
|
||||
|
||||
.macro ARM_DIV_BODY dividend, divisor, result, curbit
|
||||
|
||||
clz \curbit, \divisor
|
||||
clz \result, \dividend
|
||||
sub \result, \curbit, \result
|
||||
mov \curbit, #1
|
||||
mov \divisor, \divisor, lsl \result
|
||||
mov \curbit, \curbit, lsl \result
|
||||
mov \result, #0
|
||||
|
||||
@ Division loop
|
||||
1: cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
orrhs \result, \result, \curbit
|
||||
cmp \dividend, \divisor, lsr #1
|
||||
subhs \dividend, \dividend, \divisor, lsr #1
|
||||
orrhs \result, \result, \curbit, lsr #1
|
||||
cmp \dividend, \divisor, lsr #2
|
||||
subhs \dividend, \dividend, \divisor, lsr #2
|
||||
orrhs \result, \result, \curbit, lsr #2
|
||||
cmp \dividend, \divisor, lsr #3
|
||||
subhs \dividend, \dividend, \divisor, lsr #3
|
||||
orrhs \result, \result, \curbit, lsr #3
|
||||
cmp \dividend, #0 @ Early termination?
|
||||
movnes \curbit, \curbit, lsr #4 @ No, any more bits to do?
|
||||
movne \divisor, \divisor, lsr #4
|
||||
bne 1b
|
||||
|
||||
.endm
|
||||
|
||||
|
||||
.macro ARM_DIV2_ORDER divisor, order
|
||||
|
||||
clz \order, \divisor
|
||||
rsb \order, \order, #31
|
||||
|
||||
.endm
|
||||
|
||||
|
||||
.macro ARM_MOD_BODY dividend, divisor, order, spare
|
||||
|
||||
clz \order, \divisor
|
||||
clz \spare, \dividend
|
||||
sub \order, \order, \spare
|
||||
mov \divisor, \divisor, lsl \order
|
||||
|
||||
@ Perform all needed substractions to keep only the reminder.
|
||||
@ Do comparisons in batch of 4 first.
|
||||
subs \order, \order, #3 @ yes, 3 is intended here
|
||||
blt 2f
|
||||
|
||||
1: cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
cmp \dividend, \divisor, lsr #1
|
||||
subhs \dividend, \dividend, \divisor, lsr #1
|
||||
cmp \dividend, \divisor, lsr #2
|
||||
subhs \dividend, \dividend, \divisor, lsr #2
|
||||
cmp \dividend, \divisor, lsr #3
|
||||
subhs \dividend, \dividend, \divisor, lsr #3
|
||||
cmp \dividend, #1
|
||||
mov \divisor, \divisor, lsr #4
|
||||
subges \order, \order, #4
|
||||
bge 1b
|
||||
|
||||
tst \order, #3
|
||||
teqne \dividend, #0
|
||||
beq 5f
|
||||
|
||||
@ Either 1, 2 or 3 comparison/substractions are left.
|
||||
2: cmn \order, #2
|
||||
blt 4f
|
||||
beq 3f
|
||||
cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
mov \divisor, \divisor, lsr #1
|
||||
3: cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
mov \divisor, \divisor, lsr #1
|
||||
4: cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
5:
|
||||
.endm
|
||||
|
||||
|
||||
ENTRY(__aeabi_uidiv)
|
||||
ENTRY(__udivsi3)
|
||||
|
||||
subs r2, r1, #1
|
||||
moveq pc, lr
|
||||
bcc Ldiv0
|
||||
cmp r0, r1
|
||||
bls 11f
|
||||
tst r1, r2
|
||||
beq 12f
|
||||
|
||||
ARM_DIV_BODY r0, r1, r2, r3
|
||||
|
||||
mov r0, r2
|
||||
mov pc, lr
|
||||
|
||||
11: moveq r0, #1
|
||||
movne r0, #0
|
||||
mov pc, lr
|
||||
|
||||
12: ARM_DIV2_ORDER r1, r2
|
||||
|
||||
mov r0, r0, lsr r2
|
||||
mov pc, lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__udivsi3)
|
||||
ENDPROC(__aeabi_uidiv)
|
||||
|
||||
ENTRY(__umodsi3)
|
||||
UNWIND(.fnstart)
|
||||
|
||||
subs r2, r1, #1 @ compare divisor with 1
|
||||
bcc Ldiv0
|
||||
cmpne r0, r1 @ compare dividend with divisor
|
||||
moveq r0, #0
|
||||
tsthi r1, r2 @ see if divisor is power of 2
|
||||
andeq r0, r0, r2
|
||||
movls pc, lr
|
||||
|
||||
ARM_MOD_BODY r0, r1, r2, r3
|
||||
|
||||
mov pc, lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__umodsi3)
|
||||
|
||||
ENTRY(__divsi3)
|
||||
ENTRY(__aeabi_idiv)
|
||||
UNWIND(.fnstart)
|
||||
|
||||
cmp r1, #0
|
||||
eor ip, r0, r1 @ save the sign of the result.
|
||||
beq Ldiv0
|
||||
rsbmi r1, r1, #0 @ loops below use unsigned.
|
||||
subs r2, r1, #1 @ division by 1 or -1 ?
|
||||
beq 10f
|
||||
movs r3, r0
|
||||
rsbmi r3, r0, #0 @ positive dividend value
|
||||
cmp r3, r1
|
||||
bls 11f
|
||||
tst r1, r2 @ divisor is power of 2 ?
|
||||
beq 12f
|
||||
|
||||
ARM_DIV_BODY r3, r1, r0, r2
|
||||
|
||||
cmp ip, #0
|
||||
rsbmi r0, r0, #0
|
||||
mov pc, lr
|
||||
|
||||
10: teq ip, r0 @ same sign ?
|
||||
rsbmi r0, r0, #0
|
||||
mov pc, lr
|
||||
|
||||
11: movlo r0, #0
|
||||
moveq r0, ip, asr #31
|
||||
orreq r0, r0, #1
|
||||
mov pc, lr
|
||||
|
||||
12: ARM_DIV2_ORDER r1, r2
|
||||
|
||||
cmp ip, #0
|
||||
mov r0, r3, lsr r2
|
||||
rsbmi r0, r0, #0
|
||||
mov pc, lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__divsi3)
|
||||
ENDPROC(__aeabi_idiv)
|
||||
|
||||
ENTRY(__modsi3)
|
||||
UNWIND(.fnstart)
|
||||
|
||||
cmp r1, #0
|
||||
beq Ldiv0
|
||||
rsbmi r1, r1, #0 @ loops below use unsigned.
|
||||
movs ip, r0 @ preserve sign of dividend
|
||||
rsbmi r0, r0, #0 @ if negative make positive
|
||||
subs r2, r1, #1 @ compare divisor with 1
|
||||
cmpne r0, r1 @ compare dividend with divisor
|
||||
moveq r0, #0
|
||||
tsthi r1, r2 @ see if divisor is power of 2
|
||||
andeq r0, r0, r2
|
||||
bls 10f
|
||||
|
||||
ARM_MOD_BODY r0, r1, r2, r3
|
||||
|
||||
10: cmp ip, #0
|
||||
rsbmi r0, r0, #0
|
||||
mov pc, lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__modsi3)
|
||||
|
||||
ENTRY(__aeabi_uidivmod)
|
||||
UNWIND(.fnstart)
|
||||
UNWIND(.save {r0, r1, ip, lr} )
|
||||
|
||||
stmfd sp!, {r0, r1, ip, lr}
|
||||
bl __aeabi_uidiv
|
||||
ldmfd sp!, {r1, r2, ip, lr}
|
||||
mul r3, r0, r2
|
||||
sub r1, r1, r3
|
||||
mov pc, lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__aeabi_uidivmod)
|
||||
|
||||
ENTRY(__aeabi_idivmod)
|
||||
UNWIND(.fnstart)
|
||||
UNWIND(.save {r0, r1, ip, lr} )
|
||||
stmfd sp!, {r0, r1, ip, lr}
|
||||
bl __aeabi_idiv
|
||||
ldmfd sp!, {r1, r2, ip, lr}
|
||||
mul r3, r0, r2
|
||||
sub r1, r1, r3
|
||||
mov pc, lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__aeabi_idivmod)
|
||||
|
||||
Ldiv0:
|
||||
UNWIND(.fnstart)
|
||||
UNWIND(.pad #4)
|
||||
UNWIND(.save {lr})
|
||||
str lr, [sp, #-8]!
|
||||
bl __div0
|
||||
mov r0, #0 @ About as wrong as it could be.
|
||||
ldr pc, [sp], #8
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(Ldiv0)
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* arm/math.c - math routines for ARM
|
||||
*
|
||||
* Copright (C) 2014 Linaro Ltd.
|
||||
* Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
UINT64
|
||||
LShiftU64 (
|
||||
IN UINT64 Operand,
|
||||
IN UINTN Count
|
||||
)
|
||||
// Left shift 64bit by 32bit and get a 64bit result
|
||||
{
|
||||
return Operand << Count;
|
||||
}
|
||||
|
||||
UINT64
|
||||
RShiftU64 (
|
||||
IN UINT64 Operand,
|
||||
IN UINTN Count
|
||||
)
|
||||
// Right shift 64bit by 32bit and get a 64bit result
|
||||
{
|
||||
return Operand >> Count;
|
||||
}
|
||||
|
||||
|
||||
UINT64
|
||||
MultU64x32 (
|
||||
IN UINT64 Multiplicand,
|
||||
IN UINTN Multiplier
|
||||
)
|
||||
// Multiple 64bit by 32bit and get a 64bit result
|
||||
{
|
||||
return Multiplicand * Multiplier;
|
||||
}
|
Loading…
Reference in New Issue