ZXFoundation™ 26h2
Loading...
Searching...
No Matches
types.cxxm
Go to the documentation of this file.
1/// SPDX-License-Identifier: Apache-2.0
2/// @file zxfoundation/dgp/domain.zcomponent/types.cxxm
3/// @brief Domain subsystem types — the central DGP entity, its strands, and
4/// its asynchronous signal mechanism.
5
6export module zxfoundation.dgp.domain.types;
7import zxfoundation.base.types;
8import zxfoundation.base.typestate;
9import zxfoundation.scoms.kobject.base;
10import zxfoundation.memory.vm.types;
11import zxfoundation.sync.qspinlock.core;
12import zxfoundation.dgp.isolation.types;
13import zxfoundation.dgp.signal.types;
14import zxfoundation.dgp.sync_contract;
15import zxfoundation.sched.policy;
16import zxfoundation.sched.entity;
17import zxfoundation.sched.sd.types;
18import zxfoundation.sched.rt.bandwidth;
19import zxfoundation.sched.nohz.core;
20import zxfoundation.sched.cbs.core;
21import arch.s390x.cpu.aste.consts;
22import arch.s390x.mmu.types;
23import arch.s390x.sched.types;
24import lib.error;
25import lib.rbtree;
26import lib.list;
27import std;
28
29export {
30
31namespace zxfoundation::dgp::domain {
32
33 /// @brief Opaque strand identifier.
34 using strand_id = u32;
35
36 /// @brief Sentinel value: no strand.
37 constexpr strand_id STRAND_ID_INVALID = 0xFFFF'FFFFU;
38
39 /// @brief Maximum strands per domain.
40 constexpr u32 MAX_STRANDS_PER_DOMAIN = 64U;
41
42 /// @brief Domain entry function type used by executor-style strand creation.
43 using strand_entry_fn = auto (*)(void*) noexcept -> void;
44
45 /// @brief Request used to create a secondary strand inside a domain.
46 struct strand_create_request {
47 u32 owner_domain{0xFFFF'FFFFU}; ///< Owning domain identifier.
48 strand_entry_fn entry{nullptr}; ///< Kernel entry fn (kthread mode);
49 /// null + non-null @c uregs selects user mode.
50 /// null + null @c uregs selects bare mode.
51 void* arg{nullptr}; ///< Opaque argument passed to @c entry (kthread mode only).
52 arch::s390x::sched::user_regs* uregs{nullptr}; ///< User register snapshot (user mode only).
53 /// Required when @c entry is null
54 /// and the strand is to be runnable.
55 /// Must have @c psw_addr != 0.
56 u16 cpu{0}; ///< Initial CPU affinity; zero is the deterministic bootstrap CPU.
57 u32 stack_order{2U}; ///< Kernel stack allocation order; currently constrained to the domain stack order.
58 bool enqueue{true}; ///< True when the scheduler should admit the strand immediately.
59 /// Must be false in bare mode.
60 };
61
62 /// @brief Per-strand flags (bitfield, stored in strand::flags).
63 enum class strand_flags : u8 {
64 none = 0,
65 idle = 1U << 0, ///< Idle strand (per-CPU, owner is nullptr).
66 };
67
68 [[nodiscard]] constexpr auto operator|(strand_flags a, strand_flags b) noexcept -> strand_flags {
69 return static_cast<strand_flags>(static_cast<u8>(a) | static_cast<u8>(b));
70 }
71 [[nodiscard]] constexpr auto operator&(strand_flags a, strand_flags b) noexcept -> strand_flags {
72 return static_cast<strand_flags>(static_cast<u8>(a) & static_cast<u8>(b));
73 }
74 constexpr auto operator|=(strand_flags& a, strand_flags b) noexcept -> strand_flags& {
75 a = a | b;
76 return a;
77 }
78 constexpr auto operator&=(strand_flags& a, strand_flags b) noexcept -> strand_flags& {
79 a = a & b;
80 return a;
81 }
82
83 struct strand_body;
84
85 /// @brief Strand — the DGP kernel's unit of schedulable execution.
86 struct strand {
87 scoms::kobject::bobject ko{};
88
89 void* owner{nullptr};
90
91 sched::sched_substate substate{sched::sched_substate::idle};
92 u8 _pad0[3]{};
93 u16 cpu{0};
94 bool on_rq{false};
95 strand_flags flags{strand_flags::none};
96
97 zxfoundation::sched::sched_entity se{};
98
99 strand_body* body{nullptr}; ///< allocated cold-fields body.
100 u64 kstack_top{0}; ///< Virtual kernel stack top (offset 112).
101 u64 ksp{0}; ///< Current kernel stack pointer (offset 120).
102
103 lib::list_node sched_link{};
104
105 zxfoundation::sched::sched_policy sched_policy{};
106 zxfoundation::sched::sched_admission_result sched_admission{};
107
108 strand() noexcept = default;
109 strand(const strand&) = delete;
110 auto operator=(const strand&) = delete;
111 strand(strand&&) = delete;
112 auto operator=(strand&&) = delete;
113 };
114
115
116 static_assert(__builtin_offsetof(strand, ko) == 0,
117 "strand::ko must be at offset 0");
118
119 static_assert(__builtin_offsetof(strand, se) == 40,
120 "strand::se must be at offset 40");
121
122 static_assert(__builtin_offsetof(strand, kstack_top) == 112,
123 "strand::kstack_top must be at offset 112");
124
125 static_assert(__builtin_offsetof(strand, ksp) == 120,
126 "strand::ksp must be at offset 120 — __switch_to_asm depends on this");
127
128
129 /// @brief Cold-field body for a strand
130 struct strand_body {
131 u64 kstack_base{0}; ///< Base VA of the kernel stack.
132 lib::list_node strand_list{}; ///< Link into domain's strand list.
133
134 u64 rt_runtime_used_ns{0}; /// Runtime consumed during current RT period.
135 u64 rt_period_start_ns{0}; /// RT accounting period start.
136 u64 deadline_runtime_used_ns{0}; /// Runtime consumed during current deadline period.
137 u64 absolute_deadline_ns{0}; /// Conservative absolute deadline key.
138
139 /// @brief PELT averaging state
140 sched::sched_avg pelt_avg{};
141
142 /// @note Only meaningful when @c sched_policy.class_id == deadline.
143 sched::cbs::cbs_replen cbs{};
144
145 void* blocked_on{nullptr};
146 lib::list_node pi_waiters{};
147 u8 boosted_prio{0};
148 sched::sched_class_id saved_class{zxfoundation::sched::sched_class_id::fair};
149 u8 saved_prio{0};
150 u8 _pad_pi[1]{};
151
152 arch::s390x::sched::user_regs uregs{}; ///< User-mode register save area.
153
154 strand_body() noexcept = default;
155 strand_body(const strand_body&) = delete;
156 auto operator=(const strand_body&) = delete;
157 strand_body(strand_body&&) = delete;
158 auto operator=(strand_body&&) = delete;
159 };
160
161 /// @brief Check whether a strand is an idle (per-CPU) strand.
162 [[nodiscard]] inline auto is_idle_strand(const strand& s) noexcept -> bool {
163 return (s.flags & strand_flags::idle) != strand_flags::none;
164 }
165
166 /// @brief Opaque domain identifier.
167 using domain_id = u32;
168
169 /// @brief Sentinel value: no domain.
170 constexpr domain_id DOMAIN_ID_INVALID = 0xFFFF'FFFFU;
171
172 /// @brief The nucleus itself is always domain 0.
173 constexpr domain_id DOMAIN_ID_NUCLEUS = 0U;
174
175 /// @brief Maximum number of domains in the system.
176 constexpr u32 MAX_DOMAINS = 256U;
177
178 /// @brief Key 0 = nucleus.
179 constexpr u8 SKEY_NUCLEUS = 0U;
180
181 /// @brief First user-assignable storage key.
182 constexpr u8 SKEY_USER_BASE = 8U;
183
184 /// @brief Last user-assignable storage key.
185 constexpr u8 SKEY_USER_MAX = 15U;
186
187 /// @brief Per-domain flags (bitfield).
188 enum class domain_flags : u32 {
189 none = 0,
190 idle = 1U << 1, ///< Idle domain (per-CPU).
191 need_resched = 1U << 2, ///< Reschedule requested.
192 nucleus = 1U << 3, ///< The kernel itself — immortal, never destroyed.
193 };
194
195 /// @brief Must match TIF_NEED_RESCHED = 4 in arch/s390x/trap/entry.S.
196 static_assert(static_cast<u32>(domain_flags::need_resched) == 4U,
197 "domain_flags::need_resched must match TIF_NEED_RESCHED in entry.S");
198
199 [[nodiscard]] constexpr auto operator|(domain_flags a, domain_flags b) noexcept -> domain_flags {
200 return static_cast<domain_flags>(static_cast<u32>(a) | static_cast<u32>(b));
201 }
202 [[nodiscard]] constexpr auto operator&(domain_flags a, domain_flags b) noexcept -> domain_flags {
203 return static_cast<domain_flags>(static_cast<u32>(a) & static_cast<u32>(b));
204 }
205 [[nodiscard]] constexpr auto operator~(domain_flags f) noexcept -> domain_flags {
206 return static_cast<domain_flags>(~static_cast<u32>(f));
207 }
208 [[nodiscard]] constexpr auto operator!(domain_flags f) noexcept -> bool {
209 return static_cast<u32>(f) == 0;
210 }
211 constexpr auto operator|=(domain_flags& a, domain_flags b) noexcept -> domain_flags& {
212 a = a | b;
213 return a;
214 }
215 constexpr auto operator&=(domain_flags& a, domain_flags b) noexcept -> domain_flags& {
216 a = a & b;
217 return a;
218 }
219
220 /// @brief The domain struct — the central entity of the DGP kernel.
221 struct domain {
222 scoms::kobject::bobject ko{};
223
224 const char* name{nullptr};
225
226 domain_flags flags{domain_flags::none};
227 u8 storage_key{0};
228 u8 _pad0[3]{};
229 u64 root_phys{0};
230
231 strand primary_strand{};
232
233 char name_storage[64]{};
234
235 arch::s390x::mmu::typed_asce<arch::s390x::mmu::dat_level::region_1> asce{};
236 arch::s390x::cpu::aste::art_context art{};
237 u16 portal_ar_mask{0};
238 u16 _pad_art{0};
239
240 u32 gate_count{0};
241 u32 portal_count{0};
242
243 zxfoundation::dgp::isolation::isolation_rights granted_rights{zxfoundation::dgp::isolation::isolation_rights::none};
244 u8 numa_node{0};
245 std::atomic<u16> revocation_epoch{0};
246 u32 storage_key_generation{0};
247 zxfoundation::dgp::isolation::skey_revocation_state storage_key_state{zxfoundation::dgp::isolation::skey_revocation_state::none};
248 zxfoundation::dgp::sync_contract::teardown_phase teardown_phase{zxfoundation::dgp::sync_contract::teardown_phase::none};
249
250 u32 pending_rights_revoke_raw{0};
251 u8 _pad_dgp_rev{0};
252 lib::list_node domain_list{};
253 lib::list_head strands{};
254 memory::vm::vm_space vm_space{};
255 signal::signal_queue signal_queue{};
256 u64 admin_token{0};
257
258 u64 rt_capability_token{0};
259 u64 rt_period_ns{100'000'000ULL};
260 u64 rt_budget_ns{20'000'000ULL};
261 u64 rt_reserved_ns{0};
262 u64 deadline_period_ns{100'000'000ULL};
263 u64 deadline_budget_ns{10'000'000ULL};
264 u64 deadline_reserved_ns{0};
265 zxfoundation::sched::sched_mask allowed_cpus{};
266 zxfoundation::sched::sched_mask allowed_numa_nodes{};
267
268 domain() noexcept = default;
269 domain(const domain&) = delete;
270 auto operator=(const domain&) = delete;
271 domain(domain&&) = delete;
272 auto operator=(domain&&) = delete;
273 };
274
275 static_assert(__builtin_offsetof(domain, ko) == 0,
276 "domain::ko must be at offset 0 — kobject layout constraint");
277
278 static_assert(__builtin_offsetof(domain, primary_strand) == 48,
279 "domain::primary_strand must be at offset 48");
280
281 [[nodiscard]] auto is_idle_domain(const domain& d) noexcept -> bool {
282 return (d.flags & domain_flags::idle) != domain_flags::none;
283 }
284
285 [[nodiscard]] auto is_active_domain(const domain& d) noexcept -> bool {
286 return d.ko.state == zxfoundation::base::lifecycle_state::active;
287 }
288
289} // namespace zxfoundation::dgp::domain
290
291} // end export