Cleaned up ELF64 address handling.

* platform_allocate_elf_region() is removed, it is implemented in platform-
  independent code now (ELF*Class::AllocateRegion). For ELF64 it is now
  assumed that 64-bit addresses are mapped in the loader's 32-bit address space
  as (address - KERNEL_BASE_64BIT + KERNEL_BASE).
* mapped_delta field from preloaded_*_image removed, now handled compile-time
  using the ELF*Class::Map method.
* Also link the kernel with -z max-page-size=0x1000, removes the need for
  2MB alignment on the data segment (not going to map the kernel with large
  pages for the time being).
This commit is contained in:
Alex Smith
2012-06-25 13:00:50 +01:00
parent 8846189866
commit 6f6d78e877
16 changed files with 124 additions and 239 deletions
+1
View File
@@ -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 ;
@@ -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
@@ -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)
+2 -14
View File
@@ -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<Elf32_Sym> syms;
FixedWidthPointer<Elf32_Rel> 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<Elf64_Sym> syms;
FixedWidthPointer<Elf64_Rel> 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<typename ImageType, typename AddrType>
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 */
-7
View File
@@ -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 */
+100 -60
View File
@@ -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<ELF32Class> 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<ELF64Class> ELF64Loader;
@@ -227,15 +273,15 @@ ELFLoader<Class>::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<Class>::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<Class>::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<Class>::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<Class>::Relocate(preloaded_image* _image)
{
ImageType* image = static_cast<ImageType*>(_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<Class>::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<typename Class>
/*static*/ status_t
ELFLoader<Class>::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<typename Class>
/*static*/ status_t
@@ -487,7 +545,7 @@ error1:
template<typename Class>
/*static*/ status_t
ELFLoader<Class>::_ParseDynamicSection(ImageType* image, AddrType delta)
ELFLoader<Class>::_ParseDynamicSection(ImageType* image)
{
image->syms = 0;
image->rel = 0;
@@ -501,8 +559,7 @@ ELFLoader<Class>::_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<Class>::_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<typename ImageType, typename SymType, typename AddrType>
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
@@ -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)
{
@@ -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)
{
@@ -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)
{
-18
View File
@@ -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;
}
@@ -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;
}
@@ -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)
{
@@ -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)
{
-18
View File
@@ -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)
{
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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.*) }