From 8b86f5de608f80423a7258efe78fa2d68200a7c9 Mon Sep 17 00:00:00 2001 From: liwenxiang1 Date: Wed, 9 Oct 2024 15:28:49 +0800 Subject: [PATCH] arch/x86_64: add support for thread_local Signed-off-by: liwenxiang1 --- arch/Kconfig | 1 + arch/x86_64/src/common/CMakeLists.txt | 4 ++ arch/x86_64/src/common/Make.defs | 4 ++ arch/x86_64/src/common/x86_64_internal.h | 18 +++++ arch/x86_64/src/common/x86_64_tls.c | 71 +++++++++++++++++++ .../src/intel64/intel64_fullcontextrestore.S | 8 ++- .../x86_64/src/intel64/intel64_initialstate.c | 23 +++++- .../qemu-intel64/configs/nsh/defconfig | 1 + .../intel64/qemu-intel64/scripts/qemu.ld | 15 ++++ 9 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 arch/x86_64/src/common/x86_64_tls.c diff --git a/arch/Kconfig b/arch/Kconfig index 3beab388c2..9237150062 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -138,6 +138,7 @@ config ARCH_X86_64 select ARCH_HAVE_TESTSET select ARCH_HAVE_INTERRUPTSTACK select ARCH_HAVE_CUSTOMOPT + select ARCH_HAVE_THREAD_LOCAL select PCI_LATE_DRIVERS_REGISTER if PCI select LIBC_ARCH_ELF_64BIT if LIBC_ARCH_ELF select ARCH_TOOLCHAIN_GNU diff --git a/arch/x86_64/src/common/CMakeLists.txt b/arch/x86_64/src/common/CMakeLists.txt index 3ee09cfdb1..51570e536f 100644 --- a/arch/x86_64/src/common/CMakeLists.txt +++ b/arch/x86_64/src/common/CMakeLists.txt @@ -45,6 +45,10 @@ if(CONFIG_ARCH_X86_64_ACPI) list(APPEND SRCS x86_64_acpi.c) endif() +if(CONFIG_SCHED_THREAD_LOCAL) + list(APPEND SRCS x86_64_tls.c) +endif() + if(CONFIG_ARCH_USE_MMU) list(APPEND SRCS x86_64_mmu.c) endif() diff --git a/arch/x86_64/src/common/Make.defs b/arch/x86_64/src/common/Make.defs index 3c2db5bf01..e18caaa270 100644 --- a/arch/x86_64/src/common/Make.defs +++ b/arch/x86_64/src/common/Make.defs @@ -38,6 +38,10 @@ ifeq ($(CONFIG_ARCH_X86_64_ACPI),y) CMN_CSRCS += x86_64_acpi.c endif +ifeq ($(CONFIG_SCHED_THREAD_LOCAL),y) +CMN_CSRCS += x86_64_tls.c +endif + ifeq ($(CONFIG_ARCH_USE_MMU),y) CMN_CSRCS += x86_64_mmu.c endif diff --git a/arch/x86_64/src/common/x86_64_internal.h b/arch/x86_64/src/common/x86_64_internal.h index 0a34222b4e..d4089f11b4 100644 --- a/arch/x86_64/src/common/x86_64_internal.h +++ b/arch/x86_64/src/common/x86_64_internal.h @@ -134,6 +134,20 @@ # define IRQ_STACK_SIZE CONFIG_ARCH_INTERRUPTSTACK #endif +/* Linker defined section addresses */ + +#define _START_TEXT _stext +#define _END_TEXT _etext +#define _START_BSS _sbss +#define _END_BSS _ebss +#define _DATA_INIT _eronly +#define _START_DATA _sdata +#define _END_DATA _edata +#define _START_TDATA _stdata +#define _END_TDATA _etdata +#define _START_TBSS _stbss +#define _END_TBSS _etbss + /**************************************************************************** * Public Types ****************************************************************************/ @@ -171,6 +185,10 @@ extern uint8_t _sdata[]; /* Start of .data */ extern uint8_t _edata[]; /* End+1 of .data */ extern uint8_t _sbss[]; /* Start of .bss */ extern uint8_t _ebss[]; /* End+1 of .bss */ +extern uint8_t _stdata[]; /* Start of .tdata */ +extern uint8_t _etdata[]; /* End+1 of .tdata */ +extern uint8_t _stbss[]; /* Start of .tbss */ +extern uint8_t _etbss[]; /* End+1 of .tbss */ #endif /**************************************************************************** diff --git a/arch/x86_64/src/common/x86_64_tls.c b/arch/x86_64/src/common/x86_64_tls.c new file mode 100644 index 0000000000..1a0c32b045 --- /dev/null +++ b/arch/x86_64/src/common/x86_64_tls.c @@ -0,0 +1,71 @@ +/**************************************************************************** + * arch/x86_64/src/common/x86_64_tls.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "x86_64_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_tls_size + * + * Description: + * Get TLS (sizeof(struct tls_info_s) + tdata + tbss) section size. + * + * Returned Value: + * Size of (sizeof(struct tls_info_s) + tdata + tbss). + * + ****************************************************************************/ + +int up_tls_size(void) +{ + return sizeof(struct tls_info_s) + + _END_TBSS - _START_TDATA + sizeof(void *); +} + +/**************************************************************************** + * Name: up_tls_initialize + * + * Description: + * Initialize thread local region. + * + * Input Parameters: + * info - The TLS structure to initialize. + * + ****************************************************************************/ + +void up_tls_initialize(struct tls_info_s *info) +{ + uint8_t *tls_data = (uint8_t *)(info + 1); + uint32_t tdata_len = _END_TDATA - _START_TDATA; + uint32_t tbss_len = _END_TBSS - _START_TBSS; + + memcpy(tls_data, _START_TDATA, tdata_len); + memset(tls_data + tdata_len, 0, tbss_len); +} diff --git a/arch/x86_64/src/intel64/intel64_fullcontextrestore.S b/arch/x86_64/src/intel64/intel64_fullcontextrestore.S index d52b7da744..55b1ee871d 100644 --- a/arch/x86_64/src/intel64/intel64_fullcontextrestore.S +++ b/arch/x86_64/src/intel64/intel64_fullcontextrestore.S @@ -108,7 +108,6 @@ x86_64_fullcontextrestore: movq (8*REG_R10)(%rdi), %r10 movq (8*REG_RBP)(%rdi), %rbp movq (8*REG_RBX)(%rdi), %rbx - movq (8*REG_RAX)(%rdi), %rax /* Restore the data segment register. I think there is an issue that will * need to be address here at some time: If the register save area is in @@ -124,6 +123,13 @@ x86_64_fullcontextrestore: * XXX: Should use wrgsbase and wrfsbase to restore the gs and fs register */ +#ifdef CONFIG_SCHED_THREAD_LOCAL + mov (8*REG_FS)(%rdi), %rax + wrfsbase %rax +#endif + + movq (8*REG_RAX)(%rdi), %rax + /* Restore the correct value of EAX and then return */ popq %rdi diff --git a/arch/x86_64/src/intel64/intel64_initialstate.c b/arch/x86_64/src/intel64/intel64_initialstate.c index 1c482fccbe..0b0ad138f5 100644 --- a/arch/x86_64/src/intel64/intel64_initialstate.c +++ b/arch/x86_64/src/intel64/intel64_initialstate.c @@ -30,6 +30,10 @@ #include #include +#ifdef CONFIG_SCHED_THREAD_LOCAL +# include +#endif + #include "x86_64_internal.h" #include "sched/sched.h" @@ -132,12 +136,25 @@ void up_initial_state(struct tcb_s *tcb) xcp->regs[REG_SS] = up_getss(); xcp->regs[REG_ES] = up_getes(); - /* Aux GS and FS are set to be 0 */ +/* FS used by for TLS + * used by some libc for TLS and segment reference + */ - /* used by some libc for TLS and segment reference */ +#ifdef CONFIG_SCHED_THREAD_LOCAL + xcp->regs[REG_FS] = (uintptr_t)tcb->stack_alloc_ptr + + sizeof(struct tls_info_s) + + (_END_TBSS - _START_TDATA); + + *(uint64_t *)(xcp->regs[REG_FS]) = xcp->regs[REG_FS]; + + write_fsbase(xcp->regs[REG_FS]); +#else + xcp->regs[REG_FS] = 0; +#endif + + /* GS used for CPU private data */ xcp->regs[REG_GS] = 0; - xcp->regs[REG_FS] = 0; /* Set supervisor- or user-mode, depending on how NuttX is configured and * what kind of thread is being started. Disable FIQs in any event diff --git a/boards/x86_64/intel64/qemu-intel64/configs/nsh/defconfig b/boards/x86_64/intel64/qemu-intel64/configs/nsh/defconfig index b1e799c472..53b3678530 100644 --- a/boards/x86_64/intel64/qemu-intel64/configs/nsh/defconfig +++ b/boards/x86_64/intel64/qemu-intel64/configs/nsh/defconfig @@ -45,6 +45,7 @@ CONFIG_PTHREAD_STACK_MIN=4194304 CONFIG_RAM_SIZE=268435456 CONFIG_SCHED_CHILD_STATUS=y CONFIG_SCHED_HAVE_PARENT=y +CONFIG_SCHED_THREAD_LOCAL=y CONFIG_SCHED_TICKLESS=y CONFIG_SCHED_TICKLESS_ALARM=y CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP=y diff --git a/boards/x86_64/intel64/qemu-intel64/scripts/qemu.ld b/boards/x86_64/intel64/qemu-intel64/scripts/qemu.ld index df9abc7f1c..85351ae7f7 100644 --- a/boards/x86_64/intel64/qemu-intel64/scripts/qemu.ld +++ b/boards/x86_64/intel64/qemu-intel64/scripts/qemu.ld @@ -48,6 +48,11 @@ SECTIONS *(.loader.rodata) } + .loader.tdata_tbss : { + *(.loader.tdata) + *(.loader.tbss) + } + .loader.data : { *(.loader.data) } @@ -89,6 +94,16 @@ SECTIONS _erodata = ABSOLUTE(.); } + .tdata_tbss ALIGN(0x1000) : + { + _stdata = ABSOLUTE(.); + *(.tdata .tdata.* .gnu.linkonce.td.*); + _etdata = ABSOLUTE(.); + _stbss = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.* .tcommon); + _etbss = ABSOLUTE(.); + } + .data ALIGN(0x1000) : { _sdata = ABSOLUTE(.);