From 20e11028aa31e17ff6f4a08f288afa0e703cc6f2 Mon Sep 17 00:00:00 2001 From: Fredrik Holmqvist Date: Sun, 8 Sep 2013 13:22:29 +0200 Subject: [PATCH 01/21] Don't use partition pointer as id, as it only works on 32bit platforms. Use a counter to generate the partition id, and store the id to partition lookup in a hashmap instead. --- src/system/boot/loader/partitions.cpp | 30 ++++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/system/boot/loader/partitions.cpp b/src/system/boot/loader/partitions.cpp index f70bc8a407..21348ed824 100644 --- a/src/system/boot/loader/partitions.cpp +++ b/src/system/boot/loader/partitions.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "RootFileSystem.h" @@ -99,6 +100,10 @@ private: }; +static int32 sIdCounter = 0; +static HashMap, Partition*> sIdPartitionMap; + + // #pragma mark - @@ -111,7 +116,9 @@ 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); + sIdPartitionMap.Put(id, this); // it's safe to close the file fFD = dup(fd); @@ -132,6 +139,7 @@ Partition::~Partition() child->SetParent(NULL); } + sIdPartitionMap.Remove(id); close(fFD); } @@ -469,8 +477,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 = sIdPartitionMap.Get(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,8 +503,6 @@ 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)); @@ -503,8 +514,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 = sIdPartitionMap.Get(id); + if (partition == NULL) { + dprintf("could not find parent partition.\n"); + return NULL; + } + return partition->Parent(); } From 211483cb512baaca8b17e0112a360b5a17cde0ca Mon Sep 17 00:00:00 2001 From: Fredrik Holmqvist Date: Thu, 14 Apr 2016 19:15:55 +1200 Subject: [PATCH 02/21] EFI: Initial test EFI application * Only set HAIKU_BOOT_PLATFORM to bios_ia32 if not defined * Add gnuefi build feature * Introduce BOOT_LDFLAGS, and move options for passing to linker into ArchitectureSetup * x86_64 compile fixes for warnings in boot loader * loader/elf.cpp: don't include ELF32 support when targeting EFI * relocation_func.cpp: copy of the relocation code from gnuefi to make _relocate extern "C", and avoid including * boot_loader_efi.ld: copy of gnuefi's elf_x86_64_efi.lds, modified to include support for C++ constructors, etc. Keep in sync with the gnuefi package Signed-off-by: Jessica Hamilton --- build/jam/ArchitectureRules | 39 +++++--- build/jam/BootRules | 2 +- build/jam/BuildFeatures | 17 ++++ build/jam/BuildSetup | 2 +- build/jam/repositories/HaikuPorts/x86_64 | 0 .../boot/platform/efi/platform_kernel_args.h | 46 +++++++++ .../boot/platform/efi/platform_stage2_args.h | 17 ++++ src/system/boot/Jamfile | 33 +++++-- src/system/boot/arch/x86/Jamfile | 34 ++++--- src/system/boot/loader/Jamfile | 5 + src/system/boot/loader/elf.cpp | 15 ++- .../loader/file_systems/amiga_ffs/File.cpp | 2 +- .../file_systems/amiga_ffs/amiga_ffs.cpp | 2 +- .../boot/loader/file_systems/bfs/Stream.cpp | 2 +- .../boot/loader/file_systems/bfs/bfs.cpp | 3 +- .../boot/loader/file_systems/fat/Stream.cpp | 2 +- .../file_systems/packagefs/packagefs.cpp | 2 +- .../boot/loader/load_driver_settings.cpp | 2 +- src/system/boot/loader/loader.cpp | 6 +- src/system/boot/loader/net/RemoteDisk.cpp | 3 +- src/system/boot/loader/partitions.cpp | 17 ++-- src/system/boot/loader/vfs.cpp | 4 +- src/system/boot/platform/efi/Jamfile | 40 ++++++++ .../efi/arch/x86_64/relocation_func.cpp | 97 +++++++++++++++++++ src/system/boot/platform/efi/start.c | 58 +++++++++++ src/system/kernel/arch/x86/arch_elf.cpp | 4 +- .../ldscripts/x86_64/boot_loader_efi.ld | 79 +++++++++++++++ 27 files changed, 474 insertions(+), 59 deletions(-) mode change 100755 => 100644 build/jam/repositories/HaikuPorts/x86_64 create mode 100644 headers/private/kernel/boot/platform/efi/platform_kernel_args.h create mode 100644 headers/private/kernel/boot/platform/efi/platform_stage2_args.h create mode 100644 src/system/boot/platform/efi/Jamfile create mode 100644 src/system/boot/platform/efi/arch/x86_64/relocation_func.cpp create mode 100644 src/system/boot/platform/efi/start.c create mode 100644 src/system/ldscripts/x86_64/boot_loader_efi.ld diff --git a/build/jam/ArchitectureRules b/build/jam/ArchitectureRules index 0730e2db7c..0c824c4fdc 100644 --- a/build/jam/ArchitectureRules +++ b/build/jam/ArchitectureRules @@ -279,7 +279,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 @@ -291,7 +291,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 @@ -326,12 +326,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 @@ -361,6 +355,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 ; @@ -370,6 +365,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 @@ -401,10 +406,20 @@ 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 ; } # 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 e70a411ad4..0f80ffdf56 100644 --- a/build/jam/BuildFeatures +++ b/build/jam/BuildFeatures @@ -571,6 +571,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 d13922a9a4..a96f847ef2 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -649,7 +649,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/build/jam/repositories/HaikuPorts/x86_64 b/build/jam/repositories/HaikuPorts/x86_64 old mode 100755 new mode 100644 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/system/boot/Jamfile b/src/system/boot/Jamfile index e751743336..c8099dfb83 100644 --- a/src/system/boot/Jamfile +++ b/src/system/boot/Jamfile @@ -2,8 +2,14 @@ SubDir HAIKU_TOP src system boot ; 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 ] ; @@ -44,11 +50,6 @@ BootMergeObject boot_libroot.o : : -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 +77,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 +131,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/x86/Jamfile b/src/system/boot/arch/x86/Jamfile index 0fd15d01f3..66fb94feae 100644 --- a/src/system/boot/arch/x86/Jamfile +++ b/src/system/boot/arch/x86/Jamfile @@ -6,13 +6,15 @@ 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 +22,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..a44793d93b 100644 --- a/src/system/boot/loader/Jamfile +++ b/src/system/boot/loader/Jamfile @@ -45,6 +45,11 @@ UsePrivateHeaders shared storage ; #BOOT_SUPPORT_FILE_SYSTEM_FAT ; + if $(HAIKU_BOOT_PLATFORM) != efi { + DEFINES += + BOOT_SUPPORT_ELF32 + ; + } } } diff --git a/src/system/boot/loader/elf.cpp b/src/system/boot/loader/elf.cpp index ec685a4fe8..abb4f5e6ca 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 @@ -225,7 +227,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 +322,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 +644,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 +709,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/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/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/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/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/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/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 21348ed824..45c580b48f 100644 --- a/src/system/boot/loader/partitions.cpp +++ b/src/system/boot/loader/partitions.cpp @@ -168,7 +168,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); @@ -185,7 +185,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, @@ -321,7 +321,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 @@ -379,9 +379,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_PRId64 + ", size = %" B_PRIdOFF ", parent = %p)!\n", this, child, + child->offset, child->size, child->Parent())); child->Scan(mountFileSystems); @@ -466,7 +466,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; @@ -505,7 +505,8 @@ get_child_partition(partition_id id, int32 index) { // 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; } diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index 8408970a4a..9a0646053c 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/efi/Jamfile b/src/system/boot/platform/efi/Jamfile new file mode 100644 index 0000000000..cb925349d4 --- /dev/null +++ b/src/system/boot/platform/efi/Jamfile @@ -0,0 +1,40 @@ +SubDir HAIKU_TOP src system boot platform efi ; + +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.c + ; + +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/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/start.c b/src/system/boot/platform/efi/start.c new file mode 100644 index 0000000000..fe36d5c63f --- /dev/null +++ b/src/system/boot/platform/efi/start.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011, Intel Corporation + * 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. + * + * 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 ANY DIRECT, 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 "efibind.h" +#include "efidef.h" +#include "efidevp.h" +#include "eficon.h" +#include "efiprot.h" +#include "efiapi.h" +#include "efierr.h" + +static const CHAR16 *exampleText = L"Example EFI Application. Press any key!"; + +EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable); + +/** + * efi_main - The entry point for the EFI application + * @image: firmware-allocated handle that identifies the image + * @SystemTable: EFI system table + */ +EFI_STATUS +efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) +{ + UINTN index; + EFI_EVENT event = systemTable->ConIn->WaitForKey; + + SIMPLE_TEXT_OUTPUT_INTERFACE *conOut = systemTable->ConOut; + conOut->OutputString(conOut, (CHAR16*)exampleText); + + systemTable->BootServices->WaitForEvent(1, &event, &index); + + return EFI_SUCCESS; +} 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/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) } +} From bd0604764ee1b12fde65c90eeb8621e68d0dd251 Mon Sep 17 00:00:00 2001 From: Fredrik Holmqvist Date: Wed, 6 Nov 2013 21:12:36 +0100 Subject: [PATCH 03/21] Setup -fno-pic or -fpic in Architecture Rules. EFI boot needs -fpic but all boot code was built with -fno-pic. This is now set accordingly in HAIKU_BOOT_CCFLAGS and HAIKU_BOOT_C++FLAGS. Also setup compile flags for EFI platform. --- build/jam/ArchitectureRules | 3 +++ src/system/boot/Jamfile | 1 - src/system/boot/arch/arm/Jamfile | 2 +- src/system/boot/arch/m68k/Jamfile | 8 ++++---- src/system/boot/loader/Jamfile | 3 --- src/system/boot/loader/file_systems/amiga_ffs/Jamfile | 1 - src/system/boot/loader/file_systems/bfs/Jamfile | 1 - src/system/boot/loader/file_systems/fat/Jamfile | 1 - src/system/boot/loader/file_systems/hfs_plus/Jamfile | 1 - src/system/boot/loader/file_systems/packagefs/Jamfile | 2 -- src/system/boot/loader/file_systems/tarfs/Jamfile | 2 -- src/system/boot/loader/net/Jamfile | 2 -- src/system/boot/platform/amiga_m68k/Jamfile | 2 +- src/system/boot/platform/atari_m68k/Jamfile | 2 +- src/system/boot/platform/bios_ia32/Jamfile | 2 +- src/system/boot/platform/generic/Jamfile | 1 - src/system/boot/platform/pxe_ia32/Jamfile | 2 +- src/system/boot/platform/raspberrypi_arm/Jamfile | 2 +- src/system/boot/platform/u-boot/Jamfile | 2 +- src/system/boot/platform/u-boot/arch/arm/Jamfile | 1 - src/system/boot/platform/u-boot/arch/ppc/Jamfile | 4 ++-- 21 files changed, 16 insertions(+), 29 deletions(-) diff --git a/build/jam/ArchitectureRules b/build/jam/ArchitectureRules index 0c824c4fdc..c0c35a1375 100644 --- a/build/jam/ArchitectureRules +++ b/build/jam/ArchitectureRules @@ -420,6 +420,9 @@ rule KernelArchitectureSetup architecture 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 ; + } else { + HAIKU_BOOT_CCFLAGS += -fno-pic ; + HAIKU_BOOT_C++FLAGS += -fno-pic ; } # warning flags diff --git a/src/system/boot/Jamfile b/src/system/boot/Jamfile index c8099dfb83..72bb340278 100644 --- a/src/system/boot/Jamfile +++ b/src/system/boot/Jamfile @@ -47,7 +47,6 @@ BootMergeObject boot_libroot.o : strrchr.c strtol.c $(extraSources) - : -fno-pic ; AddResources haiku_loader : boot_loader.rdef ; 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/loader/Jamfile b/src/system/boot/loader/Jamfile index a44793d93b..2884fe6950 100644 --- a/src/system/boot/loader/Jamfile +++ b/src/system/boot/loader/Jamfile @@ -90,8 +90,6 @@ BootStaticLibrary boot_loader : DataIO.cpp Referenceable.cpp - - : -fno-pic ; # The partition support is built in an extra static library @@ -110,7 +108,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/file_systems/amiga_ffs/Jamfile b/src/system/boot/loader/file_systems/amiga_ffs/Jamfile index 1b2d8bbc27..ce7ec5e28a 100644 --- a/src/system/boot/loader/file_systems/amiga_ffs/Jamfile +++ b/src/system/boot/loader/file_systems/amiga_ffs/Jamfile @@ -13,5 +13,4 @@ BootStaticLibrary boot_amiga_ffs : Volume.cpp Directory.cpp File.cpp - : -fno-pic ; diff --git a/src/system/boot/loader/file_systems/bfs/Jamfile b/src/system/boot/loader/file_systems/bfs/Jamfile index 25827bdd91..bf31e7578b 100644 --- a/src/system/boot/loader/file_systems/bfs/Jamfile +++ b/src/system/boot/loader/file_systems/bfs/Jamfile @@ -18,7 +18,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/fat/Jamfile b/src/system/boot/loader/file_systems/fat/Jamfile index 52de886b8c..ec1ea39899 100644 --- a/src/system/boot/loader/file_systems/fat/Jamfile +++ b/src/system/boot/loader/file_systems/fat/Jamfile @@ -20,5 +20,4 @@ BootStaticLibrary boot_fatfs : Directory.cpp File.cpp Stream.cpp - : -fno-pic ; diff --git a/src/system/boot/loader/file_systems/hfs_plus/Jamfile b/src/system/boot/loader/file_systems/hfs_plus/Jamfile index 13bbb378ac..9617ab0bb3 100644 --- a/src/system/boot/loader/file_systems/hfs_plus/Jamfile +++ b/src/system/boot/loader/file_systems/hfs_plus/Jamfile @@ -8,5 +8,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..d1953b12a9 100644 --- a/src/system/boot/loader/file_systems/packagefs/Jamfile +++ b/src/system/boot/loader/file_systems/packagefs/Jamfile @@ -46,8 +46,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/tarfs/Jamfile b/src/system/boot/loader/file_systems/tarfs/Jamfile index 8d1c40b916..c0dda86520 100644 --- a/src/system/boot/loader/file_systems/tarfs/Jamfile +++ b/src/system/boot/loader/file_systems/tarfs/Jamfile @@ -29,7 +29,6 @@ Depends [ FGristFiles $(zlibSources) ] BootStaticLibrary boot_zlib : $(zlibSources) - : -fno-pic ; @@ -41,5 +40,4 @@ Includes [ FGristFiles tarfs.cpp ] : [ BuildFeatureAttribute zlib : sources ] ; BootStaticLibrary boot_tarfs : tarfs.cpp - : -fno-pic ; diff --git a/src/system/boot/loader/net/Jamfile b/src/system/boot/loader/net/Jamfile index 5bb8291a3f..a06a45a80b 100644 --- a/src/system/boot/loader/net/Jamfile +++ b/src/system/boot/loader/net/Jamfile @@ -23,6 +23,4 @@ BootStaticLibrary boot_net : UDP.cpp $(tcp) $(iscsi) - - : -fno-pic ; 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..3f573c0ae3 100644 --- a/src/system/boot/platform/bios_ia32/Jamfile +++ b/src/system/boot/platform/bios_ia32/Jamfile @@ -47,7 +47,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/generic/Jamfile b/src/system/boot/platform/generic/Jamfile index 0ffd7b2cb5..758d9a83ee 100644 --- a/src/system/boot/platform/generic/Jamfile +++ b/src/system/boot/platform/generic/Jamfile @@ -9,7 +9,6 @@ BootStaticLibrary boot_platform_generic : text_menu.cpp video_blit.cpp video_splash.cpp - : -fno-pic ; Includes [ FGristFiles video_splash.cpp ] 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 ; From 735f1daee956b15d1e2e8a80d54463fd2aba4a61 Mon Sep 17 00:00:00 2001 From: Fredrik Holmqvist Date: Sat, 30 Nov 2013 21:35:06 +0100 Subject: [PATCH 04/21] EFI: Implement console code. --- src/system/boot/platform/efi/Jamfile | 3 +- src/system/boot/platform/efi/console.cpp | 218 ++++++++++++++++++++ src/system/boot/platform/efi/console.h | 15 ++ src/system/boot/platform/efi/efi_platform.h | 23 +++ src/system/boot/platform/efi/start.c | 58 ------ src/system/boot/platform/efi/start.cpp | 53 +++++ 6 files changed, 311 insertions(+), 59 deletions(-) create mode 100644 src/system/boot/platform/efi/console.cpp create mode 100644 src/system/boot/platform/efi/console.h create mode 100644 src/system/boot/platform/efi/efi_platform.h delete mode 100644 src/system/boot/platform/efi/start.c create mode 100644 src/system/boot/platform/efi/start.cpp diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index cb925349d4..c125fab3a9 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -18,7 +18,8 @@ local efi_glue_src = local platform_src = relocation_func.cpp - start.c + start.cpp + console.cpp ; Includes [ FGristFiles $(efi_glue_src) $(platform_src) ] diff --git a/src/system/boot/platform/efi/console.cpp b/src/system/boot/platform/efi/console.cpp new file mode 100644 index 0000000000..47f1cd449d --- /dev/null +++ b/src/system/boot/platform/efi/console.cpp @@ -0,0 +1,218 @@ +/* + * 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; +} + + +extern "C" void +platform_switch_to_text_mode(void) +{ + kSystemTable->ConOut->Reset(kSystemTable->ConOut, false); + kSystemTable->ConOut->SetMode(kSystemTable->ConOut, sScreenMode); +} diff --git a/src/system/boot/platform/efi/console.h b/src/system/boot/platform/efi/console.h new file mode 100644 index 0000000000..15942139e0 --- /dev/null +++ b/src/system/boot/platform/efi/console.h @@ -0,0 +1,15 @@ +/* +** 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 + + +extern "C" status_t console_init(void); + + +#endif /* CONSOLE_H */ 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/start.c b/src/system/boot/platform/efi/start.c deleted file mode 100644 index fe36d5c63f..0000000000 --- a/src/system/boot/platform/efi/start.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2011, Intel Corporation - * 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. - * - * 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 ANY DIRECT, 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 "efibind.h" -#include "efidef.h" -#include "efidevp.h" -#include "eficon.h" -#include "efiprot.h" -#include "efiapi.h" -#include "efierr.h" - -static const CHAR16 *exampleText = L"Example EFI Application. Press any key!"; - -EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable); - -/** - * efi_main - The entry point for the EFI application - * @image: firmware-allocated handle that identifies the image - * @SystemTable: EFI system table - */ -EFI_STATUS -efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) -{ - UINTN index; - EFI_EVENT event = systemTable->ConIn->WaitForKey; - - SIMPLE_TEXT_OUTPUT_INTERFACE *conOut = systemTable->ConOut; - conOut->OutputString(conOut, (CHAR16*)exampleText); - - systemTable->BootServices->WaitForEvent(1, &event, &index); - - return EFI_SUCCESS; -} diff --git a/src/system/boot/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp new file mode 100644 index 0000000000..09ddbf0b84 --- /dev/null +++ b/src/system/boot/platform/efi/start.cpp @@ -0,0 +1,53 @@ +/* + * 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 + +#include "console.h" +#include "efi_platform.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; + + +static void +call_ctors(void) +{ + void (**f)(void); + + for (f = &__ctor_list; f < &__ctor_end; f++) + (**f)(); +} + + +/** + * 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) +{ + kSystemTable = systemTable; + kBootServices = systemTable->BootServices; + kRuntimeServices = systemTable->RuntimeServices; + + call_ctors(); + + console_init(); + + printf("Hello from EFI Loader for Haiku!\nPress any key to continue...\n"); + console_wait_for_key(); + + return EFI_SUCCESS; +} From 495efc382b3cfb100fba1a6e60b6451e5a482ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Sat, 7 Dec 2013 07:47:19 +0100 Subject: [PATCH 05/21] loader: Drop the HashMap for partition lookup by id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HashMap constructor was called before the heap is initialized, ending up calling malloc from the OpenHashMap constructor. Oddly it was still working on x86 but broke other platforms. Instead we add a Lookup() static method to Partition, which by default walks gPartitions for the id, and recursively calls itself on the children lists. This means we must add a partition even temporarily to gPartitions before Scan()ing it though. Signed-off-by: François Revol --- headers/private/kernel/boot/partitions.h | 2 ++ src/system/boot/loader/partitions.cpp | 42 ++++++++++++++++++------ 2 files changed, 34 insertions(+), 10 deletions(-) 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/src/system/boot/loader/partitions.cpp b/src/system/boot/loader/partitions.cpp index 45c580b48f..cfcaaa7639 100644 --- a/src/system/boot/loader/partitions.cpp +++ b/src/system/boot/loader/partitions.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include "RootFileSystem.h" @@ -101,7 +100,6 @@ private: static int32 sIdCounter = 0; -static HashMap, Partition*> sIdPartitionMap; // #pragma mark - @@ -118,7 +116,6 @@ Partition::Partition(int fd) memset((partition_data *)this, 0, sizeof(partition_data)); id = atomic_add(&sIdCounter, 1); - sIdPartitionMap.Put(id, this); // it's safe to close the file fFD = dup(fd); @@ -139,11 +136,33 @@ Partition::~Partition() child->SetParent(NULL); } - sIdPartitionMap.Remove(id); close(fFD); } +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) { @@ -379,7 +398,7 @@ Partition::Scan(bool mountFileSystems, bool isBootDevice) Partition *child = NULL; while ((child = (Partition *)iterator.Next()) != NULL) { - TRACE(("%p Partition::Scan(): scan child %p (start = %" B_PRId64 + TRACE(("%p Partition::Scan(): scan child %p (start = %" B_PRIdOFF ", size = %" B_PRIdOFF ", parent = %p)!\n", this, child, child->offset, child->size, child->Parent())); @@ -439,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; } @@ -477,7 +499,7 @@ partition_data * create_child_partition(partition_id id, int32 index, off_t offset, off_t size, partition_id childID) { - Partition *partition = sIdPartitionMap.Get(id); + Partition *partition = Partition::Lookup(id); if (partition == NULL) { dprintf("creating partition failed: could not find partition.\n"); return NULL; @@ -515,7 +537,7 @@ get_child_partition(partition_id id, int32 index) partition_data * get_parent_partition(partition_id id) { - Partition *partition = sIdPartitionMap.Get(id); + Partition *partition = Partition::Lookup(id); if (partition == NULL) { dprintf("could not find parent partition.\n"); return NULL; From e2e1558a02e410c6c54b62014b2df6096a6f7949 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Thu, 21 Apr 2016 12:37:24 +1200 Subject: [PATCH 06/21] EFI: stub functions so we can call loader's main() function. --- build/jam/ArchitectureRules | 2 +- src/system/boot/platform/efi/Jamfile | 15 ++++++-- src/system/boot/platform/efi/console.cpp | 15 +++++--- src/system/boot/platform/efi/debug.cpp | 44 ++++++++++++++++++++++++ src/system/boot/platform/efi/devices.cpp | 39 +++++++++++++++++++++ src/system/boot/platform/efi/heap.cpp | 22 ++++++++++++ src/system/boot/platform/efi/menu.cpp | 40 +++++++++++++++++++++ src/system/boot/platform/efi/mmu.cpp | 25 ++++++++++++++ src/system/boot/platform/efi/start.cpp | 32 +++++++++++++++-- src/system/boot/platform/efi/video.cpp | 41 ++++++++++++++++++++++ 10 files changed, 263 insertions(+), 12 deletions(-) create mode 100644 src/system/boot/platform/efi/debug.cpp create mode 100644 src/system/boot/platform/efi/devices.cpp create mode 100644 src/system/boot/platform/efi/heap.cpp create mode 100644 src/system/boot/platform/efi/menu.cpp create mode 100644 src/system/boot/platform/efi/mmu.cpp create mode 100644 src/system/boot/platform/efi/video.cpp diff --git a/build/jam/ArchitectureRules b/build/jam/ArchitectureRules index c0c35a1375..6e8564dc18 100644 --- a/build/jam/ArchitectureRules +++ b/build/jam/ArchitectureRules @@ -419,7 +419,7 @@ rule KernelArchitectureSetup architecture -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 ; + HAIKU_BOOT_LDFLAGS = -Bstatic -Bsymbolic -shared -nostdlib -znocombreloc -nostartfiles -no-undefined ; } else { HAIKU_BOOT_CCFLAGS += -fno-pic ; HAIKU_BOOT_C++FLAGS += -fno-pic ; diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index c125fab3a9..38ee97d6bc 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -20,6 +20,12 @@ local platform_src = relocation_func.cpp start.cpp console.cpp + video.cpp + debug.cpp + mmu.cpp + heap.cpp + menu.cpp + devices.cpp ; Includes [ FGristFiles $(efi_glue_src) $(platform_src) ] @@ -36,6 +42,9 @@ BootMergeObject boot_platform_efi.o : : 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 ] ; +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/console.cpp b/src/system/boot/platform/efi/console.cpp index 47f1cd449d..c3a12138d0 100644 --- a/src/system/boot/platform/efi/console.cpp +++ b/src/system/boot/platform/efi/console.cpp @@ -1,6 +1,7 @@ /* * Copyright 2014-2016 Haiku, Inc. All rights reserved. - * Copyright 2013 Fredrik Holmqvist, fredrik.holmqvist@gmail.com. All rights reserved. + * Copyright 2013 Fredrik Holmqvist, fredrik.holmqvist@gmail.com. All rights + * reserved. * Distributed under the terms of the MIT License. */ @@ -22,8 +23,10 @@ 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); + 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); }; @@ -51,7 +54,8 @@ Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) ssize_t -Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, size_t bufferSize) +Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, + size_t bufferSize) { const char *string = (const char *)buffer; CHAR16 ucsBuffer[bufferSize + 3]; @@ -67,7 +71,8 @@ Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, size_t bufferS //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); + kSystemTable->ConOut->OutputString(kSystemTable->ConOut, + ucsBuffer); j = 0; continue; } 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..de151c276c --- /dev/null +++ b/src/system/boot/platform/efi/devices.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + + +status_t +platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) +{ + return B_ERROR; +} + + +status_t +platform_add_block_devices(struct stage2_args *args, NodeList *devicesList) +{ + return B_ERROR; +} + + +status_t +platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, + NodeList *partitions, boot::Partition **_partition) +{ + panic("platform_get_boot_partition not implemented"); + return B_ERROR; +} + + +status_t +platform_register_boot_device(Node *device) +{ + panic("platform_register_boot_device not implemented"); + return B_ERROR; +} diff --git a/src/system/boot/platform/efi/heap.cpp b/src/system/boot/platform/efi/heap.cpp new file mode 100644 index 0000000000..282dab2d3d --- /dev/null +++ b/src/system/boot/platform/efi/heap.cpp @@ -0,0 +1,22 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + + +extern "C" void +platform_release_heap(struct stage2_args *args, void *base) +{ + return; +} + + +extern "C" status_t +platform_init_heap(struct stage2_args *args, void **_base, void **_top) +{ + return B_ERROR; +} 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..28140d71fc --- /dev/null +++ b/src/system/boot/platform/efi/mmu.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + + +extern "C" status_t +platform_allocate_region(void **_virtualAddress, size_t size, uint8 protection, + bool exactAddress) +{ + panic("platform_allocate_region not implemented"); + return B_ERROR; +} + + +extern "C" status_t +platform_free_region(void *address, size_t size) +{ + panic("platform_free_region not implemented"); + return B_ERROR; +} diff --git a/src/system/boot/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp index 09ddbf0b84..468baa1b0a 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -5,7 +5,9 @@ */ -#include +#include +#include +#include #include "console.h" #include "efi_platform.h" @@ -30,6 +32,27 @@ call_ctors(void) } +extern "C" uint32 +platform_boot_options() +{ + return 0; +} + + +extern "C" void +platform_start_kernel(void) +{ + panic("platform_start_kernel not implemented"); +} + + +extern "C" void +platform_exit(void) +{ + return; +} + + /** * efi_main - The entry point for the EFI application * @image: firmware-allocated handle that identifies the image @@ -38,16 +61,19 @@ call_ctors(void) extern "C" EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) { + stage2_args args; + kSystemTable = systemTable; kBootServices = systemTable->BootServices; kRuntimeServices = systemTable->RuntimeServices; + memset(&args, 0, sizeof(stage2_args)); + call_ctors(); console_init(); - printf("Hello from EFI Loader for Haiku!\nPress any key to continue...\n"); - console_wait_for_key(); + main(&args); return EFI_SUCCESS; } diff --git a/src/system/boot/platform/efi/video.cpp b/src/system/boot/platform/efi/video.cpp new file mode 100644 index 0000000000..4523bd5749 --- /dev/null +++ b/src/system/boot/platform/efi/video.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2016, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#include "efi_platform.h" + + +extern "C" status_t +platform_init_video(void) +{ + return B_ERROR; +} + + +extern "C" void +platform_switch_to_logo(void) +{ +} + + +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; +} From c0002a79e77908016731c2a1f6ddba7ca29a1df7 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Thu, 21 Apr 2016 13:04:28 +1200 Subject: [PATCH 07/21] EFI: Implement heap --- src/system/boot/platform/efi/heap.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/system/boot/platform/efi/heap.cpp b/src/system/boot/platform/efi/heap.cpp index 282dab2d3d..ade11ed003 100644 --- a/src/system/boot/platform/efi/heap.cpp +++ b/src/system/boot/platform/efi/heap.cpp @@ -7,16 +7,34 @@ #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) { - return; + 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) { - return B_ERROR; + 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; } From c0bdc8bef58917882da6e66d57015afed6f8bd74 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Fri, 22 Apr 2016 19:42:26 +1200 Subject: [PATCH 08/21] bootloader: build objects in $(TARGET_BOOT_PLATFORM) This separates the objects required for the various boot loaders, allowing the build system to be able to build for different targets alongside each other. Currently only done for bios_ia32 vs efi, as both loaders will be needed for the x86_64 images. --- src/system/boot/Jamfile | 2 ++ src/system/boot/arch/x86/Jamfile | 2 ++ src/system/boot/loader/Jamfile | 2 ++ src/system/boot/loader/file_systems/amiga_ffs/Jamfile | 2 ++ src/system/boot/loader/file_systems/bfs/Jamfile | 2 ++ src/system/boot/loader/file_systems/fat/Jamfile | 2 ++ src/system/boot/loader/file_systems/hfs_plus/Jamfile | 2 ++ src/system/boot/loader/file_systems/packagefs/Jamfile | 2 ++ src/system/boot/loader/file_systems/tarfs/Jamfile | 2 ++ src/system/boot/loader/net/Jamfile | 2 ++ src/system/boot/platform/bios_ia32/Jamfile | 2 ++ src/system/boot/platform/efi/Jamfile | 2 ++ src/system/boot/platform/generic/Jamfile | 4 +++- 13 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/system/boot/Jamfile b/src/system/boot/Jamfile index 72bb340278..6e98fe4efe 100644 --- a/src/system/boot/Jamfile +++ b/src/system/boot/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + DEFINES += _BOOT_MODE ; if $(TARGET_ARCH) = x86_64 && $(TARGET_BOOT_PLATFORM) != bios_ia32 { diff --git a/src/system/boot/arch/x86/Jamfile b/src/system/boot/arch/x86/Jamfile index 66fb94feae..b1ca213e6c 100644 --- a/src/system/boot/arch/x86/Jamfile +++ b/src/system/boot/arch/x86/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot arch x86 ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + DEFINES += _BOOT_MODE ; local kernelArchSources = diff --git a/src/system/boot/loader/Jamfile b/src/system/boot/loader/Jamfile index 2884fe6950..78a861182f 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 ; diff --git a/src/system/boot/loader/file_systems/amiga_ffs/Jamfile b/src/system/boot/loader/file_systems/amiga_ffs/Jamfile index ce7ec5e28a..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 ; diff --git a/src/system/boot/loader/file_systems/bfs/Jamfile b/src/system/boot/loader/file_systems/bfs/Jamfile index bf31e7578b..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 ; diff --git a/src/system/boot/loader/file_systems/fat/Jamfile b/src/system/boot/loader/file_systems/fat/Jamfile index ec1ea39899..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 ] ; diff --git a/src/system/boot/loader/file_systems/hfs_plus/Jamfile b/src/system/boot/loader/file_systems/hfs_plus/Jamfile index 9617ab0bb3..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 ; diff --git a/src/system/boot/loader/file_systems/packagefs/Jamfile b/src/system/boot/loader/file_systems/packagefs/Jamfile index d1953b12a9..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 ; diff --git a/src/system/boot/loader/file_systems/tarfs/Jamfile b/src/system/boot/loader/file_systems/tarfs/Jamfile index c0dda86520..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 ; diff --git a/src/system/boot/loader/net/Jamfile b/src/system/boot/loader/net/Jamfile index a06a45a80b..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 ; diff --git a/src/system/boot/platform/bios_ia32/Jamfile b/src/system/boot/platform/bios_ia32/Jamfile index 3f573c0ae3..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 ] ; diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index 38ee97d6bc..f9a2bdfc3b 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system boot platform efi ; +SetupFeatureObjectsDir $(TARGET_BOOT_PLATFORM) ; + UsePrivateHeaders [ FDirName kernel boot ] ; UseBuildFeatureHeaders gnuefi ; UseBuildFeatureHeaders gnuefi : headersProtocol ; diff --git a/src/system/boot/platform/generic/Jamfile b/src/system/boot/platform/generic/Jamfile index 758d9a83ee..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 ; @@ -11,5 +13,5 @@ BootStaticLibrary boot_platform_generic : video_splash.cpp ; -Includes [ FGristFiles video_splash.cpp ] +Includes [ FGristFiles video_splash.cpp ] : [ BuildFeatureAttribute zlib : headers ] ; From 96f4d68b2b1c6f981c8adcfd99a46e18ba0c60e7 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Wed, 22 Jun 2016 18:35:44 +1200 Subject: [PATCH 09/21] EFI: check for boot keys * Only supports spacebar for the boot menu, and escape for enabling debug output. Shift keys will not work. --- src/system/boot/platform/efi/console.cpp | 23 +++++++++++++++++++++++ src/system/boot/platform/efi/console.h | 3 ++- src/system/boot/platform/efi/start.cpp | 6 +++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/system/boot/platform/efi/console.cpp b/src/system/boot/platform/efi/console.cpp index c3a12138d0..ebfd21f441 100644 --- a/src/system/boot/platform/efi/console.cpp +++ b/src/system/boot/platform/efi/console.cpp @@ -215,6 +215,29 @@ console_init(void) } +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) { diff --git a/src/system/boot/platform/efi/console.h b/src/system/boot/platform/efi/console.h index 15942139e0..5cf79e6700 100644 --- a/src/system/boot/platform/efi/console.h +++ b/src/system/boot/platform/efi/console.h @@ -9,7 +9,8 @@ #include -extern "C" status_t console_init(void); +status_t console_init(void); +uint32 console_check_boot_keys(void); #endif /* CONSOLE_H */ diff --git a/src/system/boot/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp index 468baa1b0a..c782989446 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -21,6 +21,8 @@ const EFI_SYSTEM_TABLE *kSystemTable; const EFI_BOOT_SERVICES *kBootServices; const EFI_RUNTIME_SERVICES *kRuntimeServices; +static uint32 sBootOptions; + static void call_ctors(void) @@ -35,7 +37,7 @@ call_ctors(void) extern "C" uint32 platform_boot_options() { - return 0; + return sBootOptions; } @@ -73,6 +75,8 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) console_init(); + sBootOptions = console_check_boot_keys(); + main(&args); return EFI_SUCCESS; From dbf1363b41466de954c4cf71f164375806ec21f4 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Fri, 24 Jun 2016 15:56:59 +1200 Subject: [PATCH 10/21] EFI: naive platform_allocate_region() implementation --- src/system/boot/platform/efi/mmu.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/system/boot/platform/efi/mmu.cpp b/src/system/boot/platform/efi/mmu.cpp index 28140d71fc..ae4f9b2133 100644 --- a/src/system/boot/platform/efi/mmu.cpp +++ b/src/system/boot/platform/efi/mmu.cpp @@ -7,19 +7,25 @@ #include #include +#include "efi_platform.h" + extern "C" status_t platform_allocate_region(void **_virtualAddress, size_t size, uint8 protection, bool exactAddress) { - panic("platform_allocate_region not implemented"); - return B_ERROR; + if (kBootServices->AllocatePool(EfiLoaderData, size, _virtualAddress) != EFI_SUCCESS) + return B_NO_MEMORY; + + return B_OK; } extern "C" status_t platform_free_region(void *address, size_t size) { - panic("platform_free_region not implemented"); - return B_ERROR; + if (kBootServices->FreePool(address) != EFI_SUCCESS) + return B_ERROR; + + return B_OK; } From 325b1e378771d5046bdfe7f8472089246d1854b3 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Fri, 25 Apr 2014 15:03:59 +1200 Subject: [PATCH 11/21] EFI: add support for graphics mode output * We can now switch between graphics and text modes, and display the splash screen --- src/system/boot/platform/efi/console.cpp | 1 + src/system/boot/platform/efi/video.cpp | 69 +++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/system/boot/platform/efi/console.cpp b/src/system/boot/platform/efi/console.cpp index ebfd21f441..35500e731a 100644 --- a/src/system/boot/platform/efi/console.cpp +++ b/src/system/boot/platform/efi/console.cpp @@ -243,4 +243,5 @@ 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/video.cpp b/src/system/boot/platform/efi/video.cpp index 4523bd5749..68a35aca2d 100644 --- a/src/system/boot/platform/efi/video.cpp +++ b/src/system/boot/platform/efi/video.cpp @@ -4,22 +4,89 @@ */ +#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) { - return B_ERROR; + 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); } From 2da1cb75a40bc7785b07b90adef0c17b604160d2 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Wed, 31 Aug 2016 01:11:16 +1200 Subject: [PATCH 12/21] EFI: device support for anyboot CDs. I have tried to get normal ISOs working, but the bootloader doesn't seem to detect any bootable partitions. --- src/system/boot/platform/efi/devices.cpp | 213 ++++++++++++++++++++++- 1 file changed, 208 insertions(+), 5 deletions(-) diff --git a/src/system/boot/platform/efi/devices.cpp b/src/system/boot/platform/efi/devices.cpp index de151c276c..8538ddd4be 100644 --- a/src/system/boot/platform/efi/devices.cpp +++ b/src/system/boot/platform/efi/devices.cpp @@ -4,21 +4,201 @@ */ +#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) { - return B_ERROR; + // 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) { - return B_ERROR; + // add_boot_devices will add all available devices, so nothing to do here + return B_OK; } @@ -26,7 +206,14 @@ status_t platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, NodeList *partitions, boot::Partition **_partition) { - panic("platform_get_boot_partition not implemented"); + 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; } @@ -34,6 +221,22 @@ platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, status_t platform_register_boot_device(Node *device) { - panic("platform_register_boot_device not implemented"); - return B_ERROR; + 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; } From b3215a62758dd9e0939ff152c863e6e6fdad5118 Mon Sep 17 00:00:00 2001 From: Henry Harrington Date: Tue, 21 Oct 2014 20:14:45 +0100 Subject: [PATCH 13/21] EFI: preliminary support for starting the kernel. Enough to let the kernel to print hello, but not much beyond that. Signed-off-by: Jessica Hamilton --- src/system/boot/loader/Jamfile | 4 + src/system/boot/loader/elf.cpp | 31 ++- src/system/boot/platform/efi/Jamfile | 3 +- src/system/boot/platform/efi/entry.S | 66 ++++++ src/system/boot/platform/efi/mmu.cpp | 307 ++++++++++++++++++++++++- src/system/boot/platform/efi/mmu.h | 70 ++++++ src/system/boot/platform/efi/start.cpp | 213 ++++++++++++++++- 7 files changed, 682 insertions(+), 12 deletions(-) create mode 100644 src/system/boot/platform/efi/entry.S create mode 100644 src/system/boot/platform/efi/mmu.h diff --git a/src/system/boot/loader/Jamfile b/src/system/boot/loader/Jamfile index 78a861182f..d566b68b9c 100644 --- a/src/system/boot/loader/Jamfile +++ b/src/system/boot/loader/Jamfile @@ -51,6 +51,10 @@ UsePrivateHeaders shared storage ; DEFINES += BOOT_SUPPORT_ELF32 ; + } else { + DEFINES += + _BOOT_PLATFORM_EFI + ; } } } diff --git a/src/system/boot/loader/elf.cpp b/src/system/boot/loader/elf.cpp index abb4f5e6ca..eba9c86b76 100644 --- a/src/system/boot/loader/elf.cpp +++ b/src/system/boot/loader/elf.cpp @@ -101,6 +101,15 @@ typedef ELFLoader ELF32Loader; #ifdef BOOT_SUPPORT_ELF64 + +#ifdef _BOOT_PLATFORM_EFI +extern "C" status_t +platform_bootloader_address_to_kernel_address(void *address, uint64_t *_result); +extern "C" status_t +platform_kernel_address_to_bootloader_address(uint64_t address, void **_result); +#endif + + struct ELF64Class { static const uint8 kIdentClass = ELFCLASS64; @@ -119,6 +128,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. @@ -132,14 +152,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 } }; @@ -154,7 +183,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); diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index f9a2bdfc3b..f9312a794f 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -8,7 +8,7 @@ UseBuildFeatureHeaders gnuefi : headersProtocol ; UseBuildFeatureHeaders gnuefi : headersArch ; { - local defines = _BOOT_MODE GNU_EFI_USE_MS_ABI _BOOT_PLATFORM=efi ; + local defines = _BOOT_MODE GNU_EFI_USE_MS_ABI _BOOT_PLATFORM_EFI ; defines = [ FDefines $(defines) ] ; SubDirCcFlags $(defines) ; SubDirC++Flags $(defines) -fno-rtti ; @@ -24,6 +24,7 @@ local platform_src = console.cpp video.cpp debug.cpp + entry.S mmu.cpp heap.cpp menu.cpp diff --git a/src/system/boot/platform/efi/entry.S b/src/system/boot/platform/efi/entry.S new file mode 100644 index 0000000000..b432dc982c --- /dev/null +++ b/src/system/boot/platform/efi/entry.S @@ -0,0 +1,66 @@ +/* + * 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 long_gdtr(%rip) +/* + // Jump into the 64-bit code segment. + ljmp $KERNEL_CODE_SELECTOR, $.Llmode +.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 + + +long_gdtr: + .word BOOT_GDT_SEGMENT_COUNT * 8 - 1 +SYMBOL(gLongGDT): + .quad 0 diff --git a/src/system/boot/platform/efi/mmu.cpp b/src/system/boot/platform/efi/mmu.cpp index ae4f9b2133..4a3dc2ab3f 100644 --- a/src/system/boot/platform/efi/mmu.cpp +++ b/src/system/boot/platform/efi/mmu.cpp @@ -1,31 +1,324 @@ /* * 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; +} + + +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_allocate_region(void **_virtualAddress, size_t size, uint8 protection, - bool exactAddress) +platform_bootloader_address_to_kernel_address(void *address, uint64_t *_result) { - if (kBootServices->AllocatePool(EfiLoaderData, size, _virtualAddress) != EFI_SUCCESS) - return B_NO_MEMORY; + uint64_t addr = (uint64_t)address; - return B_OK; + 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) { - if (kBootServices->FreePool(address) != EFI_SUCCESS) - return B_ERROR; + //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..068b5bf995 --- /dev/null +++ b/src/system/boot/platform/efi/mmu.h @@ -0,0 +1,70 @@ +/* + * 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 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/start.cpp b/src/system/boot/platform/efi/start.cpp index c782989446..6ff215fb9b 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -1,16 +1,26 @@ /* * 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. + * 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 "console.h" #include "efi_platform.h" +#include "mmu.h" extern void (*__ctor_list)(void); @@ -20,8 +30,18 @@ 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; +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 @@ -41,10 +61,188 @@ platform_boot_options() } +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 = fix_address((addr_t)gBootGDT); + 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; + } + + // Set correct kernel args range addresses. + dprintf("kernel args ranges:\n"); + for (uint32 i = 0; i < gKernelArgs.num_kernel_args_ranges; i++) { + gKernelArgs.kernel_args_range[i].start = fix_address( + gKernelArgs.kernel_args_range[i].start); + dprintf(" base %#018" B_PRIx64 ", length %#018" B_PRIx64 "\n", + gKernelArgs.kernel_args_range[i].start, + gKernelArgs.kernel_args_range[i].size); + } + + // 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) { - panic("platform_start_kernel not implemented"); + if (gKernelArgs.kernel_image->elf_class != ELFCLASS64) + panic("32-bit kernels not supported with EFI"); + + 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); + + // Enter the kernel! + efi_enter_kernel(final_pml4, + gLongKernelEntry, + gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size); + + panic("Shouldn't get here"); } @@ -65,6 +263,9 @@ 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; @@ -77,6 +278,12 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) 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; From 34a6dd672874183fd407787167d6c521ea972f5c Mon Sep 17 00:00:00 2001 From: Henry Harrington Date: Wed, 22 Oct 2014 02:13:45 +0100 Subject: [PATCH 14/21] EFI: Initialize/load the GDT. Signed-off-by: Jessica Hamilton --- src/system/boot/platform/efi/entry.S | 9 ++++++--- src/system/boot/platform/efi/start.cpp | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/system/boot/platform/efi/entry.S b/src/system/boot/platform/efi/entry.S index b432dc982c..5c5180df7a 100644 --- a/src/system/boot/platform/efi/entry.S +++ b/src/system/boot/platform/efi/entry.S @@ -27,9 +27,12 @@ FUNCTION(efi_enter_kernel): // Load 64-bit enabled GDT lgdtq long_gdtr(%rip) -/* + // Jump into the 64-bit code segment. - ljmp $KERNEL_CODE_SELECTOR, $.Llmode + push $KERNEL_CODE_SELECTOR + lea .Llmode(%rip), %rax + push %rax + lretq .align 8 .code64 .Llmode: @@ -41,7 +44,7 @@ FUNCTION(efi_enter_kernel): mov %ax, %es mov %ax, %fs mov %ax, %gs -*/ + // Set the stack pointer. movq %rdx, %rsp diff --git a/src/system/boot/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp index 6ff215fb9b..d5b3219c1e 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -77,7 +77,7 @@ long_gdt_init() DPL_USER); // Used by long_enter_kernel(). - gLongGDT = fix_address((addr_t)gBootGDT); + gLongGDT = (addr_t)gBootGDT + 0xFFFFFF0000000000; dprintf("GDT at 0x%lx\n", gLongGDT); } From 21e3ac6cf52f91dba8217f15fc33dc1d45dffd40 Mon Sep 17 00:00:00 2001 From: Henry Harrington Date: Wed, 22 Oct 2014 04:01:23 +0100 Subject: [PATCH 15/21] vm: Try harder to allocate early physical pages. Signed-off-by: Jessica Hamilton --- src/system/kernel/vm/vm.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) 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 } From 82dcc31606c97c793b2189c4f8cc30ff5f8de44f Mon Sep 17 00:00:00 2001 From: Henry Harrington Date: Wed, 22 Oct 2014 18:25:05 +0100 Subject: [PATCH 16/21] bootloader: Translate kernel args before adding them to kernel_args_range. Chunks may be physically contiguous, but virtually disjoint. Adding physical addresses may cause ranges to be merged incorrectly. Signed-off-by: Jessica Hamilton --- headers/private/kernel/boot/platform.h | 2 ++ src/system/boot/loader/elf.cpp | 9 --------- src/system/boot/loader/kernel_args.cpp | 12 ++++++++++++ src/system/boot/platform/efi/start.cpp | 10 ---------- 4 files changed, 14 insertions(+), 19 deletions(-) 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/src/system/boot/loader/elf.cpp b/src/system/boot/loader/elf.cpp index eba9c86b76..37af301bff 100644 --- a/src/system/boot/loader/elf.cpp +++ b/src/system/boot/loader/elf.cpp @@ -101,15 +101,6 @@ typedef ELFLoader ELF32Loader; #ifdef BOOT_SUPPORT_ELF64 - -#ifdef _BOOT_PLATFORM_EFI -extern "C" status_t -platform_bootloader_address_to_kernel_address(void *address, uint64_t *_result); -extern "C" status_t -platform_kernel_address_to_bootloader_address(uint64_t address, void **_result); -#endif - - struct ELF64Class { static const uint8 kIdentClass = ELFCLASS64; 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/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp index d5b3219c1e..3e07eea0b8 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -122,16 +122,6 @@ convert_kernel_args() image = next; } - // Set correct kernel args range addresses. - dprintf("kernel args ranges:\n"); - for (uint32 i = 0; i < gKernelArgs.num_kernel_args_ranges; i++) { - gKernelArgs.kernel_args_range[i].start = fix_address( - gKernelArgs.kernel_args_range[i].start); - dprintf(" base %#018" B_PRIx64 ", length %#018" B_PRIx64 "\n", - gKernelArgs.kernel_args_range[i].start, - gKernelArgs.kernel_args_range[i].size); - } - // Fix driver settings files. driver_settings_file* file = gKernelArgs.driver_settings; fix_address(gKernelArgs.driver_settings); From 6e6efaecdc518b9efb7118d6697439593003adf7 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Thu, 24 Apr 2014 23:35:40 +1200 Subject: [PATCH 17/21] EFI: add ACPI support Also add support in the kernel to get the ACPI RSDP from the bootloader, and pass onto the ACPI driver using get_boot_item. --- .../kernel/arch/x86/arch_kernel_args.h | 2 + .../kernel/bus_managers/acpi/ACPICAHaiku.cpp | 14 +- src/system/boot/platform/efi/Jamfile | 1 + src/system/boot/platform/efi/acpi.cpp | 272 ++++++++++++++++++ src/system/boot/platform/efi/acpi.h | 22 ++ src/system/boot/platform/efi/start.cpp | 5 + src/system/kernel/arch/x86/arch_platform.cpp | 82 +++--- 7 files changed, 355 insertions(+), 43 deletions(-) create mode 100644 src/system/boot/platform/efi/acpi.cpp create mode 100644 src/system/boot/platform/efi/acpi.h diff --git a/headers/private/kernel/arch/x86/arch_kernel_args.h b/headers/private/kernel/arch/x86/arch_kernel_args.h index cada9db4a0..bd7659157b 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/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/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index f9312a794f..db60aef07f 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -27,6 +27,7 @@ local platform_src = entry.S mmu.cpp heap.cpp + acpi.cpp menu.cpp devices.cpp ; diff --git a/src/system/boot/platform/efi/acpi.cpp b/src/system/boot/platform/efi/acpi.cpp new file mode 100644 index 0000000000..76364ec4b8 --- /dev/null +++ b/src/system/boot/platform/efi/acpi.cpp @@ -0,0 +1,272 @@ +/* + * 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; + + +extern "C" addr_t +mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags) +{ + return physicalAddress; +} + +extern "C" void +mmu_free(void *virtualAddress, size_t size) +{ + return; +} + + +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/start.cpp b/src/system/boot/platform/efi/start.cpp index 3e07eea0b8..43f5155822 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -13,11 +13,13 @@ #include #include +#include #include #include #include #include +#include "acpi.h" #include "console.h" #include "efi_platform.h" #include "mmu.h" @@ -270,6 +272,9 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) // disable apm in case we ever load a 32-bit kernel... gKernelArgs.platform_args.apm.version = 0; + + acpi_init(); + gKernelArgs.num_cpus = 1; gKernelArgs.arch_args.hpet_phys = 0; gKernelArgs.arch_args.hpet = NULL; 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; +} + From a1d0102ee4a83b2ce837228683dc807473edc7b6 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Sun, 26 Apr 2015 17:22:39 +1200 Subject: [PATCH 18/21] EFI: add support for HPET --- src/system/boot/platform/efi/Jamfile | 1 + src/system/boot/platform/efi/hpet.cpp | 62 ++++++++++++++++++++++++++ src/system/boot/platform/efi/hpet.h | 21 +++++++++ src/system/boot/platform/efi/start.cpp | 2 + 4 files changed, 86 insertions(+) create mode 100644 src/system/boot/platform/efi/hpet.cpp create mode 100644 src/system/boot/platform/efi/hpet.h diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index db60aef07f..0409f6d6a4 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -30,6 +30,7 @@ local platform_src = acpi.cpp menu.cpp devices.cpp + hpet.cpp ; Includes [ FGristFiles $(efi_glue_src) $(platform_src) ] diff --git a/src/system/boot/platform/efi/hpet.cpp b/src/system/boot/platform/efi/hpet.cpp new file mode 100644 index 0000000000..69e1192aea --- /dev/null +++ b/src/system/boot/platform/efi/hpet.cpp @@ -0,0 +1,62 @@ +/* + * 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 + + +static addr_t +mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags) +{ + return physicalAddress; +} + + +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/start.cpp b/src/system/boot/platform/efi/start.cpp index 43f5155822..5be1478815 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -22,6 +22,7 @@ #include "acpi.h" #include "console.h" #include "efi_platform.h" +#include "hpet.h" #include "mmu.h" @@ -274,6 +275,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) gKernelArgs.platform_args.apm.version = 0; acpi_init(); + hpet_init(); gKernelArgs.num_cpus = 1; gKernelArgs.arch_args.hpet_phys = 0; From a7142a503761aef9adbf7b0bcbd0b9b55ff89317 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Wed, 29 Apr 2015 10:54:08 +1200 Subject: [PATCH 19/21] EFI: add cpu.cpp from bios_ia32 --- src/system/boot/platform/efi/Jamfile | 2 + src/system/boot/platform/efi/cpu.cpp | 349 +++++++++++++++++++++++++ src/system/boot/platform/efi/cpu.h | 22 ++ src/system/boot/platform/efi/start.cpp | 2 + src/system/boot/platform/efi/support.S | 39 +++ 5 files changed, 414 insertions(+) create mode 100644 src/system/boot/platform/efi/cpu.cpp create mode 100644 src/system/boot/platform/efi/cpu.h create mode 100644 src/system/boot/platform/efi/support.S diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index 0409f6d6a4..19ee053356 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -31,6 +31,8 @@ local platform_src = menu.cpp devices.cpp hpet.cpp + cpu.cpp + support.S ; Includes [ FGristFiles $(efi_glue_src) $(platform_src) ] 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/start.cpp b/src/system/boot/platform/efi/start.cpp index 5be1478815..8193a4ddaf 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -23,6 +23,7 @@ #include "console.h" #include "efi_platform.h" #include "hpet.h" +#include "cpu.h" #include "mmu.h" @@ -274,6 +275,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) // disable apm in case we ever load a 32-bit kernel... gKernelArgs.platform_args.apm.version = 0; + cpu_init(); acpi_init(); hpet_init(); 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 From ec239abcf5924471fd53f06e67ddb1264d063fd7 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Sun, 26 Apr 2015 17:20:33 +1200 Subject: [PATCH 20/21] EFI: implement mmu_map_physical_memory & mmu_free. Also move cpu, acpi, hpet init into platform_start_kernel, as we need an initialised heap for alllocating memory for recording the mapped regions. --- src/system/boot/platform/efi/acpi.cpp | 13 ------ src/system/boot/platform/efi/hpet.cpp | 7 ---- src/system/boot/platform/efi/mmu.cpp | 57 ++++++++++++++++++++++++++ src/system/boot/platform/efi/mmu.h | 3 ++ src/system/boot/platform/efi/start.cpp | 8 ++-- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/system/boot/platform/efi/acpi.cpp b/src/system/boot/platform/efi/acpi.cpp index 76364ec4b8..fe5a23d997 100644 --- a/src/system/boot/platform/efi/acpi.cpp +++ b/src/system/boot/platform/efi/acpi.cpp @@ -39,19 +39,6 @@ static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table static int32 sNumEntries = -1; -extern "C" addr_t -mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags) -{ - return physicalAddress; -} - -extern "C" void -mmu_free(void *virtualAddress, size_t size) -{ - return; -} - - static status_t acpi_validate_rsdp(acpi_rsdp* rsdp) { diff --git a/src/system/boot/platform/efi/hpet.cpp b/src/system/boot/platform/efi/hpet.cpp index 69e1192aea..7371ae460e 100644 --- a/src/system/boot/platform/efi/hpet.cpp +++ b/src/system/boot/platform/efi/hpet.cpp @@ -31,13 +31,6 @@ #endif -static addr_t -mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags) -{ - return physicalAddress; -} - - void hpet_init(void) { diff --git a/src/system/boot/platform/efi/mmu.cpp b/src/system/boot/platform/efi/mmu.cpp index 4a3dc2ab3f..fc40e2d2ea 100644 --- a/src/system/boot/platform/efi/mmu.cpp +++ b/src/system/boot/platform/efi/mmu.cpp @@ -259,6 +259,63 @@ platform_allocate_region(void **_address, size_t size, uint8 /* protection */, b } +/*! + 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) { diff --git a/src/system/boot/platform/efi/mmu.h b/src/system/boot/platform/efi/mmu.h index 068b5bf995..e078a3f89d 100644 --- a/src/system/boot/platform/efi/mmu.h +++ b/src/system/boot/platform/efi/mmu.h @@ -30,6 +30,9 @@ static const uint64 kPageMappingFlags = 0x103; // present, R/W, user, globa 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 diff --git a/src/system/boot/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp index 8193a4ddaf..02a5920857 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -144,6 +144,10 @@ 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(); + preloaded_elf64_image *image = static_cast( gKernelArgs.kernel_image.Pointer()); @@ -275,10 +279,6 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) // disable apm in case we ever load a 32-bit kernel... gKernelArgs.platform_args.apm.version = 0; - cpu_init(); - acpi_init(); - hpet_init(); - gKernelArgs.num_cpus = 1; gKernelArgs.arch_args.hpet_phys = 0; gKernelArgs.arch_args.hpet = NULL; From a99a0c003d14a7ff1e03a49034f8736ee94d3396 Mon Sep 17 00:00:00 2001 From: Nick Smallbone Date: Sat, 2 May 2015 21:43:33 +0200 Subject: [PATCH 21/21] EFI: add support for SMP. Signed-off-by: Jessica Hamilton --- src/system/boot/platform/efi/Jamfile | 2 + src/system/boot/platform/efi/entry.S | 4 +- src/system/boot/platform/efi/smp.cpp | 457 ++++++++++++++++++ src/system/boot/platform/efi/smp.h | 30 ++ src/system/boot/platform/efi/smp_trampoline.S | 129 +++++ src/system/boot/platform/efi/start.cpp | 6 + 6 files changed, 626 insertions(+), 2 deletions(-) create mode 100644 src/system/boot/platform/efi/smp.cpp create mode 100644 src/system/boot/platform/efi/smp.h create mode 100644 src/system/boot/platform/efi/smp_trampoline.S diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index 19ee053356..8356f7674f 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -32,6 +32,8 @@ local platform_src = devices.cpp hpet.cpp cpu.cpp + smp.cpp + smp_trampoline.S support.S ; diff --git a/src/system/boot/platform/efi/entry.S b/src/system/boot/platform/efi/entry.S index 5c5180df7a..75717080d8 100644 --- a/src/system/boot/platform/efi/entry.S +++ b/src/system/boot/platform/efi/entry.S @@ -26,7 +26,7 @@ FUNCTION(efi_enter_kernel): movq %rdi, %cr3 // Load 64-bit enabled GDT - lgdtq long_gdtr(%rip) + lgdtq gLongGDTR(%rip) // Jump into the 64-bit code segment. push $KERNEL_CODE_SELECTOR @@ -63,7 +63,7 @@ FUNCTION(efi_enter_kernel): .data -long_gdtr: +SYMBOL(gLongGDTR): .word BOOT_GDT_SEGMENT_COUNT * 8 - 1 SYMBOL(gLongGDT): .quad 0 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 index 02a5920857..1c035c713c 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -25,6 +25,7 @@ #include "hpet.h" #include "cpu.h" #include "mmu.h" +#include "smp.h" extern void (*__ctor_list)(void); @@ -40,6 +41,7 @@ EFI_HANDLE kImage; static uint32 sBootOptions; static uint64 gLongKernelEntry; extern uint64 gLongGDT; +extern uint64 gLongGDTR; segment_descriptor gBootGDT[BOOT_GDT_SEGMENT_COUNT]; @@ -147,6 +149,8 @@ platform_start_kernel(void) cpu_init(); acpi_init(); hpet_init(); + smp_init(); + smp_init_other_cpus(); preloaded_elf64_image *image = static_cast( gKernelArgs.kernel_image.Pointer()); @@ -235,6 +239,8 @@ platform_start_kernel(void) // 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,