diff --git a/build/jam/ArchitectureRules b/build/jam/ArchitectureRules index 274789f506..03a6f3b000 100644 --- a/build/jam/ArchitectureRules +++ b/build/jam/ArchitectureRules @@ -284,7 +284,7 @@ rule KernelArchitectureSetup architecture HAIKU_BOOT_ARCHIVE_IMAGE_OFFSET = 192 ; # in kB - unused yet case x86 : - HAIKU_BOOT_PLATFORM = bios_ia32 ; + HAIKU_BOOT_PLATFORM ?= bios_ia32 ; HAIKU_BOOT_FLOPPY_IMAGE_SIZE = 2880 ; # in kB # offset in floppy image (>= sizeof(haiku_loader)) HAIKU_BOOT_ARCHIVE_IMAGE_OFFSET = 320 ; # in kB @@ -296,7 +296,7 @@ rule KernelArchitectureSetup architecture case x86_64 : # x86_64 completely shares the x86 bootloader. - HAIKU_BOOT_PLATFORM = bios_ia32 ; + HAIKU_BOOT_PLATFORM ?= bios_ia32 ; HAIKU_BOOT_FLOPPY_IMAGE_SIZE = 2880 ; # in kB # offset in floppy image (>= sizeof(haiku_loader)) HAIKU_BOOT_ARCHIVE_IMAGE_OFFSET = 320 ; # in kB @@ -331,12 +331,6 @@ rule KernelArchitectureSetup architecture Exit "Currently unsupported target CPU:" $(cpu) ; } - # Include embedded board-specific file. - if $(HAIKU_BOOT_BOARD) { - include [ FDirName $(HAIKU_BUILD_RULES_DIR) board $(HAIKU_BOOT_BOARD) - BoardSetup ] ; - } - # private kernel headers to be used when compiling kernel code HAIKU_PRIVATE_KERNEL_HEADERS = [ PrivateHeaders $(DOT) kernel libroot shared @@ -366,6 +360,7 @@ rule KernelArchitectureSetup architecture HAIKU_BOOT_CCFLAGS = $(HAIKU_CCFLAGS_$(architecture)) $(gccBaseFlags) ; HAIKU_BOOT_C++FLAGS = $(HAIKU_C++FLAGS_$(architecture)) $(g++BaseFlags) ; HAIKU_BOOT_LINKFLAGS = ; + HAIKU_BOOT_LDFLAGS = -Bstatic ; if $(gccVersion[1]) >= 4 { HAIKU_KERNEL_C++FLAGS += -std=gnu++11 ; @@ -375,6 +370,16 @@ rule KernelArchitectureSetup architecture HAIKU_KERNEL_PIC_LINKFLAGS = ; HAIKU_KERNEL_ADDON_LINKFLAGS = ; + # Include embedded board-specific file. + if $(HAIKU_BOOT_BOARD) { + include [ FDirName $(HAIKU_BUILD_RULES_DIR) board $(HAIKU_BOOT_BOARD) + BoardSetup ] ; + if $(HAIKU_BOARD_LOADER_BASE) { + HAIKU_BOOT_LDFLAGS += + --defsym BOARD_LOADER_BASE=$(HAIKU_BOARD_LOADER_BASE) ; + } + } + switch $(cpu) { case ppc : # Build a position independent PPC kernel. We need to be able to @@ -406,10 +411,23 @@ rule KernelArchitectureSetup architecture HAIKU_KERNEL_PIC_LINKFLAGS += -z max-page-size=0x1000 ; HAIKU_KERNEL_ADDON_LINKFLAGS += -z max-page-size=0x1000 ; - # Bootloader is 32-bit. - HAIKU_BOOT_LINKFLAGS += -m elf_i386_haiku ; - HAIKU_BOOT_CCFLAGS += -m32 -march=pentium ; - HAIKU_BOOT_C++FLAGS += -m32 -march=pentium ; + # BIOS Bootloader is 32-bit. + if $(HAIKU_BOOT_PLATFORM) = bios_ia32 { + HAIKU_BOOT_LINKFLAGS += -m elf_i386_haiku ; + HAIKU_BOOT_CCFLAGS += -m32 -march=pentium ; + HAIKU_BOOT_C++FLAGS += -m32 -march=pentium ; + } + } + + if $(HAIKU_BOOT_PLATFORM) = efi { + HAIKU_BOOT_CCFLAGS += -fpic -fno-stack-protector -fPIC -fshort-wchar -mno-red-zone + -maccumulate-outgoing-args -Wno-error=unused-variable ; + HAIKU_BOOT_C++FLAGS += -fpic -fno-stack-protector -fPIC -fshort-wchar -mno-red-zone + -maccumulate-outgoing-args -Wno-error=unused-variable ; + HAIKU_BOOT_LDFLAGS = -Bstatic -Bsymbolic -shared -nostdlib -znocombreloc -nostartfiles -no-undefined ; + } else { + HAIKU_BOOT_CCFLAGS += -fno-pic ; + HAIKU_BOOT_C++FLAGS += -fno-pic ; } # warning flags diff --git a/build/jam/BootRules b/build/jam/BootRules index 63efcc5237..f369eadc1e 100644 --- a/build/jam/BootRules +++ b/build/jam/BootRules @@ -47,7 +47,7 @@ rule BootLd LINK on $(1) = $(TARGET_LD_$(TARGET_PACKAGING_ARCH)) ; - LINKFLAGS on $(1) = $(4) ; + LINKFLAGS on $(1) = $(TARGET_BOOT_LINKFLAGS) $(4) ; if $(3) { LINKFLAGS on $(1) += --script=$(3) ; } # Remove any preset LINKLIBS, but link against libgcc.a. Linking against diff --git a/build/jam/BuildFeatures b/build/jam/BuildFeatures index 660ee579d0..4312be0371 100644 --- a/build/jam/BuildFeatures +++ b/build/jam/BuildFeatures @@ -624,6 +624,23 @@ if [ IsPackageAvailable expat_devel ] { } +# gnu-efi +if $(TARGET_PACKAGING_ARCH) = x86_64 { + if [ IsPackageAvailable gnuefi ] { + ExtractBuildFeatureArchives gnuefi : + file: base gnuefi + headers: $(developHeadersDir)/gnuefi + headersProtocol: $(developHeadersDir)/gnuefi/protocol + headersArch: $(developHeadersDir)/gnuefi/$(TARGET_ARCH) + libdir: $(libDir)/gnuefi + ; + + EnableBuildFeatures gnuefi ; + } else { + Echo "gnuefi support not available on $(TARGET_PACKAGING_ARCH)" ; + } +} + # GPL add-ons if $(HAIKU_INCLUDE_GPL_ADDONS) = 1 { EnableBuildFeatures gpl ; diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index 0781dd44ef..8ca886bdfd 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -650,7 +650,7 @@ local buildVars = KERNEL_CCFLAGS KERNEL_C++FLAGS KERNEL_PIC_CCFLAGS KERNEL_PIC_LINKFLAGS KERNEL_ADDON_LINKFLAGS - BOOT_CCFLAGS BOOT_C++FLAGS BOOT_LINKFLAGS + BOOT_CCFLAGS BOOT_C++FLAGS BOOT_LINKFLAGS BOOT_LDFLAGS KERNEL_WARNING_CCFLAGS KERNEL_WARNING_C++FLAGS diff --git a/headers/private/kernel/arch/x86/arch_kernel_args.h b/headers/private/kernel/arch/x86/arch_kernel_args.h index ae418f187c..011bdf0e6f 100644 --- a/headers/private/kernel/arch/x86/arch_kernel_args.h +++ b/headers/private/kernel/arch/x86/arch_kernel_args.h @@ -38,6 +38,8 @@ typedef struct { // hpet stuff uint32 hpet_phys; FixedWidthPointer hpet; + // needed for UEFI, otherwise kernel acpi support can't find ACPI root + FixedWidthPointer acpi_root; } _PACKED arch_kernel_args; #endif /* KERNEL_ARCH_x86_KERNEL_ARGS_H */ diff --git a/headers/private/kernel/boot/partitions.h b/headers/private/kernel/boot/partitions.h index 24ef1690c3..908d00719c 100644 --- a/headers/private/kernel/boot/partitions.h +++ b/headers/private/kernel/boot/partitions.h @@ -30,6 +30,8 @@ class Partition : public Node, public partition_data { status_t Mount(Directory **_fileSystem = NULL, bool isBootDevice = false); status_t Scan(bool mountFileSystems, bool isBootDevice = false); + static Partition *Lookup(partition_id id, NodeList *list = NULL); + void SetParent(Partition *parent); Partition *Parent() const; diff --git a/headers/private/kernel/boot/platform.h b/headers/private/kernel/boot/platform.h index 9f3c8eb637..7d3afda1a3 100644 --- a/headers/private/kernel/boot/platform.h +++ b/headers/private/kernel/boot/platform.h @@ -28,6 +28,8 @@ extern status_t platform_init_heap(struct stage2_args *args, void **_base, void extern status_t platform_allocate_region(void **_virtualAddress, size_t size, uint8 protection, bool exactAddress); extern status_t platform_free_region(void *address, size_t size); +extern status_t platform_bootloader_address_to_kernel_address(void *address, uint64_t *_result); +extern status_t platform_kernel_address_to_bootloader_address(uint64_t address, void **_result); /* boot options */ #define BOOT_OPTION_MENU 1 diff --git a/headers/private/kernel/boot/platform/efi/platform_kernel_args.h b/headers/private/kernel/boot/platform/efi/platform_kernel_args.h new file mode 100644 index 0000000000..4ad0453a73 --- /dev/null +++ b/headers/private/kernel/boot/platform/efi/platform_kernel_args.h @@ -0,0 +1,46 @@ +/* + * Copyright 2013-2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_BOOT_PLATFORM_EFI_KERNEL_ARGS_H +#define KERNEL_BOOT_PLATFORM_EFI_KERNEL_ARGS_H + + +#ifndef KERNEL_BOOT_KERNEL_ARGS_H +# error This file is included from only +#endif + +// currently the EFI loader pretends to be the bios_ia32 platform. +// not quite right, as the kernel needs to be aware of efi runtime services + +#include +#include +#include + + +#define SMP_MAX_CPUS 64 + +#define MAX_PHYSICAL_MEMORY_RANGE 32 +#define MAX_PHYSICAL_ALLOCATED_RANGE 32 +#define MAX_VIRTUAL_ALLOCATED_RANGE 32 + +#define MAX_SERIAL_PORTS 4 + +typedef struct bios_drive { + struct bios_drive *next; + uint16 drive_number; + disk_identifier identifier; +} bios_drive; + +typedef struct { + uint16 serial_base_ports[MAX_SERIAL_PORTS]; + + FixedWidthPointer drives; + // this does not contain the boot drive + // seems to be ignored entirely? + + apm_info apm; +} _PACKED platform_kernel_args; + + +#endif /* KERNEL_BOOT_PLATFORM_BIOS_IA32_KERNEL_ARGS_H */ diff --git a/headers/private/kernel/boot/platform/efi/platform_stage2_args.h b/headers/private/kernel/boot/platform/efi/platform_stage2_args.h new file mode 100644 index 0000000000..ef2f2ed40e --- /dev/null +++ b/headers/private/kernel/boot/platform/efi/platform_stage2_args.h @@ -0,0 +1,17 @@ +/* + * Copyright 2013-2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_BOOT_PLATFORM_EFI_STAGE2_ARGS_H +#define _KERNEL_BOOT_PLATFORM_EFI_STAGE2_ARGS_H + + +#ifndef KERNEL_BOOT_STAGE2_ARGS_H +# error This file is included from only +#endif + +struct platform_stage2_args { +}; + + +#endif /* _KERNEL_BOOT_PLATFORM_EFI_STAGE2_ARGS_H */ diff --git a/src/add-ons/kernel/bus_managers/acpi/ACPICAHaiku.cpp b/src/add-ons/kernel/bus_managers/acpi/ACPICAHaiku.cpp index 00a05b7391..90bbb79e86 100644 --- a/src/add-ons/kernel/bus_managers/acpi/ACPICAHaiku.cpp +++ b/src/add-ons/kernel/bus_managers/acpi/ACPICAHaiku.cpp @@ -127,6 +127,7 @@ # include # include +# include # include # include #endif @@ -181,7 +182,7 @@ extern void *gDPCHandle; extern FILE *AcpiGbl_DebugFile; FILE *AcpiGbl_OutputFile; -static uint32 sACPIRoot = 0; +static ACPI_PHYSICAL_ADDRESS sACPIRoot = 0; static void *sInterruptHandlerData[32]; @@ -233,12 +234,15 @@ AcpiOsGetRootPointer() { #ifdef _KERNEL_MODE ACPI_PHYSICAL_ADDRESS address; - ACPI_STATUS status; + ACPI_STATUS status = AE_OK; DEBUG_FUNCTION(); if (sACPIRoot == 0) { - status = AcpiFindRootPointer(&address); - if (status == AE_OK) - sACPIRoot = address; + sACPIRoot = (ACPI_PHYSICAL_ADDRESS)get_boot_item("ACPI_ROOT_POINTER", NULL); + if (sACPIRoot == 0) { + status = AcpiFindRootPointer(&address); + if (status == AE_OK) + sACPIRoot = address; + } } return sACPIRoot; #else diff --git a/src/system/boot/Jamfile b/src/system/boot/Jamfile index e751743336..6e98fe4efe 100644 --- a/src/system/boot/Jamfile +++ b/src/system/boot/Jamfile @@ -1,9 +1,17 @@ SubDir HAIKU_TOP src system boot ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + DEFINES += _BOOT_MODE ; -SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) libroot os arch - $(TARGET_KERNEL_ARCH) ] ; +if $(TARGET_ARCH) = x86_64 && $(TARGET_BOOT_PLATFORM) != bios_ia32 { + SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) libroot os arch + x86_64 ] ; +} else { + SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) libroot os arch + $(TARGET_KERNEL_ARCH) ] ; +} + SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) libroot posix string ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) libroot posix stdlib ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) libroot posix locale ] ; @@ -41,14 +49,8 @@ BootMergeObject boot_libroot.o : strrchr.c strtol.c $(extraSources) - : -fno-pic ; -local extraLinkerArgs = ; -if $(HAIKU_BOARD_LOADER_BASE) { - extraLinkerArgs += --defsym BOARD_LOADER_BASE=$(HAIKU_BOARD_LOADER_BASE) ; -} - AddResources haiku_loader : boot_loader.rdef ; BootLd boot_loader_$(TARGET_BOOT_PLATFORM) : @@ -76,7 +78,7 @@ BootLd boot_loader_$(TARGET_BOOT_PLATFORM) : boot_libroot.o : $(HAIKU_TOP)/src/system/ldscripts/$(TARGET_ARCH)/boot_loader_$(TARGET_BOOT_PLATFORM).ld - : -Bstatic $(extraLinkerArgs) + : $(TARGET_BOOT_LDFLAGS) ; rule BuildCoffLoader { @@ -130,6 +132,22 @@ BuildBiosLoader haiku_loader : boot_loader_$(TARGET_BOOT_PLATFORM) ; # different target for PXE, to be build with TARGET_BOOT_PLATFORM=pxe_ia32 jam pxehaiku-loader BuildBiosLoader pxehaiku-loader : boot_loader_$(TARGET_BOOT_PLATFORM) ; +rule BuildEFILoader { + local efiLoader = $(1) ; + local bootLoader = $(2) ; + + Depends $(efiLoader) : $(bootLoader) ; + MakeLocateDebug $(efiLoader) ; +} + +actions BuildEFILoader { + rm -f $(1) + $(TARGET_OBJCOPY_$(TARGET_PACKAGING_ARCH)) -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ + -j .rel -j .rela -j .reloc --target=efi-app-x86_64 $(2) $(1) +} + +BuildEFILoader haiku_loader.efi : boot_loader_$(TARGET_BOOT_PLATFORM) ; + SubInclude HAIKU_TOP src system boot arch $(TARGET_KERNEL_ARCH) ; SubInclude HAIKU_TOP src system boot loader ; SubInclude HAIKU_TOP src system boot platform ; diff --git a/src/system/boot/arch/arm/Jamfile b/src/system/boot/arch/arm/Jamfile index bea34280d0..c03776717b 100644 --- a/src/system/boot/arch/arm/Jamfile +++ b/src/system/boot/arch/arm/Jamfile @@ -49,7 +49,7 @@ BootMergeObject boot_arch_$(TARGET_KERNEL_ARCH).o : $(kernelDebugSources) $(librootArchObjects) - : -fno-pic + : : $(kernelLibArchObjects) ; diff --git a/src/system/boot/arch/m68k/Jamfile b/src/system/boot/arch/m68k/Jamfile index 4e3359bded..e6e5b947a6 100644 --- a/src/system/boot/arch/m68k/Jamfile +++ b/src/system/boot/arch/m68k/Jamfile @@ -16,24 +16,24 @@ local kernelLibArchObjects = BootMergeObject boot_arch_$(TARGET_KERNEL_ARCH).o : arch_elf.cpp $(librootArchObjects) - : -fno-pic + : : $(kernelLibArchObjects) ; BootMergeObject boot_arch_m68k_030.o : mmu_030.cpp - : -fno-pic -Wno-unused -mcpu=68030 + : -Wno-unused -mcpu=68030 ; BootMergeObject boot_arch_m68k_040.o : mmu_040.cpp - : -fno-pic -Wno-unused -mcpu=68040 -Wa,-m68040 + : -Wno-unused -mcpu=68040 -Wa,-m68040 ; BootMergeObject boot_arch_m68k_060.o : mmu_060.cpp - : -fno-pic -Wno-unused -mcpu=68060 + : -Wno-unused -mcpu=68060 ; SEARCH on [ FGristFiles arch_elf.cpp ] diff --git a/src/system/boot/arch/x86/Jamfile b/src/system/boot/arch/x86/Jamfile index 0fd15d01f3..b1ca213e6c 100644 --- a/src/system/boot/arch/x86/Jamfile +++ b/src/system/boot/arch/x86/Jamfile @@ -1,18 +1,22 @@ SubDir HAIKU_TOP src system boot arch x86 ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + DEFINES += _BOOT_MODE ; local kernelArchSources = arch_elf.cpp ; -local kernelArch32Sources = - cpuid.S -; - -local kernelLibArchSources = - arch_string.S -; +local kernelArchSpecificSources ; +local kernelLibArchSpecificSources ; +if $(TARGET_ARCH) = x86_64 && $(TARGET_BOOT_PLATFORM) != bios_ia32 { + kernelArchSpecificSources = cpuid.cpp ; + kernelLibArchSpecificSources = arch_string.cpp ; +} else { + kernelArchSpecificSources = cpuid.S ; + kernelLibArchSpecificSources = arch_string.S ; +} local librootOsArchSources = byteorder.S @@ -20,17 +24,25 @@ local librootOsArchSources = BootMergeObject boot_arch_$(TARGET_KERNEL_ARCH).o : $(kernelArchSources) - $(kernelArch32Sources) - $(kernelLibArchSources) + $(kernelArchSpecificSources) + $(kernelLibArchSpecificSources) $(librootOsArchSources) - : # additional flags + : -std=c++11 # additional flags ; SEARCH on [ FGristFiles $(kernelArchSources) ] = [ FDirName $(HAIKU_TOP) src system kernel arch x86 ] ; -SEARCH on [ FGristFiles $(kernelArch32Sources) ] + +if $(TARGET_ARCH) = x86_64 && $(TARGET_BOOT_PLATFORM) != bios_ia32 { +SEARCH on [ FGristFiles $(kernelArchSpecificSources) ] + = [ FDirName $(HAIKU_TOP) src system kernel arch x86 64 ] ; +SEARCH on [ FGristFiles $(kernelLibArchSpecificSources) ] + = [ FDirName $(HAIKU_TOP) src system libroot posix string arch x86_64 ] ; +} else { +SEARCH on [ FGristFiles $(kernelArchSpecificSources) ] = [ FDirName $(HAIKU_TOP) src system kernel arch x86 32 ] ; -SEARCH on [ FGristFiles $(kernelLibArchSources) ] +SEARCH on [ FGristFiles $(kernelLibArchSpecificSources) ] = [ FDirName $(HAIKU_TOP) src system kernel lib arch x86 ] ; +} SEARCH on [ FGristFiles $(librootOsArchSources) ] = [ FDirName $(HAIKU_TOP) src system libroot os arch x86 ] ; diff --git a/src/system/boot/loader/Jamfile b/src/system/boot/loader/Jamfile index 6bee5caa8f..d566b68b9c 100644 --- a/src/system/boot/loader/Jamfile +++ b/src/system/boot/loader/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot loader ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + SubDirHdrs $(HAIKU_TOP) src add-ons kernel partitioning_systems amiga ; SubDirHdrs $(HAIKU_TOP) src add-ons kernel partitioning_systems apple ; SubDirHdrs $(HAIKU_TOP) src add-ons kernel partitioning_systems gpt ; @@ -45,6 +47,15 @@ UsePrivateHeaders shared storage ; #BOOT_SUPPORT_FILE_SYSTEM_FAT ; + if $(HAIKU_BOOT_PLATFORM) != efi { + DEFINES += + BOOT_SUPPORT_ELF32 + ; + } else { + DEFINES += + _BOOT_PLATFORM_EFI + ; + } } } @@ -85,8 +96,6 @@ BootStaticLibrary boot_loader : DataIO.cpp Referenceable.cpp - - : -fno-pic ; # The partition support is built in an extra static library @@ -105,7 +114,6 @@ BootStaticLibrary boot_partitions : intel.cpp PartitionMap.cpp PartitionMapParser.cpp - : -fno-pic ; # Tell Jam where to find the utility sources diff --git a/src/system/boot/loader/elf.cpp b/src/system/boot/loader/elf.cpp index 579ae1173f..950a042374 100644 --- a/src/system/boot/loader/elf.cpp +++ b/src/system/boot/loader/elf.cpp @@ -61,6 +61,7 @@ private: }; +#ifdef BOOT_SUPPORT_ELF32 struct ELF32Class { static const uint8 kIdentClass = ELFCLASS32; @@ -96,6 +97,7 @@ struct ELF32Class { }; typedef ELFLoader ELF32Loader; +#endif #ifdef BOOT_SUPPORT_ELF64 @@ -117,6 +119,17 @@ struct ELF64Class { AllocateRegion(AddrType* _address, AddrType size, uint8 protection, void **_mappedAddress) { +#ifdef _BOOT_PLATFORM_EFI + void* address = (void*)*_address; + + status_t status = platform_allocate_region(&address, size, protection, + false); + if (status != B_OK) + return status; + + *_mappedAddress = address; + platform_bootloader_address_to_kernel_address(address, _address); +#else // Assume the real 64-bit base address is KERNEL_LOAD_BASE_64_BIT and // the mappings in the loader address space are at KERNEL_LOAD_BASE. @@ -130,14 +143,23 @@ struct ELF64Class { *_mappedAddress = address; *_address = (AddrType)(addr_t)address + KERNEL_LOAD_BASE_64_BIT - KERNEL_LOAD_BASE; +#endif return B_OK; } static inline void* Map(AddrType address) { +#ifdef _BOOT_PLATFORM_EFI + void *result; + if (platform_kernel_address_to_bootloader_address(address, &result) != B_OK) { + panic("Couldn't convert address %#lx", address); + } + return result; +#else return (void*)(addr_t)(address - KERNEL_LOAD_BASE_64_BIT + KERNEL_LOAD_BASE); +#endif } }; @@ -152,7 +174,7 @@ ELFLoader::Create(int fd, preloaded_image** _image) ImageType* image = (ImageType*)kernel_args_malloc(sizeof(ImageType)); if (image == NULL) return B_NO_MEMORY; - + ssize_t length = read_pos(fd, 0, &image->elf_header, sizeof(EhdrType)); if (length < (ssize_t)sizeof(EhdrType)) { kernel_args_free(image); @@ -225,7 +247,7 @@ ELFLoader::Load(int fd, preloaded_image* _image) // known but unused type continue; default: - dprintf("unhandled pheader type 0x%lx\n", header.p_type); + dprintf("unhandled pheader type 0x%" B_PRIx32 "\n", header.p_type); continue; } @@ -320,7 +342,7 @@ ELFLoader::Load(int fd, preloaded_image* _image) header.p_filesz); if (length < (ssize_t)header.p_filesz) { status = B_BAD_DATA; - dprintf("error reading in seg %ld\n", i); + dprintf("error reading in seg %" B_PRId32 "\n", i); goto error2; } @@ -642,13 +664,14 @@ elf_load_image(int fd, preloaded_image** _image) return status; } #endif - +#if BOOT_SUPPORT_ELF32 if (gKernelArgs.kernel_image == NULL || gKernelArgs.kernel_image->elf_class == ELFCLASS32) { status = ELF32Loader::Create(fd, _image); if (status == B_OK) return ELF32Loader::Load(fd, *_image); } +#endif return status; } @@ -706,16 +729,22 @@ elf_relocate_image(preloaded_image* image) return ELF64Loader::Relocate(image); else #endif +#ifdef BOOT_SUPPORT_ELF32 return ELF32Loader::Relocate(image); +#else + return B_ERROR; +#endif } +#ifdef BOOT_SUPPORT_ELF32 status_t boot_elf_resolve_symbol(preloaded_elf32_image* image, Elf32_Sym* symbol, Elf32_Addr* symbolAddress) { return ELF32Loader::Resolve(image, symbol, symbolAddress); } +#endif #ifdef BOOT_SUPPORT_ELF64 diff --git a/src/system/boot/loader/file_systems/amiga_ffs/File.cpp b/src/system/boot/loader/file_systems/amiga_ffs/File.cpp index 7222fb3ea0..cb9da33ef3 100644 --- a/src/system/boot/loader/file_systems/amiga_ffs/File.cpp +++ b/src/system/boot/loader/file_systems/amiga_ffs/File.cpp @@ -107,7 +107,7 @@ Stream::ReadAt(off_t offset, uint8 *buffer, size_t size) { if (offset < 0) return B_BAD_VALUE; - if (offset + size > fNode.Size()) + if (offset + (off_t)size > fNode.Size()) size = fNode.Size() - offset; ssize_t bytesLeft = (ssize_t)size; diff --git a/src/system/boot/loader/file_systems/amiga_ffs/Jamfile b/src/system/boot/loader/file_systems/amiga_ffs/Jamfile index 1b2d8bbc27..7b94061dfd 100644 --- a/src/system/boot/loader/file_systems/amiga_ffs/Jamfile +++ b/src/system/boot/loader/file_systems/amiga_ffs/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot loader file_systems amiga_ffs ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; UsePrivateHeaders kernel storage ; @@ -13,5 +15,4 @@ BootStaticLibrary boot_amiga_ffs : Volume.cpp Directory.cpp File.cpp - : -fno-pic ; diff --git a/src/system/boot/loader/file_systems/amiga_ffs/amiga_ffs.cpp b/src/system/boot/loader/file_systems/amiga_ffs/amiga_ffs.cpp index 28cc48f82e..1df6e857a1 100644 --- a/src/system/boot/loader/file_systems/amiga_ffs/amiga_ffs.cpp +++ b/src/system/boot/loader/file_systems/amiga_ffs/amiga_ffs.cpp @@ -186,7 +186,7 @@ HashIterator::GetNext(int32 &block) fNode.SetTo(fData); if (fNode.ValidateCheckSum() != B_OK) { - dprintf("block at %ld bad checksum.\n", fBlock); + dprintf("block at %" B_PRId32 " bad checksum.\n", fBlock); return NULL; } diff --git a/src/system/boot/loader/file_systems/bfs/Jamfile b/src/system/boot/loader/file_systems/bfs/Jamfile index 25827bdd91..31e8f291d9 100644 --- a/src/system/boot/loader/file_systems/bfs/Jamfile +++ b/src/system/boot/loader/file_systems/bfs/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot loader file_systems bfs ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + UsePrivateKernelHeaders ; UsePrivateHeaders file_systems shared storage ; @@ -18,7 +20,6 @@ BootStaticLibrary boot_bfs : Stream.cpp BPlusTree.cpp QueryParserUtils.cpp - : -fno-pic ; SEARCH on [ FGristFiles BPlusTree.cpp ] diff --git a/src/system/boot/loader/file_systems/bfs/Stream.cpp b/src/system/boot/loader/file_systems/bfs/Stream.cpp index 47a20e4816..d134e6f038 100644 --- a/src/system/boot/loader/file_systems/bfs/Stream.cpp +++ b/src/system/boot/loader/file_systems/bfs/Stream.cpp @@ -306,7 +306,7 @@ Stream::ReadAt(off_t pos, uint8* buffer, size_t* _length) size_t length = *_length; - if (pos + length > data.Size()) + if (pos + (off_t)length > data.Size()) length = data.Size() - pos; block_run run; diff --git a/src/system/boot/loader/file_systems/bfs/bfs.cpp b/src/system/boot/loader/file_systems/bfs/bfs.cpp index f32e4bae78..0fdae9b5d6 100644 --- a/src/system/boot/loader/file_systems/bfs/bfs.cpp +++ b/src/system/boot/loader/file_systems/bfs/bfs.cpp @@ -112,7 +112,8 @@ Volume::ValidateBlockRun(block_run run) || run.Start() > (1UL << AllocationGroupShift()) || run.length == 0 || uint32(run.Length() + run.Start()) > (1UL << AllocationGroupShift())) { - dprintf("bfs: invalid run(%ld,%d,%d)\n", run.AllocationGroup(), run.Start(), run.Length()); + dprintf("bfs: invalid run(%" B_PRId32 ",%d,%d)\n", + run.AllocationGroup(), run.Start(), run.Length()); return B_BAD_DATA; } return B_OK; diff --git a/src/system/boot/loader/file_systems/fat/Jamfile b/src/system/boot/loader/file_systems/fat/Jamfile index 52de886b8c..1bd92389b6 100644 --- a/src/system/boot/loader/file_systems/fat/Jamfile +++ b/src/system/boot/loader/file_systems/fat/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot loader file_systems fat ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + #UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; #UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; #UsePrivateHeaders [ FDirName storage ] ; @@ -20,5 +22,4 @@ BootStaticLibrary boot_fatfs : Directory.cpp File.cpp Stream.cpp - : -fno-pic ; diff --git a/src/system/boot/loader/file_systems/fat/Stream.cpp b/src/system/boot/loader/file_systems/fat/Stream.cpp index c8fc4ada49..07874cfd55 100644 --- a/src/system/boot/loader/file_systems/fat/Stream.cpp +++ b/src/system/boot/loader/file_systems/fat/Stream.cpp @@ -257,7 +257,7 @@ Stream::ReadAt(off_t pos, void *_buffer, size_t *_length, off_t *diskOffset) size_t length = *_length; - if (pos + length > fSize) + if (pos + (off_t)length > fSize) length = fSize - pos; off_t num; // block number diff --git a/src/system/boot/loader/file_systems/hfs_plus/Jamfile b/src/system/boot/loader/file_systems/hfs_plus/Jamfile index 13bbb378ac..9fdadd3582 100644 --- a/src/system/boot/loader/file_systems/hfs_plus/Jamfile +++ b/src/system/boot/loader/file_systems/hfs_plus/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot loader file_systems hfs_plus ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; UsePrivateHeaders kernel storage ; @@ -8,5 +10,4 @@ SubDirC++Flags -fno-rtti ; BootStaticLibrary boot_hfs_plus : hfs_plus.cpp - : -fno-pic ; diff --git a/src/system/boot/loader/file_systems/packagefs/Jamfile b/src/system/boot/loader/file_systems/packagefs/Jamfile index 8ef09b5086..8220f1385b 100644 --- a/src/system/boot/loader/file_systems/packagefs/Jamfile +++ b/src/system/boot/loader/file_systems/packagefs/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot loader file_systems packagefs ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; UsePrivateHeaders kernel shared storage support ; UseBuildFeatureHeaders zlib ; @@ -46,8 +48,6 @@ BootStaticLibrary boot_packagefs : # support kit CompressionAlgorithm.cpp ZlibCompressionAlgorithm.cpp - - : -fno-pic ; Includes [ FGristFiles ZlibCompressionAlgorithm.cpp ] diff --git a/src/system/boot/loader/file_systems/packagefs/packagefs.cpp b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp index 52be8672e3..3b5dbb59f2 100644 --- a/src/system/boot/loader/file_systems/packagefs/packagefs.cpp +++ b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp @@ -525,7 +525,7 @@ struct File : ::Node { off_t size = fFile->Size(); if (pos < 0 || pos > size) return B_BAD_VALUE; - if (pos + bufferSize > size) + if (pos + (off_t)bufferSize > size) bufferSize = size - pos; if (bufferSize > 0) { diff --git a/src/system/boot/loader/file_systems/tarfs/Jamfile b/src/system/boot/loader/file_systems/tarfs/Jamfile index 8d1c40b916..29de6d32f1 100644 --- a/src/system/boot/loader/file_systems/tarfs/Jamfile +++ b/src/system/boot/loader/file_systems/tarfs/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot loader file_systems tarfs ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; UsePrivateHeaders kernel shared storage ; @@ -29,7 +31,6 @@ Depends [ FGristFiles $(zlibSources) ] BootStaticLibrary boot_zlib : $(zlibSources) - : -fno-pic ; @@ -41,5 +42,4 @@ Includes [ FGristFiles tarfs.cpp ] : [ BuildFeatureAttribute zlib : sources ] ; BootStaticLibrary boot_tarfs : tarfs.cpp - : -fno-pic ; diff --git a/src/system/boot/loader/kernel_args.cpp b/src/system/boot/loader/kernel_args.cpp index d625728cf4..a5ddc2bb63 100644 --- a/src/system/boot/loader/kernel_args.cpp +++ b/src/system/boot/loader/kernel_args.cpp @@ -370,7 +370,13 @@ kernel_args_malloc(size_t size) return NULL; } +#ifdef _BOOT_PLATFORM_EFI + uint64 translated_block; + platform_bootloader_address_to_kernel_address(block, &translated_block); + if (add_kernel_args_range((void *)translated_block, size) != B_OK) +#else if (add_kernel_args_range(block, size) != B_OK) +#endif panic("kernel_args max range too low!\n"); return block; } @@ -385,7 +391,13 @@ kernel_args_malloc(size_t size) sFirstFree = (void*)((addr_t)block + size); sLast = block; sFree = kChunkSize - size; +#ifdef _BOOT_PLATFORM_EFI + uint64 translated_block; + platform_bootloader_address_to_kernel_address(block, &translated_block); + if (add_kernel_args_range((void *)translated_block, kChunkSize) != B_OK) +#else if (add_kernel_args_range(block, kChunkSize) != B_OK) +#endif panic("kernel_args max range too low!\n"); return block; diff --git a/src/system/boot/loader/load_driver_settings.cpp b/src/system/boot/loader/load_driver_settings.cpp index 5eabfd4402..8a2241fa78 100644 --- a/src/system/boot/loader/load_driver_settings.cpp +++ b/src/system/boot/loader/load_driver_settings.cpp @@ -101,7 +101,7 @@ load_driver_settings(stage2_args* /*args*/, Directory* volume) status_t status = load_driver_settings_file(settings, name); if (status != B_OK) - dprintf("Could not load \"%s\" error %ld\n", name, status); + dprintf("Could not load \"%s\" error %" B_PRIx32 "\n", name, status); } settings->Close(cookie); diff --git a/src/system/boot/loader/loader.cpp b/src/system/boot/loader/loader.cpp index 9824ee5872..2651468c32 100644 --- a/src/system/boot/loader/loader.cpp +++ b/src/system/boot/loader/loader.cpp @@ -123,7 +123,7 @@ load_kernel(stage2_args* args, BootVolume& volume) close(fd); if (status < B_OK) { - dprintf("loading kernel failed: %lx!\n", status); + dprintf("loading kernel failed: %" B_PRIx32 "!\n", status); return status; } @@ -131,7 +131,7 @@ load_kernel(stage2_args* args, BootVolume& volume) status = elf_relocate_image(gKernelArgs.kernel_image); if (status < B_OK) { - dprintf("relocating kernel failed: %lx!\n", status); + dprintf("relocating kernel failed: %" B_PRIx32 "!\n", status); return status; } @@ -163,7 +163,7 @@ load_modules_from(BootVolume& volume, const char* path) status_t status = elf_load_image(modules, name); if (status != B_OK) - dprintf("Could not load \"%s\" error %ld\n", name, status); + dprintf("Could not load \"%s\" error %" B_PRIx32 "\n", name, status); } modules->Close(cookie); diff --git a/src/system/boot/loader/net/Jamfile b/src/system/boot/loader/net/Jamfile index 5bb8291a3f..5d3fd0e039 100644 --- a/src/system/boot/loader/net/Jamfile +++ b/src/system/boot/loader/net/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot loader net ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + UsePrivateHeaders kernel [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; UsePrivateHeaders drivers ; @@ -23,6 +25,4 @@ BootStaticLibrary boot_net : UDP.cpp $(tcp) $(iscsi) - - : -fno-pic ; diff --git a/src/system/boot/loader/net/RemoteDisk.cpp b/src/system/boot/loader/net/RemoteDisk.cpp index 6778f716c5..4cce254694 100644 --- a/src/system/boot/loader/net/RemoteDisk.cpp +++ b/src/system/boot/loader/net/RemoteDisk.cpp @@ -169,7 +169,8 @@ RemoteDisk::GetName(char *nameBuffer, size_t bufferSize) const if (!nameBuffer) return B_BAD_VALUE; - snprintf(nameBuffer, bufferSize, "RemoteDisk:%ld.%ld.%ld.%ld:%hd", + snprintf(nameBuffer, bufferSize, + "RemoteDisk:%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 ":%hd", (fServerAddress >> 24) & 0xff, (fServerAddress >> 16) & 0xff, (fServerAddress >> 8) & 0xff, fServerAddress & 0xff, fServerPort); diff --git a/src/system/boot/loader/partitions.cpp b/src/system/boot/loader/partitions.cpp index f70bc8a407..cfcaaa7639 100644 --- a/src/system/boot/loader/partitions.cpp +++ b/src/system/boot/loader/partitions.cpp @@ -99,6 +99,9 @@ private: }; +static int32 sIdCounter = 0; + + // #pragma mark - @@ -111,7 +114,8 @@ Partition::Partition(int fd) TRACE(("%p Partition::Partition\n", this)); memset((partition_data *)this, 0, sizeof(partition_data)); - id = (partition_id)this; + + id = atomic_add(&sIdCounter, 1); // it's safe to close the file fFD = dup(fd); @@ -136,6 +140,29 @@ Partition::~Partition() } +Partition * +Partition::Lookup(partition_id id, NodeList *list) +{ + Partition *p; + + if (list == NULL) + list = &gPartitions; + + NodeIterator iterator = list->GetIterator(); + + while ((p = (Partition *)iterator.Next()) != NULL) { + if (p->id == id) + return p; + if (!p->fChildren.IsEmpty()) { + Partition *c = Lookup(id, &p->fChildren); + if (c) + return c; + } + } + return NULL; +} + + void Partition::SetParent(Partition *parent) { @@ -160,7 +187,7 @@ Partition::ReadAt(void *cookie, off_t position, void *buffer, size_t bufferSize) if (position < 0) return B_BAD_VALUE; - if (position + bufferSize > this->size) + if (position + (off_t)bufferSize > this->size) bufferSize = this->size - position; ssize_t result = read_pos(fFD, this->offset + position, buffer, bufferSize); @@ -177,7 +204,7 @@ Partition::WriteAt(void *cookie, off_t position, const void *buffer, if (position < 0) return B_BAD_VALUE; - if (position + bufferSize > this->size) + if (position + (off_t)bufferSize > this->size) bufferSize = this->size - position; ssize_t result = write_pos(fFD, this->offset + position, buffer, @@ -313,7 +340,7 @@ Partition::Scan(bool mountFileSystems, bool isBootDevice) if (priority < 0.0) continue; - TRACE((" priority: %ld\n", (int32)(priority * 1000))); + TRACE((" priority: %" B_PRId32 "\n", (int32)(priority * 1000))); if (priority <= bestPriority) { // the disk system recognized the partition worse than the currently // best one @@ -371,9 +398,9 @@ Partition::Scan(bool mountFileSystems, bool isBootDevice) Partition *child = NULL; while ((child = (Partition *)iterator.Next()) != NULL) { - TRACE(("%p Partition::Scan(): scan child %p (start = %Ld, size " - "= %Ld, parent = %p)!\n", this, child, child->offset, - child->size, child->Parent())); + TRACE(("%p Partition::Scan(): scan child %p (start = %" B_PRIdOFF + ", size = %" B_PRIdOFF ", parent = %p)!\n", this, child, + child->offset, child->size, child->Parent())); child->Scan(mountFileSystems); @@ -431,16 +458,19 @@ add_partitions_for(int fd, bool mountFileSystems, bool isBootDevice) partition->block_size = 512; partition->size = partition->Size(); - // add this partition to the list of partitions, if it contains - // or might contain a file system + // add this partition to the list of partitions + // temporarily for Lookup() to work + gPartitions.Add(partition); + + // keep it, if it contains or might contain a file system if ((partition->Scan(mountFileSystems, isBootDevice) == B_OK && partition->IsFileSystem()) || (!partition->IsPartitioningSystem() && !mountFileSystems)) { - gPartitions.Add(partition); return B_OK; } // if not, we no longer need the partition + gPartitions.Remove(partition); delete partition; return B_OK; } @@ -458,7 +488,7 @@ add_partitions_for(Node *device, bool mountFileSystems, bool isBootDevice) status_t status = add_partitions_for(fd, mountFileSystems, isBootDevice); if (status < B_OK) - dprintf("add_partitions_for(%d) failed: %ld\n", fd, status); + dprintf("add_partitions_for(%d) failed: %" B_PRIx32 "\n", fd, status); close(fd); return B_OK; @@ -469,8 +499,13 @@ partition_data * create_child_partition(partition_id id, int32 index, off_t offset, off_t size, partition_id childID) { - Partition &partition = *(Partition *)id; - Partition *child = partition.AddChild(); + Partition *partition = Partition::Lookup(id); + if (partition == NULL) { + dprintf("creating partition failed: could not find partition.\n"); + return NULL; + } + + Partition *child = partition->AddChild(); if (child == NULL) { dprintf("creating partition failed: no memory\n"); return NULL; @@ -490,11 +525,10 @@ create_child_partition(partition_id id, int32 index, off_t offset, off_t size, partition_data * get_child_partition(partition_id id, int32 index) { - //Partition &partition = *(Partition *)id; - // TODO: do we really have to implement this? // The intel partition module doesn't really need this for our mission... - TRACE(("get_child_partition(id = %lu, index = %ld)\n", id, index)); + TRACE(("get_child_partition(id = %" B_PRId32 ", index = %" B_PRId32 ")\n", + id, index)); return NULL; } @@ -503,8 +537,11 @@ get_child_partition(partition_id id, int32 index) partition_data * get_parent_partition(partition_id id) { - Partition &partition = *(Partition *)id; - - return partition.Parent(); + Partition *partition = Partition::Lookup(id); + if (partition == NULL) { + dprintf("could not find parent partition.\n"); + return NULL; + } + return partition->Parent(); } diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index a136b6ce91..73344cce11 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -294,7 +294,9 @@ MemoryDisk::MemoryDisk(const uint8* data, size_t size, const char* name) ssize_t MemoryDisk::ReadAt(void* cookie, off_t pos, void* buffer, size_t bufferSize) { - if (pos >= fSize) + if (pos < 0) + return B_BAD_VALUE; + if ((size_t)pos >= fSize) return 0; if (pos + bufferSize > fSize) diff --git a/src/system/boot/platform/amiga_m68k/Jamfile b/src/system/boot/platform/amiga_m68k/Jamfile index b867ef7f6f..e923167fe0 100644 --- a/src/system/boot/platform/amiga_m68k/Jamfile +++ b/src/system/boot/platform/amiga_m68k/Jamfile @@ -49,7 +49,7 @@ BootMergeObject boot_platform_amiga_m68k_other.o : #decode_edid.c #dump_edid.c - : -fno-pic #-Wa,--pcrel + : #-Wa,--pcrel : boot_platform_generic.a ; diff --git a/src/system/boot/platform/atari_m68k/Jamfile b/src/system/boot/platform/atari_m68k/Jamfile index e8eb76030b..0332881c8c 100644 --- a/src/system/boot/platform/atari_m68k/Jamfile +++ b/src/system/boot/platform/atari_m68k/Jamfile @@ -54,7 +54,7 @@ BootMergeObject boot_platform_atari_m68k_other.o : #decode_edid.c #dump_edid.c - : -fno-pic #-Wa,--pcrel + : #-Wa,--pcrel : boot_platform_generic.a ; diff --git a/src/system/boot/platform/bios_ia32/Jamfile b/src/system/boot/platform/bios_ia32/Jamfile index 934ddc0f0b..0822156732 100644 --- a/src/system/boot/platform/bios_ia32/Jamfile +++ b/src/system/boot/platform/bios_ia32/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot platform bios_ia32 ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + SubDirHdrs $(HAIKU_TOP) headers private kernel boot platform $(TARGET_BOOT_PLATFORM) ; UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; @@ -47,7 +49,7 @@ BootMergeObject boot_platform_bios_ia32.o : decode_edid.c dump_edid.c - : -fno-pic + : : boot_platform_generic.a ; diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile new file mode 100644 index 0000000000..8356f7674f --- /dev/null +++ b/src/system/boot/platform/efi/Jamfile @@ -0,0 +1,59 @@ +SubDir HAIKU_TOP src system boot platform efi ; + +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + +UsePrivateHeaders [ FDirName kernel boot ] ; +UseBuildFeatureHeaders gnuefi ; +UseBuildFeatureHeaders gnuefi : headersProtocol ; +UseBuildFeatureHeaders gnuefi : headersArch ; + +{ + local defines = _BOOT_MODE GNU_EFI_USE_MS_ABI _BOOT_PLATFORM_EFI ; + defines = [ FDefines $(defines) ] ; + SubDirCcFlags $(defines) ; + SubDirC++Flags $(defines) -fno-rtti ; +} + +local efi_glue_src = + crt0-efi-x86_64.S + ; + +local platform_src = + relocation_func.cpp + start.cpp + console.cpp + video.cpp + debug.cpp + entry.S + mmu.cpp + heap.cpp + acpi.cpp + menu.cpp + devices.cpp + hpet.cpp + cpu.cpp + smp.cpp + smp_trampoline.S + support.S + ; + +Includes [ FGristFiles $(efi_glue_src) $(platform_src) ] + : + [ BuildFeatureAttribute gnuefi : headers ] + [ BuildFeatureAttribute gnuefi : headersProtocol ] + [ BuildFeatureAttribute gnuefi : headersArch ] + ; + +BootMergeObject boot_platform_efi.o : + $(efi_glue_src) + $(platform_src) + : + : boot_platform_generic.a + ; + +SEARCH on [ FGristFiles relocation_func.cpp ] + = [ FDirName $(SUBDIR) arch $(TARGET_ARCH) ] ; +LOCATE on [ FGristFiles $(efi_glue_src) ] + = [ BuildFeatureAttribute gnuefi : libdir : path ] ; +Depends [ FGristFiles $(efi_glue_src) ] + : [ BuildFeatureAttribute gnuefi : libdir ] ; diff --git a/src/system/boot/platform/efi/acpi.cpp b/src/system/boot/platform/efi/acpi.cpp new file mode 100644 index 0000000000..fe5a23d997 --- /dev/null +++ b/src/system/boot/platform/efi/acpi.cpp @@ -0,0 +1,259 @@ +/* + * Copyright 2014, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Copyright 2011, Rene Gollent, rene@gollent.com. + * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. + * Copyright 2007, Michael Lotz, mmlr@mlotz.ch + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. +*/ + + +#include + +#include +#include + +#include +#include +#include +#include + +#include "efi_platform.h" +#include "acpi.h" +#include "mmu.h" + + +#define TRACE_ACPI +#ifdef TRACE_ACPI +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +static acpi_descriptor_header* sAcpiRsdt; // System Description Table +static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table +static int32 sNumEntries = -1; + + +static status_t +acpi_validate_rsdp(acpi_rsdp* rsdp) +{ + const char* data = (const char*)rsdp; + unsigned char checksum = 0; + for (uint32 i = 0; i < sizeof(acpi_rsdp_legacy); i++) + checksum += data[i]; + + if ((checksum & 0xff) != 0) { + TRACE(("acpi: rsdp failed basic checksum\n")); + return B_BAD_DATA; + } + + // for ACPI 2.0+ we need to also validate the extended checksum + if (rsdp->revision > 0) { + for (uint32 i = sizeof(acpi_rsdp_legacy); + i < sizeof(acpi_rsdp_extended); i++) { + checksum += data[i]; + } + + if ((checksum & 0xff) != 0) { + TRACE(("acpi: rsdp failed extended checksum\n")); + return B_BAD_DATA; + } + } + + return B_OK; +} + + + +static status_t +acpi_validate_rsdt(acpi_descriptor_header* rsdt) +{ + const char* data = (const char*)rsdt; + unsigned char checksum = 0; + for (uint32 i = 0; i < rsdt->length; i++) + checksum += data[i]; + + return checksum == 0 ? B_OK : B_BAD_DATA; +} + + +static status_t +acpi_check_rsdt(acpi_rsdp* rsdp) +{ + if (acpi_validate_rsdp(rsdp) != B_OK) + return B_BAD_DATA; + + bool usingXsdt = false; + + TRACE(("acpi: found rsdp at %p oem id: %.6s, rev %d\n", + rsdp, rsdp->oem_id, rsdp->revision)); + TRACE(("acpi: rsdp points to rsdt at 0x%x\n", rsdp->rsdt_address)); + + uint32 length = 0; + acpi_descriptor_header* rsdt = NULL; + if (rsdp->revision > 0) { + length = rsdp->xsdt_length; + rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( + (uint32)rsdp->xsdt_address, rsdp->xsdt_length, kDefaultPageFlags); + if (rsdt != NULL + && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 0) { + mmu_free(rsdt, rsdp->xsdt_length); + rsdt = NULL; + TRACE(("acpi: invalid extended system description table\n")); + } else + usingXsdt = true; + } + + // if we're ACPI v1 or we fail to map the XSDT for some reason, + // attempt to use the RSDT instead. + if (rsdt == NULL) { + // map and validate the root system description table + rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( + rsdp->rsdt_address, sizeof(acpi_descriptor_header), + kDefaultPageFlags); + if (rsdt == NULL) { + TRACE(("acpi: couldn't map rsdt header\n")); + return B_ERROR; + } + if (strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) { + mmu_free(rsdt, sizeof(acpi_descriptor_header)); + rsdt = NULL; + TRACE(("acpi: invalid root system description table\n")); + return B_ERROR; + } + + length = rsdt->length; + // Map the whole table, not just the header + TRACE(("acpi: rsdt length: %u\n", length)); + mmu_free(rsdt, sizeof(acpi_descriptor_header)); + rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( + rsdp->rsdt_address, length, kDefaultPageFlags); + } + + if (rsdt != NULL) { + if (acpi_validate_rsdt(rsdt) != B_OK) { + TRACE(("acpi: rsdt failed checksum validation\n")); + mmu_free(rsdt, length); + return B_ERROR; + } else { + if (usingXsdt) + sAcpiXsdt = rsdt; + else + sAcpiRsdt = rsdt; + TRACE(("acpi: found valid %s at %p\n", + usingXsdt ? ACPI_XSDT_SIGNATURE : ACPI_RSDT_SIGNATURE, + rsdt)); + } + } else + return B_ERROR; + + return B_OK; +} + +template +acpi_descriptor_header* +acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt) +{ + if (acpiSdt == NULL) + return NULL; + + if (sNumEntries == -1) { + // if using the xsdt, our entries are 64 bits wide. + sNumEntries = (acpiSdt->length + - sizeof(acpi_descriptor_header)) + / sizeof(PointerType); + } + + if (sNumEntries <= 0) { + TRACE(("acpi: root system description table is empty\n")); + return NULL; + } + + TRACE(("acpi: searching %d entries for table '%.4s'\n", sNumEntries, + signature)); + + PointerType* pointer = (PointerType*)((uint8*)acpiSdt + + sizeof(acpi_descriptor_header)); + + acpi_descriptor_header* header = NULL; + for (int32 j = 0; j < sNumEntries; j++, pointer++) { + header = (acpi_descriptor_header*) + mmu_map_physical_memory((uint32)*pointer, + sizeof(acpi_descriptor_header), kDefaultPageFlags); + + if (header == NULL + || strncmp(header->signature, signature, 4) != 0) { + // not interesting for us + TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n", + signature, header != NULL ? header->signature : "null")); + + if (header != NULL) { + mmu_free(header, sizeof(acpi_descriptor_header)); + header = NULL; + } + + continue; + } + + TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer)); + break; + } + + + if (header == NULL) + return NULL; + + // Map the whole table, not just the header + uint32 length = header->length; + mmu_free(header, sizeof(acpi_descriptor_header)); + + return (acpi_descriptor_header*)mmu_map_physical_memory( + (uint32)*pointer, length, kDefaultPageFlags); +} + + +acpi_descriptor_header* +acpi_find_table(const char* signature) +{ + if (sAcpiRsdt != NULL) + return acpi_find_table_generic(signature, sAcpiRsdt); + else if (sAcpiXsdt != NULL) + return acpi_find_table_generic(signature, sAcpiXsdt); + + return NULL; +} + + +void +acpi_init() +{ + EFI_GUID acpi = ACPI_20_TABLE_GUID; + EFI_CONFIGURATION_TABLE *table = kSystemTable->ConfigurationTable; + UINTN entries = kSystemTable->NumberOfTableEntries; + + // Try to find the ACPI RSDP. + for (uint32 i = 0; i < entries; i++) { + acpi_rsdp *rsdp = NULL; + + EFI_GUID vendor = table[i].VendorGuid; + + if (vendor.Data1 == acpi.Data1 + && vendor.Data2 == acpi.Data2 + && vendor.Data3 == acpi.Data3 + && strncmp((char *)vendor.Data4, (char *)acpi.Data4, 8) == 0) { + rsdp = (acpi_rsdp *)(table[i].VendorTable); + if (strncmp((char *)rsdp, ACPI_RSDP_SIGNATURE, 8) == 0) + TRACE(("acpi_init: found ACPI RSDP signature at %p\n", rsdp)); + + if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK) { + gKernelArgs.arch_args.acpi_root = rsdp; + break; + } + } + } +} diff --git a/src/system/boot/platform/efi/acpi.h b/src/system/boot/platform/efi/acpi.h new file mode 100644 index 0000000000..8d45c4b4fc --- /dev/null +++ b/src/system/boot/platform/efi/acpi.h @@ -0,0 +1,22 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ACPI_H +#define ACPI_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +acpi_descriptor_header *acpi_find_table(const char *signature); +void acpi_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ACPI_H */ diff --git a/src/system/boot/platform/efi/arch/x86_64/relocation_func.cpp b/src/system/boot/platform/efi/arch/x86_64/relocation_func.cpp new file mode 100644 index 0000000000..66918e6483 --- /dev/null +++ b/src/system/boot/platform/efi/arch/x86_64/relocation_func.cpp @@ -0,0 +1,97 @@ +/* reloc_x86_64.c - position independent x86_64 ELF shared object relocator + Copyright (C) 1999 Hewlett-Packard Co. + Contributed by David Mosberger . + Copyright (C) 2005 Intel Co. + Contributed by Fenghua Yu . + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of Hewlett-Packard Co. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +#include + +#include + +extern "C" EFI_STATUS _relocate (long ldbase, Elf64_Dyn *dyn, + EFI_HANDLE image __attribute__((__unused__)), + EFI_SYSTEM_TABLE *systab __attribute__((__unused__))) +{ + long relsz = 0, relent = 0; + Elf64_Rel *rel = 0; + unsigned long *addr; + int i; + + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { + switch (dyn[i].d_tag) { + case DT_RELA: + rel = (Elf64_Rel*) + ((unsigned long)dyn[i].d_un.d_ptr + + ldbase); + break; + + case DT_RELASZ: + relsz = dyn[i].d_un.d_val; + break; + + case DT_RELAENT: + relent = dyn[i].d_un.d_val; + break; + + default: + break; + } + } + + if (!rel && relent == 0) + return EFI_SUCCESS; + + if (!rel || relent == 0) + return EFI_LOAD_ERROR; + + while (relsz > 0) { + /* apply the relocs */ + switch (ELF64_R_TYPE (rel->r_info)) { + case R_X86_64_NONE: + break; + + case R_X86_64_RELATIVE: + addr = (unsigned long *) + (ldbase + rel->r_offset); + *addr += ldbase; + break; + + default: + break; + } + rel = (Elf64_Rel*) ((char *) rel + relent); + relsz -= relent; + } + return EFI_SUCCESS; +} diff --git a/src/system/boot/platform/efi/console.cpp b/src/system/boot/platform/efi/console.cpp new file mode 100644 index 0000000000..35500e731a --- /dev/null +++ b/src/system/boot/platform/efi/console.cpp @@ -0,0 +1,247 @@ +/* + * Copyright 2014-2016 Haiku, Inc. All rights reserved. + * Copyright 2013 Fredrik Holmqvist, fredrik.holmqvist@gmail.com. All rights + * reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "console.h" + +#include + +#include + +#include +#include +#include + +#include "efi_platform.h" + + +class Console : public ConsoleNode { + public: + Console(); + + virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, + size_t bufferSize); + virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, + size_t bufferSize); +}; + + +static uint32 sScreenWidth; +static uint32 sScreenHeight; +static uint32 sScreenMode; +static Console sInput, sOutput; +FILE *stdin, *stdout, *stderr; + + +// #pragma mark - + + +Console::Console() + : ConsoleNode() +{ +} + + +ssize_t +Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) +{ + return B_ERROR; +} + + +ssize_t +Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, + size_t bufferSize) +{ + const char *string = (const char *)buffer; + CHAR16 ucsBuffer[bufferSize + 3]; + uint32 j = 0; + + for (uint32 i = 0; i < bufferSize; i++) { + switch (string[i]) { + case '\n': { + ucsBuffer[j++] = '\r'; + ucsBuffer[j++] = '\n'; + } //fallthrough + case 0 : { + //Not sure if we should keep going or abort for 0. + //Keep going was easy anyway. + ucsBuffer[j] = 0; + kSystemTable->ConOut->OutputString(kSystemTable->ConOut, + ucsBuffer); + j = 0; + continue; + } + default: + ucsBuffer[j++] = (CHAR16) string[i]; + } + } + + if (j > 0) { + ucsBuffer[j] = 0; + kSystemTable->ConOut->OutputString(kSystemTable->ConOut, ucsBuffer); + } + return bufferSize; +} + + +// #pragma mark - + + +void +console_clear_screen(void) +{ + kSystemTable->ConOut->ClearScreen(kSystemTable->ConOut); +} + + +int32 +console_width(void) +{ + return sScreenWidth; +} + + +int32 +console_height(void) +{ + return sScreenHeight; +} + + +void +console_set_cursor(int32 x, int32 y) +{ + kSystemTable->ConOut->SetCursorPosition(kSystemTable->ConOut, x, y); +} + + +void +console_show_cursor(void) +{ + kSystemTable->ConOut->EnableCursor(kSystemTable->ConOut, true); +} + + +void +console_hide_cursor(void) +{ + kSystemTable->ConOut->EnableCursor(kSystemTable->ConOut, false); +} + + +void +console_set_color(int32 foreground, int32 background) +{ + kSystemTable->ConOut->SetAttribute(kSystemTable->ConOut, + EFI_TEXT_ATTR((foreground & 0xf), (background & 0xf))); +} + + +int +console_wait_for_key(void) +{ + UINTN index; + EFI_STATUS status; + EFI_INPUT_KEY key; + EFI_EVENT event = kSystemTable->ConIn->WaitForKey; + + do { + kBootServices->WaitForEvent(1, &event, &index); + status = kSystemTable->ConIn->ReadKeyStroke(kSystemTable->ConIn, &key); + } while (status == EFI_NOT_READY); + + if (key.UnicodeChar > 0) + return (int) key.UnicodeChar; + + switch (key.ScanCode) { + case SCAN_UP: + return TEXT_CONSOLE_KEY_UP; + case SCAN_DOWN: + return TEXT_CONSOLE_KEY_DOWN; + case SCAN_LEFT: + return TEXT_CONSOLE_KEY_LEFT; + case SCAN_RIGHT: + return TEXT_CONSOLE_KEY_RIGHT; + case SCAN_PAGE_UP: + return TEXT_CONSOLE_KEY_PAGE_UP; + case SCAN_PAGE_DOWN: + return TEXT_CONSOLE_KEY_PAGE_DOWN; + case SCAN_HOME: + return TEXT_CONSOLE_KEY_HOME; + case SCAN_END: + return TEXT_CONSOLE_KEY_END; + } + return 0; +} + + +static void update_screen_size(void) +{ + UINTN width, height; + UINTN area = 0; + SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut = kSystemTable->ConOut; + + for (int mode = 0; mode < ConOut->Mode->MaxMode; ++mode) { + if (ConOut->QueryMode(ConOut, mode, &width, &height) == EFI_SUCCESS) { + if (width * height > area) { + sScreenWidth = width; + sScreenHeight = height; + sScreenMode = mode; + } + } + } + + ConOut->SetMode(ConOut, sScreenMode); +} + + +status_t +console_init(void) +{ + update_screen_size(); + console_hide_cursor(); + console_clear_screen(); + + // enable stdio functionality + stdin = (FILE *)&sInput; + stdout = stderr = (FILE *)&sOutput; + + return B_OK; +} + + +uint32 +console_check_boot_keys(void) +{ + EFI_STATUS status; + EFI_INPUT_KEY key; + + // give the user a chance to press a key + kBootServices->Stall(500000); + + status = kSystemTable->ConIn->ReadKeyStroke(kSystemTable->ConIn, &key); + + if (status != EFI_SUCCESS) + return 0; + + if (key.UnicodeChar == 0 && key.ScanCode == SCAN_ESC) + return BOOT_OPTION_DEBUG_OUTPUT; + if (key.UnicodeChar == ' ') + return BOOT_OPTION_MENU; + + return 0; +} + + +extern "C" void +platform_switch_to_text_mode(void) +{ + kSystemTable->ConOut->Reset(kSystemTable->ConOut, false); + kSystemTable->ConOut->SetMode(kSystemTable->ConOut, sScreenMode); + gKernelArgs.frame_buffer.enabled = false; +} diff --git a/src/system/boot/platform/efi/console.h b/src/system/boot/platform/efi/console.h new file mode 100644 index 0000000000..5cf79e6700 --- /dev/null +++ b/src/system/boot/platform/efi/console.h @@ -0,0 +1,16 @@ +/* +** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the Haiku License. +*/ +#ifndef CONSOLE_H +#define CONSOLE_H + + +#include + + +status_t console_init(void); +uint32 console_check_boot_keys(void); + + +#endif /* CONSOLE_H */ diff --git a/src/system/boot/platform/efi/cpu.cpp b/src/system/boot/platform/efi/cpu.cpp new file mode 100644 index 0000000000..66f8748cc9 --- /dev/null +++ b/src/system/boot/platform/efi/cpu.cpp @@ -0,0 +1,349 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + * + * calculate_cpu_conversion_factor() was written by Travis Geiselbrecht and + * licensed under the NewOS license. + */ + + +#include "cpu.h" + +#include "efi_platform.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +//#define TRACE_CPU +#ifdef TRACE_CPU +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +extern "C" uint64 rdtsc(); + +uint32 gTimeConversionFactor; + +// PIT definitions +#define TIMER_CLKNUM_HZ (14318180 / 12) + +// PIT IO Ports +#define PIT_CHANNEL_PORT_BASE 0x40 +#define PIT_CONTROL 0x43 + +// Channel selection +#define PIT_SELECT_CHANNEL_SHIFT 6 + +// Access mode +#define PIT_ACCESS_LATCH_COUNTER (0 << 4) +#define PIT_ACCESS_LOW_BYTE_ONLY (1 << 4) +#define PIT_ACCESS_HIGH_BYTE_ONLY (2 << 4) +#define PIT_ACCESS_LOW_THEN_HIGH_BYTE (3 << 4) + +// Operating modes +#define PIT_MODE_INTERRUPT_ON_0 (0 << 1) +#define PIT_MODE_HARDWARE_COUNTDOWN (1 << 1) +#define PIT_MODE_RATE_GENERATOR (2 << 1) +#define PIT_MODE_SQUARE_WAVE_GENERATOR (3 << 1) +#define PIT_MODE_SOFTWARE_STROBE (4 << 1) +#define PIT_MODE_HARDWARE_STROBE (5 << 1) + +// BCD/Binary mode +#define PIT_BINARY_MODE 0 +#define PIT_BCD_MODE 1 + +// Channel 2 control (speaker) +#define PIT_CHANNEL_2_CONTROL 0x61 +#define PIT_CHANNEL_2_GATE_HIGH 0x01 +#define PIT_CHANNEL_2_SPEAKER_OFF_MASK ~0x02 + + +// Maximum values +#define MAX_QUICK_SAMPLES 20 +#define MAX_SLOW_SAMPLES 20 + // TODO: These are arbitrary. They are here to avoid spinning indefinitely + // if the TSC just isn't stable and we can't get our desired error range. + + +#define CPUID_EFLAGS (1UL << 21) +#define RDTSC_FEATURE (1UL << 4) + + +struct uint128 { + uint128(uint64 low, uint64 high = 0) + : + low(low), + high(high) + { + } + + bool operator<(const uint128& other) const + { + return high < other.high || (high == other.high && low < other.low); + } + + bool operator<=(const uint128& other) const + { + return !(other < *this); + } + + uint128 operator<<(int count) const + { + if (count == 0) + return *this; + + if (count >= 128) + return 0; + + if (count >= 64) + return uint128(0, low << (count - 64)); + + return uint128(low << count, (high << count) | (low >> (64 - count))); + } + + uint128 operator>>(int count) const + { + if (count == 0) + return *this; + + if (count >= 128) + return 0; + + if (count >= 64) + return uint128(high >> (count - 64), 0); + + return uint128((low >> count) | (high << (64 - count)), high >> count); + } + + uint128 operator+(const uint128& other) const + { + uint64 resultLow = low + other.low; + return uint128(resultLow, + high + other.high + (resultLow < low ? 1 : 0)); + } + + uint128 operator-(const uint128& other) const + { + uint64 resultLow = low - other.low; + return uint128(resultLow, + high - other.high - (resultLow > low ? 1 : 0)); + } + + uint128 operator*(uint32 other) const + { + uint64 resultMid = (low >> 32) * other; + uint64 resultLow = (low & 0xffffffff) * other + (resultMid << 32); + return uint128(resultLow, + high * other + (resultMid >> 32) + + (resultLow < resultMid << 32 ? 1 : 0)); + } + + uint128 operator/(const uint128& other) const + { + int shift = 0; + uint128 shiftedDivider = other; + while (shiftedDivider.high >> 63 == 0 && shiftedDivider < *this) { + shiftedDivider = shiftedDivider << 1; + shift++; + } + + uint128 result = 0; + uint128 temp = *this; + for (; shift >= 0; shift--, shiftedDivider = shiftedDivider >> 1) { + if (shiftedDivider <= temp) { + result = result + (uint128(1) << shift); + temp = temp - shiftedDivider; + } + } + + return result; + } + + operator uint64() const + { + return low; + } + +private: + uint64 low; + uint64 high; +}; + + +static inline void +calibration_loop(uint8 desiredHighByte, uint8 channel, uint64& tscDelta, + double& conversionFactor, uint16& expired) +{ + uint8 select = channel << PIT_SELECT_CHANNEL_SHIFT; + out8(select | PIT_ACCESS_LOW_THEN_HIGH_BYTE | PIT_MODE_INTERRUPT_ON_0 + | PIT_BINARY_MODE, PIT_CONTROL); + + // Fill in count of 0xffff, low then high byte + uint8 channelPort = PIT_CHANNEL_PORT_BASE + channel; + out8(0xff, channelPort); + out8(0xff, channelPort); + + // Read the count back once to delay the start. This ensures that we've + // waited long enough for the counter to actually start counting down, as + // this only happens on the next clock cycle after reload. + in8(channelPort); + in8(channelPort); + + // We're expecting the PIT to be at the starting position (high byte 0xff) + // as we just programmed it, but if it isn't we wait for it to wrap. + uint8 startLow; + uint8 startHigh; + do { + out8(select | PIT_ACCESS_LATCH_COUNTER, PIT_CONTROL); + startLow = in8(channelPort); + startHigh = in8(channelPort); + } while (startHigh != 255); + + // Read in the first TSC value + uint64 startTSC = rdtsc(); + + // Wait for the PIT to count down to our desired value + uint8 endLow; + uint8 endHigh; + do { + out8(select | PIT_ACCESS_LATCH_COUNTER, PIT_CONTROL); + endLow = in8(channelPort); + endHigh = in8(channelPort); + } while (endHigh > desiredHighByte); + + // And read the second TSC value + uint64 endTSC = rdtsc(); + + tscDelta = endTSC - startTSC; + expired = ((startHigh << 8) | startLow) - ((endHigh << 8) | endLow); + conversionFactor = (double)tscDelta / (double)expired; +} + + +static void +calculate_cpu_conversion_factor() +{ + uint8 channel = 2; + + // When using channel 2, enable the input and disable the speaker. + if (channel == 2) { + uint8 control = in8(PIT_CHANNEL_2_CONTROL); + control &= PIT_CHANNEL_2_SPEAKER_OFF_MASK; + control |= PIT_CHANNEL_2_GATE_HIGH; + out8(control, PIT_CHANNEL_2_CONTROL); + } + + uint64 tscDeltaQuick, tscDeltaSlower, tscDeltaSlow; + double conversionFactorQuick, conversionFactorSlower, conversionFactorSlow; + uint16 expired; + + uint32 quickSampleCount = 1; + uint32 slowSampleCount = 1; + +quick_sample: + calibration_loop(224, channel, tscDeltaQuick, conversionFactorQuick, + expired); + +slower_sample: + calibration_loop(192, channel, tscDeltaSlower, conversionFactorSlower, + expired); + + double deviation = conversionFactorQuick / conversionFactorSlower; + if (deviation < 0.99 || deviation > 1.01) { + // We might have been hit by a SMI or were otherwise stalled + if (quickSampleCount++ < MAX_QUICK_SAMPLES) + goto quick_sample; + } + + // Slow sample + calibration_loop(128, channel, tscDeltaSlow, conversionFactorSlow, + expired); + + deviation = conversionFactorSlower / conversionFactorSlow; + if (deviation < 0.99 || deviation > 1.01) { + // We might have been hit by a SMI or were otherwise stalled + if (slowSampleCount++ < MAX_SLOW_SAMPLES) + goto slower_sample; + } + + // Scale the TSC delta to timer units + tscDeltaSlow *= TIMER_CLKNUM_HZ; + + uint64 clockSpeed = tscDeltaSlow / expired; + gTimeConversionFactor = ((uint128(expired) * uint32(1000000)) << 32) + / uint128(tscDeltaSlow); + +#ifdef TRACE_CPU + if (clockSpeed > 1000000000LL) { + dprintf("CPU at %Ld.%03Ld GHz\n", clockSpeed / 1000000000LL, + (clockSpeed % 1000000000LL) / 1000000LL); + } else { + dprintf("CPU at %Ld.%03Ld MHz\n", clockSpeed / 1000000LL, + (clockSpeed % 1000000LL) / 1000LL); + } +#endif + + gKernelArgs.arch_args.system_time_cv_factor = gTimeConversionFactor; + gKernelArgs.arch_args.cpu_clock_speed = clockSpeed; + //dprintf("factors: %lu %llu\n", gTimeConversionFactor, clockSpeed); + + if (quickSampleCount > 1) { + dprintf("needed %u quick samples for TSC calibration\n", + quickSampleCount); + } + + if (slowSampleCount > 1) { + dprintf("needed %u slow samples for TSC calibration\n", + slowSampleCount); + } + + if (channel == 2) { + // Set the gate low again + out8(in8(PIT_CHANNEL_2_CONTROL) & ~PIT_CHANNEL_2_GATE_HIGH, + PIT_CHANNEL_2_CONTROL); + } +} + + +// #pragma mark - + + +extern "C" bigtime_t +system_time() +{ + uint64 lo, hi; + asm("rdtsc": "=a"(lo), "=d"(hi)); + return ((lo * gTimeConversionFactor) >> 32) + hi * gTimeConversionFactor; +} + + +extern "C" void +spin(bigtime_t microseconds) +{ + bigtime_t time = system_time(); + + while ((system_time() - time) < microseconds) + asm volatile ("pause;"); +} + + +extern "C" void +cpu_init() +{ + calculate_cpu_conversion_factor(); + + gKernelArgs.num_cpus = 1; + // this will eventually be corrected later on +} diff --git a/src/system/boot/platform/efi/cpu.h b/src/system/boot/platform/efi/cpu.h new file mode 100644 index 0000000000..f8eff4f44a --- /dev/null +++ b/src/system/boot/platform/efi/cpu.h @@ -0,0 +1,22 @@ +/* + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef CPU_H +#define CPU_H + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void cpu_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_H */ diff --git a/src/system/boot/platform/efi/debug.cpp b/src/system/boot/platform/efi/debug.cpp new file mode 100644 index 0000000000..0a40169b8c --- /dev/null +++ b/src/system/boot/platform/efi/debug.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include + +#include "efi_platform.h" + + +extern "C" void +dprintf(const char *format, ...) +{ +} + + +extern "C" void +panic(const char *format, ...) +{ + va_list args; + + platform_switch_to_text_mode(); + + puts("*** PANIC ***"); + + va_start(args, format); + vprintf(format, args); + va_end(args); + + while (true) + kBootServices->Stall(1000000); +} + + +char* +platform_debug_get_log_buffer(size_t *_size) +{ + return NULL; +} diff --git a/src/system/boot/platform/efi/devices.cpp b/src/system/boot/platform/efi/devices.cpp new file mode 100644 index 0000000000..8538ddd4be --- /dev/null +++ b/src/system/boot/platform/efi/devices.cpp @@ -0,0 +1,242 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + +#include "efi_platform.h" + + +class EfiDevice : public Node +{ + public: + EfiDevice(EFI_BLOCK_IO *blockIo, EFI_DEVICE_PATH *devicePath); + virtual ~EfiDevice(); + + virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, + size_t bufferSize); + virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, + size_t bufferSize) { return B_UNSUPPORTED; } + virtual off_t Size() const { return fSize; } + + uint32 BlockSize() const { return fBlockSize; } + private: + EFI_BLOCK_IO* fBlockIo; + EFI_DEVICE_PATH* fDevicePath; + + uint32 fBlockSize; + uint64 fSize; +}; + + +EfiDevice::EfiDevice(EFI_BLOCK_IO *blockIo, EFI_DEVICE_PATH *devicePath) + : + fBlockIo(blockIo), + fDevicePath(devicePath) +{ + fBlockSize = fBlockIo->Media->BlockSize; + fSize = (fBlockIo->Media->LastBlock + 1) * fBlockSize; +} + + +EfiDevice::~EfiDevice() +{ +} + + +ssize_t +EfiDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) +{ + uint32 offset = pos % fBlockSize; + pos /= fBlockSize; + + uint32 numBlocks = (offset + bufferSize + fBlockSize) / fBlockSize; + char readBuffer[numBlocks * fBlockSize]; + + EFI_STATUS status = fBlockIo->ReadBlocks(fBlockIo, fBlockIo->Media->MediaId, + pos, sizeof(readBuffer), readBuffer); + + if (status != EFI_SUCCESS) + return B_ERROR; + + memcpy(buffer, readBuffer + offset, bufferSize); + + return bufferSize; +} + + +static EFI_DEVICE_PATH* +find_device_path(EFI_DEVICE_PATH *devicePath, uint16 type, uint16 subType) +{ + EFI_DEVICE_PATH *node = devicePath; + while (!IsDevicePathEnd(node)) { + if (DevicePathType(node) == type + && (subType == 0xFFFF || DevicePathSubType(node) == subType)) + return node; + + node = NextDevicePathNode(node); + } + + return NULL; +} + + +static status_t +add_boot_devices(NodeList *devicesList) +{ + EFI_GUID blockIoGuid = BLOCK_IO_PROTOCOL; + EFI_GUID devicePathGuid = DEVICE_PATH_PROTOCOL; + EFI_BLOCK_IO *blockIo; + EFI_DEVICE_PATH *devicePath, *node, *targetDevicePath = NULL; + EFI_HANDLE *handles = NULL; + EFI_STATUS status; + UINTN size = 0; + + status = kBootServices->LocateHandle(ByProtocol, &blockIoGuid, 0, &size, 0); + if (status != EFI_BUFFER_TOO_SMALL) + return B_ENTRY_NOT_FOUND; + + handles = (EFI_HANDLE*)malloc(size); + status = kBootServices->LocateHandle(ByProtocol, &blockIoGuid, 0, &size, + handles); + if (status != EFI_SUCCESS) { + if (handles != NULL) + free(handles); + return B_ENTRY_NOT_FOUND; + } + + for (int n = (size / sizeof(EFI_HANDLE)) - 1; n >= 0; --n) { + status = kBootServices->HandleProtocol(handles[n], &devicePathGuid, + (void**)&devicePath); + if (status != EFI_SUCCESS) + continue; + + node = devicePath; + while (!IsDevicePathEnd(NextDevicePathNode(node))) + node = NextDevicePathNode(node); + + if (DevicePathType(node) == MEDIA_DEVICE_PATH + && DevicePathSubType(node) == MEDIA_CDROM_DP) { + targetDevicePath = find_device_path(devicePath, + MESSAGING_DEVICE_PATH, 0xFFFF); + continue; + } + + if (DevicePathType(node) != MESSAGING_DEVICE_PATH) + continue; + + status = kBootServices->HandleProtocol(handles[n], &blockIoGuid, + (void**)&blockIo); + if (status != EFI_SUCCESS || !blockIo->Media->MediaPresent) + continue; + + EfiDevice *device = new(std::nothrow)EfiDevice(blockIo, devicePath); + if (device == NULL) + continue; + + if (targetDevicePath != NULL + && memcmp(targetDevicePath, node, DevicePathNodeLength(node)) == 0) + devicesList->InsertBefore(devicesList->Head(), device); + else + devicesList->Insert(device); + + targetDevicePath = NULL; + } + + return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND; +} + + +static off_t +get_next_check_sum_offset(int32 index, off_t maxSize) +{ + if (index < 2) + return index * 512; + + if (index < 4) + return (maxSize >> 10) + index * 2048; + + //return ((system_time() + index) % (maxSize >> 9)) * 512; + return 42 * 512; +} + + +static uint32 +compute_check_sum(Node *device, off_t offset) +{ + char buffer[512]; + ssize_t bytesRead = device->ReadAt(NULL, offset, buffer, sizeof(buffer)); + if (bytesRead < B_OK) + return 0; + + if (bytesRead < (ssize_t)sizeof(buffer)) + memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead); + + uint32 *array = (uint32*)buffer; + uint32 sum = 0; + + for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) + sum += array[i]; + + return sum; +} + + +status_t +platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) +{ + // TODO: get GUID of partition to boot, and support for SATA/ATA devices + return add_boot_devices(devicesList); +} + + +status_t +platform_add_block_devices(struct stage2_args *args, NodeList *devicesList) +{ + // add_boot_devices will add all available devices, so nothing to do here + return B_OK; +} + + +status_t +platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, + NodeList *partitions, boot::Partition **_partition) +{ + NodeIterator it = partitions->GetIterator(); + while (it.HasNext()) { + boot::Partition *partition = (boot::Partition*)it.Next(); + // we're only looking for CDs atm, so just return first found + *_partition = partition; + return B_OK; + } + + return B_ERROR; +} + + +status_t +platform_register_boot_device(Node *device) +{ + disk_identifier identifier; + + identifier.bus_type = UNKNOWN_BUS; + identifier.device_type = UNKNOWN_DEVICE; + identifier.device.unknown.size = device->Size(); + + for (uint32 i = 0; i < NUM_DISK_CHECK_SUMS; ++i) { + off_t offset = get_next_check_sum_offset(i, device->Size()); + identifier.device.unknown.check_sums[i].offset = offset; + identifier.device.unknown.check_sums[i].sum = compute_check_sum(device, offset); + } + + gBootVolume.SetInt32(BOOT_METHOD, BOOT_METHOD_CD); + gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, true); + gBootVolume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, + &identifier, sizeof(disk_identifier)); + + return B_OK; +} diff --git a/src/system/boot/platform/efi/efi_platform.h b/src/system/boot/platform/efi/efi_platform.h new file mode 100644 index 0000000000..b9670e9869 --- /dev/null +++ b/src/system/boot/platform/efi/efi_platform.h @@ -0,0 +1,23 @@ +/* + * Copyright 2013, Fredrik Homlqvist, fredrik.holmqvist@gmail.com. + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef EFI_PLATFORM_H +#define EFI_PLATFORM_H + + +#include "efibind.h" +#include "efidef.h" +#include "efidevp.h" +#include "efiprot.h" +#include "eficon.h" +#include "efierr.h" +#include "efiapi.h" + + +extern const EFI_SYSTEM_TABLE *kSystemTable; +extern const EFI_BOOT_SERVICES *kBootServices; +extern const EFI_RUNTIME_SERVICES *kRuntimeServices; + + +#endif /* EFI_PLATFORM_H */ diff --git a/src/system/boot/platform/efi/entry.S b/src/system/boot/platform/efi/entry.S new file mode 100644 index 0000000000..75717080d8 --- /dev/null +++ b/src/system/boot/platform/efi/entry.S @@ -0,0 +1,69 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Copyright 2014, Henry Harrington, henry.harrington@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include + +#define __x86_64__ +#include + +#include "mmu.h" +#undef __x86_64__ + + +#define GDT_LIMIT 0x800 + + +.code64 + + +/*! void efi_enter_kernel(uint64 pml4, uint64 entry_point, uint64 stackTop); */ +FUNCTION(efi_enter_kernel): + // Point CR3 to the kernel's PML4. + movq %rdi, %cr3 + + // Load 64-bit enabled GDT + lgdtq gLongGDTR(%rip) + + // Jump into the 64-bit code segment. + push $KERNEL_CODE_SELECTOR + lea .Llmode(%rip), %rax + push %rax + lretq +.align 8 +.code64 +.Llmode: + // Set data segments. + mov $KERNEL_DATA_SELECTOR, %ax + mov %ax, %ss + xor %ax, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + // Set the stack pointer. + movq %rdx, %rsp + + // Clear the stack frame/RFLAGS. + xorq %rbp, %rbp + push $2 + popf + + // Get arguments and call the kernel entry point. + mov %rsi, %rax // entry point + leaq gKernelArgs(%rip), %rdi + xorl %esi, %esi // current cpu + call *%rax + + +.data + + +SYMBOL(gLongGDTR): + .word BOOT_GDT_SEGMENT_COUNT * 8 - 1 +SYMBOL(gLongGDT): + .quad 0 diff --git a/src/system/boot/platform/efi/heap.cpp b/src/system/boot/platform/efi/heap.cpp new file mode 100644 index 0000000000..ade11ed003 --- /dev/null +++ b/src/system/boot/platform/efi/heap.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#include "efi_platform.h" + + +#define STAGE_PAGES 0x2000 /* 32 MB */ + + +static EFI_PHYSICAL_ADDRESS staging; + + +extern "C" void +platform_release_heap(struct stage2_args *args, void *base) +{ + if ((void*)staging != base) + panic("Attempt to release heap with wrong base address!"); + + kBootServices->FreePages(staging, STAGE_PAGES); +} + + +extern "C" status_t +platform_init_heap(struct stage2_args *args, void **_base, void **_top) +{ + if (kBootServices->AllocatePages(AllocateAnyPages, EfiLoaderData, + STAGE_PAGES, &staging) != EFI_SUCCESS) + return B_NO_MEMORY; + + *_base = (void*)staging; + *_top = (void*)((int8*)staging + STAGE_PAGES * PAGE_SIZE); + + return B_OK; +} diff --git a/src/system/boot/platform/efi/hpet.cpp b/src/system/boot/platform/efi/hpet.cpp new file mode 100644 index 0000000000..7371ae460e --- /dev/null +++ b/src/system/boot/platform/efi/hpet.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. +*/ + + +#include "mmu.h" +#include "acpi.h" +#include "hpet.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +//#define TRACE_HPET +#ifdef TRACE_HPET +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +void +hpet_init(void) +{ + // Try to find the HPET ACPI table. + TRACE(("hpet_init: Looking for HPET...\n")); + acpi_hpet *hpet = (acpi_hpet *)acpi_find_table(ACPI_HPET_SIGNATURE); + + if (hpet == NULL) { + // No HPET table in the RSDT. + // Since there are no other methods for finding it, + // assume we don't have one. + TRACE(("hpet_init: HPET not found.\n")); + gKernelArgs.arch_args.hpet_phys = 0; + gKernelArgs.arch_args.hpet = NULL; + return; + } + + TRACE(("hpet_init: found HPET at %x.\n", hpet->hpet_address.address)); + gKernelArgs.arch_args.hpet_phys = hpet->hpet_address.address; + gKernelArgs.arch_args.hpet = (void *)mmu_map_physical_memory( + gKernelArgs.arch_args.hpet_phys, B_PAGE_SIZE, EfiACPIReclaimMemory); +} diff --git a/src/system/boot/platform/efi/hpet.h b/src/system/boot/platform/efi/hpet.h new file mode 100644 index 0000000000..124eef7fc8 --- /dev/null +++ b/src/system/boot/platform/efi/hpet.h @@ -0,0 +1,21 @@ +/* + * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef HPET_H +#define HPET_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void hpet_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HPET_H */ diff --git a/src/system/boot/platform/efi/menu.cpp b/src/system/boot/platform/efi/menu.cpp new file mode 100644 index 0000000000..0b13b2dcc0 --- /dev/null +++ b/src/system/boot/platform/efi/menu.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#include "efi_platform.h" + + +void +platform_add_menus(Menu *menu) +{ + // No platform specific menus +} + + +void +platform_update_menu_item(Menu *menu, MenuItem *item) +{ + platform_generic_update_text_menu_item(menu, item); +} + + +void +platform_run_menu(Menu *menu) +{ + platform_generic_run_text_menu(menu); +} + + +size_t +platform_get_user_input_text(Menu *menu, MenuItem *item, char *buffer, + size_t bufferSize) +{ + return platform_generic_get_user_input_text(menu, item, buffer, + bufferSize); +} diff --git a/src/system/boot/platform/efi/mmu.cpp b/src/system/boot/platform/efi/mmu.cpp new file mode 100644 index 0000000000..fc40e2d2ea --- /dev/null +++ b/src/system/boot/platform/efi/mmu.cpp @@ -0,0 +1,381 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Copyright 2014, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Copyright 2014, Henry Harrington, henry.harrington@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include + +#include "efi_platform.h" +#include "mmu.h" + + +struct allocated_memory_region { + allocated_memory_region *next; + uint64_t vaddr; + uint64_t paddr; + size_t size; + bool released; +}; + + +static uint64_t next_virtual_address = KERNEL_LOAD_BASE_64_BIT + 32 * 1024 * 1024; +static allocated_memory_region *allocated_memory_regions = NULL; + + +static uint64_t mmu_allocate_page() +{ + EFI_PHYSICAL_ADDRESS addr; + EFI_STATUS s = kBootServices->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, &addr); + if (s != EFI_SUCCESS) + panic("Unabled to allocate memory: %li", s); + + return addr; +} + + +uint64_t +mmu_generate_post_efi_page_tables(UINTN memory_map_size, + EFI_MEMORY_DESCRIPTOR *memory_map, UINTN descriptor_size, + UINTN descriptor_version) +{ + // Generate page tables, matching bios_ia32/long.cpp. + uint64_t *pml4; + uint64_t *pdpt; + uint64_t *pageDir; + uint64_t *pageTable; + + // Allocate the top level PML4. + pml4 = NULL; + if (platform_allocate_region((void**)&pml4, B_PAGE_SIZE, 0, false) != B_OK) + panic("Failed to allocate PML4."); + gKernelArgs.arch_args.phys_pgdir = (uint32_t)(addr_t)pml4; + memset(pml4, 0, B_PAGE_SIZE); + platform_bootloader_address_to_kernel_address(pml4, &gKernelArgs.arch_args.vir_pgdir); + + // Store the virtual memory usage information. + gKernelArgs.virtual_allocated_range[0].start = KERNEL_LOAD_BASE_64_BIT; + gKernelArgs.virtual_allocated_range[0].size = next_virtual_address - KERNEL_LOAD_BASE_64_BIT; + gKernelArgs.num_virtual_allocated_ranges = 1; + gKernelArgs.arch_args.virtual_end = ROUNDUP(KERNEL_LOAD_BASE_64_BIT + + gKernelArgs.virtual_allocated_range[0].size, 0x200000); + + // Find the highest physical memory address. We map all physical memory + // into the kernel address space, so we want to make sure we map everything + // we have available. + uint64 maxAddress = 0; + for (UINTN i = 0; i < memory_map_size / descriptor_size; ++i) { + EFI_MEMORY_DESCRIPTOR *entry = (EFI_MEMORY_DESCRIPTOR *)((addr_t)memory_map + i * descriptor_size); + maxAddress = std::max(maxAddress, + entry->PhysicalStart + entry->NumberOfPages * 4096); + } + + // Want to map at least 4GB, there may be stuff other than usable RAM that + // could be in the first 4GB of physical address space. + maxAddress = std::max(maxAddress, (uint64)0x100000000ll); + maxAddress = ROUNDUP(maxAddress, 0x40000000); + + // Currently only use 1 PDPT (512GB). This will need to change if someone + // wants to use Haiku on a box with more than 512GB of RAM but that's + // probably not going to happen any time soon. + if (maxAddress / 0x40000000 > 512) + panic("Can't currently support more than 512GB of RAM!"); + + // Create page tables for the physical map area. Also map this PDPT + // temporarily at the bottom of the address space so that we are identity + // mapped. + + pdpt = (uint64*)mmu_allocate_page(); + memset(pdpt, 0, B_PAGE_SIZE); + pml4[510] = (addr_t)pdpt | kTableMappingFlags; + pml4[0] = (addr_t)pdpt | kTableMappingFlags; + + for (uint64 i = 0; i < maxAddress; i += 0x40000000) { + pageDir = (uint64*)mmu_allocate_page(); + memset(pageDir, 0, B_PAGE_SIZE); + pdpt[i / 0x40000000] = (addr_t)pageDir | kTableMappingFlags; + + for (uint64 j = 0; j < 0x40000000; j += 0x200000) { + pageDir[j / 0x200000] = (i + j) | kLargePageMappingFlags; + } + } + + // Allocate tables for the kernel mappings. + + pdpt = (uint64*)mmu_allocate_page(); + memset(pdpt, 0, B_PAGE_SIZE); + pml4[511] = (addr_t)pdpt | kTableMappingFlags; + + pageDir = (uint64*)mmu_allocate_page(); + memset(pageDir, 0, B_PAGE_SIZE); + pdpt[510] = (addr_t)pageDir | kTableMappingFlags; + + // We can now allocate page tables and duplicate the mappings across from + // the 32-bit address space to them. + pageTable = NULL; // shush, compiler. + for (uint32 i = 0; i < gKernelArgs.virtual_allocated_range[0].size + / B_PAGE_SIZE; i++) { + if ((i % 512) == 0) { + pageTable = (uint64*)mmu_allocate_page(); + memset(pageTable, 0, B_PAGE_SIZE); + pageDir[i / 512] = (addr_t)pageTable | kTableMappingFlags; + } + + // Get the physical address to map. + void *phys; + if (platform_kernel_address_to_bootloader_address(KERNEL_LOAD_BASE_64_BIT + (i * B_PAGE_SIZE), + &phys) != B_OK) + continue; + + pageTable[i % 512] = (addr_t)phys | kPageMappingFlags; + } + + return (uint64)pml4; +} + + +// Called after EFI boot services exit. +// Currently assumes that the memory map is sane... Sorted and no overlapping +// regions. +void +mmu_post_efi_setup(UINTN memory_map_size, EFI_MEMORY_DESCRIPTOR *memory_map, UINTN descriptor_size, UINTN descriptor_version) +{ + // Add physical memory to the kernel args and update virtual addresses for EFI regions.. + addr_t addr = (addr_t)memory_map; + gKernelArgs.num_physical_memory_ranges = 0; + for (UINTN i = 0; i < memory_map_size / descriptor_size; ++i) { + EFI_MEMORY_DESCRIPTOR *entry = (EFI_MEMORY_DESCRIPTOR *)(addr + i * descriptor_size); + switch (entry->Type) { + case EfiLoaderCode: + case EfiLoaderData: + case EfiBootServicesCode: + case EfiBootServicesData: + case EfiConventionalMemory: { + // Usable memory. + // Ignore memory below 1MB and above 512GB. + uint64_t base = entry->PhysicalStart; + uint64_t end = entry->PhysicalStart + entry->NumberOfPages * 4096; + if (base < 0x100000) + base = 0x100000; + if (end > (512ull * 1024 * 1024 * 1024)) + end = 512ull * 1024 * 1024 * 1024; + if (base >= end) + break; + uint64_t size = end - base; + + insert_physical_memory_range(base, size); + // LoaderData memory is bootloader allocated memory, possibly + // containing the kernel or loaded drivers. + if (entry->Type == EfiLoaderData) + insert_physical_allocated_range(base, size); + break; + } + case EfiACPIReclaimMemory: + // ACPI reclaim -- physical memory we could actually use later + gKernelArgs.ignored_physical_memory += entry->NumberOfPages * 4096; + break; + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + entry->VirtualStart = entry->PhysicalStart + 0xFFFFFF0000000000ull; + break; + } + } + + // Sort the address ranges. + sort_address_ranges(gKernelArgs.physical_memory_range, + gKernelArgs.num_physical_memory_ranges); + sort_address_ranges(gKernelArgs.physical_allocated_range, + gKernelArgs.num_physical_allocated_ranges); + sort_address_ranges(gKernelArgs.virtual_allocated_range, + gKernelArgs.num_virtual_allocated_ranges); + + // Switch EFI to virtual mode, using the kernel pmap. + // Something involving ConvertPointer might need to be done after this? + // http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#SetVirtualAddressMap.28.29 + kRuntimeServices->SetVirtualAddressMap(memory_map_size, descriptor_size, descriptor_version, memory_map); +} + + +// Platform allocator. +// The bootloader assumes that bootloader address space == kernel address space. +// This is not true until just before the kernel is booted, so an ugly hack is +// used to cover the difference. platform_allocate_region allocates addresses +// in bootloader space, but can convert them to kernel space. The ELF loader +// accesses kernel memory via Mao(), and much later in the boot process, +// addresses in the kernel argument struct are converted from bootloader +// addresses to kernel addresses. + +extern "C" status_t +platform_allocate_region(void **_address, size_t size, uint8 /* protection */, bool exactAddress) +{ + // We don't have any control over the page tables, give up right away if an + // exactAddress is wanted. + if (exactAddress) + return B_NO_MEMORY; + + EFI_PHYSICAL_ADDRESS addr; + size_t aligned_size = ROUNDUP(size, B_PAGE_SIZE); + allocated_memory_region *region = new(std::nothrow) allocated_memory_region; + + if (region == NULL) + return B_NO_MEMORY; + + EFI_STATUS status = kBootServices->AllocatePages(AllocateAnyPages, + EfiLoaderData, aligned_size / B_PAGE_SIZE, &addr); + if (status != EFI_SUCCESS) { + delete region; + return B_NO_MEMORY; + } + + // Addresses above 512GB not supported. + // Memory map regions above 512GB can be ignored, but if EFI returns pages + // above that there's nothing that can be done to fix it. + if (addr + size > (512ull * 1024 * 1024 * 1024)) + panic("Can't currently support more than 512GB of RAM!"); + + region->next = allocated_memory_regions; + allocated_memory_regions = region; + region->vaddr = 0; + region->paddr = addr; + region->size = size; + region->released = false; + + if (*_address != NULL) { + region->vaddr = (uint64_t)*_address; + } + + //dprintf("Allocated region %#lx (requested %p) %#lx %lu\n", region->vaddr, *_address, region->paddr, region->size); + + *_address = (void *)region->paddr; + + return B_OK; +} + + +/*! + Neither \a virtualAddress nor \a size need to be aligned, but the function + will map all pages the range intersects with. + If physicalAddress is not page-aligned, the returned virtual address will + have the same "misalignment". +*/ +extern "C" addr_t +mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags) +{ + addr_t pageOffset = physicalAddress & (B_PAGE_SIZE - 1); + + physicalAddress -= pageOffset; + size += pageOffset; + + size_t aligned_size = ROUNDUP(size, B_PAGE_SIZE); + allocated_memory_region *region = new(std::nothrow) allocated_memory_region; + + if (!region) + return B_NO_MEMORY; + + // Addresses above 512GB not supported. + // Memory map regions above 512GB can be ignored, but if EFI returns pages above + // that there's nothing that can be done to fix it. + if (physicalAddress + size > (512ull * 1024 * 1024 * 1024)) + panic("Can't currently support more than 512GB of RAM!"); + + region->next = allocated_memory_regions; + allocated_memory_regions = region; + region->vaddr = 0; + region->paddr = physicalAddress; + region->size = aligned_size; + region->released = false; + + return physicalAddress + pageOffset; +} + + +extern "C" void +mmu_free(void *virtualAddress, size_t size) +{ + addr_t physicalAddress = (addr_t)virtualAddress; + addr_t pageOffset = physicalAddress & (B_PAGE_SIZE - 1); + + physicalAddress -= pageOffset; + size += pageOffset; + + size_t aligned_size = ROUNDUP(size, B_PAGE_SIZE); + + for (allocated_memory_region *region = allocated_memory_regions; region; region = region->next) { + if (region->paddr == physicalAddress && region->size == aligned_size) { + region->released = true; + return; + } + } +} + + +static allocated_memory_region * +get_region(void *address, size_t size) +{ + for (allocated_memory_region *region = allocated_memory_regions; region; region = region->next) { + if (region->paddr == (uint64_t)address && region->size == size) { + return region; + } + } + return 0; +} + + +extern "C" status_t +platform_bootloader_address_to_kernel_address(void *address, uint64_t *_result) +{ + uint64_t addr = (uint64_t)address; + + for (allocated_memory_region *region = allocated_memory_regions; region; region = region->next) { + if (region->paddr <= addr && addr < region->paddr + region->size) { + // Lazily allocate virtual memory. + if (region->vaddr == 0) { + region->vaddr = next_virtual_address; + next_virtual_address += ROUNDUP(region->size, B_PAGE_SIZE); + } + *_result = region->vaddr + (addr - region->paddr); + //dprintf("Converted bootloader address %p in region %#lx-%#lx to %#lx\n", + // address, region->paddr, region->paddr + region->size, *_result); + return B_OK; + } + } + + return B_ERROR; +} + + +extern "C" status_t +platform_kernel_address_to_bootloader_address(uint64_t address, void **_result) +{ + for (allocated_memory_region *region = allocated_memory_regions; region; region = region->next) { + if (region->vaddr != 0 && region->vaddr <= address && address < region->vaddr + region->size) { + *_result = (void *)(region->paddr + (address - region->vaddr)); + //dprintf("Converted kernel address %#lx in region %#lx-%#lx to %p\n", + // address, region->vaddr, region->vaddr + region->size, *_result); + return B_OK; + } + } + + return B_ERROR; +} + + +extern "C" status_t +platform_free_region(void *address, size_t size) +{ + //dprintf("Release region %p %lu\n", address, size); + allocated_memory_region *region = get_region(address, size); + if (!region) + panic("Unknown region??"); + + kBootServices->FreePages((EFI_PHYSICAL_ADDRESS)address, ROUNDUP(size, B_PAGE_SIZE) / B_PAGE_SIZE); + + return B_OK; +} diff --git a/src/system/boot/platform/efi/mmu.h b/src/system/boot/platform/efi/mmu.h new file mode 100644 index 0000000000..e078a3f89d --- /dev/null +++ b/src/system/boot/platform/efi/mmu.h @@ -0,0 +1,73 @@ +/* + * Copyright 2014, Henry Harrington, henry.harrington@gmail.com. + * Distributed under the terms of the MIT License. + */ + +#ifndef MMU_H +#define MMU_H + +#include + +#undef BOOT_GDT_SEGMENT_COUNT +#define BOOT_GDT_SEGMENT_COUNT (USER_DATA_SEGMENT + 1) + +#ifndef _ASSEMBLER + +#include "efi_platform.h" + +#include + + +extern segment_descriptor gBootGDT[BOOT_GDT_SEGMENT_COUNT]; + +static const uint32 kDefaultPageFlags = 0x3; // present, R/W +static const uint64 kTableMappingFlags = 0x7; // present, R/W, user +static const uint64 kLargePageMappingFlags = 0x183; // present, R/W, user, global, large +static const uint64 kPageMappingFlags = 0x103; // present, R/W, user, global + + +#ifdef __cplusplus +extern "C" { +#endif + +extern addr_t mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags); +extern void mmu_free(void *virtualAddress, size_t size); + +extern void +mmu_post_efi_setup(UINTN memory_map_size, EFI_MEMORY_DESCRIPTOR *memory_map, UINTN descriptor_size, UINTN descriptor_version); +extern uint64_t +mmu_generate_post_efi_page_tables(UINTN memory_map_size, EFI_MEMORY_DESCRIPTOR *memory_map, UINTN descriptor_size, UINTN descriptor_version); +extern status_t +platform_kernel_address_to_bootloader_address(uint64_t address, void **_result); +extern status_t +platform_bootloader_address_to_kernel_address(void *address, uint64_t *_result); + +#ifdef __cplusplus +} +#endif + + +/*! Convert a 32-bit address to a 64-bit address. */ +inline uint64 +fix_address(uint64 address) +{ + uint64 result; + if (platform_bootloader_address_to_kernel_address((void *)address, &result) != B_OK) + return address; + else + return result; +} + + +template +inline void +fix_address(FixedWidthPointer& p) +{ + if (p != NULL) + p.SetTo(fix_address(p.Get())); +} + + +#endif // !_ASSEMBLER + +#endif /* MMU_H */ diff --git a/src/system/boot/platform/efi/smp.cpp b/src/system/boot/platform/efi/smp.cpp new file mode 100644 index 0000000000..d597ea5fde --- /dev/null +++ b/src/system/boot/platform/efi/smp.cpp @@ -0,0 +1,457 @@ +/* + * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. + * Copyright 2004-2010, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. +*/ + + +#include "smp.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mmu.h" +#include "acpi.h" + + +#define NO_SMP 0 + +//#define TRACE_SMP +#ifdef TRACE_SMP +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +extern "C" void execute_n_instructions(int count); + +extern "C" void smp_trampoline(void); +extern "C" void smp_trampoline_args(void); +extern "C" void smp_trampoline_end(void); + +struct gdtr { + uint16 limit; + uint32 base; + unsigned char null[8]; + unsigned char code[8]; + unsigned char data[8]; +} __attribute__((packed)); + +// Arguments passed to the SMP trampoline. +struct trampoline_args { + uint32 trampoline; // Trampoline address + uint32 gdt32; // 32-bit GDTR + uint32 pml4; // 64-bit PML4 + uint32 gdt64; // 64-bit GDTR + uint64 kernel_entry; // Kernel entry point + uint64 kernel_args; // Kernel arguments + uint64 current_cpu; // CPU number + uint64 stack_top; // Kernel stack + volatile uint64 sentinel; // Sentinel, AP sets to 0 when finished + + // smp_boot_other_cpus puts the GDTR here. + struct gdtr gdtr; +}; + + +static uint32 +apic_read(uint32 offset) +{ + return *(volatile uint32 *)((addr_t)gKernelArgs.arch_args.apic_phys + offset); +} + + +static void +apic_write(uint32 offset, uint32 data) +{ + *(volatile uint32 *)((addr_t)gKernelArgs.arch_args.apic_phys + offset) = data; +} + + +static status_t +smp_do_acpi_config(void) +{ + TRACE(("smp: using ACPI to detect MP configuration\n")); + + // reset CPU count + gKernelArgs.num_cpus = 0; + + acpi_madt *madt = (acpi_madt *)acpi_find_table(ACPI_MADT_SIGNATURE); + + if (madt == NULL) { + TRACE(("smp: Failed to find MADT!\n")); + return B_ERROR; + } + + gKernelArgs.arch_args.apic_phys = madt->local_apic_address; + TRACE(("smp: local apic address is 0x%" B_PRIx32 "\n", madt->local_apic_address)); + + acpi_apic *apic = (acpi_apic *)((uint8 *)madt + sizeof(acpi_madt)); + acpi_apic *end = (acpi_apic *)((uint8 *)madt + madt->header.length); + while (apic < end) { + switch (apic->type) { + case ACPI_MADT_LOCAL_APIC: + { + if (gKernelArgs.num_cpus == SMP_MAX_CPUS) { + TRACE(("smp: already reached maximum CPUs (%d)\n", + SMP_MAX_CPUS)); + break; + } + + acpi_local_apic *localApic = (acpi_local_apic *)apic; + TRACE(("smp: found local APIC with id %u\n", + localApic->apic_id)); + if ((localApic->flags & ACPI_LOCAL_APIC_ENABLED) == 0) { + TRACE(("smp: APIC is disabled and will not be used\n")); + break; + } + + gKernelArgs.arch_args.cpu_apic_id[gKernelArgs.num_cpus] + = localApic->apic_id; + // TODO: how to find out? putting 0x10 in to indicate a local apic + gKernelArgs.arch_args.cpu_apic_version[gKernelArgs.num_cpus] + = 0x10; + gKernelArgs.num_cpus++; + break; + } + + case ACPI_MADT_IO_APIC: { + acpi_io_apic *ioApic = (acpi_io_apic *)apic; + TRACE(("smp: found io APIC with id %" B_PRIu32 " and address 0x%" B_PRIx32 "\n", + ioApic->io_apic_id, ioApic->io_apic_address)); + if (gKernelArgs.arch_args.ioapic_phys == 0) + gKernelArgs.arch_args.ioapic_phys = ioApic->io_apic_address; + break; + } + default: + break; + } + + apic = (acpi_apic *)((uint8 *)apic + apic->length); + } + + return gKernelArgs.num_cpus > 0 ? B_OK : B_ERROR; +} + + +static void +calculate_apic_timer_conversion_factor(void) +{ + int64 t1, t2; + uint32 config; + uint32 count; + + TRACE(("calculating apic timer conversion factor\n")); + + // setup the timer + config = apic_read(APIC_LVT_TIMER); + config = (config & APIC_LVT_TIMER_MASK) + APIC_LVT_MASKED; + // timer masked, vector 0 + apic_write(APIC_LVT_TIMER, config); + + config = (apic_read(APIC_TIMER_DIVIDE_CONFIG) & ~0x0000000f); + apic_write(APIC_TIMER_DIVIDE_CONFIG, config | APIC_TIMER_DIVIDE_CONFIG_1); + // divide clock by one + + t1 = system_time(); + apic_write(APIC_INITIAL_TIMER_COUNT, 0xffffffff); // start the counter + + execute_n_instructions(128 * 20000); + + count = apic_read(APIC_CURRENT_TIMER_COUNT); + t2 = system_time(); + + count = 0xffffffff - count; + + gKernelArgs.arch_args.apic_time_cv_factor + = (uint32)((1000000.0/(t2 - t1)) * count); + + TRACE(("APIC ticks/sec = %" B_PRId32 "\n", + gKernelArgs.arch_args.apic_time_cv_factor)); +} + + +// #pragma mark - + + +int +smp_get_current_cpu(void) +{ + if (gKernelArgs.arch_args.apic == NULL) + return 0; + + uint8 apicID = apic_read(APIC_ID) >> 24; + for (uint32 i = 0; i < gKernelArgs.num_cpus; i++) { + if (gKernelArgs.arch_args.cpu_apic_id[i] == apicID) + return i; + } + + return 0; +} + + +void +smp_init_other_cpus(void) +{ + if (get_safemode_boolean(B_SAFEMODE_DISABLE_SMP, false)) { + // SMP has been disabled! + TRACE(("smp disabled per safemode setting\n")); + gKernelArgs.num_cpus = 1; + } + + if (get_safemode_boolean(B_SAFEMODE_DISABLE_APIC, false)) { + TRACE(("local apic disabled per safemode setting, disabling smp\n")); + gKernelArgs.arch_args.apic_phys = 0; + gKernelArgs.num_cpus = 1; + } + + if (gKernelArgs.arch_args.apic_phys == 0) + return; + + TRACE(("smp: found %" B_PRId32 " cpu%s\n", gKernelArgs.num_cpus, + gKernelArgs.num_cpus != 1 ? "s" : "")); + TRACE(("smp: apic_phys = %lx\n", (addr_t)gKernelArgs.arch_args.apic_phys)); + TRACE(("smp: ioapic_phys = %lx\n", + (addr_t)gKernelArgs.arch_args.ioapic_phys)); + + // map in the apic + gKernelArgs.arch_args.apic = (void *)mmu_map_physical_memory( + gKernelArgs.arch_args.apic_phys, B_PAGE_SIZE, kDefaultPageFlags); + + TRACE(("smp: apic (mapped) = %lx\n", (addr_t)gKernelArgs.arch_args.apic.Pointer())); + + // calculate how fast the apic timer is + calculate_apic_timer_conversion_factor(); + + if (gKernelArgs.num_cpus < 2) + return; + + for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) { + // create a final stack the trampoline code will put the ap processor on + void * stack = NULL; + const size_t size = KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; + if (platform_allocate_region(&stack, size, 0, false) != B_OK) { + panic("Unable to allocate AP stack"); + } + memset(stack, 0, size); + gKernelArgs.cpu_kstack[i].start = fix_address((uint64_t)stack); + gKernelArgs.cpu_kstack[i].size = size; + } +} + + +void +smp_boot_other_cpus(uint32 pml4, uint32 gdtr64, uint64 kernel_entry) +{ + if (gKernelArgs.num_cpus < 2) + return; + + TRACE(("trampolining other cpus\n")); + + // allocate a stack and a code area for the smp trampoline + // (these have to be < 1M physical, 0xa0000-0xfffff is reserved by the BIOS) + uint64 trampolineCode = 0x9000; + uint64 trampolineStack = 0x8000; + + // copy the trampoline code over + TRACE(("copying the trampoline code to %p from %p\n", (char*)trampolineCode, (const void*)&smp_trampoline)); + TRACE(("size of trampoline code = %lu bytes\n", (uint64)&smp_trampoline_end - (uint64)&smp_trampoline)); + memcpy((char *)trampolineCode, (const void*)&smp_trampoline, + (uint64)&smp_trampoline_end - (uint64)&smp_trampoline); + + // boot the cpus + TRACE(("we have %d CPUs to boot...\n", gKernelArgs.num_cpus - 1)); + for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) { + TRACE(("trampolining CPU %d\n", i)); + uint32 config; + uint64 numStartups; + uint32 j; + trampoline_args * args = (trampoline_args *)trampolineStack; + args->trampoline = trampolineCode; + args->gdt32 = (uint64) &args->gdtr; + args->gdtr.limit = 23; + args->gdtr.base = (uint32)(uint64)args->gdtr.null; + #define COPY_ARRAY(A, X0, X1, X2, X3, X4, X5, X6, X7) \ + { A[0] = X0; A[1] = X1; A[2] = X2; A[3] = X3; A[4] = X4; A[5] = X5; A[6] = X6; A[7] = X7; } + COPY_ARRAY(args->gdtr.null, 0, 0, 0, 0, 0, 0, 0, 0); + COPY_ARRAY(args->gdtr.code, 0xff, 0xff, 0, 0, 0, 0x9a, 0xcf, 0); + COPY_ARRAY(args->gdtr.data, 0xff, 0xff, 0, 0, 0, 0x92, 0xcf, 0); + #undef COPY_ARRAY + args->pml4 = pml4; + args->gdt64 = gdtr64; + args->kernel_entry = kernel_entry; + args->kernel_args = (uint64)&gKernelArgs; + args->current_cpu = i; + args->stack_top = gKernelArgs.cpu_kstack[i].start + gKernelArgs.cpu_kstack[i].size; + args->sentinel = 1; + + // put the args in the right place + uint32 * args_ptr = + (uint32 *)(trampolineCode + (uint64)smp_trampoline_args - (uint64)smp_trampoline); + *args_ptr = (uint32)(uint64)args; + + /* clear apic errors */ + if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) { + apic_write(APIC_ERROR_STATUS, 0); + apic_read(APIC_ERROR_STATUS); + } + + /* send (aka assert) INIT IPI */ + config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) + | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); + apic_write(APIC_INTR_COMMAND_2, config); /* set target pe */ + config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000) + | APIC_TRIGGER_MODE_LEVEL | APIC_INTR_COMMAND_1_ASSERT + | APIC_DELIVERY_MODE_INIT; + apic_write(APIC_INTR_COMMAND_1, config); + + // wait for pending to end + while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) + asm volatile ("pause;"); + + /* deassert INIT */ + config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) + | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); + apic_write(APIC_INTR_COMMAND_2, config); + config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000) + | APIC_TRIGGER_MODE_LEVEL | APIC_DELIVERY_MODE_INIT; + apic_write(APIC_INTR_COMMAND_1, config); + + // wait for pending to end + while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) + asm volatile ("pause;"); + + /* wait 10ms */ + spin(10000); + /* is this a local apic or an 82489dx ? */ + numStartups = (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) + ? 2 : 0; + for (j = 0; j < numStartups; j++) { + /* it's a local apic, so send STARTUP IPIs */ + apic_write(APIC_ERROR_STATUS, 0); + + /* set target pe */ + config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) + | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); + apic_write(APIC_INTR_COMMAND_2, config); + + /* send the IPI */ + config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff0f800) + | APIC_DELIVERY_MODE_STARTUP | (trampolineCode >> 12); + apic_write(APIC_INTR_COMMAND_1, config); + + /* wait */ + spin(200); + + while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) + asm volatile ("pause;"); + } + + // Wait for the trampoline code to clear the final stack location. + // This serves as a notification for us that it has loaded the address + // and it is safe for us to overwrite it to trampoline the next CPU. + while (args->sentinel != 0) + spin(1000); + } + + TRACE(("done trampolining\n")); +} + + +void +smp_add_safemode_menus(Menu *menu) +{ + MenuItem *item; + + if (gKernelArgs.arch_args.ioapic_phys != 0) { + menu->AddItem(item = new(nothrow) MenuItem("Disable IO-APIC")); + item->SetType(MENU_ITEM_MARKABLE); + item->SetData(B_SAFEMODE_DISABLE_IOAPIC); + item->SetHelpText("Disables using the IO APIC for interrupt routing, " + "forcing the use of the legacy PIC instead."); + } + + if (gKernelArgs.arch_args.apic_phys != 0) { + menu->AddItem(item = new(nothrow) MenuItem("Disable local APIC")); + item->SetType(MENU_ITEM_MARKABLE); + item->SetData(B_SAFEMODE_DISABLE_APIC); + item->SetHelpText("Disables using the local APIC, also disables SMP."); + + cpuid_info info; + if (get_current_cpuid(&info, 1, 0) == B_OK + && (info.regs.ecx & IA32_FEATURE_EXT_X2APIC) != 0) { +#if 0 + menu->AddItem(item = new(nothrow) MenuItem("Disable X2APIC")); + item->SetType(MENU_ITEM_MARKABLE); + item->SetData(B_SAFEMODE_DISABLE_X2APIC); + item->SetHelpText("Disables using X2APIC."); +#else + menu->AddItem(item = new(nothrow) MenuItem("Enable X2APIC")); + item->SetType(MENU_ITEM_MARKABLE); + item->SetData(B_SAFEMODE_ENABLE_X2APIC); + item->SetHelpText("Enables using X2APIC."); +#endif + } + } + + if (gKernelArgs.num_cpus < 2) + return; + + item = new(nothrow) MenuItem("Disable SMP"); + menu->AddItem(item); + item->SetData(B_SAFEMODE_DISABLE_SMP); + item->SetType(MENU_ITEM_MARKABLE); + item->SetHelpText("Disables all but one CPU core."); +} + + +void +smp_init(void) +{ +#if NO_SMP + gKernelArgs.num_cpus = 1; + return; +#endif + + cpuid_info info; + if (get_current_cpuid(&info, 1, 0) != B_OK) + return; + + if ((info.eax_1.features & IA32_FEATURE_APIC) == 0) { + // Local APICs aren't present; As they form the basis for all inter CPU + // communication and therefore SMP, we don't need to go any further. + TRACE(("no local APIC present, not attempting SMP init\n")); + return; + } + + // first try to find ACPI tables to get MP configuration as it handles + // physical as well as logical MP configurations as in multiple cpus, + // multiple cores or hyper threading. + if (smp_do_acpi_config() == B_OK) { + TRACE(("smp init success\n")); + return; + } + + // Everything failed or we are not running an SMP system, reset anything + // that might have been set through an incomplete configuration attempt. + gKernelArgs.arch_args.apic_phys = 0; + gKernelArgs.arch_args.ioapic_phys = 0; + gKernelArgs.num_cpus = 1; +} diff --git a/src/system/boot/platform/efi/smp.h b/src/system/boot/platform/efi/smp.h new file mode 100644 index 0000000000..b2eda62368 --- /dev/null +++ b/src/system/boot/platform/efi/smp.h @@ -0,0 +1,30 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef SMP_H +#define SMP_H + + +#include + + +#ifdef __cplusplus +// this is only available in C++ +# include +extern void smp_add_safemode_menus(Menu *menu); + +extern "C" { +#endif + +extern void smp_init(void); +extern void smp_init_other_cpus(void); +extern void smp_boot_other_cpus(uint32 pml4, uint32 gdt64, uint64 kernel_entry); + +extern int smp_get_current_cpu(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SMP_H */ diff --git a/src/system/boot/platform/efi/smp_trampoline.S b/src/system/boot/platform/efi/smp_trampoline.S new file mode 100644 index 0000000000..48cebf493f --- /dev/null +++ b/src/system/boot/platform/efi/smp_trampoline.S @@ -0,0 +1,129 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Copyright 2012, Alex Smith, alex@alex-smith.me.uk. +** Distributed under the terms of the NewOS License. +*/ + +// Relocatable. Before calling, smp_trampoline_args should point +// to a struct trampoline_args (see smp.cpp). This pointer should +// be 16-byte aligned, below 1MB and identity-mapped. +.globl smp_trampoline +.globl smp_trampoline_end +.globl smp_trampoline_args + +#include + +#include +#include "mmu.h" + +.code16 +smp_trampoline: + cli + +// movl 0xdeadbeef, esi + .byte 0x66 + .byte 0xbe +smp_trampoline_args: + .long 0xdeadbeef + + // Load the trampoline args into ss. + movl %esi, %eax + shrl $4, %eax + movw %ax, %ss + xorw %sp, %sp + + // Switch to protected mode. + popl %ebx + popl %edx + lgdt (%edx) + + movl %cr0,%eax + orl $0x01,%eax + movl %eax,%cr0 + + pushl $8 + leal (trampoline_32 - smp_trampoline)(%ebx), %eax + pushl %eax + .byte 0x66 +.code32 + retf + +trampoline_32: + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + // Put the trampoline args on the stack. + movl %esi, %esp + addl $8, %esp + + // Enable PAE and PGE + movl %cr4, %eax + orl $(1 << 5) | (1 << 7), %eax + movl %eax, %cr4 + + // Point CR3 to the kernel's PML4. + popl %eax + movl %eax, %cr3 + + // Enable long mode by setting EFER.LME. + movl $0xc0000080, %ecx + rdmsr + orl $(1 << 8), %eax + wrmsr + + // Re-enable paging, which will put us in compatibility mode as we are + // currently in a 32-bit code segment. + movl %cr0, %ecx + orl $(1 << 31), %ecx + movl %ecx, %cr0 + + // Load 64-bit enabled GDT + popl %eax + lgdtl (%eax) + + // Jump into the 64-bit code segment. + pushl $KERNEL_CODE_SELECTOR + leal (.Llmode - smp_trampoline)(%ebx), %eax + pushl %eax + retf +.align 8 +.code64 +.Llmode: + // Set data segments. + mov $KERNEL_DATA_SELECTOR, %ax + mov %ax, %ss + xor %ax, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + // Initialisation that comes from long_smp_start_kernel. + movq %cr0, %rax + orq $0x10000, %rax + andq $(~6), %rax + movq %rax, %cr0 + fninit + movq %cr4, %rax + orq $0x600, %rax + movq %rax, %cr4 + + // Get kernel arguments. + popq %rax + popq %rdi + popq %rsi + + // Set the stack pointer, write to the sentinel and clear the stack frame/RFLAGS. + popq %rbp + movq $0, (%rsp) + movq %rbp, %rsp + xorq %rbp, %rbp + push $0 + popf + + // Call the entry point. + call *%rax +smp_trampoline_end: diff --git a/src/system/boot/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp new file mode 100644 index 0000000000..1c035c713c --- /dev/null +++ b/src/system/boot/platform/efi/start.cpp @@ -0,0 +1,295 @@ +/* + * Copyright 2014-2016 Haiku, Inc. All rights reserved. + * Copyright 2013-2014, Fredrik Holmqvist, fredrik.holmqvist@gmail.com. + * Copyright 2014, Henry Harrington, henry.harrington@gmail.com. + * All rights reserved. + * Distributed under the terms of the Haiku License. + */ + + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "acpi.h" +#include "console.h" +#include "efi_platform.h" +#include "hpet.h" +#include "cpu.h" +#include "mmu.h" +#include "smp.h" + + +extern void (*__ctor_list)(void); +extern void (*__ctor_end)(void); + + +const EFI_SYSTEM_TABLE *kSystemTable; +const EFI_BOOT_SERVICES *kBootServices; +const EFI_RUNTIME_SERVICES *kRuntimeServices; +EFI_HANDLE kImage; + + +static uint32 sBootOptions; +static uint64 gLongKernelEntry; +extern uint64 gLongGDT; +extern uint64 gLongGDTR; +segment_descriptor gBootGDT[BOOT_GDT_SEGMENT_COUNT]; + + +extern "C" int main(stage2_args *args); +extern "C" void _start(void); +extern "C" void efi_enter_kernel(uint64 pml4, uint64 entry_point, uint64 stack); + + +static void +call_ctors(void) +{ + void (**f)(void); + + for (f = &__ctor_list; f < &__ctor_end; f++) + (**f)(); +} + + +extern "C" uint32 +platform_boot_options() +{ + return sBootOptions; +} + + +static void +long_gdt_init() +{ + clear_segment_descriptor(&gBootGDT[0]); + + // Set up code/data segments (TSS segments set up later in the kernel). + set_segment_descriptor(&gBootGDT[KERNEL_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY, + DPL_KERNEL); + set_segment_descriptor(&gBootGDT[KERNEL_DATA_SEGMENT], DT_DATA_WRITEABLE, + DPL_KERNEL); + set_segment_descriptor(&gBootGDT[USER_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY, + DPL_USER); + set_segment_descriptor(&gBootGDT[USER_DATA_SEGMENT], DT_DATA_WRITEABLE, + DPL_USER); + + // Used by long_enter_kernel(). + gLongGDT = (addr_t)gBootGDT + 0xFFFFFF0000000000; + dprintf("GDT at 0x%lx\n", gLongGDT); +} + + +static void +convert_preloaded_image(preloaded_elf64_image* image) +{ + fix_address(image->next); + fix_address(image->name); + fix_address(image->debug_string_table); + fix_address(image->syms); + fix_address(image->rel); + fix_address(image->rela); + fix_address(image->pltrel); + fix_address(image->debug_symbols); +} + + +/*! Convert all addresses in kernel_args to 64-bit addresses. */ +static void +convert_kernel_args() +{ + fix_address(gKernelArgs.boot_volume); + fix_address(gKernelArgs.vesa_modes); + fix_address(gKernelArgs.edid_info); + fix_address(gKernelArgs.debug_output); + fix_address(gKernelArgs.boot_splash); + fix_address(gKernelArgs.arch_args.apic); + fix_address(gKernelArgs.arch_args.hpet); + + convert_preloaded_image(static_cast( + gKernelArgs.kernel_image.Pointer())); + fix_address(gKernelArgs.kernel_image); + + // Iterate over the preloaded images. Must save the next address before + // converting, as the next pointer will be converted. + preloaded_image* image = gKernelArgs.preloaded_images; + fix_address(gKernelArgs.preloaded_images); + while (image != NULL) { + preloaded_image* next = image->next; + convert_preloaded_image(static_cast(image)); + image = next; + } + + // Fix driver settings files. + driver_settings_file* file = gKernelArgs.driver_settings; + fix_address(gKernelArgs.driver_settings); + while (file != NULL) { + driver_settings_file* next = file->next; + fix_address(file->next); + fix_address(file->buffer); + file = next; + } +} + + +extern "C" void +platform_start_kernel(void) +{ + if (gKernelArgs.kernel_image->elf_class != ELFCLASS64) + panic("32-bit kernels not supported with EFI"); + + cpu_init(); + acpi_init(); + hpet_init(); + smp_init(); + smp_init_other_cpus(); + + preloaded_elf64_image *image = static_cast( + gKernelArgs.kernel_image.Pointer()); + + long_gdt_init(); + convert_kernel_args(); + + // Save the kernel entry point address. + gLongKernelEntry = image->elf_header.e_entry; + dprintf("kernel entry at %#lx\n", gLongKernelEntry); + + // map in a kernel stack + void *stack_address = NULL; + if (platform_allocate_region(&stack_address, KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, 0, false) != B_OK) { + panic("Unabled to allocate a stack"); + } + gKernelArgs.cpu_kstack[0].start = fix_address((uint64_t)stack_address); + gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; + dprintf("Kernel stack at %#lx\n", gKernelArgs.cpu_kstack[0].start); + + // Prepare to exit EFI boot services. + // Read the memory map. + // First call is to determine the buffer size. + UINTN memory_map_size = 0; + EFI_MEMORY_DESCRIPTOR dummy; + EFI_MEMORY_DESCRIPTOR *memory_map; + UINTN map_key; + UINTN descriptor_size; + UINT32 descriptor_version; + if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key, &descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) { + panic("Unable to determine size of system memory map"); + } + + // Allocate a buffer twice as large as needed just in case it gets bigger between + // calls to ExitBootServices. + UINTN actual_memory_map_size = memory_map_size * 2; + memory_map = (EFI_MEMORY_DESCRIPTOR *)kernel_args_malloc(actual_memory_map_size); + if (memory_map == NULL) + panic("Unable to allocate memory map."); + + // Read (and print) the memory map. + memory_map_size = actual_memory_map_size; + if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, &descriptor_size, &descriptor_version) != EFI_SUCCESS) { + panic("Unable to fetch system memory map."); + } + + addr_t addr = (addr_t)memory_map; + dprintf("System provided memory map:\n"); + for (UINTN i = 0; i < memory_map_size / descriptor_size; ++i) { + EFI_MEMORY_DESCRIPTOR *entry = (EFI_MEMORY_DESCRIPTOR *)(addr + i * descriptor_size); + dprintf(" %#lx-%#lx %#lx %#x %#lx\n", + entry->PhysicalStart, entry->PhysicalStart + entry->NumberOfPages * 4096, + entry->VirtualStart, entry->Type, entry->Attribute); + } + + // Generate page tables for use after ExitBootServices. + uint64_t final_pml4 = mmu_generate_post_efi_page_tables(memory_map_size, memory_map, descriptor_size, descriptor_version); + dprintf("Final PML4 at %#lx\n", final_pml4); + + // Attempt to fetch the memory map and exit boot services. + // This needs to be done in a loop, as ExitBootServices can change the + // memory map. + // Even better: Only GetMemoryMap and ExitBootServices can be called after + // the first call to ExitBootServices, as the firmware is permitted to + // partially exit. This is why twice as much space was allocated for the + // memory map, as it's impossible to allocate more now. + // A changing memory map shouldn't affect the generated page tables, as + // they only needed to know about the maximum address, not any specific + // entry. + dprintf("Calling ExitBootServices. So long, EFI!\n"); + while (true) { + if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) { + break; + } + + memory_map_size = actual_memory_map_size; + if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, &descriptor_size, &descriptor_version) != EFI_SUCCESS) { + panic("Unable to fetch system memory map."); + } + } + // We're on our own now... + + // The console was provided by boot services, disable it. + stdout = NULL; + + // Update EFI, generate final kernel physical memory map, etc. + mmu_post_efi_setup(memory_map_size, memory_map, descriptor_size, descriptor_version); + + smp_boot_other_cpus(final_pml4, (uint32_t)(uint64_t)&gLongGDTR, gLongKernelEntry); + + // Enter the kernel! + efi_enter_kernel(final_pml4, + gLongKernelEntry, + gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size); + + panic("Shouldn't get here"); +} + + +extern "C" void +platform_exit(void) +{ + return; +} + + +/** + * efi_main - The entry point for the EFI application + * @image: firmware-allocated handle that identifies the image + * @systemTable: EFI system table + */ +extern "C" EFI_STATUS +efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) +{ + stage2_args args; + + memset(&args, 0, sizeof(stage2_args)); + + kImage = image; + kSystemTable = systemTable; + kBootServices = systemTable->BootServices; + kRuntimeServices = systemTable->RuntimeServices; + + memset(&args, 0, sizeof(stage2_args)); + + call_ctors(); + + console_init(); + + sBootOptions = console_check_boot_keys(); + + // disable apm in case we ever load a 32-bit kernel... + gKernelArgs.platform_args.apm.version = 0; + + gKernelArgs.num_cpus = 1; + gKernelArgs.arch_args.hpet_phys = 0; + gKernelArgs.arch_args.hpet = NULL; + + main(&args); + + return EFI_SUCCESS; +} diff --git a/src/system/boot/platform/efi/support.S b/src/system/boot/platform/efi/support.S new file mode 100644 index 0000000000..81828472d6 --- /dev/null +++ b/src/system/boot/platform/efi/support.S @@ -0,0 +1,39 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + + +#define FUNCTION(x) .global x; .type x,@function; x + + +/* uint64 rdtsc() */ +FUNCTION(rdtsc): + rdtsc + /* Convert to 64-bit result in rax. */ + shlq $32, %rdx + orq %rdx, %rax + ret + +FUNCTION(execute_n_instructions): + movl %edi, %ecx + shrl $4, %ecx +.again: + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + loop .again + ret diff --git a/src/system/boot/platform/efi/video.cpp b/src/system/boot/platform/efi/video.cpp new file mode 100644 index 0000000000..68a35aca2d --- /dev/null +++ b/src/system/boot/platform/efi/video.cpp @@ -0,0 +1,108 @@ +/* + * Copyright 2016, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include + +#include "efi_platform.h" + + +static EFI_GUID sGraphicsOutputGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +static EFI_GRAPHICS_OUTPUT_PROTOCOL *sGraphicsOutput; +static UINTN sGraphicsMode; + + +extern "C" status_t +platform_init_video(void) +{ + EFI_STATUS status = kBootServices->LocateProtocol(&sGraphicsOutputGuid, + NULL, (void **)&sGraphicsOutput); + if (sGraphicsOutput == NULL || status != EFI_SUCCESS) { + gKernelArgs.frame_buffer.enabled = false; + sGraphicsOutput = NULL; + return B_ERROR; + } + + UINTN bestArea = 0; + UINTN bestDepth = 0; + + for (UINTN mode = 0; mode < sGraphicsOutput->Mode->MaxMode; ++mode) { + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; + UINTN size, depth; + sGraphicsOutput->QueryMode(sGraphicsOutput, mode, &size, &info); + UINTN area = info->HorizontalResolution * info->VerticalResolution; + if (info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) + depth = 32; + else if (info->PixelFormat == PixelBitMask + && info->PixelInformation.RedMask == 0xFF0000 + && info->PixelInformation.GreenMask == 0x00FF00 + && info->PixelInformation.BlueMask == 0x0000FF + && info->PixelInformation.ReservedMask == 0) + depth = 24; + else + continue; + + area *= depth; + if (area >= bestArea) { + bestArea = area; + bestDepth = depth; + sGraphicsMode = mode; + } + } + + if (bestArea == 0 || bestDepth == 0) { + sGraphicsOutput = NULL; + return B_ERROR; + } + + return B_OK; +} + + +extern "C" void +platform_switch_to_logo(void) +{ + if (sGraphicsOutput == NULL || gKernelArgs.frame_buffer.enabled) + return; + + sGraphicsOutput->SetMode(sGraphicsOutput, sGraphicsMode); + gKernelArgs.frame_buffer.enabled = true; + gKernelArgs.frame_buffer.physical_buffer.start = + sGraphicsOutput->Mode->FrameBufferBase; + gKernelArgs.frame_buffer.physical_buffer.size = + sGraphicsOutput->Mode->FrameBufferSize; + gKernelArgs.frame_buffer.width = + sGraphicsOutput->Mode->Info->HorizontalResolution; + gKernelArgs.frame_buffer.height = + sGraphicsOutput->Mode->Info->VerticalResolution; + gKernelArgs.frame_buffer.depth = + sGraphicsOutput->Mode->Info->PixelFormat == PixelBitMask ? 24 : 32; + gKernelArgs.frame_buffer.bytes_per_row = + sGraphicsOutput->Mode->Info->PixelsPerScanLine + * gKernelArgs.frame_buffer.depth / 8; + + video_display_splash(gKernelArgs.frame_buffer.physical_buffer.start); +} + + +extern "C" void +platform_blit4(addr_t frameBuffer, const uint8 *data, + uint16 width, uint16 height, uint16 imageWidth, + uint16 left, uint16 top) +{ + panic("platform_blit4 unsupported"); + return; +} + + +extern "C" void +platform_set_palette(const uint8 *palette) +{ + panic("platform_set_palette unsupported"); + return; +} diff --git a/src/system/boot/platform/generic/Jamfile b/src/system/boot/platform/generic/Jamfile index 0ffd7b2cb5..565f3662d8 100644 --- a/src/system/boot/platform/generic/Jamfile +++ b/src/system/boot/platform/generic/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot platform generic ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + UseBuildFeatureHeaders zlib ; UsePrivateKernelHeaders ; @@ -9,8 +11,7 @@ BootStaticLibrary boot_platform_generic : text_menu.cpp video_blit.cpp video_splash.cpp - : -fno-pic ; -Includes [ FGristFiles video_splash.cpp ] +Includes [ FGristFiles video_splash.cpp ] : [ BuildFeatureAttribute zlib : headers ] ; diff --git a/src/system/boot/platform/pxe_ia32/Jamfile b/src/system/boot/platform/pxe_ia32/Jamfile index 7adb3072ec..74d51b85ec 100644 --- a/src/system/boot/platform/pxe_ia32/Jamfile +++ b/src/system/boot/platform/pxe_ia32/Jamfile @@ -57,7 +57,7 @@ BootMergeObject boot_platform_pxe_ia32.o : $(bios_ia32_src) $(bios_ia32_edid_src) - : -fno-pic + : : boot_platform_generic.a ; diff --git a/src/system/boot/platform/raspberrypi_arm/Jamfile b/src/system/boot/platform/raspberrypi_arm/Jamfile index bd6a8abb0f..d9a102d80d 100644 --- a/src/system/boot/platform/raspberrypi_arm/Jamfile +++ b/src/system/boot/platform/raspberrypi_arm/Jamfile @@ -40,7 +40,7 @@ BootMergeObject boot_platform_raspberrypi_arm.o : arch_framebuffer_bcm2835.cpp $(genericPlatformSources) - : -fno-pic + : : boot_platform_generic.a ; diff --git a/src/system/boot/platform/u-boot/Jamfile b/src/system/boot/platform/u-boot/Jamfile index a2e84e18a5..52aed326fc 100644 --- a/src/system/boot/platform/u-boot/Jamfile +++ b/src/system/boot/platform/u-boot/Jamfile @@ -59,7 +59,7 @@ BootMergeObject boot_platform_u-boot_common.o : $(libFDTSources) - : -fno-pic + : : boot_platform_generic.a ; diff --git a/src/system/boot/platform/u-boot/arch/arm/Jamfile b/src/system/boot/platform/u-boot/arch/arm/Jamfile index 7463dc9a49..8a7939a5f1 100644 --- a/src/system/boot/platform/u-boot/arch/arm/Jamfile +++ b/src/system/boot/platform/u-boot/arch/arm/Jamfile @@ -16,7 +16,6 @@ BootMergeObject boot_platform_u-boot_arm.o : shell.S arch_mailbox.cpp - : -fno-pic ; #SEARCH on [ FGristFiles arch_cpu_asm.S ] diff --git a/src/system/boot/platform/u-boot/arch/ppc/Jamfile b/src/system/boot/platform/u-boot/arch/ppc/Jamfile index 639e56fd35..d7dbefb5d2 100644 --- a/src/system/boot/platform/u-boot/arch/ppc/Jamfile +++ b/src/system/boot/platform/u-boot/arch/ppc/Jamfile @@ -12,7 +12,7 @@ SubDirC++Flags -fno-rtti ; BootMergeObject boot_platform_u-boot_ppc_amcc440.o : arch_mmu_amcc440.cpp - : -fno-pic -mcpu=440 + : -mcpu=440 ; BootMergeObject boot_platform_u-boot_ppc.o : @@ -24,7 +24,7 @@ BootMergeObject boot_platform_u-boot_ppc.o : arch_start_kernel.S arch_cpu.cpp #mmu.cpp - : -fno-pic + : : boot_platform_u-boot_ppc_amcc440.o ; diff --git a/src/system/kernel/arch/x86/arch_elf.cpp b/src/system/kernel/arch/x86/arch_elf.cpp index eef0c8c71e..204eb522ac 100644 --- a/src/system/kernel/arch/x86/arch_elf.cpp +++ b/src/system/kernel/arch/x86/arch_elf.cpp @@ -37,7 +37,7 @@ is_in_image(struct elf_image_info *image, addr_t address) #endif // !_BOOT_MODE -#if !defined(__x86_64__) || defined(_BOOT_MODE) +#if !defined(__x86_64__) || (defined(_BOOT_MODE) && _BOOT_PLATFORM != efi) #ifdef TRACE_ARCH_ELF @@ -183,7 +183,7 @@ arch_elf_relocate_rela(struct elf_image_info *image, } -#endif // !__x86_64__ || _BOOT_MODE +#endif // !__x86_64__ || (_BOOT_MODE && _BOOT_PLATFORM != efi) #if defined(__x86_64__) || defined(_BOOT_MODE) diff --git a/src/system/kernel/arch/x86/arch_platform.cpp b/src/system/kernel/arch/x86/arch_platform.cpp index d967139701..ac15e227df 100644 --- a/src/system/kernel/arch/x86/arch_platform.cpp +++ b/src/system/kernel/arch/x86/arch_platform.cpp @@ -1,38 +1,44 @@ -/* - * Copyright 2006, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Ingo Weinhold - * Axel Dörfler, axeld@pinc-software.de - */ - - -#include -#include - - -status_t -arch_platform_init(struct kernel_args *args) -{ - return B_OK; -} - - -status_t -arch_platform_init_post_vm(struct kernel_args *args) -{ - return B_OK; -} - - -status_t -arch_platform_init_post_thread(struct kernel_args *args) -{ - // APM is not supported on x86_64. -#ifndef __x86_64__ - apm_init(args); -#endif - return B_OK; -} - +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include +#include +#include +#include + + +status_t +arch_platform_init(struct kernel_args *args) +{ + return B_OK; +} + + +status_t +arch_platform_init_post_vm(struct kernel_args *args) +{ + // Now we can add boot items; pass on the ACPI root pointer + add_boot_item("ACPI_ROOT_POINTER", + args->arch_args.acpi_root.Pointer(), sizeof(void*)); + + return B_OK; +} + + +status_t +arch_platform_init_post_thread(struct kernel_args *args) +{ + // APM is not supported on x86_64. +#ifndef __x86_64__ + apm_init(args); +#endif + return B_OK; +} + diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 553f937ced..5a148a7ab4 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -3916,6 +3916,26 @@ vm_allocate_early_physical_page(kernel_args* args) } } + // Expanding upwards didn't work, try going downwards. + for (uint32 i = 0; i < args->num_physical_allocated_ranges; i++) { + phys_addr_t nextPage; + + nextPage = args->physical_allocated_range[i].start - B_PAGE_SIZE; + // see if the page after the prev allocated paddr run can be allocated + if (i > 0 && args->physical_allocated_range[i - 1].size != 0) { + // see if the next page will collide with the next allocated range + if (nextPage < args->physical_allocated_range[i-1].start + args->physical_allocated_range[i-1].size) + continue; + } + // see if the next physical page fits in the memory block + if (is_page_in_physical_memory_range(args, nextPage)) { + // we got one! + args->physical_allocated_range[i].start -= B_PAGE_SIZE; + args->physical_allocated_range[i].size += B_PAGE_SIZE; + return nextPage / B_PAGE_SIZE; + } + } + return 0; // could not allocate a block } diff --git a/src/system/ldscripts/x86_64/boot_loader_efi.ld b/src/system/ldscripts/x86_64/boot_loader_efi.ld new file mode 100644 index 0000000000..88f4b25d1f --- /dev/null +++ b/src/system/ldscripts/x86_64/boot_loader_efi.ld @@ -0,0 +1,79 @@ +/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below & ctor support - KEEP IN SYNC */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + . = 0; + ImageBase = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = ALIGN(4096); + .eh_frame : + { + *(.eh_frame) + } + . = ALIGN(4096); + .text : + { + _text = .; + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + . = ALIGN(16); + } + _etext = .; + _text_size = . - _text; + . = ALIGN(4096); + .reloc : + { + *(.reloc) + } + . = ALIGN(4096); + .data : + { + . = ALIGN(0x4); + __ctor_list = .; + *(.ctors) + __ctor_end = .; + _data = .; + *(.rodata*) + *(.got.plt) + *(.got) + *(.data*) + *(.sdata) + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + *(.rel.local) + } + .note.gnu.build-id : { *(.note.gnu.build-id) } + + _edata = .; + _data_size = . - _etext; + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rela : + { + *(.rela.data*) + *(.rela.ctors) + *(.rela.got) + *(.rela.stab) + } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .ignored.reloc : + { + *(.rela.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +}