diff --git a/arch/x86_64/src/common/x86_64_internal.h b/arch/x86_64/src/common/x86_64_internal.h index c71769df460..0a34222b4ed 100644 --- a/arch/x86_64/src/common/x86_64_internal.h +++ b/arch/x86_64/src/common/x86_64_internal.h @@ -104,6 +104,14 @@ #define STACK_ALIGN_DOWN(a) ((a) & ~STACK_ALIGN_MASK) #define STACK_ALIGN_UP(a) (((a) + STACK_ALIGN_MASK) & ~STACK_ALIGN_MASK) +/* This is the value used to mark the stack for subsequent stack monitoring + * logic. + */ + +#define STACK_COLOR 0xdeadbeef +#define INTSTACK_COLOR 0xdeadbeef +#define HEAP_COLOR 'h' + #define getreg8(p) inb(p) #define putreg8(v,p) outb(v,p) #define getreg16(p) inw(p) @@ -254,6 +262,13 @@ void x86_64_usbuninitialize(void); void x86_64_pci_init(void); #endif +/* Defined in intel64_checkstack.c */ + +#ifdef CONFIG_STACK_COLORATION +size_t x86_64_stack_check(void *stackbase, size_t nbytes); +void x86_64_stack_color(void *stackbase, size_t nbytes); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __ARCH_X86_64_SRC_COMMON_UP_INTERNAL_H */ diff --git a/arch/x86_64/src/intel64/CMakeLists.txt b/arch/x86_64/src/intel64/CMakeLists.txt index daea8ac1bf5..956e0ac57a8 100644 --- a/arch/x86_64/src/intel64/CMakeLists.txt +++ b/arch/x86_64/src/intel64/CMakeLists.txt @@ -52,6 +52,10 @@ if(CONFIG_x86_64_UNWINDER_FRAME_POINTER) list(APPEND SRCS intel64_backtrace_fp.c) endif() +if(CONFIG_STACK_COLORATION) + list(APPEND SRCS intel64_checkstack.c) +endif() + if(CONFIG_MM_PGALLOC) list(APPEND SRCS intel64_pgalloc.c) endif() diff --git a/arch/x86_64/src/intel64/Make.defs b/arch/x86_64/src/intel64/Make.defs index 6867fa29b4c..7a8bd25817f 100644 --- a/arch/x86_64/src/intel64/Make.defs +++ b/arch/x86_64/src/intel64/Make.defs @@ -37,6 +37,9 @@ CHIP_CSRCS += intel64_cpu.c ifeq ($(CONFIG_x86_64_UNWINDER_FRAME_POINTER),y) CMN_CSRCS += intel64_backtrace_fp.c endif +ifeq ($(CONFIG_STACK_COLORATION),y) + CMN_CSRCS += intel64_checkstack.c +endif ifeq ($(CONFIG_MM_PGALLOC),y) CHIP_CSRCS += intel64_pgalloc.c diff --git a/arch/x86_64/src/intel64/intel64_checkstack.c b/arch/x86_64/src/intel64/intel64_checkstack.c new file mode 100644 index 00000000000..f87dd6fe07a --- /dev/null +++ b/arch/x86_64/src/intel64/intel64_checkstack.c @@ -0,0 +1,184 @@ +/**************************************************************************** + * arch/x86_64/src/intel64/intel64_checkstack.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 "sched/sched.h" +#include "x86_64_internal.h" + +#ifdef CONFIG_STACK_COLORATION + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: x86_64_stack_check + * + * Description: + * Determine (approximately) how much stack has been used by searching the + * stack memory for a high water mark. That is, the deepest level of the + * stack that clobbered some recognizable marker in the stack memory. + * + * Input Parameters: + * alloc - Allocation base address of the stack + * size - The size of the stack in bytes + * + * Returned Value: + * The estimated amount of stack space used. + * + ****************************************************************************/ + +size_t x86_64_stack_check(void *stackbase, size_t nbytes) +{ + uintptr_t start; + uintptr_t end; + uint32_t *ptr; + size_t mark; + + if (nbytes == 0) + { + return 0; + } + + /* Take extra care that we do not check outside the stack boundaries */ + + start = STACK_ALIGN_UP((uintptr_t)stackbase); + end = STACK_ALIGN_DOWN((uintptr_t)stackbase + nbytes); + + /* Get the adjusted size based on the top and bottom of the stack */ + + nbytes = end - start; + + /* The x64 uses a push-down stack: the stack grows toward lower addresses + * in memory. We need to start at the lowest address in the stack memory + * allocation and search to higher addresses. The first word we encounter + * that does not have the magic value is the high water mark. + */ + + for (ptr = (uint32_t *)start, mark = (nbytes >> 2); + *ptr == STACK_COLOR && mark > 0; + ptr++, mark--); + + /* Return our guess about how much stack space was used */ + + return mark << 2; +} + +/**************************************************************************** + * Name: x86_64_stack_color + * + * Description: + * Write a well know value into the stack + * + ****************************************************************************/ + +void x86_64_stack_color(void *stackbase, size_t nbytes) +{ + uint32_t *stkptr; + uintptr_t stkend; + size_t nwords; + uintptr_t sp; + + /* Take extra care that we do not write outside the stack boundaries */ + + stkptr = (uint32_t *)STACK_ALIGN_UP((uintptr_t)stackbase); + + if (nbytes == 0) /* 0: colorize the running stack */ + { + stkend = up_getsp(); + if (stkend > (uintptr_t)&sp) + { + stkend = (uintptr_t)&sp; + } + } + else + { + stkend = (uintptr_t)stackbase + nbytes; + } + + stkend = STACK_ALIGN_DOWN(stkend); + nwords = (stkend - (uintptr_t)stkptr) >> 2; + + /* Set the entire stack to the coloration value */ + + while (nwords-- > 0) + { + *stkptr++ = STACK_COLOR; + } +} + +/**************************************************************************** + * Name: up_check_tcbstack and friends + * + * Description: + * Determine (approximately) how much stack has been used be searching the + * stack memory for a high water mark. That is, the deepest level of the + * stack that clobbered some recognizable marker in the stack memory. + * + * Input Parameters: + * None + * + * Returned Value: + * The estimated amount of stack space used. + * + ****************************************************************************/ + +size_t up_check_tcbstack(struct tcb_s *tcb) +{ + size_t size; + +#ifdef CONFIG_ARCH_ADDRENV + struct addrenv_s *oldenv; + + if (tcb->addrenv_own != NULL) + { + addrenv_select(tcb->addrenv_own, &oldenv); + } +#endif + + size = x86_64_stack_check(tcb->stack_base_ptr, tcb->adj_stack_size); + +#ifdef CONFIG_ARCH_ADDRENV + if (tcb->addrenv_own != NULL) + { + addrenv_restore(oldenv); + } +#endif + + return size; +} + +#if CONFIG_ARCH_INTERRUPTSTACK > 3 +size_t up_check_intstack(int cpu) +{ + return x86_64_stack_check((void *)up_get_intstackbase(cpu), + STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK)); +} +#endif + +#endif /* CONFIG_STACK_COLORATION */ diff --git a/arch/x86_64/src/intel64/intel64_initialstate.c b/arch/x86_64/src/intel64/intel64_initialstate.c index 196f9d329ef..1c482fccbe4 100644 --- a/arch/x86_64/src/intel64/intel64_initialstate.c +++ b/arch/x86_64/src/intel64/intel64_initialstate.c @@ -68,23 +68,17 @@ void up_initial_state(struct tcb_s *tcb) { char *stack_ptr = (char *)(g_idle_topstack[0] - CONFIG_IDLETHREAD_STACKSIZE); + tcb->stack_alloc_ptr = stack_ptr; + tcb->stack_base_ptr = stack_ptr; + tcb->adj_stack_size = CONFIG_IDLETHREAD_STACKSIZE; #ifdef CONFIG_STACK_COLORATION - char *stack_end = (char *)up_getsp(); - /* If stack debug is enabled, then fill the stack with a * recognizable value that we can use later to test for high * water marks. */ - while (stack_ptr < stack_end) - { - *--stack_end = 0xaa; - } + x86_64_stack_color(tcb->stack_alloc_ptr, 0); #endif /* CONFIG_STACK_COLORATION */ - - tcb->stack_alloc_ptr = stack_ptr; - tcb->stack_base_ptr = stack_ptr; - tcb->adj_stack_size = CONFIG_IDLETHREAD_STACKSIZE; } /* Initialize the initial exception register context structure */ diff --git a/arch/x86_64/src/intel64/intel64_irq.c b/arch/x86_64/src/intel64/intel64_irq.c index 38f44a480fd..2e9c9a21a4a 100644 --- a/arch/x86_64/src/intel64/intel64_irq.c +++ b/arch/x86_64/src/intel64/intel64_irq.c @@ -429,6 +429,29 @@ static inline void up_idtinit(void) setidt(&g_idt_entries, sizeof(struct idt_entry_s) * NR_IRQS - 1); } +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_color_intstack + * + * Description: + * Set the interrupt stack to a value so that later we can determine how + * much stack space was used by interrupt handling logic + * + ****************************************************************************/ + +#if defined(CONFIG_STACK_COLORATION) && CONFIG_ARCH_INTERRUPTSTACK > 3 +static inline void x86_64_color_intstack(void) +{ + x86_64_stack_color((void *)up_get_intstackbase(up_cpu_index()), + IRQ_STACK_SIZE); +} +#else +# define x86_64_color_intstack() +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -445,6 +468,10 @@ void up_irqinitialize(void) x86_64_cpu_tss_init(cpu); + /* Colorize the interrupt stack */ + + x86_64_color_intstack(); + /* Initialize the APIC */ up_apic_init(); diff --git a/arch/x86_64/src/intel64/intel64_usestack.c b/arch/x86_64/src/intel64/intel64_usestack.c index 386d7c77cdb..9f2784dfdf1 100644 --- a/arch/x86_64/src/intel64/intel64_usestack.c +++ b/arch/x86_64/src/intel64/intel64_usestack.c @@ -92,14 +92,6 @@ int up_use_stack(struct tcb_s *tcb, void *stack, size_t stack_size) tcb->stack_alloc_ptr = stack; - /* If stack debug is enabled, then fill the stack with a recognizable value - * that we can use later to test for high water marks. - */ - -#ifdef CONFIG_STACK_COLORATION - memset(tcb->stack_alloc_ptr, 0xaa, stack_size); -#endif - /* The intel64 uses a push-down stack: the stack grows toward lower * addresses in memory. The stack pointer register, points to the lowest, * valid work address (the "top" of the stack). Items on the stack are @@ -123,5 +115,14 @@ int up_use_stack(struct tcb_s *tcb, void *stack, size_t stack_size) tcb->stack_base_ptr = tcb->stack_alloc_ptr; tcb->adj_stack_size = size_of_stack; +#ifdef CONFIG_STACK_COLORATION + /* If stack debug is enabled, then fill the stack with a + * recognizable value that we can use later to test for high + * water marks. + */ + + x86_64_stack_color(tcb->stack_base_ptr, tcb->adj_stack_size); +#endif /* CONFIG_STACK_COLORATION */ + return OK; }