5export module arch.s390x.cpu.lowcore;
6import arch.s390x.cpu.psw;
7import arch.s390x.cpu.percpu;
8import arch.s390x.init.zxfl.protocol;
9import zxfoundation.sys.syschk.types;
10import zxfoundation.base.types;
14namespace arch::s390x::cpu::lowcore {
16 constexpr usize LOWCORE_SIZE = 0x2000UL;
18 constexpr u64 LC_EXT_OLD_PSW = 0x0130UL;
19 constexpr u64 LC_SVC_OLD_PSW = 0x0140UL;
20 constexpr u64 LC_PGM_OLD_PSW = 0x0150UL;
21 constexpr u64 LC_MCCK_OLD_PSW = 0x0160UL;
22 constexpr u64 LC_IO_OLD_PSW = 0x0170UL;
24 constexpr u64 LC_PSW_TEMP = 0x0248UL;
25 constexpr u64 LC_RETURN_PSW = 0x0290UL;
26 constexpr u64 LC_KERNEL_STACK = 0x0348UL;
27 constexpr u64 LC_ASYNC_STACK = 0x0350UL;
28 constexpr u64 LC_NODAT_STACK = 0x0358UL;
29 constexpr u64 LC_RESTART_STACK = 0x0360UL;
30 constexpr u64 LC_MCCK_STACK = 0x0368UL;
31 constexpr u64 LC_AP_CR0 = 0x0330UL;
32 constexpr u64 LC_AP_CR13 = 0x0338UL;
33 constexpr u64 LC_CURRENT_DOMAIN = 0x0340UL;
34 constexpr u64 LC_KERNEL_ASCE = 0x0388UL;
36 constexpr u64 LC_PERCPU_OFFSET = 0x0400UL;
37 constexpr u64 LC_CPU_ID_OFFSET = 0x0408UL;
38 constexpr u64 LC_PREEMPT_COUNT = 0x0430UL;
39 constexpr u64 LC_IRQ_NESTING = 0x0438UL;
40 constexpr u64 LC_NUCLEUS_NESTING = 0x043CUL;
41 constexpr u64 LC_IRQ_CLASS = 0x0444UL;
44 struct alignas(8192) zx_lowcore {
45 u8 pad_0x0000[0x0014 - 0x0000]{};
46 u32 ipl_parmblock_ptr{};
47 u8 pad_0x0018[0x0080 - 0x0018]{};
65 u8 pad_0x00a4[0x00a8 - 0x00a4]{};
72 u8 pad_0x00c4[0x00c8 - 0x00c4]{};
74 u8 pad_0x00cc[0x00e8 - 0x00cc]{};
75 u64 mcck_interruption_code{};
76 u8 pad_0x00f0[0x00f4 - 0x00f0]{};
77 u32 external_damage_code{};
78 u64 failing_storage_address{};
79 u8 pad_0x0100[0x0110 - 0x0100]{};
80 u64 breaking_event_addr{};
81 u8 pad_0x0118[0x0120 - 0x0118]{};
83 psw::zx_psw restart_old_psw{};
84 psw::zx_psw external_old_psw{};
85 psw::zx_psw svc_old_psw{};
86 psw::zx_psw program_old_psw{};
87 psw::zx_psw mcck_old_psw{};
88 psw::zx_psw io_old_psw{};
89 u8 pad_0x0180[0x01a0 - 0x0180]{};
91 psw::zx_psw restart_psw{};
92 psw::zx_psw external_new_psw{};
93 psw::zx_psw svc_new_psw{};
94 psw::zx_psw program_new_psw{};
95 psw::zx_psw mcck_new_psw{};
96 psw::zx_psw io_new_psw{};
98 u64 save_area_sync[8]{};
101 psw::zx_psw return_psw_temp{};
102 u8 pad_0x0258[0x0280 - 0x0258]{};
104 u64 save_area_restart[1]{};
107 psw::zx_psw return_psw{};
108 psw::zx_psw return_mcck_psw{};
111 u64 sys_enter_timer{};
112 u64 mcck_enter_timer{};
120 u64 avg_steal_timer{};
121 u64 last_update_timer{};
122 u64 last_update_clock{};
124 u8 pad_0x0320[0x0328 - 0x0320]{};
125 u64 clock_comparator{};
130 u64 current_domain{};
140 u32 restart_source{};
150 u32 softirq_pending{};
152 u32 spinlock_lockval{};
153 u32 spinlock_index{};
154 u8 pad_0x03b4[0x03b8 - 0x03b4]{};
157 u8 pad_0x03c0[0x0400 - 0x03c0]{};
159 percpu::percpu_data percpu{};
161 u8 pad_percpu_end[0x1200 - (0x0400 +
sizeof(percpu::percpu_data))]{};
163 u64 floating_pt_save_area[16]{};
164 u64 gpregs_save_area[16]{};
165 psw::zx_psw psw_save_area{};
166 u8 pad_0x1310[0x1318 - 0x1310]{};
167 u32 prefixreg_save_area{};
168 u32 fpt_creg_save_area{};
169 u8 pad_0x1320[0x1324 - 0x1320]{};
170 u32 tod_progreg_save_area{};
171 u32 cpu_timer_save_area[2]{};
172 u32 clock_comp_save_area[2]{};
173 u64 last_break_save_area{};
174 u32 access_regs_save_area[16]{};
175 u64 cregs_save_area[16]{};
176 zxfoundation::sys::syschk::zx_crash_record crash_record{};
177 u8 pad_0x1400_rest[0x1800 - 0x1400 -
sizeof(zxfoundation::sys::syschk::zx_crash_record)]{};
180 u8 pad_0x1900[0x2000 - 0x1900]{};
183 static_assert(
sizeof(zx_lowcore) == LOWCORE_SIZE,
184 "zx_lowcore must be exactly 8192 bytes");
186 static_assert(
__builtin_offsetof(zx_lowcore, external_old_psw) == LC_EXT_OLD_PSW,
187 "LC_EXT_OLD_PSW mismatch");
188 static_assert(
__builtin_offsetof(zx_lowcore, svc_old_psw) == LC_SVC_OLD_PSW,
189 "LC_SVC_OLD_PSW mismatch");
190 static_assert(
__builtin_offsetof(zx_lowcore, program_old_psw) == LC_PGM_OLD_PSW,
191 "LC_PGM_OLD_PSW mismatch");
192 static_assert(
__builtin_offsetof(zx_lowcore, mcck_old_psw) == LC_MCCK_OLD_PSW,
193 "LC_MCCK_OLD_PSW mismatch");
194 static_assert(
__builtin_offsetof(zx_lowcore, io_old_psw) == LC_IO_OLD_PSW,
195 "LC_IO_OLD_PSW mismatch");
197 static_assert(
__builtin_offsetof(zx_lowcore, return_psw_temp) == LC_PSW_TEMP,
198 "LC_PSW_TEMP mismatch");
199 static_assert(
__builtin_offsetof(zx_lowcore, return_psw) == LC_RETURN_PSW,
200 "LC_RETURN_PSW mismatch");
201 static_assert(
__builtin_offsetof(zx_lowcore, kernel_stack) == LC_KERNEL_STACK,
202 "LC_KERNEL_STACK mismatch");
203 static_assert(
__builtin_offsetof(zx_lowcore, async_stack) == LC_ASYNC_STACK,
204 "LC_ASYNC_STACK mismatch");
205 static_assert(
__builtin_offsetof(zx_lowcore, nodat_stack) == LC_NODAT_STACK,
206 "LC_NODAT_STACK mismatch");
207 static_assert(
__builtin_offsetof(zx_lowcore, restart_stack) == LC_RESTART_STACK,
208 "LC_RESTART_STACK mismatch");
209 static_assert(
__builtin_offsetof(zx_lowcore, mcck_stack) == LC_MCCK_STACK,
210 "LC_MCCK_STACK mismatch");
211 static_assert(
__builtin_offsetof(zx_lowcore, ap_cr0) == LC_AP_CR0,
212 "LC_AP_CR0 mismatch");
213 static_assert(
__builtin_offsetof(zx_lowcore, ap_cr13) == LC_AP_CR13,
214 "LC_AP_CR13 mismatch");
215 static_assert(
__builtin_offsetof(zx_lowcore, current_domain) == LC_CURRENT_DOMAIN,
216 "LC_CURRENT_DOMAIN mismatch");
217 static_assert(
__builtin_offsetof(zx_lowcore, kernel_asce) == LC_KERNEL_ASCE,
218 "LC_KERNEL_ASCE mismatch");
219 static_assert(
__builtin_offsetof(zx_lowcore, percpu) == LC_PERCPU_OFFSET,
220 "LC_PERCPU_OFFSET mismatch");
223 __builtin_offsetof(zx_lowcore, percpu) +
224 __builtin_offsetof(percpu::percpu_data, cpu_id) == LC_CPU_ID_OFFSET,
225 "LC_CPU_ID_OFFSET does not match actual cpu_id field offset in zx_lowcore; "
226 "update LC_CPU_ID_OFFSET to match");
229 __builtin_offsetof(zx_lowcore, percpu) +
230 __builtin_offsetof(percpu::percpu_data, irq_nesting) == LC_IRQ_NESTING,
231 "LC_IRQ_NESTING does not match irq_nesting field; update LC_IRQ_NESTING");
234 __builtin_offsetof(zx_lowcore, percpu) +
235 __builtin_offsetof(percpu::percpu_data, nucleus_nesting) == LC_NUCLEUS_NESTING,
236 "LC_NUCLEUS_NESTING does not match nucleus_nesting field; update LC_NUCLEUS_NESTING");
239 __builtin_offsetof(zx_lowcore, percpu) +
240 __builtin_offsetof(percpu::percpu_data, preempt_count) == LC_PREEMPT_COUNT,
241 "LC_PREEMPT_COUNT does not match preempt_count field; update entry.S");
243 [[nodiscard]]
auto get_current()
noexcept -> zx_lowcore*;
244 [[nodiscard]]
auto get_current_phys()
noexcept -> zx_lowcore*;
249 [[nodiscard]]
auto get_for_cpu(u16 cpu_id)
noexcept -> zx_lowcore*;
251 auto register_cpu_lowcore(u16 cpu_id, u64 phys_lc)
noexcept ->
void;
254 auto init_bsp(
const init::zxfl::protocol& proto)
noexcept ->
void;
256 [[nodiscard]]
auto this_cpu_percpu()
noexcept -> percpu::percpu_data&;
258 [[nodiscard]]
auto cpu_percpu(u16 cpu_id)
noexcept -> percpu::percpu_data*;
261 [[nodiscard]]
auto current_domain_ptr()
noexcept ->
void*;
264 [[nodiscard]]
auto current_strand_ptr()
noexcept ->
void*;
269 auto register_restart_handler(
270 void(*fn)(
void*)
noexcept,
275 struct ap_init_params {
288 auto init_ap(zx_lowcore& lc,
const ap_init_params& p)
noexcept ->
void;