diff --git a/mmax.config b/mmax.config new file mode 100644 index 00000000000..d5abbbd5ca8 --- /dev/null +++ b/mmax.config @@ -0,0 +1,762 @@ +# +# Automatically generated file; DO NOT EDIT. +# coreboot configuration +# + +# +# General setup +# +CONFIG_COREBOOT_BUILD=y +CONFIG_LOCALVERSION="" +CONFIG_CBFS_PREFIX="fallback" +CONFIG_COMPILER_GCC=y +# CONFIG_COMPILER_LLVM_CLANG is not set +# CONFIG_ANY_TOOLCHAIN is not set +# CONFIG_CCACHE is not set +# CONFIG_FMD_GENPARSER is not set +# CONFIG_UTIL_GENPARSER is not set +# CONFIG_USE_OPTION_TABLE is not set +CONFIG_COMPRESS_RAMSTAGE=y +CONFIG_INCLUDE_CONFIG_FILE=y +CONFIG_COLLECT_TIMESTAMPS=y +# CONFIG_TIMESTAMPS_ON_CONSOLE is not set +# CONFIG_USE_BLOBS is not set +# CONFIG_COVERAGE is not set +# CONFIG_UBSAN is not set +CONFIG_NO_RELOCATABLE_RAMSTAGE=y +# CONFIG_RELOCATABLE_RAMSTAGE is not set +# CONFIG_UPDATE_IMAGE is not set +# CONFIG_BOOTSPLASH_IMAGE is not set + +# +# Mainboard +# + +# +# Important: Run 'make distclean' before switching boards +# +# CONFIG_VENDOR_ADI is not set +# CONFIG_VENDOR_ADLINK is not set +# CONFIG_VENDOR_ADVANSUS is not set +# CONFIG_VENDOR_AMD is not set +# CONFIG_VENDOR_AOPEN is not set +# CONFIG_VENDOR_APPLE is not set +# CONFIG_VENDOR_ASROCK is not set +# CONFIG_VENDOR_ASUS is not set +# CONFIG_VENDOR_AVALUE is not set +# CONFIG_VENDOR_BAP is not set +# CONFIG_VENDOR_BIOSTAR is not set +# CONFIG_VENDOR_CAVIUM is not set +# CONFIG_VENDOR_COMPULAB is not set +# CONFIG_VENDOR_CUBIETECH is not set +# CONFIG_VENDOR_ELMEX is not set +# CONFIG_VENDOR_EMULATION is not set +# CONFIG_VENDOR_ESD is not set +# CONFIG_VENDOR_FACEBOOK is not set +# CONFIG_VENDOR_FOXCONN is not set +# CONFIG_VENDOR_GETAC is not set +# CONFIG_VENDOR_GIGABYTE is not set +# CONFIG_VENDOR_GIZMOSPHERE is not set +# CONFIG_VENDOR_GOOGLE is not set +# CONFIG_VENDOR_HP is not set +# CONFIG_VENDOR_IBASE is not set +# CONFIG_VENDOR_IEI is not set +CONFIG_VENDOR_INTEL=y +# CONFIG_VENDOR_JETWAY is not set +# CONFIG_VENDOR_KONTRON is not set +# CONFIG_VENDOR_LENOVO is not set +# CONFIG_VENDOR_LIPPERT is not set +# CONFIG_VENDOR_MSI is not set +# CONFIG_VENDOR_OCP is not set +# CONFIG_VENDOR_OPENCELLULAR is not set +# CONFIG_VENDOR_PACKARDBELL is not set +# CONFIG_VENDOR_PCENGINES is not set +# CONFIG_VENDOR_PURISM is not set +# CONFIG_VENDOR_RODA is not set +# CONFIG_VENDOR_SAMSUNG is not set +# CONFIG_VENDOR_SAPPHIRE is not set +# CONFIG_VENDOR_SCALEWAY is not set +# CONFIG_VENDOR_SIEMENS is not set +# CONFIG_VENDOR_SIFIVE is not set +# CONFIG_VENDOR_SUPERMICRO is not set +# CONFIG_VENDOR_TI is not set +# CONFIG_VENDOR_TYAN is not set +# CONFIG_VENDOR_VIA is not set +CONFIG_BOARD_SPECIFIC_OPTIONS=y +CONFIG_MAINBOARD_DIR="intel/minnowmax" +CONFIG_MAINBOARD_PART_NUMBER="Minnow Max" +CONFIG_MAX_CPUS=16 +CONFIG_FSP_FILE="3rdparty/fsp/BayTrailFspBinPkg/FspBin/BayTrailFSP.fd" +CONFIG_CBFS_SIZE=0x00600000 +CONFIG_ENABLE_FSP_FAST_BOOT=y +CONFIG_VIRTUAL_ROM_SIZE=0x800000 +CONFIG_UART_FOR_CONSOLE=0 +CONFIG_PAYLOAD_CONFIGFILE="" +CONFIG_MAINBOARD_VENDOR="Intel" +CONFIG_VGA_BIOS_ID="8086,0f31" +# CONFIG_ONBOARD_VGA_IS_PRIMARY is not set +CONFIG_DIMM_SPD_SIZE=256 +CONFIG_VGA_BIOS=y +CONFIG_MAINBOARD_SERIAL_NUMBER="123456789" +CONFIG_VGA_BIOS_FILE="3rdparty/blobs/mainboard/$(MAINBOARDDIR)/vga.dat" +CONFIG_C_ENV_BOOTBLOCK_SIZE=0x10000 +CONFIG_MAINBOARD_SMBIOS_MANUFACTURER="Intel" +CONFIG_DEVICETREE="devicetree.cb" +CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00 +CONFIG_POST_IO=y +CONFIG_DCACHE_RAM_BASE=0xfef00000 +CONFIG_DCACHE_RAM_SIZE=0x4000 +CONFIG_MAX_REBOOT_CNT=3 +CONFIG_OVERRIDE_DEVICETREE="" +CONFIG_BOOT_DEVICE_SPI_FLASH_BUS=0 +CONFIG_FMDFILE="" +CONFIG_MMCONF_BASE_ADDRESS=0xe0000000 +CONFIG_HAVE_INTEL_FIRMWARE=y +# CONFIG_POST_DEVICE is not set +CONFIG_DRIVERS_UART_8250IO=y +# CONFIG_VBOOT is not set +CONFIG_TTYS0_LCS=3 +# CONFIG_BOARD_INTEL_APOLLOLAKE_RVP1 is not set +# CONFIG_BOARD_INTEL_APOLLOLAKE_RVP2 is not set +# CONFIG_BOARD_INTEL_BASKING_RIDGE is not set +# CONFIG_BOARD_INTEL_BAKERSPORT_FSP is not set +# CONFIG_BOARD_INTEL_BAYLEYBAY_FSP is not set +# CONFIG_BOARD_INTEL_CAMELBACKMOUNTAIN_FSP is not set +# CONFIG_BOARD_INTEL_CANNONLAKE_RVPU is not set +# CONFIG_BOARD_INTEL_CANNONLAKE_RVPY is not set + +# +# Coffeelake RVP +# +# CONFIG_BOARD_INTEL_COFFEELAKE_RVPU is not set +# CONFIG_BOARD_INTEL_COFFEELAKE_RVP11 is not set +# CONFIG_BOARD_INTEL_WHISKEYLAKE_RVP is not set +# CONFIG_BOARD_INTEL_COFFEELAKE_RVP8 is not set +# CONFIG_BOARD_INTEL_COMETLAKE_RVP is not set +# CONFIG_BOARD_INTEL_D510MO is not set +# CONFIG_BOARD_INTEL_D945GCLF is not set +# CONFIG_BOARD_INTEL_DCP847SKE is not set +# CONFIG_BOARD_INTEL_DG41WV is not set +# CONFIG_BOARD_INTEL_DG43GT is not set +# CONFIG_BOARD_INTEL_EMERALDLAKE2 is not set +# CONFIG_BOARD_INTEL_GALILEO is not set +# CONFIG_BOARD_INTEL_GLKRVP is not set +# CONFIG_BOARD_INTEL_HARCUVAR is not set +# CONFIG_BOARD_INTEL_ICELAKE_RVPU is not set +# CONFIG_BOARD_INTEL_ICELAKE_RVPY is not set +# CONFIG_BOARD_INTEL_KBLRVP3 is not set +# CONFIG_BOARD_INTEL_KBLRVP7 is not set +# CONFIG_BOARD_INTEL_KBLRVP8 is not set +# CONFIG_BOARD_INTEL_KBLRVP11 is not set +# CONFIG_BOARD_INTEL_KUNIMITSU is not set +# CONFIG_BOARD_INTEL_LEAFHILL is not set +# CONFIG_BOARD_INTEL_LITTLEPLAINS is not set +# CONFIG_BOARD_INTEL_MINNOW3 is not set +CONFIG_BOARD_INTEL_MINNOWMAX=y +# CONFIG_BOARD_INTEL_MOHONPEAK is not set +# CONFIG_BOARD_INTEL_SKLSDLBRK is not set +# CONFIG_BOARD_INTEL_STRAGO is not set +# CONFIG_BOARD_INTEL_WTM2 is not set +CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="Minnow Max" +# CONFIG_BOARD_INTEL_BASEBOARD_GLKRVP is not set +CONFIG_IFD_BIN_PATH="3rdparty/blobs/mainboard/$(MAINBOARDDIR)/descriptor.bin" +CONFIG_ME_BIN_PATH="3rdparty/blobs/mainboard/$(MAINBOARDDIR)/txe.bin" +CONFIG_HAVE_IFD_BIN=y +CONFIG_CPU_ADDR_BITS=36 +CONFIG_DEFAULT_CONSOLE_LOGLEVEL=7 +CONFIG_FSP_LOC=0xfffc0000 +CONFIG_MAINBOARD_VERSION="1.0" +# CONFIG_DRIVERS_PS2_KEYBOARD is not set +# CONFIG_PCIEXP_L1_SUB_STATE is not set +CONFIG_SMBIOS_ENCLOSURE_TYPE=0x03 +CONFIG_HEAP_SIZE=0x4000 +CONFIG_BOARD_ROMSIZE_KB_8192=y +# CONFIG_COREBOOT_ROMSIZE_KB_64 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_128 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_256 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_512 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_1024 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_2048 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_4096 is not set +CONFIG_COREBOOT_ROMSIZE_KB_8192=y +# CONFIG_COREBOOT_ROMSIZE_KB_10240 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_12288 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_16384 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_32768 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_65536 is not set +CONFIG_COREBOOT_ROMSIZE_KB=8192 +CONFIG_ROM_SIZE=0x800000 +# CONFIG_SYSTEM_TYPE_LAPTOP is not set +# CONFIG_SYSTEM_TYPE_TABLET is not set +# CONFIG_SYSTEM_TYPE_DETACHABLE is not set +# CONFIG_SYSTEM_TYPE_CONVERTIBLE is not set +# CONFIG_CBFS_AUTOGEN_ATTRIBUTES is not set + +# +# Chipset +# + +# +# SoC +# +CONFIG_CPU_SPECIFIC_OPTIONS=y +CONFIG_SMM_TSEG_SIZE=0x800000 +CONFIG_SMM_RESERVED_SIZE=0x100000 +CONFIG_SMM_MODULE_STACK_SIZE=0x400 +CONFIG_ACPI_CPU_STRING="\\_PR.CP%02d" +# CONFIG_SOC_CAVIUM_CN81XX is not set +CONFIG_ARCH_ARMV8_EXTENSION=0 +CONFIG_STACK_SIZE=0x1000 +# CONFIG_SOC_CAVIUM_COMMON is not set +CONFIG_BOOTBLOCK_CPU_INIT="soc/intel/fsp_baytrail/bootblock/bootblock.c" +# CONFIG_SOC_INTEL_GLK is not set +CONFIG_X86_TOP4G_BOOTMEDIA_MAP=y +CONFIG_ROMSTAGE_ADDR=0x2000000 +CONFIG_VERSTAGE_ADDR=0x2000000 +CONFIG_FSP_HEADER_PATH="" +CONFIG_SPI_FLASH_INCLUDE_ALL_DRIVERS=y +CONFIG_ENABLE_BUILTIN_COM1=y +# CONFIG_PCIEXP_ASPM is not set +# CONFIG_PCIEXP_COMMON_CLOCK is not set +# CONFIG_PCIEXP_CLK_PM is not set +CONFIG_TTYS0_BASE=0x3f8 +# CONFIG_SOC_INTEL_COMMON_CANNONLAKE_BASE is not set +# CONFIG_SOC_INTEL_COFFEELAKE is not set +# CONFIG_SOC_INTEL_WHISKEYLAKE is not set +# CONFIG_SOC_INTEL_COMETLAKE is not set +# CONFIG_SOC_INTEL_CANNONLAKE_PCH_H is not set +CONFIG_SOC_INTEL_FSP_BAYTRAIL=y +# CONFIG_SOC_INTEL_FSP_BAYTRAIL_MD is not set +CONFIG_CPU_MICROCODE_HEADER_FILES="3rdparty/blobs/mainboard/$(MAINBOARDDIR)/M0130673324.h 3rdparty/blobs/mainboard/$(MAINBOARDDIR)/M0130679901.h" +CONFIG_BAYTRAIL_FSP_SPECIFIC_OPTIONS=y +CONFIG_CONSOLE_CBMEM=y +CONFIG_FSP_SRC_PATH="" +CONFIG_UART_PCI_ADDR=0x0 +# CONFIG_SOC_INTEL_KABYLAKE is not set +# CONFIG_SOC_MEDIATEK_MT8173 is not set +# CONFIG_SOC_MEDIATEK_MT8183 is not set +# CONFIG_SOC_NVIDIA_TEGRA124 is not set +# CONFIG_SOC_NVIDIA_TEGRA210 is not set +# CONFIG_SOC_QC_IPQ40XX is not set +# CONFIG_SOC_QC_IPQ806X is not set +# CONFIG_SOC_QUALCOMM_QCS405 is not set +# CONFIG_SOC_QUALCOMM_SDM845 is not set +# CONFIG_SOC_ROCKCHIP_RK3288 is not set +# CONFIG_SOC_ROCKCHIP_RK3399 is not set +# CONFIG_CPU_SAMSUNG_EXYNOS5250 is not set +# CONFIG_CPU_SAMSUNG_EXYNOS5420 is not set +# CONFIG_SOC_UCB_RISCV is not set + +# +# CPU +# +# CONFIG_CPU_ALLWINNER_A10 is not set +CONFIG_XIP_ROM_SIZE=0x10000 +CONFIG_NUM_IPI_STARTS=2 +# CONFIG_CPU_AMD_AGESA is not set +CONFIG_ENABLE_MRC_CACHE=y +# CONFIG_CPU_AMD_PI is not set +# CONFIG_CPU_ARMLTD_CORTEX_A9 is not set +CONFIG_SSE2=y +# CONFIG_CPU_INTEL_FIRMWARE_INTERFACE_TABLE is not set +# CONFIG_CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED is not set +# CONFIG_CPU_TI_AM335X is not set +# CONFIG_PARALLEL_CPU_INIT is not set +CONFIG_PARALLEL_MP=y +# CONFIG_PARALLEL_MP_AP_WORK is not set +# CONFIG_UDELAY_IO is not set +# CONFIG_UDELAY_LAPIC is not set +CONFIG_UDELAY_TSC=y +CONFIG_TSC_CONSTANT_RATE=y +CONFIG_TSC_MONOTONIC_TIMER=y +# CONFIG_UDELAY_TIMER2 is not set +# CONFIG_TSC_SYNC_LFENCE is not set +CONFIG_TSC_SYNC_MFENCE=y +# CONFIG_NO_FIXED_XIP_ROM_SIZE is not set +CONFIG_LOGICAL_CPUS=y +CONFIG_SMM_TSEG=y +CONFIG_SMM_MODULE_HEAP_SIZE=0x4000 +CONFIG_SMM_STUB_STACK_SIZE=0x400 +# CONFIG_SMM_LAPIC_REMAP_MITIGATION is not set +# CONFIG_SERIALIZED_SMM_INITIALIZATION is not set +# CONFIG_X86_AMD_FIXED_MTRRS is not set +CONFIG_PLATFORM_USES_FSP1_0=y +# CONFIG_MIRROR_PAYLOAD_TO_RAM_BEFORE_LOADING is not set +# CONFIG_SOC_SETS_MSRS is not set +CONFIG_CACHE_AS_RAM=y +# CONFIG_NO_CAR_GLOBAL_MIGRATION is not set +CONFIG_SMP=y +CONFIG_SSE=y +CONFIG_SUPPORT_CPU_UCODE_IN_CBFS=y +CONFIG_USES_MICROCODE_HEADER_FILES=y +CONFIG_MICROCODE_BLOB_NOT_HOOKED_UP=y +# CONFIG_CPU_MICROCODE_CBFS_EXTERNAL_BINS is not set +CONFIG_CPU_MICROCODE_CBFS_EXTERNAL_HEADER=y +# CONFIG_CPU_MICROCODE_CBFS_NONE is not set + +# +# Northbridge +# +# CONFIG_NORTHBRIDGE_AMD_AGESA is not set +# CONFIG_NORTHBRIDGE_AMD_PI is not set +CONFIG_MAX_PIRQ_LINKS=4 + +# +# Southbridge +# +# CONFIG_AMD_SB_CIMX is not set +# CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800 is not set +# CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900 is not set +# CONFIG_SOUTHBRIDGE_INTEL_COMMON is not set +CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET=y +# CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO is not set +# CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMBUS is not set +# CONFIG_SOUTHBRIDGE_INTEL_COMMON_SPI is not set +# CONFIG_SOUTHBRIDGE_INTEL_COMMON_PIRQ_ACPI_GEN is not set +# CONFIG_SOUTHBRIDGE_INTEL_COMMON_RCBA_PIRQ is not set +# CONFIG_HAVE_INTEL_CHIPSET_LOCKDOWN is not set +# CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMM is not set +CONFIG_INTEL_DESCRIPTOR_MODE_CAPABLE=y +CONFIG_INTEL_DESCRIPTOR_MODE_REQUIRED=y + +# +# Super I/O +# +# CONFIG_SUPERIO_NUVOTON_NCT6776_COM_A is not set + +# +# Embedded Controllers +# +# CONFIG_EC_GOOGLE_WILCO is not set +CONFIG_EC_BASE_ACPI_DATA=0x930 +CONFIG_EC_BASE_ACPI_COMMAND=0x934 +CONFIG_EC_BASE_HOST_DATA=0x940 +CONFIG_EC_BASE_HOST_COMMAND=0x944 +CONFIG_EC_BASE_PACKET=0x950 +CONFIG_SEABIOS_PS2_TIMEOUT=0 + +# +# Intel FSP +# +CONFIG_HAVE_FSP_BIN=y +CONFIG_MRC_CACHE_FMAP=y +CONFIG_USE_GENERIC_FSP_CAR_INC=y +CONFIG_FSP_USES_UPD=y + +# +# Intel Firmware +# +CONFIG_HAVE_ME_BIN=y +# CONFIG_MAINBOARD_USES_IFD_GBE_REGION is not set +# CONFIG_MAINBOARD_USES_IFD_EC_REGION is not set +# CONFIG_DO_NOT_TOUCH_DESCRIPTOR_REGION is not set +# CONFIG_LOCK_MANAGEMENT_ENGINE is not set +CONFIG_UNLOCK_FLASH_REGIONS=y +# CONFIG_CAVIUM_BDK is not set +# CONFIG_MAINBOARD_HAS_CHROMEOS is not set +# CONFIG_GOOGLE_SMBIOS_MAINBOARD_VERSION is not set +CONFIG_FSP_VENDORCODE_HEADER_PATH="fsp1_0/baytrail" +# CONFIG_UEFI_2_4_BINDING is not set +# CONFIG_UDK_2015_BINDING is not set +# CONFIG_UDK_2017_BINDING is not set +CONFIG_UDK_2013_VERSION=2013 +CONFIG_UDK_2015_VERSION=2015 +CONFIG_UDK_2017_VERSION=2017 +CONFIG_UDK_VERSION=2013 +# CONFIG_USE_SIEMENS_HWILIB is not set +# CONFIG_ARCH_ARM is not set +# CONFIG_ARCH_BOOTBLOCK_ARM is not set +# CONFIG_ARCH_VERSTAGE_ARM is not set +# CONFIG_ARCH_ROMSTAGE_ARM is not set +# CONFIG_ARCH_RAMSTAGE_ARM is not set +# CONFIG_ARCH_BOOTBLOCK_ARMV4 is not set +# CONFIG_ARCH_VERSTAGE_ARMV4 is not set +# CONFIG_ARCH_ROMSTAGE_ARMV4 is not set +# CONFIG_ARCH_RAMSTAGE_ARMV4 is not set +# CONFIG_ARCH_BOOTBLOCK_ARMV7 is not set +# CONFIG_ARCH_VERSTAGE_ARMV7 is not set +# CONFIG_ARCH_ROMSTAGE_ARMV7 is not set +# CONFIG_ARCH_RAMSTAGE_ARMV7 is not set +# CONFIG_ARCH_BOOTBLOCK_ARMV7_M is not set +# CONFIG_ARCH_VERSTAGE_ARMV7_M is not set +# CONFIG_ARCH_BOOTBLOCK_ARMV7_R is not set +# CONFIG_ARCH_VERSTAGE_ARMV7_R is not set +# CONFIG_ARCH_ROMSTAGE_ARMV7_R is not set +# CONFIG_ARCH_RAMSTAGE_ARMV7_R is not set +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_ARM64 is not set +# CONFIG_ARCH_BOOTBLOCK_ARM64 is not set +# CONFIG_ARCH_VERSTAGE_ARM64 is not set +# CONFIG_ARCH_ROMSTAGE_ARM64 is not set +# CONFIG_ARCH_RAMSTAGE_ARM64 is not set +# CONFIG_ARCH_BOOTBLOCK_ARMV8_64 is not set +# CONFIG_ARCH_VERSTAGE_ARMV8_64 is not set +# CONFIG_ARCH_ROMSTAGE_ARMV8_64 is not set +# CONFIG_ARCH_RAMSTAGE_ARMV8_64 is not set +# CONFIG_ARM64_USE_ARCH_TIMER is not set +# CONFIG_ARM64_A53_ERRATUM_843419 is not set +# CONFIG_ARCH_MIPS is not set +# CONFIG_ARCH_BOOTBLOCK_MIPS is not set +# CONFIG_ARCH_VERSTAGE_MIPS is not set +# CONFIG_ARCH_ROMSTAGE_MIPS is not set +# CONFIG_ARCH_RAMSTAGE_MIPS is not set +# CONFIG_ARCH_PPC64 is not set +# CONFIG_ARCH_BOOTBLOCK_PPC64 is not set +# CONFIG_ARCH_VERSTAGE_PPC64 is not set +# CONFIG_ARCH_ROMSTAGE_PPC64 is not set +# CONFIG_ARCH_RAMSTAGE_PPC64 is not set +# CONFIG_ARCH_RISCV is not set +CONFIG_ARCH_RISCV_M=y +# CONFIG_ARCH_RISCV_S is not set +# CONFIG_ARCH_RISCV_U is not set +# CONFIG_ARCH_RISCV_RV64 is not set +# CONFIG_ARCH_RISCV_RV32 is not set +# CONFIG_ARCH_RISCV_PMP is not set +# CONFIG_ARCH_BOOTBLOCK_RISCV is not set +# CONFIG_ARCH_VERSTAGE_RISCV is not set +# CONFIG_ARCH_ROMSTAGE_RISCV is not set +# CONFIG_ARCH_RAMSTAGE_RISCV is not set +# CONFIG_RISCV_USE_ARCH_TIMER is not set +CONFIG_ARCH_X86=y +CONFIG_ARCH_BOOTBLOCK_X86_32=y +CONFIG_ARCH_VERSTAGE_X86_32=y +CONFIG_ARCH_ROMSTAGE_X86_32=y +# CONFIG_ARCH_POSTCAR_X86_32 is not set +CONFIG_ARCH_RAMSTAGE_X86_32=y +# CONFIG_ARCH_BOOTBLOCK_X86_64 is not set +# CONFIG_ARCH_VERSTAGE_X86_64 is not set +# CONFIG_ARCH_ROMSTAGE_X86_64 is not set +# CONFIG_ARCH_POSTCAR_X86_64 is not set +# CONFIG_ARCH_RAMSTAGE_X86_64 is not set +# CONFIG_USE_MARCH_586 is not set +# CONFIG_AP_IN_SIPI_WAIT is not set +# CONFIG_SIPI_VECTOR_IN_ROM is not set +CONFIG_RAMBASE=0xe00000 +CONFIG_RAMTOP=0x1000000 +# CONFIG_CBMEM_TOP_BACKUP is not set +# CONFIG_EARLY_EBDA_INIT is not set +CONFIG_PC80_SYSTEM=y +# CONFIG_BOOTBLOCK_DEBUG_SPINLOOP is not set +# CONFIG_BOOTBLOCK_SAVE_BIST_AND_TIMESTAMP is not set +# CONFIG_HAVE_CMOS_DEFAULT is not set +CONFIG_IOAPIC_INTERRUPTS_ON_FSB=y +# CONFIG_IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS is not set +# CONFIG_HPET_ADDRESS_OVERRIDE is not set +CONFIG_HPET_ADDRESS=0xfed00000 +CONFIG_ID_SECTION_OFFSET=0x80 +# CONFIG_POSTCAR_STAGE is not set +# CONFIG_VERSTAGE_DEBUG_SPINLOOP is not set +# CONFIG_ROMSTAGE_DEBUG_SPINLOOP is not set +CONFIG_BOOTBLOCK_SIMPLE=y +# CONFIG_BOOTBLOCK_NORMAL is not set +CONFIG_BOOTBLOCK_SOURCE="bootblock_simple.c" +# CONFIG_COLLECT_TIMESTAMPS_NO_TSC is not set +CONFIG_COLLECT_TIMESTAMPS_TSC=y +# CONFIG_PAGING_IN_CACHE_AS_RAM is not set +# CONFIG_IDT_IN_EVERY_STAGE is not set +CONFIG_HAVE_CF9_RESET=y + +# +# Devices +# +# CONFIG_MAINBOARD_HAS_NATIVE_VGA_INIT is not set +# CONFIG_MAINBOARD_HAS_LIBGFXINIT is not set +# CONFIG_VGA_ROM_RUN is not set +CONFIG_NO_GFX_INIT=y +# CONFIG_MULTIPLE_VGA_ADAPTERS is not set +# CONFIG_SMBUS_HAS_AUX_CHANNELS is not set +CONFIG_PCI=y +# CONFIG_NO_MMCONF_SUPPORT is not set +CONFIG_MMCONF_SUPPORT=y +# CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT is not set +CONFIG_PCIX_PLUGIN_SUPPORT=y +CONFIG_CARDBUS_PLUGIN_SUPPORT=y +# CONFIG_AZALIA_PLUGIN_SUPPORT is not set +CONFIG_PCIEXP_PLUGIN_SUPPORT=y +# CONFIG_EARLY_PCI_BRIDGE is not set +CONFIG_SUBSYSTEM_VENDOR_ID=0x0000 +CONFIG_SUBSYSTEM_DEVICE_ID=0x0000 +# CONFIG_VGA_BIOS_DGPU is not set +# CONFIG_SOFTWARE_I2C is not set + +# +# Generic Drivers +# +# CONFIG_DRIVERS_AS3722_RTC is not set +# CONFIG_GIC is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_DRIVERS_LENOVO_WACOM is not set +# CONFIG_RT8168_GET_MAC_FROM_VPD is not set +# CONFIG_RT8168_SET_LED_MODE is not set +# CONFIG_SMMSTORE_IN_CBFS is not set +CONFIG_SPI_FLASH=y +CONFIG_BOOT_DEVICE_SPI_FLASH_RW_NOMMAP=y +# CONFIG_BOOT_DEVICE_SPI_FLASH_RW_NOMMAP_EARLY is not set +# CONFIG_SPI_FLASH_NO_FAST_READ is not set +CONFIG_SPI_FLASH_ADESTO=y +CONFIG_SPI_FLASH_AMIC=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_SPI_FLASH_EON=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_SST=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B is not set +# CONFIG_SPI_FLASH_HAS_VOLATILE_GROUP is not set +CONFIG_HAVE_SPI_CONSOLE_SUPPORT=y +CONFIG_DRIVERS_UART=y +# CONFIG_DRIVERS_UART_8250IO_SKIP_INIT is not set +# CONFIG_NO_UART_ON_SUPERIO is not set +# CONFIG_UART_OVERRIDE_INPUT_CLOCK_DIVIDER is not set +# CONFIG_UART_OVERRIDE_REFCLK is not set +# CONFIG_DRIVERS_UART_8250MEM is not set +# CONFIG_DRIVERS_UART_8250MEM_32 is not set +# CONFIG_HAVE_UART_SPECIAL is not set +# CONFIG_DRIVERS_UART_OXPCIE is not set +# CONFIG_DRIVERS_UART_PL011 is not set +# CONFIG_UART_USE_REFCLK_AS_INPUT_CLOCK is not set +# CONFIG_HAVE_USBDEBUG is not set +# CONFIG_HAVE_USBDEBUG_OPTIONS is not set +# CONFIG_VPD is not set +# CONFIG_DRIVERS_AMD_PI is not set +# CONFIG_SMBIOS_PROVIDED_BY_MOBO is not set +# CONFIG_DRIVERS_I2C_MAX98373 is not set +# CONFIG_DRIVERS_I2C_MAX98927 is not set +# CONFIG_DRIVERS_I2C_PCA9538 is not set +# CONFIG_DRIVERS_I2C_PCF8523 is not set +# CONFIG_DRIVERS_I2C_RT5663 is not set +# CONFIG_DRIVERS_I2C_RTD2132 is not set +# CONFIG_DRIVERS_I2C_RX6110SA is not set +# CONFIG_DRIVERS_I2C_SX9310 is not set +# CONFIG_MAINBOARD_HAS_I2C_TPM_ATMEL is not set +# CONFIG_MAINBOARD_HAS_I2C_TPM_CR50 is not set +# CONFIG_MAINBOARD_HAS_I2C_TPM_GENERIC is not set + +# +# Intel FSP +# +# CONFIG_PLATFORM_USES_FSP2_0 is not set +# CONFIG_PLATFORM_USES_FSP2_1 is not set +# CONFIG_INTEL_DDI is not set +# CONFIG_INTEL_EDID is not set +# CONFIG_INTEL_INT15 is not set +# CONFIG_INTEL_GMA_ACPI is not set +# CONFIG_INTEL_GMA_SSC_ALTERNATE_REF is not set +# CONFIG_INTEL_GMA_SWSMISCI is not set +# CONFIG_DRIVER_INTEL_I210 is not set +# CONFIG_DRIVERS_INTEL_MIPI_CAMERA is not set +CONFIG_DRIVERS_INTEL_WIFI=y +# CONFIG_USE_SAR is not set +# CONFIG_DRIVERS_LENOVO_HYBRID_GRAPHICS is not set +# CONFIG_DRIVER_MAXIM_MAX77686 is not set +# CONFIG_DRIVER_PARADE_PS8625 is not set +# CONFIG_DRIVER_PARADE_PS8640 is not set +CONFIG_DRIVERS_MC146818=y +# CONFIG_LPC_TPM is not set +# CONFIG_MAINBOARD_HAS_LPC_TPM is not set +# CONFIG_DRIVERS_RICOH_RCE822 is not set +# CONFIG_DRIVER_SIEMENS_NC_FPGA is not set +# CONFIG_NC_FPGA_NOTIFY_CB_READY is not set +# CONFIG_DRIVERS_SIL_3114 is not set +# CONFIG_MAINBOARD_HAS_SPI_TPM_CR50 is not set +# CONFIG_DRIVER_TI_TPS65090 is not set +# CONFIG_DRIVERS_TI_TPS65913 is not set +# CONFIG_DRIVERS_TI_TPS65913_RTC is not set +# CONFIG_DRIVERS_USB_ACPI is not set +# CONFIG_DRIVER_XPOWERS_AXP209 is not set +# CONFIG_COMMONLIB_STORAGE is not set + +# +# Security +# + +# +# Verified Boot (vboot) +# + +# +# Trusted Platform Module +# +CONFIG_USER_NO_TPM=y +# CONFIG_ACPI_SATA_GENERATOR is not set +CONFIG_ACPI_INTEL_HARDWARE_SLEEP_VALUES=y +# CONFIG_ACPI_AMD_HARDWARE_SLEEP_VALUES is not set +# CONFIG_BOOT_DEVICE_NOT_SPI_FLASH is not set +CONFIG_BOOT_DEVICE_SPI_FLASH=y +CONFIG_BOOT_DEVICE_MEMORY_MAPPED=y +# CONFIG_BOOT_DEVICE_SUPPORTS_WRITES is not set +# CONFIG_RTC is not set + +# +# Console +# +CONFIG_SQUELCH_EARLY_SMP=y +CONFIG_CONSOLE_SERIAL=y + +# +# I/O mapped, 8250-compatible +# + +# +# Serial port base address = 0x3f8 +# +# CONFIG_CONSOLE_SERIAL_921600 is not set +# CONFIG_CONSOLE_SERIAL_460800 is not set +# CONFIG_CONSOLE_SERIAL_230400 is not set +CONFIG_CONSOLE_SERIAL_115200=y +# CONFIG_CONSOLE_SERIAL_57600 is not set +# CONFIG_CONSOLE_SERIAL_38400 is not set +# CONFIG_CONSOLE_SERIAL_19200 is not set +# CONFIG_CONSOLE_SERIAL_9600 is not set +CONFIG_TTYS0_BAUD=115200 +# CONFIG_SPKMODEM is not set +# CONFIG_CONSOLE_NE2K is not set +CONFIG_CONSOLE_CBMEM_BUFFER_SIZE=0x20000 +# CONFIG_CONSOLE_SPI_FLASH is not set +# CONFIG_SPI_CONSOLE is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_8 is not set +CONFIG_DEFAULT_CONSOLE_LOGLEVEL_7=y +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_6 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_5 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_4 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_3 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_2 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_1 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_0 is not set +# CONFIG_NO_POST is not set +# CONFIG_CMOS_POST is not set +# CONFIG_CONSOLE_POST is not set +CONFIG_POST_IO_PORT=0x80 +# CONFIG_NO_EARLY_BOOTBLOCK_POSTCODES is not set +CONFIG_HWBASE_DEBUG_CB=y +# CONFIG_HAVE_ACPI_RESUME is not set +# CONFIG_ACPI_HUGE_LOWMEM_BACKUP is not set +# CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK is not set +# CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK is not set +# CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK is not set +CONFIG_HAVE_MONOTONIC_TIMER=y +# CONFIG_GENERIC_UDELAY is not set +# CONFIG_TIMER_QUEUE is not set +CONFIG_HAVE_OPTION_TABLE=y +# CONFIG_PIRQ_ROUTE is not set +CONFIG_HAVE_SMI_HANDLER=y +# CONFIG_PCI_IO_CFG_EXT is not set +# CONFIG_IOAPIC is not set +# CONFIG_USE_WATCHDOG_ON_BOOT is not set +# CONFIG_GFXUMA is not set +CONFIG_HAVE_ACPI_TABLES=y +# CONFIG_COMMON_FADT is not set +# CONFIG_ACPI_NHLT is not set + +# +# System tables +# +# CONFIG_GENERATE_MP_TABLE is not set +# CONFIG_GENERATE_PIRQ_TABLE is not set +CONFIG_GENERATE_SMBIOS_TABLES=y + +# +# Payload +# +# CONFIG_PAYLOAD_NONE is not set +# CONFIG_PAYLOAD_ELF is not set +# CONFIG_PAYLOAD_BAYOU is not set +# CONFIG_PAYLOAD_FILO is not set +# CONFIG_PAYLOAD_GRUB2 is not set +# CONFIG_PAYLOAD_LINUXBOOT is not set +CONFIG_PAYLOAD_SEABIOS=y +# CONFIG_PAYLOAD_UBOOT is not set +# CONFIG_PAYLOAD_YABITS is not set +# CONFIG_PAYLOAD_LINUX is not set +# CONFIG_PAYLOAD_TIANOCORE is not set +CONFIG_PAYLOAD_FILE="payloads/external/SeaBIOS/seabios/out/bios.bin.elf" +CONFIG_SEABIOS_STABLE=y +# CONFIG_SEABIOS_MASTER is not set +# CONFIG_SEABIOS_REVISION is not set +# CONFIG_SEABIOS_THREAD_OPTIONROMS is not set +CONFIG_SEABIOS_BOOTORDER_FILE="" +CONFIG_SEABIOS_ADD_SERCON_PORT_FILE=y +CONFIG_SEABIOS_SERCON_PORT_ADDR=0x3f8 +CONFIG_SEABIOS_DEBUG_LEVEL=-1 + +# +# Using default SeaBIOS log level +# +CONFIG_PAYLOAD_OPTIONS="" +CONFIG_PXE=y + +# +# PXE Options +# +# CONFIG_PXE_ROM is not set +CONFIG_BUILD_IPXE=y +CONFIG_IPXE_STABLE=y +# CONFIG_IPXE_MASTER is not set +CONFIG_PXE_ROM_ID="8086,1539" +CONFIG_PXE_SERIAL_CONSOLE=y +CONFIG_COMPRESSED_PAYLOAD_LZMA=y +# CONFIG_COMPRESSED_PAYLOAD_LZ4 is not set +# CONFIG_PAYLOAD_IS_FLAT_BINARY is not set +CONFIG_COMPRESS_SECONDARY_PAYLOAD=y + +# +# Secondary Payloads +# +# CONFIG_COREINFO_SECONDARY_PAYLOAD is not set +CONFIG_BAREFLANK_SECONDARY_PAYLOAD=y +CONFIG_MEMTEST_SECONDARY_PAYLOAD=y +# CONFIG_NVRAMCUI_SECONDARY_PAYLOAD is not set +# CONFIG_TINT_SECONDARY_PAYLOAD is not set +CONFIG_MEMTEST_STABLE=y +# CONFIG_MEMTEST_MASTER is not set +# CONFIG_MEMTEST_REVISION is not set + +# +# Reserve RAM for payload +# +CONFIG_CUSTOM_RAM_RES_ADDR=0x21000000 +CONFIG_CUSTOM_RAM_RES_SIZE=0x45000000 + +# +# Debugging +# + +# +# CPU Debug Settings +# +# CONFIG_DEBUG_SMM_RELOCATION is not set + +# +# General Debug Settings +# +# CONFIG_GDB_STUB is not set +# CONFIG_FATAL_ASSERTS is not set +# CONFIG_DEBUG_CBFS is not set +# CONFIG_HAVE_DEBUG_RAM_SETUP is not set +# CONFIG_HAVE_DEBUG_SMBUS is not set +# CONFIG_DEBUG_SMI is not set +# CONFIG_DEBUG_MALLOC is not set +# CONFIG_DEBUG_ACPI is not set +# CONFIG_DEBUG_CONSOLE_INIT is not set +# CONFIG_DEBUG_SPI_FLASH is not set +# CONFIG_TRACE is not set +# CONFIG_DEBUG_BOOT_STATE is not set +# CONFIG_DEBUG_ADA_CODE is not set +CONFIG_HAVE_EM100_SUPPORT=y +# CONFIG_EM100 is not set +CONFIG_NO_EDID_FILL_FB=y +# CONFIG_ENABLE_APIC_EXT_ID is not set +CONFIG_WARNINGS_ARE_ERRORS=y +# CONFIG_POWER_BUTTON_DEFAULT_ENABLE is not set +# CONFIG_POWER_BUTTON_DEFAULT_DISABLE is not set +# CONFIG_POWER_BUTTON_FORCE_ENABLE is not set +# CONFIG_POWER_BUTTON_FORCE_DISABLE is not set +# CONFIG_POWER_BUTTON_IS_OPTIONAL is not set +CONFIG_REG_SCRIPT=y +# CONFIG_NO_XIP_EARLY_STAGES is not set +# CONFIG_EARLY_CBMEM_LIST is not set +CONFIG_RELOCATABLE_MODULES=y +CONFIG_NO_STAGE_CACHE=y +CONFIG_BOOTBLOCK_CUSTOM=y diff --git a/payloads/Kconfig b/payloads/Kconfig index d0f8a440800..d339cfeb34b 100644 --- a/payloads/Kconfig +++ b/payloads/Kconfig @@ -124,6 +124,13 @@ config COREINFO_SECONDARY_PAYLOAD coreinfo can be loaded as a secondary payload under SeaBIOS, GRUB, or any other payload that can load additional payloads. +config BAREFLANK_SECONDARY_PAYLOAD + bool "Load Bareflank as a secondary payload" + default n + depends on ARCH_X86 + help + Bareflank can be loaded before primary payload. + config MEMTEST_SECONDARY_PAYLOAD bool "Load Memtest86+ as a secondary payload" default n @@ -151,4 +158,20 @@ config TINT_SECONDARY_PAYLOAD source "payloads/external/*/Kconfig.secondary" endmenu # "Secondary Payloads" + +menu "Reserve RAM for payload" + +config CUSTOM_RAM_RES_ADDR + hex "Base address for reserved memory" + default 0 + help + If a payload needs some preallocated memory this field specifies + starting address of reserved memory region. + +config CUSTOM_RAM_RES_SIZE + hex "Size of reserved memory" + default 0 + help + Size (in bytes) of reserved memory region. +endmenu endmenu diff --git a/payloads/Makefile.inc b/payloads/Makefile.inc index 83d3910ce06..3f77fe432e8 100644 --- a/payloads/Makefile.inc +++ b/payloads/Makefile.inc @@ -13,6 +13,11 @@ ## GNU General Public License for more details. ## +cbfs-files-$(CONFIG_BAREFLANK_SECONDARY_PAYLOAD) += $(CONFIG_CBFS_PREFIX)/payload +$(CONFIG_CBFS_PREFIX)/payload-file := payloads/bareflank/build/bareflank.elf +$(CONFIG_CBFS_PREFIX)/payload-type := payload +$(CONFIG_CBFS_PREFIX)/payload-compression := $(CBFS_SECONDARY_PAYLOAD_COMPRESS_FLAG) + cbfs-files-$(CONFIG_COREINFO_SECONDARY_PAYLOAD) += img/coreinfo img/coreinfo-file := payloads/coreinfo/build/coreinfo.elf img/coreinfo-type := payload @@ -24,6 +29,7 @@ img/nvramcui-type := payload img/nvramcui-compression := $(CBFS_SECONDARY_PAYLOAD_COMPRESS_FLAG) PAYLOADS_LIST=\ +payloads/bareflank \ payloads/coreinfo \ payloads/nvramcui \ payloads/libpayload \ @@ -38,6 +44,9 @@ payloads/external/GRUB2 \ payloads/external/LinuxBoot \ payloads/external/Yabits \ +payloads/bareflank/build/bareflank.elf bareflank: + $(MAKE) -C payloads/bareflank defaultbuild CONFIG_CBFS_PREFIX=$(CONFIG_CBFS_PREFIX) + payloads/coreinfo/build/coreinfo.elf coreinfo: $(MAKE) -C payloads/coreinfo defaultbuild diff --git a/payloads/bareflank/Kconfig b/payloads/bareflank/Kconfig new file mode 100644 index 00000000000..8cee21381db --- /dev/null +++ b/payloads/bareflank/Kconfig @@ -0,0 +1,17 @@ +## +## 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; version 2 of the License. +## +## 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. +## + +# +# For a description of the syntax of this configuration file, +# see http://lxr.linux.no/source/Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "Bareflank Configuration" diff --git a/payloads/bareflank/Makefile b/payloads/bareflank/Makefile new file mode 100644 index 00000000000..c19fcb79dd6 --- /dev/null +++ b/payloads/bareflank/Makefile @@ -0,0 +1,144 @@ +## +## This file is part of the coreinfo project. +## +## Copyright (C) 2008 Advanced Micro Devices, Inc. +## Copyright (C) 2008 Uwe Hermann +## +## 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; version 2 of the License. +## +## 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. +## + +src := $(CURDIR) +srctree := $(src) +srck := $(src)/../../util/kconfig +coreinfo_obj := $(src)/build +objk := $(src)/build/util/kconfig + +ifeq ($(filter %clean,$(MAKECMDGOALS)),) +export KERNELVERSION := 0.1.0 +export KCONFIG_AUTOHEADER := $(coreinfo_obj)/config.h +export KCONFIG_AUTOCONFIG := $(coreinfo_obj)/auto.conf +export KCONFIG_DEPENDENCIES := $(coreinfo_obj)/auto.conf.cmd +export KCONFIG_SPLITCONFIG := $(coreinfo_obj)/config +export KCONFIG_TRISTATE := $(coreinfo_obj)/tristate.conf +export KCONFIG_CONFIG := $(CURDIR)/.config +export KCONFIG_NEGATIVES := 1 +export Kconfig := Kconfig + +export V := $(V) + +CONFIG_SHELL := sh +KBUILD_DEFCONFIG := configs/defconfig +UNAME_RELEASE := $(shell uname -r) +HAVE_DOTCONFIG := $(wildcard .config) +MAKEFLAGS += -rR --no-print-directory + +# Make is silent per default, but 'make V=1' will show all compiler calls. +ifneq ($(V),1) +.SILENT: +endif + +HOSTCC ?= gcc +HOSTCXX ?= g++ +HOSTCFLAGS := -I$(srck) -I$(objk) +HOSTCXXFLAGS := -I$(srck) -I$(objk) + +LIBPAYLOAD_PATH := $(realpath ../libpayload) +LIBPAYLOAD_OBJ := $(coreinfo_obj)/libpayload +HAVE_LIBPAYLOAD := $(wildcard $(LIBPAYLOAD_OBJ)/lib/libpayload.a) +LIBPAYLOAD_CONFIG ?= configs/defconfig-tinycurses-64 +OBJCOPY ?= objcopy + +INCLUDES = -I$(coreinfo_obj) -include $(LIBPAYLOAD_OBJ)/include/kconfig.h -I$(src)/../../src/commonlib/include -I$(src)/include -I$(src) +OBJECTS = common.o entry.o platform.o +OBJS = $(patsubst %,$(coreinfo_obj)/%,$(OBJECTS)) +TARGET = $(coreinfo_obj)/bareflank.elf + +all: real-all + +# in addition to the dependency below, create the file if it doesn't exist +# to silence warnings about a file that would be generated anyway. +$(if $(wildcard .xcompile),,$(eval $(shell ../../util/xcompile/xcompile $(XGCCPATH) > .xcompile || rm -f .xcompile))) +.xcompile: ../../util/xcompile/xcompile + $< $(XGCCPATH) > $@.tmp + \mv -f $@.tmp $@ 2> /dev/null || rm -f $@.tmp $@ + +CONFIG_COMPILER_GCC := y +ARCH-y := x86_64 + +include .xcompile + +CC := $(CC_$(ARCH-y)) +AS := $(AS_$(ARCH-y)) +OBJCOPY := $(OBJCOPY_$(ARCH-y)) + +LPCC := CC="$(CC)" $(LIBPAYLOAD_OBJ)/bin/lpgcc +LPAS := AS="$(AS)" $(LIBPAYLOAD_OBJ)/bin/lpas + +CFLAGS += -Wall -Werror -Os -fno-builtin $(CFLAGS_$(ARCH-y)) $(INCLUDES) + +ifneq ($(strip $(HAVE_DOTCONFIG)),) +include $(src)/.config +real-all: $(TARGET) + +$(TARGET): $(src)/.config $(coreinfo_obj)/config.h $(OBJS) libpayload + printf " LPCC $(subst $(CURDIR)/,,$(@)) (LINK)\n" + $(LPCC) -o $@ $(OBJS) + $(OBJCOPY) --only-keep-debug $@ $(TARGET).debug + $(OBJCOPY) --strip-debug $@ + $(OBJCOPY) --add-gnu-debuglink=$(TARGET).debug $@ + +$(coreinfo_obj)/%.S.o: $(src)/%.S libpayload + printf " LPAS $(subst $(CURDIR)/,,$(@))\n" + $(LPAS) -o $@ $< + +$(coreinfo_obj)/%.o: $(src)/%.c libpayload + printf " LPCC $(subst $(CURDIR)/,,$(@))\n" + $(LPCC) $(CFLAGS) -c -o $@ $< -DCONFIG_CBFS_PREFIX=\"$(CONFIG_CBFS_PREFIX)\" + +else +real-all: config +endif + +defaultbuild: + $(MAKE) olddefconfig + $(MAKE) all + +ifneq ($(strip $(HAVE_LIBPAYLOAD)),) +libpayload: + printf "Found Libpayload $(LIBPAYLOAD_OBJ).\n" +else +LPOPTS=obj="$(CURDIR)/lpbuild" DOTCONFIG="$(CURDIR)/lp.config" +libpayload: + printf "Building libpayload @ $(LIBPAYLOAD_PATH).\n" + $(MAKE) -C $(LIBPAYLOAD_PATH) $(LPOPTS) distclean coreinfo_obj=$(coreinfo_obj)/libptmp + $(MAKE) -C $(LIBPAYLOAD_PATH) $(LPOPTS) defconfig KBUILD_DEFCONFIG=$(LIBPAYLOAD_CONFIG) + $(MAKE) -C $(LIBPAYLOAD_PATH) $(LPOPTS) install DESTDIR=$(coreinfo_obj) +endif + +$(coreinfo_obj)/config.h: + $(MAKE) oldconfig + +$(shell mkdir -p $(coreinfo_obj) $(objk)/lxdialog $(KCONFIG_SPLITCONFIG)) + +include $(srck)/Makefile + +.PHONY: $(PHONY) prepare + +else + +clean: + rm -rf build/*.elf build/*.o .xcompile + +distclean: clean + rm -rf build lpbuild + rm -f .config* lp.config* + +.PHONY: clean distclean +endif diff --git a/payloads/bareflank/common.c b/payloads/bareflank/common.c new file mode 100755 index 00000000000..2e1d55ab6bb --- /dev/null +++ b/payloads/bareflank/common.c @@ -0,0 +1,521 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +/* -------------------------------------------------------------------------- */ +/* Global */ +/* -------------------------------------------------------------------------- */ + +int64_t g_num_modules = 0; +struct bfelf_binary_t g_modules[MAX_NUM_MODULES]; + +_start_t _start_func = 0; +struct crt_info_t g_info; +struct bfelf_loader_t g_loader; + +int64_t g_num_cpus_started = 0; +int64_t g_vmm_status = VMM_UNLOADED; + +void *g_tls = 0; +void *g_stack = 0; + +uint64_t g_tls_size = 0; +uint64_t g_stack_size = 0; +uint64_t g_stack_top = 0; + +void *g_rsdp = 0; + +/* -------------------------------------------------------------------------- */ +/* Helpers */ +/* -------------------------------------------------------------------------- */ + +int64_t +private_setup_stack(void) +{ + g_stack_size = STACK_SIZE * 2; + + g_stack = platform_alloc_rw(g_stack_size); + if (g_stack == 0) { + return BF_ERROR_OUT_OF_MEMORY; + } + + g_stack_top = (uint64_t)g_stack + g_stack_size; + g_stack_top = (g_stack_top & ~(STACK_SIZE - 1)) - 1; + + platform_memset(g_stack, 0, g_stack_size); + return BF_SUCCESS; +} + +int64_t +private_setup_tls(void) +{ + g_tls_size = THREAD_LOCAL_STORAGE_SIZE * (uint64_t)platform_num_cpus(); + + g_tls = platform_alloc_rw(g_tls_size); + if (g_tls == 0) { + return BF_ERROR_OUT_OF_MEMORY; + } + + platform_memset(g_tls, 0, g_tls_size); + return BF_SUCCESS; +} + +int64_t +private_setup_rsdp(void) +{ + g_rsdp = platform_get_rsdp(); + return BF_SUCCESS; +} + +int64_t +private_add_raw_md_to_memory_manager(uint64_t virt, uint64_t type) +{ + int64_t ret = 0; + struct memory_descriptor md = {0, 0, 0}; + + md.virt = virt; + md.phys = (uint64_t)platform_virt_to_phys((void *)md.virt); + md.type = type; + + ret = platform_call_vmm_on_core( + 0, BF_REQUEST_ADD_MDL, (uintptr_t)&md, 0); + + if (ret != MEMORY_MANAGER_SUCCESS) { + return ret; + } + + return BF_SUCCESS; +} + +int64_t +private_add_md_to_memory_manager(struct bfelf_binary_t *module) +{ + bfelf64_word s = 0; + + for (s = 0; s < bfelf_file_get_num_load_instrs(&module->ef); s++) { + + int64_t ret = 0; + + uint64_t exec_s = 0; + uint64_t exec_e = 0; + const struct bfelf_load_instr *instr = 0; + + ret = bfelf_file_get_load_instr(&module->ef, s, &instr); + bfignored(ret); + + exec_s = (uint64_t)module->exec + instr->mem_offset; + exec_e = (uint64_t)module->exec + instr->mem_offset + instr->memsz; + exec_s &= ~(BAREFLANK_PAGE_SIZE - 1); + exec_e &= ~(BAREFLANK_PAGE_SIZE - 1); + + for (; exec_s <= exec_e; exec_s += BAREFLANK_PAGE_SIZE) { + if ((instr->perm & bfpf_x) != 0) { + ret = private_add_raw_md_to_memory_manager( + exec_s, MEMORY_TYPE_R | MEMORY_TYPE_E); + } + else { + ret = private_add_raw_md_to_memory_manager( + exec_s, MEMORY_TYPE_R | MEMORY_TYPE_W); + } + + if (ret != MEMORY_MANAGER_SUCCESS) { + return ret; + } + } + } + + return BF_SUCCESS; +} + +int64_t +private_add_tss_mdl(void) +{ + uint64_t i = 0; + + for (i = 0; i < g_tls_size; i += BAREFLANK_PAGE_SIZE) { + + int64_t ret = private_add_raw_md_to_memory_manager( + (uint64_t)g_tls + i, MEMORY_TYPE_R | MEMORY_TYPE_W); + + if (ret != BF_SUCCESS) { + return ret; + } + } + + return BF_SUCCESS; +} + +int64_t +private_add_modules_mdl(void) +{ + int64_t i = 0; + + for (i = 0; i < g_num_modules; i++) { + int64_t ret = private_add_md_to_memory_manager(&g_modules[i]); + if (ret != BF_SUCCESS) { + return ret; + } + } + + return BF_SUCCESS; +} + +/* -------------------------------------------------------------------------- */ +/* Implementation */ +/* -------------------------------------------------------------------------- */ + +int64_t +common_vmm_status(void) +{ return g_vmm_status; } + +void +common_reset(void) +{ + int64_t i; + + for (i = 0; i < g_num_modules; i++) { + if (g_modules[i].exec != 0) { + platform_free_rwe(g_modules[i].exec, g_modules[i].exec_size); + } + } + + platform_memset(&g_modules, 0, sizeof(g_modules)); + platform_memset(&g_loader, 0, sizeof(struct bfelf_loader_t)); + platform_memset(&g_info, 0, sizeof(struct crt_info_t)); + platform_memset(&g_loader, 0, sizeof(struct bfelf_loader_t)); + + _start_func = 0; + + g_num_modules = 0; + g_num_cpus_started = 0; + g_vmm_status = VMM_UNLOADED; + + if (g_tls != 0) { + platform_free_rw(g_tls, g_tls_size); + } + + if (g_stack != 0) { + platform_free_rw(g_stack, g_stack_size); + } + + g_tls = 0; + g_stack = 0; + g_stack_top = 0; + + g_rsdp = 0; +} + +int64_t +common_init(void) +{ + int64_t ret = platform_init(); + if (ret != BF_SUCCESS) { + return ret; + } + + common_reset(); + + return BF_SUCCESS; +} + +int64_t +common_fini(void) +{ + if (common_vmm_status() == VMM_RUNNING) { + if (common_stop_vmm() != BF_SUCCESS) { + BFALERT("common_fini: failed to stop vmm\n"); + } + } + + if (common_vmm_status() == VMM_LOADED) { + if (common_unload_vmm() != BF_SUCCESS) { + BFALERT("common_fini: failed to unload vmm\n"); + } + } + + if (common_vmm_status() == VMM_CORRUPT) { + return BF_ERROR_VMM_CORRUPTED; + } + + if (g_num_modules > 0) { + common_reset(); + } + + return BF_SUCCESS; +} + +int64_t +common_add_module(const char *file, uint64_t fsize) +{ + if (file == 0 || fsize == 0) { + return BF_ERROR_INVALID_ARG; + } + + switch (common_vmm_status()) { + case VMM_CORRUPT: + return BF_ERROR_VMM_CORRUPTED; + case VMM_LOADED: + return BF_ERROR_VMM_INVALID_STATE; + case VMM_RUNNING: + return BF_ERROR_VMM_INVALID_STATE; + default: + break; + } + + if (g_num_modules >= MAX_NUM_MODULES) { + return BF_ERROR_MAX_MODULES_REACHED; + } + + g_modules[g_num_modules].file = file; + g_modules[g_num_modules].file_size = fsize; + + g_num_modules++; + return BF_SUCCESS; +} + +int64_t +common_load_vmm(void) +{ + int64_t ret = 0; + int64_t ignore_ret = 0; + + switch (common_vmm_status()) { + case VMM_CORRUPT: + return BF_ERROR_VMM_CORRUPTED; + case VMM_LOADED: + return BF_SUCCESS; + case VMM_RUNNING: + return BF_ERROR_VMM_INVALID_STATE; + default: + break; + } + + if (g_num_modules == 0) { + return BF_ERROR_NO_MODULES_ADDED; + } + + ret = private_setup_stack(); + if (ret != BF_SUCCESS) { + goto failure; + } + + ret = private_setup_tls(); + if (ret != BF_SUCCESS) { + goto failure; + } + + ret = private_setup_rsdp(); + if (ret != BF_SUCCESS) { + goto failure; + } + + ret = bfelf_load(g_modules, (uint64_t)g_num_modules,(void **)&_start_func, &g_info, &g_loader); + if (ret != BF_SUCCESS) { + goto failure; + } + + ret = platform_call_vmm_on_core(0, BF_REQUEST_INIT, 0, 0); + if (ret != BF_SUCCESS) { + goto failure; + } + + ret = platform_call_vmm_on_core(0, BF_REQUEST_SET_RSDP, (uint64_t)g_rsdp, 0); + if (ret != BF_SUCCESS) { + goto failure; + } + + ret = private_add_modules_mdl(); + if (ret != BF_SUCCESS) { + goto failure; + } + + ret = private_add_tss_mdl(); + if (ret != BF_SUCCESS) { + goto failure; + } + + g_vmm_status = VMM_LOADED; + return BF_SUCCESS; + +failure: + + ignore_ret = common_unload_vmm(); + bfignored(ignore_ret); + + return ret; +} + +int64_t +common_unload_vmm(void) +{ + int64_t ret = 0; + + switch (common_vmm_status()) { + case VMM_CORRUPT: + return BF_ERROR_VMM_CORRUPTED; + case VMM_RUNNING: + return BF_ERROR_VMM_INVALID_STATE; + case VMM_UNLOADED: + goto unloaded; + default: + break; + } + + ret = platform_call_vmm_on_core(0, BF_REQUEST_FINI, 0, 0); + if (ret != BF_SUCCESS) { + goto corrupted; + } + +unloaded: + + common_reset(); + + g_vmm_status = VMM_UNLOADED; + return BF_SUCCESS; + +corrupted: + + g_vmm_status = VMM_CORRUPT; + return ret; +} + +int64_t +common_start_vmm(void) +{ + int64_t ret = 0; + int64_t cpuid = 0; + int64_t ignore_ret = 0; + + switch (common_vmm_status()) { + case VMM_CORRUPT: + return BF_ERROR_VMM_CORRUPTED; + case VMM_RUNNING: + return BF_SUCCESS; + case VMM_UNLOADED: + return BF_ERROR_VMM_INVALID_STATE; + default: + break; + } + + for (cpuid = 0, g_num_cpus_started = 0; cpuid < platform_num_cpus(); cpuid++) { + ret = platform_call_vmm_on_core( + (uint64_t)cpuid, BF_REQUEST_VMM_INIT, (uint64_t)cpuid, 0); + + if (ret != BF_SUCCESS) { + goto failure; + } + + g_num_cpus_started++; + } + + g_vmm_status = VMM_RUNNING; + return BF_SUCCESS; + +failure: + + ignore_ret = common_stop_vmm(); + bfignored(ignore_ret); + + return ret; +} + +int64_t +common_stop_vmm(void) +{ + int64_t ret = 0; + int64_t cpuid = 0; + + switch (common_vmm_status()) { + case VMM_CORRUPT: + return BF_ERROR_VMM_CORRUPTED; + case VMM_UNLOADED: + return BF_ERROR_VMM_INVALID_STATE; + default: + break; + } + + for (cpuid = g_num_cpus_started - 1; cpuid >= 0 ; cpuid--) { + ret = platform_call_vmm_on_core( + (uint64_t)cpuid, BF_REQUEST_VMM_FINI, (uint64_t)cpuid, 0); + + if (ret != BFELF_SUCCESS) { + goto corrupted; + } + + g_num_cpus_started--; + } + + g_vmm_status = VMM_LOADED; + return BF_SUCCESS; + +corrupted: + + g_vmm_status = VMM_CORRUPT; + return ret; +} + +int64_t +common_dump_vmm(struct debug_ring_resources_t **drr, uint64_t vcpuid) +{ + int64_t ret = 0; + + if (drr == 0) { + return BF_ERROR_INVALID_ARG; + } + + if (common_vmm_status() == VMM_UNLOADED) { + return BF_ERROR_VMM_INVALID_STATE; + } + + ret = platform_call_vmm_on_core( + 0, BF_REQUEST_GET_DRR, (uint64_t)vcpuid, (uint64_t)drr); + + if (ret != BFELF_SUCCESS) { + return ret; + } + + return BF_SUCCESS; +} + +typedef struct thread_context_t tc_t; + +int64_t +common_call_vmm( + uint64_t cpuid, uint64_t request, uintptr_t arg1, uintptr_t arg2) +{ + int64_t ignored_ret = 0; + tc_t *tc = (tc_t *)(g_stack_top - sizeof(tc_t)); + + ignored_ret = bfelf_set_integer_args(&g_info, request, arg1, arg2, 0); + bfignored(ignored_ret); + + tc->cpuid = cpuid; + tc->tlsptr = (uint64_t *)((uint64_t)g_tls + (THREAD_LOCAL_STORAGE_SIZE * (uint64_t)cpuid)); + + return _start_func((void *)(g_stack_top - sizeof(tc_t) - 1), &g_info); +} diff --git a/payloads/bareflank/entry.c b/payloads/bareflank/entry.c new file mode 100644 index 00000000000..fc24858d0b3 --- /dev/null +++ b/payloads/bareflank/entry.c @@ -0,0 +1,205 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include // TODO: read file from CBFS? +#include + +#include +#include +#include +#include + +#include +#include +#include + +extern void i386_do_exec(void* addr, int argc, char **argv, int *ret); + +/* -------------------------------------------------------------------------- */ +/* Global */ +/* -------------------------------------------------------------------------- */ + +uint64_t g_vcpuid = 0; + +struct pmodule_t { + const char *data; + uint64_t size; +}; + +uint64_t g_num_pmodules = 0; +struct pmodule_t pmodules[MAX_NUM_MODULES] = {{0}}; + +/* -------------------------------------------------------------------------- */ +/* Misc Device */ +/* -------------------------------------------------------------------------- */ + +static int64_t +ioctl_add_module(const char *file, uint64_t len) +{ + char *buf; + int64_t ret; + + if (g_num_pmodules >= MAX_NUM_MODULES) { + BFALERT("IOCTL_ADD_MODULE: too many modules have been loaded\n"); + return BF_IOCTL_FAILURE; + } + + buf = platform_alloc_rw(len); + if (buf == NULL) { + BFALERT("IOCTL_ADD_MODULE: failed to allocate memory for the module\n"); + return BF_IOCTL_FAILURE; + } + + platform_memcpy(buf, file, len); + + ret = common_add_module(buf, len); + if (ret != BF_SUCCESS) { + BFALERT("IOCTL_ADD_MODULE: common_add_module failed: %p - %s\n", (void *)ret, ec_to_str(ret)); + goto failed; + } + + pmodules[g_num_pmodules].data = buf; + pmodules[g_num_pmodules].size = len; + + g_num_pmodules++; + + return BF_IOCTL_SUCCESS; + +failed: + + platform_free_rw(buf, len); + + BFALERT("IOCTL_ADD_MODULE: failed\n"); + return BF_IOCTL_FAILURE; +} + +static long +ioctl_load_vmm(void) +{ + int64_t ret; + + ret = common_load_vmm(); + if (ret != BF_SUCCESS) { + BFALERT("IOCTL_LOAD_VMM: common_load_vmm failed: %p - %s\n", (void *)ret, ec_to_str(ret)); + goto failure; + } + + return BF_IOCTL_SUCCESS; + +failure: + + BFDEBUG("IOCTL_LOAD_VMM: failed\n"); + return BF_IOCTL_FAILURE; +} + +static long +ioctl_start_vmm(void) +{ + int64_t ret; + + ret = common_start_vmm(); + if (ret != BF_SUCCESS) { + BFALERT("IOCTL_START_VMM: common_start_vmm failed: %p - %s\n", (void *)ret, ec_to_str(ret)); + goto failure; + } + + return BF_IOCTL_SUCCESS; + +failure: + + BFDEBUG("IOCTL_START_VMM: failed\n"); + return BF_IOCTL_FAILURE; +} + +static void cbfs_run_payload(struct cbfs_payload *pay) +{ + struct cbfs_payload_segment *seg = &pay->segments; + for (;;) { + void *src = (void*)pay + ntohl(seg->offset); + void *dest = (void*)ntohll(seg->load_addr); + u32 src_len = ntohl(seg->len); + u32 dest_len = ntohl(seg->mem_len); + switch (seg->type) { + case PAYLOAD_SEGMENT_BSS: + printf("BSS segment %d@%p\n", dest_len, dest); + memset(dest, 0, dest_len); + break; + case PAYLOAD_SEGMENT_ENTRY: { + printf("Calling addr %p\n", dest); + i386_do_exec(dest, 0, NULL, NULL); + return; + } + default: + printf("Segment %x %d@%p -> %d@%p\n", seg->type, src_len, src, + dest_len, dest); + if (seg->compression == ntohl(CBFS_COMPRESS_NONE)) { + if (src_len > dest_len) + src_len = dest_len; + memcpy(dest, src, src_len); + } else if (CONFIG_LP_LZMA + && seg->compression == ntohl(CBFS_COMPRESS_LZMA)) { + int ret = ulzman(src, src_len, dest, dest_len); + if (ret < 0) + return; + src_len = ret; + } else { + printf("No support for compression type %x\n", seg->compression); + return; + } + if (dest_len > src_len) + memset(dest + src_len, 0, dest_len - src_len); + break; + } + seg++; + } +} + +/* -------------------------------------------------------------------------- */ +/* Entry / Exit */ +/* -------------------------------------------------------------------------- */ + +int main(void) +{ + void *payload = NULL; + + printf("\n"); + printf(" ___ __ _ _ \n"); + printf(" | _ ) __ _ _ _ ___ / _| |__ _ _ _ | |__\n"); + printf(" | _ \\/ _` | '_/ -_) _| / _` | ' \\| / /\n"); + printf(" |___/\\__,_|_| \\___|_| |_\\__,_|_||_|_\\_\\\n"); + printf("\n"); + printf(" Please give us a star on: https://github.com/Bareflank/hypervisor\n"); + printf("\n"); + + if (common_init() != BF_SUCCESS) { + return -1; + } + + ioctl_add_module((char *)vmm, vmm_len); + ioctl_load_vmm(); + ioctl_start_vmm(); + + payload = cbfs_load_payload(CBFS_DEFAULT_MEDIA, CONFIG_CBFS_PREFIX "/realpayload"); + + cbfs_run_payload(payload); + + printf("Should not get here...\n"); + + return 0; +} diff --git a/payloads/bareflank/include/bfaffinity.h b/payloads/bareflank/include/bfaffinity.h new file mode 100644 index 00000000000..1fb98f38e51 --- /dev/null +++ b/payloads/bareflank/include/bfaffinity.h @@ -0,0 +1,61 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfbuffer.h +/// +/// + +#ifdef WIN64 + +#include + +inline int +set_affinity(uint64_t core) +{ + if (SetProcessAffinityMask(GetCurrentProcess(), 1ULL << core) == 0) { + return -1; + } + + return 0; +} + +#else + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include + +inline int +set_affinity(uint64_t core) +{ + cpu_set_t mask; + + CPU_ZERO(&mask); + CPU_SET(core, &mask); + + if (sched_setaffinity(0, sizeof(mask), &mask) != 0) { + return -1; + } + + return 0; +} + +#endif diff --git a/payloads/bareflank/include/bfarch.h b/payloads/bareflank/include/bfarch.h new file mode 100644 index 00000000000..17c6ea47e3a --- /dev/null +++ b/payloads/bareflank/include/bfarch.h @@ -0,0 +1,49 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2017 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BFARCH_H +#define BFARCH_H + +#ifndef BF_ARCH + +#if defined(_MSC_VER) +# if defined(_M_X64) +# define BF_ARCH "intel_x64" +# define BF_X64 +# define BF_INTEL_X64 +# else +# error "bfarch.h: unsupported architecture" +# endif +#elif defined(__GNUC__) || defined(__clang__) +# if defined(__x86_64__) +# define BF_ARCH "intel_x64" +# define BF_X64 +# define BF_INTEL_X64 +# elif defined(__aarch64__) +# define BF_ARCH "aarch64" +# define BF_AARCH64 +# else +# error "bfarch.h: unsupported architecture" +# endif +#else +# error "bfarch.h: unsupported compiler" +#endif + +#endif +#endif diff --git a/payloads/bareflank/include/bfbenchmark.h b/payloads/bareflank/include/bfbenchmark.h new file mode 100644 index 00000000000..6d78980accb --- /dev/null +++ b/payloads/bareflank/include/bfbenchmark.h @@ -0,0 +1,114 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULLAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#ifndef BFBENCHMARK_H +#define BFBENCHMARK_H + +#if defined(__clang__) || defined(__GNUC__) +#pragma GCC system_header +#endif + +#include +#include + +#include + +template +uint64_t benchmark(T func) +{ + auto s = std::chrono::high_resolution_clock::now(); + func(); + auto e = std::chrono::high_resolution_clock::now(); + + return static_cast((e - s).count()); +} + +size_t g_page_allocs = 0; +size_t g_nonpage_allocs = 0; + +inline void * +custom_new(std::size_t size) +{ + if ((size & 0xFFF) == 0) { + g_page_allocs += size; + } + else { + g_nonpage_allocs += size; + } + + return malloc(size); +} + +inline void +custom_delete(void *ptr, std::size_t size) +{ + bfignored(size); + free(ptr); +} + +void * +operator new[](std::size_t size) +{ return custom_new(size); } + +void * +operator new (std::size_t size) +{ return custom_new(size); } + +void * +operator new (std::size_t count, const std::nothrow_t &) +{ return custom_new(count); } + +void * +operator new[](std::size_t count, const std::nothrow_t &) +{ return custom_new(count); } + +void +operator delete (void *ptr, std::size_t size) throw() +{ custom_delete(ptr, size); } + +void +operator delete (void *ptr) throw() +{ operator delete (ptr, static_cast(0)); } + +void +operator delete[](void *ptr, std::size_t size) throw() +{ custom_delete(ptr, size); } + +void +operator delete[](void *ptr) throw() +{ operator delete[](ptr, static_cast(0)); } + +inline void +print_memory_stats() +{ + auto page_allocs = g_page_allocs; + auto nonpage_allocs = g_nonpage_allocs; + + bfdebug_nhex(0, "bytes allocated", page_allocs + nonpage_allocs); + bfdebug_subnhex(0, "page aligned bytes allocated", page_allocs); + bfdebug_subnhex(0, "non-page aligned bytes allocated", nonpage_allocs); +} + +inline void +clear_memory_stats() +{ + g_page_allocs = 0; + g_nonpage_allocs = 0; +} + +#endif diff --git a/payloads/bareflank/include/bfbitmanip.h b/payloads/bareflank/include/bfbitmanip.h new file mode 100644 index 00000000000..528ddbb9ec3 --- /dev/null +++ b/payloads/bareflank/include/bfbitmanip.h @@ -0,0 +1,274 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULLAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfbitmanip.h +/// + +#ifndef BFBITMANIP_H +#define BFBITMANIP_H + +#include + +#include +#include + +/// Set Bit +/// +/// Sets a bit given the bit position and an integer. +/// +/// @expects +/// @ensures +/// +/// @param t integer whose bit is to be set +/// @param b bit position +/// @return t with bit set at position b +/// +template < + typename T, + typename B, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +set_bit(T t, B b) noexcept +{ + return t | (0x1ULL << b); +} + +/// Set Bit +/// +/// Sets a bit given the bit position and an integer. +/// +/// @expects +/// @ensures +/// +/// @param view view whose bit is to be set +/// @param b bit position +/// @return t with bit set at position b +/// +template < + typename T, + typename B, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +set_bit(gsl::span &view, B b) +{ + auto byte_view = gsl::as_writeable_bytes(view); + byte_view.at(b >> 3) |= gsl::narrow_cast((1 << (b & 7))); +} + +/// Clear Bit +/// +/// Clears a bit given the bit position and an integer. +/// +/// @expects +/// @ensures +/// +/// @param t integer whose bit is to be cleared +/// @param b bit position +/// @return t with bit cleared at position b +/// +template < + typename T, + typename B, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +clear_bit(T t, B b) noexcept +{ + return t & ~(0x1ULL << b); +} + +/// Clear Bit +/// +/// Clears a bit given the bit position and an integer. +/// +/// @expects +/// @ensures +/// +/// @param view view whose bit is to be cleared +/// @param b bit position +/// @return t with bit cleared at position b +/// +template < + typename T, + typename B, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +clear_bit(gsl::span &view, B b) +{ + auto byte_view = gsl::as_writeable_bytes(view); + byte_view.at(b >> 3) &= gsl::narrow_cast(~(1 << (b & 7))); +} + +/// Get Bit +/// +/// @expects +/// @ensures +/// +/// @param t integer whose bit is to be gotten +/// @param b bit position +/// @return value of bit b for integer t +/// +template < + typename T, + typename B, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +get_bit(T t, B b) noexcept +{ + return (t & (0x1ULL << b)) >> b; +} + +/// Get Bit +/// +/// @expects +/// @ensures +/// +/// @param view view whose bit is to be gotten +/// @param b bit position +/// @return value of bit b for integer t +/// +template < + typename T, + typename B, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +get_bit(const gsl::span &view, B b) +{ + auto byte_view = gsl::as_writeable_bytes(view); + return byte_view.at(b >> 3) & gsl::narrow_cast((1 << (b & 7))); +} + +/// Is Bit Set +/// +/// @expects +/// @ensures +/// +/// @param t integer whose bit is to be tested +/// @param b bit position +/// @return true if bit b in t is set, false otherwise +/// +template < + typename T, + typename B, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +is_bit_set(T t, B b) noexcept +{ + return static_cast(get_bit(t, b)) != static_cast(0); +} + +/// Is Bit Cleared +/// +/// @expects +/// @ensures +/// +/// @param t integer whose bit is to be tested +/// @param b bit position +/// @return true if bit b in t is cleared, false otherwise +/// +template < + typename T, + typename B, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +is_bit_cleared(T t, B b) noexcept +{ + return static_cast(get_bit(t, b)) == static_cast(0); +} + +/// Number of Bits Set +/// +/// @expects +/// @ensures +/// +/// @param t integer whose bit is to be tested +/// @return the number of bits set in t +/// +template < + typename T, + typename = std::enable_if::value> + > +auto +num_bits_set(T t) noexcept +{ + std::bitset<64> b{t}; + return b.count(); +} + +/// Get Bits +/// +/// @expects +/// @ensures +/// +/// @param t integer whose bits are to be gotten +/// @param m the bit mask +/// @return t & m +/// +template < + typename T, + typename M, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +get_bits(T t, M m) noexcept +{ + return t & m; +} + +/// Set Bits +/// +/// @expects +/// @ensures +/// +/// @param t integer whose bits are to be set +/// @param m the bit mask +/// @param v the bits to set +/// @return t with bits set to v masked by m +/// +template < + typename T, + typename M, + typename V, + typename = std::enable_if::value>, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +constexpr auto +set_bits(T t, M m, V v) noexcept +{ + return (t & ~m) | (v & m); +} + +#endif diff --git a/payloads/bareflank/include/bfbuffer.h b/payloads/bareflank/include/bfbuffer.h new file mode 100644 index 00000000000..7ca1c0a5944 --- /dev/null +++ b/payloads/bareflank/include/bfbuffer.h @@ -0,0 +1,309 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfbuffer.h +/// + +#ifndef BFBUFFER_H +#define BFBUFFER_H + +#include +#include + +namespace bfn +{ + +/// Buffer +/// +/// Simple character buffer class that stores both a buffer and its size. +/// This class is a hybrid between std::array, and std::unique_ptr. It's +/// dynamic, doesn't have support for iterators or random memory access, +/// and cannot be copied. +/// +class buffer +{ +public: + + using size_type = std::size_t; ///< Size type of buffer + using data_type = char; ///< Data type of buffer + + /// Default Constructor + /// + /// @expects none + /// @ensures none + /// + buffer() = default; + + /// Allocate Buffer Constructor + /// + /// @expects none + /// @ensures none + /// + /// @param size the size of the buffer to allocate + /// + /// @throws std::bad_alloc if this constructor is unable to allocate memory for the buffer + /// + buffer(size_type size) : + m_size(size), + m_data(std::make_unique(m_size)) + { + expects(size != 0); + } + + /// Pre-Allocated Buffer Constructor + /// + /// @note Takes ownership of data, and frees the provided buffer when the + /// buffer goes out of scope + /// + /// @expects none + /// @ensures none + /// + /// @param data a pointer to the buffer to store. + /// @param size the size of the provided buffer + /// + buffer(void *data, size_type size) : + m_size(size), + m_data(static_cast(data)) + { + expects(size != 0 || data == nullptr); + expects(data != nullptr || size == 0); + } + + /// Initializer List Constructor + /// + /// @expects none + /// @ensures none + /// + /// @param list initial list to create the buffer + /// + /// @throws std::bad_alloc if this constructor is unable to allocate memory for the buffer + /// + buffer(std::initializer_list list) : + m_size(list.size()), + m_data(std::make_unique(list.size())) + { + auto _i = 0LL; + auto _span = span(); + + for (const auto &elem : list) { + _span[_i++] = elem; + } + } + + /// Default Destructor + /// + /// @expects none + /// @ensures none + /// + ~buffer() = default; + + /// Get Data + /// + /// @expects none + /// @ensures none + /// + /// @return returns a pointer to the buffer + /// + data_type *get() noexcept + { return m_data.get(); } + + /// Get Data + /// + /// @expects none + /// @ensures none + /// + /// @return returns a pointer to the buffer + /// + data_type *data() noexcept + { return m_data.get(); } + + /// Get Data + /// + /// @expects none + /// @ensures none + /// + /// @return returns a pointer to the buffer + /// + const data_type *data() const noexcept + { return m_data.get(); } + + /// Is Empty + /// + /// @expects none + /// @ensures none + /// + /// @return returns true if size() == 0, false otherwise + /// + bool empty() const noexcept + { return m_size == 0; } + + /// Valid + /// + /// @return returns true if the buffer is valid, false otherwise + /// + operator bool() const noexcept + { return m_data.operator bool(); } + + /// Size + /// + /// @expects none + /// @ensures none + /// + /// @return returns the size of the buffer + /// + size_type size() const noexcept + { return m_size; } + + /// Release + /// + /// @expects none + /// @ensures none + /// + void + release() noexcept + { + m_size = 0; + m_data.release(); + } + + /// Swap + /// + /// @expects none + /// @ensures none + /// + /// @param other the other buffer to swap with + /// + void + swap(buffer &other) noexcept + { + std::swap(m_size, other.m_size); + std::swap(m_data, other.m_data); + } + + /// Span + /// + /// @expects none + /// @ensures none + /// + /// @return returns a gsl::span that can be used to access the buffer. + /// + gsl::span + span() const + { return gsl::make_span(m_data.get(), gsl::narrow_cast(m_size)); } + + /// Resize + /// + /// Resize the buffer. If count is smaller than the original size, the + /// data is truncated. If count is larger than the original size, the + /// remaining data is undefined. + /// + /// @expects none + /// @ensures none + /// + /// @param count the number of bytes to resize the buffer to + /// + /// @throws std::bad_alloc if this method is unable to allocate memory for the buffer + /// + void + resize(size_type count) + { + auto new_data = std::make_unique(count); + memcpy(new_data.get(), m_data.get(), std::min(m_size, count)); + + m_size = count; + m_data = std::move(new_data); + } + +private: + + size_type m_size{0}; + std::unique_ptr m_data; + +public: + + /// @cond + + buffer(buffer &&) noexcept = default; + buffer &operator=(buffer &&) noexcept = default; + + buffer(const buffer &) = delete; + buffer &operator=(const buffer &) = delete; + + /// @endcond +}; + +/// Swap +/// +/// @expects none +/// @ensures none +/// +/// @param lhs buffer to swap +/// @param rhs buffer to swap +/// +inline void +swap(buffer &lhs, buffer &rhs) noexcept +{ lhs.swap(rhs); } + +/// Equals +/// +/// @expects none +/// @ensures none +/// +/// @param lhs buffer to compare +/// @param rhs buffer to compare +/// @return true if ==, false otherwise +/// +inline bool +operator==(const buffer &lhs, const buffer &rhs) noexcept +{ + if (lhs.size() != rhs.size()) { + return false; + } + + return memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; +} + +/// Not Equals +/// +/// @expects none +/// @ensures none +/// +/// @param lhs buffer to compare +/// @param rhs buffer to compare +/// @return true if !=, false otherwise +/// +inline bool +operator!=(const buffer &lhs, const buffer &rhs) noexcept +{ return !(lhs == rhs); } + +/// Default Out Stream Operator +/// +/// @expects none +/// @ensures none +/// +/// @param os the out stream object +/// @return os +/// +inline std::ostream & +operator<<(std::ostream &os, const buffer &) +{ return os; } + +} + +#endif diff --git a/payloads/bareflank/include/bfcallonce.h b/payloads/bareflank/include/bfcallonce.h new file mode 100644 index 00000000000..05a7776bb39 --- /dev/null +++ b/payloads/bareflank/include/bfcallonce.h @@ -0,0 +1,56 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULLAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#ifndef BFCALLONCE +#define BFCALLONCE + +/// @cond + +#include + +// TODO +// +// This code is only needed because there seems to be a bug with GCC that +// causes a system error when --coverage is enabled. The following was written +// to have the same names and implementation as std::call_once so that at +// some point this code can easily be removed. +// +namespace bfn +{ + +struct once_flag { + bool m_value{false}; + mutable std::mutex m_mutex{}; +}; + +template +void call_once(once_flag &flag, FUNC func) +{ + std::lock_guard lock(flag.m_mutex); + + if (!flag.m_value) { + func(); + flag.m_value = true; + } +} + +} + +/// @endcond + +#endif diff --git a/payloads/bareflank/include/bfconstants.h b/payloads/bareflank/include/bfconstants.h new file mode 100755 index 00000000000..f3334e21176 --- /dev/null +++ b/payloads/bareflank/include/bfconstants.h @@ -0,0 +1,277 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BFCONSTANTS_H +#define BFCONSTANTS_H + +#include +#include + +/* + * Max Physical Address + * + * Defines the maximum physical address the system can access. This can be + * used by CR3 and EPT to define the memory map used by the VMM. Note that + * if this value is too large, its possible additional memory would be needed + * by the VMM to setup CR3 or EPT depending on the granulairty used. + * + * Note: defined in bytes + */ +#ifndef MAX_PHYS_ADDR +#define MAX_PHYS_ADDR 0x1000000000 +#endif + +/* + * Bareflank Page Size + * + * Defines the page size that is supported by the VMM. For now, this is + * set to a value that is likely supported by most hardware. + * + * Note: defined in bytes + */ +#ifndef BAREFLANK_PAGE_SIZE +#define BAREFLANK_PAGE_SIZE (0x1000ULL) +#endif + +/* + * Page Pool K + * + * Defines the size of the initial page pool used by the VMM. If more memory + * is needed by the VMM initially, this value may be increased. Note that + * increasing "K" by 1 will double the amount of memory. + */ +#ifndef PAGE_POOL_K +#define PAGE_POOL_K (15ULL) +#endif + +/* +* Huge Pool K +* +* Defines the size of the initial huge pool used by the VMM. If more memory +* is needed by the VMM initially, this value may be increased. Note that +* increasing "K" by 1 will double the amount of memory. +*/ + +#ifndef HUGE_POOL_K +#define HUGE_POOL_K (15ULL) +#endif +/* +* Memory Map Pool K +* +* Defines the size of the initial mem map pool used by the VMM. If more memory +* is needed by the VMM for mapping, this value may be increased. Note that +* increasing "K" by 1 will double the amount of memory. +*/ +#ifndef MEM_MAP_POOL_K +#define MEM_MAP_POOL_K (15ULL) +#endif + +/* + * Memory Map Pool Start + * + * This defines the starting location of the virtual memory that is used + * for memory mapping. Note that on some systems, this might need to be + * changed to prevent collisions. + * + * Note: defined in bytes (defaults to 2MB) + */ +#ifndef MEM_MAP_POOL_START +#define MEM_MAP_POOL_START 0x200000ULL +#endif + +/* + * Max Supported Modules + * + * The maximum number of modules supported by the VMM. If you VMM has a large + * number of dynamic libraries to load, this value might need to be increased + */ +#ifndef MAX_NUM_MODULES +#define MAX_NUM_MODULES (75LL) +#endif + +/* + * Debug Ring Size + * + * Defines the size of the debug ring. Note that the memory manager is used to + * allocate memory for the debug ring, so if you need more than one ring, + * which is supported, make sure the memory manager has enough memory in + * the huge pool to support your needs. + * + * Note: Must be defined using a bit shift as this prevents the debug ring from + * allocating memory that generates fragmentation in the memory manager + * + * Note: defined in bytes + */ +#define DEBUG_RING_SIZE (1 << 15ULL) + +/* + * Stack Size + * + * Each entry function is guarded with a custom stack to prevent stack + * overflows from corrupting the kernel, as well as providing a larger stack + * that's common in userspace code, but not in the kernel. If stack corruption + * is occuring, this function likely needs to be increased. Note one stack + * frame is allocated per CPU, so only increase this if needed. + * + * Note: Must be defined using a bit shift as we will mask to get the + * bottom of the stack if needed. + * + * Note: This is hard coded in the thread_context.asm as there is no way to + * use this include in NASM. If you change this, you must change the + * value in that file as well. + * + * Note: defined in bytes + */ +#ifndef STACK_SIZE +#define STACK_SIZE (1ULL << 15ULL) +#endif + +/* + * Thread Local Storage (TLS) Size + * + * Bareflank don't support threads, but it does support Multi-Core, and + * we need a way to store CPU specific information. Certain libc++ + * operations (for example, std::uncaught_exceptions) need to use this CPU + * specific storage so that the cores are not interfering with each other. + * So as far as the code is concerned, TLS is being used, even if a "thread" + * in the traditional sense isn't. + * + * Note: Defined in bytes + */ +#ifndef THREAD_LOCAL_STORAGE_SIZE +#define THREAD_LOCAL_STORAGE_SIZE (0x1000ULL) +#endif + +/* + * Default Serial COM Port + * + * On x64, possible values include (but not limited to): + * - 0x03F8U // COM1 + * - 0x02F8U // COM2 + * - 0x03E8U // COM3 + * - 0x02E8U // COM4 + * - 0xE000U + * - 0xE010U + * + * On aarch64, the value is the serial peripheral's physical base address. + * + * Note: See bfvmm/serial/serial_ns16550a.h + */ +#ifndef DEFAULT_COM_PORT +#if defined(BF_AARCH64) +# define DEFAULT_COM_PORT 0x09000000 +#else +# define DEFAULT_COM_PORT 0x03F8U +# define DEFAULT_COM_DRIVER serial_ns16550a +#endif +#endif + +/* + * Serial Port Driver + * + * Possible values include: + * - serial_ns16550a + * - serial_pl011 + * + * On x64, this should always be serial_ns16550a. + */ +#ifndef DEFAULT_COM_DRIVER +#if defined(BF_AARCH64) +# define DEFAULT_COM_DRIVER serial_pl011 +#else +# define DEFAULT_COM_DRIVER serial_ns16550a +#endif +#endif + +/* + * Serial port memory length (aarch64 only) + * + * This is the length of the memory region occupied by the memory-mapped + * serial port. + */ +#if !defined(DEFAULT_COM_LENGTH) && defined(BF_AARCH64) +#define DEFAULT_COM_LENGTH 0x1000 +#endif + +/* + * Default Serial Baud Rate + * + * Note: See bfvmm/serial/serial_ns16550a.h + */ +#ifndef DEFAULT_BAUD_RATE +#define DEFAULT_BAUD_RATE baud_rate_115200 +#endif + +/* + * Default serial baud rate divisor, integer part (for PL011) + * + * Note: See bfvmm/serial/serial_pl011.h + */ +#ifndef DEFAULT_BAUD_RATE_INT +#define DEFAULT_BAUD_RATE_INT 0x4 +#endif + +/* + * Default serial baud rate divisor, fractional part (for PL011) + * + * Note: See bfvmm/serial/serial_pl011.h + */ +#ifndef DEFAULT_BAUD_RATE_FRAC +#define DEFAULT_BAUD_RATE_FRAC 0x0 +#endif + +/* + * Default Serial Data Bits + * + * Note: See bfvmm/serial/serial_ns16550a.h + */ +#ifndef DEFAULT_DATA_BITS +#define DEFAULT_DATA_BITS char_length_8 +#endif + +/* + * Default Serial Stop Bits + * + * Note: See bfvmm/serial/serial_ns16550a.h + */ +#ifndef DEFAULT_STOP_BITS +#define DEFAULT_STOP_BITS stop_bits_1 +#endif + +/* + * Default Serial Parity Bits + * + * Note: See bfvmm/serial/serial_ns16550a.h + */ +#ifndef DEFAULT_PARITY_BITS +#define DEFAULT_PARITY_BITS parity_none +#endif + +/* + * Debug Level + * + * Defines how noisy Bareflank is. This defaults to 0 which only prints status + * information. Raise this level to include additional verbosity. Note that + * as you increase this level, performance will degrade. + */ +#ifndef DEBUG_LEVEL +#define DEBUG_LEVEL 0 +#endif + +#endif diff --git a/payloads/bareflank/include/bfdebug.h b/payloads/bareflank/include/bfdebug.h new file mode 100644 index 00000000000..03cf53b2214 --- /dev/null +++ b/payloads/bareflank/include/bfdebug.h @@ -0,0 +1,1137 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BFDEBUG_H +#define BFDEBUG_H + +#include + +/** @cond */ + +/* -------------------------------------------------------------------------- */ +/* C++ Debugging */ +/* -------------------------------------------------------------------------- */ + +#ifdef __cplusplus + +#include +#include + +#include + +#ifdef _MSC_VER +#define bfcolor_black "" +#define bfcolor_red "" +#define bfcolor_green "" +#define bfcolor_yellow "" +#define bfcolor_blue "" +#define bfcolor_magenta "" +#define bfcolor_cyan "" +#define bfcolor_end "" +#else +#define bfcolor_black "\033[1;30m" +#define bfcolor_red "\033[1;31m" +#define bfcolor_green "\033[1;32m" +#define bfcolor_yellow "\033[1;33m" +#define bfcolor_blue "\033[1;34m" +#define bfcolor_magenta "\033[1;35m" +#define bfcolor_cyan "\033[1;36m" +#define bfcolor_end "\033[0m" +#endif + +#define bfcolor_debug bfcolor_green +#define bfcolor_alert bfcolor_yellow +#define bfcolor_error bfcolor_red + +using cstr_t = const char *; + +#ifdef UNIX +#define __BFFUNC__ static_cast(__PRETTY_FUNCTION__) +#else +#define __BFFUNC__ static_cast(__FUNCTION__) +#endif + +#ifdef VMM +extern "C" uint64_t thread_context_cpuid(void); +extern "C" uint64_t write_str(const std::string &str); +#else +#include +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4312) +#endif + +template < + typename T, + typename = std::enable_if_t < + std::is_pointer::value || + std::is_integral::value + > + > +const void * +view_as_pointer(const T val) +{ return reinterpret_cast(val); } + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +extern "C" uint64_t +unsafe_write_cstr(const char *cstr, size_t len); + +/* ---------------------------------------------------------------------------*/ +/* Low Level Debugging */ +/* ---------------------------------------------------------------------------*/ + +inline char * +bfitoa(size_t value, char *str, size_t base) +{ + const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + int i = 0, j = 0; + size_t remainder; + + do { + remainder = value % base; + str[i++] = digits[remainder]; + value = value / base; + } + while (value != 0); + + str[i] = '\0'; + + for (j = 0, i--; j < i; j++, i--) { + char c = str[j]; + str[j] = str[i]; + str[i] = c; + } + + return str; +} + +#define CALLED() \ + { \ + const auto *str_text = "\033[1;32mDEBUG\033[0m: function called = "; \ + const auto *str_func = __BFFUNC__; \ + const auto *str_endl = "\n"; \ + unsafe_write_cstr(str_text, strlen(str_text)); \ + unsafe_write_cstr(str_func, strlen(str_func)); \ + unsafe_write_cstr(str_endl, strlen(str_endl)); \ + } + +#define WARNING(a) \ + { \ + const auto *str_text = "\033[1;33mWARNING\033[0m: " a " = "; \ + const auto *str_func = __BFFUNC__; \ + const auto *str_endl = "\n"; \ + unsafe_write_cstr(str_text, strlen(str_text)); \ + unsafe_write_cstr(str_func, strlen(str_func)); \ + unsafe_write_cstr(str_endl, strlen(str_endl)); \ + } + +#define UNHANDLED() \ + { \ + const auto *str_text = "\033[1;33mWARNING\033[0m: unsupported function called = "; \ + const auto *str_func = __BFFUNC__; \ + const auto *str_endl = "\n"; \ + unsafe_write_cstr(str_text, strlen(str_text)); \ + unsafe_write_cstr(str_func, strlen(str_func)); \ + unsafe_write_cstr(str_endl, strlen(str_endl)); \ + } + +#define ARG_UNSUPPORTED(a) \ + { \ + const auto *str_text = "\033[1;33mWARNING\033[0m: " a " not supported for function called = "; \ + const auto *str_func = __BFFUNC__; \ + const auto *str_endl = "\n"; \ + unsafe_write_cstr(str_text, strlen(str_text)); \ + unsafe_write_cstr(str_func, strlen(str_func)); \ + unsafe_write_cstr(str_endl, strlen(str_endl)); \ + } + + +#define DEBUG_STR(a,b) \ + { \ + const auto *str_text = "\033[1;32mDEBUG\033[0m: " a " = "; \ + const auto *str_endl = "\n"; \ + unsafe_write_cstr(str_text, strlen(str_text)); \ + unsafe_write_cstr(b, strlen(b)); \ + unsafe_write_cstr(str_endl, strlen(str_endl)); \ + } + +#define DEBUG_DEC(a,b) \ + { \ + char numstr[64]; \ + bfitoa(b, numstr, 10); \ + const auto *str_text = "\033[1;32mDEBUG\033[0m: " a " = "; \ + const auto *str_endl = "\n"; \ + unsafe_write_cstr(str_text, strlen(str_text)); \ + unsafe_write_cstr(numstr, strlen(numstr)); \ + unsafe_write_cstr(str_endl, strlen(str_endl)); \ + } + +#define DEBUG_HEX(a,b) \ + { \ + char numstr[64]; \ + bfitoa(b, numstr, 16); \ + const auto *str_text = "\033[1;32mDEBUG\033[0m: " a " = "; \ + const auto *str_endl = "\n"; \ + unsafe_write_cstr(str_text, strlen(str_text)); \ + unsafe_write_cstr(numstr, strlen(numstr)); \ + unsafe_write_cstr(str_endl, strlen(str_endl)); \ + } + +#define DEBUG_LINE() \ + { \ + char numstr[64]; \ + bfitoa(__LINE__, numstr, 10); \ + const auto *str_text = "\033[1;32mDEBUG\033[0m: "; \ + const auto *str_func = __BFFUNC__; \ + const auto *str_next = " = "; \ + const auto *str_endl = "\n"; \ + unsafe_write_cstr(str_text, strlen(str_text)); \ + unsafe_write_cstr(str_func, strlen(str_func)); \ + unsafe_write_cstr(str_next, strlen(str_next)); \ + unsafe_write_cstr(numstr, strlen(numstr)); \ + unsafe_write_cstr(str_endl, strlen(str_endl)); \ + } + +/* ---------------------------------------------------------------------------*/ +/* Helpers (Private) */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_core(gsl::not_null msg) +{ + *msg += bfcolor_cyan; + *msg += "["; + *msg += bfcolor_yellow; +#ifdef VMM + *msg += std::to_string(thread_context_cpuid()); +#else + *msg += '0'; +#endif + *msg += bfcolor_cyan; + *msg += "] "; + *msg += bfcolor_end; +} + +inline void +__bfdebug_type(gsl::not_null msg, cstr_t color, cstr_t type) +{ + *msg += color; + *msg += type; + *msg += bfcolor_end; + *msg += ": "; +} + +inline void +__bfdebug_jtfy(gsl::not_null msg, uint64_t width, cstr_t title, cstr_t indent) +{ + if (title != nullptr) { + auto len = width - strlen(title); + + if (indent != nullptr) { + len -= strlen(indent); + *msg += indent; + } + + *msg += title; + *msg += std::string(len, ' '); + } + else { + *msg += std::string(width, ' '); + } +} + +template +void __bfdebug_transaction(F func) +{ + std::string msg; + msg.reserve(0x1000); + func(&msg); + +#ifdef VMM + write_str(msg); +#else + std::cout << msg; +#endif +} + +template +void __bfdebug_add_line(std::string *msg, F func) +{ + if (msg == nullptr) { + __bfdebug_transaction([&](std::string * tmsg) { + func(tmsg); + }); + } + else { + std::string ln; + ln.reserve(0x1000); + + func(&ln); + + if (msg->size() + ln.size() > msg->capacity()) { + msg->reserve(msg->capacity() + 0x1000); + } + + *msg += ln; + } +} + +#define bfdebug_transaction(level,func) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_transaction(func); \ + } + +/* ---------------------------------------------------------------------------*/ +/* Get Macro Magic */ +/* ---------------------------------------------------------------------------*/ + +/* + * This is a cleaned up version of the following: + * https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments + * + * This is needed because some of the debug macros only take a single argument, + * which means __VA_ARGS__ gets mad because it's not used. For macros with more + * than one arg, this is not needed. Also, if this becomes needed for other + * things in the future, we should move this to it's own header + * + * The bug fix for MSVC comes from the following: + * https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly + */ + +#define __BUGFX(x) x + +#define __NARG2(...) __BUGFX(__NARG1(__VA_ARGS__,__RSEQN())) +#define __NARG1(...) __BUGFX(__ARGSN(__VA_ARGS__)) +#define __ARGSN(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N +#define __RSEQN() 10,9,8,7,6,5,4,3,2,1,0 + +#define __FUNC2(name,n) name ## n +#define __FUNC1(name,n) __FUNC2(name,n) +#define GET_MACRO(func,...) __FUNC1(func,__BUGFX(__NARG2(__VA_ARGS__))) (__VA_ARGS__) + +/* ---------------------------------------------------------------------------*/ +/* Info */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_info_core(cstr_t color, cstr_t type, cstr_t title, gsl::not_null msg) +{ + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + + if (title != nullptr) { + *msg += std::string(title); + } + + *msg += '\n'; +} + +inline void +__bfdebug_info(cstr_t color, cstr_t type, cstr_t title, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_info_core(color, type, title, ln); + }); +} + +#define bfdebug_info(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_info(bfcolor_debug, "DEBUG", __VA_ARGS__); \ + } + +#define bfalert_info(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_info(bfcolor_alert, "ALERT", __VA_ARGS__); \ + } + +#define bferror_info(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_info(bfcolor_error, "ERROR", __VA_ARGS__); \ + } + +/* ---------------------------------------------------------------------------*/ +/* Line Break */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_lnbr_core(cstr_t color, cstr_t type, gsl::not_null msg) +{ + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + + *msg += '\n'; +} + +inline void +__bfdebug_lnbr(cstr_t color, cstr_t type, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_lnbr_core(color, type, ln); + }); +} + +#define bfdebug_lnbr1(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_lnbr(bfcolor_debug, "DEBUG"); \ + } + +#define bfalert_lnbr1(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_lnbr(bfcolor_alert, "ALERT"); \ + } + +#define bferror_lnbr1(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_lnbr(bfcolor_error, "ERROR"); \ + } + +#define bfdebug_lnbr2(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_lnbr(bfcolor_debug, "DEBUG", msg); \ + } + +#define bfalert_lnbr2(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_lnbr(bfcolor_alert, "ALERT", msg); \ + } + +#define bferror_lnbr2(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_lnbr(bfcolor_error, "ERROR", msg); \ + } + +#define bfdebug_lnbr(...) GET_MACRO(bfdebug_lnbr, __VA_ARGS__) +#define bfalert_lnbr(...) GET_MACRO(bfalert_lnbr, __VA_ARGS__) +#define bferror_lnbr(...) GET_MACRO(bferror_lnbr, __VA_ARGS__) + +/* ---------------------------------------------------------------------------*/ +/* Horizontal Line Break1 */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_brk1_core(cstr_t color, cstr_t type, gsl::not_null msg) +{ + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + + *msg += "======================================================================"; + *msg += '\n'; +} + +inline void +__bfdebug_brk1(cstr_t color, cstr_t type, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_brk1_core(color, type, ln); + }); +} + +#define bfdebug_brk11(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk1(bfcolor_debug, "DEBUG"); \ + } + +#define bfalert_brk11(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk1(bfcolor_alert, "ALERT"); \ + } + +#define bferror_brk11(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk1(bfcolor_error, "ERROR"); \ + } + +#define bfdebug_brk12(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk1(bfcolor_debug, "DEBUG", msg); \ + } + +#define bfalert_brk12(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk1(bfcolor_alert, "ALERT", msg); \ + } + +#define bferror_brk12(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk1(bfcolor_error, "ERROR", msg); \ + } + +#define bfdebug_brk1(...) GET_MACRO(bfdebug_brk1, __VA_ARGS__) +#define bfalert_brk1(...) GET_MACRO(bfalert_brk1, __VA_ARGS__) +#define bferror_brk1(...) GET_MACRO(bferror_brk1, __VA_ARGS__) + +/* ---------------------------------------------------------------------------*/ +/* Horizontal Line Break2 */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_brk2_core(cstr_t color, cstr_t type, gsl::not_null msg) +{ + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + + *msg += "----------------------------------------------------------------------"; + *msg += '\n'; +} + +inline void +__bfdebug_brk2(cstr_t color, cstr_t type, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_brk2_core(color, type, ln); + }); +} + +#define bfdebug_brk21(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk2(bfcolor_debug, "DEBUG"); \ + } + +#define bfalert_brk21(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk2(bfcolor_alert, "ALERT"); \ + } + +#define bferror_brk21(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk2(bfcolor_error, "ERROR"); \ + } + +#define bfdebug_brk22(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk2(bfcolor_debug, "DEBUG", msg); \ + } + +#define bfalert_brk22(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk2(bfcolor_alert, "ALERT", msg); \ + } + +#define bferror_brk22(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk2(bfcolor_error, "ERROR", msg); \ + } + +#define bfdebug_brk2(...) GET_MACRO(bfdebug_brk2, __VA_ARGS__) +#define bfalert_brk2(...) GET_MACRO(bfalert_brk2, __VA_ARGS__) +#define bferror_brk2(...) GET_MACRO(bferror_brk2, __VA_ARGS__) + +/* ---------------------------------------------------------------------------*/ +/* Horizontal Line Break3 */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_brk3_core(cstr_t color, cstr_t type, gsl::not_null msg) +{ + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + + *msg += "......................................................................"; + *msg += '\n'; +} + +inline void +__bfdebug_brk3(cstr_t color, cstr_t type, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_brk3_core(color, type, ln); + }); +} + +#define bfdebug_brk31(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk3(bfcolor_debug, "DEBUG"); \ + } + +#define bfalert_brk31(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk3(bfcolor_alert, "ALERT"); \ + } + +#define bferror_brk31(level) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk3(bfcolor_error, "ERROR"); \ + } + +#define bfdebug_brk32(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk3(bfcolor_debug, "DEBUG", msg); \ + } + +#define bfalert_brk32(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk3(bfcolor_alert, "ALERT", msg); \ + } + +#define bferror_brk32(level,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_brk3(bfcolor_error, "ERROR", msg); \ + } + +#define bfdebug_brk3(...) GET_MACRO(bfdebug_brk3, __VA_ARGS__) +#define bfalert_brk3(...) GET_MACRO(bfalert_brk3, __VA_ARGS__) +#define bferror_brk3(...) GET_MACRO(bferror_brk3, __VA_ARGS__) + +/* ---------------------------------------------------------------------------*/ +/* Hex Number */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_nhex_core( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, uint64_t nhex, gsl::not_null msg) +{ + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + __bfdebug_jtfy(msg, 52, title, indent); + + *msg += bfn::to_string(nhex, 16); + *msg += '\n'; +} + +inline void +__bfdebug_nhex( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, uint64_t nhex, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_nhex_core(color, type, indent, title, nhex, ln); + }); +} + +inline void +__bfdebug_nhex( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, void *nhex, std::string *msg = nullptr) +{ __bfdebug_nhex(color, type, indent, title, reinterpret_cast(nhex), msg); } + +#define bfdebug_nhex(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_nhex(bfcolor_debug, "DEBUG", nullptr, __VA_ARGS__); \ + } + +#define bfalert_nhex(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_nhex(bfcolor_alert, "ALERT", nullptr, __VA_ARGS__); \ + } + +#define bferror_nhex(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_nhex(bfcolor_error, "ERROR", nullptr, __VA_ARGS__); \ + } + +#define bfdebug_subnhex(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_nhex(bfcolor_debug, "DEBUG", " - ", __VA_ARGS__); \ + } + +#define bfalert_subnhex(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_nhex(bfcolor_alert, "ALERT", " - ", __VA_ARGS__); \ + } + +#define bferror_subnhex(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_nhex(bfcolor_error, "ERROR", " - ", __VA_ARGS__); \ + } + +/* ---------------------------------------------------------------------------*/ +/* Decimal Number */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_ndec_core( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, uint64_t ndec, gsl::not_null msg) +{ + auto str = bfn::to_string(ndec, 10); + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + __bfdebug_jtfy(msg, 70 - str.length(), title, indent); + + *msg += str; + *msg += '\n'; +} + +inline void +__bfdebug_ndec( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, uint64_t ndec, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_ndec_core(color, type, indent, title, ndec, ln); + }); +} + +#define bfdebug_ndec(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_ndec(bfcolor_debug, "DEBUG", nullptr, __VA_ARGS__); \ + } + +#define bfalert_ndec(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_ndec(bfcolor_alert, "ALERT", nullptr, __VA_ARGS__); \ + } + +#define bferror_ndec(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_ndec(bfcolor_error, "ERROR", nullptr, __VA_ARGS__); \ + } + +#define bfdebug_subndec(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_ndec(bfcolor_debug, "DEBUG", " - ", __VA_ARGS__); \ + } + +#define bfalert_subndec(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_ndec(bfcolor_alert, "ALERT", " - ", __VA_ARGS__); \ + } + +#define bferror_subndec(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_ndec(bfcolor_error, "ERROR", " - ", __VA_ARGS__); \ + } + +/* ---------------------------------------------------------------------------*/ +/* Boolean */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_bool_core( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, bool val, gsl::not_null msg) +{ + auto str = val ? "true" : "false"; + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + __bfdebug_jtfy(msg, 70 - strlen(str), title, indent); + + *msg += str; + *msg += '\n'; +} + +inline void +__bfdebug_bool( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, bool val, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_bool_core(color, type, indent, title, val, ln); + }); +} + +#define bfdebug_bool(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_bool(bfcolor_debug, "DEBUG", nullptr, __VA_ARGS__); \ + } + +#define bfalert_bool(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_bool(bfcolor_alert, "ALERT", nullptr, __VA_ARGS__); \ + } + +#define bferror_bool(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_bool(bfcolor_error, "ERROR", nullptr, __VA_ARGS__); \ + } + +#define bfdebug_subbool(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_bool(bfcolor_debug, "DEBUG", " - ", __VA_ARGS__); \ + } + +#define bfalert_subbool(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_bool(bfcolor_alert, "ALERT", " - ", __VA_ARGS__); \ + } + +#define bferror_subbool(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_bool(bfcolor_error, "ERROR", " - ", __VA_ARGS__); \ + } + +/* ---------------------------------------------------------------------------*/ +/* Text */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_text_core( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, cstr_t text, gsl::not_null msg) +{ + auto str = text == nullptr ? std::string{} : std::string{text}; + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + __bfdebug_jtfy(msg, 70 - str.length(), title, indent); + + *msg += str; + *msg += '\n'; +} + +inline void +__bfdebug_text( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, cstr_t text, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_text_core(color, type, indent, title, text, ln); + }); +} + +#define bfdebug_text(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_text(bfcolor_debug, "DEBUG", nullptr, __VA_ARGS__); \ + } + +#define bfalert_text(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_text(bfcolor_alert, "ALERT", nullptr, __VA_ARGS__); \ + } + +#define bferror_text(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_text(bfcolor_error, "ERROR", nullptr, __VA_ARGS__); \ + } + +#define bfdebug_subtext(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_text(bfcolor_debug, "DEBUG", " - ", __VA_ARGS__); \ + } + +#define bfalert_subtext(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_text(bfcolor_alert, "ALERT", " - ", __VA_ARGS__); \ + } + +#define bferror_subtext(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_text(bfcolor_error, "ERROR", " - ", __VA_ARGS__); \ + } + +/* ---------------------------------------------------------------------------*/ +/* Pass */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_pass_core( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, gsl::not_null msg) +{ + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + __bfdebug_jtfy(msg, 66, title, indent); + + *msg += bfcolor_green "pass" bfcolor_end; + *msg += '\n'; +} + +inline void +__bfdebug_pass( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_pass_core(color, type, indent, title, ln); + }); +} + +#define bfdebug_pass(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_pass(bfcolor_debug, "DEBUG", nullptr, __VA_ARGS__); \ + } + +#define bfalert_pass(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_pass(bfcolor_alert, "ALERT", nullptr, __VA_ARGS__); \ + } + +#define bferror_pass(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_pass(bfcolor_error, "ERROR", nullptr, __VA_ARGS__); \ + } + +#define bfdebug_subpass(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_pass(bfcolor_debug, "DEBUG", " - ", __VA_ARGS__); \ + } + +#define bfalert_subpass(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_pass(bfcolor_alert, "ALERT", " - ", __VA_ARGS__); \ + } + +#define bferror_subpass(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_pass(bfcolor_error, "ERROR", " - ", __VA_ARGS__); \ + } + +/* ---------------------------------------------------------------------------*/ +/* Fail */ +/* ---------------------------------------------------------------------------*/ + +inline void +__bfdebug_fail_core( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, gsl::not_null msg) +{ + __bfdebug_core(msg); + __bfdebug_type(msg, color, type); + __bfdebug_jtfy(msg, 66, title, indent); + + *msg += bfcolor_red "fail <----" bfcolor_end; + *msg += '\n'; +} + +inline void +__bfdebug_fail( + cstr_t color, cstr_t type, cstr_t indent, cstr_t title, std::string *msg = nullptr) +{ + __bfdebug_add_line(msg, [&](std::string * ln) { + __bfdebug_fail_core(color, type, indent, title, ln); + }); +} + +#define bfdebug_fail(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_fail(bfcolor_debug, "DEBUG", nullptr, __VA_ARGS__); \ + } + +#define bfalert_fail(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_fail(bfcolor_alert, "ALERT", nullptr, __VA_ARGS__); \ + } + +#define bferror_fail(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_fail(bfcolor_error, "ERROR", nullptr, __VA_ARGS__); \ + } + +#define bfdebug_subfail(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_fail(bfcolor_debug, "DEBUG", " - ", __VA_ARGS__); \ + } + +#define bfalert_subfail(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_fail(bfcolor_alert, "ALERT", " - ", __VA_ARGS__); \ + } + +#define bferror_subfail(level, ...) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + __bfdebug_fail(bfcolor_error, "ERROR", " - ", __VA_ARGS__); \ + } + +/* ---------------------------------------------------------------------------*/ +/* Test */ +/* ---------------------------------------------------------------------------*/ + +#define bfdebug_test3(level,title,val) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bfdebug_pass(level,title); \ + } \ + else { \ + bfdebug_fail(level,title); \ + } \ + } + +#define bfdebug_subtest3(level,title,val) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bfdebug_subpass(level,title); \ + } \ + else { \ + bfdebug_subfail(level,title); \ + } \ + } + +#define bfalert_test3(level,title,val) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bfalert_pass(level,title); \ + } \ + else { \ + bfalert_fail(level,title); \ + } \ + } + +#define bfalert_subtest3(level,title,val) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bfalert_subpass(level,title); \ + } \ + else { \ + bfalert_subfail(level,title); \ + } \ + } + +#define bferror_test3(level,title,val) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bferror_pass(level,title); \ + } \ + else { \ + bferror_fail(level,title); \ + } \ + } + +#define bferror_subtest3(level,title,val) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bferror_subpass(level,title); \ + } \ + else { \ + bferror_subfail(level,title); \ + } \ + } + +#define bfdebug_test4(level,title,val,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bfdebug_pass(level,title,msg); \ + } \ + else { \ + bfdebug_fail(level,title,msg); \ + } \ + } + +#define bfdebug_subtest4(level,title,val,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bfdebug_subpass(level,title,msg); \ + } \ + else { \ + bfdebug_subfail(level,title,msg); \ + } \ + } + +#define bfalert_test4(level,title,val,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bfalert_pass(level,title,msg); \ + } \ + else { \ + bfalert_fail(level,title,msg); \ + } \ + } + +#define bfalert_subtest4(level,title,val,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bfalert_subpass(level,title,msg); \ + } \ + else { \ + bfalert_subfail(level,title,msg); \ + } \ + } + +#define bferror_test4(level,title,val,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bferror_pass(level,title,msg); \ + } \ + else { \ + bferror_fail(level,title,msg); \ + } \ + } + +#define bferror_subtest4(level,title,val,msg) \ + if (GSL_UNLIKELY(level <= DEBUG_LEVEL)) { \ + if ((val)) { \ + bferror_subpass(level,title,msg); \ + } \ + else { \ + bferror_subfail(level,title,msg); \ + } \ + } + +#define bfdebug_test(...) GET_MACRO(bfdebug_test, __VA_ARGS__) +#define bfdebug_subtest(...) GET_MACRO(bfdebug_subtest, __VA_ARGS__) +#define bfalert_test(...) GET_MACRO(bfalert_test, __VA_ARGS__) +#define bfalert_subtest(...) GET_MACRO(bfalert_subtest, __VA_ARGS__) +#define bferror_test(...) GET_MACRO(bferror_test, __VA_ARGS__) +#define bferror_subtest(...) GET_MACRO(bferror_subtest, __VA_ARGS__) + +/* ---------------------------------------------------------------------------*/ +/* Line / Field */ +/* ---------------------------------------------------------------------------*/ + +#define bfline bfdebug_ndec(0, "line", __LINE__); +#define __bffield1(a,b) bfdebug_ndec(0, "[" #b "] " #a, a); +#define __bffield2(a,b) __bffield1(a,b); +#define bffield(a) __bffield2(a,__LINE__) +#define __bffield_hex1(a,b) bfdebug_nhex(0, "[" #b "] " #a, a); +#define __bffield_hex2(a,b) __bffield_hex1(a,b); +#define bffield_hex(a) __bffield_hex2(a,__LINE__) + +#endif + +/* -------------------------------------------------------------------------- */ +/* C Debugging */ +/* -------------------------------------------------------------------------- */ + +#ifndef KERNEL +#ifdef __cplusplus +#include +#else +#include +#endif +#define BFDEBUG(...) printf("[BAREFLANK DEBUG]: " __VA_ARGS__) +#define BFALERT(...) printf("[BAREFLANK ALERT]: " __VA_ARGS__) +#define BFERROR(...) printf("[BAREFLANK ERROR]: " __VA_ARGS__) +#endif + +/* -------------------------------------------------------------------------- */ +/* Linux Debugging */ +/* -------------------------------------------------------------------------- */ + +#ifdef KERNEL +#ifdef __linux__ +#include +#define BFDEBUG(...) printk(KERN_INFO "[BAREFLANK DEBUG]: " __VA_ARGS__) +#define BFALERT(...) printk(KERN_INFO "[BAREFLANK ALERT]: " __VA_ARGS__) +#define BFERROR(...) printk(KERN_ALERT "[BAREFLANK ERROR]: " __VA_ARGS__) +#endif +#endif + +/* -------------------------------------------------------------------------- */ +/* Windows Debugging */ +/* -------------------------------------------------------------------------- */ + +#ifdef KERNEL +#ifdef _WIN32 +#include +#define BFDEBUG(...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[BAREFLANK DEBUG]: " __VA_ARGS__) +#define BFALERT(...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[BAREFLANK ALERT]: " __VA_ARGS__) +#define BFERROR(...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[BAREFLANK ERROR]: " __VA_ARGS__) +#endif +#endif + +/* -------------------------------------------------------------------------- */ +/* EFI Debugging */ +/* -------------------------------------------------------------------------- */ + +#ifdef KERNEL +#ifdef EFI +#include "efi.h" +#include "efilib.h" +#define BFDEBUG(...) Print(L"[BAREFLANK DEBUG]: " __VA_ARGS__) +#define BFALERT(...) Print(L"[BAREFLANK ALERT]: " __VA_ARGS__) +#define BFERROR(...) Print(L"[BAREFLANK ERROR]: " __VA_ARGS__) +#endif +#endif + + +/** @endcond */ + +#endif diff --git a/payloads/bareflank/include/bfdebugringinterface.h b/payloads/bareflank/include/bfdebugringinterface.h new file mode 100644 index 00000000000..6aedf3b8f58 --- /dev/null +++ b/payloads/bareflank/include/bfdebugringinterface.h @@ -0,0 +1,163 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfdebug.h + */ + +#ifndef BFDEBUGRINGINTERFACE_H +#define BFDEBUGRINGINTERFACE_H + +#include +#include +#include +#include + +#pragma pack(push, 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get Debug Ring Resource Typedef + * + * @expects none + * @ensures none + * + * This is used by the driver entry to as the function signature for + * getting it's internal debug ring + */ +typedef struct debug_ring_resources_t *(*get_drr_t)(uint64_t vcpuid); + +/** + * @struct debug_ring_resources_t + * + * Debug Ring Resources + * + * Each driver entry needs to allocate some memory for the debug ring, and + * then cast this structure over the allocated memory to access the bits used + * by the ring. + * + * Prior to providing this structure to the debug ring, the memory should be + * cleared, and the len of the buffer should be set to the total length of + * memory allocated minus the size of debug_ring_resources_t. + * + * @code + * + * int len = PAGE_SIZE * 100; + * struct debug_ring_resources_t *drr = valloc(len); + * + * memset(drr, 0, len); + * drr->len = len - sizeof(debug_ring_resources_t); + * + * + * + * int ret; + * char read_buf[len] + * + * ret = debug_ring_read(drr, read_buf, len); + * if(ret < 0) + * + * + * @endcode + * + * Note there are many different designs for cicular buffers, but all of the + * designs have to face the same problem. How to detect when the buffer is + * full vs when it is empty. This design uses two counters the grow + * forever. The current position in the buffer is then pos % len. If the + * counters are 64bit, it would take a life time for the counters to + * overflow. + * + * @var debug_ring_resources_t::epos + * the end position in the circular buffer + * @var debug_ring_resources_t::spos + * the start position in the circular buffer + * @var debug_ring_resources_t::tag1 + * used to identify the debug ring from a memory dump + * @var debug_ring_resources_t::buf + * the circular buffer that stores the debug strings. + * @var debug_ring_resources_t::tag2 + * used to identify the debug ring from a memory dump + */ +struct debug_ring_resources_t { + uint64_t epos; + uint64_t spos; + + uint64_t tag1; + char buf[DEBUG_RING_SIZE]; + uint64_t tag2; +}; + +/** + * Debug Ring Read + * + * Reads strings that have been written to the debug ring. Although you can + * provide any buffer size you want, it's advised to provide a buffer that + * is the same size as the buffer that was originally allocated. + * + * @expects none + * @ensures none + * + * @param drr the debug_ring_resource that was used to create the + * debug ring + * @param str the buffer to read the string into. should be the same size + * as drr in bytes + * @param len the length of the str buffer in bytes + * @return the number of bytes read from the debug ring, 0 + * on error + */ +static inline uint64_t +debug_ring_read(struct debug_ring_resources_t *drr, char *str, uint64_t len) +{ + uint64_t i; + uint64_t spos; + uint64_t count; + uint64_t content; + + if (drr == 0 || str == 0 || len == 0) { + return 0; + } + + if (drr->spos > drr->epos) { + return 0; + } + + spos = drr->spos % DEBUG_RING_SIZE; + content = drr->epos - drr->spos; + + for (i = 0, count = 0; i < content && i < len - 1; i++) { + if (drr->buf[spos] != '\0') { + str[count++] = drr->buf[spos]; + } + + spos = ((spos + 1) % DEBUG_RING_SIZE); + } + + str[i] = '\0'; + return count; +} + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#endif diff --git a/payloads/bareflank/include/bfdelegate.h b/payloads/bareflank/include/bfdelegate.h new file mode 100644 index 00000000000..7e661f82678 --- /dev/null +++ b/payloads/bareflank/include/bfdelegate.h @@ -0,0 +1,282 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULLAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfdelegate.h +/// + +#ifndef BFDELEGATE_H +#define BFDELEGATE_H + +#include + +// ----------------------------------------------------------------------------- +// Delegate Definition +// ----------------------------------------------------------------------------- + +template < + typename T, + typename = std::enable_if::value> + > +class delegate; + +// ----------------------------------------------------------------------------- +// Delegate Partial Specialization +// ----------------------------------------------------------------------------- + +/// Delegate +/// +/// This delegate class provides the ability to register a call back function +/// that originates from: +/// - A free function +/// - A member function +/// - A lambda function (including capture lists) +/// +/// It should be noted that this class attempts to provide the most effcient +/// implementation without the need for malloc / free, or inheritance, at +/// the expense of a very specific syntax requirement. +/// +template < + typename RET, + typename ...PARAMS + > +class delegate +{ + using stub_t = RET(*)(void *, PARAMS...); ///< Stub function type + +public: + + /// Default Constructor + /// + /// Creates a nullptr delegate. Note that attempts to execute a nullptr + /// delegate will result in a crash as we do not perform a check for + /// null + /// + delegate() noexcept = default; + + /// Default Destructor + /// + ~delegate() noexcept = default; + + /// Is Valid + /// + /// @return true if valid, false otherwise + /// + constexpr bool is_valid() const noexcept + { return m_stub != nullptr; } + + /// Is Valid + /// + /// @return true if valid, false otherwise + /// + constexpr explicit operator bool() const noexcept + { return is_valid(); } + + /// Create (Member Function Pointer) + /// + /// Example usage: + /// @code + /// test_class t; + /// auto d = delegate::create(&t); + /// std::cout << "d: " << d(1) << '\n'; + /// @endcode + /// + /// @param obj a pointer to the class who's member function will + /// be executed. + /// @return resulting delegate + /// + template < + typename T, + RET(T::*FUNC)(PARAMS...), + typename = std::enable_if::value> + > + constexpr static delegate create(T &obj) noexcept + { return delegate(std::addressof(obj), member_stub); } + + /// Create (Member Function Pointer Class Pointer) + /// + /// Example usage: + /// @code + /// test_class t; + /// auto d = delegate::create(&t); + /// std::cout << "d: " << d(1) << '\n'; + /// @endcode + /// + /// @param obj a pointer to the class who's member function will + /// be executed. + /// @return resulting delegate + /// + template < + typename T, + RET(T::*FUNC)(PARAMS...), + typename = std::enable_if::value> + > + constexpr static delegate create(T *obj) noexcept + { return delegate(obj, member_stub); } + + /// Create (Member Function Unique Pointer) + /// + /// Example usage: + /// @code + /// auto t = make_unique(); + /// auto d = delegate::create(t); + /// std::cout << "d: " << d(1) << '\n'; + /// @endcode + /// + /// @param obj a pointer to the class who's member function will + /// be executed. + /// @return resulting delegate + /// + template < + typename T, + RET(T::*FUNC)(PARAMS...), + typename = std::enable_if::value> + > + constexpr static delegate create(const std::unique_ptr &obj) noexcept + { return delegate(obj.get(), member_stub); } + + /// Create (Const Member Function Pointer) + /// + /// Example usage: + /// @code + /// test_class t; + /// auto d = delegate::create(&t); + /// std::cout << "d: " << d(1) << '\n'; + /// @endcode + /// + /// @note this function has to have _const appended to it's name because + /// MSVC doesn't understand the template overload and fails to + /// compile. + /// + /// @param obj a pointer to the class who's member function will + /// be executed. + /// @return resulting delegate + /// + template < + typename T, + RET(T::*FUNC)(PARAMS...) const, + typename = std::enable_if::value> + > + constexpr static delegate create_const(const T &obj) noexcept + { return delegate(const_cast(std::addressof(obj)), const_member_stub); } + + /// Create (Function Pointer) + /// + /// Example usage: + /// @code + /// auto d = delegate::create<&foo>(); + /// std::cout << "d: " << d(1) << '\n'; + /// @endcode + /// + /// @return resulting delegate + /// + template + constexpr static delegate create() noexcept + { return delegate(nullptr, function_stub); } + + /// Create (Lambda Pointer) + /// + /// Example usage: + /// @code + /// test_class t; + /// auto d = delegate::create([](int val) -> int { return val; }); + /// std::cout << "d: " << d(1) << '\n'; + /// @endcode + /// + /// @param ptr a pointer to the lambda function that will + /// be executed. + /// @return resulting delegate + /// + template + constexpr static delegate create(const LAMBDA &ptr) noexcept + { return delegate(reinterpret_cast(const_cast(std::addressof(ptr))), lambda_stub); } + + /// Operator () + /// + /// @param params the parameters to pass to the delegate function. + /// @return the result of executing the delegate function + /// + constexpr RET operator()(PARAMS... params) const + { return (*m_stub)(m_obj, std::forward(params)...); } + +private: + + /// @cond + + // Note: + // + // The only public constructor is the default constructor. To create a + // delegate, use the delegate::create function. + // + + constexpr explicit delegate(void *obj, stub_t stub) noexcept : + m_obj(obj), + m_stub(stub) + { } + + /// @endcond + +private: + + /// @cond + + template < + typename T, + RET(T::*FUNC)(PARAMS...), + typename = std::enable_if::value> + > + constexpr static RET member_stub(void *obj, PARAMS... params) + { return (static_cast(obj)->*FUNC)(std::forward(params)...); } + + template < + typename T, + RET(T::*FUNC)(PARAMS...) const, + typename = std::enable_if::value> + > + constexpr static RET const_member_stub(void *obj, PARAMS... params) + { return (static_cast(obj)->*FUNC)(std::forward(params)...); } + + template + constexpr static RET function_stub(void *, PARAMS... params) + { return (FUNC)(std::forward(params)...); } + + template + constexpr static RET lambda_stub(void *ptr, PARAMS... params) + { return (static_cast(ptr)->operator())(std::forward(params)...); } + + /// @endcond + +private: + + void *m_obj{nullptr}; ///< Object containing member function + stub_t m_stub{nullptr}; ///< Stub that executes the delegate function + +public: + + /// @cond + + delegate(const delegate &other) noexcept = default; + delegate &operator=(const delegate &other) noexcept = default; + + delegate(delegate &&other) noexcept = default; + delegate &operator=(delegate &&other) noexcept = default; + + /// @endcond +}; + +#endif diff --git a/payloads/bareflank/include/bfdriverinterface.h b/payloads/bareflank/include/bfdriverinterface.h new file mode 100644 index 00000000000..af07deb8ee7 --- /dev/null +++ b/payloads/bareflank/include/bfdriverinterface.h @@ -0,0 +1,116 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BFDRIVERINTERFACE_H +#define BFDRIVERINTERFACE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* -------------------------------------------------------------------------- */ +/* Common */ +/* -------------------------------------------------------------------------- */ + +#define VMM_UNLOADED 10 +#define VMM_LOADED 11 +#define VMM_RUNNING 12 +#define VMM_CORRUPT 100 + +#ifndef BAREFLANK_NAME +#define BAREFLANK_NAME "bareflank" +#endif + +#ifndef BAREFLANK_MAJOR +#define BAREFLANK_MAJOR 150 +#endif + +#ifndef BAREFLANK_DEVICETYPE +#define BAREFLANK_DEVICETYPE 0xF00D +#endif + +#define IOCTL_ADD_MODULE_LENGTH_CMD 0x801 +#define IOCTL_ADD_MODULE_CMD 0x802 +#define IOCTL_LOAD_VMM_CMD 0x803 +#define IOCTL_UNLOAD_VMM_CMD 0x804 +#define IOCTL_START_VMM_CMD 0x805 +#define IOCTL_STOP_VMM_CMD 0x806 +#define IOCTL_DUMP_VMM_CMD 0x807 +#define IOCTL_VMM_STATUS_CMD 0x808 +#define IOCTL_SET_VCPUID_CMD 0x80A + +/* -------------------------------------------------------------------------- */ +/* Linux Interfaces */ +/* -------------------------------------------------------------------------- */ + +#ifdef __linux__ + +#define IOCTL_ADD_MODULE_LENGTH _IOW(BAREFLANK_MAJOR, IOCTL_ADD_MODULE_LENGTH_CMD, uint64_t *) +#define IOCTL_ADD_MODULE _IOW(BAREFLANK_MAJOR, IOCTL_ADD_MODULE_CMD, char *) +#define IOCTL_LOAD_VMM _IO(BAREFLANK_MAJOR, IOCTL_LOAD_VMM_CMD) +#define IOCTL_UNLOAD_VMM _IO(BAREFLANK_MAJOR, IOCTL_UNLOAD_VMM_CMD) +#define IOCTL_START_VMM _IO(BAREFLANK_MAJOR, IOCTL_START_VMM_CMD) +#define IOCTL_STOP_VMM _IO(BAREFLANK_MAJOR, IOCTL_STOP_VMM_CMD) +#define IOCTL_DUMP_VMM _IOR(BAREFLANK_MAJOR, IOCTL_DUMP_VMM_CMD, struct debug_ring_resources_t *) +#define IOCTL_VMM_STATUS _IOR(BAREFLANK_MAJOR, IOCTL_VMM_STATUS_CMD, int64_t *) +#define IOCTL_SET_VCPUID _IOW(BAREFLANK_MAJOR, IOCTL_SET_VCPUID_CMD, uint64_t *) + +#endif + +/* -------------------------------------------------------------------------- */ +/* Windows Interfaces */ +/* -------------------------------------------------------------------------- */ + +#if defined(_WIN32) || defined(__CYGWIN__) + +#include + +DEFINE_GUID( + GUID_DEVINTERFACE_bareflank, + 0x1d9c9218, + 0x3c88, + 0x4b81, + 0x8e, + 0x81, + 0xb4, + 0x62, + 0x2a, + 0x4d, + 0xcb, + 0x44); + +#define IOCTL_ADD_MODULE CTL_CODE(BAREFLANK_DEVICETYPE, IOCTL_ADD_MODULE_CMD, METHOD_IN_DIRECT, FILE_WRITE_DATA) +#define IOCTL_LOAD_VMM CTL_CODE(BAREFLANK_DEVICETYPE, IOCTL_LOAD_VMM_CMD, METHOD_BUFFERED, 0) +#define IOCTL_UNLOAD_VMM CTL_CODE(BAREFLANK_DEVICETYPE, IOCTL_UNLOAD_VMM_CMD, METHOD_BUFFERED, 0) +#define IOCTL_START_VMM CTL_CODE(BAREFLANK_DEVICETYPE, IOCTL_START_VMM_CMD, METHOD_BUFFERED, 0) +#define IOCTL_STOP_VMM CTL_CODE(BAREFLANK_DEVICETYPE, IOCTL_STOP_VMM_CMD, METHOD_BUFFERED, 0) +#define IOCTL_DUMP_VMM CTL_CODE(BAREFLANK_DEVICETYPE, IOCTL_DUMP_VMM_CMD, METHOD_OUT_DIRECT, FILE_READ_DATA) +#define IOCTL_VMM_STATUS CTL_CODE(BAREFLANK_DEVICETYPE, IOCTL_VMM_STATUS_CMD, METHOD_BUFFERED, FILE_READ_DATA) +#define IOCTL_SET_VCPUID CTL_CODE(BAREFLANK_DEVICETYPE, IOCTL_SET_VCPUID_CMD, METHOD_IN_DIRECT, FILE_WRITE_DATA) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/payloads/bareflank/include/bfdwarf.h b/payloads/bareflank/include/bfdwarf.h new file mode 100644 index 00000000000..b13bc99b7bd --- /dev/null +++ b/payloads/bareflank/include/bfdwarf.h @@ -0,0 +1,96 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfdwarf.h + */ + +#ifndef BFDWARF_H +#define BFDWARF_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @struct dwarf_sections_t + * + * Struct to hold pointers to all the used DWARF sections + * + * @var dwarf_sections_t::debug_info_addr + * the virtual address of ".debug_info" after relocation + * @var dwarf_sections_t::debug_info_size + * the size of ".debug_info" + * @var dwarf_sections_t::debug_abbrev_addr + * the virtual address of ".debug_abbrev" after relocation + * @var dwarf_sections_t::debug_abbrev_size + * the size of ".debug_abbrev" + * @var dwarf_sections_t::debug_line_addr + * the virtual address of ".debug_line" after relocation + * @var dwarf_sections_t::debug_line_size + * the size of ".debug_line" + * @var dwarf_sections_t::debug_str_addr + * the virtual address of ".debug_str" after relocation + * @var dwarf_sections_t::debug_str_size + * the size of ".debug_str" + * @var dwarf_sections_t::debug_ranges_addr + * the virtual address of ".debug_ranges" after relocation + * @var dwarf_sections_t::debug_ranges_size + * the size of ".debug_ranges" + */ +struct dwarf_sections_t { + void *debug_info_addr; + uint64_t debug_info_size; + + void *debug_abbrev_addr; + uint64_t debug_abbrev_size; + + void *debug_line_addr; + uint64_t debug_line_size; + + void *debug_str_addr; + uint64_t debug_str_size; + + void *debug_ranges_addr; + uint64_t debug_ranges_size; +}; + +/** + * Get DWARF sections + * + * @expects none + * @ensures ret != nullptr + * + * Returns a list containing pointers to the found DWARF sections. These + * sections are used to map instruction pointers to function names in the + * unwinder. + * + * @return dwarf_sections_t pointer + */ +struct dwarf_sections_t * +get_dwarf_sections() noexcept; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/payloads/bareflank/include/bfehframelist.h b/payloads/bareflank/include/bfehframelist.h new file mode 100644 index 00000000000..5d9be204303 --- /dev/null +++ b/payloads/bareflank/include/bfehframelist.h @@ -0,0 +1,68 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfehframelist.h + */ + +#ifndef BFEHFRAMELIST_H +#define BFEHFRAMELIST_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @struct eh_frame_t + * + * Defines a ".eh_frame" section. + * + * @var eh_frame_t::addr + * the starting address of the the .eh_frame section + * @var eh_frame_t::size + * the size of the .eh_frame section + */ +struct eh_frame_t { + void *addr; + uint64_t size; +}; + +/** + * Get EH Framework List + * + * @expects none + * @ensures ret != nullptr + * + * Returns a list of ".eh_frame" sections, containing their start address, + * and size. This is used by the unwind library to find stack frames. The + * list should have one .eh_frame section for each module that is loaded. + * + * @return eh_frame list (of size MAX_NUM_MODULES) + */ +struct eh_frame_t * +get_eh_frame_list() noexcept; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/payloads/bareflank/include/bfelf_loader.h b/payloads/bareflank/include/bfelf_loader.h new file mode 100644 index 00000000000..7e0113fe540 --- /dev/null +++ b/payloads/bareflank/include/bfelf_loader.h @@ -0,0 +1,2531 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfelf_loader.h + */ + +#ifndef BFELF_LOADER_H +#define BFELF_LOADER_H + +#include +#include +#include +#include +#include +#include +#include + +#pragma pack(push, 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Defines */ +/* ---------------------------------------------------------------------------------------------- */ + +/* @cond */ + +#ifndef BFELF_MAX_NEEDED +#define BFELF_MAX_NEEDED (25) +#endif + +#ifndef BFELF_MAX_SEGMENTS +#define BFELF_MAX_SEGMENTS (4) +#endif + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Data Types */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * Data Representation + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 2 + */ + +/* @cond */ + +#ifndef __cplusplus +typedef uint64_t bfelf64_addr; +typedef uint64_t bfelf64_off; +typedef uint16_t bfelf64_half; +typedef uint32_t bfelf64_word; +typedef int32_t bfelf64_sword; +typedef uint64_t bfelf64_xword; +typedef int64_t bfelf64_sxword; +#else +using bfelf64_addr = uint64_t; +using bfelf64_off = uint64_t; +using bfelf64_half = uint16_t; +using bfelf64_word = uint32_t; +using bfelf64_sword = int32_t; +using bfelf64_xword = uint64_t; +using bfelf64_sxword = int64_t; +#endif + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Error Codes */ +/* ---------------------------------------------------------------------------------------------- */ + +/* @cond */ + +static inline int64_t +private_error(const char *header, const char *msg, const char *func, int line, int64_t code) +{ + BFALERT("%s [%d] %s: %s\n", func, line, header, msg); + return code; +} + +#define bfinvalid_argument(a) \ + private_error("invalid argument", a, __func__, __LINE__, BFELF_ERROR_INVALID_ARG); + +#define bfinvalid_file(a) \ + private_error("invalid file", a, __func__, __LINE__, BFELF_ERROR_INVALID_FILE); + +#define bfinvalid_index(a) \ + private_error("invalid index", a, __func__, __LINE__, BFELF_ERROR_INVALID_INDEX); + +#define bfinvalid_signature(a) \ + private_error("invalid signature", a, __func__, __LINE__, BFELF_ERROR_INVALID_SIGNATURE); + +#define bfunsupported_file(a) \ + private_error("unsupported elf file", a, __func__, __LINE__, BFELF_ERROR_UNSUPPORTED_FILE); + +#define bfloader_full(a) \ + private_error("loader full", a, __func__, __LINE__, BFELF_ERROR_LOADER_FULL); + +#define bfno_such_symbol(a) \ + private_error("no such symbol", a, __func__, __LINE__, BFELF_ERROR_NO_SUCH_SYMBOL); + +#define bfunsupported_rel(a) \ + private_error("unsupported relocation", a, __func__, __LINE__, BFELF_ERROR_UNSUPPORTED_RELA); + +#define bfout_of_memory(a) \ + private_error("out of memory", a, __func__, __LINE__, BFELF_ERROR_OUT_OF_MEMORY); + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Helpers */ +/* ---------------------------------------------------------------------------------------------- */ + +/* @cond */ + +static inline int64_t +private_strcmp(const char *s1, const char *s2) +{ + while ((*s1 != 0) && (*s1 == *s2)) { + s1++, s2++; + } + + return *s1 == *s2 ? BFELF_SUCCESS : BFELF_ERROR_MISMATCH; +} + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF File Definition */ +/* ---------------------------------------------------------------------------------------------- */ + +struct bfelf_dyn; +struct bfelf_sym; +struct bfelf_rela; +struct bfelf_shdr; +struct bfelf_phdr; +struct bfelf_ehdr; + +/** + * @struct bfelf_load_instr + * + * ELF Load Segment + * + * The load instructions that each segment provides is missing some helpful + * info. This structure provides the info that is needed, in a cleaned up + * format. + * + * Note that there are two different char * buffers that you need to know about + * when loading a segment. There is the char * for the ELF file, and the char * + * for the memory that the ELF file is being loaded into. The ELF file does + * not equal memory. The best example is the BSS section, which is empty in the + * ELF file. Also, the RE vs RW sections are usually aligned. To use this + * information use the following steps: + * - get the total size of memory + * - allocate RW memory for the total size + * - get the number of load instructions + * - loop through each load instruction and copy the file char * to the mem + * char * using the file/mem offset/size. + * - map memory using the virt_addr and mem_size + * + * @var bfelf_load_instr::perm + * defines the permissions (read/write/execute) for this segment + * @var bfelf_load_instr::mem_offset + * defines the segment offset in memory + * @var bfelf_load_instr::file_offset + * defines the segment offset in the ELF file + * @var bfelf_load_instr::memsz + * defines the segment size in memory + * @var bfelf_load_instr::filesz + * defines the segment size in the ELF file + * @var bfelf_load_instr::virt_addr + * defines the assumed virtual address of the segment if PIC == false + */ +struct bfelf_load_instr { + bfelf64_word perm; + bfelf64_off mem_offset; + bfelf64_off file_offset; + bfelf64_xword memsz; + bfelf64_xword filesz; + bfelf64_addr virt_addr; +}; + +/* + * ELF File + * + * The following is used by this API to store information about the ELF file + * being used. + * + * @cond + */ +struct bfelf_file_t { + uint64_t filesz; + const char *file; + + char *exec_addr; + char *exec_virt; + + bfelf64_off entry; + + bfelf64_xword num_load_instr; + struct bfelf_load_instr load_instr[BFELF_MAX_SEGMENTS]; + + bfelf64_xword num_loadable_segments; + const struct bfelf_phdr *loadable_segments[BFELF_MAX_SEGMENTS]; + + bfelf64_addr start_addr; + bfelf64_xword total_memsz; + + bfelf64_xword num_needed; + bfelf64_xword needed[BFELF_MAX_NEEDED]; + + const struct bfelf_ehdr *ehdr; + const struct bfelf_phdr *phdrtab; + const struct bfelf_shdr *shdrtab; + + bfelf64_addr dynoff; + + const char *strtab; + const char *strtab_offset; + const char *shstrtab; + + bfelf64_word nbucket; + bfelf64_word nchain; + const bfelf64_word *bucket; + const bfelf64_word *chain; + const bfelf64_word *hash; + + bfelf64_xword dynnum; + const struct bfelf_dyn *dyntab; + + bfelf64_xword symnum; + const struct bfelf_sym *symtab; + + bfelf64_xword relanum_dyn; + const struct bfelf_rela *relatab_dyn; + + bfelf64_xword relanum_plt; + const struct bfelf_rela *relatab_plt; + + bfelf64_addr init; + bfelf64_addr fini; + + bfelf64_addr init_array; + bfelf64_xword init_arraysz; + + bfelf64_addr fini_array; + bfelf64_xword fini_arraysz; + + bfelf64_addr eh_frame; + bfelf64_xword eh_framesz; + + bfelf64_xword flags_1; + bfelf64_xword stack_flags; + + bfelf64_addr relaro_vaddr; + bfelf64_xword relaro_memsz; + + bfelf64_word added; +}; + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF File Header */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * e_ident indexes + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 3 + * + * @cond + */ +#define bfei_mag0 bfscast(bfelf64_sword, 0) +#define bfei_mag1 bfscast(bfelf64_sword, 1) +#define bfei_mag2 bfscast(bfelf64_sword, 2) +#define bfei_mag3 bfscast(bfelf64_sword, 3) +#define bfei_class bfscast(bfelf64_sword, 4) +#define bfei_data bfscast(bfelf64_sword, 5) +#define bfei_version bfscast(bfelf64_sword, 6) +#define bfei_osabi bfscast(bfelf64_sword, 7) +#define bfei_abiversion bfscast(bfelf64_sword, 8) +#define bfei_pad bfscast(bfelf64_sword, 9) +#define bfei_nident bfscast(bfelf64_sword, 16) + +/* @endcond */ + +/* + * ELF Class Types + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 5 + * + * @cond + */ +#define bfelfclass32 bfscast(unsigned char, 1) +#define bfelfclass64 bfscast(unsigned char, 2) + +/* @endcond */ + +/* + * ELF Data Types + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 5 + * + * @cond + */ +#define bfelfdata2lsb bfscast(unsigned char, 1) +#define bfelfdata2msb bfscast(unsigned char, 2) + +/* @endcond */ + +/* + * ELF Version + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 4 + * + * @cond + */ +#define bfev_current bfscast(unsigned char, 1) + +/* @endcond */ + +/* + * ELF OS / ABI Types + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 5 + * + * @cond + */ +#define bfelfosabi_sysv bfscast(unsigned char, 0) +#define bfelfosabi_hpux bfscast(unsigned char, 1) +#define bfelfosabi_standalone bfscast(unsigned char, 255) + +/* @endcond */ + +/* + * ELF Types + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 5 + * + * @cond + */ +#define bfet_none bfscast(bfelf64_half, 0) +#define bfet_rel bfscast(bfelf64_half, 1) +#define bfet_exec bfscast(bfelf64_half, 2) +#define bfet_dyn bfscast(bfelf64_half, 3) +#define bfet_core bfscast(bfelf64_half, 4) +#define bfet_loos bfscast(bfelf64_half, 0xFE00) +#define bfet_hios bfscast(bfelf64_half, 0xFEFF) +#define bfet_loproc bfscast(bfelf64_half, 0xFF00) +#define bfet_hiproc bfscast(bfelf64_half, 0xFFFF) + +/* @endcond */ + +/* + * ELF Machine Codes + * + * The following is defined in the Linux kernel sources: + * linux/include/uapi/linux/elf-em.h + * + * @cond + */ +#define bfem_none bfscast(bfelf64_half, 0) +#define bfem_m32 bfscast(bfelf64_half, 1) +#define bfem_sparc bfscast(bfelf64_half, 2) +#define bfem_386 bfscast(bfelf64_half, 3) +#define bfem_68k bfscast(bfelf64_half, 4) +#define bfem_88k bfscast(bfelf64_half, 5) +#define bfem_486 bfscast(bfelf64_half, 6) +#define bfem_860 bfscast(bfelf64_half, 7) +#define bfem_mips bfscast(bfelf64_half, 8) +#define bfem_mips_rs3_le bfscast(bfelf64_half, 10) +#define bfem_mips_rs4_be bfscast(bfelf64_half, 11) +#define bfem_parisc bfscast(bfelf64_half, 15) +#define bfem_sparc32plus bfscast(bfelf64_half, 18) +#define bfem_ppc bfscast(bfelf64_half, 20) +#define bfem_ppc64 bfscast(bfelf64_half, 21) +#define bfem_spu bfscast(bfelf64_half, 23) +#define bfem_arm bfscast(bfelf64_half, 40) +#define bfem_sh bfscast(bfelf64_half, 42) +#define bfem_sparcv9 bfscast(bfelf64_half, 43) +#define bfem_h8_300 bfscast(bfelf64_half, 46) +#define bfem_ia_64 bfscast(bfelf64_half, 50) +#define bfem_x86_64 bfscast(bfelf64_half, 62) +#define bfem_s390 bfscast(bfelf64_half, 22) +#define bfem_cris bfscast(bfelf64_half, 76) +#define bfem_v850 bfscast(bfelf64_half, 87) +#define bfem_m32r bfscast(bfelf64_half, 88) +#define bfem_mn10300 bfscast(bfelf64_half, 89) +#define bfem_openrisc bfscast(bfelf64_half, 92) +#define bfem_blackfin bfscast(bfelf64_half, 106) +#define bfem_altera_nios2 bfscast(bfelf64_half, 113) +#define bfem_ti_c6000 bfscast(bfelf64_half, 140) +#define bfem_aarch64 bfscast(bfelf64_half, 183) +#define bfem_frv bfscast(bfelf64_half, 0x5441) +#define bfem_avr32 bfscast(bfelf64_half, 0x18AD) +#define bfem_alpha bfscast(bfelf64_half, 0x9026) +#define bfem_cygnus_v850 bfscast(bfelf64_half, 0x9080) +#define bfem_cygnus_m32r bfscast(bfelf64_half, 0x9041) +#define bfem_s390_old bfscast(bfelf64_half, 0xA390) +#define bfem_cygnus_mn10300 bfscast(bfelf64_half, 0xBEEF) + +/* @endcond */ + +/* + * ELF File Header + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 3 + * + * The file header is located at the beginning of the file, and is used to + * locate the other parts of the file. + * + * @cond + */ +struct bfelf_ehdr { + unsigned char e_ident[bfei_nident]; + bfelf64_half e_type; + bfelf64_half e_machine; + bfelf64_word e_version; + bfelf64_addr e_entry; + bfelf64_off e_phoff; + bfelf64_off e_shoff; + bfelf64_word e_flags; + bfelf64_half e_ehsize; + bfelf64_half e_phentsize; + bfelf64_half e_phnum; + bfelf64_half e_shentsize; + bfelf64_half e_shnum; + bfelf64_half e_shstrndx; +}; + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Section Header Table */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * ELF Section Type + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 7 + * + * @cond + */ +#define bfsht_null bfscast(bfelf64_word, 0) +#define bfsht_progbits bfscast(bfelf64_word, 1) +#define bfsht_symtab bfscast(bfelf64_word, 2) +#define bfsht_strtab bfscast(bfelf64_word, 3) +#define bfsht_rela bfscast(bfelf64_word, 4) +#define bfsht_hash bfscast(bfelf64_word, 5) +#define bfsht_dynamic bfscast(bfelf64_word, 6) +#define bfsht_note bfscast(bfelf64_word, 7) +#define bfsht_nobits bfscast(bfelf64_word, 8) +#define bfsht_rel bfscast(bfelf64_word, 9) +#define bfsht_shlib bfscast(bfelf64_word, 10) +#define bfsht_dynsym bfscast(bfelf64_word, 11) +#define bfsht_init_array bfscast(bfelf64_word, 14) +#define bfsht_fini_array bfscast(bfelf64_word, 15) +#define bfsht_loos bfscast(bfelf64_word, 0x60000000) +#define bfsht_hios bfscast(bfelf64_word, 0x6FFFFFFF) +#define bfsht_loproc bfscast(bfelf64_word, 0x70000000) +#define bfsht_x86_64_unwind bfscast(bfelf64_word, 0x70000001) +#define bfsht_hiproc bfscast(bfelf64_word, 0x7FFFFFFF) + +/* @endcond */ + +/* + * ELF Section Attributes + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 8 + * + * @cond + */ +#define bfshf_write bfscast(bfelf64_xword, 0x1) +#define bfshf_alloc bfscast(bfelf64_xword, 0x2) +#define bfshf_execinstr bfscast(bfelf64_xword, 0x4) +#define bfshf_maskos bfscast(bfelf64_xword, 0x0F000000) +#define bfshf_maskproc bfscast(bfelf64_xword, 0xF0000000) +#define bfshf_undocumneted bfscast(bfelf64_xword, 0x00000060) + +#define bfshf_a (bfshf_alloc) +#define bfshf_wa (bfshf_write | bfshf_alloc) +#define bfshf_ai (bfshf_alloc | bfshf_write | bfshf_undocumneted) + +/* @endcond */ + +/* + * ELF Section Header Entry + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 6 + * + * Sections contain all the information in an ELF file, except for the ELF + * header, program header table, and section header table. Sections are + * identified by an index into the section header table. + * + * @cond + */ +struct bfelf_shdr { + bfelf64_word sh_name; + bfelf64_word sh_type; + bfelf64_xword sh_flags; + bfelf64_addr sh_addr; + bfelf64_off sh_offset; + bfelf64_xword sh_size; + bfelf64_word sh_link; + bfelf64_word sh_info; + bfelf64_xword sh_addralign; + bfelf64_xword sh_entsize; +}; + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Dynamic Section */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * ELF Dynamic Table Entry Tags + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 14 + * + * @cond + */ +#define bfdt_null bfscast(bfelf64_xword, 0) +#define bfdt_needed bfscast(bfelf64_xword, 1) +#define bfdt_pltrelsz bfscast(bfelf64_xword, 2) +#define bfdt_pltgot bfscast(bfelf64_xword, 3) +#define bfdt_hash bfscast(bfelf64_xword, 4) +#define bfdt_strtab bfscast(bfelf64_xword, 5) +#define bfdt_symtab bfscast(bfelf64_xword, 6) +#define bfdt_rela bfscast(bfelf64_xword, 7) +#define bfdt_relasz bfscast(bfelf64_xword, 8) +#define bfdt_relaent bfscast(bfelf64_xword, 9) +#define bfdt_strsz bfscast(bfelf64_xword, 10) +#define bfdt_syment bfscast(bfelf64_xword, 11) +#define bfdt_init bfscast(bfelf64_xword, 12) +#define bfdt_fini bfscast(bfelf64_xword, 13) +#define bfdt_soname bfscast(bfelf64_xword, 14) +#define bfdt_rpath bfscast(bfelf64_xword, 15) +#define bfdt_symbolic bfscast(bfelf64_xword, 16) +#define bfdt_rel bfscast(bfelf64_xword, 17) +#define bfdt_relsz bfscast(bfelf64_xword, 18) +#define bfdt_relent bfscast(bfelf64_xword, 19) +#define bfdt_pltrel bfscast(bfelf64_xword, 20) +#define bfdt_debug bfscast(bfelf64_xword, 21) +#define bfdt_textrel bfscast(bfelf64_xword, 22) +#define bfdt_jmprel bfscast(bfelf64_xword, 23) +#define bfdt_bind_now bfscast(bfelf64_xword, 24) +#define bfdt_init_array bfscast(bfelf64_xword, 25) +#define bfdt_fini_array bfscast(bfelf64_xword, 26) +#define bfdt_init_arraysz bfscast(bfelf64_xword, 27) +#define bfdt_fini_arraysz bfscast(bfelf64_xword, 28) +#define bfdt_loos bfscast(bfelf64_xword, 0x60000000) +#define bfdt_relacount bfscast(bfelf64_xword, 0x6ffffff9) +#define bfdt_relcount bfscast(bfelf64_xword, 0x6ffffffa) +#define bfdt_flags_1 bfscast(bfelf64_xword, 0x6ffffffb) +#define bfdt_hios bfscast(bfelf64_xword, 0x6FFFFFFF) +#define bfdt_loproc bfscast(bfelf64_xword, 0x70000000) +#define bfdt_hiproc bfscast(bfelf64_xword, 0x7FFFFFFF) + +#define bfdf_1_now bfscast(bfelf64_xword, 0x00000001) +#define bfdf_1_global bfscast(bfelf64_xword, 0x00000002) +#define bfdf_1_group bfscast(bfelf64_xword, 0x00000004) +#define bfdf_1_nodelete bfscast(bfelf64_xword, 0x00000008) +#define bfdf_1_loadfltr bfscast(bfelf64_xword, 0x00000010) +#define bfdf_1_initfirst bfscast(bfelf64_xword, 0x00000020) +#define bfdf_1_noopen bfscast(bfelf64_xword, 0x00000040) +#define bfdf_1_origin bfscast(bfelf64_xword, 0x00000080) +#define bfdf_1_direct bfscast(bfelf64_xword, 0x00000100) +#define bfdf_1_trans bfscast(bfelf64_xword, 0x00000200) +#define bfdf_1_interpose bfscast(bfelf64_xword, 0x00000400) +#define bfdf_1_nodeflib bfscast(bfelf64_xword, 0x00000800) +#define bfdf_1_nodump bfscast(bfelf64_xword, 0x00001000) +#define bfdf_1_confalt bfscast(bfelf64_xword, 0x00002000) +#define bfdf_1_endfiltee bfscast(bfelf64_xword, 0x00004000) +#define bfdf_1_dispreldne bfscast(bfelf64_xword, 0x00008000) +#define bfdf_1_disprelpnd bfscast(bfelf64_xword, 0x00010000) +#define bfdf_1_nodirect bfscast(bfelf64_xword, 0x00020000) +#define bfdf_1_ignmuldef bfscast(bfelf64_xword, 0x00040000) +#define bfdf_1_noksyms bfscast(bfelf64_xword, 0x00080000) +#define bfdf_1_nohdr bfscast(bfelf64_xword, 0x00100000) +#define bfdf_1_edited bfscast(bfelf64_xword, 0x00200000) +#define bfdf_1_noreloc bfscast(bfelf64_xword, 0x00400000) +#define bfdf_1_symintpose bfscast(bfelf64_xword, 0x00800000) +#define bfdf_1_globaudit bfscast(bfelf64_xword, 0x01000000) +#define bfdf_1_singleton bfscast(bfelf64_xword, 0x02000000) +#define bfdf_1_pie bfscast(bfelf64_xword, 0x08000000) + +/* @endcond */ + +/* + * ELF Dynamic Table + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 14 + * + * NOTE: The spec actually uses a union, but the use of a union goes against + * the C++ Core Guidelines, and Windows seems to get really mad. There really + * is not need for a union since the type size if the same. For this reason, + * we simply use d_val and cast when needed. + * + * @cond + */ +struct bfelf_dyn { + bfelf64_sxword d_tag; + bfelf64_xword d_val; +}; + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Symbol Table */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * ELF Symbol Bindings + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 10 + * + * @cond + */ +#define bfstb_local bfscast(unsigned char, 0) +#define bfstb_global bfscast(unsigned char, 1) +#define bfstb_weak bfscast(unsigned char, 2) +#define bfstb_loos bfscast(unsigned char, 10) +#define bfstb_hios bfscast(unsigned char, 12) +#define bfstb_loproc bfscast(unsigned char, 13) +#define bfstb_hiproc bfscast(unsigned char, 15) + +/* @endcond */ + +/* + * ELF Symbol Types + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 10 + * + * @cond + */ +#define bfstt_notype bfscast(unsigned char, 0) +#define bfstt_object bfscast(unsigned char, 1) +#define bfstt_func bfscast(unsigned char, 2) +#define bfstt_section bfscast(unsigned char, 3) +#define bfstt_file bfscast(unsigned char, 4) +#define bfstt_loos bfscast(unsigned char, 10) +#define bfstt_hios bfscast(unsigned char, 12) +#define bfstt_loproc bfscast(unsigned char, 13) +#define bfstt_hiproc bfscast(unsigned char, 15) + +/* @endcond */ + +/* + * ELF Symbol Info Algorithms + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 11 + * + * @cond + */ +#define BFELF_SYM_BIND(x) ((x) >> 4) +#define BFELF_SYM_TYPE(x) ((x)&0xF) + +/* @endcond */ + +/* + * ELF Undefined Symbol Index + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 9 + * + * @cond + */ +#define STN_UNDEF 0 + +/* @endcond */ + +/* + * ELF Symbol + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 9 + * + * @cond + */ +struct bfelf_sym { + bfelf64_word st_name; + unsigned char st_info; + unsigned char st_other; + bfelf64_half st_shndx; + bfelf64_addr st_value; + bfelf64_xword st_size; +}; + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Relocations */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * ELF Relocation + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 11 + * + * @cond + */ +struct bfelf_rel { + bfelf64_addr r_offset; + bfelf64_xword r_info; +}; + +/* @endcond */ + +/* + * ELF Relocation Addend + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 11 + * + * @cond + */ +struct bfelf_rela { + bfelf64_addr r_offset; + bfelf64_xword r_info; + bfelf64_sxword r_addend; +}; + +/* @endcond */ + +/* + * ELF Relocation Info Algorithms + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 11 + * + * @cond + */ +#define BFELF_REL_SYM(i) ((i) >> 32) +#define BFELF_REL_TYPE(i) ((i)&0xFFFFFFFFL) + +/* @endcond */ + + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Program Header */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * ELF Section Attributes + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 12 + * + * @cond + */ +#define bfpt_null bfscast(bfelf64_word, 0) +#define bfpt_load bfscast(bfelf64_word, 1) +#define bfpt_dynamic bfscast(bfelf64_word, 2) +#define bfpt_interp bfscast(bfelf64_word, 3) +#define bfpt_note bfscast(bfelf64_word, 4) +#define bfpt_shlib bfscast(bfelf64_word, 5) +#define bfpt_phdr bfscast(bfelf64_word, 6) +#define bfpt_loos bfscast(bfelf64_word, 0x60000000) +#define bfpt_gnu_eh_frame bfscast(bfelf64_word, 0x6474e550) +#define bfpt_gnu_stack bfscast(bfelf64_word, 0x6474e551) +#define bfpt_gnu_relro bfscast(bfelf64_word, 0x6474e552) +#define bfpt_hios bfscast(bfelf64_word, 0x6FFFFFFF) +#define bfpt_loproc bfscast(bfelf64_word, 0x70000000) +#define bfpt_hiproc bfscast(bfelf64_word, 0x7FFFFFFF) + +/* @endcond */ + +/* + * ELF Section Attributes + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 13 + * + * @cond + */ +#define bfpf_x bfscast(bfelf64_xword, 0x1) +#define bfpf_w bfscast(bfelf64_xword, 0x2) +#define bfpf_r bfscast(bfelf64_xword, 0x4) +#define bfpf_maskos bfscast(bfelf64_xword, 0x00FF0000) +#define bfpf_maskproc bfscast(bfelf64_xword, 0xFF000000) + +/* @endcond */ + +/* + * ELF Program Header Entry + * + * The following is defined in the ELF 64bit file format specification: + * http://www.uclibc.org/docs/elf-64-gen.pdf, page 12 + * + * In executable and shared object files, sections are grouped into segments for + * loading. The program header table contains a list of entries describing + * each segment. This information is needed when using the ELF loader to + * load each segment into memory allocated by the user. For more information + * on how to do this, please see the unit tests. + * + * @cond + */ +struct bfelf_phdr { + bfelf64_word p_type; + bfelf64_word p_flags; + bfelf64_off p_offset; + bfelf64_addr p_vaddr; + bfelf64_addr p_paddr; + bfelf64_xword p_filesz; + bfelf64_xword p_memsz; + bfelf64_xword p_align; +}; + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Loader Definition */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * ELF Loader + * + * The following structure is used to create an ELF loader, which groups up + * all of the ELF files used by a single program, mainly needed for global + * symbol searching. + * + * @cond + */ +struct bfelf_loader_t { + bfelf64_word num; + bfelf64_word relocated; + struct bfelf_file_t *efs[MAX_NUM_MODULES]; +}; + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Symbol Table Implementation */ +/* ---------------------------------------------------------------------------------------------- */ + +/* @cond */ + +static inline unsigned long +private_hash(const char *name) +{ + unsigned long h = 0; + + while (*name != 0) { + char c = *name++; + unsigned long g; + unsigned char uc = bfscast(unsigned char, c); + + if (c >= 0) { + h = (h << 4) + uc; + } + else { + h = (h << 4) - uc; + } + + if ((g = (h & 0xf0000000)) != 0) { + h ^= g >> 24; + } + + h &= 0x0fffffff; + } + + return h; +} + +static inline int64_t +private_get_sym_by_hash( + struct bfelf_file_t *ef, const char *name, const struct bfelf_sym **sym) +{ + bfelf64_word i = 0; + unsigned long x = private_hash(name); + + i = ef->bucket[x % ef->nbucket]; + while (i > STN_UNDEF && i < ef->nchain) { + int64_t ret = 0; + const char *str = nullptr; + + *sym = &(ef->symtab[i]); + str = &(ef->strtab[(*sym)->st_name]); + + ret = private_strcmp(name, str); + if (ret == BFELF_ERROR_MISMATCH) { + i = ef->chain[i]; + continue; + } + + return BFELF_SUCCESS; + } + + return BFELF_ERROR_NO_SUCH_SYMBOL; +} + +static inline int64_t +private_get_sym_by_name( + struct bfelf_file_t *ef, const char *name, const struct bfelf_sym **sym) +{ + bfelf64_word i = 0; + + if (ef->hash != nullptr) { + return private_get_sym_by_hash(ef, name, sym); + } + + for (i = 0; i < ef->symnum; i++) { + int64_t ret = 0; + const char *str = nullptr; + + *sym = &(ef->symtab[i]); + str = &(ef->strtab[(*sym)->st_name]); + + ret = private_strcmp(name, str); + if (ret == BFELF_ERROR_MISMATCH) { + continue; + } + + return BFELF_SUCCESS; + } + + return BFELF_ERROR_NO_SUCH_SYMBOL; +} + +static inline int64_t +private_get_sym_global( + const struct bfelf_loader_t *loader, const char *name, + struct bfelf_file_t **ef_found, const struct bfelf_sym **sym) +{ + int64_t ret = 0; + bfelf64_word i = 0; + struct bfelf_file_t *ef_ignore = *ef_found; + const struct bfelf_sym *found_sym = nullptr; + + *sym = nullptr; + *ef_found = nullptr; + + for (i = 0; i < loader->num; i++) { + if (loader->efs[i] == ef_ignore) { + continue; + } + + ret = private_get_sym_by_name(loader->efs[i], name, &found_sym); + if (ret == BFELF_ERROR_NO_SUCH_SYMBOL) { + continue; + } + + if (found_sym->st_value == 0) { + continue; + } + + *sym = found_sym; + *ef_found = loader->efs[i]; + + if (BFELF_SYM_BIND(found_sym->st_info) == bfstb_weak) { + continue; + } + + return BFELF_SUCCESS; + } + + if (*sym != nullptr) { + return BFELF_SUCCESS; + } + + return bfno_such_symbol(name); +} + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Relocations Implementation */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * Forward declarations required by relocator + * + * @cond + */ + +static inline int64_t +private_get_sym_global( + const struct bfelf_loader_t *loader, const char *name, + struct bfelf_file_t **ef_found, const struct bfelf_sym **sym); + +/* @endcond */ + +/* + * Relocation definitions and relocators + * + * @cond + */ + +#if defined(BF_AARCH64) +# include +#elif defined(BF_X64) +# include +#else +# error "Unsupported architecture" +#endif + +/* @endcond */ + +/* @cond */ + +static inline int64_t +private_relocate_symbols(struct bfelf_loader_t *loader, struct bfelf_file_t *ef) +{ + int64_t ret = 0; + bfelf64_word i = 0; + + for (i = 0; i < ef->relanum_dyn; i++) { + const struct bfelf_rela *rela = &(ef->relatab_dyn[i]); + + ret = private_relocate_symbol(loader, ef, rela); + if (ret != BFELF_SUCCESS) { + return ret; + } + } + + for (i = 0; i < ef->relanum_plt; i++) { + const struct bfelf_rela *rela = &(ef->relatab_plt[i]); + + ret = private_relocate_symbol(loader, ef, rela); + if (ret != BFELF_SUCCESS) { + return ret; + } + } + + return BFELF_SUCCESS; +} + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF File Implementation */ +/* ---------------------------------------------------------------------------------------------- */ + +/* @cond */ + +static inline int64_t +private_check_signature(struct bfelf_file_t *ef) +{ + if (ef->ehdr->e_ident[bfei_mag0] != 0x7F) { + return bfinvalid_signature("magic #0 has unexpected value"); + } + + if (ef->ehdr->e_ident[bfei_mag1] != 'E') { + return bfinvalid_signature("magic #1 has unexpected value"); + } + + if (ef->ehdr->e_ident[bfei_mag2] != 'L') { + return bfinvalid_signature("magic #2 has unexpected value"); + } + + if (ef->ehdr->e_ident[bfei_mag3] != 'F') { + return bfinvalid_signature("magic #3 has unexpected value"); + } + + return BFELF_SUCCESS; +} + +static inline int64_t +private_check_support(struct bfelf_file_t *ef) +{ + if (ef->ehdr->e_ident[bfei_class] != bfelfclass64) { + return bfunsupported_file("file is not 64bit"); + } + + if (ef->ehdr->e_ident[bfei_data] != bfelfdata2lsb) { + return bfunsupported_file("file is not little endian"); + } + + if (ef->ehdr->e_ident[bfei_version] != bfev_current) { + return bfunsupported_file("unsupported version"); + } + + if (ef->ehdr->e_ident[bfei_osabi] != bfelfosabi_sysv) { + return bfunsupported_file("file does not use the system v abi"); + } + + if (ef->ehdr->e_ident[bfei_abiversion] != 0) { + return bfunsupported_file("unsupported abi version"); + } + + if (ef->ehdr->e_type != bfet_dyn && ef->ehdr->e_type != bfet_exec) { + return bfunsupported_file("file must be an executable or shared library"); + } + +#ifdef BF_AARCH64 + if (ef->ehdr->e_machine != bfem_aarch64) { + return bfunsupported_file("file must be compiled for aarch64"); + } +#endif + +#ifdef BF_X64 + if (ef->ehdr->e_machine != bfem_x86_64) { + return bfunsupported_file("file must be compiled for x86_64"); + } +#endif + + if (ef->ehdr->e_version != bfev_current) { + return bfunsupported_file("unsupported version"); + } + + if (ef->ehdr->e_flags != 0) { + return bfunsupported_file("unsupported flags"); + } + + return BFELF_SUCCESS; +} + +static inline void +private_process_segments(struct bfelf_file_t *ef) +{ + bfelf64_xword i = 0; + + for (i = 0; i < ef->ehdr->e_phnum; i++) { + const struct bfelf_phdr *phdr = &(ef->phdrtab[i]); + + switch (phdr->p_type) { + case bfpt_load: + + if (ef->num_loadable_segments < BFELF_MAX_SEGMENTS) { + ef->total_memsz = phdr->p_vaddr + phdr->p_memsz; + ef->loadable_segments[ef->num_loadable_segments++] = phdr; + } + + break; + + case bfpt_dynamic: + ef->dynoff = phdr->p_offset; + ef->dynnum = phdr->p_filesz / sizeof(struct bfelf_dyn); + break; + + case bfpt_gnu_stack: + ef->stack_flags = phdr->p_flags; + break; + + case bfpt_gnu_relro: + ef->relaro_vaddr = phdr->p_vaddr; + ef->relaro_memsz = phdr->p_memsz; + break; + } + } + + if (ef->num_loadable_segments > 0) { + ef->start_addr = ef->loadable_segments[0]->p_vaddr; + ef->total_memsz -= ef->start_addr; + } + + for (i = 0; i < ef->num_loadable_segments; i++) { + const struct bfelf_phdr *phdr = ef->loadable_segments[i]; + + ef->load_instr[i].perm = phdr->p_flags; + ef->load_instr[i].mem_offset = phdr->p_vaddr - ef->start_addr; + ef->load_instr[i].file_offset = phdr->p_offset; + ef->load_instr[i].memsz = phdr->p_memsz; + ef->load_instr[i].filesz = phdr->p_filesz; + ef->load_instr[i].virt_addr = phdr->p_vaddr; + + ef->num_load_instr++; + } +} + +static inline void +private_process_dynamic_section(struct bfelf_file_t *ef) +{ + bfelf64_xword i = 0; + + if (ef->dynnum == 0 || ef->dynoff == 0) { + return; + } + + ef->num_needed = 0; + ef->dyntab = bfrcast(const struct bfelf_dyn *, ef->file + ef->dynoff); + + for (i = 0; i < ef->dynnum; i++) { + const struct bfelf_dyn *dyn = &(ef->dyntab[i]); + + switch (dyn->d_tag) { + case bfdt_null: + return; + + case bfdt_needed: + + if (ef->num_needed < BFELF_MAX_NEEDED) { + ef->needed[ef->num_needed++] = dyn->d_val; + } + + break; + + case bfdt_pltrelsz: + ef->relanum_plt = dyn->d_val / sizeof(struct bfelf_rela); + break; + + case bfdt_hash: + ef->hash = bfrcast(bfelf64_word *, dyn->d_val); + break; + + case bfdt_strtab: + ef->strtab_offset = bfrcast(char *, dyn->d_val); + break; + + case bfdt_symtab: + ef->symtab = bfrcast(struct bfelf_sym *, dyn->d_val); + break; + + case bfdt_rela: + ef->relatab_dyn = bfrcast(struct bfelf_rela *, dyn->d_val); + break; + + case bfdt_relasz: + ef->relanum_dyn = dyn->d_val / sizeof(struct bfelf_rela); + break; + + case bfdt_init: + ef->init = dyn->d_val; + break; + + case bfdt_fini: + ef->fini = dyn->d_val; + break; + + case bfdt_jmprel: + ef->relatab_plt = bfrcast(struct bfelf_rela *, dyn->d_val); + break; + + case bfdt_init_array: + ef->init_array = dyn->d_val; + break; + + case bfdt_fini_array: + ef->fini_array = dyn->d_val; + break; + + case bfdt_init_arraysz: + ef->init_arraysz = dyn->d_val; + break; + + case bfdt_fini_arraysz: + ef->fini_arraysz = dyn->d_val; + break; + + case bfdt_flags_1: + ef->flags_1 = dyn->d_val; + break; + + default: + break; + } + } +} + +/* @endcond */ + +/** + * Initialize an ELF file + * + * This function initializes an ELF file structure given the file's contents + * in memory. The resulting structure will be used by all of the other + * functions. + * + * @expects file != nullptr + * @expects filesz != nullptr + * @expects ef != nullptr + * @ensures + * + * @param file a character buffer containing the contents of the ELF file to + * be loaded. + * @param filesz the size of the character buffer + * @param ef the ELF file structure to initialize. + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_file_init(const char *file, uint64_t filesz, struct bfelf_file_t *ef) +{ + int64_t ret = 0; + bfelf64_word i = 0; + + if (file == nullptr) { + return bfinvalid_argument("file == nullptr"); + } + + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + if (filesz < sizeof(struct bfelf_ehdr)) { + return bfinvalid_argument("filesz invalid"); + } + + ef->file = file; + ef->filesz = filesz; + + ef->ehdr = bfrcast(const struct bfelf_ehdr *, file); + ef->phdrtab = bfrcast(const struct bfelf_phdr *, file + ef->ehdr->e_phoff); + ef->shdrtab = bfrcast(const struct bfelf_shdr *, file + ef->ehdr->e_shoff); + + ret = private_check_signature(ef); + if (ret != BFELF_SUCCESS) { + return ret; + } + + ret = private_check_support(ef); + if (ret != BFELF_SUCCESS) { + return ret; + } + + private_process_segments(ef); + private_process_dynamic_section(ef); + + ef->entry = ef->ehdr->e_entry; + ef->shstrtab = bfrcast(const char *, file + ef->shdrtab[ef->ehdr->e_shstrndx].sh_offset); + + /* + * ld from binutils 2.27 only has rela.dyn, while ld.gold and ld.lld both + * have rela.dyn and rela.plt. ld from binutils 2.27 also uses + * .init_array / .fini_array instead of .ctors / .dtors, while ld.gold and + * ld.lld still use the old .ctors / .dtors, which do not seems to show + * up in the .dynamic section, so we need to manually search for them. + * Since you will likely only have one or the other, if we see the old + * .ctors / .dtors, we treat it like .init_array / .fini_array for now + * which keeps things simple. Also, ld from binutils 2.27 marks .eh_frame + * with bfsht_x86_64_unwind, while ld.gold and ld.lld both mark .eh_frame + * with bfsht_progbits, also requiring a manual string search. + * + * Note that the file provided in this function is assumed to be deleted + * after this function is called, and thus, we have to search for these + * sections now because the file will not be available later. + */ + + for (i = 0; i < ef->ehdr->e_shnum; i++) { + const struct bfelf_shdr *shdr = &(ef->shdrtab[i]); + const char *name = &ef->shstrtab[shdr->sh_name]; + + if (private_strcmp(name, ".eh_frame") == BFELF_SUCCESS) { + ef->eh_frame = shdr->sh_addr; + ef->eh_framesz = shdr->sh_size; + continue; + } + + if (private_strcmp(name, ".ctors") == BFELF_SUCCESS) { + ef->init_array = shdr->sh_addr; + ef->init_arraysz = shdr->sh_size; + continue; + } + + if (private_strcmp(name, ".dtors") == BFELF_SUCCESS) { + ef->fini_array = shdr->sh_addr; + ef->fini_arraysz = shdr->sh_size; + continue; + } + } + + /* + * The string table is located in both ELF file provided here, as well as + * in the exec provided to bfelf_loader_add. By the time bfelf_loader_add + * is called, we assume that the file provided to this function has been + * deleted, but up to this point, the user is free to use some of the + * functions (like bfelf_file_get_needed), and for these we need a valid + * string table, so we store the location of the string table relative + * to the provided file, and then overwrite this when the user adds the + * ELF file to the loader, in which case we reference the string table + * relative to the provided exec. + */ + ef->strtab = bfcadd(const char *, ef->strtab_offset, bfrcast(bfelf64_addr, file)); + + return BFELF_SUCCESS; +} + +/** + * Get number of load instructions + * + * Once an ELF file has been initialized, the next step is to load all of the + * program segments into memory, relocate them, and then execute the entry + * point. To assist this operation, this function returns the total number of + * load instructions. + * + * @expects ef != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file + * @return number of load instructions on success, negative on error + */ +static inline int64_t +bfelf_file_get_num_load_instrs(const struct bfelf_file_t *ef) +{ + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + return bfscast(int64_t, ef->num_load_instr); +} + +/** + * Get load instructions + * + * Once you know how many load instructions there are, you can use this + * function to get each instruction structure. + * + * @expects ef != nullptr + * @expects index < bfelf_file_get_num_load_instrs() + * @expects instr != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file + * @param index the index of the instructions to get + * @param instr where to store the load instructions + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_file_get_load_instr( + const struct bfelf_file_t *ef, uint64_t index, const struct bfelf_load_instr **instr) +{ + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + if (instr == nullptr) { + return bfinvalid_argument("phdr == nullptr"); + } + + if (index >= ef->num_load_instr) { + return bfinvalid_index("index >= number of load instructions"); + } + + *instr = &(ef->load_instr[index]); + return BFELF_SUCCESS; +} + +/** + * Get Info + * + * Once an ELF loader has had all of it's ELF files initialized and added, + * use the relocate ELF loader to setup the ELF files such that they can + * be executed. Once this is done, this function can be used to get the + * C runtime information for bootstrapping a binary / module. + * + * @expects ef != nullptr + * @expects info != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file to get the info structure for + * @param info the info structure to store the results. + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_file_get_section_info( + const struct bfelf_file_t *ef, struct section_info_t *info) +{ + bfelf64_word i = 0; + + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + if (info == nullptr) { + return bfinvalid_argument("info == nullptr"); + } + + if (ef->added == 0) { + return bfinvalid_argument("ef must be added to a loader first"); + } + + for (i = 0; i < sizeof(struct section_info_t); i++) { + bfrcast(char *, info)[i] = 0; + } + + if (ef->init != 0) { + info->init_addr = ef->init + ef->exec_virt; + } + + if (ef->fini != 0) { + info->fini_addr = ef->fini + ef->exec_virt; + } + + if (ef->init_array != 0) { + info->init_array_addr = ef->init_array + ef->exec_virt; + info->init_array_size = ef->init_arraysz; + } + + if (ef->fini_array != 0) { + info->fini_array_addr = ef->fini_array + ef->exec_virt; + info->fini_array_size = ef->fini_arraysz; + } + + if (ef->eh_frame != 0) { + info->eh_frame_addr = ef->eh_frame + ef->exec_virt; + info->eh_frame_size = ef->eh_framesz; + } + + return BFELF_SUCCESS; +} + +/** + * Get Entry Point + * + * Returns the entry point of the ELF file. + * + * @expects ef != nullptr + * @expects addr != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file to get the entry location from + * @param addr the resulting address of the entry point + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_file_get_entry(const struct bfelf_file_t *ef, void **addr) +{ + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + if (addr == nullptr) { + return bfinvalid_argument("addr == nullptr"); + } + + if (ef->added == 0) { + return bfinvalid_argument("ef must be added to a loader first"); + } + + *addr = bfrcast(void *, ef->entry + ef->exec_virt); + return BFELF_SUCCESS; +} + +/** + * Get Stack Permissions + * + * Returns the ELF file's stack permissions. + * + * @expects ef != nullptr + * @expects perm != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file to get the stack permission info from + * @param perm the resulting permissions + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_file_get_stack_perm(const struct bfelf_file_t *ef, bfelf64_xword *perm) +{ + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + if (perm == nullptr) { + return bfinvalid_argument("perm == nullptr"); + } + + *perm = ef->stack_flags; + return BFELF_SUCCESS; +} + +/** + * Get Relocation Read-Only Info + * + * Returns the ELF file's RELRO information for + * re-mapping previously writable memory to read-only + * + * @expects ef != nullptr + * @expects addr != nullptr + * @expects size != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file to get the relro info from + * @param addr the resulting address + * @param size the resulting size + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_file_get_relro( + const struct bfelf_file_t *ef, bfelf64_addr *addr, bfelf64_xword *size) +{ + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + if (addr == nullptr) { + return bfinvalid_argument("addr == nullptr"); + } + + if (size == nullptr) { + return bfinvalid_argument("size == nullptr"); + } + + if (ef->added == 0) { + return bfinvalid_argument("ef must be added to a loader first"); + } + + *addr = ef->relaro_vaddr + bfrcast(bfelf64_addr, ef->exec_virt); + *size = ef->relaro_memsz; + return BFELF_SUCCESS; +} + +/** + * Get Number of Needed Libraries + * + * Returns the number of DT_NEEDED entries in the ELF + * file + * + * @expects ef != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file to get the number of needed files from + * @return number of needed entries on success, negative on error + */ +static inline int64_t +bfelf_file_get_num_needed(const struct bfelf_file_t *ef) +{ + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + return bfscast(int64_t, ef->num_needed); +} + +/** + * Get Needed Library + * + * Returns the name of a shared library that is needed by this + * ELF file + * + * @expects ef != nullptr + * @expects index < bfelf_file_get_num_needed() + * @expects needed != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file to get the needed filename from + * @param index the shared library name to get + * @param needed the resulting needed library + * @return number of needed entries on success, negative on error + */ +static inline int64_t +bfelf_file_get_needed( + const struct bfelf_file_t *ef, uint64_t index, const char **needed) +{ + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + if (needed == nullptr) { + return bfinvalid_argument("needed == nullptr"); + } + + if (index >= ef->num_needed) { + return bfinvalid_index("index >= number of needed"); + } + + *needed = &(ef->strtab[ef->needed[index]]); + return BFELF_SUCCESS; +} + +/** + * Get Total Memory Size + * + * Returns the total number of bytes needed in memory for this ELF file + * when loading the ELF file + * + * @expects ef != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file to get the total size from + * @return number of needed entries on success, negative on error + */ +static inline int64_t +bfelf_file_get_total_size(const struct bfelf_file_t *ef) +{ + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + return bfscast(int64_t, ef->total_memsz); +} + +/** + * Get PIC/PIE + * + * Returns 1 if this ELF file was compiled using PIC / PIE, or + * 0 otherwise + * + * @expects ef != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param ef the ELF file to get the pic/pie info from + * @return 1 if compiled with PIC/PIE, 0 otherwise + */ +static inline int64_t +bfelf_file_get_pic_pie(const struct bfelf_file_t *ef) +{ + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + return ef->start_addr == 0 ? 1 : 0; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Loader Implementation */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Add ELF file to an ELF loader + * + * Once an ELF loader has been initialized, use this function to add an + * ELF file to the ELF loader + * + * @expects loader != nullptr + * @expects ef != nullptr + * @expects exec_addr != nullptr + * @expects exec_virt != nullptr + * @ensures + * + * @param loader the ELF loader + * @param ef the ELF file to add + * @param exec_addr the address in memory where this ELF file was loaded. + * @param exec_virt the address in memory where this ELF file will be run. + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_loader_add( + struct bfelf_loader_t *loader, struct bfelf_file_t *ef, char *exec_addr, char *exec_virt) +{ + bfelf64_addr start; + + if (loader == nullptr) { + return bfinvalid_argument("loader == nullptr"); + } + + if (ef == nullptr) { + return bfinvalid_argument("ef == nullptr"); + } + + if (exec_addr == nullptr) { + return bfinvalid_argument("exec_addr == nullptr"); + } + + if (loader->num >= MAX_NUM_MODULES) { + return bfloader_full("increase MAX_NUM_MODULES"); + } + + if (ef->added++ != 0) { + return bfinvalid_argument("ef already added"); + } + + ef->exec_addr = exec_addr; + + if (ef->start_addr == 0) { + ef->exec_virt = exec_virt; + } + + start = bfrcast(bfelf64_addr, ef->exec_addr - ef->start_addr); + + ef->hash = bfcadd(const bfelf64_word *, ef->hash, start); + ef->strtab = bfcadd(const char *, ef->strtab_offset, start); + ef->symtab = bfcadd(const struct bfelf_sym *, ef->symtab, start); + ef->relatab_dyn = bfcadd(const struct bfelf_rela *, ef->relatab_dyn, start); + ef->relatab_plt = bfcadd(const struct bfelf_rela *, ef->relatab_plt, start); + + ef->nbucket = ef->hash[0]; + ef->nchain = ef->hash[1]; + ef->bucket = &(ef->hash[2]); + ef->chain = &(ef->hash[2 + ef->nbucket]); + + /* + * Sadly, the only way to determine the total size of the dynamic symbol + * table is to assume that the dynamic string table is always after the + * dynamic symbol table. :( + */ + ef->symnum = (bfrcast(bfelf64_addr, ef->strtab) - bfrcast(bfelf64_addr, ef->symtab)) / + sizeof(struct bfelf_sym); + + loader->efs[loader->num++] = ef; + return BFELF_SUCCESS; +} + +/** + * Relocate ELF Loader + * + * Relocates all of the ELF files that have been added to the ELF loader. + * Once all of the ELF files have been relocated, it's safe to resolve + * symbols for execution. + * + * @expects loader != nullptr + * @ensures + * + * @param loader the ELF loader + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_loader_relocate(struct bfelf_loader_t *loader) +{ + bfelf64_word i = 0; + + if (loader == nullptr) { + return bfinvalid_argument("loader == nullptr"); + } + + if (loader->relocated == 1) { + return BFELF_SUCCESS; + } + + for (i = 0; i < loader->num; i++) { + int64_t ret = private_relocate_symbols(loader, loader->efs[i]); + if (ret != BFELF_SUCCESS) { + return ret; + } + } + + loader->relocated = 1; + return BFELF_SUCCESS; +} + +/** + * Resolve Symbol + * + * Once an ELF loader has had all of it's ELF files initialized and added, + * use the relocate ELF loader to setup the ELF files such that they can + * be executed. If the ELF file is relocated into memory that is accessible + * via the ELF loader, the resolve symbol function can be used to get the + * address of a specific symbol so that it can be executed. + * + * @expects loader != nullptr + * @expects loader != name + * @expects loader != addr + * @ensures + * + * @param loader the ELF loader + * @param name the name of the symbol to resolve + * @param addr the resulting address if the symbol is successfully resolved + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_loader_resolve_symbol( + const struct bfelf_loader_t *loader, const char *name, void **addr) +{ + int64_t ret = 0; + + struct bfelf_file_t *found_ef = nullptr; + const struct bfelf_sym *found_sym = nullptr; + + if (loader == nullptr) { + return bfinvalid_argument("loader == nullptr"); + } + + if (name == nullptr) { + return bfinvalid_argument("name == nullptr"); + } + + if (addr == nullptr) { + return bfinvalid_argument("addr == nullptr"); + } + + ret = private_get_sym_global(loader, name, &found_ef, &found_sym); + if (ret != BFELF_SUCCESS) { + return ret; + } + + *addr = found_ef->exec_virt + found_sym->st_value; + return BFELF_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Loading APIs */ +/* ---------------------------------------------------------------------------------------------- */ + +/* @cond */ + +struct bfelf_binary_t { + char *exec; + const char *file; + uint64_t exec_size; + uint64_t file_size; + struct bfelf_file_t ef; +}; + +static inline int64_t +private_load_binary(struct bfelf_binary_t *binary) +{ + int64_t i = 0; + int64_t ret = 0; + int64_t num_segments = 0; + + /* + * Note: + * + * This function expects that binary->file and binary->file_size have + * already been filled in before executing this function. It will + * allocate the exec, and then copy each program segment in the provided + * file into the exec + */ + + if (binary->ef.file == nullptr) { + ret = bfelf_file_init(binary->file, binary->file_size, &binary->ef); + if (ret != BF_SUCCESS) { + return ret; + } + } + + num_segments = bfelf_file_get_num_load_instrs(&binary->ef); + binary->exec_size = bfscast(uint64_t, bfelf_file_get_total_size(&binary->ef)); + + /* + * TODO: + * + * Currently we allocate RWE memory instead of W^E. This code is used in + * two different places, the hypervisor and guest applications. In both + * cases this memory is changed to W^E by either the hypervisor's memory + * manager, or by a set of hypercalls. The only time the memory is actually + * used as RWE is during the initialization of the hypervisor, and not it's + * normal operation. + * + * Since this has to be cross platform, most operating systems support some + * form of RWE so this is what we use today. The risk for attack is limited + * to the initialization of the hypervisor which in most cases will be + * performed by a root-of-trust, so the attack surface is low. Still, + * someday it would be nice to find an mprotect like function for all + * operating systems such that memory can be allocated RW, and changed + * to RE as needed. If this functionality is found, the code here will have + * to be changed to support this. + */ + + binary->exec = bfscast(char *, platform_alloc_rwe(binary->exec_size)); + if (binary->exec == nullptr) { + return bfout_of_memory("unable to allocate exec RWE memory"); + } + + platform_memset(binary->exec, 0, binary->exec_size); + + for (i = 0; i < num_segments; i++) { + const struct bfelf_load_instr *instr = nullptr; + + const char *src = nullptr; + char *dst = nullptr; + + ret = bfelf_file_get_load_instr(&binary->ef, bfscast(uint64_t, i), &instr); + bfignored(ret); + + if (instr != nullptr) { + dst = bfadd(char *, binary->exec, instr->mem_offset); + src = bfcadd(const char *, binary->file, instr->file_offset); + + platform_memcpy(dst, src, instr->filesz); + } + } + + return BF_SUCCESS; +} + +static inline int64_t +private_relocate_binaries( + struct bfelf_binary_t *binaries, uint64_t num_binaries, struct bfelf_loader_t *loader) +{ + uint64_t i = 0; + int64_t ret = 0; + + for (i = 0; i < num_binaries; i++) { + ret = bfelf_loader_add(loader, &binaries[i].ef, binaries[i].exec, binaries[i].exec); + bfignored(ret); + } + + ret = bfelf_loader_relocate(loader); + if (ret != BFELF_SUCCESS) { + return ret; + } + + return BF_SUCCESS; +} + +static inline int64_t +private_crt_info( + struct bfelf_binary_t *binaries, uint64_t num_binaries, struct crt_info_t *crt_info) +{ + uint64_t i = 0; + + for (i = 0; i < num_binaries; i++) { + + int64_t ret = 0; + struct section_info_t section_info; + + ret = bfelf_file_get_section_info(&binaries[i].ef, §ion_info); + bfignored(ret); + + crt_info->info[crt_info->info_num++] = section_info; + } + + return BF_SUCCESS; +} + +/* @endcond */ + +/** + * Load + * + * Takes an array of ELF binaries and loads them. The resulting output is an + * entry point that can be executed. The CRT info and the ELF loader are also + * provided as a result. + * + * @note This function gets the entry point of the last binary provided. + * For this reason, the main executable should ALWAYS be last in the list + * of ELF binaries provided + * + * @note It is assumed that file and file_size are already provided for each + * ELF binary. This function will loop through each binary, and use this + * information to actually load everything into ELF file specific + * structures. + * + * @expects binaries != null + * @expects num_binaries != 0 && num_binaries < MAX_NUM_MODULES + * @expects entry != null + * @expects crt_info != null + * @expects loader != null + * @ensures none + * + * @param binaries the list of ELF binaries to load + * @param num_binaries the number of binaries provided + * @param entry the resulting entry point + * @param crt_info the resulting CRT info + * @param loader the resulting ELF loader + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_load( + struct bfelf_binary_t *binaries, uint64_t num_binaries, void **entry, + struct crt_info_t *crt_info, struct bfelf_loader_t *loader) +{ + uint64_t i = 0; + int64_t ret = 0; + + if (binaries == nullptr) { + return bfinvalid_argument("binaries == nullptr"); + } + + if (num_binaries == 0 || num_binaries >= MAX_NUM_MODULES) { + return bfinvalid_argument("num_binaries == 0 || num_binaries >= MAX_NUM_MODULES"); + } + + if (entry == nullptr) { + return bfinvalid_argument("entry == nullptr"); + } + + if (crt_info == nullptr) { + return bfinvalid_argument("crt_info == nullptr"); + } + + if (loader == nullptr) { + return bfinvalid_argument("loader == nullptr"); + } + + for (i = 0; i < num_binaries; i++) { + ret = private_load_binary(&binaries[i]); + if (ret != BF_SUCCESS) { + return ret; + } + } + + ret = private_relocate_binaries(binaries, num_binaries, loader); + if (ret != BF_SUCCESS) { + return ret; + } + + ret = private_crt_info(binaries, num_binaries, crt_info); + bfignored(ret); + + ret = bfelf_file_get_entry(&binaries[num_binaries - 1].ef, entry); + bfignored(ret); + + return BF_SUCCESS; +} + +/** + * Set Args + * + * Tells the CRT info to use the standard main(arc, argv) function, and sets + * the values of these. This information will be passed to the resulting + * entry point + * + * @expects crt_info != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param crt_info the CRT info to fill where the args will be stored + * @param argc the total number of args + * @param argv the args + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_set_args(struct crt_info_t *crt_info, int argc, const char **argv) +{ + if (crt_info == nullptr) { + return bfinvalid_argument("crt_info == nullptr"); + } + + crt_info->argc = argc; + crt_info->argv = argv; + crt_info->arg_type = 0; + + return BF_SUCCESS; +} + +/** + * Set Integer Args + * + * There are two different types of main functions supported: the standard + * main(arc, argv) and then another form that uses 64bit integers in the + * form int64_t bfmain(int64_t, int64_t, int64_t, int64_t). This function tells + * the CRT info to use the integer version, and sets the values of these. + * This information will be passed to the resulting entry point + * + * @expects crt_info != nullptr + * @ensures returns BFELF_SUCCESS if params == valid + * + * @param crt_info the CRT info to fill where the args will be stored + * @param request the request id + * @param arg1 integer arg #1 + * @param arg2 integer arg #2 + * @param arg3 integer arg #3 + * @return BFELF_SUCCESS on success, negative on error + */ +static inline int64_t +bfelf_set_integer_args( + struct crt_info_t *crt_info, uintptr_t request, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) +{ + if (crt_info == nullptr) { + return bfinvalid_argument("crt_info == nullptr"); + } + + crt_info->request = request; + crt_info->arg1 = arg1; + crt_info->arg2 = arg2; + crt_info->arg3 = arg3; + crt_info->arg_type = 1; + + return BF_SUCCESS; +} + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +#include +#include +#include + +#include +#include +#include +#include + +/* @cond */ + +inline auto +private_read_binary( + gsl::not_null f, const std::string &filename, bfelf_binary_t &binary) +{ + auto buffer = f->read_binary(filename); + + binary.file = buffer.get(); + binary.file_size = buffer.size(); + + return buffer; +} + +inline auto +private_get_needed_list(const bfelf_file_t &ef) +{ + int64_t ret = 0; + std::vector list; + + for (auto i = 0LL; i < bfelf_file_get_num_needed(&ef); i++) { + const char *needed = nullptr; + + ret = bfelf_file_get_needed(&ef, static_cast(i), &needed); + bfignored(ret); + + list.emplace_back(needed); + } + + return list; +} + +/* @endcond */ + +/** + * Read Binary and Get Needed List + * + * This function takes a filename, and a list of paths to locate the + * provide file. If the ELF binary is located, the function then parses + * the ELF file and returns the list of binaries that are needed (i.e. + * have to be linked to this ELF binary to resolve needed symbols). If + * the binary cannot be located, an exception is thrown. + * + * @expects none + * @ensures none + * + * @param f the file object to read the located filename + * @param filename the name of the ELF binary to get the needed list from + * @param paths a list of paths to locate the ELF binary from + * @param buffer the buffer to read the ELF binary into + * @param binary the binary object + * @return list of needed binaries or throws + */ +inline auto +bfelf_read_binary_and_get_needed_list( + gsl::not_null f, const std::string &filename, + const std::vector &paths, bfn::buffer &buffer, bfelf_binary_t &binary) +{ + buffer = private_read_binary(f, filename, binary); + + auto ret = bfelf_file_init(buffer.data(), buffer.size(), &binary.ef); + if (ret != BFELF_SUCCESS) { + throw std::runtime_error("bfelf_file_init failed: " + std::to_string(ret)); + } + + auto list = f->find_files(private_get_needed_list(binary.ef), paths); + return list; +} + +/** + * Binaries Info + * + * Provides a C++ wrapper for all of the ELF structures that are needed to + * load an ELF binary. + */ +class binaries_info +{ +public: + + using index_type = std::size_t; ///< Index type + using info_type = crt_info_t; ///< CRT info type + using entry_type = void *; ///< Entry point address type + using loader_type = bfelf_loader_t; ///< ELF loader type + + /** + * Constructor + * + * Loads the file provided, and searches the needed list to identify + * any other files that are needed for symbol resolution. + * + * @expects none + * @ensures none + * + * @param f the file object to read the located filename + * @param filename the name of the ELF binary to load + * @param paths a list of paths to locate the ELF binary from + * @param load if true, loads the binaries + */ + binaries_info( + gsl::not_null f, const std::string &filename, const std::vector &paths, bool load = true) + { + bfn::buffer data; + bfelf_binary_t binary = {}; + + auto filenames = bfelf_read_binary_and_get_needed_list(f, filename, paths, data, binary); + + this->init_binaries(f, filenames); + this->push_binary(std::move(data), std::move(binary)); + + auto ___ = gsl::on_failure([&] { + this->unload_binaries(); + }); + + if (load) { + this->load_binaries(); + } + } + + /** + * Constructor + * + * Loads all of the files provided. This does not search the needed list + * and instead expects that the list of binaries provided is complete. + * + * @expects none + * @ensures none + * + * @param f the file object to read the located filename + * @param filenames the list of files to load + * @param load if true, loads the binaries + */ + binaries_info( + gsl::not_null f, const std::vector &filenames, bool load = true) + { + this->init_binaries(f, filenames); + + auto ___ = gsl::on_failure([&] { + this->unload_binaries(); + }); + + if (load) { + this->load_binaries(); + } + } + + /** + * Default Destructor + */ + ~binaries_info() + { this->unload_binaries(); } + + /** + * Set Args + * + * Sets the argc and argv for this binary. + * + * @expects none + * @ensures none + * + * @param argc the number of arguments to pass to this binary + * @param argv the arguments to pass to this binary + */ + void + set_args(int argc, const char **argv) + { + auto ret = bfelf_set_args(&m_info, argc, argv); + bfignored(ret); + } + + /** + * Get Main ELF Binary + * + * Returns the main ELF binary (i.e. does not return the shared libraries + * needed by the main binary) + * + * @expects none + * @ensures none + * + * @return main binary + */ + auto & + ef() + { return m_binaries.back().ef; } + + /** + * Get Specific ELF Binary + * + * Returns a specific ELF binary given an index + * + * @expects index is valid + * @ensures none + * + * @param index of the ELF binary to get + * @return main binary + */ + auto & + ef(index_type index) + { return m_binaries.at(index).ef; } + + /** + * Get A Specific Binary + * + * @expects none + * @ensures none + * + * @param index of the specific binary to get + * @return returns a specific binary + */ + auto & + at(index_type index) + { return m_binaries.at(index); } + + /** + * Get The First Binary + * + * @expects none + * @ensures none + * + * @return returns the first binary + */ + auto & + front() + { return m_binaries.front(); } + + /** + * Get The Last Binary + * + * @expects none + * @ensures none + * + * @return returns the last binary + */ + auto & + back() + { return m_binaries.back(); } + + /** + * Get Binaries + * + * @expects none + * @ensures none + * + * @return returns the Binaries + */ + auto & + binaries() + { return m_binaries; } + + /** + * Get CRT Info + * + * @expects none + * @ensures none + * + * @return returns CRT info + */ + const auto & + info() const + { return m_info; } + + /** + * Get Entry Point Address + * + * @expects none + * @ensures none + * + * @return returns entry point address + */ + auto + entry() const + { return m_entry; } + + /** + * Get ELF Loader + * + * @expects none + * @ensures none + * + * @return returns the ELF loader + */ + auto & + loader() + { return m_loader; } + +private: + + void + push_binary(bfn::buffer &&data, bfelf_binary_t &&binary) + { + m_datas.push_back(std::move(data)); + m_binaries.push_back(std::move(binary)); + } + + void + init_binaries(gsl::not_null f, const std::vector &filenames) + { + expects(!filenames.empty()); + + for (const auto &filename : filenames) { + bfelf_binary_t binary = {}; + this->push_binary(private_read_binary(f, filename, binary), std::move(binary)); + } + } + + void + load_binaries() + { + auto ret = bfelf_load(m_binaries.data(), m_binaries.size(), &m_entry, &m_info, &m_loader); + if (ret != BF_SUCCESS) { + throw std::runtime_error("bfelf_load failed: " + bfn::to_string(ret, 16)); + } + } + + void + unload_binaries() + { + for (const auto &binary : m_binaries) { + platform_free_rwe(binary.exec, binary.exec_size); + } + } + + info_type m_info{}; + entry_type m_entry{}; + loader_type m_loader{}; + + std::vector m_binaries; + std::vector m_datas; + +public: + + /** @cond */ + + binaries_info(binaries_info &&) noexcept = default; + binaries_info &operator=(binaries_info &&) noexcept = default; + + binaries_info(const binaries_info &) = delete; + binaries_info &operator=(const binaries_info &) = delete; + + /** @endcond */ +}; + +#endif + +#pragma pack(pop) +#endif diff --git a/payloads/bareflank/include/bfelf_loader_reloc_aarch64.h b/payloads/bareflank/include/bfelf_loader_reloc_aarch64.h new file mode 100644 index 00000000000..80155de61cb --- /dev/null +++ b/payloads/bareflank/include/bfelf_loader_reloc_aarch64.h @@ -0,0 +1,263 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2017 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfelf_loader_reloc_aarch64.h + */ + +/* + * AArch64 Relocations + * + * The following is defined in the "ELF for the ARM 64-bit architecture" + * specification: + * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf + * + * @cond + */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Miscellaneous relocations */ +/* ---------------------------------------------------------------------------------------------- */ +#define BFR_AARCH64_NONE bfscast(bfelf64_xword, 0) + +/* ---------------------------------------------------------------------------------------------- */ +/* Static data relocations */ +/* ---------------------------------------------------------------------------------------------- */ +/* Data relocations */ +#define BFR_AARCH64_ABS64 bfscast(bfelf64_xword, 257) +#define BFR_AARCH64_ABS32 bfscast(bfelf64_xword, 258) +#define BFR_AARCH64_ABS16 bfscast(bfelf64_xword, 259) +#define BFR_AARCH64_PREL64 bfscast(bfelf64_xword, 260) +#define BFR_AARCH64_PREL32 bfscast(bfelf64_xword, 261) +#define BFR_AARCH64_PREL16 bfscast(bfelf64_xword, 262) + +/* ---------------------------------------------------------------------------------------------- */ +/* Static AArch64 relocations */ +/* ---------------------------------------------------------------------------------------------- */ +/* Group relocations to create an unsigned data value or address inline */ +#define BFR_AARCH64_MOVW_UABS_G0 bfscast(bfelf64_xword, 263) +#define BFR_AARCH64_MOVW_UABS_G0_NC bfscast(bfelf64_xword, 264) +#define BFR_AARCH64_MOVW_UABS_G1 bfscast(bfelf64_xword, 265) +#define BFR_AARCH64_MOVW_UABS_G1_NC bfscast(bfelf64_xword, 266) +#define BFR_AARCH64_MOVW_UABS_G2 bfscast(bfelf64_xword, 267) +#define BFR_AARCH64_MOVW_UABS_G2_NC bfscast(bfelf64_xword, 268) +#define BFR_AARCH64_MOVW_UABS_G3 bfscast(bfelf64_xword, 269) + +/* Group relocations to create a signed data or offset value inline */ +#define BFR_AARCH64_MOVW_SABS_G0 bfscast(bfelf64_xword, 270) +#define BFR_AARCH64_MOVW_SABS_G1 bfscast(bfelf64_xword, 271) +#define BFR_AARCH64_MOVW_SABS_G2 bfscast(bfelf64_xword, 272) + +/* Relocations to generate PC-relative addresses */ +#define BFR_AARCH64_LD_PREL_LO19 bfscast(bfelf64_xword, 273) +#define BFR_AARCH64_ADR_PREL_LO21 bfscast(bfelf64_xword, 274) +#define BFR_AARCH64_ADR_PREL_PG_HI21 bfscast(bfelf64_xword, 275) +#define BFR_AARCH64_ADR_PREL_PG_HI21_NC bfscast(bfelf64_xword, 276) +#define BFR_AARCH64_ADD_ABS_LO12_NC bfscast(bfelf64_xword, 277) +#define BFR_AARCH64_LDST8_ABS_LO12_NC bfscast(bfelf64_xword, 278) +#define BFR_AARCH64_LDST16_ABS_LO12_NC bfscast(bfelf64_xword, 284) +#define BFR_AARCH64_LDST32_ABS_LO12_NC bfscast(bfelf64_xword, 285) +#define BFR_AARCH64_LDST64_ABS_LO12_NC bfscast(bfelf64_xword, 286) +#define BFR_AARCH64_LDST128_ABS_LO12_NC bfscast(bfelf64_xword, 299) + +/* Relocations for control-flow instructions */ +#define BFR_AARCH64_TSTBR14 bfscast(bfelf64_xword, 279) +#define BFR_AARCH64_CONDBR19 bfscast(bfelf64_xword, 280) +#define BFR_AARCH64_JUMP26 bfscast(bfelf64_xword, 282) +#define BFR_AARCH64_CALL26 bfscast(bfelf64_xword, 283) + +/* Group relocations to create a PC-relative offset inline */ +#define BFR_AARCH64_MOVW_PREL_G0 bfscast(bfelf64_xword, 287) +#define BFR_AARCH64_MOVW_PREL_G0_NC bfscast(bfelf64_xword, 288) +#define BFR_AARCH64_MOVW_PREL_G1 bfscast(bfelf64_xword, 289) +#define BFR_AARCH64_MOVW_PREL_G1_NC bfscast(bfelf64_xword, 290) +#define BFR_AARCH64_MOVW_PREL_G2 bfscast(bfelf64_xword, 291) +#define BFR_AARCH64_MOVW_PREL_G2_NC bfscast(bfelf64_xword, 292) +#define BFR_AARCH64_MOVW_PREL_G3 bfscast(bfelf64_xword, 293) + +/* Group relocations to create a GOT-relative offset inline */ +#define BFR_AARCH64_MOVW_GOTOFF_G0 bfscast(bfelf64_xword, 300) +#define BFR_AARCH64_MOVW_GOTOFF_G0_NC bfscast(bfelf64_xword, 301) +#define BFR_AARCH64_MOVW_GOTOFF_G1 bfscast(bfelf64_xword, 302) +#define BFR_AARCH64_MOVW_GOTOFF_G1_NC bfscast(bfelf64_xword, 303) +#define BFR_AARCH64_MOVW_GOTOFF_G2 bfscast(bfelf64_xword, 304) +#define BFR_AARCH64_MOVW_GOTOFF_G2_NC bfscast(bfelf64_xword, 305) +#define BFR_AARCH64_MOVW_GOTOFF_G3 bfscast(bfelf64_xword, 306) + +/* GOT-relative data relocations */ +#define BFR_AARCH64_GOTREL64 bfscast(bfelf64_xword, 307) +#define BFR_AARCH64_GOTREL32 bfscast(bfelf64_xword, 308) + +/* GOT-relative instruction relocations */ +#define BFR_AARCH64_GOT_LD_PREL19 bfscast(bfelf64_xword, 309) +#define BFR_AARCH64_LD64_GOTOFF_LO15 bfscast(bfelf64_xword, 310) +#define BFR_AARCH64_ADR_GOT_PAGE bfscast(bfelf64_xword, 311) +#define BFR_AARCH64_LD64_GOT_LO12_NC bfscast(bfelf64_xword, 312) +#define BFR_AARCH64_LD64_GOTPAGE_LO15 bfscast(bfelf64_xword, 313) + +/* ---------------------------------------------------------------------------------------------- */ +/* Relocations for thread-local storage */ +/* ---------------------------------------------------------------------------------------------- */ +/* General dynamic TLS relocations */ +#define BFR_AARCH64_TLSGD_ADR_PREL21 bfscast(bfelf64_xword, 512) +#define BFR_AARCH64_TLSGD_ADR_PAGE21 bfscast(bfelf64_xword, 513) +#define BFR_AARCH64_TLSGD_ADD_LO12_NC bfscast(bfelf64_xword, 514) +#define BFR_AARCH64_TLSGD_MOVW_G1 bfscast(bfelf64_xword, 515) +#define BFR_AARCH64_TLSGD_MOVW_G0_NC bfscast(bfelf64_xword, 516) + +/* Local dynamic TLS relocations */ +#define BFR_AARCH64_TLSLD_ADR_PREL21 bfscast(bfelf64_xword, 517) +#define BFR_AARCH64_TLSLD_ADR_PAGE21 bfscast(bfelf64_xword, 518) +#define BFR_AARCH64_TLSLD_ADD_LO12_NC bfscast(bfelf64_xword, 519) +#define BFR_AARCH64_TLSLD_MOVW_G1 bfscast(bfelf64_xword, 520) +#define BFR_AARCH64_TLSLD_MOVW_G0_NC bfscast(bfelf64_xword, 521) +#define BFR_AARCH64_TLSLD_LD_PREL19 bfscast(bfelf64_xword, 522) +#define BFR_AARCH64_TLSLD_MOVW_DTPREL_G2 bfscast(bfelf64_xword, 523) +#define BFR_AARCH64_TLSLD_MOVW_DTPREL_G1 bfscast(bfelf64_xword, 524) +#define BFR_AARCH64_TLSLD_MOVW_DTPREL_G1_NC bfscast(bfelf64_xword, 525) +#define BFR_AARCH64_TLSLD_MOVW_DTPREL_G0 bfscast(bfelf64_xword, 526) +#define BFR_AARCH64_TLSLD_MOVW_DTPREL_G0_NC bfscast(bfelf64_xword, 527) +#define BFR_AARCH64_TLSLD_ADD_DTPREL_HI12 bfscast(bfelf64_xword, 528) +#define BFR_AARCH64_TLSLD_ADD_DTPREL_LO12 bfscast(bfelf64_xword, 529) +#define BFR_AARCH64_TLSLD_ADD_DTPREL_LO12_NC bfscast(bfelf64_xword, 530) +#define BFR_AARCH64_TLSLD_LDST8_DTPREL_LO12 bfscast(bfelf64_xword, 531) +#define BFR_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC bfscast(bfelf64_xword, 532) +#define BFR_AARCH64_TLSLD_LDST16_DTPREL_LO12 bfscast(bfelf64_xword, 533) +#define BFR_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC bfscast(bfelf64_xword, 534) +#define BFR_AARCH64_TLSLD_LDST32_DTPREL_LO12 bfscast(bfelf64_xword, 535) +#define BFR_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC bfscast(bfelf64_xword, 536) +#define BFR_AARCH64_TLSLD_LDST64_DTPREL_LO12 bfscast(bfelf64_xword, 537) +#define BFR_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC bfscast(bfelf64_xword, 538) +#define BFR_AARCH64_TLSLD_LDST128_DTPREL_LO12 bfscast(bfelf64_xword, 572) +#define BFR_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC bfscast(bfelf64_xword, 573) + +/* Initial exec TLS relocations */ +#define BFR_AARCH64_TLSIE_MOVW_GOTTPREP_G1 bfscast(bfelf64_xword, 539) +#define BFR_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC bfscast(bfelf64_xword, 540) +#define BFR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 bfscast(bfelf64_xword, 541) +#define BFR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC bfscast(bfelf64_xword, 542) +#define BFR_AARCH64_TLSIE_LD_GOTTPREL_PREL19 bfscast(bfelf64_xword, 543) + +/* Local exec TLS relocations */ +#define BFR_AARCH64_TLSLE_MOVW_TPREL_G2 bfscast(bfelf64_xword, 544) +#define BFR_AARCH64_TLSLE_MOVW_TPREL_G1 bfscast(bfelf64_xword, 545) +#define BFR_AARCH64_TLSLE_MOVW_TPREL_G1_NC bfscast(bfelf64_xword, 546) +#define BFR_AARCH64_TLSLE_MOVW_TPREL_G0 bfscast(bfelf64_xword, 547) +#define BFR_AARCH64_TLSLE_MOVW_TPREL_G0_NC bfscast(bfelf64_xword, 548) +#define BFR_AARCH64_TLSLE_ADD_TPREL_HI12 bfscast(bfelf64_xword, 549) +#define BFR_AARCH64_TLSLE_ADD_TPREL_LO12 bfscast(bfelf64_xword, 550) +#define BFR_AARCH64_TLSLE_ADD_TPREL_LO12_NC bfscast(bfelf64_xword, 551) +#define BFR_AARCH64_TLSLE_LDST8_TPREL_LO12 bfscast(bfelf64_xword, 552) +#define BFR_AARCH64_TLSLE_LDST8_TPREL_LO12_NC bfscast(bfelf64_xword, 553) +#define BFR_AARCH64_TLSLE_LDST16_TPREL_LO12 bfscast(bfelf64_xword, 554) +#define BFR_AARCH64_TLSLE_LDST16_TPREL_LO12_NC bfscast(bfelf64_xword, 555) +#define BFR_AARCH64_TLSLE_LDST32_TPREL_LO12 bfscast(bfelf64_xword, 556) +#define BFR_AARCH64_TLSLE_LDST32_TPREL_LO12_NC bfscast(bfelf64_xword, 557) +#define BFR_AARCH64_TLSLE_LDST64_TPREL_LO12 bfscast(bfelf64_xword, 558) +#define BFR_AARCH64_TLSLE_LDST64_TPREL_LO12_NC bfscast(bfelf64_xword, 559) +#define BFR_AARCH64_TLSLE_LDST128_TPREL_LO12 bfscast(bfelf64_xword, 570) +#define BFR_AARCH64_TLSLE_LDST128_TPREL_LO12_NC bfscast(bfelf64_xword, 571) + +/* TLS descriptor relocations */ +#define BFR_AARCH64_TLSDESC_LD_PREL19 bfscast(bfelf64_xword, 560) +#define BFR_AARCH64_TLSDESC_ADR_PREL21 bfscast(bfelf64_xword, 561) +#define BFR_AARCH64_TLSDESC_ADR_PAGE21 bfscast(bfelf64_xword, 562) +#define BFR_AARCH64_TLSDESC_LD64_LO12 bfscast(bfelf64_xword, 563) +#define BFR_AARCH64_TLSDESC_ADD_LO12 bfscast(bfelf64_xword, 564) +#define BFR_AARCH64_TLSDESC_OFF_G1 bfscast(bfelf64_xword, 656) +#define BFR_AARCH64_TLSDESC_OFF_G0_NC bfscast(bfelf64_xword, 566) +#define BFR_AARCH64_TLSDESC_LDR bfscast(bfelf64_xword, 567) +#define BFR_AARCH64_TLSDESC_ADD bfscast(bfelf64_xword, 568) +#define BFR_AARCH64_TLSDESC_CALL bfscast(bfelf64_xword, 569) + +/* ---------------------------------------------------------------------------------------------- */ +/* Dynamic relocations */ +/* ---------------------------------------------------------------------------------------------- */ +#define BFR_AARCH64_COPY bfscast(bfelf64_xword, 1024) +#define BFR_AARCH64_GLOB_DAT bfscast(bfelf64_xword, 1025) +#define BFR_AARCH64_JUMP_SLOT bfscast(bfelf64_xword, 1026) +#define BFR_AARCH64_RELATIVE bfscast(bfelf64_xword, 1027) +#define BFR_AARCH64_TLS_DTPREL64 bfscast(bfelf64_xword, 1028) +#define BFR_AARCH64_TLS_DTPMOD64 bfscast(bfelf64_xword, 1029) +#define BFR_AARCH64_TLS_TPREL64 bfscast(bfelf64_xword, 1030) +#define BFR_AARCH64_TLSDESC bfscast(bfelf64_xword, 1031) +#define BFR_AARCH64_IRELATIVE bfscast(bfelf64_xword, 1032) + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Relocations Implementation */ +/* ---------------------------------------------------------------------------------------------- */ + +/* @cond */ + +static inline int64_t +private_relocate_symbol( + struct bfelf_loader_t *loader, struct bfelf_file_t *ef, const struct bfelf_rela *rela) +{ + const char *str = nullptr; + const struct bfelf_sym *found_sym = nullptr; + struct bfelf_file_t *found_ef = ef; + bfelf64_addr *ptr = bfrcast(bfelf64_addr *, ef->exec_addr + rela->r_offset - ef->start_addr); + + if (BFELF_REL_TYPE(rela->r_info) == BFR_AARCH64_RELATIVE) { + *ptr = bfrcast(bfelf64_addr, ef->exec_virt + rela->r_addend); + return BFELF_SUCCESS; + } + + found_sym = &(ef->symtab[BFELF_REL_SYM(rela->r_info)]); + + if (BFELF_SYM_BIND(found_sym->st_info) == bfstb_weak) { + found_ef = nullptr; + } + + if (found_sym->st_value == 0 || found_ef == nullptr) { + int64_t ret; + + str = &(ef->strtab[found_sym->st_name]); + ret = private_get_sym_global(loader, str, &found_ef, &found_sym); + + if (ret != BFELF_SUCCESS) { + return ret; + } + } + + switch (BFELF_REL_TYPE(rela->r_info)) { + case BFR_AARCH64_GLOB_DAT: + case BFR_AARCH64_JUMP_SLOT: + case BFR_AARCH64_ABS64: + *ptr = bfrcast(bfelf64_addr, found_ef->exec_virt + found_sym->st_value); + break; + + case BFR_AARCH64_ABS32: + *(uint32_t *) ptr = bfrcast(uint32_t, found_ef->exec_virt + found_sym->st_value); + break; + + case BFR_AARCH64_ABS16: + *(uint16_t *) ptr = bfrcast(uint16_t, found_ef->exec_virt + found_sym->st_value); + break; + + default: + return bfunsupported_rel(str); + } + + return BFELF_SUCCESS; +} + +/* @endcond */ diff --git a/payloads/bareflank/include/bfelf_loader_reloc_x64.h b/payloads/bareflank/include/bfelf_loader_reloc_x64.h new file mode 100644 index 00000000000..5127762ff76 --- /dev/null +++ b/payloads/bareflank/include/bfelf_loader_reloc_x64.h @@ -0,0 +1,93 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2017 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfelf_loader_reloc_x64.h + */ + +/* + * System V ABI 64bit Relocations + * + * The following is defined in the ELF 64bit file format specification: + * http://www.x86-64.org/documentation/abi.pdf, page 71 + * + * @cond + */ +#define BFR_X86_64_64 bfscast(bfelf64_xword, 1) +#define BFR_X86_64_GLOB_DAT bfscast(bfelf64_xword, 6) +#define BFR_X86_64_JUMP_SLOT bfscast(bfelf64_xword, 7) +#define BFR_X86_64_RELATIVE bfscast(bfelf64_xword, 8) + +/* @endcond */ + +/* ---------------------------------------------------------------------------------------------- */ +/* ELF Relocations Implementation */ +/* ---------------------------------------------------------------------------------------------- */ + +/* @cond */ + +static inline int64_t +private_relocate_symbol( + struct bfelf_loader_t *loader, struct bfelf_file_t *ef, const struct bfelf_rela *rela) +{ + const char *str = nullptr; + const struct bfelf_sym *found_sym = nullptr; + struct bfelf_file_t *found_ef = ef; + bfelf64_addr *ptr = bfrcast(bfelf64_addr *, ef->exec_addr + rela->r_offset - ef->start_addr); + + if (BFELF_REL_TYPE(rela->r_info) == BFR_X86_64_RELATIVE) { + *ptr = bfrcast(bfelf64_addr, ef->exec_virt + rela->r_addend); + return BFELF_SUCCESS; + } + + found_sym = &(ef->symtab[BFELF_REL_SYM(rela->r_info)]); + + if (BFELF_SYM_BIND(found_sym->st_info) == bfstb_weak) { + found_ef = nullptr; + } + + if (found_sym->st_value == 0 || found_ef == nullptr) { + int64_t ret = 0; + str = &(ef->strtab[found_sym->st_name]); + + ret = private_get_sym_global(loader, str, &found_ef, &found_sym); + if (ret != BFELF_SUCCESS) { + return ret; + } + } + + *ptr = bfrcast(bfelf64_addr, found_ef->exec_virt + found_sym->st_value); + + switch (BFELF_REL_TYPE(rela->r_info)) { + case BFR_X86_64_64: + *ptr += bfscast(bfelf64_addr, rela->r_addend); + break; + + case BFR_X86_64_GLOB_DAT: + case BFR_X86_64_JUMP_SLOT: + break; + + default: + return bfunsupported_rel(str); + } + + return BFELF_SUCCESS; +} + +/* @endcond */ diff --git a/payloads/bareflank/include/bferrorcodes.h b/payloads/bareflank/include/bferrorcodes.h new file mode 100644 index 00000000000..647a13a1d6b --- /dev/null +++ b/payloads/bareflank/include/bferrorcodes.h @@ -0,0 +1,174 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BFERROR_CODES_H +#define BFERROR_CODES_H + +#include + +/* -------------------------------------------------------------------------- */ +/* Success */ +/* -------------------------------------------------------------------------- */ + +#define SUCCESS 0 + +/* -------------------------------------------------------------------------- */ +/* Entry Error Codes */ +/* -------------------------------------------------------------------------- */ + +#define ENTRY_SUCCESS bfscast(int64_t, SUCCESS) +#define ENTRY_ERROR_STACK_OVERFLOW bfscast(int64_t, 0x8000000000000010) +#define ENTRY_ERROR_VMM_INIT_FAILED bfscast(int64_t, 0x8000000000000020) +#define ENTRY_ERROR_VMM_START_FAILED bfscast(int64_t, 0x8000000000000030) +#define ENTRY_ERROR_VMM_STOP_FAILED bfscast(int64_t, 0x8000000000000040) +#define ENTRY_ERROR_UNKNOWN bfscast(int64_t, 0x8000000000000050) + +/* -------------------------------------------------------------------------- */ +/* C Runtime Error Codes */ +/* -------------------------------------------------------------------------- */ + +#define CRT_SUCCESS bfscast(int64_t, SUCCESS) +#define CRT_FAILURE bfscast(int64_t, 0x8000000000000100) + +/* -------------------------------------------------------------------------- */ +/* Unwinder Error Codes */ +/* -------------------------------------------------------------------------- */ + +#define REGISTER_EH_FRAME_SUCCESS bfscast(int64_t, SUCCESS) +#define REGISTER_EH_FRAME_FAILURE bfscast(int64_t, 0x8000000000001000) + +/* -------------------------------------------------------------------------- */ +/* Debug Ring Error Codes */ +/* -------------------------------------------------------------------------- */ + +#define GET_DRR_SUCCESS bfscast(int64_t, SUCCESS) +#define GET_DRR_FAILURE bfscast(int64_t, 0x8000000000010000) + +/* -------------------------------------------------------------------------- */ +/* ELF Loader Error Codes */ +/* -------------------------------------------------------------------------- */ + +#define BFELF_SUCCESS bfscast(int64_t, SUCCESS) +#define BFELF_ERROR_INVALID_ARG bfscast(int64_t, 0x8000000000100000) +#define BFELF_ERROR_INVALID_FILE bfscast(int64_t, 0x8000000000200000) +#define BFELF_ERROR_INVALID_INDEX bfscast(int64_t, 0x8000000000300000) +#define BFELF_ERROR_INVALID_SIGNATURE bfscast(int64_t, 0x8000000000500000) +#define BFELF_ERROR_UNSUPPORTED_FILE bfscast(int64_t, 0x8000000000600000) +#define BFELF_ERROR_INVALID_SEGMENT bfscast(int64_t, 0x8000000000700000) +#define BFELF_ERROR_INVALID_SECTION bfscast(int64_t, 0x8000000000800000) +#define BFELF_ERROR_LOADER_FULL bfscast(int64_t, 0x8000000000900000) +#define BFELF_ERROR_NO_SUCH_SYMBOL bfscast(int64_t, 0x8000000000A00000) +#define BFELF_ERROR_MISMATCH bfscast(int64_t, 0x8000000000B00000) +#define BFELF_ERROR_UNSUPPORTED_RELA bfscast(int64_t, 0x8000000000C00000) +#define BFELF_ERROR_OUT_OF_ORDER bfscast(int64_t, 0x8000000000D00000) +#define BFELF_ERROR_OUT_OF_MEMORY bfscast(int64_t, 0x8000000000E00000) + +/* -------------------------------------------------------------------------- */ +/* Memory Manager Error Codes */ +/* -------------------------------------------------------------------------- */ + +#define MEMORY_MANAGER_SUCCESS bfscast(int64_t, SUCCESS) +#define MEMORY_MANAGER_FAILURE bfscast(int64_t, 0x8000000001000000) + +/* -------------------------------------------------------------------------- */ +/* Common Error Codes */ +/* -------------------------------------------------------------------------- */ + +#define BF_SUCCESS bfscast(int64_t, SUCCESS) +#define BF_ERROR_INVALID_ARG bfscast(int64_t, 0x8000000010000000) +#define BF_ERROR_INVALID_INDEX bfscast(int64_t, 0x8000000020000000) +#define BF_ERROR_NO_MODULES_ADDED bfscast(int64_t, 0x8000000030000000) +#define BF_ERROR_MAX_MODULES_REACHED bfscast(int64_t, 0x8000000040000000) +#define BF_ERROR_VMM_INVALID_STATE bfscast(int64_t, 0x8000000050000000) +#define BF_ERROR_FAILED_TO_ADD_FILE bfscast(int64_t, 0x8000000060000000) +#define BF_ERROR_FAILED_TO_DUMP_DR bfscast(int64_t, 0x8000000070000000) +#define BF_ERROR_OUT_OF_MEMORY bfscast(int64_t, 0x8000000080000000) +#define BF_ERROR_VMM_CORRUPTED bfscast(int64_t, 0x8000000090000000) +#define BF_ERROR_UNKNOWN bfscast(int64_t, 0x80000000A0000000) + +/* -------------------------------------------------------------------------- */ +/* IOCTL Error Codes */ +/* -------------------------------------------------------------------------- */ + +#define BF_IOCTL_SUCCESS bfscast(int64_t, SUCCESS) +#define BF_IOCTL_FAILURE bfscast(int64_t, -1) + +/* -------------------------------------------------------------------------- */ +/* Bad Alloc */ +/* -------------------------------------------------------------------------- */ + +#define BF_BAD_ALLOC bfscast(int64_t, 0x8000000100000000) + +/* -------------------------------------------------------------------------- */ +/* VMCall */ +/* -------------------------------------------------------------------------- */ + +#define BF_VMCALL_SUCCESS bfscast(int64_t, SUCCESS) +#define BF_VMCALL_FAILURE bfscast(int64_t, 0x8000001000000000) + +/* -------------------------------------------------------------------------- */ +/* Stringify Error Codes */ +/* -------------------------------------------------------------------------- */ + +static inline const char * +ec_to_str(int64_t value) +{ + switch (value) { + case SUCCESS: return "SUCCESS"; + case ENTRY_ERROR_STACK_OVERFLOW: return "ENTRY_ERROR_STACK_OVERFLOW"; + case ENTRY_ERROR_VMM_INIT_FAILED: return "ENTRY_ERROR_VMM_INIT_FAILED"; + case ENTRY_ERROR_VMM_START_FAILED: return "ENTRY_ERROR_VMM_START_FAILED"; + case ENTRY_ERROR_VMM_STOP_FAILED: return "ENTRY_ERROR_VMM_STOP_FAILED"; + case ENTRY_ERROR_UNKNOWN: return "ENTRY_ERROR_UNKNOWN"; + case CRT_FAILURE: return "CRT_FAILURE"; + case REGISTER_EH_FRAME_FAILURE: return "REGISTER_EH_FRAME_FAILURE"; + case GET_DRR_FAILURE: return "GET_DRR_FAILURE"; + case MEMORY_MANAGER_FAILURE: return "MEMORY_MANAGER_FAILURE"; + case BFELF_ERROR_INVALID_ARG: return "BFELF_ERROR_INVALID_ARG"; + case BFELF_ERROR_INVALID_FILE: return "BFELF_ERROR_INVALID_FILE"; + case BFELF_ERROR_INVALID_INDEX: return "BFELF_ERROR_INVALID_INDEX"; + case BFELF_ERROR_INVALID_SIGNATURE: return "BFELF_ERROR_INVALID_SIGNATURE"; + case BFELF_ERROR_UNSUPPORTED_FILE: return "BFELF_ERROR_UNSUPPORTED_FILE"; + case BFELF_ERROR_INVALID_SEGMENT: return "BFELF_ERROR_INVALID_SEGMENT"; + case BFELF_ERROR_INVALID_SECTION: return "BFELF_ERROR_INVALID_SECTION"; + case BFELF_ERROR_LOADER_FULL: return "BFELF_ERROR_LOADER_FULL"; + case BFELF_ERROR_NO_SUCH_SYMBOL: return "BFELF_ERROR_NO_SUCH_SYMBOL"; + case BFELF_ERROR_MISMATCH: return "BFELF_ERROR_MISMATCH"; + case BFELF_ERROR_UNSUPPORTED_RELA: return "BFELF_ERROR_UNSUPPORTED_RELA"; + case BFELF_ERROR_OUT_OF_ORDER: return "BFELF_ERROR_OUT_OF_ORDER"; + case BFELF_ERROR_OUT_OF_MEMORY: return "BFELF_ERROR_OUT_OF_MEMORY"; + case BF_ERROR_INVALID_ARG: return "BF_ERROR_INVALID_ARG"; + case BF_ERROR_INVALID_INDEX: return "BF_ERROR_INVALID_INDEX"; + case BF_ERROR_NO_MODULES_ADDED: return "BF_ERROR_NO_MODULES_ADDED"; + case BF_ERROR_MAX_MODULES_REACHED: return "BF_ERROR_MAX_MODULES_REACHED"; + case BF_ERROR_VMM_INVALID_STATE: return "BF_ERROR_VMM_INVALID_STATE"; + case BF_ERROR_FAILED_TO_ADD_FILE: return "BF_ERROR_FAILED_TO_ADD_FILE"; + case BF_ERROR_FAILED_TO_DUMP_DR: return "BF_ERROR_FAILED_TO_DUMP_DR"; + case BF_ERROR_OUT_OF_MEMORY: return "BF_ERROR_OUT_OF_MEMORY"; + case BF_ERROR_VMM_CORRUPTED: return "BF_ERROR_VMM_CORRUPTED"; + case BF_ERROR_UNKNOWN: return "BF_ERROR_UNKNOWN"; + case BF_BAD_ALLOC: return "BF_BAD_ALLOC"; + case BF_IOCTL_FAILURE: return "BF_IOCTL_FAILURE"; + + default: + return "UNDEFINED_ERROR_CODE"; + } +} + +#endif diff --git a/payloads/bareflank/include/bfexception.h b/payloads/bareflank/include/bfexception.h new file mode 100755 index 00000000000..0e7f12794fc --- /dev/null +++ b/payloads/bareflank/include/bfexception.h @@ -0,0 +1,144 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfexception.h +/// + +#ifndef BFEXCEPTION_H +#define BFEXCEPTION_H + +#include +#include + +#include +#include +#include + +/// Guard Exceptions +/// +/// Catches all exceptions and prints the exception that occurred. The point of +/// this function is to prevent any exception from bubbling beyond this point. +/// +/// @expects +/// @ensures +/// +/// @param error_code an error code to return if an exception occurs +/// @param func the function to run that is guarded +/// @param error_func the function to run when an exception occurs +/// @return error_code on failure, SUCCESS on success +/// +template < + typename FUNC, + typename ERROR_FUNC, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +int64_t +guard_exceptions(int64_t error_code, FUNC func, ERROR_FUNC error_func) +{ + try { + func(); + return SUCCESS; + } + catch (std::bad_alloc &) { + error_func(); + return BF_BAD_ALLOC; + } + catch (std::exception &e) { + bfdebug_transaction(0, [&](std::string * msg) { + bferror_lnbr(0, msg); + bferror_brk1(0, msg); + bferror_info(0, typeid(e).name(), msg); + bferror_brk1(0, msg); + bferror_info(0, e.what(), msg); + }); + } + catch (...) { + bfdebug_transaction(0, [&](std::string * msg) { + bferror_lnbr(0, msg); + bferror_brk1(0, msg); + bferror_info(0, "unknown exception", msg); + bferror_brk1(0, msg); + }); + } + + error_func(); + return error_code; +} + +/// Guard Exceptions +/// +/// Catches all exceptions and prints the exception that occurred. The point of +/// this function is to prevent any exception from bubbling beyond this point. +/// +/// @expects +/// @ensures +/// +/// @param error_code an error code to return if an exception occurs +/// @param func the function to run that is guarded +/// @return error_code on failure, SUCCESS on success +/// +template < + typename FUNC, + typename = std::enable_if::value> + > +int64_t +guard_exceptions(int64_t error_code, FUNC && func) +{ return guard_exceptions(error_code, std::forward(func), [] {}); } + +/// Guard Exceptions +/// +/// Catches all exceptions and prints the exception that occurred. The point of +/// this function is to prevent any exception from bubbling beyond this point. +/// +/// @expects +/// @ensures +/// +/// @param func the function to run that is guarded +/// +template < + typename FUNC, + typename = std::enable_if::value> + > +void +guard_exceptions(FUNC && func) +{ guard_exceptions(0L, std::forward(func), [] {}); } + +/// Guard Exceptions +/// +/// Catches all exceptions and prints the exception that occurred. The point of +/// this function is to prevent any exception from bubbling beyond this point. +/// +/// @expects +/// @ensures +/// +/// @param func the function to run that is guarded +/// @param error_func the function to run when an exception occurs +/// +template < + typename FUNC, + typename ERROR_FUNC, + typename = std::enable_if::value>, + typename = std::enable_if::value> + > +void +guard_exceptions(FUNC && func, ERROR_FUNC && error_func) +{ guard_exceptions(0L, std::forward(func), std::forward(error_func)); } + +#endif diff --git a/payloads/bareflank/include/bfexports.h b/payloads/bareflank/include/bfexports.h new file mode 100644 index 00000000000..1cc48ccce0f --- /dev/null +++ b/payloads/bareflank/include/bfexports.h @@ -0,0 +1,37 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BFEXPORTS_H +#define BFEXPORTS_H + +#if defined(_WIN32) || defined(__CYGWIN__) +#define IMPORT_SYM __declspec(dllimport) +#define EXPORT_SYM __declspec(dllexport) +#else +#define IMPORT_SYM +#define EXPORT_SYM __attribute__ ((visibility ("default"))) +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +#define WEAK_SYM +#else +#define WEAK_SYM __attribute__((weak)) +#endif + +#endif diff --git a/payloads/bareflank/include/bffile.h b/payloads/bareflank/include/bffile.h new file mode 100644 index 00000000000..57a9e0939de --- /dev/null +++ b/payloads/bareflank/include/bffile.h @@ -0,0 +1,345 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bffile.h +/// + +#ifndef BFFILE_H +#define BFFILE_H + +#include + +#include +#include +#include + +#include +#include +#include +#include + +/// File +/// +/// This class is responsible for working with a file. Specifically, this +/// class wraps calls to ifstream and fstream to simplify their interface +/// as well as provide an implementation for the rest of the Bareflank +/// Manager, such that testing is easier. +/// +class file +{ +public: + + using text_data = std::string; ///< File format for text data + using binary_data = bfn::buffer; ///< File format for binary data + using filename_type = std::string; ///< File name type + using extension_type = std::string; ///< Extension name type + using path_list_type = std::vector; ///< Find files path type + using filesize_type = std::size_t; ///< File size type + + /// File Constructor + /// + /// @expects none + /// @ensures none + /// + /// Creates a file class that can be used to working with files. + /// + file() noexcept = default; + + /// File Destructor + /// + /// @expects none + /// @ensures none + /// + VIRTUAL ~file() noexcept = default; + + /// Read + /// + /// Reads the entire contents of a file, in text form + /// + /// @expects filename.empty() == false + /// @ensures none + /// + /// @param filename name of the file to read. + /// @return the contents of filename + /// + /// optimization notes: + /// - http://insanecoding.blogspot.it/2011/11/how-to-read-in-file-in-c.html + /// - since std::string has to initialize the backing array, reading in + /// a binary will always be faster. Thus, use read_binary if possible + /// + VIRTUAL text_data + read_text(const filename_type &filename) const + { + expects(!filename.empty()); + + std::fstream handle(filename, std::ios_base::in | std::ios_base::binary); + if (handle) { + + handle.seekg(0, std::ios::end); + auto size = handle.tellg(); + + if (size <= 0) { + return text_data{}; + } + + handle.seekg(0, std::ios::beg); + text_data buffer(static_cast(size), 0); + + handle.read(&buffer.front(), size); + return buffer; + } + + throw std::runtime_error("invalid filename: " + filename); + } + + /// Read + /// + /// Reads the entire contents of a file, in binary form + /// + /// @expects filename.empty() == false + /// @ensures none + /// + /// @param filename name of the file to read. + /// @return the contents of filename + /// + /// optimization notes: + /// - http://insanecoding.blogspot.it/2011/11/how-to-read-in-file-in-c.html + /// + VIRTUAL binary_data + read_binary(const filename_type &filename) const + { + expects(!filename.empty()); + + std::fstream handle(filename, std::ios_base::in | std::ios_base::binary); + if (handle) { + + handle.seekg(0, std::ios::end); + auto size = handle.tellg(); + + if (size <= 0) { + return binary_data{}; + } + + handle.seekg(0, std::ios::beg); + binary_data buffer(static_cast(size)); + + handle.read(buffer.data(), size); + return buffer; + } + + throw std::runtime_error("invalid filename: " + filename); + } + + /// Write + /// + /// Writes text data to the file provided + /// + /// @expects filename.empty() == false + /// @expects buffer.empty() == false + /// @ensures none + /// + /// @param filename name of the file to write to. + /// @param buffer data to write + /// + VIRTUAL void + write_text(const filename_type &filename, const text_data &buffer) const + { + expects(!filename.empty()); + + std::fstream handle(filename, std::ios_base::out | std::ios_base::binary); + if (handle) { + handle.write(buffer.data(), static_cast(buffer.size())); + return; + } + + throw std::runtime_error("invalid filename: " + filename); + } + + /// Write + /// + /// Writes binary data to the file provided + /// + /// @expects filename.empty() == false + /// @expects buffer.empty() == false + /// @ensures none + /// + /// @param filename name of the file to write to. + /// @param buffer data to write + /// + VIRTUAL void + write_binary(const filename_type &filename, const binary_data &buffer) const + { + expects(!filename.empty()); + + std::fstream handle(filename, std::ios_base::out | std::ios_base::binary); + if (handle) { + handle.write(buffer.data(), static_cast(buffer.size())); + return; + } + + throw std::runtime_error("invalid filename: " + filename); + } + + /// Get File Extension + /// + /// @expects none + /// @ensures none + /// + /// @param filename the file name to extract the extension + /// @return the filename's extension + /// + VIRTUAL extension_type + extension(const filename_type &filename) const + { + if (filename.empty()) { + return {}; + } + + auto index = filename.find_last_of('.'); + + if (index != filename_type::npos) { + return filename.substr(index); + } + + return {}; + } + + /// File Exists + /// + /// @expects none + /// @ensures none + /// + /// @param filename the file name to check + /// @return true if the file exists, false otherwise + /// + VIRTUAL bool + exists(const filename_type &filename) const + { + std::ifstream handle{filename}; + return handle.good(); + } + + /// File Size + /// + /// @expects filename.empty() == false + /// @ensures none + /// + /// @param filename to get the size of + /// @return size of filename + /// + VIRTUAL filesize_type + size(const filename_type &filename) const + { + expects(!filename.empty()); + + std::fstream handle(filename, std::ios_base::in | std::ios_base::binary); + if (handle) { + handle.seekg(0, std::ios::end); + return static_cast(handle.tellg()); + } + + throw std::runtime_error("invalid filename: " + filename); + } + + /// Find Files + /// + /// Loops through all of the provided files and file paths and + /// returns a list of each filename combined with the path and the filename + /// that was first found. If a filename cannot be found, an exception is + /// thrown. + /// + /// @note we use the '/' separator on both Windows and POSIX. The reason + /// is both support '/' for the versions we support. + /// + /// @expects files.empty() == false + /// @expects paths.empty() == false + /// @ensures ret: path_list_type.size() == files.size() + /// + /// @param files list of files to locate in the list of provided paths + /// @param paths list of paths to search for the provided list of files + /// @return pull paths for each file located, throws otherwise + /// + VIRTUAL path_list_type + find_files(const path_list_type &files, const path_list_type &paths) const + { + expects(!paths.empty()); + path_list_type results; + + for (const auto &filename : files) { + auto found = false; + + for (auto path : paths) { + path += '/'; + path += filename; + + if (exists(path)) { + results.push_back(path); + + found = true; + break; + } + } + + if (!found) { + throw std::runtime_error("unable to locate file: " + filename); + } + } + + return results; + } + + /// Get Home Directory + /// + /// @expects none + /// @expects none + /// + /// @return returns home directory + /// + VIRTUAL std::string + home() const + { + char *home; + + home = std::getenv("HOME"); + if (home != nullptr) { + return {home}; + } + + home = std::getenv("HOMEPATH"); + if (home != nullptr) { + return {home}; + } + + throw std::runtime_error("HOME or HOMEPATH not set"); + } + +public: + + /// @cond + + file(file &&) noexcept = default; + file &operator=(file &&) noexcept = default; + + file(const file &) = default; + file &operator=(const file &) = default; + + /// @endcond +}; + +#endif diff --git a/payloads/bareflank/include/bfgsl.h b/payloads/bareflank/include/bfgsl.h new file mode 100644 index 00000000000..4e8ee400ee2 --- /dev/null +++ b/payloads/bareflank/include/bfgsl.h @@ -0,0 +1,282 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfgsl.h +/// + +#ifndef BFGSL_H +#define BFGSL_H + +#if defined(__clang__) || defined(__GNUC__) +#pragma GCC system_header +#endif + +#include + +/// @cond + +#define concat1(a,b) a ## b +#define concat2(a,b) concat1(a,b) +#define ___ concat2(dont_care, __COUNTER__) + +/// @endcond + +#ifndef NEED_GSL_LITE + +#include + +namespace gsl +{ + +/// @cond + +#define expects(cond) Expects(cond) +#define ensures(cond) Ensures(cond) + +template +class final_act_success +{ +public: + explicit final_act_success(F f) noexcept : f_(std::move(f)), invoke_(true) {} + + final_act_success(final_act_success &&other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_) + { + other.invoke_ = false; + } + + final_act_success(const final_act_success &) = delete; + final_act_success &operator=(const final_act_success &) = delete; + + ~final_act_success() noexcept + { + if (std::uncaught_exception()) { + return; + } + + if (invoke_) { f_(); } + } + +private: + F f_; + bool invoke_; +}; + +template +class final_act_failure +{ +public: + explicit final_act_failure(F f) noexcept : f_(std::move(f)), invoke_(true) {} + + final_act_failure(final_act_failure &&other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_) + { + other.invoke_ = false; + } + + final_act_failure(const final_act_failure &) = delete; + final_act_failure &operator=(const final_act_failure &) = delete; + + ~final_act_failure() noexcept + { + if (!std::uncaught_exception()) { + return; + } + + if (invoke_) { f_(); } + } + +private: + F f_; + bool invoke_; +}; + +template +inline final_act_success on_success(const F &f) noexcept +{ + return final_act_success(f); +} + +template +inline final_act_success on_success(F &&f) noexcept +{ + return final_act_success(std::forward(f)); +} + +template +inline final_act_failure on_failure(const F &f) noexcept +{ + return final_act_failure(f); +} + +template +inline final_act_failure on_failure(F &&f) noexcept +{ + return final_act_failure(std::forward(f)); +} + +/// @endcond + +/// Memset +/// +/// Same as std::memset, but for spans +/// +/// @param dst The span to memset +/// @param val The value to set the span to +/// @return Returns dst +/// +template +auto memset(span dst, T val) +{ + expects(dst.size() > 0); + + return std::memset( + dst.data(), + static_cast(val), + static_cast(dst.size()) + ); +} + +} + +#else + +#ifdef NEED_STD_LITE +#include +#endif + +/// @cond + +#if defined(__clang__) || defined(__GNUC__) +#define gsl_likely(x) __builtin_expect(!!(x), 1) +#define gsl_unlikely(x) __builtin_expect(!!(x), 0) +#else +#define gsl_likely(x) (x) +#define gsl_unlikely(x) (x) +#endif + +#ifndef GSL_ABORT +#define GSL_ABORT abort +#endif + +#define expects(cond) \ + if (gsl_unlikely(!(cond))) { \ + GSL_ABORT(); \ + } +#define ensures(cond) \ + if (gsl_unlikely(!(cond))) { \ + GSL_ABORT(); \ + } + +/// @endcond + +namespace gsl +{ + +/// Narrow Cast +/// +/// A rename of static_cast to indicate a narrow (e.g. 64bit to 32bit) +/// +/// @param u the value to narrow +/// @return static_cast(u) +/// +template +inline constexpr T +narrow_cast(U &&u) noexcept +{ + return static_cast(std::forward(u)); +} + +/// At +/// +/// Returns a reference to an element in an array given an index. Unlike +/// the [] operator, if the indexis out-of-bounds, an exception is thrown, +/// or std::terminate() is called. +/// +/// @param arr the array +/// @param index the index of the element to retrieve. +/// @return a reference to +/// +template +constexpr T & +at(T(&arr)[N], I index) +{ + expects(index >= 0 && index < narrow_cast(N)); + return arr[static_cast(index)]; +} + +/// At +/// +/// Returns a reference to an element in an array given an index. Unlike +/// the [] operator, if the indexis out-of-bounds, an exception is thrown, +/// or std::terminate() is called. +/// +/// @param arr the array +/// @param index the index of the element to retrieve. +/// @return a reference to +/// +template +const constexpr T & +at(const T(&arr)[N], I index) +{ + expects(index >= 0 && index < narrow_cast(N)); + return arr[static_cast(index)]; +} + +/// At +/// +/// Returns a reference to an element in an array given an index. Unlike +/// the [] operator, if the indexis out-of-bounds, an exception is thrown, +/// or std::terminate() is called. +/// +/// @param arr the array +/// @param N the size of the array +/// @param index the index of the element to retrieve. +/// @return a reference to +/// +template +constexpr T & +at(T *arr, size_t N, I index) +{ + expects(index >= 0 && index < narrow_cast(N)); + return arr[static_cast(index)]; +} + +/// At +/// +/// Returns a reference to an element in an array given an index. Unlike +/// the [] operator, if the indexis out-of-bounds, an exception is thrown, +/// or std::terminate() is called. +/// +/// @param arr the array +/// @param N the size of the array +/// @param index the index of the element to retrieve. +/// @return a reference to +/// +template +const constexpr T & +at(const T *arr, size_t N, I index) +{ + expects(index >= 0 && index < narrow_cast(N)); + return arr[static_cast(index)]; +} + +} + +#endif + +#endif diff --git a/payloads/bareflank/include/bfjson.h b/payloads/bareflank/include/bfjson.h new file mode 100644 index 00000000000..62e4a9a393d --- /dev/null +++ b/payloads/bareflank/include/bfjson.h @@ -0,0 +1,113 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULLAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfjson.h +/// + +#ifndef BFJSON_H +#define BFJSON_H + +#include + +#include +using json = nlohmann::json; ///< Simply namespace + +/// JSON Hex or Dec +/// +/// Converts a JSON object's field to T. The field name can either be "" +/// or "_hex". If "_hex" is added to the field name, the value is +/// interpreted as a hex string, other wise it's interpreted as a dec number. +/// +/// @expects none +/// @ensures none +/// +/// @param obj the json object +/// @param field the field name +/// @return returns the converted number or throws +/// +template < + typename T, + typename J, + typename = std::enable_if::value> + > +auto +json_hex_or_dec(const J &obj, const std::string &field) +{ + auto val_hex = obj.value(field + "_hex", json(nullptr)); + + if (val_hex.is_string()) { + return gsl::narrow_cast(std::stoull(val_hex.template get(), 0, 16)); + } + + auto val_dec = obj.at(field); + + if (val_dec.is_number()) { + return gsl::narrow_cast(val_dec.template get()); + } + + throw std::runtime_error("json is neither a hex or dec"); +} + +/// JSON Hex or Dec Array +/// +/// Converts a JSON object's field to [T]. The field name can either be +/// "" or "_hex". If "_hex" is added to the field name, each value +/// is interpreted as a hex string, other wise they are interpreted as a dec +/// number. +/// +/// @expects none +/// @ensures none +/// +/// @param obj the json object +/// @param field the field name +/// @return returns std::vector with the converted numbers or throws +/// +template < + typename T, + typename J, + typename = std::enable_if::value> + > +auto +json_hex_or_dec_array(const J &obj, const std::string &field) +{ + std::vector result; + auto array_hex = obj.value(field + "_hex", json(nullptr)); + + if (array_hex.is_array()) { + for (auto val : array_hex) { + result.push_back(gsl::narrow_cast(std::stoull(val.template get(), 0, 16))); + } + + return result; + } + + auto array_dec = obj.at(field); + + if (array_dec.is_array()) { + for (auto val : array_dec) { + result.push_back(gsl::narrow_cast(val.template get())); + } + + return result; + } + + throw std::runtime_error("json is neither a hex or dec"); +} + +#endif diff --git a/payloads/bareflank/include/bfmanager.h b/payloads/bareflank/include/bfmanager.h new file mode 100644 index 00000000000..3e4f5a0716d --- /dev/null +++ b/payloads/bareflank/include/bfmanager.h @@ -0,0 +1,198 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#ifndef BFMANAGER_H +#define BFMANAGER_H + +#include +#include +#include + +#include +#include + +/// Manager +/// +/// A generic class for creating, destroying, running and stopping T given a +/// T_factory to actually instantiate T, and a tid to identify which T to +/// interact with. +/// +template +class bfmanager +{ +public: + + /// Destructor + /// + /// @expects none + /// @ensures none + /// + ~bfmanager() = default; + + /// Get Singleton Instance + /// + /// @expects none + /// @ensures ret != nullptr + /// + /// @return a singleton instance of bfmanager + /// + static bfmanager *instance() noexcept + { + static bfmanager self; + return &self; + } + + /// Create T + /// + /// Creates T. Note that the T is actually created by the + /// T factory's make_t function. + /// + /// @expects none + /// @ensures none + /// + /// @param id the t to initialize + /// @param obj object that can be passed around as needed + /// by extensions of Bareflank + /// + void create(tid id, bfobject *obj = nullptr) + { + auto ___ = gsl::on_failure([&] { + std::lock_guard guard(m_mutex); + m_ts.erase(id); + }); + + if (auto &&t = add_t(id, obj)) { + t->init(obj); + } + } + + /// Destroy T + /// + /// Deletes T. + /// + /// @param id the t to destroy + /// @param obj object that can be passed around as needed + /// by extensions of Bareflank + /// + void destroy(tid id, bfobject *obj = nullptr) + { + auto ___ = gsl::finally([&] { + std::lock_guard guard(m_mutex); + m_ts.erase(id); + }); + + if (auto &&t = get_t(id)) { + t->fini(obj); + } + } + + /// Run T + /// + /// Executes T. + /// + /// @expects t exists + /// @ensures none + /// + /// @param id the t to run + /// @param obj object that can be passed around as needed + /// by extensions of Bareflank + /// + void run(tid id, bfobject *obj = nullptr) + { + if (auto &&t = get_t(id)) { + t->run(obj); + } + } + + /// Halt T + /// + /// Halts T. + /// + /// @expects none + /// @ensures none + /// + /// @param id the t to halt + /// @param obj object that can be passed around as needed + /// by extensions of Bareflank + /// + void hlt(tid id, bfobject *obj = nullptr) + { + if (auto &&t = get_t(id)) { + t->hlt(obj); + } + } + + /// Set Factory + /// + /// Should only be used by unit tests + /// + /// @expects none + /// @ensures none + /// + /// @param factory the new factory to use + /// + void set_factory(std::unique_ptr factory) + { m_T_factory = std::move(factory); } + +private: + + bfmanager() noexcept : + m_T_factory(std::make_unique()) + { } + + std::unique_ptr &add_t(tid id, bfobject *obj) + { + if (auto &&t = get_t(id)) { + return t; + } + + if (auto t = m_T_factory->make(id, obj)) { + std::lock_guard guard(m_mutex); + return m_ts[id] = std::move(t); + } + + throw std::runtime_error("make returned a nullptr"); + } + + std::unique_ptr &get_t(tid id) + { + std::lock_guard guard(m_mutex); + return m_ts[id]; + } + +private: + + std::unique_ptr m_T_factory; + std::map> m_ts; + + mutable std::mutex m_mutex; + +public: + + /// @cond + + bfmanager(bfmanager &&) noexcept = delete; + bfmanager &operator=(bfmanager &&) noexcept = delete; + + bfmanager(const bfmanager &) = delete; + bfmanager &operator=(const bfmanager &) = delete; + + /// @endcond +}; + +#endif diff --git a/payloads/bareflank/include/bfmemory.h b/payloads/bareflank/include/bfmemory.h new file mode 100644 index 00000000000..49d39029a03 --- /dev/null +++ b/payloads/bareflank/include/bfmemory.h @@ -0,0 +1,75 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfmemory.h + */ + +#ifndef BFMEMORY_H +#define BFMEMORY_H + +#include +#include +#include + +#pragma pack(push, 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/* @cond */ + +#define MEMORY_TYPE_R 0x1U +#define MEMORY_TYPE_W 0x2U +#define MEMORY_TYPE_E 0x4U + +/* @endcond */ + +/** + * @struct memory_descriptor + * + * Memory Descriptor + * + * A memory descriptor provides information about a block of memory. + * Typically, each page of memory that the VMM uses will have a memory + * descriptor associated with it. The VMM will use this information to create + * its resources, as well as generate page tables as needed. + * + * @var memory_descriptor::phys + * the starting physical address of the block of memory + * @var memory_descriptor::virt + * the starting virtual address of the block of memory + * @var memory_descriptor::type + * the type of memory block. This is likely architecture specific as + * this holds information about access rights, etc... + */ +struct memory_descriptor { + uint64_t phys; + uint64_t virt; + uint64_t type; +}; + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#endif diff --git a/payloads/bareflank/include/bfobject.h b/payloads/bareflank/include/bfobject.h new file mode 100644 index 00000000000..295c5fe25ab --- /dev/null +++ b/payloads/bareflank/include/bfobject.h @@ -0,0 +1,57 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfobject.h +/// + +#ifndef BFOBJECT_H +#define BFOBJECT_H + +/// User Data +/// +/// This defines the base class used for passing around subclasses. +/// This is mainly used so that dynamic_cast can be used if desired +/// for casting and deletion. +/// +class bfobject +{ +public: + + /// Default Constructor + /// + bfobject() = default; + + /// Default Destructor + /// + virtual ~bfobject() = default; + +public: + + /// @cond + + bfobject(bfobject &&) noexcept = delete; + bfobject &operator=(bfobject &&) noexcept = delete; + + bfobject(const bfobject &) = delete; + bfobject &operator=(const bfobject &) = delete; + + /// @endcond +}; + +#endif diff --git a/payloads/bareflank/include/bfplatform.h b/payloads/bareflank/include/bfplatform.h new file mode 100755 index 00000000000..657622734f1 --- /dev/null +++ b/payloads/bareflank/include/bfplatform.h @@ -0,0 +1,177 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfplatform.h + */ + +#ifndef BFPLATFORM_H +#define BFPLATFORM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initalize Platform Logic + * + * @expects none + * @ensures none + * + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t platform_init(void); + +/** + * Allocate Memory + * + * @expects none + * @ensures none + * + * @note: If this function is used in userspace, it must be assumed that free() + * can be used to free this memory. In the kernel, it can be assumed that + * platform_free_rw is used instead, which provides the length field. + * + * @param len the size of memory to allocate in bytes. + * @return returns the address of the newly allocated memory + */ +void *platform_alloc_rw(uint64_t len); + +/** + * Allocate Executable Memory + * + * @expects none + * @ensures none + * + * @note: memory allocated from this function must be 4k aligned. If this + * function is used in userspace, it must be assumed that free() can be + * used to free this memory. In the kernel, it can be assumed that + * platform_free_rwe is used instead, which provides the length field. + * + * @param len the size of memory to allocate in bytes. + * @return returns the address of the newly allocated, executable memory + */ +void *platform_alloc_rwe(uint64_t len); + +/** + * Free Memory + * + * @expects none + * @ensures none + * + * @param addr the address of memory allocated using platform_alloc_rw + * @param len the size of the memory allocated using platform_alloc_rw + */ +void platform_free_rw(const void *addr, uint64_t len); + +/** + * Free Executable Memory + * + * @expects none + * @ensures none + * + * @param addr the address of memory allocated using platform_alloc_rwe + * @param len the size of the memory allocated using platform_alloc_rwe + */ +void platform_free_rwe(const void *addr, uint64_t len); + +/** + * Convert Virtual Address to Physical Address + * + * @expects none + * @ensures none + * + * @param virt the virtual address to convert + * @return the physical address associated with the provided virtual address + */ +void *platform_virt_to_phys(void *virt); + +/** + * Memset + * + * @expects none + * @ensures none + * + * @param ptr a pointer to the memory to set + * @param value the value to set each byte to + * @param num the number of bytes to set + */ +void *platform_memset(void *ptr, char value, uint64_t num); + +/** + * Memcpy + * + * @expects none + * @ensures none + * + * @param dst a pointer to the memory to copy to + * @param src a pointer to the memory to copy from + * @param num the number of bytes to copy + */ +void *platform_memcpy(void *dst, const void *src, uint64_t num); + +/** + * Get Number of CPUs + * + * @expects none + * @ensures none + * + * @return returns the total number of CPUs available. + */ +int64_t platform_num_cpus(void); + +/** + * Call VMM on Core + * + * Executes the VMM. The VMM has a single entry point, with a switch statement + * that executes the provided "request". When this occurs, arg1 and arg2 are + * provided to the requested function. Note that the first arg takes a cpuid, + * which is the core number want to execute the VMM on. If a -1 is provided, + * the currently executing core will be used. + * + * @param cpuid the core id this code is to be execute on + * @param request the requested function in the VMM to execute + * @param arg1 arg #1 + * @param arg2 arg #2 + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t platform_call_vmm_on_core( + uint64_t cpuid, uint64_t request, uintptr_t arg1, uintptr_t arg2); + +/** + * Get RSDP + * + * Returns the address of the Root System Description Pointer for ACPI. + * If ACPI is not supported, return 0. + * + * @expects none + * @ensures none + * + * @return returns the RSDP or 0 if ACPI is not supported + */ +void *platform_get_rsdp(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/payloads/bareflank/include/bfshuffle.h b/payloads/bareflank/include/bfshuffle.h new file mode 100644 index 00000000000..bda3fc27971 --- /dev/null +++ b/payloads/bareflank/include/bfshuffle.h @@ -0,0 +1,49 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfshuffle.h +/// + +#ifndef BFSHUFFLE_H +#define BFSHUFFLE_H + +#include +#include +#include + +namespace bfn +{ + +/// Shuffle Vector +/// +/// @expects none +/// @ensures none +/// +/// @param list the vector to shuffle +/// +template void +shuffle(std::vector &list) +{ + std::random_device rd; + std::shuffle(list.begin(), list.end(), std::mt19937{rd()}); +} + +} + +#endif diff --git a/payloads/bareflank/include/bfstd.h b/payloads/bareflank/include/bfstd.h new file mode 100644 index 00000000000..eea919d3188 --- /dev/null +++ b/payloads/bareflank/include/bfstd.h @@ -0,0 +1,118 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfstd.h +/// + +#ifndef BFSTD_H +#define BFSTD_H + +#if defined(__clang__) || defined(__GNUC__) +#pragma GCC system_header +#endif + +#include +#include + +// Note: +// +// This file exists for code that cannot include libc++ +// + +namespace std +{ +/// Remove Reference +/// +/// Returns T regardless of lvalue / rvalue type +/// +template struct remove_reference { + typedef T type; ///< Type T +}; + +/// Remove Reference +/// +/// Returns T regardless of lvalue / rvalue type +/// +template struct remove_reference { + typedef T type; ///< Type T +}; + +/// Remove Reference +/// +/// Returns T regardless of lvalue / rvalue type +/// +template struct remove_reference < T && > { + typedef T type; ///< Type T +}; + +/// Forward +/// +/// Preserves lvalue / rvalue reference +/// +/// @param t the object to be forwarded +/// @return static_cast(t) +/// +template +constexpr T && +forward(typename std::remove_reference::type &t) noexcept +{ + return static_cast < T && >(t); +} + +/// Forward +/// +/// Preserves lvalue / rvalue reference +/// +/// @param t the object to be forwarded +/// @return static_cast(t) +/// +template +constexpr T && +forward(typename std::remove_reference::type &&t) noexcept +{ + return static_cast < T && >(t); +} + +/// Move +/// +/// Produces a rvalue reference +/// +/// @param t the object to be moved +/// @return static_cast::type&&>(t) +/// +template +constexpr typename std::remove_reference::type && +move(T &&t) noexcept +{ + return static_cast < typename std::remove_reference::type && >(t); +} + +/// Terminate +/// +/// A C++ wrapper around C's abort(). +/// +[[noreturn]] inline void +terminate() noexcept +{ + printf("FATAL ERROR: std::terminate() called!!!\n"); + abort(); +} +} + +#endif diff --git a/payloads/bareflank/include/bfstring.h b/payloads/bareflank/include/bfstring.h new file mode 100644 index 00000000000..4212fcdcd1e --- /dev/null +++ b/payloads/bareflank/include/bfstring.h @@ -0,0 +1,142 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfstring.h +/// + +#ifndef BFSTRING_H +#define BFSTRING_H + +#include +#include +#include +#include +#include + +/// std::string literal +/// +/// @param str string to convert to std::string +/// @param len len of str +/// @return std::string(str, len) +/// +inline auto operator""_s(const char *str, std::size_t len) +{ + return std::string(str, len); +} + +namespace bfn +{ + +/// Convert to String (with base) +/// +/// Same thing as std::to_string, but adds the ability to state the base for +/// conversion. +/// +/// @expects none +/// @ensures none +/// +/// @param val the value to convert +/// @param base the base for conversion. +/// @return string version of val converted to the provided base +/// +template < + typename T, + typename = std::enable_if::value> + > +std::string +to_string(const T val, const int base) +{ + // TODO: + // + // C++17 has a new set of functions that called to_chars which gets rid + // of the allocation. We should use this in the VMM when compiled with + // our cross compiler. When not compiled with our cross compiler, we + // should use this code to emulate it so that we do not need C++17 on all + // systems. This optimization would reduce the debugging code to just + // page allocations as needed which is ideal + // + + std::stringstream stream; + + switch (base) { + case 16: + stream << std::setfill('0') << std::setw(18) << std::internal; + break; + + default: + break; + }; + + stream << std::setbase(base) << std::showbase << val; + return stream.str(); +} + +/// Split String +/// +/// Splits a string into a string vector based on a provided +/// delimiter +/// +/// @expects none +/// @ensures none +/// +/// @param str the string to split +/// @param delimiter the delimiter to split the string with +/// @return std::vector version of str, split using delimiter +/// +inline std::vector +split(const std::string &str, char delimiter) +{ + std::istringstream ss{str}; + std::vector result; + + while (!ss.eof()) { + std::string field; + std::getline(ss, field, delimiter); + + result.push_back(field); + } + + return result; +} + +/// Split String +/// +/// Splits a string into a string vector based on a provided +/// delimiter +/// +/// @expects none +/// @ensures none +/// +/// @param str the string to split +/// @param delimiter the delimiter to split the string with +/// @return std::vector version of str, split using delimiter +/// +inline std::vector +split(const char *str, char delimiter) +{ + if (str == nullptr) { + return {}; + } + + return split(std::string(str), delimiter); +} + +} + +#endif diff --git a/payloads/bareflank/include/bfsupport.h b/payloads/bareflank/include/bfsupport.h new file mode 100755 index 00000000000..496e114ed31 --- /dev/null +++ b/payloads/bareflank/include/bfsupport.h @@ -0,0 +1,196 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfsupport.h + */ + +#ifndef BFSUPPORT_H +#define BFSUPPORT_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @struct section_info_t + * + * Provides information about the ELF file that is used to init/fini the + * file. + * + * @var section_info_t::init_addr + * the virtual address of ".init" after relocation + * @var section_info_t::fini_addr + * the virtual address of ".fini" after relocation + * @var section_info_t::init_array_addr + * the virtual address of ".init_array" after relocation + * @var section_info_t::init_array_size + * the size of ".init_array" + * @var section_info_t::fini_array_addr + * the virtual address of ".fini_array" after relocation + * @var section_info_t::fini_array_size + * the size of ".fini_array" + * @var section_info_t::eh_frame_addr + * the virtual address of ".eh_frame" after relocation + * @var section_info_t::eh_frame_size + * the size of ".eh_frame" + * @var section_info_t::debug_info_addr + * the virtual address of ".debug_info" after relocation + * @var section_info_t::debug_info_size + * the size of ".debug_info" + * @var section_info_t::debug_abbrev_addr + * the virtual address of ".debug_abbrev" after relocation + * @var section_info_t::debug_abbrev_size + * the size of ".debug_abbrev" + * @var section_info_t::debug_line_addr + * the virtual address of ".debug_line" after relocation + * @var section_info_t::debug_line_size + * the size of ".debug_line" + * @var section_info_t::debug_str_addr + * the virtual address of ".debug_str" after relocation + * @var section_info_t::debug_str_size + * the size of ".debug_str" + * @var section_info_t::debug_ranges_addr + * the virtual address of ".debug_ranges" after relocation + * @var section_info_t::debug_ranges_size + * the size of ".debug_ranges" + */ +struct section_info_t { + void *init_addr; + void *fini_addr; + + void *init_array_addr; + uint64_t init_array_size; + + void *fini_array_addr; + uint64_t fini_array_size; + + void *eh_frame_addr; + uint64_t eh_frame_size; + + void *debug_info_addr; + uint64_t debug_info_size; + + void *debug_abbrev_addr; + uint64_t debug_abbrev_size; + + void *debug_line_addr; + uint64_t debug_line_size; + + void *debug_str_addr; + uint64_t debug_str_size; + + void *debug_ranges_addr; + uint64_t debug_ranges_size; +}; + +/** + * @struct crt_info_t + * + * Provides information for executing an application including section + * information, the program break and arguments. + * + * @var crt_info_t::arg_type + * 0 = argc/argv, 1 == arg#, undefined otherwise + * @var crt_info_t::argc + * the number of arguments + * @var crt_info_t::argv + * the arguments +* @var crt_info_t::request + * - + * @var crt_info_t::arg1 + * integer argument #1 + * @var crt_info_t::arg2 + * integer argument #2 + * @var crt_info_t::arg3 + * integer argument #3 + * @var crt_info_t::info_num + * the number of modules + * @var crt_info_t::info + * the section info for each module + * @var crt_info_t::func + * (optional) function to call + * @var crt_info_t::vcpuid + * (optional) vcpuid the executable is running on + * @var crt_info_t::program_break + * (optional) the executable's program break + */ +struct crt_info_t { + + int arg_type; + + int argc; + const char **argv; + + uintptr_t request; + uintptr_t arg1; + uintptr_t arg2; + uintptr_t arg3; + + int info_num; + struct section_info_t info[MAX_NUM_MODULES]; + + uintptr_t func; + uintptr_t vcpuid; + uintptr_t program_break; +}; + +/** + * Request IDs + * + * The following defines the different types of requests that can be made + * when calling bfmain instead of main. Note that these are simply the + * currently defined requests, users can add to this as needed. + * + * @cond + */ + +#define BF_REQUEST_INIT 0 +#define BF_REQUEST_FINI 1 +#define BF_REQUEST_VMM_INIT 2 +#define BF_REQUEST_VMM_FINI 3 +#define BF_REQUEST_ADD_MDL 4 +#define BF_REQUEST_GET_DRR 5 +#define BF_REQUEST_SET_RSDP 6 +#define BF_REQUEST_END 0xFFFF + +/* @endcond */ + +/** + * Start + * + * Defines the function signature for the _start function + */ +#ifdef __cplusplus +using _start_t = int64_t (*)(char *stack, const struct crt_info_t *); +#else +typedef int64_t (*_start_t)(char *stack, const struct crt_info_t *); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/payloads/bareflank/include/bfthreadcontext.h b/payloads/bareflank/include/bfthreadcontext.h new file mode 100644 index 00000000000..3fa562e92bd --- /dev/null +++ b/payloads/bareflank/include/bfthreadcontext.h @@ -0,0 +1,115 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file bfthreadcontext.h + */ + +#ifndef BFTHREADCONTEXT +#define BFTHREADCONTEXT + +#include +#include + +#pragma pack(push, 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return CPUID + * + * @return returns the CPUID for the currently executing thread + */ +uint64_t thread_context_cpuid(void); + +/** + * Return TLS data + * + * @return returns the TLS data for the currently executing thread + */ +uint64_t *thread_context_tlsptr(void); + +/** + * @struct thread_context_t + * + * Thread Context + * + * On the top of every stack pointer sits one of these structures, which is + * used to identify thread specific information. For more information on + * how this works, please see the following post: + * + * https://github.com/Bareflank/hypervisor/issues/213 + * + * Note: If this struct changes, assembly code in the misc module will + * likely have to change as well since we don't have a clean way to bridge + * between C and NASM + * + * @var thread_context_t::cpuid + * the cpuid of the thread + * @var thread_context_t::tlsptr + * the TLS pointer of the thread + * @var thread_context_t::reserved1 + * reserved + * @var thread_context_t::reserved2 + * reserved + */ +struct thread_context_t { + uint64_t cpuid; + uint64_t *tlsptr; + uint64_t reserved1; + uint64_t reserved2; +}; + +/** + * Setup Stack + * + * The following function sets up the stack to match the algorithm defined + * in the following issue: + * + * https://github.com/Bareflank/hypervisor/issues/213 + * + * @param stack the stack pointer + * @return the stack pointer (in interger form) + */ +static inline uint64_t +setup_stack(void *stack) +{ + struct thread_context_t *tc; + uint64_t stack_int = bfrcast(uint64_t, stack); + + uint64_t stack_top = stack_int + (STACK_SIZE * 2); + stack_top = (stack_top & ~(STACK_SIZE - 1)) - 1; + stack_int = stack_top - sizeof(struct thread_context_t) - 1; + + tc = bfrcast(struct thread_context_t *, stack_top - sizeof(struct thread_context_t)); + tc->cpuid = thread_context_cpuid(); + tc->tlsptr = thread_context_tlsptr(); + + return stack_int; +} + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#endif diff --git a/payloads/bareflank/include/bftypes.h b/payloads/bareflank/include/bftypes.h new file mode 100644 index 00000000000..13d0671b8c0 --- /dev/null +++ b/payloads/bareflank/include/bftypes.h @@ -0,0 +1,138 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BFTYPES_H +#define BFTYPES_H + +/* -------------------------------------------------------------------------- */ +/* Helper Macros */ +/* -------------------------------------------------------------------------- */ + +#ifdef __cplusplus +#define bfscast(a, b) (static_cast(b)) +#else +#define bfscast(a, b) ((a)(b)) +#endif + +#ifdef __cplusplus +#define bfrcast(a, b) (reinterpret_cast(b)) +#else +#define bfrcast(a, b) ((a)(b)) +#endif + +#ifdef __cplusplus +#define bfadd(a, b, c) (reinterpret_cast(reinterpret_cast(b) + (c))) +#else +#define bfadd(a, b, c) ((a)((char *)(b) + (c))) +#endif + +#ifdef __cplusplus +#define bfcadd(a, b, c) (reinterpret_cast(reinterpret_cast(b) + (c))) +#else +#define bfcadd(a, b, c) ((a)((const char *)(b) + (c))) +#endif + +#define bfignored(a) (void)a + +/* -------------------------------------------------------------------------- */ +/* Stringify */ +/* -------------------------------------------------------------------------- */ + +#define bfstringify(a) __bfstringify(a) +#define __bfstringify(a) #a + +/* -------------------------------------------------------------------------- */ +/* NULL */ +/* -------------------------------------------------------------------------- */ + +#if !defined(__cplusplus) && !defined(nullptr) +#define nullptr 0 +#endif + +/* -------------------------------------------------------------------------- */ +/* Debug */ +/* -------------------------------------------------------------------------- */ + +#ifdef NDEBUG +#define ndebug 1 +#else +#define ndebug 0 +#endif + +/* -------------------------------------------------------------------------- */ +/* Testing */ +/* -------------------------------------------------------------------------- */ + +#ifdef ENABLE_BUILD_TEST +#define VIRTUAL virtual +#else +#define VIRTUAL +#endif + +/* -------------------------------------------------------------------------- */ +/* Userspace */ +/* -------------------------------------------------------------------------- */ + +#if !defined(KERNEL) && !defined(_WIN32) +#if defined(__cplusplus) && __has_include("cstdint") +#include +#else +#include +#endif +#endif + +/* -------------------------------------------------------------------------- */ +/* Linux Types */ +/* -------------------------------------------------------------------------- */ + +#if defined(KERNEL) && defined(__linux__) +#include +#define PRId64 "lld" +#endif + +/* -------------------------------------------------------------------------- */ +/* Windows Types */ +/* -------------------------------------------------------------------------- */ + +#if defined(_WIN32) +#include +typedef INT8 int8_t; +typedef INT16 int16_t; +typedef INT32 int32_t; +typedef INT64 int64_t; +typedef UINT8 uint8_t; +typedef UINT16 uint16_t; +typedef UINT32 uint32_t; +typedef UINT64 uint64_t; +typedef UINT_PTR uintptr_t; +typedef INT_PTR intptr_t; +#define PRId64 "lld" +#endif + +/* -------------------------------------------------------------------------- */ +/* EFI Types */ +/* -------------------------------------------------------------------------- */ + +#if defined(KERNEL) && defined(EFI) +#include "efi.h" +#include "efilib.h" +#define PRId64 "lld" +#endif + +#endif diff --git a/payloads/bareflank/include/bfupperlower.h b/payloads/bareflank/include/bfupperlower.h new file mode 100644 index 00000000000..dd7161bd565 --- /dev/null +++ b/payloads/bareflank/include/bfupperlower.h @@ -0,0 +1,146 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfupperlower.h +/// + +#ifndef BFUPPERLOWER_H +#define BFUPPERLOWER_H + +#include +#include + +namespace bfn +{ + +/// Lower +/// +/// @param val the pointer to mask +/// @return the lower 12 bits of val +/// +template < + typename T, + typename = std::enable_if::value> + > +auto +lower(T val) noexcept +{ + return static_cast(static_cast(val) & (0xFFFULL)); +} + +/// Lower +/// +/// @param val the pointer to mask +/// @return the lower 12 bits of val +/// +template +auto +lower(T *val) noexcept +{ + return reinterpret_cast(reinterpret_cast(val) & (0xFFFULL)); +} + +/// Lower +/// +/// @param val the pointer to mask +/// @param from the number of bits to mask +/// @return the lower "from" bits of val +/// +template < + typename T, + typename = std::enable_if::value> + > +auto +lower(T val, uintptr_t from) noexcept +{ + return static_cast(static_cast(val) & ((0x1ULL << from) - 1)); +} + +/// Lower +/// +/// @param val the pointer to mask +/// @param from the number of bits to mask +/// @return the lower "from" bits of val +/// +template +auto +lower(T *val, uintptr_t from) noexcept +{ + return reinterpret_cast(reinterpret_cast(val) & ((0x1ULL << from) - 1)); +} + +/// Upper +/// +/// @param val the pointer to mask +/// @return the upper 12 bits of val +/// +template < + typename T, + typename = std::enable_if::value> + > +auto +upper(T val) noexcept +{ + return static_cast(static_cast(val) & ~(0xFFFULL)); +} + +/// Upper +/// +/// @param val the pointer to mask +/// @return the upper 12 bits of val +/// +template +auto +upper(T *val) noexcept +{ + return reinterpret_cast(reinterpret_cast(val) & ~(0xFFFULL)); +} + +/// Upper +/// +/// @param val the pointer to mask +/// @param from the number of bits to mask +/// @return the upper "from" bits of val +/// +template < + typename T, + typename = std::enable_if::value> + > +auto +upper(T val, uintptr_t from) noexcept +{ + return static_cast(static_cast(val) & ~((0x1ULL << from) - 1)); +} + +/// Upper +/// +/// @param val the pointer to mask +/// @param from the number of bits to mask +/// @return the upper "from" bits of val +/// +template +auto +upper(T *val, uintptr_t from) noexcept +{ + return reinterpret_cast(reinterpret_cast(val) & ~((0x1ULL << from) - 1)); +} + +} + +#endif diff --git a/payloads/bareflank/include/bfvcpuid.h b/payloads/bareflank/include/bfvcpuid.h new file mode 100644 index 00000000000..23e7f8cf89b --- /dev/null +++ b/payloads/bareflank/include/bfvcpuid.h @@ -0,0 +1,64 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#ifndef BFVCPUID_H +#define BFVCPUID_H + +#include + +// *INDENT-OFF* + +namespace vcpuid +{ + using type = uint64_t; + + constexpr const auto reserved = 0x8000000000000000UL; + + constexpr const auto invalid = 0xFFFFFFFFFFFFFFFFUL; + constexpr const auto current = 0xFFFFFFFFFFFFFFF0UL; + + constexpr const auto guest_mask = 0xFFFFFFFFFFFF0000UL; + constexpr const auto guest_from = 16; + + /// Is Bootstrap vCPU + /// + /// @expects none + /// @ensures none + /// + /// @param id the id to check + /// @return true if this vCPU is the bootstrap vCPU, false otherwise + /// + constexpr inline bool is_bootstrap_vcpu(type id) + { return id == 0; } + + /// Is Host VM vCPU + /// + /// @expects none + /// @ensures none + /// + /// @param id the id to check + /// @return true if this vCPU belongs to the host VM, false otherwise + /// + constexpr inline bool is_hvm_vcpu(type id) + { return (id & (vcpuid::guest_mask & ~vcpuid::reserved)) == 0; } + +} + +// *INDENT-ON* + +#endif diff --git a/payloads/bareflank/include/bfvector.h b/payloads/bareflank/include/bfvector.h new file mode 100644 index 00000000000..7e76f28828f --- /dev/null +++ b/payloads/bareflank/include/bfvector.h @@ -0,0 +1,140 @@ +// +// Bareflank Hypervisor +// Copyright (C) 2015 Assured Information Security, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/// +/// @file bfvector.h +/// + +#ifndef BFVECTOR +#define BFVECTOR + +#include +#include + +namespace bfn +{ + +/// Find +/// +/// Get the iterator from the provided vector, given an index. +/// +/// @expects index >= 0 +/// @expects index < v.size() +/// @ensures ret != v.end() +/// +/// @param v std::vector to get iterator from +/// @param index the iterator to locate +/// @return returns the iterator at pos == index, or throws gsl::fail_fast +/// +template < + typename T, + typename A + > +auto +find(std::vector &v, const std::ptrdiff_t index) +{ + // [[ensures ret: ret != v.end()]] + expects(index >= 0 && index < gsl::narrow_cast(v.size())); + + return v.begin() + index; +} + +/// Find (const) +/// +/// Get the iterator from the provided vector, given an index. +/// +/// @expects index >= 0 +/// @expects index < v.size() +/// @ensures ret != v.end() +/// +/// @param v std::vector to get iterator from +/// @param index the iterator to locate +/// @return returns the iterator at pos == index, or throws gsl::fail_fast +/// +template < + typename T, + typename A + > +auto +cfind(const std::vector &v, const std::ptrdiff_t index) +{ + // [[ensures ret: ret != v.end()]] + expects(index >= 0 && index < gsl::narrow_cast(v.size())); + + return v.cbegin() + index; +} + +/// Remove +/// +/// Removes an element from the provided vector. This function uses +/// std::vector::erase, and thus, all iterators are invalidated after this +/// function call is made. +/// +/// @expects index >= 0 +/// @expects index < v.size() +/// @ensures +/// +/// @param v std::vector to get iterator from +/// @param index the iterator to locate +/// +template < + typename T, + typename A, + typename I, + typename = std::enable_if::value> + > +void +remove(std::vector &v, const I index) +{ + v.erase(cfind(v, index)); +} + +/// Take +/// +/// Takes an element from the provided vector. This function uses +/// std::vector::erase, and thus, all iterators are invalidated after this +/// function call is made. +/// +/// @expects index >= 0 +/// @expects index < v.size() +/// @ensures +/// +/// @param v std::vector to get iterator from +/// @param index the iterator to locate +/// @return returns the element that was removed +/// +template < + typename T, + typename A, + typename I, + typename = std::enable_if::value> + > +auto +take(std::vector &v, const I index) +{ + const auto iter = cfind(v, index); + auto val = *iter; + + v.erase(iter); + + return val; +} + +} + +#endif diff --git a/payloads/bareflank/include/common.h b/payloads/bareflank/include/common.h new file mode 100644 index 00000000000..f0d314ec60b --- /dev/null +++ b/payloads/bareflank/include/common.h @@ -0,0 +1,176 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef COMMON_H +#define COMMON_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * VMM Status + * + * @return returns the current status of the VMM. + */ +int64_t +common_vmm_status(void); + +/** + * Reset + * + * This function should not be called directly. Instead, use common_unload. + * This is only exposed publically for unit testing. + */ +void +common_reset(void); + +/** + * Initialize Driver Entry + * + * This code should be run as part of the driver entry's init code. This + * sets up some resources that are needed throughout the lifetime of the + * driver entry. + */ +int64_t +common_init(void); + +/** + * Finalize Driver Entry + * + * This code should be run as part of the driver entry's fini code. This + * cleans up some resources that were needed throughout the lifetime of the + * driver entry. + * + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t +common_fini(void); + +/** + * Add Module + * + * Add's a module into memory to be executed once start_vmm is run. This + * function uses the platform functions to allocate memory for the executable. + * The file that is provided should not be removed until after stop_vmm is + * run. Removing the file from memory could cause a crash, as the start_vmm + * function uses the file that is being added to search for symbols that are + * needed, as well as the stop_vmm function. Once stop_vmm is run, it's safe + * to remove the files. Also, this function cannot be run if the vmm has + * already been started. + * + * @param file the file to add to memory + * @param fsize the size of the file in bytes + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t +common_add_module(const char *file, uint64_t fsize); + +/** + * Load VMM + * + * This function loads the vmm (assuming that the modules that were + * loaded are actually a vmm). Once a VMM is loaded, it is placed in memory, + * and all of the modules are properly reloacted such that, code within each + * module is now capable of executing. + * + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t +common_load_vmm(void); + +/** + * Unload VMM + * + * This function unloads the vmm. Once the VMM is unloaded, all of the symbols + * for the VMM are removed from memory, and are no longer accessible. The VMM + * cannot be unloaded unless the VMM is already loaded, but is not running. + * + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t +common_unload_vmm(void); + +/** + * Start VMM + * + * This function starts the vmm. Before the VMM can be started, it must first + * be loaded. + * + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t +common_start_vmm(void); + +/** + * Stop VMM + * + * This function stops the vmm. Before a VMM can be stopped, it must first be + * loaded, and running. + * + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t +common_stop_vmm(void); + +/** + * Dump VMM + * + * This grabs the conents of the debug ring, and dumps the contents to the + * driver entry's console. This is one of a couple of ways to get feedback + * from the VMM. Note that the VMM must at least be loaded for this function + * to work as it has to do a symbol lookup + * + * @param drr a pointer to the drr provided by the user + * @param vcpuid indicates which drr to get as each vcpu has its own drr + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t +common_dump_vmm(struct debug_ring_resources_t **drr, uint64_t vcpuid); + +/** + * Call VMM + * + * Executes the VMM. The VMM has a single entry point, with a switch statement + * that executes the provided "request". When this occurs, arg1 and arg2 are + * provided to the requested function. Note that the first arg takes a cpuid, + * which is the core number you are currently executing on. This is needed + * because this function needs to set up the proper stack before executing + * the VMM, and it needs to know which core you are on to use the proper stack + * which in turn also executes with the proper TLS region. + * + * @param cpuid the core id this code is currently being executed on + * @param request the requested function in the VMM to execute + * @param arg1 arg #1 + * @param arg2 arg #2 + * @return BF_SUCCESS on success, negative error code on failure + */ +int64_t +common_call_vmm(uint64_t cpuid, uint64_t request, uintptr_t arg1, uintptr_t arg2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/payloads/bareflank/platform.c b/payloads/bareflank/platform.c new file mode 100755 index 00000000000..27197fe55a9 --- /dev/null +++ b/payloads/bareflank/platform.c @@ -0,0 +1,86 @@ +/* + * Bareflank Hypervisor + * Copyright (C) 2015 Assured Information Security, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include +#include +#include + + +int platform_info_should_fail = 0; + +int64_t +platform_init(void) +{ return BF_SUCCESS; } + +void * +platform_alloc_rw(uint64_t len) +{ + return memalign(BAREFLANK_PAGE_SIZE, len); +} + +void * +platform_alloc_rwe(uint64_t len) +{ + return memalign(BAREFLANK_PAGE_SIZE, len); +} + +void +platform_free_rw(const void *addr, uint64_t len) +{ + bfignored(len); + free((void *)addr); +} + +void +platform_free_rwe(const void *addr, uint64_t len) +{ + bfignored(len); + free((void *)addr); +} + +void * +platform_virt_to_phys(void *virt) +{ return virt; } + +void * +platform_memset(void *ptr, char value, uint64_t num) +{ return memset(ptr, value, num); } + +void * +platform_memcpy(void *dst, const void *src, uint64_t num) +{ return memcpy(dst, src, num); } + +int64_t +platform_num_cpus(void) +{ return 1; } + +int64_t +platform_call_vmm_on_core( + uint64_t cpuid, uint64_t request, uintptr_t arg1, uintptr_t arg2) +{ + return common_call_vmm(cpuid, request, arg1, arg2); +} + +void * +platform_get_rsdp(void) +{ return 0; } diff --git a/payloads/coreinfo/Makefile b/payloads/coreinfo/Makefile index 50659d3c0b3..c04287c4fc9 100644 --- a/payloads/coreinfo/Makefile +++ b/payloads/coreinfo/Makefile @@ -52,7 +52,7 @@ HOSTCXXFLAGS := -I$(srck) -I$(objk) LIBPAYLOAD_PATH := $(realpath ../libpayload) LIBPAYLOAD_OBJ := $(coreinfo_obj)/libpayload HAVE_LIBPAYLOAD := $(wildcard $(LIBPAYLOAD_OBJ)/lib/libpayload.a) -LIBPAYLOAD_CONFIG ?= configs/defconfig-tinycurses +LIBPAYLOAD_CONFIG ?= configs/defconfig-tinycurses-64 OBJCOPY ?= objcopy INCLUDES = -I$(coreinfo_obj) -include $(LIBPAYLOAD_OBJ)/include/kconfig.h -I$(src)/../../src/commonlib/include @@ -72,7 +72,7 @@ $(if $(wildcard .xcompile),,$(eval $(shell ../../util/xcompile/xcompile $(XGCCPA \mv -f $@.tmp $@ 2> /dev/null || rm -f $@.tmp $@ CONFIG_COMPILER_GCC := y -ARCH-y := x86_32 +ARCH-y := x86_64 include .xcompile diff --git a/payloads/coreinfo/cbfs_module.c b/payloads/coreinfo/cbfs_module.c index e7cfc8ccc60..f980a7a6ca6 100644 --- a/payloads/coreinfo/cbfs_module.c +++ b/payloads/coreinfo/cbfs_module.c @@ -63,7 +63,8 @@ static struct cbheader *header = NULL; static struct cbfile *getfile(struct cbfile *f) { while (1) { - if (f < (struct cbfile *)(0xffffffff - ntohl(header->romsize))) + if (((size_t)f & 0xffffffffULL) < + (size_t)(0xffffffffULL - ntohl(header->romsize))) return NULL; if (f->magic == 0) return NULL; @@ -75,7 +76,7 @@ static struct cbfile *getfile(struct cbfile *f) static struct cbfile *firstfile(void) { - return getfile((void *)(0 - ntohl(header->romsize) + + return getfile((void *)(size_t)(0 - ntohl(header->romsize) + ntohl(header->offset))); } @@ -101,7 +102,7 @@ static int cbfs_module_init(void) struct cbfile *f; int index = 0; - header = *(void **)HEADER_ADDR; + header = (void *)(size_t)(*(u32 *)HEADER_ADDR); if (header->magic != ntohl(HEADER_MAGIC)) { header = NULL; return 0; diff --git a/payloads/coreinfo/cpuid.S b/payloads/coreinfo/cpuid.S index d98bd2c304c..63118305385 100644 --- a/payloads/coreinfo/cpuid.S +++ b/payloads/coreinfo/cpuid.S @@ -24,6 +24,7 @@ .type docpuid,@function docpuid: +.if 0 pushl %ebp movl %esp, %ebp pushl %edi @@ -59,5 +60,31 @@ L4: popl %edx movl %ebp,%esp popl %ebp ret +.else +.code64 + movq %rcx,%r9 + movq %rdx,%r10 + movq %rbx,%r11 + movq %rdi,%rax + cpuid + test %rsi,%rsi + jz L1 + movl %eax, (%rsi) + +L1: test %r10,%r10 + jz L2 + movl %ebx,(%r10) + +L2: test %r9,%r9 + jz L3 + movl %ecx,(%r9) + +L3: test %r8,%r8 + jz L4 + movl %edx,(%r8) + +L4: movq %r11,%rbx + ret +.endif .section .note.GNU-stack,"", @progbits diff --git a/payloads/coreinfo/ramdump_module.c b/payloads/coreinfo/ramdump_module.c index 28d7a0381a4..662af7c65e4 100644 --- a/payloads/coreinfo/ramdump_module.c +++ b/payloads/coreinfo/ramdump_module.c @@ -25,7 +25,7 @@ static int ramdump_module_init(void) return 0; } -static void dump_ram(WINDOW *win, uint32_t addr, int row, int col) +static void dump_ram(WINDOW *win, size_t addr, int row, int col) { int i, x = 0, y = 0, count = 0; volatile uint8_t *ptr = (void *)(addr); diff --git a/payloads/external/Makefile.inc b/payloads/external/Makefile.inc index 5edbb81b187..60206b0c627 100644 --- a/payloads/external/Makefile.inc +++ b/payloads/external/Makefile.inc @@ -47,6 +47,17 @@ ifneq ($(strip $(call strip_quotes,$(CONFIG_PAYLOAD_OPTIONS))),) ADDITIONAL_PAYLOAD_CONFIG+=$(strip $(call strip_quotes,$(CONFIG_PAYLOAD_OPTIONS))) endif +ifeq ($(CONFIG_BAREFLANK_SECONDARY_PAYLOAD),y) +cbfs-files-y += $(CONFIG_CBFS_PREFIX)/realpayload +$(CONFIG_CBFS_PREFIX)/realpayload-file := $(CONFIG_PAYLOAD_FILE) +ifeq ($(CONFIG_PAYLOAD_IS_FLAT_BINARY),y) +$(CONFIG_CBFS_PREFIX)/realpayload-type := flat-binary +else +$(CONFIG_CBFS_PREFIX)/realpayload-type := payload +endif +$(CONFIG_CBFS_PREFIX)/realpayload-compression := $(CBFS_PAYLOAD_COMPRESS_FLAG) +$(CONFIG_CBFS_PREFIX)/realpayload-options := $(ADDITIONAL_PAYLOAD_CONFIG) +else cbfs-files-y += $(CONFIG_CBFS_PREFIX)/payload $(CONFIG_CBFS_PREFIX)/payload-file := $(CONFIG_PAYLOAD_FILE) ifeq ($(CONFIG_PAYLOAD_IS_FLAT_BINARY),y) @@ -56,6 +67,7 @@ $(CONFIG_CBFS_PREFIX)/payload-type := payload endif $(CONFIG_CBFS_PREFIX)/payload-compression := $(CBFS_PAYLOAD_COMPRESS_FLAG) $(CONFIG_CBFS_PREFIX)/payload-options := $(ADDITIONAL_PAYLOAD_CONFIG) +endif cbfs-files-$(CONFIG_INCLUDE_CONFIG_FILE) += payload_config payload_config-file := $(PAYLOAD_CONFIG) diff --git a/payloads/libpayload/arch/x86_64/Makefile.inc b/payloads/libpayload/arch/x86_64/Makefile.inc index 4626241c428..7544ee2799c 100644 --- a/payloads/libpayload/arch/x86_64/Makefile.inc +++ b/payloads/libpayload/arch/x86_64/Makefile.inc @@ -28,15 +28,14 @@ ## # x64 needs at least 16 bytes (PSB=4, default) -CFLAGS += -mpreferred-stack-boundary=4 +CFLAGS += -mpreferred-stack-boundary=4 -mno-red-zone head.o-y += head.S libc-y += main.c sysinfo.c libc-y += timer.c coreboot.c util.S libc-y += virtual.c exec.S libc-y += selfboot.c -# TODO: -#libc-y += exception_asm.S exception.c +libc-y += exception_asm.S exception.c libc-y += delay.c # Will fall back to default_memXXX() in libc/memory.c if GPL not allowed. diff --git a/payloads/libpayload/arch/x86_64/exception.c b/payloads/libpayload/arch/x86_64/exception.c index 13ff58ccbe4..f3d70759c40 100644 --- a/payloads/libpayload/arch/x86_64/exception.c +++ b/payloads/libpayload/arch/x86_64/exception.c @@ -35,7 +35,7 @@ #define IF_FLAG (1 << 9) -u32 exception_stack[0x400] __attribute__((aligned(8))); +u64 exception_stack[0x400] __attribute__((aligned(8))); static interrupt_handler handlers[256]; @@ -61,9 +61,9 @@ static const char *names[EXC_COUNT] = { [EXC_SX] = "Security", }; -static void print_segment_error_code(u32 code) +static void print_segment_error_code(u64 code) { - printf("%#x - descriptor %#x in the ", code, (code >> 3) & 0x1FFF); + printf("%#llx - descriptor %#llx in the ", code, (code >> 3) & 0x1FFF); if (code & (0x1 << 1)) { printf("IDT"); } else { @@ -78,9 +78,9 @@ static void print_segment_error_code(u32 code) printf(", internal to the CPU"); } -static void print_page_fault_error_code(u32 code) +static void print_page_fault_error_code(u64 code) { - printf("%#x -", code); + printf("%#llx -", code); if (code & (0x1 << 0)) printf(" page protection"); else @@ -99,22 +99,22 @@ static void print_page_fault_error_code(u32 code) printf(", instruction fetch"); } -static void print_raw_error_code(u32 code) +static void print_raw_error_code(u64 code) { - printf("%#x", code); + printf("%#llx", code); } static void dump_stack(uintptr_t addr, size_t bytes) { int i, j; - const int line = 8; - uint32_t *ptr = (uint32_t *)(addr & ~(line * sizeof(*ptr) - 1)); + const int line = 4; + u64 *ptr = (u64 *)(addr & ~(line * sizeof(*ptr) - 1)); printf("Dumping stack:\n"); for (i = bytes / sizeof(*ptr); i >= 0; i -= line) { printf("%p: ", ptr + i); for (j = i; j < i + line; j++) - printf("%08x ", *(ptr + j)); + printf("%016llx ", *(ptr + j)); printf("\n"); } } @@ -144,28 +144,36 @@ static void dump_exception_state(void) break; } printf("\n"); - printf("EIP: 0x%08x\n", exception_state->regs.eip); - printf("CS: 0x%04x\n", exception_state->regs.cs); - printf("EFLAGS: 0x%08x\n", exception_state->regs.eflags); - printf("EAX: 0x%08x\n", exception_state->regs.eax); - printf("ECX: 0x%08x\n", exception_state->regs.ecx); - printf("EDX: 0x%08x\n", exception_state->regs.edx); - printf("EBX: 0x%08x\n", exception_state->regs.ebx); - printf("ESP: 0x%08x\n", exception_state->regs.esp); - printf("EBP: 0x%08x\n", exception_state->regs.ebp); - printf("ESI: 0x%08x\n", exception_state->regs.esi); - printf("EDI: 0x%08x\n", exception_state->regs.edi); - printf("DS: 0x%04x\n", exception_state->regs.ds); - printf("ES: 0x%04x\n", exception_state->regs.es); - printf("SS: 0x%04x\n", exception_state->regs.ss); - printf("FS: 0x%04x\n", exception_state->regs.fs); - printf("GS: 0x%04x\n", exception_state->regs.gs); + printf("RIP: 0x%016llx\n", exception_state->regs.rip); + printf("CS: 0x%04llx\n", exception_state->regs.cs); + printf("RFLAGS: 0x%016llx\n", exception_state->regs.rflags); + printf("RAX: 0x%016llx\n", exception_state->regs.rax); + printf("RCX: 0x%016llx\n", exception_state->regs.rcx); + printf("RDX: 0x%016llx\n", exception_state->regs.rdx); + printf("RBX: 0x%016llx\n", exception_state->regs.rbx); + printf("RSP: 0x%016llx\n", exception_state->regs.rsp); + printf("RBP: 0x%016llx\n", exception_state->regs.rbp); + printf("RSI: 0x%016llx\n", exception_state->regs.rsi); + printf("RDI: 0x%016llx\n", exception_state->regs.rdi); + printf("R8: 0x%016llx\n", exception_state->regs.r8); + printf("R9: 0x%016llx\n", exception_state->regs.r9); + printf("R10: 0x%016llx\n", exception_state->regs.r10); + printf("R11: 0x%016llx\n", exception_state->regs.r11); + printf("R12: 0x%016llx\n", exception_state->regs.r12); + printf("R13: 0x%016llx\n", exception_state->regs.r13); + printf("R14: 0x%016llx\n", exception_state->regs.r14); + printf("R15: 0x%016llx\n", exception_state->regs.r15); + printf("DS: 0x%04llx\n", exception_state->regs.ds); + printf("ES: 0x%04llx\n", exception_state->regs.es); + printf("SS: 0x%04llx\n", exception_state->regs.ss); + printf("FS: 0x%04llx\n", exception_state->regs.fs); + printf("GS: 0x%04llx\n", exception_state->regs.gs); } void exception_dispatch(void) { die_if(exception_state->vector >= ARRAY_SIZE(handlers), - "Invalid vector %u\n", exception_state->vector); + "Invalid vector %llu\n", exception_state->vector); u8 vec = exception_state->vector; @@ -185,7 +193,7 @@ void exception_dispatch(void) vec); dump_exception_state(); - dump_stack(exception_state->regs.esp, 512); + dump_stack(exception_state->regs.rsp, 512); /* We don't call apic_eoi because we don't want to ack the interrupt and allow another interrupt to wake the processor. */ halt(); @@ -207,14 +215,14 @@ void set_interrupt_handler(u8 vector, interrupt_handler handler) handlers[vector] = handler; } -static uint32_t eflags(void) +static u64 rflags(void) { - uint32_t eflags; + u64 rflags; asm volatile( "pushf\n\t" "pop %0\n\t" - : "=rm" (eflags)); - return eflags; + : "=rm" (rflags)); + return rflags; } void enable_interrupts(void) @@ -234,5 +242,5 @@ void disable_interrupts(void) int interrupts_enabled(void) { - return !!(eflags() & IF_FLAG); + return !!(rflags() & IF_FLAG); } diff --git a/payloads/libpayload/arch/x86_64/exception_asm.S b/payloads/libpayload/arch/x86_64/exception_asm.S index 00dc888207d..a14742870a3 100644 --- a/payloads/libpayload/arch/x86_64/exception_asm.S +++ b/payloads/libpayload/arch/x86_64/exception_asm.S @@ -27,25 +27,29 @@ * SUCH DAMAGE. */ - .align 4 + .align 16 .global exception_stack_end exception_stack_end: - .long 0 + .quad 0 .global exception_state exception_state: - .long 0 + .quad 0 /* Some temporary variables which are used while saving exception state. */ vector: - .long 0 + .quad 0 error_code: - .long 0 -old_esp: - .long 0 -old_eax: - .long 0 + .quad 0 +old_rsp: + .quad 0 +old_rax: + .quad 0 +old_rdx: + .quad 0 - .align 8 + .align 16 + +.code64 /* * Each exception vector has a small stub associated with it which sets aside @@ -56,15 +60,15 @@ old_eax: .macro stub num exception_stub_\num: - movl $0, error_code - movl $\num, vector + movq $0, error_code + movq $\num, vector jmp exception_common .endm .macro stub_err num exception_stub_\num: - popl error_code - movl $\num, vector + popq error_code + movq $\num, vector jmp exception_common .endm @@ -120,34 +124,48 @@ exception_common: * exception stack. eax points to the old stack which has the * exception ip, cs, and flags. */ - mov %esp, old_esp - addl $12, old_esp - mov %eax, old_eax - mov %esp, %eax - mov exception_stack_end, %esp + movq %rax, old_rax + movq 24(%rsp), %rax + movq %rax, old_rsp + movq %rdx, old_rdx + movq %rsp, %rax + movq exception_stack_end, %rsp /* * Push values onto the top of the exception stack to form an * exception state structure. */ - pushl vector - pushl error_code - pushl %gs - pushl %fs - pushl %es - pushl %ds - pushl %ss - pushl 4(%eax) - pushl 8(%eax) - pushl (%eax) - pushl %edi - pushl %esi - pushl %ebp - pushl old_esp - pushl %ebx - pushl %edx - pushl %ecx - pushl old_eax + pushq vector + pushq error_code + mov %gs, %rdx + pushq %rdx + mov %fs, %rdx + pushq %rdx + mov %es, %rdx + pushq %rdx + mov %ds, %rdx + pushq %rdx + mov %ss, %rdx + pushq %rdx + pushq 8(%rax) + pushq 16(%rax) + pushq (%rax) + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rdi + pushq %rsi + pushq %rbp + pushq old_rsp + pushq %rbx + pushq old_rdx + pushq %rcx + pushq old_rax /* * Call the C exception handler. It will find the exception state @@ -155,68 +173,54 @@ exception_common: * passing parameters means we don't have to worry about what ABI * is being used. */ - mov %esp, exception_state + movq %rsp, exception_state call exception_dispatch /* * Restore state from the exception state structure, including any * changes that might have been made. */ - popl old_eax - popl %ecx - popl %edx - popl %ebx - popl old_esp + popq old_rax + popq %rcx + popq old_rdx + popq %rbx + popq old_rsp - mov old_esp, %eax - subl $12, %eax + movq old_rsp, %rax + andq $~(0xf), %rax + subq $40, %rax - popl %ebp - popl %esi - popl %edi - popl (%eax) - popl 8(%eax) - popl 4(%eax) - popl %ss - popl %ds - popl %es - popl %fs - popl %gs + popq %rbp + popq %rsi + popq %rdi + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + popq (%rax) + popq 16(%rax) + popq 8(%rax) + popq %rdx + mov %rdx, %ss + popq %rdx + mov %rdx, %ds + popq %rdx + mov %rdx, %es + popq %rdx + mov %rdx, %fs + popq %rdx + mov %rdx, %gs - mov %eax, %esp - mov old_eax, %eax + movq %rax, %rsp + movq old_rax, %rax + movq old_rdx, %rdx /* Return from the exception. */ - iretl - -/* - * We need segment selectors for the IDT, so we need to know where things are - * in the GDT. We set one up here which is pretty standard and largely copied - * from coreboot. - */ - .align 8 -gdt: - /* selgdt 0, unused */ - .word 0x0000, 0x0000 - .byte 0x00, 0x00, 0x00, 0x00 - - /* selgdt 8, unused */ - .word 0x0000, 0x0000 - .byte 0x00, 0x00, 0x00, 0x00 - - /* selgdt 0x10, flat 4GB code segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x9b, 0xcf, 0x00 - - /* selgdt 0x18, flat 4GB data segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x93, 0xcf, 0x00 -gdt_end: - -/* GDT pointer for use with lgdt */ -gdt_ptr: - .word gdt_end - gdt - 1 - .long gdt + iretq /* * Record the target and construct the actual entry at init time. This @@ -224,8 +228,8 @@ gdt_ptr: * for us. */ .macro interrupt_gate target - .long \target - .long \target + .quad \target + .quad \target .endm .altmacro @@ -280,42 +284,34 @@ idt_end: /* IDT pointer for use with lidt */ idt_ptr: .word idt_end - idt - 1 - .long idt + .quad idt .global exception_init_asm exception_init_asm: - /* Save eax so we can use it as a temporary variable. */ - pushl %eax - - /* Install the GDT. */ - lgdt gdt_ptr - /* Load the segment registers from it. */ - ljmp $0x10, $1f -1: movl $0x18, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - movl %eax, %fs - movl %eax, %gs - /* * Loop over the entries which start out as two copies of the target * address. We can turn them into real interrupt gates by selectively * replacing certain bit fields. */ - movl $idt, %eax + movq $idt, %rax + movq $0x00008e0000180000, %rcx 1: - andl $0x0000ffff, (%eax) - orl $0x00100000, (%eax) - andl $0xffff0000, 4(%eax) - orl $0x0000ee00, 4(%eax) - addl $8, %eax - cmp $idt_end, %eax + movq (%rax), %rdi + movq %rdi, %rsi + movq %rdi, %rdx + andl $0xffff0000, %esi + shlq $32, %rsi + andq $0x0000ffff, %rdx + orq %rdx, %rsi + orq %rcx, %rsi + movq %rsi, (%rax) + shrq $32, %rdi + movq %rdi, 8(%rax) + addq $16, %rax + cmpq $idt_end, %rax jne 1b /* Install the IDT. */ lidt idt_ptr - /* Restore eax and return to the caller. */ - popl %eax ret diff --git a/payloads/libpayload/arch/x86_64/main.c b/payloads/libpayload/arch/x86_64/main.c index 3c1edd0201b..2e876f23e9c 100644 --- a/payloads/libpayload/arch/x86_64/main.c +++ b/payloads/libpayload/arch/x86_64/main.c @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ -//#include +#include #include #include @@ -56,15 +56,13 @@ int start_main(void) console_init(); #endif - // TODO: -/* exception_init(); + exception_init(); if (CONFIG(LP_ENABLE_APIC)) { apic_init(); enable_interrupts(); } -*/ /* * Any other system init that has to happen before the diff --git a/payloads/libpayload/include/x86_64/arch/exception.h b/payloads/libpayload/include/x86_64/arch/exception.h index a6c2afcf0d7..8fe92ff2961 100644 --- a/payloads/libpayload/include/x86_64/arch/exception.h +++ b/payloads/libpayload/include/x86_64/arch/exception.h @@ -43,30 +43,38 @@ struct exception_state { /* Careful: x86/gdb.c currently relies on the size and order of regs. */ struct { - u32 eax; - u32 ecx; - u32 edx; - u32 ebx; - u32 esp; - u32 ebp; - u32 esi; - u32 edi; - u32 eip; - u32 eflags; - u32 cs; - u32 ss; - u32 ds; - u32 es; - u32 fs; - u32 gs; + u64 rax; + u64 rcx; + u64 rdx; + u64 rbx; + u64 rsp; + u64 rbp; + u64 rsi; + u64 rdi; + u64 r8; + u64 r9; + u64 r10; + u64 r11; + u64 r12; + u64 r13; + u64 r14; + u64 r15; + u64 rip; + u64 rflags; + u64 cs; + u64 ss; + u64 ds; + u64 es; + u64 fs; + u64 gs; } regs; - u32 error_code; - u32 vector; + u64 error_code; + u64 vector; } __packed; extern struct exception_state *exception_state; -extern u32 exception_stack[]; -extern u32 *exception_stack_end; +extern u64 exception_stack[]; +extern u64 *exception_stack_end; enum { EXC_DE = 0, /* Divide by zero */ diff --git a/src/lib/bootmem.c b/src/lib/bootmem.c index 01ad3e841bf..02727d74123 100644 --- a/src/lib/bootmem.c +++ b/src/lib/bootmem.c @@ -96,6 +96,28 @@ static void bootmem_init(void) bootmem_arch_add_ranges(); bootmem_platform_add_ranges(); + + if (CONFIG_CUSTOM_RAM_RES_SIZE != 0) { + const struct range_entry *r; + size_t start = CONFIG_CUSTOM_RAM_RES_ADDR; + size_t end = CONFIG_CUSTOM_RAM_RES_ADDR + CONFIG_CUSTOM_RAM_RES_SIZE; + memranges_each_entry(r, bm) { + /* All further bootmem entries are beyond this range. */ + if (end <= range_entry_base(r)) + break; + + if (start >= range_entry_base(r) && end <= range_entry_end(r)) { + if (range_entry_tag(r) == BM_MEM_RAM) { + bootmem_add_range(CONFIG_CUSTOM_RAM_RES_ADDR, + CONFIG_CUSTOM_RAM_RES_SIZE, BM_MEM_RESERVED); + return; + } + } + } + printk(BIOS_ERR, "ERROR: Tried to reserve memory %lx - %lx," + " but it is not RAM\n", start, end); + die("Check CUSTOM_RAM_RES_ADDR and CUSTOM_RAM_RES_ADDR\n"); + } } void bootmem_add_range(uint64_t start, uint64_t size, diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c index 9aa47413c5c..19f223428d4 100644 --- a/src/lib/selfboot.c +++ b/src/lib/selfboot.c @@ -46,6 +46,17 @@ static void cbfs_decode_payload_segment(struct cbfs_payload_segment *segment, segment->mem_len = read_be32(&src->mem_len); } +static int payload_target_custom_reserved_ram(uint64_t start, uint64_t size) +{ + if (start >= CONFIG_CUSTOM_RAM_RES_ADDR && + (start + size) <= (CONFIG_CUSTOM_RAM_RES_ADDR + CONFIG_CUSTOM_RAM_RES_SIZE)) { + printk(BIOS_DEBUG, "Payload being loaded in reserved memory.\n"); + return 1; + } + + return 0; +} + static int segment_targets_type(void *dest, unsigned long memsz, enum bootmem_type dest_type) { @@ -56,6 +67,9 @@ static int segment_targets_type(void *dest, unsigned long memsz, if (payload_arch_usable_ram_quirk(d, memsz)) return 1; + if (payload_target_custom_reserved_ram(d, memsz)) + return 1; + printk(BIOS_ERR, "SELF segment doesn't target RAM: 0x%p, %lu bytes\n", dest, memsz); bootmem_dump_ranges(); return 0;