Skip to main content

starnix_core/task/
thread_state.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::task::CurrentTask;
6use extended_pstate::{ExtendedPstatePointer, ExtendedPstateState};
7use starnix_registers::{HeapRegs, RegisterState, RegisterStorage, RegisterStorageEnum};
8use starnix_syscalls::SyscallResult;
9use starnix_types::arch::ArchWidth;
10use starnix_uapi::errors::{Errno, ErrnoCode};
11use starnix_uapi::user_address::ArchSpecific;
12
13#[derive(Clone)]
14pub enum ArchExtendedPstateStorage {
15    // Storage for 64 bit restricted mode.
16    State64(Box<ExtendedPstateState>),
17    #[cfg(target_arch = "aarch64")]
18    // Storage for 32 bit arm restricted mode.
19    State32(Box<extended_pstate::ExtendedAarch32PstateState>),
20}
21
22impl ArchExtendedPstateStorage {
23    /// Returns a type-erased pointer to the underlying storage currently in use.
24    pub fn as_ptr(&mut self) -> ExtendedPstatePointer {
25        match self {
26            ArchExtendedPstateStorage::State64(state) => {
27                ExtendedPstatePointer { extended_pstate: state.as_mut() as *mut _ }
28            }
29            #[cfg(target_arch = "aarch64")]
30            ArchExtendedPstateStorage::State32(state) => {
31                ExtendedPstatePointer { extended_aarch32_pstate: state.as_mut() as *mut _ }
32            }
33        }
34    }
35
36    pub fn reset(&mut self) {
37        match self {
38            ArchExtendedPstateStorage::State64(state) => state.reset(),
39            #[cfg(target_arch = "aarch64")]
40            ArchExtendedPstateStorage::State32(state) => state.reset(),
41        }
42    }
43
44    fn with_arch(arch_width: ArchWidth) -> Self {
45        #[cfg(target_arch = "aarch64")]
46        if arch_width == ArchWidth::Arch32 {
47            return ArchExtendedPstateStorage::State32(Box::new(
48                extended_pstate::ExtendedAarch32PstateState::default(),
49            ));
50        }
51        let _ = arch_width;
52        ArchExtendedPstateStorage::State64(Box::new(ExtendedPstateState::default()))
53    }
54}
55
56/// The thread related information of a `CurrentTask`. The information should never be used outside
57/// of the thread owning the `CurrentTask`.
58pub struct ThreadState<T: RegisterStorage> {
59    /// A copy of the registers associated with the Zircon thread. Up-to-date values can be read
60    /// from `self.handle.read_state_general_regs()`. To write these values back to the thread, call
61    /// `self.handle.write_state_general_regs(self.thread_state.registers.into())`.
62    pub registers: RegisterState<T>,
63
64    /// Copy of the current extended processor state including floating point and vector registers.
65    pub extended_pstate: ArchExtendedPstateStorage,
66
67    /// The errno code (if any) that indicated this task should restart a syscall.
68    pub restart_code: Option<ErrnoCode>,
69
70    /// A custom function to resume a syscall that has been interrupted by SIGSTOP.
71    /// To use, call set_syscall_restart_func and return ERESTART_RESTARTBLOCK. sys_restart_syscall
72    /// will eventually call it.
73    pub syscall_restart_func: Option<Box<SyscallRestartFunc>>,
74}
75
76impl<T: RegisterStorage + Default> Default for ThreadState<T> {
77    // TODO(https://fxbug.dev/407084069): Implementing default doesn't make much
78    // sense - we should only initialize thread state when we know the target
79    // architecture and we should initialize for that target specifically.
80    fn default() -> Self {
81        let registers = RegisterState::<T>::default();
82        let extended_pstate = ArchExtendedPstateStorage::with_arch(ArchWidth::Arch64);
83
84        Self { registers, extended_pstate, restart_code: None, syscall_restart_func: None }
85    }
86}
87
88impl<T: RegisterStorage> ThreadState<T> {
89    pub fn arch_width(&self) -> ArchWidth {
90        #[cfg(target_arch = "aarch64")]
91        {
92            return if self.registers.is_arch32() { ArchWidth::Arch32 } else { ArchWidth::Arch64 };
93        }
94        #[cfg(not(target_arch = "aarch64"))]
95        ArchWidth::Arch64
96    }
97
98    /// Returns a new `ThreadState` with the same `registers` as this one.
99    pub fn snapshot<R: RegisterStorage>(&self) -> ThreadState<R>
100    where
101        RegisterState<R>: From<RegisterState<T>>,
102    {
103        ThreadState::<R> {
104            registers: self.registers.clone().into(),
105            extended_pstate: self.extended_pstate.clone(),
106            restart_code: self.restart_code,
107            syscall_restart_func: None,
108        }
109    }
110
111    pub fn extended_snapshot<R: RegisterStorage>(&self) -> ThreadState<R>
112    where
113        RegisterState<R>: From<RegisterState<T>>,
114    {
115        ThreadState::<R> {
116            registers: self.registers.clone().into(),
117            extended_pstate: self.extended_pstate.clone(),
118            restart_code: self.restart_code,
119            syscall_restart_func: None,
120        }
121    }
122
123    pub fn replace_registers<O: RegisterStorage>(&mut self, other: &ThreadState<O>) {
124        let self_arch = self.arch_width();
125        let other_arch = other.arch_width();
126        self.registers.load(*other.registers);
127        // If we're switching between 32 and 64 bit mode, re-initialize the extended processor state.
128        self.extended_pstate = if self_arch == other_arch {
129            other.extended_pstate.clone()
130        } else {
131            ArchExtendedPstateStorage::with_arch(other_arch)
132        };
133    }
134
135    pub fn get_user_register(&mut self, offset: usize) -> Result<usize, Errno> {
136        let mut result: usize = 0;
137        self.registers.apply_user_register(offset, &mut |register| result = *register as usize)?;
138        Ok(result)
139    }
140
141    pub fn set_user_register(&mut self, offset: usize, value: usize) -> Result<(), Errno> {
142        let self_arch = self.arch_width();
143        let result =
144            self.registers.apply_user_register(offset, &mut |register| *register = value as u64);
145        // If setting the CPSR register to switch between 32 and 64 bit mode, re-initialize the extended processor state.
146        if self_arch != self.arch_width() {
147            self.extended_pstate = ArchExtendedPstateStorage::with_arch(self.arch_width());
148        }
149        result
150    }
151}
152
153impl From<ThreadState<HeapRegs>> for ThreadState<RegisterStorageEnum> {
154    fn from(value: ThreadState<HeapRegs>) -> Self {
155        ThreadState {
156            registers: value.registers.into(),
157            extended_pstate: value.extended_pstate,
158            restart_code: value.restart_code,
159            syscall_restart_func: value.syscall_restart_func,
160        }
161    }
162}
163
164impl<T: RegisterStorage> ArchSpecific for ThreadState<T> {
165    fn is_arch32(&self) -> bool {
166        #[cfg(target_arch = "aarch64")]
167        return self.registers.is_arch32();
168        #[cfg(not(target_arch = "aarch64"))]
169        false
170    }
171}
172
173pub type SyscallRestartFunc =
174    dyn FnOnce(&mut CurrentTask) -> Result<SyscallResult, Errno> + Send + Sync;