5export module arch.s390x.mmu.core;
6import arch.s390x.mmu.types;
7import arch.s390x.mmu.consts;
8import arch.s390x.mmu.tlb;
9import zxfoundation.base.types;
10import zxfoundation.memory.pmm;
11import zxfoundation.memory.pmm.types;
12import zxfoundation.base.transaction;
16namespace arch::s390x::mmu::detail {
18 using namespace zxfoundation::memory;
20 from_global(reference)
bool g_has_edat1;
21 from_global(reference)
bool g_has_edat2;
27 [[nodiscard]]
auto init_table(dat_level lvl, u64 phys)
noexcept -> ::
std::
expected<
void, ::lib::kernel_error>;
37 const pmm::allocation_request& table_policy
38 )
noexcept -> ::
std::
expected<
void, ::lib::kernel_error>;
46 )
noexcept -> ::
std::
expected<u64, ::lib::kernel_error>;
53 )
noexcept -> ::
std::
expected<u64, ::lib::kernel_error>;
61 )
noexcept -> ::
std::
expected<
void, ::lib::kernel_error>;
70 )
noexcept -> ::
std::
expected<
void, ::lib::kernel_error>;
79 )
noexcept -> ::
std::
expected<
void, ::lib::kernel_error>;
85namespace arch::s390x::mmu {
88 auto init()
noexcept ->
void;
91 [[nodiscard]]
auto has_edat1()
noexcept ->
bool;
94 [[nodiscard]]
auto has_edat2()
noexcept ->
bool;
97 template <dat_level Level>
98 requires (Level != dat_level::page)
99 [[nodiscard]]
auto crst_alloc()
noexcept
100 -> ::std::expected<dat_table<Level>, ::lib::kernel_error>
102 auto result = zxfoundation::memory::pmm::alloc(
104 zxfoundation::memory::pmm::zone::normal,
105 zxfoundation::memory::pmm::purpose::page_table);
106 if (!result) [[unlikely]]
107 return ::std::unexpected(result.error());
108 const u64 phys = result->phys_base;
109 auto init_result = detail::init_table(Level, phys);
110 if (!init_result) [[unlikely]] {
111 zxfoundation::memory::pmm::folio_active f{
114 zxfoundation::memory::pmm::purpose::page_table,
115 zxfoundation::memory::pmm::zone::normal};
116 zxfoundation::memory::pmm::free(::std::move(f));
117 return ::std::unexpected(init_result.error());
119 return dat_table<Level>(phys);
123 [[nodiscard]]
auto pte_table_alloc()
noexcept
124 -> ::std::expected<dat_table<dat_level::page>, ::lib::kernel_error>;
127 template <dat_level Level>
128 auto table_free(dat_table<Level> tbl)
noexcept ->
void {
129 if (!tbl.valid())
return;
130 constexpr u32 order = (Level == dat_level::page)
131 ? PTE_ALLOC_ORDER : CRST_ALLOC_ORDER;
132 zxfoundation::memory::pmm::folio_active f{
133 tbl.origin_phys, order,
134 zxfoundation::memory::pmm::purpose::page_table,
135 zxfoundation::memory::pmm::zone::normal};
136 zxfoundation::memory::pmm::free(::std::move(f));
140 template <dat_level Root>
141 requires (Root != dat_level::page)
142 [[nodiscard]]
auto asce_build(dat_table<Root> root)
noexcept -> typed_asce<Root> {
143 const u64 val = (root.origin_phys & ASCE_ORIGIN_MASK)
144 | asce_type_code<Root>()
146 return typed_asce<Root>(val);
151 template <dat_level Root>
152 [[nodiscard]]
auto map_page(
153 dat_table<Root> root,
157 )
noexcept -> ::std::expected<
void, ::lib::kernel_error> {
158 const auto table_policy = detail::default_table_request();
159 auto result = detail::map_page_impl(
160 root.origin_phys, Root, virt, phys, prot, table_policy);
172 template <dat_level Root>
173 [[nodiscard]]
auto map_page_with_policy(
174 dat_table<Root> root,
178 const zxfoundation::memory::pmm::allocation_request& table_policy
179 )
noexcept -> ::std::expected<
void, ::lib::kernel_error> {
180 auto result = detail::map_page_impl(
181 root.origin_phys, Root, virt, phys, prot, table_policy);
188 template <dat_level Root>
189 [[nodiscard]]
auto unmap_page(
190 dat_table<Root> root,
192 )
noexcept -> ::std::expected<u64, ::lib::kernel_error> {
194 auto phys_result = detail::walk_impl(
195 root.origin_phys, Root, virt);
197 return ::std::unexpected(phys_result.error());
198 const u64 old_phys = *phys_result;
200 auto size_result = detail::unmap_at_impl(
201 root.origin_phys, Root, virt);
203 return ::std::unexpected(size_result.error());
213 [[nodiscard]]
auto unmap_page_dispatch(
214 u64 asce_val, u64 virt
215 )
noexcept -> ::std::expected<u64, ::lib::kernel_error>;
219 template <dat_level Root>
220 [[nodiscard]]
auto walk(
221 dat_table<Root> root,
223 )
noexcept -> ::std::expected<u64, ::lib::kernel_error> {
224 return detail::walk_impl(root.origin_phys, Root, virt);
229 template <dat_level Root>
230 [[nodiscard]]
auto protect(
231 dat_table<Root> root,
234 )
noexcept -> ::std::expected<
void, ::lib::kernel_error> {
235 return detail::protect_impl(
236 root.origin_phys, Root, virt, new_prot);
240 class mmu_transaction
241 :
public zxfoundation::base::transaction<mmu_transaction> {
242 friend class zxfoundation::base::transaction<mmu_transaction>;
245 dat_level root_level_{dat_level::region_1};
248 u64 range_cursor_{0};
251 mmu_transaction()
noexcept =
default;
255 dat_level root_level,
259 : root_phys_(root_phys)
260 , root_level_(root_level)
261 , asce_val_(asce_val)
262 , range_start_(range_start)
263 , range_cursor_(range_start)
266 mmu_transaction(
const mmu_transaction&) =
delete;
267 auto operator=(
const mmu_transaction&) =
delete;
270 auto advance(u64 bytes)
noexcept ->
void;
273 auto commit_and_flush()
noexcept ->
void;
277 auto on_rollback()
const noexcept ->
void;
285 template <dat_level Root>
286 [[nodiscard]]
auto map_range(
287 dat_table<Root> root,
292 )
noexcept -> ::std::expected<u64, ::lib::kernel_error> {
293 const u64 asce_val = asce_build(root).raw();
294 mmu_transaction txn(root.origin_phys, Root, asce_val, virt);
300 while (remaining > 0) {
304 if (detail::g_has_edat2
305 && remaining >= REGION3_SIZE
306 && (va & (REGION3_SIZE - 1)) == 0
307 && (pa & (REGION3_SIZE - 1)) == 0) {
308 auto r = detail::map_large_2g_impl(
309 root.origin_phys, Root, va, pa, prot);
311 return ::std::unexpected(r.error());
315 else if (detail::g_has_edat1
316 && remaining >= SEGMENT_SIZE
317 && (va & (SEGMENT_SIZE - 1)) == 0
318 && (pa & (SEGMENT_SIZE - 1)) == 0) {
319 auto r = detail::map_large_1m_impl(
320 root.origin_phys, Root, va, pa, prot);
322 return ::std::unexpected(r.error());
327 auto r = detail::map_page_impl(
328 root.origin_phys, Root, va, pa, prot);
330 return ::std::unexpected(r.error());
340 txn.commit_and_flush();
347 template <dat_level Root>
348 [[nodiscard]]
auto unmap_range(
349 dat_table<Root> root,
352 )
noexcept -> ::std::expected<u64, ::lib::kernel_error> {
357 while (remaining > 0) {
358 auto r = detail::unmap_at_impl(
359 root.origin_phys, Root, va);
369 remaining = (remaining >= step) ? remaining - step : 0;
374 const u64 asce_val = asce_build(root).raw();
375 tlb_flush_asce(asce_val);
auto init_table(dat_level lvl, u64 phys) noexcept -> ::std::expected< void, ::lib::kernel_error >
Fill a freshly-allocated table with empty (invalid) entries.
Definition core.cxx:57
auto map_large_2g_impl(u64 root_phys, dat_level root_level, u64 virt, u64 phys, page_prot prot) noexcept -> ::std::expected< void, ::lib::kernel_error >
Map a 2 GiB large page (EDAT-2) via region-3 entry.
Definition core.cxx:498
auto protect_impl(u64 root_phys, dat_level root_level, u64 virt, page_prot new_prot) noexcept -> ::std::expected< void, ::lib::kernel_error >
Change protection bits on an existing mapping.
Definition core.cxx:361
auto unmap_at_impl(u64 root_phys, dat_level root_level, u64 virt) noexcept -> ::std::expected< u64, ::lib::kernel_error >
Unmap whatever exists at virt (4 KiB, 1 MiB, or 2 GiB).
Definition core.cxx:261
auto map_page_impl(u64 root_phys, dat_level root_level, u64 virt, u64 phys, page_prot prot, const pmm::allocation_request &table_policy) noexcept -> ::std::expected< void, ::lib::kernel_error >
Map a single 4 KiB page using the two-phase protocol.
Definition core.cxx:132
auto default_table_request() noexcept -> pmm::allocation_request
Build the default PMM request used for DAT table pages.
Definition core.cxx:31
auto map_large_1m_impl(u64 root_phys, dat_level root_level, u64 virt, u64 phys, page_prot prot) noexcept -> ::std::expected< void, ::lib::kernel_error >
Map a 1 MiB large page (EDAT-1) via segment entry.
Definition core.cxx:414
auto walk_impl(u64 root_phys, dat_level root_level, u64 virt) noexcept -> ::std::expected< u64, ::lib::kernel_error >
Walk the page tables to resolve virt → phys.
Definition core.cxx:324