mirror of https://github.com/ipxe/ipxe.git
Merge remote-tracking branch 'upstream/master'
commit
2fe1a387be
|
@ -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
|
|
@ -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 ) {
|
||||
}
|
34
src/Makefile
34
src/Makefile
|
@ -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 \
|
||||
|
|
|
@ -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) $<
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# Include generic EFI Makefile
|
||||
#
|
||||
MAKEDEPS += Makefile.efi
|
||||
include Makefile.efi
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/** @file
|
||||
*
|
||||
* x86_64-specific entropy API implementations
|
||||
* ARM-specific entropy API implementations
|
||||
*
|
||||
*/
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/** @file
|
||||
*
|
||||
* x86_64-specific reboot API implementations
|
||||
* ARM-specific reboot API implementations
|
||||
*
|
||||
*/
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/** @file
|
||||
*
|
||||
* x86_64-specific sanboot API implementations
|
||||
* ARM-specific sanboot API implementations
|
||||
*
|
||||
*/
|
||||
|
|
@ -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 */
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/** @file
|
||||
*
|
||||
* x86_64-specific time API implementations
|
||||
* ARM-specific time API implementations
|
||||
*
|
||||
*/
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 );
|
|
@ -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)
|
|
@ -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
|
|
@ -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" );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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" );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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] );
|
||||
}
|
||||
}
|
|
@ -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 );
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 );
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 $@
|
|
@ -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;
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
|
@ -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] );
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue