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