Merge remote-tracking branch 'upstream/master'

pull/40/head
AreRR 2018-05-01 14:39:26 +02:00
commit 2fe1a387be
804 changed files with 64749 additions and 8675 deletions

54
.travis.yml 100644
View File

@ -0,0 +1,54 @@
dist: trusty
sudo: false
language: c
cache: ccache
compiler:
- gcc
addons:
apt:
packages:
- binutils-dev
- liblzma-dev
- syslinux
- genisoimage
coverity_scan:
project:
name: "ipxe/ipxe"
version: $TRAVIS_COMMIT
build_command_prepend: "make -C src bin/deps"
build_command: "make -C src bin/blib.a"
branch_pattern: coverity_scan
env:
global:
- MAKEFLAGS="-j 4"
script:
- make -C src bin/blib.a
- make -C src bin/ipxe.pxe
- make -C src bin/ipxe.usb
- make -C src bin/ipxe.iso
- make -C src bin/8086100e.mrom
- make -C src bin-x86_64-pcbios/blib.a
- make -C src bin-x86_64-pcbios/ipxe.pxe
- make -C src bin-x86_64-pcbios/ipxe.usb
- make -C src bin-x86_64-pcbios/ipxe.iso
- make -C src bin-x86_64-pcbios/8086100e.mrom
- make -C src bin-x86_64-efi/blib.a
- make -C src bin-x86_64-efi/ipxe.efi
- make -C src bin-x86_64-efi/intel.efidrv
- make -C src bin-x86_64-efi/intel.efirom
- make -C src bin-i386-efi/blib.a
- make -C src bin-i386-efi/ipxe.efi
- make -C src bin-i386-efi/intel.efidrv
- make -C src bin-i386-efi/intel.efirom
- make -C src bin-x86_64-linux/blib.a
- make -C src bin-x86_64-linux/tap.linux
- make -C src bin-x86_64-linux/af_packet.linux
- make -C src bin-x86_64-linux/tests.linux
- ./src/bin-x86_64-linux/tests.linux

View File

@ -0,0 +1,21 @@
/*
* Coverity modelling file
*
*/
typedef long off_t;
typedef void * userptr_t;
typedef long long time_t;
struct tm;
/* Inhibit use of built-in models for functions where Coverity's
* assumptions about the modelled function are incorrect for iPXE.
*/
char * strerror ( int errno ) {
}
void copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) {
}
time_t mktime ( struct tm *tm ) {
}
int getchar ( void ) {
}

View File

@ -9,6 +9,7 @@ ASFLAGS :=
LDFLAGS :=
HOST_CFLAGS :=
MAKEDEPS := Makefile
CROSS_COMPILE ?= $(CROSS)
###############################################################################
#
@ -52,9 +53,7 @@ EINFO := ./util/einfo
GENKEYMAP := ./util/genkeymap.pl
DOXYGEN := doxygen
LCAB := lcab
BINUTILS_DIR := /usr
BFD_DIR := $(BINUTILS_DIR)
ZLIB_DIR := /usr
QEMUIMG := qemu-img
###############################################################################
#
@ -63,7 +62,7 @@ ZLIB_DIR := /usr
SRCDIRS :=
SRCDIRS += libgcc
SRCDIRS += core
SRCDIRS += net net/oncrpc net/tcp net/udp net/infiniband net/80211
SRCDIRS += net net/tcp net/udp net/infiniband
SRCDIRS += image
SRCDIRS += drivers/bus
SRCDIRS += drivers/net
@ -72,17 +71,23 @@ SRCDIRS += drivers/net/e1000e
SRCDIRS += drivers/net/igb
SRCDIRS += drivers/net/igbvf
SRCDIRS += drivers/net/phantom
SRCDIRS += drivers/net/rtl818x
SRCDIRS += drivers/net/ath
SRCDIRS += drivers/net/ath/ath5k
SRCDIRS += drivers/net/ath/ath9k
SRCDIRS += drivers/net/vxge
SRCDIRS += drivers/net/efi
SRCDIRS += drivers/net/tg3
SRCDIRS += drivers/net/sfc
SRCDIRS += drivers/block
SRCDIRS += drivers/nvs
SRCDIRS += drivers/bitbash
SRCDIRS += drivers/infiniband
SRCDIRS += drivers/infiniband/mlx_utils_flexboot/src
SRCDIRS += drivers/infiniband/mlx_utils/src/public
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_reg_access
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_nvconfig
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_vmac
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_blink_leds
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_link_speed
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_mtu
SRCDIRS += drivers/infiniband/mlx_nodnic/src
SRCDIRS += drivers/usb
SRCDIRS += interface/pxe interface/efi interface/smbios
SRCDIRS += interface/bofm
@ -96,6 +101,16 @@ SRCDIRS += hci/keymap
SRCDIRS += usr
SRCDIRS += config
# These directories contain code that is not eligible for UEFI Secure
# Boot signing.
#
SRCDIRS_INSEC += net/oncrpc
SRCDIRS_INSEC += net/80211
SRCDIRS_INSEC += drivers/net/rtl818x
SRCDIRS_INSEC += drivers/net/ath
SRCDIRS_INSEC += drivers/net/ath/ath5k
SRCDIRS_INSEC += drivers/net/ath/ath9k
# NON_AUTO_SRCS lists files that are excluded from the normal
# automatic build system.
#
@ -151,6 +166,9 @@ all : $(ALL)
everything :
$(Q)$(MAKE) --no-print-directory $(ALL) \
bin/3c509.rom bin/intel.rom bin/intel.mrom \
bin-x86_64-pcbios/8086100e.mrom bin-x86_64-pcbios/intel.rom \
bin-x86_64-pcbios/ipxe.usb bin-x86_64-pcbios/ipxe.pxe \
bin-x86_64-pcbios/undionly.kpxe \
bin-i386-efi/ipxe.efi bin-i386-efi/ipxe.efidrv \
bin-i386-efi/ipxe.efirom \
bin-x86_64-efi/ipxe.efi bin-x86_64-efi/ipxe.efidrv \

46
src/Makefile.efi 100644
View File

@ -0,0 +1,46 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# The EFI linker script
#
LDSCRIPT = scripts/efi.lds
# Retain relocation information for elf2efi
#
LDFLAGS += -q -S
# Media types.
#
NON_AUTO_MEDIA += efi
NON_AUTO_MEDIA += efidrv
NON_AUTO_MEDIA += drv.efi
NON_AUTO_MEDIA += efirom
# Include SNP driver in the all-drivers build
#
DRIVERS_net += snp
# Rules for building EFI files
#
$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI)
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(ELF2EFI) --subsystem=10 $< $@
$(BIN)/%.efidrv : $(BIN)/%.efidrv.tmp $(ELF2EFI)
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(ELF2EFI) --subsystem=11 $< $@
$(BIN)/%.drv.efi : $(BIN)/%.efidrv
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(CP) $< $@
$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) $< $@
$(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
$(QM)$(ECHO) " [CAB] $@"
$(Q)$(LCAB) -n -q $(ALL_drv.efi) $@
$(BIN)/%.usb : $(BIN)/%.efi
$(QM)$(ECHO) " [GENEFIDSK] $@"
$(Q)bash util/genefidsk -o $@ -b $(EFI_BOOT_FILE) $<

View File

@ -299,7 +299,7 @@ endif
#
# Select build architecture and platform based on $(BIN)
#
# BIN has the form bin[-[arch-]platform]
# BIN has the form bin[-[<arch>-]<platform>[-sb]]
ARCHS := $(patsubst arch/%,%,$(wildcard arch/*))
PLATFORMS := $(patsubst config/defaults/%.h,%,\
@ -312,17 +312,18 @@ platforms :
ifdef BIN
# Determine architecture portion of $(BIN), if present
BIN_ARCH := $(strip $(foreach A,$(ARCHS),\
$(patsubst bin-$(A)-%,$(A),\
$(filter bin-$(A)-%,$(BIN)))))
# Determine platform portion of $(BIN), if present
ifeq ($(BIN_ARCH),)
BIN_PLATFORM := $(patsubst bin-%,%,$(filter bin-%,$(BIN)))
# Split $(BIN) into architecture, platform, and security flag (where present)
BIN_ELEMENTS := $(subst -,$(SPACE),$(BIN))
BIN_APS := $(wordlist 2,4,$(BIN_ELEMENTS))
ifeq ($(lastword $(BIN_APS)),sb)
BIN_AP := $(wordlist 2,$(words $(BIN_APS)),discard $(BIN_APS))
BIN_SECUREBOOT := 1
else
BIN_PLATFORM := $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN))
BIN_AP := $(BIN_APS)
BIN_SECUREBOOT := 0
endif
BIN_PLATFORM := $(lastword $(BIN_AP))
BIN_ARCH := $(wordlist 2,$(words $(BIN_AP)),discard $(BIN_AP))
# Determine build architecture
DEFAULT_ARCH := i386
@ -339,6 +340,13 @@ CFLAGS += -DPLATFORM=$(PLATFORM)
platform :
@$(ECHO) $(PLATFORM)
# Determine security flag
DEFAULT_SECUREBOOT := 0
SECUREBOOT := $(firstword $(BIN_SECUREBOOT) $(DEFAULT_SECUREBOOT))
CFLAGS += -DSECUREBOOT=$(SECUREBOOT)
secureboot :
@$(ECHO) $(SECUREBOOT)
endif # defined(BIN)
# Include architecture-specific Makefile
@ -357,6 +365,11 @@ endif
#
# Source file handling
# Exclude known-insecure files from Secure Boot builds
ifeq ($(SECUREBOOT),0)
SRCDIRS += $(SRCDIRS_INSEC)
endif
# SRCDIRS lists all directories containing source files.
srcdirs :
@$(ECHO) $(SRCDIRS)
@ -491,6 +504,11 @@ LDFLAGS += -static
#
CFLAGS += -include include/compiler.h
# The section type character (e.g. "@" in "@progbits") varies by
# architecture.
#
CFLAGS += -DASM_TCHAR='$(ASM_TCHAR)' -DASM_TCHAR_OPS='$(ASM_TCHAR_OPS)'
# CFLAGS for specific object types
#
CFLAGS_c +=
@ -518,19 +536,25 @@ POST_O :=
POST_O_DEPS :=
endif
# Debug level calculations
#
DBGLVL_MAX = -DDBGLVL_MAX=$(firstword $(subst ., ,$(1)))
DBGLVL_DFLT = -DDBGLVL_DFLT=$(lastword $(subst ., ,$(1)))
DBGLVL = $(call DBGLVL_MAX,$(1)) $(call DBGLVL_DFLT,$(1))
# Rules for specific object types.
#
COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O)
RULE_c_to_ids.o = $(Q)$(ECHO_E) '$(OBJ_IDS_ASM_NL)' | $(ASSEMBLE_S) -o $@
RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -DDBGLVL_MAX=$* -c $< -o $@ $(POST_O)
RULE_c_to_dbg%.o= $(Q)$(COMPILE_c) $(call DBGLVL,$*) -c $< -o $@ $(POST_O)
RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@
RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS)
ASSEMBLE_S = $(AS) $(ASFLAGS)
RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
RULE_S_to_dbg%.o = $(Q)$(PREPROCESS_S) -DDBGLVL_MAX=$* $< | $(ASSEMBLE_S) -o $@
RULE_S_to_dbg%.o= $(Q)$(PREPROCESS_S) $(call DBGLVL,$*) $< | $(ASSEMBLE_S) -o $@
RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@
GENERIC_TARGETS += ids.o dbg%.o c s
@ -709,6 +733,60 @@ config/named.h : $(CONFIG_LIST)
.PRECIOUS : config/named.h
# (Single-element) list of assertion configuration
#
ASSERT_LIST := $(BIN)/.assert.list
ifeq ($(wildcard $(ASSERT_LIST)),)
ASSERT_OLD := <invalid>
else
ASSERT_OLD := $(shell cat $(ASSERT_LIST))
endif
ifneq ($(ASSERT_OLD),$(ASSERT))
$(shell $(ECHO) "$(ASSERT)" > $(ASSERT_LIST))
endif
$(ASSERT_LIST) : $(MAKEDEPS)
VERYCLEANUP += $(ASSERT_LIST)
# Assertion configuration
#
ifneq ($(ASSERT),)
CFLAGS += -DASSERTING=$(ASSERT)
endif
include/assert.h : $(ASSERT_LIST)
$(Q)$(TOUCH) $@
.PRECIOUS : include/assert.h
# (Single-element) list of profiling configuration
#
PROFILE_LIST := $(BIN)/.profile.list
ifeq ($(wildcard $(PROFILE_LIST)),)
PROFILE_OLD := <invalid>
else
PROFILE_OLD := $(shell cat $(PROFILE_LIST))
endif
ifneq ($(PROFILE_OLD),$(PROFILE))
$(shell $(ECHO) "$(PROFILE)" > $(PROFILE_LIST))
endif
$(PROFILE_LIST) : $(MAKEDEPS)
VERYCLEANUP += $(PROFILE_LIST)
# Profiling configuration
#
ifneq ($(PROFILE),)
CFLAGS += -DPROFILING=$(PROFILE)
endif
include/ipxe/profile.h : $(PROFILE_LIST)
$(Q)$(TOUCH) $@
.PRECIOUS : include/ipxe/profile.h
# These files use .incbin inline assembly to include a binary file.
# Unfortunately ccache does not detect this dependency and caches
# builds even when the binary file has changed.
@ -734,8 +812,8 @@ $(DBGCOL_LIST) : $(MAKEDEPS)
VERYCLEANUP += $(DBGCOL_LIST)
DBGCOL_COLOURS := $(subst -, ,$(DBGCOL))
DBGCOL_MIN := $(word 1,$(DBGCOL_COLOURS))
DBGCOL_MAX := $(word 2,$(DBGCOL_COLOURS))
DBGCOL_MIN := $(firstword $(DBGCOL_COLOURS))
DBGCOL_MAX := $(lastword $(DBGCOL_COLOURS))
debug_DEPS += $(DBGCOL_LIST)
@ -896,7 +974,7 @@ endif
# Device ID tables (using IDs from ROM definition file)
#
define obj_pci_id_asm
.section ".pci_devlist.$(1)", "a", @progbits
.section ".pci_devlist.$(1)", "a", $(ASM_TCHAR)progbits
.globl pci_devlist_$(1)
pci_devlist_$(1):
.short ( 0x$(1) & 0xffff )
@ -960,13 +1038,13 @@ DRIVERS_ipxe = $(DRIVERS_net) $(DRIVERS_infiniband) \
# TGT_DRIVERS : the driver for each element (e.g. "rtl8139 prism2_pci")
# TGT_ROM_NAME : the ROM name (e.g. "dfe538")
#
CARD_DRIVER = $(firstword $(DRIVER_$(1)) $(1))
TGT_ELEMENTS = $(subst --, ,$(firstword $(subst ., ,$(notdir $@))))
TGT_ROM_NAME = $(firstword $(TGT_ELEMENTS))
TGT_DRIVERS = $(strip $(if $(DRIVERS_$(TGT_ROM_NAME)), \
$(DRIVERS_$(TGT_ROM_NAME)), \
$(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \
$(call CARD_DRIVER,$(TGT_ELEMENT))) ))
TGT_DRIVERS = $(strip $(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \
$(if $(DRIVERS_$(TGT_ELEMENT)), \
$(DRIVERS_$(TGT_ELEMENT)), \
$(firstword $(DRIVER_$(TGT_ELEMENT)) \
$(TGT_ELEMENT)))))
TGT_PREFIX_NAME = $(word 2,$(subst ., ,$(notdir $@)))
TGT_PREFIX = $(strip $(if $(filter rom,$(TGT_PREFIX_NAME)), \
$(ROM_TYPE_$(TGT_ROM_NAME))rom, \
@ -1014,10 +1092,12 @@ TGT_LD_FLAGS = $(foreach SYM,$(TGT_LD_ENTRY) $(TGT_LD_DRIVERS) \
# the target.
#
DEBUG_LIST = $(subst $(COMMA), ,$(DEBUG))
DEBUG_OBJ_LEVEL = $(firstword $(word 2,$(subst :, ,$(1))) 1)
DEBUG_OBJ_BASE = $(word 1,$(subst :, ,$(1))).dbg$(call DEBUG_OBJ_LEVEL,$(1))
DEBUG_OBJ = $(BIN)/$(call DEBUG_OBJ_BASE,$(1)).o
DEBUG_ORIG_OBJ = $(BIN)/$(word 1,$(subst :, ,$(1))).o
DEBUG_MAX = $(firstword $(word 2,$(subst :, ,$(1))) 1)
DEBUG_DFLT = $(if $(word 3,$(subst :, ,$(1))),.$(word 3,$(subst :, ,$(1))))
DEBUG_LEVEL = $(call DEBUG_MAX,$(1))$(call DEBUG_DFLT,$(1))
DEBUG_BASE = $(firstword $(subst :, ,$(1))).dbg$(call DEBUG_LEVEL,$(1))
DEBUG_OBJ = $(BIN)/$(call DEBUG_BASE,$(1)).o
DEBUG_ORIG_OBJ = $(BIN)/$(firstword $(subst :, ,$(1))).o
DEBUG_OBJS = $(foreach D,$(DEBUG_LIST),$(call DEBUG_OBJ,$(D)))
DEBUG_ORIG_OBJS = $(foreach D,$(DEBUG_LIST),$(call DEBUG_ORIG_OBJ,$(D)))
BLIB_OBJS = $(DEBUG_OBJS) $(filter-out $(DEBUG_ORIG_OBJS),$(BOBJS))
@ -1298,21 +1378,15 @@ CLEANUP += $(ZBIN)
#
# The EFI image converter
#
ELF2EFI_CFLAGS := -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \
-I$(ZLIB_DIR)/include -idirafter include
ELF2EFI_LDFLAGS := -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
-lbfd -ldl -lz -Wl,--no-warn-search-mismatch
$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 $< \
$(ELF2EFI_LDFLAGS) -o $@
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -DEFI_TARGET32 $< -o $@
CLEANUP += $(ELF2EFI32)
$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 $< \
$(ELF2EFI_LDFLAGS) -o $@
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -DEFI_TARGET64 $< -o $@
CLEANUP += $(ELF2EFI64)
$(EFIROM) : util/efirom.c $(MAKEDEPS)

View File

@ -0,0 +1,12 @@
# Assembler section type character
#
ASM_TCHAR := %
ASM_TCHAR_OPS := %%
# Include common ARM headers
#
INCDIRS += arch/arm/include
# ARM-specific directories containing source files
#
SRCDIRS += arch/arm/interface/efi

View File

@ -0,0 +1,6 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Include generic EFI Makefile
#
MAKEDEPS += Makefile.efi
include Makefile.efi

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 any later version.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/io.h>
#include <ipxe/arm_io.h>
/** @file
*
* iPXE I/O API for ARM
*
*/
/** An ARM I/O qword */
union arm32_io_qword {
uint64_t qword;
uint32_t dword[2];
};
/**
* Read 64-bit qword from memory-mapped device
*
* @v io_addr I/O address
* @ret data Value read
*
* This is not atomic for ARM32.
*/
static uint64_t arm32_readq ( volatile uint64_t *io_addr ) {
volatile union arm32_io_qword *ptr =
container_of ( io_addr, union arm32_io_qword, qword );
union arm32_io_qword tmp;
tmp.dword[0] = readl ( &ptr->dword[0] );
tmp.dword[1] = readl ( &ptr->dword[1] );
return tmp.qword;
}
/**
* Write 64-bit qword to memory-mapped device
*
* @v data Value to write
* @v io_addr I/O address
*
* This is not atomic for ARM32.
*/
static void arm32_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
volatile union arm32_io_qword *ptr =
container_of ( io_addr, union arm32_io_qword, qword );
union arm32_io_qword tmp;
tmp.qword = data;
writel ( tmp.dword[0], &ptr->dword[0] );
writel ( tmp.dword[1], &ptr->dword[1] );
}
PROVIDE_IOAPI_INLINE ( arm, phys_to_bus );
PROVIDE_IOAPI_INLINE ( arm, bus_to_phys );
PROVIDE_IOAPI_INLINE ( arm, readb );
PROVIDE_IOAPI_INLINE ( arm, readw );
PROVIDE_IOAPI_INLINE ( arm, readl );
PROVIDE_IOAPI_INLINE ( arm, writeb );
PROVIDE_IOAPI_INLINE ( arm, writew );
PROVIDE_IOAPI_INLINE ( arm, writel );
PROVIDE_IOAPI_INLINE ( arm, iodelay );
PROVIDE_IOAPI_INLINE ( arm, mb );
#ifdef __aarch64__
PROVIDE_IOAPI_INLINE ( arm, readq );
PROVIDE_IOAPI_INLINE ( arm, writeq );
#else
PROVIDE_IOAPI ( arm, readq, arm32_readq );
PROVIDE_IOAPI ( arm, writeq, arm32_writeq );
#endif

View File

@ -0,0 +1,12 @@
#ifndef _BITS_ACPI_H
#define _BITS_ACPI_H
/** @file
*
* ARM-specific ACPI API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_ACPI_H */

View File

@ -0,0 +1,13 @@
#ifndef _BITS_ENDIAN_H
#define _BITS_ENDIAN_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* ARM may be either little-endian or big-endian */
#ifdef __ARM_BIG_ENDIAN
#define __BYTE_ORDER __BIG_ENDIAN
#else
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
#endif /* _BITS_ENDIAN_H */

View File

@ -3,7 +3,7 @@
/** @file
*
* x86_64-specific entropy API implementations
* ARM-specific entropy API implementations
*
*/

View File

@ -0,0 +1,19 @@
#ifndef _BITS_ERRFILE_H
#define _BITS_ERRFILE_H
/** @file
*
* ARM-specific error file identifiers
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @addtogroup errfile Error file identifiers
* @{
*/
/** @} */
#endif /* _BITS_ERRFILE_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_HYPERV_H
#define _BITS_HYPERV_H
/** @file
*
* Hyper-V interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_HYPERV_H */

View File

@ -0,0 +1,14 @@
#ifndef _BITS_IO_H
#define _BITS_IO_H
/** @file
*
* ARM-specific I/O API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/arm_io.h>
#endif /* _BITS_IO_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_IOMAP_H
#define _BITS_IOMAP_H
/** @file
*
* ARM-specific I/O mapping API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_IOMAP_H */

View File

@ -0,0 +1,14 @@
#ifndef _BITS_NAP_H
#define _BITS_NAP_H
/** @file
*
* ARM-specific CPU sleeping API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efiarm_nap.h>
#endif /* _BITS_MAP_H */

View File

@ -0,0 +1,14 @@
#ifndef _BITS_PCI_IO_H
#define _BITS_PCI_IO_H
/** @file
*
* ARM PCI I/O API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/io.h>
#endif /* _BITS_PCI_IO_H */

View File

@ -3,7 +3,7 @@
/** @file
*
* x86_64-specific reboot API implementations
* ARM-specific reboot API implementations
*
*/

View File

@ -3,7 +3,7 @@
/** @file
*
* x86_64-specific sanboot API implementations
* ARM-specific sanboot API implementations
*
*/

View File

@ -3,8 +3,10 @@
/** @file
*
* i386-specific SMBIOS API implementations
* ARM-specific SMBIOS API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_SMBIOS_H */

View File

@ -3,7 +3,7 @@
/** @file
*
* x86_64-specific time API implementations
* ARM-specific time API implementations
*
*/

View File

@ -3,8 +3,10 @@
/** @file
*
* x86_64-specific user access API implementations
* ARM-specific user access API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_UACCESS_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_UART_H
#define _BITS_UART_H
/** @file
*
* 16550-compatible UART
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_UART_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_UMALLOC_H
#define _BITS_UMALLOC_H
/** @file
*
* ARM-specific user memory allocation API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_UMALLOC_H */

View File

@ -0,0 +1,158 @@
#ifndef _BITS_XEN_H
#define _BITS_XEN_H
/** @file
*
* Xen interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* Hypercall registers */
#ifdef __aarch64__
#define XEN_HC "x16"
#define XEN_REG1 "x0"
#define XEN_REG2 "x1"
#define XEN_REG3 "x2"
#define XEN_REG4 "x3"
#define XEN_REG5 "x4"
#else
#define XEN_HC "r12"
#define XEN_REG1 "r0"
#define XEN_REG2 "r1"
#define XEN_REG3 "r2"
#define XEN_REG4 "r3"
#define XEN_REG5 "r4"
#endif
/**
* Issue hypercall with one argument
*
* @v xen Xen hypervisor
* @v hypercall Hypercall number
* @v arg1 First argument
* @ret retval Return value
*/
static inline __attribute__ (( always_inline )) unsigned long
xen_hypercall_1 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
unsigned long arg1 ) {
register unsigned long hc asm ( XEN_HC ) = hypercall;
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
__asm__ __volatile__ ( "hvc %1"
: "+r" ( reg1 )
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
: "memory", "cc" );
return reg1;
}
/**
* Issue hypercall with two arguments
*
* @v xen Xen hypervisor
* @v hypercall Hypercall number
* @v arg1 First argument
* @v arg2 Second argument
* @ret retval Return value
*/
static inline __attribute__ (( always_inline )) unsigned long
xen_hypercall_2 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
unsigned long arg1, unsigned long arg2 ) {
register unsigned long hc asm ( XEN_HC ) = hypercall;
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
register unsigned long reg2 asm ( XEN_REG2 ) = arg2;
__asm__ __volatile__ ( "hvc %2"
: "+r" ( reg1 ), "+r" ( reg2 )
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
: "memory", "cc" );
return reg1;
}
/**
* Issue hypercall with three arguments
*
* @v xen Xen hypervisor
* @v hypercall Hypercall number
* @v arg1 First argument
* @v arg2 Second argument
* @v arg3 Third argument
* @ret retval Return value
*/
static inline __attribute__ (( always_inline )) unsigned long
xen_hypercall_3 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
unsigned long arg1, unsigned long arg2, unsigned long arg3 ) {
register unsigned long hc asm ( XEN_HC ) = hypercall;
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
register unsigned long reg2 asm ( XEN_REG2 ) = arg2;
register unsigned long reg3 asm ( XEN_REG3 ) = arg3;
__asm__ __volatile__ ( "hvc %3"
: "+r" ( reg1 ), "+r" ( reg2 ), "+r" ( reg3 )
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
: "memory", "cc" );
return reg1;
}
/**
* Issue hypercall with four arguments
*
* @v xen Xen hypervisor
* @v hypercall Hypercall number
* @v arg1 First argument
* @v arg2 Second argument
* @v arg3 Third argument
* @v arg4 Fourth argument
* @ret retval Return value
*/
static inline __attribute__ (( always_inline )) unsigned long
xen_hypercall_4 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
unsigned long arg1, unsigned long arg2, unsigned long arg3,
unsigned long arg4 ) {
register unsigned long hc asm ( XEN_HC ) = hypercall;
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
register unsigned long reg2 asm ( XEN_REG2 ) = arg2;
register unsigned long reg3 asm ( XEN_REG3 ) = arg3;
register unsigned long reg4 asm ( XEN_REG4 ) = arg4;
__asm__ __volatile__ ( "hvc %4"
: "+r" ( reg1 ), "+r" ( reg2 ), "+r" ( reg3 ),
"+r" ( reg4 )
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
: "memory", "cc" );
return reg1;
}
/**
* Issue hypercall with five arguments
*
* @v xen Xen hypervisor
* @v hypercall Hypercall number
* @v arg1 First argument
* @v arg2 Second argument
* @v arg3 Third argument
* @v arg4 Fourth argument
* @v arg5 Fifth argument
* @ret retval Return value
*/
static inline __attribute__ (( always_inline )) unsigned long
xen_hypercall_5 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
unsigned long arg1, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5 ) {
register unsigned long hc asm ( XEN_HC ) = hypercall;
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
register unsigned long reg2 asm ( XEN_REG2 ) = arg2;
register unsigned long reg3 asm ( XEN_REG3 ) = arg3;
register unsigned long reg4 asm ( XEN_REG4 ) = arg4;
register unsigned long reg5 asm ( XEN_REG5 ) = arg5;
__asm__ __volatile__ ( "hvc %5"
: "+r" ( reg1 ), "+r" ( reg2 ), "+r" ( reg3 ),
"+r" ( reg4 ), "+r" ( reg5 )
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
: "memory", "cc" );
return reg1;
}
#endif /* _BITS_XEN_H */

View File

@ -0,0 +1,105 @@
#ifndef _IPXE_ARM_IO_H
#define _IPXE_ARM_IO_H
/** @file
*
* iPXE I/O API for ARM
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef IOAPI_ARM
#define IOAPI_PREFIX_arm
#else
#define IOAPI_PREFIX_arm __arm_
#endif
/*
* Memory space mappings
*
*/
/** Page shift */
#define PAGE_SHIFT 12
/*
* Physical<->Bus address mappings
*
*/
static inline __always_inline unsigned long
IOAPI_INLINE ( arm, phys_to_bus ) ( unsigned long phys_addr ) {
return phys_addr;
}
static inline __always_inline unsigned long
IOAPI_INLINE ( arm, bus_to_phys ) ( unsigned long bus_addr ) {
return bus_addr;
}
/*
* MMIO reads and writes up to native word size
*
*/
#define ARM_READX( _api_func, _type, _insn_suffix, _reg_prefix ) \
static inline __always_inline _type \
IOAPI_INLINE ( arm, _api_func ) ( volatile _type *io_addr ) { \
_type data; \
__asm__ __volatile__ ( "ldr" _insn_suffix " %" _reg_prefix "0, %1" \
: "=r" ( data ) : "Qo" ( *io_addr ) ); \
return data; \
}
#ifdef __aarch64__
ARM_READX ( readb, uint8_t, "b", "w" );
ARM_READX ( readw, uint16_t, "h", "w" );
ARM_READX ( readl, uint32_t, "", "w" );
ARM_READX ( readq, uint64_t, "", "" );
#else
ARM_READX ( readb, uint8_t, "b", "" );
ARM_READX ( readw, uint16_t, "h", "" );
ARM_READX ( readl, uint32_t, "", "" );
#endif
#define ARM_WRITEX( _api_func, _type, _insn_suffix, _reg_prefix ) \
static inline __always_inline void \
IOAPI_INLINE ( arm, _api_func ) ( _type data, volatile _type *io_addr ) { \
__asm__ __volatile__ ( "str" _insn_suffix " %" _reg_prefix "0, %1" \
: : "r" ( data ), "Qo" ( *io_addr ) ); \
}
#ifdef __aarch64__
ARM_WRITEX ( writeb, uint8_t, "b", "w" );
ARM_WRITEX ( writew, uint16_t, "h", "w" );
ARM_WRITEX ( writel, uint32_t, "", "w" );
ARM_WRITEX ( writeq, uint64_t, "", "" );
#else
ARM_WRITEX ( writeb, uint8_t, "b", "" );
ARM_WRITEX ( writew, uint16_t, "h", "" );
ARM_WRITEX ( writel, uint32_t, "", "" );
#endif
/*
* Slow down I/O
*
*/
static inline __always_inline void
IOAPI_INLINE ( arm, iodelay ) ( void ) {
/* Nothing to do */
}
/*
* Memory barrier
*
*/
static inline __always_inline void
IOAPI_INLINE ( arm, mb ) ( void ) {
#ifdef __aarch64__
__asm__ __volatile__ ( "dmb sy" );
#else
__asm__ __volatile__ ( "dmb" );
#endif
}
#endif /* _IPXE_ARM_IO_H */

View File

@ -0,0 +1,18 @@
#ifndef _IPXE_EFIARM_NAP_H
#define _IPXE_EFIARM_NAP_H
/** @file
*
* EFI CPU sleeping
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef NAP_EFIARM
#define NAP_PREFIX_efiarm
#else
#define NAP_PREFIX_efiarm __efiarm_
#endif
#endif /* _IPXE_EFIARM_NAP_H */

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 any later version.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/nap.h>
#include <ipxe/efi/efi.h>
/** @file
*
* iPXE CPU sleeping API for EFI
*
*/
/**
* Sleep until next interrupt
*
*/
static void efiarm_cpu_nap ( void ) {
/*
* I can't find any EFI API that allows us to put the CPU to
* sleep. The CpuSleep() function is defined in CpuLib.h, but
* isn't part of any exposed protocol so we have no way to
* call it.
*
* The EFI shell doesn't seem to bother sleeping the CPU; it
* just sits there idly burning power.
*
*/
__asm__ __volatile__ ( "wfi" );
}
PROVIDE_NAP ( efiarm, cpu_nap, efiarm_cpu_nap );

View File

@ -0,0 +1,23 @@
# ARM32-specific directories containing source files
#
SRCDIRS += arch/arm32/core
SRCDIRS += arch/arm32/libgcc
# ARM32-specific flags
#
CFLAGS += -mthumb -mcpu=cortex-a15 -mabi=aapcs -mfloat-abi=soft
CFLAGS += -mword-relocations
ASFLAGS += -mthumb -mcpu=cortex-a15
# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
#
CFLAGS += -fshort-wchar
# Include common ARM Makefile
MAKEDEPS += arch/arm/Makefile
include arch/arm/Makefile
# Include platform-specific Makefile
#
MAKEDEPS += arch/arm32/Makefile.$(PLATFORM)
include arch/arm32/Makefile.$(PLATFORM)

View File

@ -0,0 +1,18 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# UEFI requires that enums are always 32 bits
#
CFLAGS += -fno-short-enums
# Specify EFI image builder
#
ELF2EFI = $(ELF2EFI32)
# Specify EFI boot file
#
EFI_BOOT_FILE = bootarm.efi
# Include generic EFI Makefile
#
MAKEDEPS += arch/arm/Makefile.efi
include arch/arm/Makefile.efi

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 any later version.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
#include <ipxe/bigint.h>
/** @file
*
* Big integer support
*/
/**
* Multiply big integers
*
* @v multiplicand0 Element 0 of big integer to be multiplied
* @v multiplier0 Element 0 of big integer to be multiplied
* @v result0 Element 0 of big integer to hold result
* @v size Number of elements
*/
void bigint_multiply_raw ( const uint32_t *multiplicand0,
const uint32_t *multiplier0,
uint32_t *result0, unsigned int size ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
( ( const void * ) multiplicand0 );
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
( ( const void * ) multiplier0 );
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
( ( void * ) result0 );
unsigned int i;
unsigned int j;
uint32_t multiplicand_element;
uint32_t multiplier_element;
uint32_t *result_elements;
uint32_t discard_low;
uint32_t discard_high;
uint32_t discard_temp;
/* Zero result */
memset ( result, 0, sizeof ( *result ) );
/* Multiply integers one element at a time */
for ( i = 0 ; i < size ; i++ ) {
multiplicand_element = multiplicand->element[i];
for ( j = 0 ; j < size ; j++ ) {
multiplier_element = multiplier->element[j];
result_elements = &result->element[ i + j ];
/* Perform a single multiply, and add the
* resulting double-element into the result,
* carrying as necessary. The carry can
* never overflow beyond the end of the
* result, since:
*
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
__asm__ __volatile__ ( "umull %1, %2, %5, %6\n\t"
"ldr %3, [%0]\n\t"
"adds %3, %1\n\t"
"stmia %0!, {%3}\n\t"
"ldr %3, [%0]\n\t"
"adcs %3, %2\n\t"
"stmia %0!, {%3}\n\t"
"bcc 2f\n\t"
"\n1:\n\t"
"ldr %3, [%0]\n\t"
"adcs %3, #0\n\t"
"stmia %0!, {%3}\n\t"
"bcs 1b\n\t"
"\n2:\n\t"
: "+l" ( result_elements ),
"=l" ( discard_low ),
"=l" ( discard_high ),
"=l" ( discard_temp ),
"+m" ( *result )
: "l" ( multiplicand_element ),
"l" ( multiplier_element )
: "cc" );
}
}
}

View File

@ -0,0 +1,32 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.arm
/*
* Save stack context for non-local goto
*/
.globl setjmp
.type setjmp, %function
setjmp:
/* Store registers */
stmia r0, { r4, r5, r6, r7, r8, r9, r10, fp, sp, lr }
/* Return 0 when returning as setjmp() */
mov r0, #0
bx lr
.size setjmp, . - setjmp
/*
* Non-local jump to a saved stack context
*/
.globl longjmp
.type longjmp, %function
longjmp:
/* Restore registers */
ldmia r0, { r4, r5, r6, r7, r8, r9, r10, fp, sp, lr }
/* Force result to non-zero */
movs r0, r1
moveq r0, #1
/* Return to setjmp() caller */
bx lr
.size longjmp, . - longjmp

View File

@ -0,0 +1,316 @@
#ifndef _BITS_BIGINT_H
#define _BITS_BIGINT_H
/** @file
*
* Big integer support
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
#include <strings.h>
/** Element of a big integer */
typedef uint32_t bigint_element_t;
/**
* Initialise big integer
*
* @v value0 Element 0 of big integer to initialise
* @v size Number of elements
* @v data Raw data
* @v len Length of raw data
*/
static inline __attribute__ (( always_inline )) void
bigint_init_raw ( uint32_t *value0, unsigned int size,
const void *data, size_t len ) {
size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
uint8_t *value_byte = ( ( void * ) value0 );
const uint8_t *data_byte = ( data + len );
/* Copy raw data in reverse order, padding with zeros */
while ( len-- )
*(value_byte++) = *(--data_byte);
while ( pad_len-- )
*(value_byte++) = 0;
}
/**
* Add big integers
*
* @v addend0 Element 0 of big integer to add
* @v value0 Element 0 of big integer to be added to
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
uint32_t *discard_addend;
uint32_t *discard_value;
uint32_t *discard_end;
uint32_t discard_addend_i;
uint32_t discard_value_i;
__asm__ __volatile__ ( "adds %2, %0, %8, lsl #2\n\t" /* clear CF */
"\n1:\n\t"
"ldmia %0!, {%3}\n\t"
"ldr %4, [%1]\n\t"
"adcs %4, %3\n\t"
"stmia %1!, {%4}\n\t"
"teq %0, %2\n\t"
"bne 1b\n\t"
: "=l" ( discard_addend ),
"=l" ( discard_value ),
"=l" ( discard_end ),
"=l" ( discard_addend_i ),
"=l" ( discard_value_i ),
"+m" ( *value )
: "0" ( addend0 ), "1" ( value0 ), "l" ( size )
: "cc" );
}
/**
* Subtract big integers
*
* @v subtrahend0 Element 0 of big integer to subtract
* @v value0 Element 0 of big integer to be subtracted from
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
uint32_t *discard_subtrahend;
uint32_t *discard_value;
uint32_t *discard_end;
uint32_t discard_subtrahend_i;
uint32_t discard_value_i;
__asm__ __volatile__ ( "add %2, %0, %8, lsl #2\n\t"
"cmp %2, %0\n\t" /* set CF */
"\n1:\n\t"
"ldmia %0!, {%3}\n\t"
"ldr %4, [%1]\n\t"
"sbcs %4, %3\n\t"
"stmia %1!, {%4}\n\t"
"teq %0, %2\n\t"
"bne 1b\n\t"
: "=l" ( discard_subtrahend ),
"=l" ( discard_value ),
"=l" ( discard_end ),
"=l" ( discard_subtrahend_i ),
"=l" ( discard_value_i ),
"+m" ( *value )
: "0" ( subtrahend0 ), "1" ( value0 ),
"l" ( size )
: "cc" );
}
/**
* Rotate big integer left
*
* @v value0 Element 0 of big integer
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
uint32_t *discard_value;
uint32_t *discard_end;
uint32_t discard_value_i;
__asm__ __volatile__ ( "adds %1, %0, %5, lsl #2\n\t" /* clear CF */
"\n1:\n\t"
"ldr %2, [%0]\n\t"
"adcs %2, %2\n\t"
"stmia %0!, {%2}\n\t"
"teq %0, %1\n\t"
"bne 1b\n\t"
: "=l" ( discard_value ),
"=l" ( discard_end ),
"=l" ( discard_value_i ),
"+m" ( *value )
: "0" ( value0 ), "1" ( size )
: "cc" );
}
/**
* Rotate big integer right
*
* @v value0 Element 0 of big integer
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
uint32_t *discard_value;
uint32_t *discard_end;
uint32_t discard_value_i;
__asm__ __volatile__ ( "adds %1, %0, %5, lsl #2\n\t" /* clear CF */
"\n1:\n\t"
"ldmdb %1!, {%2}\n\t"
"rrxs %2, %2\n\t"
"str %2, [%1]\n\t"
"teq %0, %1\n\t"
"bne 1b\n\t"
: "=l" ( discard_value ),
"=l" ( discard_end ),
"=l" ( discard_value_i ),
"+m" ( *value )
: "0" ( value0 ), "1" ( size )
: "cc" );
}
/**
* Test if big integer is equal to zero
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @ret is_zero Big integer is equal to zero
*/
static inline __attribute__ (( always_inline, pure )) int
bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) {
const uint32_t *value = value0;
uint32_t value_i;
do {
value_i = *(value++);
if ( value_i )
break;
} while ( --size );
return ( value_i == 0 );
}
/**
* Compare big integers
*
* @v value0 Element 0 of big integer
* @v reference0 Element 0 of reference big integer
* @v size Number of elements
* @ret geq Big integer is greater than or equal to the reference
*/
static inline __attribute__ (( always_inline, pure )) int
bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0,
unsigned int size ) {
const uint32_t *value = ( value0 + size );
const uint32_t *reference = ( reference0 + size );
uint32_t value_i;
uint32_t reference_i;
do {
value_i = *(--value);
reference_i = *(--reference);
if ( value_i != reference_i )
break;
} while ( --size );
return ( value_i >= reference_i );
}
/**
* Test if bit is set in big integer
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @v bit Bit to test
* @ret is_set Bit is set
*/
static inline __attribute__ (( always_inline )) int
bigint_bit_is_set_raw ( const uint32_t *value0, unsigned int size,
unsigned int bit ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( const void * ) value0 );
unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
return ( value->element[index] & ( 1 << subindex ) );
}
/**
* Find highest bit set in big integer
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @ret max_bit Highest bit set + 1 (or 0 if no bits set)
*/
static inline __attribute__ (( always_inline )) int
bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
const uint32_t *value = ( value0 + size );
int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
uint32_t value_i;
do {
value_i = *(--value);
max_bit -= ( 32 - fls ( value_i ) );
if ( value_i )
break;
} while ( --size );
return max_bit;
}
/**
* Grow big integer
*
* @v source0 Element 0 of source big integer
* @v source_size Number of elements in source big integer
* @v dest0 Element 0 of destination big integer
* @v dest_size Number of elements in destination big integer
*/
static inline __attribute__ (( always_inline )) void
bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
uint32_t *dest0, unsigned int dest_size ) {
unsigned int pad_size = ( dest_size - source_size );
memcpy ( dest0, source0, sizeof ( bigint_t ( source_size ) ) );
memset ( ( dest0 + source_size ), 0, sizeof ( bigint_t ( pad_size ) ) );
}
/**
* Shrink big integer
*
* @v source0 Element 0 of source big integer
* @v source_size Number of elements in source big integer
* @v dest0 Element 0 of destination big integer
* @v dest_size Number of elements in destination big integer
*/
static inline __attribute__ (( always_inline )) void
bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
uint32_t *dest0, unsigned int dest_size ) {
memcpy ( dest0, source0, sizeof ( bigint_t ( dest_size ) ) );
}
/**
* Finalise big integer
*
* @v value0 Element 0 of big integer to finalise
* @v size Number of elements
* @v out Output buffer
* @v len Length of output buffer
*/
static inline __attribute__ (( always_inline )) void
bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
void *out, size_t len ) {
const uint8_t *value_byte = ( ( const void * ) value0 );
uint8_t *out_byte = ( out + len );
/* Copy raw data in reverse order */
while ( len-- )
*(--out_byte) = *(value_byte++);
}
extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
const uint32_t *multiplier0,
uint32_t *value0, unsigned int size );
#endif /* _BITS_BIGINT_H */

View File

@ -0,0 +1,100 @@
#ifndef _BITS_BITOPS_H
#define _BITS_BITOPS_H
/** @file
*
* ARM bit operations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/**
* Test and set bit atomically
*
* @v bit Bit to set
* @v bits Bit field
* @ret old Old value of bit (zero or non-zero)
*/
static inline __attribute__ (( always_inline )) int
test_and_set_bit ( unsigned int bit, volatile void *bits ) {
unsigned int index = ( bit / 32 );
unsigned int offset = ( bit % 32 );
volatile uint32_t *dword = ( ( ( volatile uint32_t * ) bits ) + index );
uint32_t mask = ( 1UL << offset );
uint32_t old;
uint32_t new;
uint32_t flag;
__asm__ __volatile__ ( "\n1:\n\t"
"ldrex %0, %3\n\t"
"orr %1, %0, %4\n\t"
"strex %2, %1, %3\n\t"
"tst %2, %2\n\t"
"bne 1b\n\t"
: "=&r" ( old ), "=&r" ( new ), "=&l" ( flag ),
"+Q" ( *dword )
: "r" ( mask )
: "cc" );
return ( old & mask );
}
/**
* Test and clear bit atomically
*
* @v bit Bit to set
* @v bits Bit field
* @ret old Old value of bit (zero or non-zero)
*/
static inline __attribute__ (( always_inline )) int
test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
unsigned int index = ( bit / 32 );
unsigned int offset = ( bit % 32 );
volatile uint32_t *dword = ( ( ( volatile uint32_t * ) bits ) + index );
uint32_t mask = ( 1UL << offset );
uint32_t old;
uint32_t new;
uint32_t flag;
__asm__ __volatile__ ( "\n1:\n\t"
"ldrex %0, %3\n\t"
"bic %1, %0, %4\n\t"
"strex %2, %1, %3\n\t"
"tst %2, %2\n\t"
"bne 1b\n\t"
: "=&r" ( old ), "=&r" ( new ), "=&l" ( flag ),
"+Q" ( *dword )
: "r" ( mask )
: "cc" );
return ( old & mask );
}
/**
* Set bit atomically
*
* @v bit Bit to set
* @v bits Bit field
*/
static inline __attribute__ (( always_inline )) void
set_bit ( unsigned int bit, volatile void *bits ) {
test_and_set_bit ( bit, bits );
}
/**
* Clear bit atomically
*
* @v bit Bit to set
* @v bits Bit field
*/
static inline __attribute__ (( always_inline )) void
clear_bit ( unsigned int bit, volatile void *bits ) {
test_and_clear_bit ( bit, bits );
}
#endif /* _BITS_BITOPS_H */

View File

@ -0,0 +1,52 @@
#ifndef _BITS_BYTESWAP_H
#define _BITS_BYTESWAP_H
/** @file
*
* Byte-order swapping functions
*
*/
#include <stdint.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static inline __attribute__ (( always_inline, const )) uint16_t
__bswap_variable_16 ( uint16_t x ) {
__asm__ ( "rev16 %0, %1" : "=l" ( x ) : "l" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_16s ( uint16_t *x ) {
*x = __bswap_variable_16 ( *x );
}
static inline __attribute__ (( always_inline, const )) uint32_t
__bswap_variable_32 ( uint32_t x ) {
__asm__ ( "rev %0, %1" : "=l" ( x ) : "l" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_32s ( uint32_t *x ) {
*x = __bswap_variable_32 ( *x );
}
static inline __attribute__ (( always_inline, const )) uint64_t
__bswap_variable_64 ( uint64_t x ) {
uint32_t in_high = ( x >> 32 );
uint32_t in_low = ( x & 0xffffffffUL );
uint32_t out_high = __bswap_variable_32 ( in_low );
uint32_t out_low = __bswap_variable_32 ( in_high );
return ( ( ( ( uint64_t ) out_high ) << 32 ) |
( ( uint64_t ) out_low ) );
}
static inline __attribute__ (( always_inline )) void
__bswap_64s ( uint64_t *x ) {
*x = __bswap_variable_64 ( *x );
}
#endif

View File

@ -0,0 +1,16 @@
#ifndef _BITS_COMPILER_H
#define _BITS_COMPILER_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Dummy relocation type */
#define RELOC_TYPE_NONE R_ARM_NONE
#ifndef ASSEMBLY
#define __asmcall
#define __libgcc
#endif /* ASSEMBLY */
#endif /*_BITS_COMPILER_H */

View File

@ -0,0 +1,30 @@
#ifndef _BITS_PROFILE_H
#define _BITS_PROFILE_H
/** @file
*
* Profiling
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/**
* Get profiling timestamp
*
* @ret timestamp Timestamp
*/
static inline __attribute__ (( always_inline )) uint64_t
profile_timestamp ( void ) {
uint32_t cycles;
/* Read cycle counter */
__asm__ __volatile__ ( "mcr p15, 0, %1, c9, c12, 0\n\t"
"mrc p15, 0, %0, c9, c13, 0\n\t"
: "=r" ( cycles ) : "r" ( 1 ) );
return cycles;
}
#endif /* _BITS_PROFILE_H */

View File

@ -0,0 +1,23 @@
#ifndef _BITS_STDINT_H
#define _BITS_STDINT_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
typedef __SIZE_TYPE__ size_t;
typedef signed long ssize_t;
typedef signed long off_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
typedef unsigned long physaddr_t;
typedef unsigned long intptr_t;
#endif /* _BITS_STDINT_H */

View File

@ -0,0 +1,60 @@
#ifndef BITS_STRING_H
#define BITS_STRING_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* String functions
*
*/
/**
* Fill memory region
*
* @v dest Destination region
* @v character Fill character
* @v len Length
* @ret dest Destination region
*/
static inline __attribute__ (( always_inline )) void *
memset ( void *dest, int character, size_t len ) {
/* Not yet optimised */
generic_memset ( dest, character, len );
return dest;
}
/**
* Copy memory region
*
* @v dest Destination region
* @v src Source region
* @v len Length
* @ret dest Destination region
*/
static inline __attribute__ (( always_inline )) void *
memcpy ( void *dest, const void *src, size_t len ) {
/* Not yet optimised */
generic_memcpy ( dest, src, len );
return dest;
}
/**
* Copy (possibly overlapping) memory region
*
* @v dest Destination region
* @v src Source region
* @v len Length
* @ret dest Destination region
*/
static inline __attribute__ (( always_inline )) void *
memmove ( void *dest, const void *src, size_t len ) {
/* Not yet optimised */
generic_memmove ( dest, src, len );
return dest;
}
#endif /* BITS_STRING_H */

View File

@ -0,0 +1,85 @@
#ifndef _BITS_STRINGS_H
#define _BITS_STRINGS_H
/** @file
*
* String functions
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Find first (i.e. least significant) set bit
*
* @v value Value
* @ret lsb Least significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
unsigned long bits = value;
unsigned long lsb;
unsigned int lz;
/* Extract least significant set bit */
lsb = ( bits & -bits );
/* Count number of leading zeroes before LSB */
__asm__ ( "clz %0, %1" : "=r" ( lz ) : "r" ( lsb ) );
return ( 32 - lz );
}
/**
* Find first (i.e. least significant) set bit
*
* @v value Value
* @ret lsb Least significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
unsigned long high = ( value >> 32 );
unsigned long low = ( value >> 0 );
if ( low ) {
return ( __ffsl ( low ) );
} else if ( high ) {
return ( 32 + __ffsl ( high ) );
} else {
return 0;
}
}
/**
* Find last (i.e. most significant) set bit
*
* @v value Value
* @ret msb Most significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __flsl ( long value ) {
unsigned int lz;
/* Count number of leading zeroes */
__asm__ ( "clz %0, %1" : "=r" ( lz ) : "r" ( value ) );
return ( 32 - lz );
}
/**
* Find last (i.e. most significant) set bit
*
* @v value Value
* @ret msb Most significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __flsll ( long long value ){
unsigned long high = ( value >> 32 );
unsigned long low = ( value >> 0 );
if ( high ) {
return ( 32 + __flsl ( high ) );
} else if ( low ) {
return ( __flsl ( low ) );
} else {
return 0;
}
}
#endif /* _BITS_STRINGS_H */

View File

@ -0,0 +1,19 @@
#ifndef _BITS_TCPIP_H
#define _BITS_TCPIP_H
/** @file
*
* Transport-network layer interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static inline __attribute__ (( always_inline )) uint16_t
tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ) {
/* Not yet optimised */
return generic_tcpip_continue_chksum ( partial, data, len );
}
#endif /* _BITS_TCPIP_H */

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
#ifndef _DHCP_ARCH_H
#define _DHCP_ARCH_H
/** @file
*
* Architecture-specific DHCP options
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_ARM32
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif

View File

@ -0,0 +1,45 @@
#ifndef GDBMACH_H
#define GDBMACH_H
/** @file
*
* GDB architecture specifics
*
* This file declares functions for manipulating the machine state and
* debugging context.
*
*/
#include <stdint.h>
typedef unsigned long gdbreg_t;
/* Register snapshot */
enum {
/* Not yet implemented */
GDBMACH_NREGS,
};
#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) )
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
/* Not yet implemented */
( void ) regs;
( void ) pc;
}
static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
/* Not yet implemented */
( void ) regs;
( void ) step;
}
static inline void gdbmach_breakpoint ( void ) {
/* Not yet implemented */
}
extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
int enable );
extern void gdbmach_init ( void );
#endif /* GDBMACH_H */

View File

@ -0,0 +1,61 @@
#ifndef LIMITS_H
#define LIMITS_H 1
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* 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_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
/* 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 2147483647
#define LONG_MIN (-LONG_MAX - 1L)
/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
#define ULONG_MAX 4294967295UL
/* 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 */

View File

@ -0,0 +1,38 @@
#ifndef _SETJMP_H
#define _SETJMP_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/** A jump buffer */
typedef struct {
/** Saved r4 */
uint32_t r4;
/** Saved r5 */
uint32_t r5;
/** Saved r6 */
uint32_t r6;
/** Saved r7 */
uint32_t r7;
/** Saved r8 */
uint32_t r8;
/** Saved r9 */
uint32_t r9;
/** Saved r10 */
uint32_t r10;
/** Saved frame pointer (r11) */
uint32_t fp;
/** Saved stack pointer (r13) */
uint32_t sp;
/** Saved link register (r14) */
uint32_t lr;
} jmp_buf[1];
extern int __asmcall __attribute__ (( returns_twice ))
setjmp ( jmp_buf env );
extern void __asmcall __attribute__ (( noreturn ))
longjmp ( jmp_buf env, int val );
#endif /* _SETJMP_H */

View File

@ -0,0 +1,50 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.thumb
/**
* Unsigned long long division
*
* @v r1:r0 Dividend
* @v r3:r2 Divisor
* @ret r1:r0 Quotient
* @ret r3:r2 Remainder
*/
.section ".text.__aeabi_uldivmod", "ax", %progbits
.globl __aeabi_uldivmod
.type __aeabi_uldivmod, %function
__aeabi_uldivmod:
/* Allocate stack space for remainder and pointer to remainder */
push {r0, r1, r2, r3, r4, lr}
/* Call __udivmoddi4() */
add r4, sp, #8
str r4, [sp]
bl __udivmoddi4
/* Retrieve remainder and return */
add sp, sp, #8
pop {r2, r3, r4, pc}
.size __aeabi_uldivmod, . - __aeabi_uldivmod
/**
* Signed long long division
*
* @v r1:r0 Dividend
* @v r3:r2 Divisor
* @ret r1:r0 Quotient
* @ret r3:r2 Remainder
*/
.section ".text.__aeabi_ldivmod", "ax", %progbits
.globl __aeabi_ldivmod
.type __aeabi_ldivmod, %function
__aeabi_ldivmod:
/* Allocate stack space for remainder and pointer to remainder */
push {r0, r1, r2, r3, r4, lr}
/* Call __divmoddi4() */
add r4, sp, #8
str r4, [sp]
bl __divmoddi4
/* Retrieve remainder and return */
add sp, sp, #8
pop {r2, r3, r4, pc}
.size __aeabi_ldivmod, . - __aeabi_ldivmod

View File

@ -0,0 +1,88 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.arm
/**
* Logical shift left
*
* @v r1:r0 Value to shift
* @v r2 Shift amount
* @ret r1:r0 Shifted value
*/
.section ".text.__aeabi_llsl", "ax", %progbits
.globl __aeabi_llsl
.type __aeabi_llsl, %function
__aeabi_llsl:
/* r3 = ( shift - 32 ) */
subs r3, r2, #32
/* If shift >= 32, then
* high = ( low << ( shift - 32 ) )
*/
movpl r1, r0, lsl r3
/* If shift < 32, then
* high = ( ( high << shift ) | ( low >> ( 32 - shift ) ) )
*/
movmi r1, r1, lsl r2
rsbmi r3, r2, #32
orrmi r1, r1, r0, lsr r3
/* low = ( low << shift ) */
mov r0, r0, lsl r2
bx lr
.size __aeabi_llsl, . - __aeabi_llsl
/**
* Logical shift right
*
* @v r1:r0 Value to shift
* @v r2 Shift amount
* @ret r1:r0 Shifted value
*/
.section ".text.__aeabi_llsr", "ax", %progbits
.globl __aeabi_llsr
.type __aeabi_llsr, %function
__aeabi_llsr:
/* r3 = ( shift - 32 ) */
subs r3, r2, #32
/* If shift >= 32, then
* low = ( high >> ( shift - 32 ) )
*/
movpl r0, r1, lsr r3
/* If shift < 32, then
* low = ( ( low >> shift ) | ( high << ( 32 - shift ) ) )
*/
movmi r0, r0, lsr r2
rsbmi r3, r2, #32
orrmi r0, r0, r1, lsl r3
/* high = ( high >> shift ) */
mov r1, r1, lsr r2
bx lr
.size __aeabi_llsr, . - __aeabi_llsr
/**
* Arithmetic shift right
*
* @v r1:r0 Value to shift
* @v r2 Shift amount
* @ret r1:r0 Shifted value
*/
.section ".text.__aeabi_lasr", "ax", %progbits
.globl __aeabi_lasr
.type __aeabi_lasr, %function
__aeabi_lasr:
/* r3 = ( shift - 32 ) */
subs r3, r2, #32
/* If shift >= 32, then
* low = ( high >> ( shift - 32 ) )
*/
movpl r0, r1, asr r3
/* If shift < 32, then
* low = ( ( low >> shift ) | ( high << ( 32 - shift ) ) )
*/
movmi r0, r0, lsr r2
rsbmi r3, r2, #32
orrmi r0, r0, r1, lsl r3
/* high = ( high >> shift ) */
mov r1, r1, asr r2
bx lr
.size __aeabi_lasr, . - __aeabi_lasr

View File

@ -0,0 +1,33 @@
# ARM64-specific directories containing source files
#
SRCDIRS += arch/arm64/core
# ARM64-specific flags
#
CFLAGS += -mlittle-endian -mcmodel=small
CFLAGS += -fomit-frame-pointer
ASFLAGS += -mabi=lp64 -EL
# We want to specify the LP64 model. There is an explicit -mabi=lp64
# on GCC 4.9 and later, and no guarantee as to which is the default
# model. In earlier versions of GCC, there is no -mabi option and the
# default appears to be LP64 anyway.
#
ifeq ($(CCTYPE),gcc)
LP64_TEST = $(CC) -mabi=lp64 -x c -c /dev/null -o /dev/null >/dev/null 2>&1
LP64_FLAGS := $(shell $(LP64_TEST) && $(ECHO) '-mabi=lp64')
WORKAROUND_CFLAGS += $(LP64_FLAGS)
endif
# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
#
CFLAGS += -fshort-wchar
# Include common ARM Makefile
MAKEDEPS += arch/arm/Makefile
include arch/arm/Makefile
# Include platform-specific Makefile
#
MAKEDEPS += arch/arm64/Makefile.$(PLATFORM)
include arch/arm64/Makefile.$(PLATFORM)

View File

@ -0,0 +1,14 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Specify EFI image builder
#
ELF2EFI = $(ELF2EFI64)
# Specify EFI boot file
#
EFI_BOOT_FILE = bootaa64.efi
# Include generic EFI Makefile
#
MAKEDEPS += arch/arm/Makefile.efi
include arch/arm/Makefile.efi

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 any later version.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
#include <ipxe/bigint.h>
/** @file
*
* Big integer support
*/
/**
* Multiply big integers
*
* @v multiplicand0 Element 0 of big integer to be multiplied
* @v multiplier0 Element 0 of big integer to be multiplied
* @v result0 Element 0 of big integer to hold result
* @v size Number of elements
*/
void bigint_multiply_raw ( const uint64_t *multiplicand0,
const uint64_t *multiplier0,
uint64_t *result0, unsigned int size ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
( ( const void * ) multiplicand0 );
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
( ( const void * ) multiplier0 );
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
( ( void * ) result0 );
unsigned int i;
unsigned int j;
uint64_t multiplicand_element;
uint64_t multiplier_element;
uint64_t *result_elements;
uint64_t discard_low;
uint64_t discard_high;
uint64_t discard_temp_low;
uint64_t discard_temp_high;
/* Zero result */
memset ( result, 0, sizeof ( *result ) );
/* Multiply integers one element at a time */
for ( i = 0 ; i < size ; i++ ) {
multiplicand_element = multiplicand->element[i];
for ( j = 0 ; j < size ; j++ ) {
multiplier_element = multiplier->element[j];
result_elements = &result->element[ i + j ];
/* Perform a single multiply, and add the
* resulting double-element into the result,
* carrying as necessary. The carry can
* never overflow beyond the end of the
* result, since:
*
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
__asm__ __volatile__ ( "mul %1, %6, %7\n\t"
"umulh %2, %6, %7\n\t"
"ldp %3, %4, [%0]\n\t"
"adds %3, %3, %1\n\t"
"adcs %4, %4, %2\n\t"
"stp %3, %4, [%0], #16\n\t"
"bcc 2f\n\t"
"\n1:\n\t"
"ldr %3, [%0]\n\t"
"adcs %3, %3, xzr\n\t"
"str %3, [%0], #8\n\t"
"bcs 1b\n\t"
"\n2:\n\t"
: "+r" ( result_elements ),
"=&r" ( discard_low ),
"=&r" ( discard_high ),
"=r" ( discard_temp_low ),
"=r" ( discard_temp_high ),
"+m" ( *result )
: "r" ( multiplicand_element ),
"r" ( multiplier_element )
: "cc" );
}
}
}

View File

@ -0,0 +1,249 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 any later version.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
/** @file
*
* Optimised string operations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
/**
* Copy memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void arm64_memcpy ( void *dest, const void *src, size_t len ) {
void *discard_dest;
void *discard_end;
const void *discard_src;
size_t discard_offset;
unsigned long discard_data;
unsigned long discard_low;
unsigned long discard_high;
/* If length is too short for an "ldp"/"stp" instruction pair,
* then just copy individual bytes.
*/
if ( len < 16 ) {
__asm__ __volatile__ ( "cbz %0, 2f\n\t"
"\n1:\n\t"
"sub %0, %0, #1\n\t"
"ldrb %w1, [%3, %0]\n\t"
"strb %w1, [%2, %0]\n\t"
"cbnz %0, 1b\n\t"
"\n2:\n\t"
: "=&r" ( discard_offset ),
"=&r" ( discard_data )
: "r" ( dest ), "r" ( src ), "0" ( len )
: "memory" );
return;
}
/* Use "ldp"/"stp" to copy 16 bytes at a time: one initial
* potentially unaligned access, multiple destination-aligned
* accesses, one final potentially unaligned access.
*/
__asm__ __volatile__ ( "ldp %3, %4, [%1], #16\n\t"
"stp %3, %4, [%0], #16\n\t"
"and %3, %0, #15\n\t"
"sub %0, %0, %3\n\t"
"sub %1, %1, %3\n\t"
"bic %2, %5, #15\n\t"
"b 2f\n\t"
"\n1:\n\t"
"ldp %3, %4, [%1], #16\n\t"
"stp %3, %4, [%0], #16\n\t"
"\n2:\n\t"
"cmp %0, %2\n\t"
"bne 1b\n\t"
"ldp %3, %4, [%6, #-16]\n\t"
"stp %3, %4, [%5, #-16]\n\t"
: "=&r" ( discard_dest ),
"=&r" ( discard_src ),
"=&r" ( discard_end ),
"=&r" ( discard_low ),
"=&r" ( discard_high )
: "r" ( dest + len ), "r" ( src + len ),
"0" ( dest ), "1" ( src )
: "memory", "cc" );
}
/**
* Zero memory region
*
* @v dest Destination region
* @v len Length
*/
void arm64_bzero ( void *dest, size_t len ) {
size_t discard_offset;
void *discard_dest;
void *discard_end;
/* If length is too short for an "stp" instruction, then just
* zero individual bytes.
*/
if ( len < 16 ) {
__asm__ __volatile__ ( "cbz %0, 2f\n\t"
"\n1:\n\t"
"sub %0, %0, #1\n\t"
"strb wzr, [%1, %0]\n\t"
"cbnz %0, 1b\n\t"
"\n2:\n\t"
: "=&r" ( discard_offset )
: "r" ( dest ), "0" ( len )
: "memory" );
return;
}
/* Use "stp" to zero 16 bytes at a time: one initial
* potentially unaligned access, multiple aligned accesses,
* one final potentially unaligned access.
*/
__asm__ __volatile__ ( "stp xzr, xzr, [%0], #16\n\t"
"bic %0, %0, #15\n\t"
"bic %1, %2, #15\n\t"
"b 2f\n\t"
"\n1:\n\t"
"stp xzr, xzr, [%0], #16\n\t"
"\n2:\n\t"
"cmp %0, %1\n\t"
"bne 1b\n\t"
"stp xzr, xzr, [%2, #-16]\n\t"
: "=&r" ( discard_dest ),
"=&r" ( discard_end )
: "r" ( dest + len ), "0" ( dest )
: "memory", "cc" );
}
/**
* Fill memory region
*
* @v dest Destination region
* @v len Length
* @v character Fill character
*
* The unusual parameter order is to allow for more efficient
* tail-calling to arm64_memset() when zeroing a region.
*/
void arm64_memset ( void *dest, size_t len, int character ) {
size_t discard_offset;
/* Use optimised zeroing code if applicable */
if ( character == 0 ) {
arm64_bzero ( dest, len );
return;
}
/* Fill one byte at a time. Calling memset() with a non-zero
* value is relatively rare and unlikely to be
* performance-critical.
*/
__asm__ __volatile__ ( "cbz %0, 2f\n\t"
"\n1:\n\t"
"sub %0, %0, #1\n\t"
"strb %w2, [%1, %0]\n\t"
"cbnz %0, 1b\n\t"
"\n2:\n\t"
: "=&r" ( discard_offset )
: "r" ( dest ), "r" ( character ), "0" ( len )
: "memory" );
}
/**
* Copy (possibly overlapping) memory region forwards
*
* @v dest Destination region
* @v src Source region
* @v len Length
*/
void arm64_memmove_forwards ( void *dest, const void *src, size_t len ) {
void *discard_dest;
const void *discard_src;
unsigned long discard_data;
/* Assume memmove() is not performance-critical, and perform a
* bytewise copy for simplicity.
*/
__asm__ __volatile__ ( "b 2f\n\t"
"\n1:\n\t"
"ldrb %w2, [%1], #1\n\t"
"strb %w2, [%0], #1\n\t"
"\n2:\n\t"
"cmp %0, %3\n\t"
"bne 1b\n\t"
: "=&r" ( discard_dest ),
"=&r" ( discard_src ),
"=&r" ( discard_data )
: "r" ( dest + len ), "0" ( dest ), "1" ( src )
: "memory" );
}
/**
* Copy (possibly overlapping) memory region backwards
*
* @v dest Destination region
* @v src Source region
* @v len Length
*/
void arm64_memmove_backwards ( void *dest, const void *src, size_t len ) {
size_t discard_offset;
unsigned long discard_data;
/* Assume memmove() is not performance-critical, and perform a
* bytewise copy for simplicity.
*/
__asm__ __volatile__ ( "cbz %0, 2f\n\t"
"\n1:\n\t"
"sub %0, %0, #1\n\t"
"ldrb %w1, [%3, %0]\n\t"
"strb %w1, [%2, %0]\n\t"
"cbnz %0, 1b\n\t"
"\n2:\n\t"
: "=&r" ( discard_offset ),
"=&r" ( discard_data )
: "r" ( dest ), "r" ( src ), "0" ( len )
: "memory" );
}
/**
* Copy (possibly overlapping) memory region
*
* @v dest Destination region
* @v src Source region
* @v len Length
*/
void arm64_memmove ( void *dest, const void *src, size_t len ) {
if ( dest <= src ) {
arm64_memmove_forwards ( dest, src, len );
} else {
arm64_memmove_backwards ( dest, src, len );
}
}

View File

@ -0,0 +1,175 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* TCP/IP checksum
*
*/
#include <strings.h>
#include <ipxe/tcpip.h>
/** Alignment used by main checksumming loop */
#define TCPIP_CHKSUM_ALIGN 16
/** Number of steps in each iteration of the unrolled main checksumming loop */
#define TCPIP_CHKSUM_UNROLL 4
/**
* Calculate continued TCP/IP checkum
*
* @v sum Checksum of already-summed data, in network byte order
* @v data Data buffer
* @v len Length of data buffer
* @ret sum Updated checksum, in network byte order
*/
uint16_t tcpip_continue_chksum ( uint16_t sum, const void *data,
size_t len ) {
intptr_t start;
intptr_t end;
intptr_t mid;
unsigned int pre;
unsigned int post;
unsigned int first;
uint64_t discard_low;
uint64_t discard_high;
/* Avoid potentially undefined shift operation */
if ( len == 0 )
return sum;
/* Find maximally-aligned midpoint. For short blocks of data,
* this may be aligned to fewer than 16 bytes.
*/
start = ( ( intptr_t ) data );
end = ( start + len );
mid = ( end &
~( ( ~( 1UL << 63 ) ) >> ( 64 - flsl ( start ^ end ) ) ) );
/* Calculate pre- and post-alignment lengths */
pre = ( ( mid - start ) & ( TCPIP_CHKSUM_ALIGN - 1 ) );
post = ( ( end - mid ) & ( TCPIP_CHKSUM_ALIGN - 1 ) );
/* Calculate number of steps in first iteration of unrolled loop */
first = ( ( ( len - pre - post ) / TCPIP_CHKSUM_ALIGN ) &
( TCPIP_CHKSUM_UNROLL - 1 ) );
/* Calculate checksum */
__asm__ ( /* Invert sum */
"eor %w0, %w0, #0xffff\n\t"
/* Clear carry flag */
"cmn xzr, xzr\n\t"
/* Byteswap and sum pre-alignment byte, if applicable */
"tbz %w4, #0, 1f\n\t"
"ldrb %w2, [%1], #1\n\t"
"rev16 %w0, %w0\n\t"
"rev16 %w2, %w2\n\t"
"adcs %0, %0, %2\n\t"
"\n1:\n\t"
/* Sum pre-alignment halfword, if applicable */
"tbz %w4, #1, 1f\n\t"
"ldrh %w2, [%1], #2\n\t"
"adcs %0, %0, %2\n\t"
"\n1:\n\t"
/* Sum pre-alignment word, if applicable */
"tbz %w4, #2, 1f\n\t"
"ldr %w2, [%1], #4\n\t"
"adcs %0, %0, %2\n\t"
"\n1:\n\t"
/* Sum pre-alignment doubleword, if applicable */
"tbz %w4, #3, 1f\n\t"
"ldr %2, [%1], #8\n\t"
"adcs %0, %0, %2\n\t"
"\n1:\n\t"
/* Jump into unrolled (x4) main loop */
"adr %2, 2f\n\t"
"sub %2, %2, %5, lsl #3\n\t"
"sub %2, %2, %5, lsl #2\n\t"
"br %2\n\t"
"\n1:\n\t"
"ldp %2, %3, [%1], #16\n\t"
"adcs %0, %0, %2\n\t"
"adcs %0, %0, %3\n\t"
"ldp %2, %3, [%1], #16\n\t"
"adcs %0, %0, %2\n\t"
"adcs %0, %0, %3\n\t"
"ldp %2, %3, [%1], #16\n\t"
"adcs %0, %0, %2\n\t"
"adcs %0, %0, %3\n\t"
"ldp %2, %3, [%1], #16\n\t"
"adcs %0, %0, %2\n\t"
"adcs %0, %0, %3\n\t"
"\n2:\n\t"
"sub %2, %1, %6\n\t"
"cbnz %2, 1b\n\t"
/* Sum post-alignment doubleword, if applicable */
"tbz %w7, #3, 1f\n\t"
"ldr %2, [%1], #8\n\t"
"adcs %0, %0, %2\n\t"
"\n1:\n\t"
/* Sum post-alignment word, if applicable */
"tbz %w7, #2, 1f\n\t"
"ldr %w2, [%1], #4\n\t"
"adcs %0, %0, %2\n\t"
"\n1:\n\t"
/* Sum post-alignment halfword, if applicable */
"tbz %w7, #1, 1f\n\t"
"ldrh %w2, [%1], #2\n\t"
"adcs %0, %0, %2\n\t"
"\n1:\n\t"
/* Sum post-alignment byte, if applicable */
"tbz %w7, #0, 1f\n\t"
"ldrb %w2, [%1], #1\n\t"
"adcs %0, %0, %2\n\t"
"\n1:\n\t"
/* Fold down to a uint32_t plus carry flag */
"lsr %2, %0, #32\n\t"
"adcs %w0, %w0, %w2\n\t"
/* Fold down to a uint16_t plus carry in bit 16 */
"ubfm %2, %0, #0, #15\n\t"
"ubfm %3, %0, #16, #31\n\t"
"adc %w0, %w2, %w3\n\t"
/* Fold down to a uint16_t */
"tbz %w0, #16, 1f\n\t"
"mov %w2, #0xffff\n\t"
"sub %w0, %w0, %w2\n\t"
"tbz %w0, #16, 1f\n\t"
"sub %w0, %w0, %w2\n\t"
"\n1:\n\t"
/* Byteswap back, if applicable */
"tbz %w4, #0, 1f\n\t"
"rev16 %w0, %w0\n\t"
"\n1:\n\t"
/* Invert sum */
"eor %w0, %w0, #0xffff\n\t"
: "+r" ( sum ), "+r" ( data ), "=&r" ( discard_low ),
"=&r" ( discard_high )
: "r" ( pre ), "r" ( first ), "r" ( end - post ),
"r" ( post )
: "cc" );
return sum;
}

View File

@ -0,0 +1,56 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
/* Must match jmp_buf structure layout */
.struct 0
env_x19_x20: .quad 0, 0
env_x21_x22: .quad 0, 0
env_x23_x24: .quad 0, 0
env_x25_x26: .quad 0, 0
env_x27_x28: .quad 0, 0
env_x29_x30: .quad 0, 0
env_sp: .quad 0
.previous
/*
* Save stack context for non-local goto
*/
.globl setjmp
.type setjmp, %function
setjmp:
/* Store registers */
stp x19, x20, [x0, #env_x19_x20]
stp x21, x22, [x0, #env_x21_x22]
stp x23, x24, [x0, #env_x23_x24]
stp x25, x26, [x0, #env_x25_x26]
stp x27, x28, [x0, #env_x27_x28]
stp x29, x30, [x0, #env_x29_x30]
mov x16, sp
str x16, [x0, #env_sp]
/* Return 0 when returning as setjmp() */
mov x0, #0
ret
.size setjmp, . - setjmp
/*
* Non-local jump to a saved stack context
*/
.globl longjmp
.type longjmp, %function
longjmp:
/* Restore registers */
ldp x19, x20, [x0, #env_x19_x20]
ldp x21, x22, [x0, #env_x21_x22]
ldp x23, x24, [x0, #env_x23_x24]
ldp x25, x26, [x0, #env_x25_x26]
ldp x27, x28, [x0, #env_x27_x28]
ldp x29, x30, [x0, #env_x29_x30]
ldr x16, [x0, #env_sp]
mov sp, x16
/* Force result to non-zero */
cmp w1, #0
csinc w0, w1, w1, ne
/* Return to setjmp() caller */
br x30
.size longjmp, . - longjmp

View File

@ -0,0 +1,317 @@
#ifndef _BITS_BIGINT_H
#define _BITS_BIGINT_H
/** @file
*
* Big integer support
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
#include <strings.h>
/** Element of a big integer */
typedef uint64_t bigint_element_t;
/**
* Initialise big integer
*
* @v value0 Element 0 of big integer to initialise
* @v size Number of elements
* @v data Raw data
* @v len Length of raw data
*/
static inline __attribute__ (( always_inline )) void
bigint_init_raw ( uint64_t *value0, unsigned int size,
const void *data, size_t len ) {
size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
uint8_t *value_byte = ( ( void * ) value0 );
const uint8_t *data_byte = ( data + len );
/* Copy raw data in reverse order, padding with zeros */
while ( len-- )
*(value_byte++) = *(--data_byte);
while ( pad_len-- )
*(value_byte++) = 0;
}
/**
* Add big integers
*
* @v addend0 Element 0 of big integer to add
* @v value0 Element 0 of big integer to be added to
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_add_raw ( const uint64_t *addend0, uint64_t *value0,
unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
uint64_t *discard_addend;
uint64_t *discard_value;
uint64_t discard_addend_i;
uint64_t discard_value_i;
unsigned int discard_size;
__asm__ __volatile__ ( "cmn xzr, xzr\n\t" /* clear CF */
"\n1:\n\t"
"ldr %3, [%0], #8\n\t"
"ldr %4, [%1]\n\t"
"adcs %4, %4, %3\n\t"
"str %4, [%1], #8\n\t"
"sub %w2, %w2, #1\n\t"
"cbnz %w2, 1b\n\t"
: "=r" ( discard_addend ),
"=r" ( discard_value ),
"=r" ( discard_size ),
"=r" ( discard_addend_i ),
"=r" ( discard_value_i ),
"+m" ( *value )
: "0" ( addend0 ), "1" ( value0 ), "2" ( size )
: "cc" );
}
/**
* Subtract big integers
*
* @v subtrahend0 Element 0 of big integer to subtract
* @v value0 Element 0 of big integer to be subtracted from
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0,
unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
uint64_t *discard_subtrahend;
uint64_t *discard_value;
uint64_t discard_subtrahend_i;
uint64_t discard_value_i;
unsigned int discard_size;
__asm__ __volatile__ ( "cmp xzr, xzr\n\t" /* set CF */
"\n1:\n\t"
"ldr %3, [%0], #8\n\t"
"ldr %4, [%1]\n\t"
"sbcs %4, %4, %3\n\t"
"str %4, [%1], #8\n\t"
"sub %w2, %w2, #1\n\t"
"cbnz %w2, 1b\n\t"
: "=r" ( discard_subtrahend ),
"=r" ( discard_value ),
"=r" ( discard_size ),
"=r" ( discard_subtrahend_i ),
"=r" ( discard_value_i ),
"+m" ( *value )
: "0" ( subtrahend0 ), "1" ( value0 ),
"2" ( size )
: "cc" );
}
/**
* Rotate big integer left
*
* @v value0 Element 0 of big integer
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_rol_raw ( uint64_t *value0, unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
uint64_t *discard_value;
uint64_t discard_value_i;
unsigned int discard_size;
__asm__ __volatile__ ( "cmn xzr, xzr\n\t" /* clear CF */
"\n1:\n\t"
"ldr %2, [%0]\n\t"
"adcs %2, %2, %2\n\t"
"str %2, [%0], #8\n\t"
"sub %w1, %w1, #1\n\t"
"cbnz %w1, 1b\n\t"
: "=r" ( discard_value ),
"=r" ( discard_size ),
"=r" ( discard_value_i ),
"+m" ( *value )
: "0" ( value0 ), "1" ( size )
: "cc" );
}
/**
* Rotate big integer right
*
* @v value0 Element 0 of big integer
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_ror_raw ( uint64_t *value0, unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
uint64_t *discard_value;
uint64_t discard_value_i;
uint64_t discard_value_j;
unsigned int discard_size;
__asm__ __volatile__ ( "mov %3, #0\n\t"
"\n1:\n\t"
"sub %w1, %w1, #1\n\t"
"ldr %2, [%0, %1, lsl #3]\n\t"
"extr %3, %3, %2, #1\n\t"
"str %3, [%0, %1, lsl #3]\n\t"
"mov %3, %2\n\t"
"cbnz %w1, 1b\n\t"
: "=r" ( discard_value ),
"=r" ( discard_size ),
"=r" ( discard_value_i ),
"=r" ( discard_value_j ),
"+m" ( *value )
: "0" ( value0 ), "1" ( size ) );
}
/**
* Test if big integer is equal to zero
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @ret is_zero Big integer is equal to zero
*/
static inline __attribute__ (( always_inline, pure )) int
bigint_is_zero_raw ( const uint64_t *value0, unsigned int size ) {
const uint64_t *value = value0;
uint64_t value_i;
do {
value_i = *(value++);
if ( value_i )
break;
} while ( --size );
return ( value_i == 0 );
}
/**
* Compare big integers
*
* @v value0 Element 0 of big integer
* @v reference0 Element 0 of reference big integer
* @v size Number of elements
* @ret geq Big integer is greater than or equal to the reference
*/
static inline __attribute__ (( always_inline, pure )) int
bigint_is_geq_raw ( const uint64_t *value0, const uint64_t *reference0,
unsigned int size ) {
const uint64_t *value = ( value0 + size );
const uint64_t *reference = ( reference0 + size );
uint64_t value_i;
uint64_t reference_i;
do {
value_i = *(--value);
reference_i = *(--reference);
if ( value_i != reference_i )
break;
} while ( --size );
return ( value_i >= reference_i );
}
/**
* Test if bit is set in big integer
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @v bit Bit to test
* @ret is_set Bit is set
*/
static inline __attribute__ (( always_inline )) int
bigint_bit_is_set_raw ( const uint64_t *value0, unsigned int size,
unsigned int bit ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( const void * ) value0 );
unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
return ( !! ( value->element[index] & ( 1UL << subindex ) ) );
}
/**
* Find highest bit set in big integer
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @ret max_bit Highest bit set + 1 (or 0 if no bits set)
*/
static inline __attribute__ (( always_inline )) int
bigint_max_set_bit_raw ( const uint64_t *value0, unsigned int size ) {
const uint64_t *value = ( value0 + size );
int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
uint64_t value_i;
do {
value_i = *(--value);
max_bit -= ( 64 - fls ( value_i ) );
if ( value_i )
break;
} while ( --size );
return max_bit;
}
/**
* Grow big integer
*
* @v source0 Element 0 of source big integer
* @v source_size Number of elements in source big integer
* @v dest0 Element 0 of destination big integer
* @v dest_size Number of elements in destination big integer
*/
static inline __attribute__ (( always_inline )) void
bigint_grow_raw ( const uint64_t *source0, unsigned int source_size,
uint64_t *dest0, unsigned int dest_size ) {
unsigned int pad_size = ( dest_size - source_size );
memcpy ( dest0, source0, sizeof ( bigint_t ( source_size ) ) );
memset ( ( dest0 + source_size ), 0, sizeof ( bigint_t ( pad_size ) ) );
}
/**
* Shrink big integer
*
* @v source0 Element 0 of source big integer
* @v source_size Number of elements in source big integer
* @v dest0 Element 0 of destination big integer
* @v dest_size Number of elements in destination big integer
*/
static inline __attribute__ (( always_inline )) void
bigint_shrink_raw ( const uint64_t *source0, unsigned int source_size __unused,
uint64_t *dest0, unsigned int dest_size ) {
memcpy ( dest0, source0, sizeof ( bigint_t ( dest_size ) ) );
}
/**
* Finalise big integer
*
* @v value0 Element 0 of big integer to finalise
* @v size Number of elements
* @v out Output buffer
* @v len Length of output buffer
*/
static inline __attribute__ (( always_inline )) void
bigint_done_raw ( const uint64_t *value0, unsigned int size __unused,
void *out, size_t len ) {
const uint8_t *value_byte = ( ( const void * ) value0 );
uint8_t *out_byte = ( out + len );
/* Copy raw data in reverse order */
while ( len-- )
*(--out_byte) = *(value_byte++);
}
extern void bigint_multiply_raw ( const uint64_t *multiplicand0,
const uint64_t *multiplier0,
uint64_t *value0, unsigned int size );
#endif /* _BITS_BIGINT_H */

View File

@ -0,0 +1,100 @@
#ifndef _BITS_BITOPS_H
#define _BITS_BITOPS_H
/** @file
*
* ARM bit operations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/**
* Test and set bit atomically
*
* @v bit Bit to set
* @v bits Bit field
* @ret old Old value of bit (zero or non-zero)
*/
static inline __attribute__ (( always_inline )) int
test_and_set_bit ( unsigned int bit, volatile void *bits ) {
unsigned int index = ( bit / 64 );
unsigned int offset = ( bit % 64 );
volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
uint64_t mask = ( 1UL << offset );
uint64_t old;
uint64_t new;
uint32_t flag;
__asm__ __volatile__ ( "\n1:\n\t"
"ldxr %0, %3\n\t"
"orr %1, %0, %4\n\t"
"stxr %w2, %1, %3\n\t"
"tst %w2, %w2\n\t"
"bne 1b\n\t"
: "=&r" ( old ), "=&r" ( new ), "=&r" ( flag ),
"+Q" ( *qword )
: "r" ( mask )
: "cc" );
return ( !! ( old & mask ) );
}
/**
* Test and clear bit atomically
*
* @v bit Bit to set
* @v bits Bit field
* @ret old Old value of bit (zero or non-zero)
*/
static inline __attribute__ (( always_inline )) int
test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
unsigned int index = ( bit / 64 );
unsigned int offset = ( bit % 64 );
volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
uint64_t mask = ( 1UL << offset );
uint64_t old;
uint64_t new;
uint32_t flag;
__asm__ __volatile__ ( "\n1:\n\t"
"ldxr %0, %3\n\t"
"bic %1, %0, %4\n\t"
"stxr %w2, %1, %3\n\t"
"tst %w2, %w2\n\t"
"bne 1b\n\t"
: "=&r" ( old ), "=&r" ( new ), "=&r" ( flag ),
"+Q" ( *qword )
: "r" ( mask )
: "cc" );
return ( !! ( old & mask ) );
}
/**
* Set bit atomically
*
* @v bit Bit to set
* @v bits Bit field
*/
static inline __attribute__ (( always_inline )) void
set_bit ( unsigned int bit, volatile void *bits ) {
test_and_set_bit ( bit, bits );
}
/**
* Clear bit atomically
*
* @v bit Bit to set
* @v bits Bit field
*/
static inline __attribute__ (( always_inline )) void
clear_bit ( unsigned int bit, volatile void *bits ) {
test_and_clear_bit ( bit, bits );
}
#endif /* _BITS_BITOPS_H */

View File

@ -0,0 +1,47 @@
#ifndef _BITS_BYTESWAP_H
#define _BITS_BYTESWAP_H
/** @file
*
* Byte-order swapping functions
*
*/
#include <stdint.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static inline __attribute__ (( always_inline, const )) uint16_t
__bswap_variable_16 ( uint16_t x ) {
__asm__ ( "rev16 %0, %1" : "=r" ( x ) : "r" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_16s ( uint16_t *x ) {
*x = __bswap_variable_16 ( *x );
}
static inline __attribute__ (( always_inline, const )) uint32_t
__bswap_variable_32 ( uint32_t x ) {
__asm__ ( "rev32 %0, %1" : "=r" ( x ) : "r" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_32s ( uint32_t *x ) {
*x = __bswap_variable_32 ( *x );
}
static inline __attribute__ (( always_inline, const )) uint64_t
__bswap_variable_64 ( uint64_t x ) {
__asm__ ( "rev %0, %1" : "=r" ( x ) : "r" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_64s ( uint64_t *x ) {
*x = __bswap_variable_64 ( *x );
}
#endif

View File

@ -0,0 +1,16 @@
#ifndef _BITS_COMPILER_H
#define _BITS_COMPILER_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Dummy relocation type */
#define RELOC_TYPE_NONE R_AARCH64_NULL
#ifndef ASSEMBLY
#define __asmcall
#define __libgcc
#endif /* ASSEMBLY */
#endif /*_BITS_COMPILER_H */

View File

@ -0,0 +1,28 @@
#ifndef _BITS_PROFILE_H
#define _BITS_PROFILE_H
/** @file
*
* Profiling
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/**
* Get profiling timestamp
*
* @ret timestamp Timestamp
*/
static inline __attribute__ (( always_inline )) uint64_t
profile_timestamp ( void ) {
uint64_t cycles;
/* Read cycle counter */
__asm__ __volatile__ ( "mrs %0, CNTVCT_EL0\n\t" : "=r" ( cycles ) );
return cycles;
}
#endif /* _BITS_PROFILE_H */

View File

@ -0,0 +1,21 @@
#ifndef _BITS_STDINT_H
#define _BITS_STDINT_H
typedef __SIZE_TYPE__ size_t;
typedef signed long ssize_t;
typedef signed long off_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
typedef unsigned long physaddr_t;
typedef unsigned long intptr_t;
#endif /* _BITS_STDINT_H */

View File

@ -0,0 +1,106 @@
#ifndef BITS_STRING_H
#define BITS_STRING_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* String functions
*
*/
extern void arm64_bzero ( void *dest, size_t len );
extern void arm64_memset ( void *dest, size_t len, int character );
extern void arm64_memcpy ( void *dest, const void *src, size_t len );
extern void arm64_memmove_forwards ( void *dest, const void *src, size_t len );
extern void arm64_memmove_backwards ( void *dest, const void *src, size_t len );
extern void arm64_memmove ( void *dest, const void *src, size_t len );
/**
* Fill memory region
*
* @v dest Destination region
* @v character Fill character
* @v len Length
* @ret dest Destination region
*/
static inline __attribute__ (( always_inline )) void *
memset ( void *dest, int character, size_t len ) {
/* Allow gcc to generate inline "stX xzr" instructions for
* small, constant lengths.
*/
if ( __builtin_constant_p ( character ) && ( character == 0 ) &&
__builtin_constant_p ( len ) && ( len <= 64 ) ) {
__builtin_memset ( dest, 0, len );
return dest;
}
/* For zeroing larger or non-constant lengths, use the
* optimised variable-length zeroing code.
*/
if ( __builtin_constant_p ( character ) && ( character == 0 ) ) {
arm64_bzero ( dest, len );
return dest;
}
/* Not necessarily zeroing: use basic variable-length code */
arm64_memset ( dest, len, character );
return dest;
}
/**
* Copy memory region
*
* @v dest Destination region
* @v src Source region
* @v len Length
* @ret dest Destination region
*/
static inline __attribute__ (( always_inline )) void *
memcpy ( void *dest, const void *src, size_t len ) {
/* Allow gcc to generate inline "ldX"/"stX" instructions for
* small, constant lengths.
*/
if ( __builtin_constant_p ( len ) && ( len <= 64 ) ) {
__builtin_memcpy ( dest, src, len );
return dest;
}
/* Otherwise, use variable-length code */
arm64_memcpy ( dest, src, len );
return dest;
}
/**
* Copy (possibly overlapping) memory region
*
* @v dest Destination region
* @v src Source region
* @v len Length
* @ret dest Destination region
*/
static inline __attribute__ (( always_inline )) void *
memmove ( void *dest, const void *src, size_t len ) {
ssize_t offset = ( dest - src );
/* If required direction of copy is known at build time, then
* use the appropriate forwards/backwards copy directly.
*/
if ( __builtin_constant_p ( offset ) ) {
if ( offset <= 0 ) {
arm64_memmove_forwards ( dest, src, len );
return dest;
} else {
arm64_memmove_backwards ( dest, src, len );
return dest;
}
}
/* Otherwise, use ambidirectional copy */
arm64_memmove ( dest, src, len );
return dest;
}
#endif /* BITS_STRING_H */

View File

@ -0,0 +1,69 @@
#ifndef _BITS_STRINGS_H
#define _BITS_STRINGS_H
/** @file
*
* String functions
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Find first (i.e. least significant) set bit
*
* @v value Value
* @ret lsb Least significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
unsigned long long bits = value;
unsigned long long lsb;
unsigned int lz;
/* Extract least significant set bit */
lsb = ( bits & -bits );
/* Count number of leading zeroes before LSB */
__asm__ ( "clz %0, %1" : "=r" ( lz ) : "r" ( lsb ) );
return ( 64 - lz );
}
/**
* Find first (i.e. least significant) set bit
*
* @v value Value
* @ret lsb Least significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
return __ffsll ( value );
}
/**
* Find last (i.e. most significant) set bit
*
* @v value Value
* @ret msb Most significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __flsll ( long long value ){
unsigned int lz;
/* Count number of leading zeroes */
__asm__ ( "clz %0, %1" : "=r" ( lz ) : "r" ( value ) );
return ( 64 - lz );
}
/**
* Find last (i.e. most significant) set bit
*
* @v value Value
* @ret msb Most significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __flsl ( long value ) {
return __flsll ( value );
}
#endif /* _BITS_STRINGS_H */

View File

@ -0,0 +1,15 @@
#ifndef _BITS_TCPIP_H
#define _BITS_TCPIP_H
/** @file
*
* Transport-network layer interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern uint16_t tcpip_continue_chksum ( uint16_t sum, const void *data,
size_t len );
#endif /* _BITS_TCPIP_H */

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
#ifndef _DHCP_ARCH_H
#define _DHCP_ARCH_H
/** @file
*
* Architecture-specific DHCP options
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_ARM64
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif

View File

@ -0,0 +1,45 @@
#ifndef GDBMACH_H
#define GDBMACH_H
/** @file
*
* GDB architecture specifics
*
* This file declares functions for manipulating the machine state and
* debugging context.
*
*/
#include <stdint.h>
typedef unsigned long gdbreg_t;
/* Register snapshot */
enum {
/* Not yet implemented */
GDBMACH_NREGS,
};
#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) )
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
/* Not yet implemented */
( void ) regs;
( void ) pc;
}
static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
/* Not yet implemented */
( void ) regs;
( void ) step;
}
static inline void gdbmach_breakpoint ( void ) {
/* Not yet implemented */
}
extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
int enable );
extern void gdbmach_init ( void );
#endif /* GDBMACH_H */

View File

@ -0,0 +1,59 @@
#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_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
/* 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 */

View File

@ -0,0 +1,44 @@
#ifndef _SETJMP_H
#define _SETJMP_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/** A jump buffer */
typedef struct {
/** Saved x19 */
uint64_t x19;
/** Saved x20 */
uint64_t x20;
/** Saved x21 */
uint64_t x21;
/** Saved x22 */
uint64_t x22;
/** Saved x23 */
uint64_t x23;
/** Saved x24 */
uint64_t x24;
/** Saved x25 */
uint64_t x25;
/** Saved x26 */
uint64_t x26;
/** Saved x27 */
uint64_t x27;
/** Saved x28 */
uint64_t x28;
/** Saved frame pointer (x29) */
uint64_t x29;
/** Saved link register (x30) */
uint64_t x30;
/** Saved stack pointer (x31) */
uint64_t sp;
} jmp_buf[1];
extern int __asmcall __attribute__ (( returns_twice ))
setjmp ( jmp_buf env );
extern void __asmcall __attribute__ (( noreturn ))
longjmp ( jmp_buf env, int val );
#endif /* _SETJMP_H */

View File

@ -74,49 +74,21 @@ CFLAGS += -Ui386
# recognise an option that starts with "no", so we have to test for
# output on stderr instead of checking the exit status.
#
# Current versions of gcc require -no-pie; older versions require
# -nopie. We therefore test for both.
#
ifeq ($(CCTYPE),gcc)
PIE_TEST = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -nopie')
WORKAROUND_CFLAGS += $(PIE_FLAGS)
PIE_TEST = [ -z "`$(CC) -fno-PIE -no-pie -x c -c /dev/null -o /dev/null 2>&1`" ]
PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -no-pie')
PIE_TEST2 = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
PIE_FLAGS2 := $(shell $(PIE_TEST2) && $(ECHO) '-fno-PIE -nopie')
WORKAROUND_CFLAGS += $(PIE_FLAGS) $(PIE_FLAGS2)
endif
# Define version string for lkrnprefix.S
#
CFLAGS_lkrnprefix += -DVERSION="\"$(VERSION)\""
# Locations of isolinux files
#
SYSLINUX_DIR_LIST := \
/usr/lib/syslinux \
/usr/lib/syslinux/bios \
/usr/lib/syslinux/modules/bios \
/usr/share/syslinux \
/usr/share/syslinux/bios \
/usr/share/syslinux/modules/bios \
/usr/local/share/syslinux \
/usr/local/share/syslinux/bios \
/usr/local/share/syslinux/modules/bios \
/usr/lib/ISOLINUX
ISOLINUX_BIN_LIST := \
$(ISOLINUX_BIN) \
$(patsubst %,%/isolinux.bin,$(SYSLINUX_DIR_LIST))
LDLINUX_C32_LIST := \
$(LDLINUX_C32) \
$(patsubst %,%/ldlinux.c32,$(SYSLINUX_DIR_LIST))
ISOLINUX_BIN = $(firstword $(wildcard $(ISOLINUX_BIN_LIST)))
LDLINUX_C32 = $(firstword $(wildcard $(LDLINUX_C32_LIST)))
# i386-specific directories containing source files
#
SRCDIRS += arch/i386/core arch/i386/transitions arch/i386/prefix
SRCDIRS += arch/i386/firmware/pcbios
SRCDIRS += arch/i386/image
SRCDIRS += arch/i386/interface/pcbios
SRCDIRS += arch/i386/interface/pxe
SRCDIRS += arch/i386/interface/pxeparent
SRCDIRS += arch/i386/interface/syslinux
SRCDIRS += arch/i386/interface/vmware
SRCDIRS += arch/i386/hci/commands
SRCDIRS += arch/i386/core
SRCDIRS += arch/i386/tests
# Include common x86 Makefile
#

View File

@ -8,6 +8,10 @@ ELF2EFI = $(ELF2EFI32)
#
CFLAGS += -malign-double
# Specify EFI boot file
#
EFI_BOOT_FILE = bootia32.efi
# Include generic EFI Makefile
#
MAKEDEPS += arch/x86/Makefile.efi

View File

@ -1,101 +1,6 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# The i386 linker script
# Include generic BIOS Makefile
#
LDSCRIPT = arch/i386/scripts/i386.lds
# Stop ld from complaining about our customised linker script
#
LDFLAGS += -N --no-check-sections
# pcbios specific drivers
SRCDIRS += arch/i386/drivers
SRCDIRS += arch/i386/drivers/net
# Media types.
#
MEDIA += rom
MEDIA += mrom
MEDIA += pcirom
MEDIA += isarom
MEDIA += pxe
MEDIA += kpxe
MEDIA += kkpxe
MEDIA += kkkpxe
MEDIA += lkrn
MEDIA += dsk
MEDIA += nbi
MEDIA += hd
MEDIA += raw
MEDIA += exe
# Padding rules
#
PAD_rom = $(PERL) $(PADIMG) --blksize=512 --byte=0xff
PAD_mrom = $(PAD_rom)
PAD_pcirom = $(PAD_rom)
PAD_isarom = $(PAD_rom)
PAD_dsk = $(PERL) $(PADIMG) --blksize=512
PAD_hd = $(PERL) $(PADIMG) --blksize=32768
PAD_exe = $(PERL) $(PADIMG) --blksize=512
# Finalisation rules
#
FINALISE_rom = $(PERL) $(FIXROM)
FINALISE_mrom = $(FINALISE_rom)
FINALISE_pcirom = $(FINALISE_rom)
FINALISE_isarom = $(FINALISE_rom)
# Use $(ROMS) rather than $(DRIVERS) for "allroms", "allmroms", etc.
#
LIST_NAME_rom := ROMS
LIST_NAME_mrom := ROMS
LIST_NAME_pcirom := ROMS
LIST_NAME_isarom := ROMS
# rule to make a non-emulation ISO boot image
NON_AUTO_MEDIA += iso
%iso: %lkrn util/geniso
$(QM)$(ECHO) " [GENISO] $@"
$(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) LDLINUX_C32=$(LDLINUX_C32) \
VERSION="$(VERSION)" bash util/geniso -o $@ $<
# rule to make a floppy emulation ISO boot image
NON_AUTO_MEDIA += liso
%liso: %lkrn util/geniso
$(QM)$(ECHO) " [GENISO] $@"
$(Q)VERSION="$(VERSION)" bash util/geniso -l -o $@ $<
# rule to make a syslinux floppy image (mountable, bootable)
NON_AUTO_MEDIA += sdsk
%sdsk: %lkrn util/gensdsk
$(QM)$(ECHO) " [GENSDSK] $@"
$(Q)bash util/gensdsk $@ $<
# rule to write disk images to /dev/fd0
NON_AUTO_MEDIA += fd0
%fd0 : %dsk
$(QM)$(ECHO) " [DD] $@"
$(Q)dd if=$< bs=512 conv=sync of=/dev/fd0
$(Q)sync
# Special target for building Master Boot Record binary
$(BIN)/mbr.bin : $(BIN)/mbr.o
$(QM)$(ECHO) " [OBJCOPY] $@"
$(Q)$(OBJCOPY) -O binary $< $@
# rule to make a USB disk image
$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o
$(QM)$(ECHO) " [OBJCOPY] $@"
$(Q)$(OBJCOPY) -O binary $< $@
NON_AUTO_MEDIA += usb
%usb: $(BIN)/usbdisk.bin %hd
$(QM)$(ECHO) " [FINISH] $@"
$(Q)cat $^ > $@
# Padded floppy image (e.g. for iLO)
NON_AUTO_MEDIA += pdsk
%pdsk : %dsk
$(Q)cp $< $@
$(Q)$(PADIMG) --blksize=1474560 $@
MAKEDEPS += arch/x86/Makefile.pcbios
include arch/x86/Makefile.pcbios

View File

@ -15,41 +15,29 @@
/* POSIX signal numbers for reporting traps to GDB */
#define SIGILL 4
#define SIGTRAP 5
#define SIGBUS 7
#define SIGFPE 8
#define SIGSEGV 11
#define SIGSTKFLT 16
.globl gdbmach_nocode_sigfpe
gdbmach_nocode_sigfpe:
.globl gdbmach_sigfpe
gdbmach_sigfpe:
pushl $SIGFPE
jmp gdbmach_interrupt
.globl gdbmach_nocode_sigtrap
gdbmach_nocode_sigtrap:
.globl gdbmach_sigtrap
gdbmach_sigtrap:
pushl $SIGTRAP
jmp gdbmach_interrupt
.globl gdbmach_nocode_sigstkflt
gdbmach_nocode_sigstkflt:
.globl gdbmach_sigstkflt
gdbmach_sigstkflt:
pushl $SIGSTKFLT
jmp gdbmach_interrupt
.globl gdbmach_nocode_sigill
gdbmach_nocode_sigill:
.globl gdbmach_sigill
gdbmach_sigill:
pushl $SIGILL
jmp gdbmach_interrupt
.globl gdbmach_withcode_sigbus
gdbmach_withcode_sigbus:
movl $SIGBUS, (%esp)
jmp gdbmach_interrupt
.globl gdbmach_withcode_sigsegv
gdbmach_withcode_sigsegv:
movl $SIGSEGV, (%esp)
jmp gdbmach_interrupt
/* When invoked, the stack contains: eflags, cs, eip, signo. */
#define IH_OFFSET_GDB_REGS ( 0 )
#define IH_OFFSET_GDB_EIP ( IH_OFFSET_GDB_REGS + SIZEOF_I386_REGS )

View File

@ -1,184 +0,0 @@
/*
* Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
*
* 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 any later version.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdio.h>
#include <assert.h>
#include <ipxe/uaccess.h>
#include <ipxe/gdbstub.h>
#include <librm.h>
#include <gdbmach.h>
/** @file
*
* GDB architecture-specific bits for i386
*
*/
enum {
DR7_CLEAR = 0x00000400, /* disable hardware breakpoints */
DR6_CLEAR = 0xffff0ff0, /* clear breakpoint status */
};
/** Hardware breakpoint, fields stored in x86 bit pattern form */
struct hwbp {
int type; /* type (1=write watchpoint, 3=access watchpoint) */
unsigned long addr; /* linear address */
size_t len; /* length (0=1-byte, 1=2-byte, 3=4-byte) */
int enabled;
};
static struct hwbp hwbps [ 4 ];
static gdbreg_t dr7 = DR7_CLEAR;
static struct hwbp *gdbmach_find_hwbp ( int type, unsigned long addr, size_t len ) {
struct hwbp *available = NULL;
unsigned int i;
for ( i = 0; i < sizeof hwbps / sizeof hwbps [ 0 ]; i++ ) {
if ( hwbps [ i ].type == type && hwbps [ i ].addr == addr && hwbps [ i ].len == len ) {
return &hwbps [ i ];
}
if ( !hwbps [ i ].enabled ) {
available = &hwbps [ i ];
}
}
return available;
}
static void gdbmach_commit_hwbp ( struct hwbp *bp ) {
unsigned int regnum = bp - hwbps;
/* Set breakpoint address */
assert ( regnum < ( sizeof hwbps / sizeof hwbps [ 0 ] ) );
switch ( regnum ) {
case 0:
__asm__ __volatile__ ( "movl %0, %%dr0\n" : : "r" ( bp->addr ) );
break;
case 1:
__asm__ __volatile__ ( "movl %0, %%dr1\n" : : "r" ( bp->addr ) );
break;
case 2:
__asm__ __volatile__ ( "movl %0, %%dr2\n" : : "r" ( bp->addr ) );
break;
case 3:
__asm__ __volatile__ ( "movl %0, %%dr3\n" : : "r" ( bp->addr ) );
break;
}
/* Set type */
dr7 &= ~( 0x3 << ( 16 + 4 * regnum ) );
dr7 |= bp->type << ( 16 + 4 * regnum );
/* Set length */
dr7 &= ~( 0x3 << ( 18 + 4 * regnum ) );
dr7 |= bp->len << ( 18 + 4 * regnum );
/* Set/clear local enable bit */
dr7 &= ~( 0x3 << 2 * regnum );
dr7 |= bp->enabled << 2 * regnum;
}
int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ) {
struct hwbp *bp;
/* Check and convert breakpoint type to x86 type */
switch ( type ) {
case GDBMACH_WATCH:
type = 0x1;
break;
case GDBMACH_AWATCH:
type = 0x3;
break;
default:
return 0; /* unsupported breakpoint type */
}
/* Only lengths 1, 2, and 4 are supported */
if ( len != 2 && len != 4 ) {
len = 1;
}
len--; /* convert to x86 breakpoint length bit pattern */
/* Calculate linear address by adding segment base */
addr += virt_offset;
/* Set up the breakpoint */
bp = gdbmach_find_hwbp ( type, addr, len );
if ( !bp ) {
return 0; /* ran out of hardware breakpoints */
}
bp->type = type;
bp->addr = addr;
bp->len = len;
bp->enabled = enable;
gdbmach_commit_hwbp ( bp );
return 1;
}
static void gdbmach_disable_hwbps ( void ) {
/* Store and clear hardware breakpoints */
__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( DR7_CLEAR ) );
}
static void gdbmach_enable_hwbps ( void ) {
/* Clear breakpoint status register */
__asm__ __volatile__ ( "movl %0, %%dr6\n" : : "r" ( DR6_CLEAR ) );
/* Restore hardware breakpoints */
__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( dr7 ) );
}
__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
gdbmach_disable_hwbps();
gdbstub_handler ( signo, regs );
gdbmach_enable_hwbps();
}
static void * gdbmach_interrupt_vectors[] = {
gdbmach_nocode_sigfpe, /* Divide by zero */
gdbmach_nocode_sigtrap, /* Debug trap */
NULL, /* Non-maskable interrupt */
gdbmach_nocode_sigtrap, /* Breakpoint */
gdbmach_nocode_sigstkflt, /* Overflow */
gdbmach_nocode_sigstkflt, /* Bound range exceeded */
gdbmach_nocode_sigill, /* Invalid opcode */
NULL, /* Device not available */
gdbmach_withcode_sigbus, /* Double fault */
NULL, /* Coprocessor segment overrun */
gdbmach_withcode_sigsegv, /* Invalid TSS */
gdbmach_withcode_sigsegv, /* Segment not present */
gdbmach_withcode_sigsegv, /* Stack segment fault */
gdbmach_withcode_sigsegv, /* General protection fault */
gdbmach_withcode_sigsegv, /* Page fault */
};
void gdbmach_init ( void ) {
unsigned int i;
for ( i = 0 ; i < ( sizeof ( gdbmach_interrupt_vectors ) /
sizeof ( gdbmach_interrupt_vectors[0] ) ) ; i++ ) {
set_interrupt_vector ( i, gdbmach_interrupt_vectors[i] );
}
}

View File

@ -1,94 +0,0 @@
/*
* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 any later version.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* RDTSC timer
*
*/
#include <assert.h>
#include <ipxe/timer.h>
#include <ipxe/pit8254.h>
/**
* Number of TSC ticks per microsecond
*
* This is calibrated on the first use of the timer.
*/
static unsigned long rdtsc_ticks_per_usec;
/**
* Delay for a fixed number of microseconds
*
* @v usecs Number of microseconds for which to delay
*/
static void rdtsc_udelay ( unsigned long usecs ) {
unsigned long start;
unsigned long elapsed;
/* Sanity guard, since we may divide by this */
if ( ! usecs )
usecs = 1;
start = currticks();
if ( rdtsc_ticks_per_usec ) {
/* Already calibrated; busy-wait until done */
do {
elapsed = ( currticks() - start );
} while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
} else {
/* Not yet calibrated; use 8254 PIT and calibrate
* based on result.
*/
pit8254_udelay ( usecs );
elapsed = ( currticks() - start );
rdtsc_ticks_per_usec = ( elapsed / usecs );
DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
"(%ld MHz)\n", elapsed, usecs,
( rdtsc_ticks_per_usec << TSC_SHIFT ) );
}
}
/**
* Get number of ticks per second
*
* @ret ticks_per_sec Number of ticks per second
*/
static unsigned long rdtsc_ticks_per_sec ( void ) {
/* Calibrate timer, if not already done */
if ( ! rdtsc_ticks_per_usec )
udelay ( 1 );
/* Sanity check */
assert ( rdtsc_ticks_per_usec != 0 );
return ( rdtsc_ticks_per_usec * 1000 * 1000 );
}
PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
PROVIDE_TIMER_INLINE ( rdtsc, currticks );
PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );

View File

@ -1,145 +0,0 @@
/*
* Functions to support the virtual addressing method of relocation
* that Etherboot uses.
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#include "librm.h"
.arch i386
.text
.code32
/****************************************************************************
* _virt_to_phys (virtual addressing)
*
* Switch from virtual to flat physical addresses. %esp is adjusted
* to a physical value. Segment registers are set to flat physical
* selectors. All other registers are preserved. Flags are
* preserved.
*
* Parameters: none
* Returns: none
****************************************************************************
*/
.globl _virt_to_phys
_virt_to_phys:
/* Preserve registers and flags */
pushfl
pushl %eax
pushl %ebp
/* Change return address to a physical address */
movl virt_offset, %ebp
addl %ebp, 12(%esp)
/* Switch to physical code segment */
cli
pushl $PHYSICAL_CS
leal 1f(%ebp), %eax
pushl %eax
lret
1:
/* Reload other segment registers and adjust %esp */
movl $PHYSICAL_DS, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %fs
movl %eax, %gs
movl %eax, %ss
addl %ebp, %esp
/* Restore registers and flags, and return */
popl %ebp
popl %eax
popfl
ret
/****************************************************************************
* _phys_to_virt (flat physical addressing)
*
* Switch from flat physical to virtual addresses. %esp is adjusted
* to a virtual value. Segment registers are set to virtual
* selectors. All other registers are preserved. Flags are
* preserved.
*
* Parameters: none
* Returns: none
****************************************************************************
*/
.globl _phys_to_virt
_phys_to_virt:
/* Preserve registers and flags */
pushfl
pushl %eax
pushl %ebp
/* Switch to virtual code segment */
cli
ljmp $VIRTUAL_CS, $1f
1:
/* Reload data segment registers */
movl $VIRTUAL_DS, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %fs
movl %eax, %gs
/* Reload stack segment and adjust %esp */
movl virt_offset, %ebp
movl %eax, %ss
subl %ebp, %esp
/* Change the return address to a virtual address */
subl %ebp, 12(%esp)
/* Restore registers and flags, and return */
popl %ebp
popl %eax
popfl
ret
/****************************************************************************
* _intr_to_virt (virtual code segment, virtual or physical stack segment)
*
* Switch from virtual code segment with either a virtual or physical
* stack segment to using virtual addressing. %esp is adjusted if
* necessary to a virtual value. Segment registers are set to virtual
* selectors. All other registers are preserved. Flags are
* preserved.
*
* Parameters: none
* Returns: none
****************************************************************************
*/
.globl _intr_to_virt
_intr_to_virt:
/* Preserve registers and flags */
pushfl
pushl %eax
pushl %ebp
/* Check whether stack segment is physical or virtual */
movl %ss, %eax
cmpw $VIRTUAL_DS, %ax
movl $VIRTUAL_DS, %eax
/* Reload data segment registers */
movl %eax, %ds
movl %eax, %es
movl %eax, %fs
movl %eax, %gs
/* Reload stack segment and adjust %esp if necessary */
je 1f
movl virt_offset, %ebp
movl %eax, %ss
subl %ebp, %esp
1:
/* Restore registers and flags, and return */
popl %ebp
popl %eax
popfl
ret

View File

@ -9,7 +9,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef ASSEMBLY
/** Declare a function with standard calling conventions */
#define __asmcall __attribute__ (( cdecl, regparm(0) ))
#define __asmcall __attribute__ (( used, cdecl, regparm(0) ))
/**
* Declare a function with libgcc implicit linkage

View File

@ -46,27 +46,4 @@ hv_call ( struct hv_hypervisor *hv, unsigned int code, const void *in,
return result;
}
/**
* Set bit atomically
*
* @v bits Bit field
* @v bit Bit to set
*/
static inline __attribute__ (( always_inline )) void
hv_set_bit ( void *bits, unsigned int bit ) {
struct {
uint32_t dword[ ( bit / 32 ) + 1 ];
} *dwords = bits;
/* Set bit using "lock bts". Inform compiler that any memory
* from the start of the bit field up to and including the
* dword containing this bit may be modified. (This is
* overkill but shouldn't matter in practice since we're
* unlikely to subsequently read other bits from the same bit
* field.)
*/
__asm__ __volatile__ ( "lock bts %1, %0"
: "+m" ( *dwords ) : "Ir" ( bit ) );
}
#endif /* _BITS_HYPERV_H */

View File

@ -1,15 +0,0 @@
#ifndef _BITS_TIMER_H
#define _BITS_TIMER_H
/** @file
*
* i386-specific timer API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/bios_timer.h>
#include <ipxe/rdtsc_timer.h>
#endif /* _BITS_TIMER_H */

View File

@ -33,14 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#define DHCP_ARCH_VENDOR_CLASS_ID \
DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':', \
'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '6', ':', \
'U', 'N', 'D', 'I', ':', '0', '0', '3', '0', '1', '0' )
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_IA32
#define DHCP_ARCH_CLIENT_ARCHITECTURE \
DHCP_WORD ( DHCP_CLIENT_ARCHITECTURE_IA32 )
#define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 3, 10 /* v3.10 */ )
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif

View File

@ -47,12 +47,10 @@ enum {
};
/* Interrupt vectors */
extern void gdbmach_nocode_sigfpe ( void );
extern void gdbmach_nocode_sigtrap ( void );
extern void gdbmach_nocode_sigstkflt ( void );
extern void gdbmach_nocode_sigill ( void );
extern void gdbmach_withcode_sigbus ( void );
extern void gdbmach_withcode_sigsegv ( void );
extern void gdbmach_sigfpe ( void );
extern void gdbmach_sigtrap ( void );
extern void gdbmach_sigstkflt ( void );
extern void gdbmach_sigill ( void );
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
regs [ GDBMACH_EIP ] = pc;

View File

@ -1,44 +0,0 @@
#ifndef _IPXE_BIOS_TIMER_H
#define _IPXE_BIOS_TIMER_H
/** @file
*
* BIOS timer
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIMER_PCBIOS
#define TIMER_PREFIX_pcbios
#else
#define TIMER_PREFIX_pcbios __pcbios_
#endif
#include <ipxe/pit8254.h>
/**
* Delay for a fixed number of microseconds
*
* @v usecs Number of microseconds for which to delay
*/
static inline __always_inline void
TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) {
/* BIOS timer is not high-resolution enough for udelay(), so
* we use the 8254 Programmable Interval Timer.
*/
pit8254_udelay ( usecs );
}
/**
* Get number of ticks per second
*
* @ret ticks_per_sec Number of ticks per second
*/
static inline __always_inline unsigned long
TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) {
/* BIOS timer ticks over at 18.2 ticks per second */
return 18;
}
#endif /* _IPXE_BIOS_TIMER_H */

View File

@ -1,39 +0,0 @@
#ifndef _IPXE_RDTSC_TIMER_H
#define _IPXE_RDTSC_TIMER_H
/** @file
*
* RDTSC timer
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIMER_RDTSC
#define TIMER_PREFIX_rdtsc
#else
#define TIMER_PREFIX_rdtsc __rdtsc_
#endif
/**
* RDTSC values can easily overflow an unsigned long. We discard the
* low-order bits in order to obtain sensibly-scaled values.
*/
#define TSC_SHIFT 8
/**
* Get current system time in ticks
*
* @ret ticks Current time, in ticks
*/
static inline __always_inline unsigned long
TIMER_INLINE ( rdtsc, currticks ) ( void ) {
unsigned long ticks;
__asm__ __volatile__ ( "rdtsc\n\t"
"shrdl %1, %%edx, %%eax\n\t"
: "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
return ticks;
}
#endif /* _IPXE_RDTSC_TIMER_H */

View File

@ -33,14 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#define DHCP_ARCH_VENDOR_CLASS_ID \
DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':', \
'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '0', ':', \
'U', 'N', 'D', 'I', ':', '0', '0', '2', '0', '0', '1' )
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_X86
#define DHCP_ARCH_CLIENT_ARCHITECTURE \
DHCP_WORD ( DHCP_CLIENT_ARCHITECTURE_X86 )
#define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 2, 1 /* v2.1 */ )
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 2, 1 /* v2.1 */
#endif

View File

@ -1,11 +0,0 @@
#ifndef PXEPARENT_H
#define PXEPARENT_H
FILE_LICENCE ( GPL2_OR_LATER );
#include <pxe_types.h>
extern int pxeparent_call ( SEGOFF16_t entry, unsigned int function,
void *params, size_t params_len );
#endif

View File

@ -4,7 +4,6 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <realmode.h>
/** A jump buffer */
typedef struct {
@ -22,29 +21,10 @@ typedef struct {
uint32_t ebp;
} jmp_buf[1];
/** A real-mode-extended jump buffer */
typedef struct {
/** Jump buffer */
jmp_buf env;
/** Real-mode stack pointer */
segoff_t rm_stack;
} rmjmp_buf[1];
extern int __asmcall __attribute__ (( returns_twice ))
setjmp ( jmp_buf env );
extern void __asmcall __attribute__ (( noreturn ))
longjmp ( jmp_buf env, int val );
#define rmsetjmp( _env ) ( { \
(_env)->rm_stack.segment = rm_ss; \
(_env)->rm_stack.offset = rm_sp; \
setjmp ( (_env)->env ); } ) \
#define rmlongjmp( _env, _val ) do { \
rm_ss = (_env)->rm_stack.segment; \
rm_sp = (_env)->rm_stack.offset; \
longjmp ( (_env)->env, (_val) ); \
} while ( 0 )
#endif /* _SETJMP_H */

View File

@ -1,283 +0,0 @@
/*
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 any later version.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/dhcp.h>
#include <ipxe/profile.h>
#include <pxeparent.h>
#include <pxe_api.h>
#include <pxe_types.h>
#include <pxe.h>
/** @file
*
* Call interface to parent PXE stack
*
*/
/* Disambiguate the various error causes */
#define EINFO_EPXECALL \
__einfo_uniqify ( EINFO_EPLATFORM, 0x01, \
"External PXE API error" )
#define EPXECALL( status ) EPLATFORM ( EINFO_EPXECALL, status )
/** A parent PXE API call profiler */
struct pxeparent_profiler {
/** Total time spent performing REAL_CALL() */
struct profiler total;
/** Time spent transitioning to real mode */
struct profiler p2r;
/** Time spent in external code */
struct profiler ext;
/** Time spent transitioning back to protected mode */
struct profiler r2p;
};
/** PXENV_UNDI_TRANSMIT profiler */
static struct pxeparent_profiler pxeparent_tx_profiler __profiler = {
{ .name = "pxeparent.tx" },
{ .name = "pxeparent.tx_p2r" },
{ .name = "pxeparent.tx_ext" },
{ .name = "pxeparent.tx_r2p" },
};
/** PXENV_UNDI_ISR profiler
*
* Note that this profiler will not see calls to
* PXENV_UNDI_ISR_IN_START, which are handled by the UNDI ISR and do
* not go via pxeparent_call().
*/
static struct pxeparent_profiler pxeparent_isr_profiler __profiler = {
{ .name = "pxeparent.isr" },
{ .name = "pxeparent.isr_p2r" },
{ .name = "pxeparent.isr_ext" },
{ .name = "pxeparent.isr_r2p" },
};
/** PXE unknown API call profiler
*
* This profiler can be used to measure the overhead of a dummy PXE
* API call.
*/
static struct pxeparent_profiler pxeparent_unknown_profiler __profiler = {
{ .name = "pxeparent.unknown" },
{ .name = "pxeparent.unknown_p2r" },
{ .name = "pxeparent.unknown_ext" },
{ .name = "pxeparent.unknown_r2p" },
};
/** Miscellaneous PXE API call profiler */
static struct pxeparent_profiler pxeparent_misc_profiler __profiler = {
{ .name = "pxeparent.misc" },
{ .name = "pxeparent.misc_p2r" },
{ .name = "pxeparent.misc_ext" },
{ .name = "pxeparent.misc_r2p" },
};
/**
* Name PXE API call
*
* @v function API call number
* @ret name API call name
*/
static inline __attribute__ (( always_inline )) const char *
pxeparent_function_name ( unsigned int function ) {
switch ( function ) {
case PXENV_START_UNDI:
return "PXENV_START_UNDI";
case PXENV_STOP_UNDI:
return "PXENV_STOP_UNDI";
case PXENV_UNDI_STARTUP:
return "PXENV_UNDI_STARTUP";
case PXENV_UNDI_CLEANUP:
return "PXENV_UNDI_CLEANUP";
case PXENV_UNDI_INITIALIZE:
return "PXENV_UNDI_INITIALIZE";
case PXENV_UNDI_RESET_ADAPTER:
return "PXENV_UNDI_RESET_ADAPTER";
case PXENV_UNDI_SHUTDOWN:
return "PXENV_UNDI_SHUTDOWN";
case PXENV_UNDI_OPEN:
return "PXENV_UNDI_OPEN";
case PXENV_UNDI_CLOSE:
return "PXENV_UNDI_CLOSE";
case PXENV_UNDI_TRANSMIT:
return "PXENV_UNDI_TRANSMIT";
case PXENV_UNDI_SET_MCAST_ADDRESS:
return "PXENV_UNDI_SET_MCAST_ADDRESS";
case PXENV_UNDI_SET_STATION_ADDRESS:
return "PXENV_UNDI_SET_STATION_ADDRESS";
case PXENV_UNDI_SET_PACKET_FILTER:
return "PXENV_UNDI_SET_PACKET_FILTER";
case PXENV_UNDI_GET_INFORMATION:
return "PXENV_UNDI_GET_INFORMATION";
case PXENV_UNDI_GET_STATISTICS:
return "PXENV_UNDI_GET_STATISTICS";
case PXENV_UNDI_CLEAR_STATISTICS:
return "PXENV_UNDI_CLEAR_STATISTICS";
case PXENV_UNDI_INITIATE_DIAGS:
return "PXENV_UNDI_INITIATE_DIAGS";
case PXENV_UNDI_FORCE_INTERRUPT:
return "PXENV_UNDI_FORCE_INTERRUPT";
case PXENV_UNDI_GET_MCAST_ADDRESS:
return "PXENV_UNDI_GET_MCAST_ADDRESS";
case PXENV_UNDI_GET_NIC_TYPE:
return "PXENV_UNDI_GET_NIC_TYPE";
case PXENV_UNDI_GET_IFACE_INFO:
return "PXENV_UNDI_GET_IFACE_INFO";
/*
* Duplicate case value; this is a bug in the PXE specification.
*
* case PXENV_UNDI_GET_STATE:
* return "PXENV_UNDI_GET_STATE";
*/
case PXENV_UNDI_ISR:
return "PXENV_UNDI_ISR";
case PXENV_GET_CACHED_INFO:
return "PXENV_GET_CACHED_INFO";
default:
return "UNKNOWN API CALL";
}
}
/**
* Determine applicable profiler pair (for debugging)
*
* @v function API call number
* @ret profiler Profiler
*/
static struct pxeparent_profiler * pxeparent_profiler ( unsigned int function ){
/* Determine applicable profiler */
switch ( function ) {
case PXENV_UNDI_TRANSMIT:
return &pxeparent_tx_profiler;
case PXENV_UNDI_ISR:
return &pxeparent_isr_profiler;
case PXENV_UNKNOWN:
return &pxeparent_unknown_profiler;
default:
return &pxeparent_misc_profiler;
}
}
/**
* PXE parent parameter block
*
* Used as the parameter block for all parent PXE API calls. Resides
* in base memory.
*/
static union u_PXENV_ANY __bss16 ( pxeparent_params );
#define pxeparent_params __use_data16 ( pxeparent_params )
/** PXE parent entry point
*
* Used as the indirection vector for all parent PXE API calls. Resides in
* base memory.
*/
SEGOFF16_t __bss16 ( pxeparent_entry_point );
#define pxeparent_entry_point __use_data16 ( pxeparent_entry_point )
/**
* Issue parent PXE API call
*
* @v entry Parent PXE stack entry point
* @v function API call number
* @v params PXE parameter block
* @v params_len Length of PXE parameter block
* @ret rc Return status code
*/
int pxeparent_call ( SEGOFF16_t entry, unsigned int function,
void *params, size_t params_len ) {
struct pxeparent_profiler *profiler = pxeparent_profiler ( function );
PXENV_EXIT_t exit;
unsigned long started;
unsigned long stopped;
int discard_D;
int rc;
/* Copy parameter block and entry point */
assert ( params_len <= sizeof ( pxeparent_params ) );
memcpy ( &pxeparent_params, params, params_len );
memcpy ( &pxeparent_entry_point, &entry, sizeof ( entry ) );
/* Call real-mode entry point. This calling convention will
* work with both the !PXE and the PXENV+ entry points.
*/
profile_start ( &profiler->total );
__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
"rdtsc\n\t"
"pushl %%eax\n\t"
"pushw %%es\n\t"
"pushw %%di\n\t"
"pushw %%bx\n\t"
"lcall *pxeparent_entry_point\n\t"
"movw %%ax, %%bx\n\t"
"rdtsc\n\t"
"addw $6, %%sp\n\t"
"popl %%edx\n\t"
"popl %%ebp\n\t" /* gcc bug */ )
: "=a" ( stopped ), "=d" ( started ),
"=b" ( exit ), "=D" ( discard_D )
: "b" ( function ),
"D" ( __from_data16 ( &pxeparent_params ) )
: "ecx", "esi" );
profile_stop ( &profiler->total );
profile_start_at ( &profiler->p2r, profile_started ( &profiler->total));
profile_stop_at ( &profiler->p2r, started );
profile_start_at ( &profiler->ext, started );
profile_stop_at ( &profiler->ext, stopped );
profile_start_at ( &profiler->r2p, stopped );
profile_stop_at ( &profiler->r2p, profile_stopped ( &profiler->total ));
/* Determine return status code based on PXENV_EXIT and
* PXENV_STATUS
*/
rc = ( ( exit == PXENV_EXIT_SUCCESS ) ?
0 : -EPXECALL ( pxeparent_params.Status ) );
/* If anything goes wrong, print as much debug information as
* it's possible to give.
*/
if ( rc != 0 ) {
SEGOFF16_t rm_params = {
.segment = rm_ds,
.offset = __from_data16 ( &pxeparent_params ),
};
DBG ( "PXEPARENT %s failed: %s\n",
pxeparent_function_name ( function ), strerror ( rc ) );
DBG ( "PXEPARENT parameters at %04x:%04x length "
"%#02zx, entry point at %04x:%04x\n",
rm_params.segment, rm_params.offset, params_len,
pxeparent_entry_point.segment,
pxeparent_entry_point.offset );
DBG ( "PXEPARENT parameters provided:\n" );
DBG_HDA ( rm_params, params, params_len );
DBG ( "PXEPARENT parameters returned:\n" );
DBG_HDA ( rm_params, &pxeparent_params, params_len );
}
/* Copy parameter block back */
memcpy ( params, &pxeparent_params, params_len );
return rc;
}

View File

@ -1,671 +0,0 @@
/*
* librm: a library for interfacing to real-mode code
*
* Michael Brown <mbrown@fensystems.co.uk>
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
/* Drag in local definitions */
#include "librm.h"
/* For switches to/from protected mode */
#define CR0_PE 1
/* Size of various C data structures */
#define SIZEOF_I386_SEG_REGS 12
#define SIZEOF_I386_REGS 32
#define SIZEOF_REAL_MODE_REGS ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
#define SIZEOF_I386_FLAGS 4
#define SIZEOF_I386_ALL_REGS ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
.arch i386
/****************************************************************************
* Global descriptor table
*
* Call init_librm to set up the GDT before attempting to use any
* protected-mode code.
*
* NOTE: This must be located before prot_to_real, otherwise gas
* throws a "can't handle non absolute segment in `ljmp'" error due to
* not knowing the value of REAL_CS when the ljmp is encountered.
*
* Note also that putting ".word gdt_end - gdt - 1" directly into
* gdt_limit, rather than going via gdt_length, will also produce the
* "non absolute segment" error. This is most probably a bug in gas.
****************************************************************************
*/
.section ".data16", "aw", @progbits
.align 16
gdt:
gdtr: /* The first GDT entry is unused, the GDTR can fit here. */
gdt_limit: .word gdt_length - 1
gdt_base: .long 0
.word 0 /* padding */
.org gdt + VIRTUAL_CS, 0
virtual_cs: /* 32 bit protected mode code segment, virtual addresses */
.word 0xffff, 0
.byte 0, 0x9f, 0xcf, 0
.org gdt + VIRTUAL_DS, 0
virtual_ds: /* 32 bit protected mode data segment, virtual addresses */
.word 0xffff, 0
.byte 0, 0x93, 0xcf, 0
.org gdt + PHYSICAL_CS, 0
physical_cs: /* 32 bit protected mode code segment, physical addresses */
.word 0xffff, 0
.byte 0, 0x9f, 0xcf, 0
.org gdt + PHYSICAL_DS, 0
physical_ds: /* 32 bit protected mode data segment, physical addresses */
.word 0xffff, 0
.byte 0, 0x93, 0xcf, 0
.org gdt + REAL_CS, 0
real_cs: /* 16 bit real mode code segment */
.word 0xffff, 0
.byte 0, 0x9b, 0x00, 0
.org gdt + REAL_DS
real_ds: /* 16 bit real mode data segment */
.word 0xffff, ( REAL_DS << 4 )
.byte 0, 0x93, 0x00, 0
gdt_end:
.equ gdt_length, gdt_end - gdt
/****************************************************************************
* init_librm (real-mode far call, 16-bit real-mode far return address)
*
* Initialise the GDT ready for transitions to protected mode.
*
* Parameters:
* %cs : .text16 segment
* %ds : .data16 segment
* %edi : Physical base of protected-mode code (virt_offset)
****************************************************************************
*/
.section ".text16", "ax", @progbits
.code16
.globl init_librm
init_librm:
/* Preserve registers */
pushl %eax
pushl %ebx
/* Store virt_offset and set up virtual_cs and virtual_ds segments */
movl %edi, %eax
movw $virtual_cs, %bx
call set_seg_base
movw $virtual_ds, %bx
call set_seg_base
movl %edi, rm_virt_offset
/* Negate virt_offset */
negl %edi
/* Store rm_cs and text16, set up real_cs segment */
xorl %eax, %eax
movw %cs, %ax
movw %ax, %cs:rm_cs
shll $4, %eax
movw $real_cs, %bx
call set_seg_base
addr32 leal (%eax, %edi), %ebx
movl %ebx, rm_text16
/* Store rm_ds and data16 */
xorl %eax, %eax
movw %ds, %ax
movw %ax, %cs:rm_ds
shll $4, %eax
addr32 leal (%eax, %edi), %ebx
movl %ebx, rm_data16
/* Set GDT base */
movl %eax, gdt_base
addl $gdt, gdt_base
/* Initialise IDT */
pushl $init_idt
pushw %cs
call prot_call
popl %eax /* discard */
/* Restore registers */
negl %edi
popl %ebx
popl %eax
lret
.section ".text16", "ax", @progbits
.code16
set_seg_base:
1: movw %ax, 2(%bx)
rorl $16, %eax
movb %al, 4(%bx)
movb %ah, 7(%bx)
roll $16, %eax
ret
/****************************************************************************
* real_to_prot (real-mode near call, 32-bit virtual return address)
*
* Switch from 16-bit real-mode to 32-bit protected mode with virtual
* addresses. The real-mode %ss:sp is stored in rm_ss and rm_sp, and
* the protected-mode %esp is restored from the saved pm_esp.
* Interrupts are disabled. All other registers may be destroyed.
*
* The return address for this function should be a 32-bit virtual
* address.
*
* Parameters:
* %ecx : number of bytes to move from RM stack to PM stack
*
****************************************************************************
*/
.section ".text16", "ax", @progbits
.code16
real_to_prot:
/* Enable A20 line */
call enable_a20
/* A failure at this point is fatal, and there's nothing we
* can do about it other than lock the machine to make the
* problem immediately visible.
*/
1: jc 1b
/* Make sure we have our data segment available */
movw %cs:rm_ds, %ax
movw %ax, %ds
/* Add virt_offset, text16 and data16 to stack to be
* copied, and also copy the return address.
*/
pushl rm_virt_offset
pushl rm_text16
pushl rm_data16
addw $16, %cx /* %ecx must be less than 64kB anyway */
/* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */
xorl %ebp, %ebp
movw %ss, %bp
movzwl %sp, %edx
movl %ebp, %eax
shll $4, %eax
addr32 leal (%eax,%edx), %esi
subl rm_virt_offset, %esi
/* Load protected-mode global descriptor table */
data32 lgdt gdtr
/* Zero segment registers. This wastes around 12 cycles on
* real hardware, but saves a substantial number of emulated
* instructions under KVM.
*/
xorw %ax, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/* Switch to protected mode */
cli
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
data32 ljmp $VIRTUAL_CS, $r2p_pmode
.section ".text", "ax", @progbits
.code32
r2p_pmode:
/* Set up protected-mode data segments and stack pointer */
movw $VIRTUAL_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
movl pm_esp, %esp
/* Load protected-mode interrupt descriptor table */
lidt idtr
/* Record real-mode %ss:sp (after removal of data) */
movw %bp, rm_ss
addl %ecx, %edx
movw %dx, rm_sp
/* Move data from RM stack to PM stack */
subl %ecx, %esp
movl %esp, %edi
rep movsb
/* Publish virt_offset, text16 and data16 for PM code to use */
popl data16
popl text16
popl virt_offset
/* Return to virtual address */
ret
/****************************************************************************
* prot_to_real (protected-mode near call, 32-bit real-mode return address)
*
* Switch from 32-bit protected mode with virtual addresses to 16-bit
* real mode. The protected-mode %esp is stored in pm_esp and the
* real-mode %ss:sp is restored from the saved rm_ss and rm_sp. The
* high word of the real-mode %esp is set to zero. All real-mode data
* segment registers are loaded from the saved rm_ds. Interrupts are
* *not* enabled, since we want to be able to use prot_to_real in an
* ISR. All other registers may be destroyed.
*
* The return address for this function should be a 32-bit (sic)
* real-mode offset within .code16.
*
* Parameters:
* %ecx : number of bytes to move from PM stack to RM stack
* %esi : real-mode global and interrupt descriptor table registers
*
****************************************************************************
*/
.section ".text", "ax", @progbits
.code32
prot_to_real:
/* Copy real-mode global descriptor table register to RM code segment */
movl text16, %edi
leal rm_gdtr(%edi), %edi
movsw
movsl
/* Load real-mode interrupt descriptor table register */
lidt (%esi)
/* Add return address to data to be moved to RM stack */
addl $4, %ecx
/* Real-mode %ss:sp => %ebp:edx and virtual address => %edi */
movzwl rm_ss, %ebp
movzwl rm_sp, %edx
subl %ecx, %edx
movl %ebp, %eax
shll $4, %eax
leal (%eax,%edx), %edi
subl virt_offset, %edi
/* Move data from PM stack to RM stack */
movl %esp, %esi
rep movsb
/* Record protected-mode %esp (after removal of data) */
movl %esi, pm_esp
/* Load real-mode segment limits */
movw $REAL_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
ljmp $REAL_CS, $p2r_rmode
.section ".text16", "ax", @progbits
.code16
p2r_rmode:
/* Load real-mode GDT */
data32 lgdt %cs:rm_gdtr
/* Switch to real mode */
movl %cr0, %eax
andb $0!CR0_PE, %al
movl %eax, %cr0
p2r_ljmp_rm_cs:
ljmp $0, $1f
1:
/* Set up real-mode data segments and stack pointer */
movw %cs:rm_ds, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %bp, %ss
movl %edx, %esp
/* Return to real-mode address */
data32 ret
/* Real-mode code and data segments. Assigned by the call to
* init_librm. rm_cs doubles as the segment part of the jump
* instruction used by prot_to_real. Both are located in
* .text16 rather than .data16: rm_cs since it forms part of
* the jump instruction within the code segment, and rm_ds
* since real-mode code needs to be able to locate the data
* segment with no other reference available.
*/
.globl rm_cs
.equ rm_cs, ( p2r_ljmp_rm_cs + 3 )
.section ".text16.data", "aw", @progbits
.globl rm_ds
rm_ds: .word 0
/* Real-mode global and interrupt descriptor table registers */
.section ".text16.data", "aw", @progbits
rm_gdtr:
.word 0 /* Limit */
.long 0 /* Base */
/****************************************************************************
* prot_call (real-mode far call, 16-bit real-mode far return address)
*
* Call a specific C function in the protected-mode code. The
* prototype of the C function must be
* void function ( struct i386_all_regs *ix86 );
* ix86 will point to a struct containing the real-mode registers
* at entry to prot_call.
*
* All registers will be preserved across prot_call(), unless the C
* function explicitly overwrites values in ix86. Interrupt status
* and GDT will also be preserved. Gate A20 will be enabled.
*
* Note that prot_call() does not rely on the real-mode stack
* remaining intact in order to return, since everything relevant is
* copied to the protected-mode stack for the duration of the call.
* In particular, this means that a real-mode prefix can make a call
* to main() which will return correctly even if the prefix's stack
* gets vapourised during the Etherboot run. (The prefix cannot rely
* on anything else on the stack being preserved, so should move any
* critical data to registers before calling main()).
*
* Parameters:
* function : virtual address of protected-mode function to call
*
* Example usage:
* pushl $pxe_api_call
* call prot_call
* addw $4, %sp
* to call in to the C function
* void pxe_api_call ( struct i386_all_regs *ix86 );
****************************************************************************
*/
#define PC_OFFSET_GDT ( 0 )
#define PC_OFFSET_IDT ( PC_OFFSET_GDT + 6 )
#define PC_OFFSET_IX86 ( PC_OFFSET_IDT + 6 )
#define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
#define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
#define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
.section ".text16", "ax", @progbits
.code16
.globl prot_call
prot_call:
/* Preserve registers, flags and GDT on external RM stack */
pushfl
pushal
pushw %gs
pushw %fs
pushw %es
pushw %ds
pushw %ss
pushw %cs
subw $PC_OFFSET_IX86, %sp
movw %sp, %bp
sidt PC_OFFSET_IDT(%bp)
sgdt PC_OFFSET_GDT(%bp)
/* For sanity's sake, clear the direction flag as soon as possible */
cld
/* Switch to protected mode and move register dump to PM stack */
movl $PC_OFFSET_END, %ecx
pushl $pc_pmode
jmp real_to_prot
.section ".text", "ax", @progbits
.code32
pc_pmode:
/* Call function */
leal PC_OFFSET_IX86(%esp), %eax
pushl %eax
call *(PC_OFFSET_FUNCTION+4)(%esp)
popl %eax /* discard */
/* Switch to real mode and move register dump back to RM stack */
movl $PC_OFFSET_END, %ecx
movl %esp, %esi
pushl $pc_rmode
jmp prot_to_real
.section ".text16", "ax", @progbits
.code16
pc_rmode:
/* Restore registers and flags and return */
addw $( PC_OFFSET_IX86 + 4 /* also skip %cs and %ss */ ), %sp
popw %ds
popw %es
popw %fs
popw %gs
popal
/* popal skips %esp. We therefore want to do "movl -20(%sp),
* %esp", but -20(%sp) is not a valid 80386 expression.
* Fortunately, prot_to_real() zeroes the high word of %esp, so
* we can just use -20(%esp) instead.
*/
addr32 movl -20(%esp), %esp
popfl
lret
/****************************************************************************
* real_call (protected-mode near call, 32-bit virtual return address)
*
* Call a real-mode function from protected-mode code.
*
* The non-segment register values will be passed directly to the
* real-mode code. The segment registers will be set as per
* prot_to_real. The non-segment register values set by the real-mode
* function will be passed back to the protected-mode caller. A
* result of this is that this routine cannot be called directly from
* C code, since it clobbers registers that the C ABI expects the
* callee to preserve.
*
* librm.h defines a convenient macro REAL_CODE() for using real_call.
* See librm.h and realmode.h for details and examples.
*
* Parameters:
* (32-bit) near pointer to real-mode function to call
*
* Returns: none
****************************************************************************
*/
#define RC_OFFSET_PRESERVE_REGS ( 0 )
#define RC_OFFSET_RETADDR ( RC_OFFSET_PRESERVE_REGS + SIZEOF_I386_REGS )
#define RC_OFFSET_FUNCTION ( RC_OFFSET_RETADDR + 4 )
#define RC_OFFSET_END ( RC_OFFSET_FUNCTION + 4 )
.section ".text", "ax", @progbits
.code32
.globl real_call
real_call:
/* Create register dump and function pointer copy on PM stack */
pushal
pushl RC_OFFSET_FUNCTION(%esp)
/* Switch to real mode and move register dump to RM stack */
movl $( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx
pushl $rc_rmode
movl $rm_default_gdtr_idtr, %esi
jmp prot_to_real
.section ".text16", "ax", @progbits
.code16
rc_rmode:
/* Call real-mode function */
popl rc_function
popal
call *rc_function
pushal
/* For sanity's sake, clear the direction flag as soon as possible */
cld
/* Switch to protected mode and move register dump back to PM stack */
movl $RC_OFFSET_RETADDR, %ecx
pushl $rc_pmode
jmp real_to_prot
.section ".text", "ax", @progbits
.code32
rc_pmode:
/* Restore registers and return */
popal
ret
/* Function vector, used because "call xx(%sp)" is not a valid
* 16-bit expression.
*/
.section ".data16", "aw", @progbits
rc_function: .word 0, 0
/* Default real-mode global and interrupt descriptor table registers */
.section ".data", "aw", @progbits
rm_default_gdtr_idtr:
.word 0 /* Global descriptor table limit */
.long 0 /* Global descriptor table base */
.word 0x03ff /* Interrupt descriptor table limit */
.long 0 /* Interrupt descriptor table base */
/****************************************************************************
* flatten_real_mode (real-mode near call)
*
* Switch to flat real mode
*
****************************************************************************
*/
.section ".text16", "ax", @progbits
.code16
.globl flatten_real_mode
flatten_real_mode:
/* Modify GDT to use flat real mode */
movb $0x8f, real_cs + 6
movb $0x8f, real_ds + 6
/* Call dummy protected-mode function */
pushl $flatten_dummy
pushw %cs
call prot_call
addw $4, %sp
/* Restore GDT */
movb $0x00, real_cs + 6
movb $0x00, real_ds + 6
/* Return */
ret
.section ".text", "ax", @progbits
.code32
flatten_dummy:
ret
/****************************************************************************
* Interrupt wrapper
*
* Used by the protected-mode interrupt vectors to call the
* interrupt() function.
*
* May be entered with either physical or virtual stack segment.
****************************************************************************
*/
.globl interrupt_wrapper
interrupt_wrapper:
/* Preserve segment registers and original %esp */
pushl %ds
pushl %es
pushl %fs
pushl %gs
pushl %ss
pushl %esp
/* Switch to virtual addressing */
call _intr_to_virt
/* Expand IRQ number to whole %eax register */
movzbl %al, %eax
/* Call interrupt handler */
call interrupt
/* Restore original stack and segment registers */
lss (%esp), %esp
popl %ss
popl %gs
popl %fs
popl %es
popl %ds
/* Restore registers and return */
popal
iret
/****************************************************************************
* Stored real-mode and protected-mode stack pointers
*
* The real-mode stack pointer is stored here whenever real_to_prot
* is called and restored whenever prot_to_real is called. The
* converse happens for the protected-mode stack pointer.
*
* Despite initial appearances this scheme is, in fact re-entrant,
* because program flow dictates that we always return via the point
* we left by. For example:
* PXE API call entry
* 1 real => prot
* ...
* Print a text string
* ...
* 2 prot => real
* INT 10
* 3 real => prot
* ...
* ...
* 4 prot => real
* PXE API call exit
*
* At point 1, the RM mode stack value, say RPXE, is stored in
* rm_ss,sp. We want this value to still be present in rm_ss,sp when
* we reach point 4.
*
* At point 2, the RM stack value is restored from RPXE. At point 3,
* the RM stack value is again stored in rm_ss,sp. This *does*
* overwrite the RPXE that we have stored there, but it's the same
* value, since the code between points 2 and 3 has managed to return
* to us.
****************************************************************************
*/
.section ".data", "aw", @progbits
.globl rm_sp
rm_sp: .word 0
.globl rm_ss
rm_ss: .word 0
pm_esp: .long _estack
/****************************************************************************
* Virtual address offsets
*
* These are used by the protected-mode code to map between virtual
* and physical addresses, and to access variables in the .text16 or
* .data16 segments.
****************************************************************************
*/
/* Internal copies, created by init_librm (which runs in real mode) */
.section ".data16", "aw", @progbits
rm_virt_offset: .long 0
rm_text16: .long 0
rm_data16: .long 0
/* Externally-visible copies, created by real_to_prot */
.section ".data", "aw", @progbits
.globl virt_offset
virt_offset: .long 0
.globl text16
text16: .long 0
.globl data16
data16: .long 0

View File

@ -1,158 +0,0 @@
/*
* librm: a library for interfacing to real-mode code
*
* Michael Brown <mbrown@fensystems.co.uk>
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/profile.h>
#include <realmode.h>
#include <pic8259.h>
/*
* This file provides functions for managing librm.
*
*/
/** The interrupt wrapper */
extern char interrupt_wrapper[];
/** The interrupt vectors */
static struct interrupt_vector intr_vec[NUM_INT];
/** The interrupt descriptor table */
struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) ));
/** The interrupt descriptor table register */
struct idtr idtr = {
.limit = ( sizeof ( idt ) - 1 ),
};
/** Timer interrupt profiler */
static struct profiler timer_irq_profiler __profiler = { .name = "irq.timer" };
/** Other interrupt profiler */
static struct profiler other_irq_profiler __profiler = { .name = "irq.other" };
/**
* Allocate space on the real-mode stack and copy data there from a
* user buffer
*
* @v data User buffer
* @v size Size of stack data
* @ret sp New value of real-mode stack pointer
*/
uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
userptr_t rm_stack;
rm_sp -= size;
rm_stack = real_to_user ( rm_ss, rm_sp );
memcpy_user ( rm_stack, 0, data, 0, size );
return rm_sp;
};
/**
* Deallocate space on the real-mode stack, optionally copying back
* data to a user buffer.
*
* @v data User buffer
* @v size Size of stack data
*/
void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
if ( data ) {
userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
memcpy_user ( rm_stack, 0, data, 0, size );
}
rm_sp += size;
};
/**
* Set interrupt vector
*
* @v intr Interrupt number
* @v vector Interrupt vector, or NULL to disable
*/
void set_interrupt_vector ( unsigned int intr, void *vector ) {
struct interrupt_descriptor *idte;
idte = &idt[intr];
idte->segment = VIRTUAL_CS;
idte->attr = ( vector ? ( IDTE_PRESENT | IDTE_TYPE_IRQ32 ) : 0 );
idte->low = ( ( ( uint32_t ) vector ) & 0xffff );
idte->high = ( ( ( uint32_t ) vector ) >> 16 );
}
/**
* Initialise interrupt descriptor table
*
*/
void init_idt ( void ) {
struct interrupt_vector *vec;
unsigned int intr;
/* Initialise the interrupt descriptor table and interrupt vectors */
for ( intr = 0 ; intr < NUM_INT ; intr++ ) {
vec = &intr_vec[intr];
vec->pushal = PUSHAL_INSN;
vec->movb = MOVB_INSN;
vec->intr = intr;
vec->jmp = JMP_INSN;
vec->offset = ( ( uint32_t ) interrupt_wrapper -
( uint32_t ) vec->next );
set_interrupt_vector ( intr, vec );
}
DBGC ( &intr_vec[0], "INTn vector at %p+%zxn (phys %#lx+%zxn)\n",
intr_vec, sizeof ( intr_vec[0] ),
virt_to_phys ( intr_vec ), sizeof ( intr_vec[0] ) );
/* Initialise the interrupt descriptor table register */
idtr.base = virt_to_phys ( idt );
}
/**
* Determine interrupt profiler (for debugging)
*
* @v intr Interrupt number
* @ret profiler Profiler
*/
static struct profiler * interrupt_profiler ( int intr ) {
switch ( intr ) {
case IRQ_INT ( 0 ) :
return &timer_irq_profiler;
default:
return &other_irq_profiler;
}
}
/**
* Interrupt handler
*
* @v intr Interrupt number
*/
void __attribute__ (( cdecl, regparm ( 1 ) )) interrupt ( int intr ) {
struct profiler *profiler = interrupt_profiler ( intr );
uint32_t discard_eax;
/* Reissue interrupt in real mode */
profile_start ( profiler );
__asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t"
"\n1:\n\t"
"int $0x00\n\t" )
: "=a" ( discard_eax ) : "0" ( intr ) );
profile_stop ( profiler );
profile_exclude ( profiler );
}
PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
PROVIDE_UACCESS_INLINE ( librm, virt_to_user );
PROVIDE_UACCESS_INLINE ( librm, user_to_virt );
PROVIDE_UACCESS_INLINE ( librm, userptr_add );
PROVIDE_UACCESS_INLINE ( librm, memcpy_user );
PROVIDE_UACCESS_INLINE ( librm, memmove_user );
PROVIDE_UACCESS_INLINE ( librm, memset_user );
PROVIDE_UACCESS_INLINE ( librm, strlen_user );
PROVIDE_UACCESS_INLINE ( librm, memchr_user );

View File

@ -1,3 +1,8 @@
# Assembler section type character
#
ASM_TCHAR := @
ASM_TCHAR_OPS := @
# Include common x86 headers
#
INCDIRS += arch/x86/include
@ -5,11 +10,17 @@ INCDIRS += arch/x86/include
# x86-specific directories containing source files
#
SRCDIRS += arch/x86/core
SRCDIRS += arch/x86/image
SRCDIRS += arch/x86/interface/pcbios
SRCDIRS += arch/x86/interface/pxe
SRCDIRS += arch/x86/interface/efi
SRCDIRS += arch/x86/interface/vmware
SRCDIRS += arch/x86/interface/syslinux
SRCDIRS += arch/x86/prefix
SRCDIRS += arch/x86/hci/commands
SRCDIRS += arch/x86/drivers/xen
SRCDIRS += arch/x86/drivers/hyperv
SRCDIRS += arch/x86/transitions
# breaks building some of the linux-related objects
CFLAGS += -Ulinux
@ -17,6 +28,10 @@ CFLAGS += -Ulinux
# disable valgrind
CFLAGS += -DNVALGRIND
# Define version string for lkrnprefix.S
#
CFLAGS_lkrnprefix += -DVERSION="\"$(VERSION)\""
# Include Hyper-V driver in the all-drivers build
#
DRIVERS_hyperv += hyperv

View File

@ -1,42 +1,6 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# The EFI linker script
# Include generic EFI Makefile
#
LDSCRIPT = arch/x86/scripts/efi.lds
# Retain relocation information for elf2efi
#
LDFLAGS += -q -S
# Media types.
#
NON_AUTO_MEDIA += efi
NON_AUTO_MEDIA += efidrv
NON_AUTO_MEDIA += drv.efi
NON_AUTO_MEDIA += efirom
# Include SNP driver in the all-drivers build
#
DRIVERS_net += snp
# Rules for building EFI files
#
$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI)
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(ELF2EFI) --subsystem=10 $< $@
$(BIN)/%.efidrv : $(BIN)/%.efidrv.tmp $(ELF2EFI)
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(ELF2EFI) --subsystem=11 $< $@
$(BIN)/%.drv.efi : $(BIN)/%.efidrv
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(CP) $< $@
$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) $< $@
$(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
$(QM)$(ECHO) " [CAB] $@"
$(Q)$(LCAB) -n -q $(ALL_drv.efi) $@
MAKEDEPS += Makefile.efi
include Makefile.efi

View File

@ -0,0 +1,132 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# BIOS-specific directories containing source files
#
SRCDIRS += arch/x86/drivers/net
# The i386 linker script
#
LDSCRIPT = arch/x86/scripts/pcbios.lds
# Stop ld from complaining about our customised linker script
#
LDFLAGS += -N --no-check-sections
# Prefix always starts at address zero
#
LDFLAGS += --section-start=.prefix=0
# Media types.
#
MEDIA += rom
MEDIA += mrom
MEDIA += pcirom
MEDIA += isarom
MEDIA += pxe
MEDIA += kpxe
MEDIA += kkpxe
MEDIA += kkkpxe
MEDIA += lkrn
MEDIA += dsk
MEDIA += nbi
MEDIA += hd
MEDIA += raw
MEDIA += exe
# Padding rules
#
PAD_rom = $(PERL) $(PADIMG) --blksize=512 --byte=0xff
PAD_mrom = $(PAD_rom)
PAD_pcirom = $(PAD_rom)
PAD_isarom = $(PAD_rom)
PAD_dsk = $(PERL) $(PADIMG) --blksize=512
PAD_hd = $(PERL) $(PADIMG) --blksize=32768
PAD_exe = $(PERL) $(PADIMG) --blksize=512
# Finalisation rules
#
FINALISE_rom = $(PERL) $(FIXROM)
FINALISE_mrom = $(FINALISE_rom)
FINALISE_pcirom = $(FINALISE_rom)
FINALISE_isarom = $(FINALISE_rom)
# Use $(ROMS) rather than $(DRIVERS) for "allroms", "allmroms", etc.
#
LIST_NAME_rom := ROMS
LIST_NAME_mrom := ROMS
LIST_NAME_pcirom := ROMS
LIST_NAME_isarom := ROMS
# Locations of isolinux files
#
SYSLINUX_DIR_LIST := \
/usr/lib/syslinux \
/usr/lib/syslinux/bios \
/usr/lib/syslinux/modules/bios \
/usr/share/syslinux \
/usr/share/syslinux/bios \
/usr/share/syslinux/modules/bios \
/usr/local/share/syslinux \
/usr/local/share/syslinux/bios \
/usr/local/share/syslinux/modules/bios \
/usr/lib/ISOLINUX
ISOLINUX_BIN_LIST := \
$(ISOLINUX_BIN) \
$(patsubst %,%/isolinux.bin,$(SYSLINUX_DIR_LIST))
LDLINUX_C32_LIST := \
$(LDLINUX_C32) \
$(patsubst %,%/ldlinux.c32,$(SYSLINUX_DIR_LIST))
ISOLINUX_BIN = $(firstword $(wildcard $(ISOLINUX_BIN_LIST)))
LDLINUX_C32 = $(firstword $(wildcard $(LDLINUX_C32_LIST)))
# rule to make a non-emulation ISO boot image
NON_AUTO_MEDIA += iso
%iso: %lkrn util/geniso
$(QM)$(ECHO) " [GENISO] $@"
$(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) LDLINUX_C32=$(LDLINUX_C32) \
VERSION="$(VERSION)" bash util/geniso -o $@ $<
# rule to make a floppy emulation ISO boot image
NON_AUTO_MEDIA += liso
%liso: %lkrn util/geniso
$(QM)$(ECHO) " [GENISO] $@"
$(Q)VERSION="$(VERSION)" bash util/geniso -l -o $@ $<
# rule to make a syslinux floppy image (mountable, bootable)
NON_AUTO_MEDIA += sdsk
%sdsk: %lkrn util/gensdsk
$(QM)$(ECHO) " [GENSDSK] $@"
$(Q)bash util/gensdsk $@ $<
# rule to write disk images to /dev/fd0
NON_AUTO_MEDIA += fd0
%fd0 : %dsk
$(QM)$(ECHO) " [DD] $@"
$(Q)dd if=$< bs=512 conv=sync of=/dev/fd0
$(Q)sync
# Special target for building Master Boot Record binary
$(BIN)/mbr.tmp : $(BIN)/mbr.o
$(QM)$(ECHO) " [LD] $@"
$(Q)$(LD) $(LDFLAGS) -o $@ -e mbr $<
# rule to make a USB disk image
$(BIN)/usbdisk.tmp : $(BIN)/usbdisk.o
$(QM)$(ECHO) " [LD] $@"
$(Q)$(LD) $(LDFLAGS) -o $@ -e mbr $<
NON_AUTO_MEDIA += usb
%usb: $(BIN)/usbdisk.bin %hd
$(QM)$(ECHO) " [FINISH] $@"
$(Q)cat $^ > $@
NON_AUTO_MEDIA += vhd
%vhd: %usb
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(QEMUIMG) convert -f raw -O vpc $< $@
# Padded floppy image (e.g. for iLO)
NON_AUTO_MEDIA += pdsk
%pdsk : %dsk
$(Q)cp $< $@
$(Q)$(PADIMG) --blksize=1474560 $@

View File

@ -58,6 +58,7 @@ static void cachedhcp_init ( void ) {
struct dhcp_packet *dhcppkt;
struct dhcp_packet *tmp;
struct dhcphdr *dhcphdr;
size_t max_len;
size_t len;
/* Do nothing if no cached DHCPACK is present */
@ -69,23 +70,25 @@ static void cachedhcp_init ( void ) {
/* No reliable way to determine length before parsing packet;
* start by assuming maximum length permitted by PXE.
*/
len = sizeof ( BOOTPLAYER_t );
max_len = sizeof ( BOOTPLAYER_t );
/* Allocate and populate DHCP packet */
dhcppkt = zalloc ( sizeof ( *dhcppkt ) + len );
dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len );
if ( ! dhcppkt ) {
DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
return;
}
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0,
len );
dhcppkt_init ( dhcppkt, dhcphdr, len );
max_len );
dhcppkt_init ( dhcppkt, dhcphdr, max_len );
/* Resize packet to required length. If reallocation fails,
* just continue to use the original packet.
/* Shrink packet to required length. If reallocation fails,
* just continue to use the original packet and waste the
* unused space.
*/
len = dhcppkt_len ( dhcppkt );
assert ( len <= max_len );
tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) );
if ( tmp )
dhcppkt = tmp;

View File

@ -24,6 +24,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
#include <ipxe/cpuid.h>
/** @file
@ -32,15 +33,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
/** Colour for debug messages */
#define colour 0x861d
/**
* Check whether or not CPUID instruction is supported
*
* @ret is_supported CPUID instruction is supported
* @ret rc Return status code
*/
int cpuid_is_supported ( void ) {
static int cpuid_instruction_supported ( void ) {
unsigned long original;
unsigned long inverted;
/* Check for instruction existence via flag modifiability */
__asm__ ( "pushf\n\t"
"pushf\n\t"
"pop %0\n\t"
@ -53,7 +58,54 @@ int cpuid_is_supported ( void ) {
"popf\n\t"
: "=&r" ( original ), "=&r" ( inverted )
: "ir" ( CPUID_FLAG ) );
return ( ( original ^ inverted ) & CPUID_FLAG );
if ( ! ( ( original ^ inverted ) & CPUID_FLAG ) ) {
DBGC ( colour, "CPUID instruction is not supported\n" );
return -ENOTSUP;
}
return 0;
}
/**
* Check whether or not CPUID function is supported
*
* @v function CPUID function
* @ret rc Return status code
*/
int cpuid_supported ( uint32_t function ) {
uint32_t max_function;
uint32_t discard_b;
uint32_t discard_c;
uint32_t discard_d;
int rc;
/* Check that CPUID instruction is available */
if ( ( rc = cpuid_instruction_supported() ) != 0 )
return rc;
/* Find highest supported function number within this family */
cpuid ( ( function & CPUID_EXTENDED ), 0, &max_function, &discard_b,
&discard_c, &discard_d );
/* Fail if maximum function number is meaningless (e.g. if we
* are attempting to call an extended function on a CPU which
* does not support them).
*/
if ( ( max_function & CPUID_AMD_CHECK_MASK ) !=
( function & CPUID_AMD_CHECK_MASK ) ) {
DBGC ( colour, "CPUID invalid maximum function %#08x\n",
max_function );
return -EINVAL;
}
/* Fail if this function is not supported */
if ( function > max_function ) {
DBGC ( colour, "CPUID function %#08x not supported\n",
function );
return -ENOTTY;
}
return 0;
}
/**
@ -62,23 +114,18 @@ int cpuid_is_supported ( void ) {
* @v features x86 CPU features to fill in
*/
static void x86_intel_features ( struct x86_features *features ) {
uint32_t max_level;
uint32_t discard_a;
uint32_t discard_b;
uint32_t discard_c;
uint32_t discard_d;
int rc;
/* Check that features are available via CPUID */
cpuid ( CPUID_VENDOR_ID, &max_level, &discard_b, &discard_c,
&discard_d );
if ( max_level < CPUID_FEATURES ) {
DBGC ( features, "CPUID has no Intel-defined features (max "
"level %08x)\n", max_level );
if ( ( rc = cpuid_supported ( CPUID_FEATURES ) ) != 0 ) {
DBGC ( features, "CPUID has no Intel-defined features\n" );
return;
}
/* Get features */
cpuid ( CPUID_FEATURES, &discard_a, &discard_b,
cpuid ( CPUID_FEATURES, 0, &discard_a, &discard_b,
&features->intel.ecx, &features->intel.edx );
DBGC ( features, "CPUID Intel features: %%ecx=%08x, %%edx=%08x\n",
features->intel.ecx, features->intel.edx );
@ -91,27 +138,18 @@ static void x86_intel_features ( struct x86_features *features ) {
* @v features x86 CPU features to fill in
*/
static void x86_amd_features ( struct x86_features *features ) {
uint32_t max_level;
uint32_t discard_a;
uint32_t discard_b;
uint32_t discard_c;
uint32_t discard_d;
int rc;
/* Check that features are available via CPUID */
cpuid ( CPUID_AMD_MAX_FN, &max_level, &discard_b, &discard_c,
&discard_d );
if ( ( max_level & CPUID_AMD_CHECK_MASK ) != CPUID_AMD_CHECK ) {
DBGC ( features, "CPUID has no extended functions\n" );
return;
}
if ( max_level < CPUID_AMD_FEATURES ) {
DBGC ( features, "CPUID has no AMD-defined features (max "
"level %08x)\n", max_level );
if ( ( rc = cpuid_supported ( CPUID_AMD_FEATURES ) ) != 0 ) {
DBGC ( features, "CPUID has no AMD-defined features\n" );
return;
}
/* Get features */
cpuid ( CPUID_AMD_FEATURES, &discard_a, &discard_b,
cpuid ( CPUID_AMD_FEATURES, 0, &discard_a, &discard_b,
&features->amd.ecx, &features->amd.edx );
DBGC ( features, "CPUID AMD features: %%ecx=%08x, %%edx=%08x\n",
features->amd.ecx, features->amd.edx );
@ -127,12 +165,6 @@ void x86_features ( struct x86_features *features ) {
/* Clear all features */
memset ( features, 0, sizeof ( *features ) );
/* Check that CPUID instruction is available */
if ( ! cpuid_is_supported() ) {
DBGC ( features, "CPUID instruction is not supported\n" );
return;
}
/* Get Intel-defined features */
x86_intel_features ( features );

View File

@ -37,10 +37,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* CPUID settings are numerically encoded as:
*
* Bit 31 Extended function
* Bits 30-28 Unused
* Bits 27-24 Number of consecutive functions to call, minus one
* Bits 30-24 (bit 22 = 1) Subfunction number
* (bit 22 = 0) Number of consecutive functions to call, minus one
* Bit 23 Return result as little-endian (used for strings)
* Bits 22-18 Unused
* Bit 22 Interpret bits 30-24 as a subfunction number
* Bits 21-18 Unused
* Bits 17-16 Number of registers in register array, minus one
* Bits 15-8 Array of register indices. First entry in array is in
* bits 9-8. Indices are 0-%eax, 1-%ebx, 2-%ecx, 3-%edx.
@ -50,6 +51,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* extracting a single register from a single function to be encoded
* using "cpuid/<register>.<function>", e.g. "cpuid/2.0x80000001" to
* retrieve the value of %ecx from calling CPUID with %eax=0x80000001.
*
* A subfunction (i.e. an input value for %ecx) may be specified using
* "cpuid/<subfunction>.0x40.<register>.<function>". This slightly
* cumbersome syntax is required in order to maintain backwards
* compatibility with older scripts.
*/
/** CPUID setting tag register indices */
@ -60,12 +66,18 @@ enum cpuid_registers {
CPUID_EDX = 3,
};
/** CPUID setting tag flags */
enum cpuid_flags {
CPUID_LITTLE_ENDIAN = 0x00800000UL,
CPUID_USE_SUBFUNCTION = 0x00400000UL,
};
/**
* Construct CPUID setting tag
*
* @v function Starting function number
* @v num_functions Number of consecutive functions
* @v little_endian Return result as little-endian
* @v subfunction Subfunction, or number of consecutive functions minus 1
* @v flags Flags
* @v num_registers Number of registers in register array
* @v register1 First register in register array (or zero, if empty)
* @v register2 Second register in register array (or zero, if empty)
@ -73,21 +85,13 @@ enum cpuid_registers {
* @v register4 Fourth register in register array (or zero, if empty)
* @ret tag Setting tag
*/
#define CPUID_TAG( function, num_functions, little_endian, num_registers, \
register1, register2, register3, register4 ) \
( (function) | ( ( (num_functions) - 1 ) << 24 ) | \
( (little_endian) << 23 ) | ( ( (num_registers) - 1) << 16 ) | \
( (register1) << 8 ) | ( (register2) << 10 ) | \
#define CPUID_TAG( function, subfunction, flags, num_registers, \
register1, register2, register3, register4 ) \
( (function) | ( (subfunction) << 24 ) | (flags) | \
( ( (num_registers) - 1 ) << 16 ) | \
( (register1) << 8 ) | ( (register2) << 10 ) | \
( (register3) << 12 ) | ( (register4) << 14 ) )
/**
* Extract endianness from CPUID setting tag
*
* @v tag Setting tag
* @ret little_endian Result should be returned as little-endian
*/
#define CPUID_LITTLE_ENDIAN( tag ) ( (tag) & 0x00800000UL )
/**
* Extract starting function number from CPUID setting tag
*
@ -97,12 +101,12 @@ enum cpuid_registers {
#define CPUID_FUNCTION( tag ) ( (tag) & 0x800000ffUL )
/**
* Extract number of consecutive functions from CPUID setting tag
* Extract subfunction number from CPUID setting tag
*
* @v tag Setting tag
* @ret num_functions Number of consecutive functions
* @ret subfunction Subfunction number
*/
#define CPUID_NUM_FUNCTIONS( tag ) ( ( ( (tag) >> 24 ) & 0xf ) + 1 )
#define CPUID_SUBFUNCTION( tag ) ( ( (tag) >> 24 ) & 0x7f )
/**
* Extract register array from CPUID setting tag
@ -149,62 +153,46 @@ static int cpuid_settings_fetch ( struct settings *settings,
struct setting *setting,
void *data, size_t len ) {
uint32_t function;
uint32_t max_function;
uint32_t subfunction;
uint32_t num_functions;
uint32_t registers;
uint32_t num_registers;
uint32_t buf[4];
uint32_t output;
uint32_t discard_b;
uint32_t discard_c;
uint32_t discard_d;
size_t frag_len;
size_t result_len = 0;
/* Fail unless CPUID is supported */
if ( ! cpuid_is_supported() ) {
DBGC ( settings, "CPUID not supported\n" );
return -ENOTSUP;
}
/* Find highest supported function number within this set */
function = CPUID_FUNCTION ( setting->tag );
cpuid ( function & CPUID_EXTENDED, &max_function, &discard_b,
&discard_c, &discard_d );
/* Fail if maximum function number is meaningless (e.g. if we
* are attempting to call an extended function on a CPU which
* does not support them).
*/
if ( ( max_function & CPUID_AMD_CHECK_MASK ) !=
( function & CPUID_AMD_CHECK_MASK ) ) {
DBGC ( settings, "CPUID invalid maximum function\n" );
return -ENOTSUP;
}
int rc;
/* Call each function in turn */
num_functions = CPUID_NUM_FUNCTIONS ( setting->tag );
function = CPUID_FUNCTION ( setting->tag );
subfunction = CPUID_SUBFUNCTION ( setting->tag );
if ( setting->tag & CPUID_USE_SUBFUNCTION ) {
num_functions = 1;
} else {
num_functions = ( subfunction + 1 );
subfunction = 0;
}
for ( ; num_functions-- ; function++ ) {
/* Fail if this function is not supported */
if ( function > max_function ) {
DBGC ( settings, "CPUID function %#08x not supported\n",
function );
return -ENOTSUP;
if ( ( rc = cpuid_supported ( function ) ) != 0 ) {
DBGC ( settings, "CPUID function %#08x not supported: "
"%s\n", function, strerror ( rc ) );
return rc;
}
/* Issue CPUID */
cpuid ( function, &buf[CPUID_EAX], &buf[CPUID_EBX],
&buf[CPUID_ECX], &buf[CPUID_EDX] );
DBGC ( settings, "CPUID %#08x => %#08x:%#08x:%#08x:%#08x\n",
function, buf[0], buf[1], buf[2], buf[3] );
cpuid ( function, subfunction, &buf[CPUID_EAX],
&buf[CPUID_EBX], &buf[CPUID_ECX], &buf[CPUID_EDX] );
DBGC ( settings, "CPUID %#08x:%x => %#08x:%#08x:%#08x:%#08x\n",
function, subfunction, buf[0], buf[1], buf[2], buf[3] );
/* Copy results to buffer */
registers = CPUID_REGISTERS ( setting->tag );
num_registers = CPUID_NUM_REGISTERS ( setting->tag );
for ( ; num_registers-- ; registers >>= 2 ) {
output = buf[ registers & 0x3 ];
if ( ! CPUID_LITTLE_ENDIAN ( setting->tag ) )
if ( ! ( setting->tag & CPUID_LITTLE_ENDIAN ) )
output = cpu_to_be32 ( output );
frag_len = sizeof ( output );
if ( frag_len > len )
@ -260,7 +248,7 @@ const struct setting cpuvendor_setting __setting ( SETTING_HOST_EXTRA,
cpuvendor ) = {
.name = "cpuvendor",
.description = "CPU vendor",
.tag = CPUID_TAG ( CPUID_VENDOR_ID, 1, 1, 3,
.tag = CPUID_TAG ( CPUID_VENDOR_ID, 0, CPUID_LITTLE_ENDIAN, 3,
CPUID_EBX, CPUID_EDX, CPUID_ECX, 0 ),
.type = &setting_type_string,
.scope = &cpuid_settings_scope,
@ -271,7 +259,7 @@ const struct setting cpumodel_setting __setting ( SETTING_HOST_EXTRA,
cpumodel ) = {
.name = "cpumodel",
.description = "CPU model",
.tag = CPUID_TAG ( CPUID_MODEL, 3, 1, 4,
.tag = CPUID_TAG ( CPUID_MODEL, 2, CPUID_LITTLE_ENDIAN, 4,
CPUID_EAX, CPUID_EBX, CPUID_ECX, CPUID_EDX ),
.type = &setting_type_string,
.scope = &cpuid_settings_scope,

View File

@ -6,11 +6,8 @@ void __asmcall _dump_regs ( struct i386_all_regs *ix86 ) {
__asm__ __volatile__ (
TEXT16_CODE ( ".globl dump_regs\n\t"
"\ndump_regs:\n\t"
"pushl $_dump_regs\n\t"
"pushw %%cs\n\t"
"call prot_call\n\t"
"addr32 leal 4(%%esp), %%esp\n\t"
"ret\n\t" ) : : );
VIRT_CALL ( _dump_regs )
"ret\n\t" ) : );
printf ( "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"

View File

@ -0,0 +1,251 @@
/*
* Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 any later version.
*
* This program 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/uaccess.h>
#include <ipxe/gdbstub.h>
#include <librm.h>
#include <gdbmach.h>
/** @file
*
* GDB architecture-specific bits for x86
*
*/
/** Number of hardware breakpoints */
#define NUM_HWBP 4
/** Debug register 7: Global breakpoint enable */
#define DR7_G( bp ) ( 2 << ( 2 * (bp) ) )
/** Debug register 7: Global exact breakpoint enable */
#define DR7_GE ( 1 << 9 )
/** Debug register 7: Break on data writes */
#define DR7_RWLEN_WRITE 0x11110000
/** Debug register 7: Break on data access */
#define DR7_RWLEN_ACCESS 0x33330000
/** Debug register 7: One-byte length */
#define DR7_RWLEN_1 0x00000000
/** Debug register 7: Two-byte length */
#define DR7_RWLEN_2 0x44440000
/** Debug register 7: Four-byte length */
#define DR7_RWLEN_4 0xcccc0000
/** Debug register 7: Eight-byte length */
#define DR7_RWLEN_8 0x88880000
/** Debug register 7: Breakpoint R/W and length mask */
#define DR7_RWLEN_MASK( bp ) ( 0xf0000 << ( 4 * (bp) ) )
/** Hardware breakpoint addresses (debug registers 0-3) */
static unsigned long dr[NUM_HWBP];
/** Active value of debug register 7 */
static unsigned long dr7 = DR7_GE;
/**
* Update debug registers
*
*/
static void gdbmach_update ( void ) {
/* Set debug registers */
__asm__ __volatile__ ( "mov %0, %%dr0" : : "r" ( dr[0] ) );
__asm__ __volatile__ ( "mov %0, %%dr1" : : "r" ( dr[1] ) );
__asm__ __volatile__ ( "mov %0, %%dr2" : : "r" ( dr[2] ) );
__asm__ __volatile__ ( "mov %0, %%dr3" : : "r" ( dr[3] ) );
__asm__ __volatile__ ( "mov %0, %%dr7" : : "r" ( dr7 ) );
}
/**
* Find reusable or available hardware breakpoint
*
* @v addr Linear address
* @v rwlen Control bits
* @ret bp Hardware breakpoint, or negative error
*/
static int gdbmach_find ( unsigned long addr, unsigned int rwlen ) {
unsigned int i;
int bp = -ENOENT;
/* Look for a reusable or available breakpoint */
for ( i = 0 ; i < NUM_HWBP ; i++ ) {
/* If breakpoint is not enabled, then it is available */
if ( ! ( dr7 & DR7_G ( i ) ) ) {
bp = i;
continue;
}
/* If breakpoint is enabled and has the same address
* and control bits, then reuse it.
*/
if ( ( dr[i] == addr ) &&
( ( ( dr7 ^ rwlen ) & DR7_RWLEN_MASK ( i ) ) == 0 ) ) {
bp = i;
break;
}
}
return bp;
}
/**
* Set hardware breakpoint
*
* @v type GDB breakpoint type
* @v addr Virtual address
* @v len Length
* @v enable Enable (not disable) breakpoint
* @ret rc Return status code
*/
int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
int enable ) {
unsigned int rwlen;
unsigned long mask;
int bp;
/* Parse breakpoint type */
switch ( type ) {
case GDBMACH_WATCH:
rwlen = DR7_RWLEN_WRITE;
break;
case GDBMACH_AWATCH:
rwlen = DR7_RWLEN_ACCESS;
break;
default:
return -ENOTSUP;
}
/* Parse breakpoint length */
switch ( len ) {
case 1:
rwlen |= DR7_RWLEN_1;
break;
case 2:
rwlen |= DR7_RWLEN_2;
break;
case 4:
rwlen |= DR7_RWLEN_4;
break;
case 8:
rwlen |= DR7_RWLEN_8;
break;
default:
return -ENOTSUP;
}
/* Convert to linear address */
if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
addr = virt_to_phys ( ( void * ) addr );
/* Find reusable or available hardware breakpoint */
bp = gdbmach_find ( addr, rwlen );
if ( bp < 0 )
return ( enable ? -ENOBUFS : 0 );
/* Configure this breakpoint */
DBGC ( &dr[0], "GDB bp %d at %p+%zx type %d (%sabled)\n",
bp, ( ( void * ) addr ), len, type, ( enable ? "en" : "dis" ) );
dr[bp] = addr;
mask = DR7_RWLEN_MASK ( bp );
dr7 = ( ( dr7 & ~mask ) | ( rwlen & mask ) );
mask = DR7_G ( bp );
dr7 &= ~mask;
if ( enable )
dr7 |= mask;
/* Update debug registers */
gdbmach_update();
return 0;
}
/**
* Handle exception
*
* @v signo GDB signal number
* @v regs Register dump
*/
__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
unsigned long dr7_disabled = DR7_GE;
unsigned long dr6_clear = 0;
/* Temporarily disable breakpoints */
__asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7_disabled ) );
/* Handle exception */
DBGC ( &dr[0], "GDB signal %d\n", signo );
DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );
gdbstub_handler ( signo, regs );
DBGC ( &dr[0], "GDB signal %d returning\n", signo );
DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );
/* Clear breakpoint status register */
__asm__ __volatile__ ( "mov %0, %%dr6\n" : : "r" ( dr6_clear ) );
/* Re-enable breakpoints */
__asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7 ) );
}
/**
* CPU exception vectors
*
* Note that we cannot intercept anything from INT8 (double fault)
* upwards, since these overlap by default with IRQ0-7.
*/
static void * gdbmach_vectors[] = {
gdbmach_sigfpe, /* Divide by zero */
gdbmach_sigtrap, /* Debug trap */
NULL, /* Non-maskable interrupt */
gdbmach_sigtrap, /* Breakpoint */
gdbmach_sigstkflt, /* Overflow */
gdbmach_sigstkflt, /* Bound range exceeded */
gdbmach_sigill, /* Invalid opcode */
};
/**
* Initialise GDB
*/
void gdbmach_init ( void ) {
unsigned int i;
/* Hook CPU exception vectors */
for ( i = 0 ; i < ( sizeof ( gdbmach_vectors ) /
sizeof ( gdbmach_vectors[0] ) ) ; i++ ) {
if ( gdbmach_vectors[i] )
set_interrupt_vector ( i, gdbmach_vectors[i] );
}
}

View File

@ -108,3 +108,42 @@ void * linux_mremap ( void *old_address, __kernel_size_t old_size,
int linux_munmap ( void *addr, __kernel_size_t length ) {
return linux_syscall ( __NR_munmap, addr, length );
}
int linux_socket ( int domain, int type_, int protocol ) {
#ifdef __NR_socket
return linux_syscall ( __NR_socket, domain, type_, protocol );
#else
#ifndef SOCKOP_socket
# define SOCKOP_socket 1
#endif
unsigned long sc_args[] = { domain, type_, protocol };
return linux_syscall ( __NR_socketcall, SOCKOP_socket, sc_args );
#endif
}
int linux_bind ( int fd, const struct sockaddr *addr, socklen_t addrlen ) {
#ifdef __NR_bind
return linux_syscall ( __NR_bind, fd, addr, addrlen );
#else
#ifndef SOCKOP_bind
# define SOCKOP_bind 2
#endif
unsigned long sc_args[] = { fd, (unsigned long)addr, addrlen };
return linux_syscall ( __NR_socketcall, SOCKOP_bind, sc_args );
#endif
}
ssize_t linux_sendto ( int fd, const void *buf, size_t len, int flags,
const struct sockaddr *daddr, socklen_t addrlen ) {
#ifdef __NR_sendto
return linux_syscall ( __NR_sendto, fd, buf, len, flags,
daddr, addrlen );
#else
#ifndef SOCKOP_sendto
# define SOCKOP_sendto 11
#endif
unsigned long sc_args[] = { fd, (unsigned long)buf, len,
flags, (unsigned long)daddr, addrlen };
return linux_syscall ( __NR_socketcall, SOCKOP_sendto, sc_args );
#endif
}

Some files were not shown because too many files have changed in this diff Show More