1 /*
2  * Copyright (c) 2025 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 /**
7  * @file
8  * @brief Indirect Branch Tracking
9  *
10  * Indirect Branch Tracking (IBT) setup routines.
11  */
12 
13 #include <zephyr/kernel.h>
14 #include <zephyr/arch/x86/msr.h>
15 #include <zephyr/arch/x86/cet.h>
16 #include <zephyr/logging/log_ctrl.h>
17 #include <zephyr/logging/log.h>
18 
19 #include <kernel_arch_data.h>
20 LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
21 
22 #ifdef CONFIG_X86_64
23 #define TOKEN_OFFSET 5
24 #else
25 #define TOKEN_OFFSET 4
26 #endif
27 
28 #ifdef CONFIG_HW_SHADOW_STACK
29 #ifdef CONFIG_HW_SHADOW_STACK_ALLOW_REUSE
30 extern void arch_shadow_stack_reset(k_tid_t thread);
31 #endif /* CONFIG_HW_SHADOW_STACK_ALLOW_REUSE */
32 
arch_thread_hw_shadow_stack_attach(k_tid_t thread,arch_thread_hw_shadow_stack_t * stack,size_t stack_size)33 int arch_thread_hw_shadow_stack_attach(k_tid_t thread,
34 				       arch_thread_hw_shadow_stack_t *stack,
35 				       size_t stack_size)
36 {
37 	/* Can't attach to NULL */
38 	if (stack == NULL) {
39 		LOG_ERR("Can't set NULL shadow stack for thread %p\n", thread);
40 		return -EINVAL;
41 	}
42 
43 	/* Or if the thread already has a shadow stack. */
44 	if (thread->arch.shstk_addr != NULL) {
45 #ifdef CONFIG_HW_SHADOW_STACK_ALLOW_REUSE
46 		/* Allow reuse of the shadow stack if the base and size are the same */
47 		if (thread->arch.shstk_base == stack &&
48 		    thread->arch.shstk_size == stack_size) {
49 			unsigned int key;
50 
51 			key = arch_irq_lock();
52 			arch_shadow_stack_reset(thread);
53 			arch_irq_unlock(key);
54 
55 			return 0;
56 		}
57 #endif
58 		LOG_ERR("Shadow stack already set up for thread %p\n", thread);
59 		return -EINVAL;
60 	}
61 
62 	thread->arch.shstk_addr = stack + (stack_size -
63 					   TOKEN_OFFSET * sizeof(*stack)) / sizeof(*stack);
64 	thread->arch.shstk_size = stack_size;
65 	thread->arch.shstk_base = stack;
66 
67 	return 0;
68 }
69 #endif
70 
z_x86_cet_enable(void)71 void z_x86_cet_enable(void)
72 {
73 #ifdef CONFIG_X86_64
74 	__asm volatile (
75 			"movq %cr4, %rax\n\t"
76 			"orq $0x800000, %rax\n\t"
77 			"movq %rax, %cr4\n\t"
78 			);
79 #else
80 	__asm volatile (
81 			"movl %cr4, %eax\n\t"
82 			"orl $0x800000, %eax\n\t"
83 			"movl %eax, %cr4\n\t"
84 			);
85 #endif
86 }
87 
88 #ifdef CONFIG_X86_CET_IBT
z_x86_ibt_enable(void)89 void z_x86_ibt_enable(void)
90 {
91 	uint64_t msr = z_x86_msr_read(X86_S_CET_MSR);
92 
93 	msr |= X86_S_CET_MSR_ENDBR | X86_S_CET_MSR_NO_TRACK;
94 	z_x86_msr_write(X86_S_CET_MSR, msr);
95 }
96 #endif
97 
98 #ifdef CONFIG_X86_CET_VERIFY_KERNEL_SHADOW_STACK
z_x86_cet_shadow_stack_panic(k_tid_t * thread)99 void z_x86_cet_shadow_stack_panic(k_tid_t *thread)
100 {
101 	LOG_ERR("Shadow stack enabled, but outgoing thread [%p] struct "
102 		"missing shadow stack pointer", thread);
103 
104 	k_panic();
105 }
106 #endif
107