ZXFoundation™ 26h2
Loading...
Searching...
No Matches
percpu.cxxm
1/// SPDX-License-Identifier: Apache-2.0
2/// @file arch/s390x/cpu/percpu_types.cxxm
3/// @brief s390x per-CPU data block embedded in the lowcore at LC_PERCPU_OFFSET (0x0400).
4
5export module arch.s390x.cpu.percpu;
6import arch.s390x.cpu.types;
7import zxfoundation.base.types;
8import zxfoundation.sync.qspinlock.mcs;
9import zxfoundation.memory.pmm.types;
10import std;
11
12export {
13
14namespace arch::s390x::cpu::percpu {
15
16 using zxfoundation::memory::pmm::pcp_pool;
17
18 /// @brief Explicit interrupt context classification.
19 enum class irq_class : u8 {
20 none = 0, ///< Not in any interrupt handler.
21 ext = 1, ///< External interrupt (SAVE_FRAME from LC_EXT_OLD_PSW).
22 io = 2, ///< I/O interrupt (SAVE_FRAME from LC_IO_OLD_PSW).
23 pgm = 3, ///< Program check (SAVE_FRAME from LC_PGM_OLD_PSW).
24 svc = 4, ///< Supervisor call (SAVE_NUCLEUS_FRAME from LC_SVC_OLD_PSW).
25 mcck = 5, ///< Machine check (SAVE_FRAME from LC_MCCK_OLD_PSW).
26 nucleus = 6, ///< Program-call (PC) gate entry.
27 };
28
29 /// @brief s390x per-CPU data block embedded in the lowcore at 0x0400.
30 struct alignas(processor::CACHE_LINE_SIZE) percpu_data {
31 u64 prefix_phys{}; ///< Physical address of this CPU's 8 KB lowcore.
32
33 u16 cpu_id{}; ///< Logical CPU ID (0 = BSP, dense, 0-based).
34 u16 cpu_addr{}; ///< Hardware CPU address (from STAP instruction).
35 u32 _pad0{}; ///< Explicit padding to align next u64.
36
37 u64 current_domain{}; ///< Virtual address of the current domain struct.
38 u64 current_strand{}; ///< Virtual address of the currently executing strand.
39 u64 kernel_stack{}; ///< Top of this CPU's kernel stack (virtual).
40 u64 user_asce{}; ///< User ASCE (CR1 value for user address space).
41
42 i32 preempt_count{}; ///< Preemption depth. >0 means non-preemptible.
43 u32 softirq_pending{}; ///< Bitmask of pending deferred softirqs.
44 u32 irq_nesting{}; ///< Hardware IRQ/MCCK nesting depth (0 = not in IRQ handler).
45 u32 nucleus_nesting{}; ///< Synchronous SVC/PC nucleus-call nesting depth.
46 u32 lock_depth{}; ///< Current qspinlock MCS node allocation depth.
47 irq_class current_irq_class{}; ///< Explicit interrupt class being serviced (set by entry.S).
48 u8 _pad_irq_class[3]{}; ///< Pad to u32 alignment.
49 std::atomic<u64> ec_bits{};
50
51 zxfoundation::sync::qspinlock::mcs_node qnodes[zxfoundation::sync::qspinlock::MCS_MAX_LOCK_DEPTH]{};
52
53 u64 rcu_gp_seq{}; ///< Last observed RCU grace-period sequence number.
54 u64 rcu_qs_seq{}; ///< Last quiescent-state sequence number.
55 u8 in_rcu_read_side{}; ///< Non-zero if inside read_unlock().
56 u8 _pad1[7]{}; ///< Pad to u64 alignment.
57
58 void* rcu_pending_cbs{nullptr}; ///< Head of pending rcu_head list (rcu_head*).
59 u64 rcu_pending_gp{0}; ///< Grace period at which pending_cbs mature.
60 u32 rcu_pending_count{0}; ///< Number of callbacks pending.
61 u32 _pad_rcu{};
62
63 u32 ipi_pending_count{}; ///< Counter of pending IPI completion events.
64 u32 _pad2{};
65
66 u64 ap_stack_phys{}; ///< Physical address of AP's initial stack top.
67
68 pcp_pool pcp{};
69
70 u8 drawer_id{0};
71 u8 cpu_type{0}; ///< ZXFL_CPU_TYPE_* for this CPU (CP, IFL, zIIP, etc.)
72 u8 core_id{0}; ///< Scheduler core-group ID from ZXFL/STSI or degraded fallback.
73 u8 smt_id{0}; ///< SMT sibling ID inside core-group, zero when unproven.
74 u8 topology_evidence{0}; ///< ZXFL_CPU_EVIDENCE_* provenance flags.
75 u8 capacity{100}; ///< Scheduler capacity percentage, 100 when unknown.
76 u8 _pad_drawer[2]{};
77
78 u64 attached_asce{0}; ///< ASCE currently attached to CR1 for DGP tracking.
79 u32 attached_domain_id{0}; ///< Domain ID owning attached_asce, or nucleus for idle/kernel.
80 u8 attached_dgp_state{0}; ///< DGP isolation_state snapshot admitted by the scheduler.
81 u8 _pad_asce[3]{};
82
83 u64 watchdog_heartbeat{0}; ///< Monotonic counter bumped by scheduler_tick().
84
85 u32 pgm_fixup_applied{0}; ///< Non-zero if last PGM applied a fixup (set by pgm handler).
86 u64 pgm_fixup_addr{0}; ///< Fixup recovery label address set by try_applying_fixup.
87
88 u32 ipd_count{0}; ///< Nullifying IPD event counter within sliding window.
89 u64 ipd_window_deadline{0}; ///< Absolute TOD deadline resetting the IPD window.
90
91 /// @brief Deferred-interrupt work bitmap
92 std::atomic<u32> deferred_pending{};
93
94 u8 _pad_fixup[2]{};
95 };
96
97 static_assert(__builtin_offsetof(percpu_data, cpu_id) == 8,
98 "cpu_id must be at offset 8 within s390x_percpu_data "
99 "(required by LC_CPU_ID_OFFSET = 0x0408)");
100
101 static_assert(__builtin_offsetof(percpu_data, prefix_phys) == 0,
102 "prefix_phys must be at offset 0 within s390x_percpu_data");
103
104 static_assert(sizeof(percpu_data) <= 0x0E00,
105 "s390x_percpu_data exceeds available lowcore space (0x0400–0x11FF = 0x0E00 bytes)");
106
107 /// @brief Finish BSP per-CPU initialization.
108 auto init_bsp() noexcept -> void;
109
110 /// @brief Finish AP per-CPU initialization.
111 /// @param pcp HHDM-mapped pointer to the AP's pcp.
112 auto init_ap(percpu_data& pcp) noexcept -> void;
113
114 /// @brief Return a reference to the current CPU's per-CPU block.
115 [[nodiscard]] auto this_cpu() noexcept -> percpu_data&;
116
117 /// @brief get current cpu id
118 [[nodiscard]] auto cpu_id() noexcept -> u16;
119
120 /// @brief get current cpu's ZXFL_CPU_TYPE_* value
121 [[nodiscard]] auto cpu_type() noexcept -> u8;
122
123 /// @brief Return the lowercase short prefix for the current CPU type.
124 /// Used by printk to format e.g. [cp00], [ifl02], [ziip03].
125 [[nodiscard]] auto cpu_type_prefix() noexcept -> std::string_view;
126
127} // namespace arch::s390x::cpu::percpu
128
129} // end export