diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index 690227cb67..97856a8aec 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -388,6 +388,7 @@ switch $(HAIKU_ARCH) { # code due to interrupts. HAIKU_KERNEL_CCFLAGS += -mcmodel=kernel -mno-red-zone ; HAIKU_KERNEL_C++FLAGS += -mcmodel=kernel -mno-red-zone ; + HAIKU_KERNEL_PIC_LINKFLAGS += -z max-page-size=0x1000 ; # Bootloader is 32-bit. HAIKU_BOOT_LINKFLAGS += -m elf_i386_haiku ; diff --git a/headers/private/kernel/arch/x86/arch_kernel.h b/headers/private/kernel/arch/x86/arch_kernel.h index 66bbfd0dbc..418d707c47 100644 --- a/headers/private/kernel/arch/x86/arch_kernel.h +++ b/headers/private/kernel/arch/x86/arch_kernel.h @@ -17,6 +17,10 @@ #define KERNEL_SIZE 0x80000000 #define KERNEL_TOP (KERNEL_BASE + (KERNEL_SIZE - 1)) +#ifdef _BOOT_MODE +# define KERNEL_BASE_64BIT 0xffffffff80000000 +#endif + /* User space layout is a little special: * The user space does not completely cover the space not covered by the * kernel. There is a gap of 64kb between the user and kernel space. The 64kb diff --git a/headers/private/kernel/arch/x86_64/arch_kernel.h b/headers/private/kernel/arch/x86_64/arch_kernel.h index 056efafcfa..612f0adff8 100644 --- a/headers/private/kernel/arch/x86_64/arch_kernel.h +++ b/headers/private/kernel/arch/x86_64/arch_kernel.h @@ -13,29 +13,30 @@ // Base of the kernel address space. // When compiling the bootloader, KERNEL_BASE is set to the x86 base address, -// the correct 64-bit addresses are calculated differently. -// For the kernel, this is the base of the kernel address space. This is NOT -// the address where the kernel is loaded to: the kernel is loaded in the top -// 2GB of the virtual address space as required by GCC's kernel code model. +// KERNEL_BASE_64BIT is set to where the kernel loaded to. +// For the kernel, KERNEL_BASE is the base of the kernel address space. This is +// NOT the address where the kernel is loaded to: the kernel is loaded in the +// top 2GB of the virtual address space as required by GCC's kernel code model. // The whole kernel address space is the top 512GB of the address space. #ifdef _BOOT_MODE -# define KERNEL_BASE 0x80000000 +# define KERNEL_BASE 0x80000000 +# define KERNEL_BASE_64BIT 0xffffffff80000000 #else -# define KERNEL_BASE 0xFFFFFF8000000000 +# define KERNEL_BASE 0xffffff8000000000 #endif -#define KERNEL_SIZE 0x8000000000 -#define KERNEL_TOP (KERNEL_BASE + (KERNEL_SIZE - 1)) +#define KERNEL_SIZE 0x8000000000 +#define KERNEL_TOP (KERNEL_BASE + (KERNEL_SIZE - 1)) // Userspace address space layout. -#define USER_BASE 0x0 -#define USER_BASE_ANY 0x100000 -#define USER_SIZE 0x800000000000 -#define USER_TOP (USER_BASE + USER_SIZE) +#define USER_BASE 0x0 +#define USER_BASE_ANY 0x100000 +#define USER_SIZE 0x800000000000 +#define USER_TOP (USER_BASE + USER_SIZE) -#define KERNEL_USER_DATA_BASE 0x7FFFEFFF0000 -#define USER_STACK_REGION 0x7FFFF0000000 +#define KERNEL_USER_DATA_BASE 0x7fffefff0000 +#define USER_STACK_REGION 0x7ffff0000000 #define USER_STACK_REGION_SIZE (USER_TOP - USER_STACK_REGION) diff --git a/headers/private/kernel/boot/elf.h b/headers/private/kernel/boot/elf.h index 46bbfc1f56..d2cfe06195 100644 --- a/headers/private/kernel/boot/elf.h +++ b/headers/private/kernel/boot/elf.h @@ -47,7 +47,6 @@ struct preloaded_elf32_image : public preloaded_image { Elf32_Ehdr elf_header; elf32_region text_region; elf32_region data_region; - uint32 mapped_delta; FixedWidthPointer syms; FixedWidthPointer rel; @@ -65,7 +64,6 @@ struct preloaded_elf64_image : public preloaded_image { Elf64_Ehdr elf_header; elf64_region text_region; elf64_region data_region; - uint64 mapped_delta; FixedWidthPointer syms; FixedWidthPointer rel; @@ -84,18 +82,8 @@ extern status_t boot_elf_resolve_symbol(preloaded_elf32_image* image, struct Elf32_Sym* symbol, Elf32_Addr* symbolAddress); extern status_t boot_elf_resolve_symbol(preloaded_elf64_image* image, struct Elf64_Sym* symbol, Elf64_Addr* symbolAddress); - - -// Helper method to set a relocation at the mapped address in the loader's -// address space. -template -inline void -boot_elf_set_relocation(ImageType* image, AddrType resolveAddress, - AddrType finalAddress) -{ - AddrType* dest = (AddrType*)(addr_t)(resolveAddress + image->mapped_delta); - *dest = finalAddress; -} +extern void boot_elf64_set_relocation(Elf64_Addr resolveAddress, + Elf64_Addr finalAddress); #endif #endif /* KERNEL_BOOT_ELF_H */ diff --git a/headers/private/kernel/boot/platform.h b/headers/private/kernel/boot/platform.h index c2514884fc..9f3c8eb637 100644 --- a/headers/private/kernel/boot/platform.h +++ b/headers/private/kernel/boot/platform.h @@ -72,13 +72,6 @@ extern size_t platform_get_user_input_text(Menu *menu, MenuItem *item, char *buffer, size_t bufferSize); extern char* platform_debug_get_log_buffer(size_t* _size); -/* ELF functions */ - -extern status_t platform_allocate_elf_region(uint32 *_address, uint32 size, - uint8 protection, void **_mappedAddress); -extern status_t platform_allocate_elf_region(uint64 *_address, uint64 size, - uint8 protection, void **_mappedAddress); - #endif #endif /* KERNEL_BOOT_PLATFORM_H */ diff --git a/src/system/boot/loader/elf.cpp b/src/system/boot/loader/elf.cpp index cf780c3fca..84a1d0a3d9 100644 --- a/src/system/boot/loader/elf.cpp +++ b/src/system/boot/loader/elf.cpp @@ -51,10 +51,12 @@ public: static status_t Create(int fd, preloaded_image** _image); static status_t Load(int fd, preloaded_image* image); static status_t Relocate(preloaded_image* image); + static status_t Resolve(ImageType* image, SymType* symbol, + AddrType* symbolAddress); private: static status_t _LoadSymbolTable(int fd, ImageType* image); - static status_t _ParseDynamicSection(ImageType* image, AddrType delta); + static status_t _ParseDynamicSection(ImageType* image); }; @@ -71,6 +73,25 @@ struct ELF32Class { typedef Elf32_Sym SymType; typedef Elf32_Rel RelType; typedef Elf32_Rela RelaType; + + static inline status_t + AllocateRegion(AddrType* _address, AddrType size, uint8 protection, + void **_mappedAddress) + { + status_t status = platform_allocate_region((void**)_address, size, + protection, false); + if (status < B_OK) + return status; + + *_mappedAddress = (void*)*_address; + return B_OK; + } + + static inline void* + Map(AddrType address) + { + return (void*)address; + } }; typedef ELFLoader ELF32Loader; @@ -90,6 +111,31 @@ struct ELF64Class { typedef Elf64_Sym SymType; typedef Elf64_Rel RelType; typedef Elf64_Rela RelaType; + + static inline status_t + AllocateRegion(AddrType* _address, AddrType size, uint8 protection, + void **_mappedAddress) + { + // Assume the real 64-bit base address is KERNEL_BASE_64BIT and the + // mappings in the loader address space are at KERNEL_BASE. + + void* address = (void*)(addr_t)(*_address & 0xffffffff); + + status_t status = platform_allocate_region(&address, size, protection, + false); + if (status < B_OK) + return status; + + *_mappedAddress = address; + *_address = (AddrType)(addr_t)address + KERNEL_BASE_64BIT - KERNEL_BASE; + return B_OK; + } + + static inline void* + Map(AddrType address) + { + return (void*)(addr_t)(address - KERNEL_BASE_64BIT + KERNEL_BASE); + } }; typedef ELFLoader ELF64Loader; @@ -227,15 +273,15 @@ ELFLoader::Load(int fd, preloaded_image* _image) // inbetween. totalSize = secondRegion->start + secondRegion->size - firstRegion->start; if (totalSize > image->text_region.size + image->data_region.size - + 0x200000) { + + 8 * 1024) { status = B_BAD_DATA; goto error1; } - // The kernel and the modules are relocatable, thus - // platform_allocate_elf_region() can automatically allocate an address, - // but shall prefer the specified base address. - if (platform_allocate_elf_region(&firstRegion->start, totalSize, + // The kernel and the modules are relocatable, thus AllocateRegion() + // can automatically allocate an address, but shall prefer the specified + // base address. + if (Class::AllocateRegion(&firstRegion->start, totalSize, B_READ_AREA | B_WRITE_AREA, &mappedRegion) < B_OK) { status = B_NO_MEMORY; goto error1; @@ -254,9 +300,6 @@ ELFLoader::Load(int fd, preloaded_image* _image) (uint64)image->data_region.start, (uint64)image->data_region.size, (int64)(AddrType)image->data_region.delta)); - // Calculate the delta from a real load address to the mapped address - image->mapped_delta = (AddrType)(addr_t)mappedRegion - firstRegion->start; - // load program data for (int32 i = 0; i < elfHeader.e_phnum; i++) { @@ -273,14 +316,11 @@ ELFLoader::Load(int fd, preloaded_image* _image) else continue; - // Calculate where to load the data to. - addr_t dest = region->start + image->mapped_delta; - - TRACE(("load segment %ld (%llu bytes) mapped at 0x%lx...\n", i, - (uint64)header.p_filesz, dest)); + TRACE(("load segment %ld (%llu bytes) mapped at %p...\n", i, + (uint64)header.p_filesz, Class::Map(region->start))); length = read_pos(fd, header.p_offset, - (void*)(dest + (header.p_vaddr % B_PAGE_SIZE)), + Class::Map(region->start + (header.p_vaddr % B_PAGE_SIZE)), header.p_filesz); if (length < (ssize_t)header.p_filesz) { status = B_BAD_DATA; @@ -293,7 +333,7 @@ ELFLoader::Load(int fd, preloaded_image* _image) uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz; if (offset < region->size) - memset((void*)(dest + offset), 0, region->size - offset); + memset(Class::Map(region->start + offset), 0, region->size - offset); } // offset dynamic section, and program entry addresses by the delta of the @@ -329,9 +369,7 @@ ELFLoader::Relocate(preloaded_image* _image) { ImageType* image = static_cast(_image); - // Pull information out of the dynamic section. First pass through we set - // the addresses we want in our address space. - status_t status = _ParseDynamicSection(image, image->mapped_delta); + status_t status = _ParseDynamicSection(image); if (status != B_OK) return status; @@ -373,13 +411,33 @@ ELFLoader::Relocate(preloaded_image* _image) return status; } - // Make a second pass through the dynamic section, storing the correct - // virtual addresses for the kernel. - _ParseDynamicSection(image, 0); - return B_OK; } +template +/*static*/ status_t +ELFLoader::Resolve(ImageType* image, SymType* symbol, + AddrType* symbolAddress) +{ + switch (symbol->st_shndx) { + case SHN_UNDEF: + // Since we do that only for the kernel, there shouldn't be + // undefined symbols. + return B_MISSING_SYMBOL; + case SHN_ABS: + *symbolAddress = symbol->st_value; + return B_NO_ERROR; + case SHN_COMMON: + // ToDo: finish this + TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n")); + return B_ERROR; + default: + // standard symbol + *symbolAddress = symbol->st_value + image->text_region.delta; + return B_OK; + } +} + template /*static*/ status_t @@ -487,7 +545,7 @@ error1: template /*static*/ status_t -ELFLoader::_ParseDynamicSection(ImageType* image, AddrType delta) +ELFLoader::_ParseDynamicSection(ImageType* image) { image->syms = 0; image->rel = 0; @@ -501,8 +559,7 @@ ELFLoader::_ParseDynamicSection(ImageType* image, AddrType delta) if(image->dynamic_section.start == 0) return B_ERROR; - DynType* d = (DynType*)(addr_t)(image->dynamic_section.start - + image->mapped_delta); + DynType* d = (DynType*)Class::Map(image->dynamic_section.start); for (int i = 0; d[i].d_tag != DT_NULL; i++) { switch (d[i].d_tag) { @@ -510,26 +567,26 @@ ELFLoader::_ParseDynamicSection(ImageType* image, AddrType delta) case DT_STRTAB: break; case DT_SYMTAB: - image->syms = (SymType*)(d[i].d_un.d_ptr - + image->text_region.delta + delta); + image->syms = (SymType*)Class::Map(d[i].d_un.d_ptr + + image->text_region.delta); break; case DT_REL: - image->rel = (RelType*)(d[i].d_un.d_ptr - + image->text_region.delta + delta); + image->rel = (RelType*)Class::Map(d[i].d_un.d_ptr + + image->text_region.delta); break; case DT_RELSZ: image->rel_len = d[i].d_un.d_val; break; case DT_RELA: - image->rela = (RelaType*)(d[i].d_un.d_ptr - + image->text_region.delta + delta); + image->rela = (RelaType*)Class::Map(d[i].d_un.d_ptr + + image->text_region.delta); break; case DT_RELASZ: image->rela_len = d[i].d_un.d_val; break; case DT_JMPREL: - image->pltrel = (RelType*)(d[i].d_un.d_ptr - + image->text_region.delta + delta); + image->pltrel = (RelType*)Class::Map(d[i].d_un.d_ptr + + image->text_region.delta); break; case DT_PLTRELSZ: image->pltrel_len = d[i].d_un.d_val; @@ -656,35 +713,11 @@ elf_relocate_image(preloaded_image* image) } -template -inline status_t -resolve_symbol(ImageType* image, SymType* symbol, AddrType* symbolAddress) -{ - switch (symbol->st_shndx) { - case SHN_UNDEF: - // Since we do that only for the kernel, there shouldn't be - // undefined symbols. - return B_MISSING_SYMBOL; - case SHN_ABS: - *symbolAddress = symbol->st_value; - return B_NO_ERROR; - case SHN_COMMON: - // ToDo: finish this - TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n")); - return B_ERROR; - default: - // standard symbol - *symbolAddress = symbol->st_value + image->text_region.delta; - return B_NO_ERROR; - } -} - - status_t boot_elf_resolve_symbol(preloaded_elf32_image* image, struct Elf32_Sym* symbol, Elf32_Addr* symbolAddress) { - return resolve_symbol(image, symbol, symbolAddress); + return ELF32Loader::Resolve(image, symbol, symbolAddress); } @@ -693,6 +726,13 @@ status_t boot_elf_resolve_symbol(preloaded_elf64_image* image, struct Elf64_Sym* symbol, Elf64_Addr* symbolAddress) { - return resolve_symbol(image, symbol, symbolAddress); + return ELF64Loader::Resolve(image, symbol, symbolAddress); +} + +void +boot_elf64_set_relocation(Elf64_Addr resolveAddress, Elf64_Addr finalAddress) +{ + Elf64_Addr* dest = (Elf64_Addr*)ELF64Class::Map(resolveAddress); + *dest = finalAddress; } #endif diff --git a/src/system/boot/platform/amiga_m68k/mmu.cpp b/src/system/boot/platform/amiga_m68k/mmu.cpp index 040c34afa0..03f56b9f4e 100644 --- a/src/system/boot/platform/amiga_m68k/mmu.cpp +++ b/src/system/boot/platform/amiga_m68k/mmu.cpp @@ -662,20 +662,6 @@ platform_free_region(void *address, size_t size) } -status_t -platform_allocate_elf_region(uint32 *_address, uint32 size, uint8 protection, - void **_mappedAddress) -{ - void *address = mmu_allocate((void *)*_address, size); - if (address == NULL) - return B_NO_MEMORY; - - *_address = (uint32)address; - *_mappedAddress = address; - return B_OK; -} - - void platform_release_heap(struct stage2_args *args, void *base) { diff --git a/src/system/boot/platform/atari_m68k/mmu.cpp b/src/system/boot/platform/atari_m68k/mmu.cpp index 77759cd244..7132119fd2 100644 --- a/src/system/boot/platform/atari_m68k/mmu.cpp +++ b/src/system/boot/platform/atari_m68k/mmu.cpp @@ -666,20 +666,6 @@ platform_free_region(void *address, size_t size) } -status_t -platform_allocate_elf_region(uint32 *_address, uint32 size, uint8 protection, - void **_mappedAddress) -{ - void *address = mmu_allocate((void *)*_address, size); - if (address == NULL) - return B_NO_MEMORY; - - *_address = (uint32)address; - *_mappedAddress = address; - return B_OK; -} - - void platform_release_heap(struct stage2_args *args, void *base) { diff --git a/src/system/boot/platform/bios_ia32/mmu.cpp b/src/system/boot/platform/bios_ia32/mmu.cpp index 344abf7c4c..cfed3de612 100644 --- a/src/system/boot/platform/bios_ia32/mmu.cpp +++ b/src/system/boot/platform/bios_ia32/mmu.cpp @@ -769,43 +769,6 @@ platform_free_region(void *address, size_t size) } -status_t -platform_allocate_elf_region(uint32 *_address, uint32 size, uint8 protection, - void **_mappedAddress) -{ - void *address = mmu_allocate((void *)*_address, size); - if (address == NULL) - return B_NO_MEMORY; - - *_address = (uint32)address; - *_mappedAddress = address; - return B_OK; -} - - -status_t -platform_allocate_elf_region(uint64 *_address, uint64 size, uint8 protection, - void **_mappedAddress) -{ - // The 64-bit kernel is loaded to 0xFFFFFFFF80000000. You'll notice that - // the low 32 bits of this address are the same as the 32-bit KERNEL_BASE - // (0x80000000). Therefore, the way this function is implemented is to use - // mmu_allocate() and then set the upper 32 bits to all 1s. The long mode - // switch code will remap everything to the correct addresses. - - void *address = mmu_allocate((void *)(addr_t)(*_address & 0xFFFFFFFF), size); - if (address == NULL) - return B_NO_MEMORY; - - // This is the address that the ELF loading code will access the mapping - // through. - *_mappedAddress = address; - - *_address = (uint64)(uint32)address | 0xFFFFFFFF00000000LL; - return B_OK; -} - - void platform_release_heap(struct stage2_args *args, void *base) { diff --git a/src/system/boot/platform/cfe/mmu.cpp b/src/system/boot/platform/cfe/mmu.cpp index e33ebe7323..b9f3143c6f 100644 --- a/src/system/boot/platform/cfe/mmu.cpp +++ b/src/system/boot/platform/cfe/mmu.cpp @@ -34,21 +34,3 @@ platform_free_region(void *address, size_t size) return arch_mmu_free(address, size); } - -status_t -platform_allocate_elf_region(uint32 *_address, uint32 size, uint8 protection, - void **_mappedAddress) -{ - if (size == 0) - return B_BAD_VALUE; - - void *address = arch_mmu_allocate((void *)*_address, size, protection, - exactAddress); - if (address == NULL) - return B_NO_MEMORY; - - *_address = (uint32)address; - *_mappedAddress = address; - return B_OK; -} - diff --git a/src/system/boot/platform/openfirmware/mmu.cpp b/src/system/boot/platform/openfirmware/mmu.cpp index f284dae029..b765e8dcb1 100644 --- a/src/system/boot/platform/openfirmware/mmu.cpp +++ b/src/system/boot/platform/openfirmware/mmu.cpp @@ -34,21 +34,3 @@ platform_free_region(void *address, size_t size) return arch_mmu_free(address, size); } - -status_t -platform_allocate_elf_region(uint32 *_address, uint32 size, uint8 protection, - void **_mappedAddress) -{ - if (size == 0) - return B_BAD_VALUE; - - void *address = arch_mmu_allocate((void *)*_address, size, protection, - exactAddress); - if (address == NULL) - return B_NO_MEMORY; - - *_address = (uint32)address; - *_mappedAddress = address; - return B_OK; -} - diff --git a/src/system/boot/platform/raspberrypi_arm/mmu.cpp b/src/system/boot/platform/raspberrypi_arm/mmu.cpp index 3b52275e53..18c39f5a39 100644 --- a/src/system/boot/platform/raspberrypi_arm/mmu.cpp +++ b/src/system/boot/platform/raspberrypi_arm/mmu.cpp @@ -678,20 +678,6 @@ platform_free_region(void *address, size_t size) } -status_t -platform_allocate_elf_region(uint32 *_address, uint32 size, uint8 protection, - void **_mappedAddress) -{ - void *address = mmu_allocate((void *)*_address, size); - if (address == NULL) - return B_NO_MEMORY; - - *_address = (uint32)address; - *_mappedAddress = address; - return B_OK; -} - - void platform_release_heap(struct stage2_args *args, void *base) { diff --git a/src/system/boot/platform/routerboard_mipsel/mmu.cpp b/src/system/boot/platform/routerboard_mipsel/mmu.cpp index 744cac4a3a..cb4611926d 100644 --- a/src/system/boot/platform/routerboard_mipsel/mmu.cpp +++ b/src/system/boot/platform/routerboard_mipsel/mmu.cpp @@ -79,15 +79,6 @@ platform_free_region(void* address, size_t size) } -status_t -platform_allocate_elf_region(uint32 *_address, uint32 size, uint8 protection, - void **_mappedAddress) -{ -#warning IMPLEMENT platform_allocate_elf_region - return B_ERROR; -} - - void platform_release_heap(struct stage2_args* args, void* base) { diff --git a/src/system/boot/platform/u-boot/mmu.cpp b/src/system/boot/platform/u-boot/mmu.cpp index a1d001c714..e38d931171 100644 --- a/src/system/boot/platform/u-boot/mmu.cpp +++ b/src/system/boot/platform/u-boot/mmu.cpp @@ -681,24 +681,6 @@ platform_free_region(void *address, size_t size) } -status_t -platform_allocate_elf_region(uint32 *_address, uint32 size, uint8 protection, - void **_mappedAddress) -{ -#ifdef __ARM__ - void *address = mmu_allocate((void *)*_address, size); - if (address == NULL) - return B_NO_MEMORY; - - *_address = (uint32)address; - *_mappedAddress = address; - return B_OK; -#else - return B_ERROR; -#endif -} - - void platform_release_heap(struct stage2_args *args, void *base) { diff --git a/src/system/kernel/arch/x86_64/arch_elf.cpp b/src/system/kernel/arch/x86_64/arch_elf.cpp index 09d2f341e2..30f022d7db 100644 --- a/src/system/kernel/arch/x86_64/arch_elf.cpp +++ b/src/system/kernel/arch/x86_64/arch_elf.cpp @@ -162,7 +162,7 @@ boot_arch_elf_relocate_rela(preloaded_elf64_image* image, Elf64_Rela* rel, return B_BAD_DATA; } #ifdef _BOOT_MODE - boot_elf_set_relocation(image, relocAddr, relocValue); + boot_elf64_set_relocation(relocAddr, relocValue); #else *(Elf64_Addr *)relocAddr = relocValue; #endif diff --git a/src/system/ldscripts/x86_64/kernel.ld b/src/system/ldscripts/x86_64/kernel.ld index 1496cc7cae..5b454248db 100644 --- a/src/system/ldscripts/x86_64/kernel.ld +++ b/src/system/ldscripts/x86_64/kernel.ld @@ -29,7 +29,7 @@ SECTIONS .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } /* writable data */ - . = ALIGN (0x200000); + . = ALIGN (0x1000); __data_start = .; .data : { *(.data .data.* .gnu.linkonce.d.*) }