[PATCH] aarch64: align up size of the kernel TLS to 64 bytes

23 views
Skip to first unread message

Waldemar Kozaczuk

unread,
Feb 25, 2021, 12:36:23 AM2/25/21
to osv...@googlegroups.com, Waldemar Kozaczuk
Unlike the x86_64 linker script, the aarch64 version of it
does not align the size of the TLS segment to 64 bytes. In release
build it happens to be 64-bytes aligned, but the debug one does not
and causes the assertion fail in setup_tcb() as described by the issue
#1120.

The TLS segment does not need to be 64-bytes aligned in the loader ELF
file. However when we setup TCB block for each thread and initialize TLS
memory block for kernel and initial exec application ELF objects,
we need to make sure the start of the first application block starting
right after the kernel block is 64-bytes aligned.

In theory we could deal with a non 64-bytes aligned TLS segment by
modifying number of places in dynamic linker to align the kernel block
to 64 bytes. But it is easier to simply align up the size of the kernel TLS
segment right when we parse it out from kernel ELF in get_init() during
early boot phase. This actually works for both 64-bytes size aligned
segment in x64 build and unaligned one in aarch64 build, as logic
in all other relevant places will zero-out and initialize the correct
parts of kernel TLS block.

This patch also modifies arch_setup_tls() to zero-out the TLS block
for the 1st thread in similar way it is done in setup_tcb().

Fixes #1120

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
arch/aarch64/arch-setup.cc | 2 +-
core/elf.cc | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/aarch64/arch-setup.cc b/arch/aarch64/arch-setup.cc
index 30fb0db6..e22b4ea4 100644
--- a/arch/aarch64/arch-setup.cc
+++ b/arch/aarch64/arch-setup.cc
@@ -128,7 +128,7 @@ void arch_setup_free_memory()
void arch_setup_tls(void *tls, const elf::tls_data& info)
{
struct thread_control_block *tcb;
- memset(tls, 0, info.size + 1024);
+ memset(tls, 0, sizeof(*tcb) + info.size);

tcb = (thread_control_block *)tls;
tcb[0].tls_base = &tcb[1];
diff --git a/core/elf.cc b/core/elf.cc
index 06537be9..94e14b07 100644
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -1758,7 +1758,7 @@ init_table get_init(Elf64_Ehdr* header)
} else if (phdr->p_type == PT_TLS) {
ret.tls.start = reinterpret_cast<void*>(phdr->p_vaddr);
ret.tls.filesize = phdr->p_filesz;
- ret.tls.size = phdr->p_memsz;
+ ret.tls.size = align_up(phdr->p_memsz, (u64)64);
}
}
return ret;
--
2.29.2

Commit Bot

unread,
Mar 1, 2021, 10:20:26 AM3/1/21
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Waldemar Kozaczuk <jwkoz...@gmail.com>
Branch: master

aarch64: align up size of the kernel TLS to 64 bytes

Unlike the x86_64 linker script, the aarch64 version of it
does not align the size of the TLS segment to 64 bytes. In release
build it happens to be 64-bytes aligned, but the debug one does not
and causes the assertion fail in setup_tcb() as described by the issue
#1120.

The TLS segment does not need to be 64-bytes aligned in the loader ELF
file. However when we setup TCB block for each thread and initialize TLS
memory block for kernel and initial exec application ELF objects,
we need to make sure the start of the first application block starting
right after the kernel block is 64-bytes aligned.

In theory we could deal with a non 64-bytes aligned TLS segment by
modifying number of places in dynamic linker to align the kernel block
to 64 bytes. But it is easier to simply align up the size of the kernel TLS
segment right when we parse it out from kernel ELF in get_init() during
early boot phase. This actually works for both 64-bytes size aligned
segment in x64 build and unaligned one in aarch64 build, as logic
in all other relevant places will zero-out and initialize the correct
parts of kernel TLS block.

This patch also modifies arch_setup_tls() to zero-out the TLS block
for the 1st thread in similar way it is done in setup_tcb().

Fixes #1120

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>

---
diff --git a/arch/aarch64/arch-setup.cc b/arch/aarch64/arch-setup.cc
--- a/arch/aarch64/arch-setup.cc
+++ b/arch/aarch64/arch-setup.cc
@@ -128,7 +128,7 @@ void arch_setup_free_memory()
void arch_setup_tls(void *tls, const elf::tls_data& info)
{
struct thread_control_block *tcb;
- memset(tls, 0, info.size + 1024);
+ memset(tls, 0, sizeof(*tcb) + info.size);

tcb = (thread_control_block *)tls;
tcb[0].tls_base = &tcb[1];
diff --git a/core/elf.cc b/core/elf.cc
Reply all
Reply to author
Forward
0 new messages