summaryrefslogtreecommitdiffhomepage
path: root/dev/kernel/HALKit/AMD64/HalPagingMgrAMD64.cc
blob: 884d7c9e30b7998159e47768880c6e7bf4bb783a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/* -------------------------------------------

	Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.

	File: HalPagingMgr.cc
	Purpose: Platform Paging Manager.

------------------------------------------- */

#include <HALKit/AMD64/Paging.h>
#include <HALKit/AMD64/Processor.h>

namespace Kernel::HAL
{
	typedef UInt32 PageTableIndex;

	/***********************************************************************************/
	/// \brief Page store type.
	/***********************************************************************************/
	struct NE_PAGE_STORE final
	{
		struct
		{
			PDE*	fPde{nullptr};
			PTE*	fPte{nullptr};
			VoidPtr fPAddr{nullptr};
		} fInternalStore;

		Bool fStoreOp{No}; // Store operation is in progress.

		bool IsValidPage(PTE* pte)
		{
			return pte && pte->Present;
		}

		bool IsWRPage(PTE* pte)
		{
			return pte && pte->Wr;
		}

		bool IsUserPage(PTE* pte)
		{
			return pte && pte->User;
		}

		static NE_PAGE_STORE& The()
		{
			static NE_PAGE_STORE the;
			return the;
		}
	};

	/// @brief Go over the Page structure and find the address of *virtual_address*

	UIntPtr hal_get_phys_address(VoidPtr virtual_address)
	{
		// Constants for table index bits
		const UInt64 kPmlIndexMask = 0x1FFULL; // Mask for PML4, PDPT, PD, PT index (9 bits)
		const UInt64 kPtIndexMask  = 0xFFFULL; // Mask for page table index (12 bits)

		UInt64 cr3 = (UInt64)hal_read_cr3();

		NE_PAGE_STORE& page_store = NE_PAGE_STORE::The();

		// Extract the indices from the virtual address
		UInt64 pml4_index = ((UIntPtr)virtual_address >> 39) & kPmlIndexMask;
		UInt64 pdpt_index = ((UIntPtr)virtual_address >> 30) & kPmlIndexMask;
		UInt64 pd_index	  = ((UIntPtr)virtual_address >> 21) & kPmlIndexMask;
		UInt64 pt_index	  = ((UIntPtr)virtual_address >> 12) & kPmlIndexMask;

		page_store.fStoreOp = Yes;

		const auto kPmlEntrySize = 8;

		// Read the PML4 entry from memory
		UInt64 pml4_base  = cr3 & ~kPtIndexMask;					  // CR3 points to the PML4 table base, mask off lower bits
		UInt64 pml4_entry = (pml4_base + pml4_index * kPmlEntrySize); // Each entry is 8 bytes

		// Read the PDPT entry
		UInt64 pdpt_base  = pml4_entry & ~kPtIndexMask; // Get the PDPT base physical address
		UInt64 pdpt_entry = (pdpt_base + pdpt_index * kPmlEntrySize);

		// Read the PD entry
		UInt64 pd_base	= pdpt_entry & ~kPtIndexMask; // Get the Page Directory base physical address
		UInt64 pd_entry = (pd_base + pd_index * kPmlEntrySize);

		// Read the PT entry
		UInt64 pt_base	= pd_entry & ~kPtIndexMask; // Get the Page Table base physical address
		UInt64 pt_entry = (pt_base + pt_index * kPmlEntrySize);

		// Lastly, grab the pte entry.
		NE_PDE* pde_struct = reinterpret_cast<NE_PDE*>(pt_base);

		return pde_struct->fEntries[pt_entry]->PhysicalAddress;
	}

	/***********************************************************************************/
	/// \brief Retrieve the page status of a PTE.
	/// \param pte Page Table Entry pointer.
	/***********************************************************************************/
	STATIC Void mmi_page_status(PTE* pte)
	{
		kout << (pte->Present ? "Present" : "Not Present") << kendl;
		kout << (pte->Wr ? "W/R" : "Not W/R") << kendl;
		kout << (pte->ExecDisable ? "NX" : "Not NX") << kendl;
		kout << (pte->User ? "User" : "Not User") << kendl;
	}

	STATIC Int32 mmi_map_page_table_entry(UInt32 physical_address, UInt32 flags, NE_PTE* pt_entry, NE_PDE* pd_entry);

	/***********************************************************************************/
	/// @brief Maps or allocates a page from virtual_address.
	/// @param virtual_address a valid virtual address.
	/// @param phys_addr point to physical address.
	/// @param flags the flags to put on the page.
	/// @return Status code of page manipulation process.
	/***********************************************************************************/
	EXTERN_C Int32 mm_map_page(VoidPtr virtual_address, VoidPtr physical_address, UInt32 flags)
	{
		// Constants for table index bits
		const UInt64 kPmlIndexMask = 0x1FFULL; // Mask for PML4, PDPT, PD, PT index (9 bits)
		const UInt64 kPtIndexMask  = 0xFFFULL; // Mask for page table index (12 bits)

		UInt64 cr3 = (UInt64)hal_read_cr3();

		NE_PAGE_STORE& page_store = NE_PAGE_STORE::The();

		// Extract the indices from the virtual address
		UInt64 pml4_index = ((UIntPtr)virtual_address >> 39) & kPmlIndexMask;
		UInt64 pdpt_index = ((UIntPtr)virtual_address >> 30) & kPmlIndexMask;
		UInt64 pd_index	  = ((UIntPtr)virtual_address >> 21) & kPmlIndexMask;
		UInt64 pt_index	  = ((UIntPtr)virtual_address >> 12) & kPmlIndexMask;

		page_store.fStoreOp = Yes;

		const auto kPmlEntrySize = 8;

		// Read the PML4 entry from memory
		UInt64 pml4_base  = cr3 & ~kPtIndexMask;					  // CR3 points to the PML4 table base, mask off lower bits
		UInt64 pml4_entry = (pml4_base + pml4_index * kPmlEntrySize); // Each entry is 8 bytes

		// Read the PDPT entry
		UInt64 pdpt_base  = pml4_entry & ~kPtIndexMask; // Get the PDPT base physical address
		UInt64 pdpt_entry = (pdpt_base + pdpt_index * kPmlEntrySize);

		// Read the PD entry
		UInt64 pd_base	= pdpt_entry & ~kPtIndexMask; // Get the Page Directory base physical address
		UInt64 pd_entry = (pd_base + pd_index * kPmlEntrySize);

		// Read the PT entry
		UInt64 pt_base	= pd_entry & ~kPtIndexMask; // Get the Page Table base physical address
		UInt64 pt_entry = (pt_base + pt_index * kPmlEntrySize);

		// Lastly, grab the pte entry.
		NE_PDE* pde_struct = reinterpret_cast<NE_PDE*>(pt_base);

		return mmi_map_page_table_entry((UInt32)(UInt64)physical_address, flags, pde_struct->fEntries[pt_entry], pde_struct);
	}

	/***********************************************************************************/
	/// @brief Maps flags for a specific pte.
	/// @internal Internal function.
	/***********************************************************************************/
	STATIC Int32 mmi_map_page_table_entry(UInt32 physical_address, UInt32 flags, NE_PTE* pt_entry, NE_PDE* pd_entry)
	{
		if (!pt_entry)
			return 1;

		pt_entry->Present = true;

		if (flags & kMMFlagsWr)
			pt_entry->Wr = true;
		else if (flags & ~kMMFlagsWr)
			pt_entry->Wr = false;

		if (flags & kMMFlagsNX)
			pt_entry->ExecDisable = true;
		else if (flags & ~kMMFlagsNX)
			pt_entry->ExecDisable = false;

		if (flags & kMMFlagsUser)
			pt_entry->User = true;
		else if (flags & ~kMMFlagsUser)
			pt_entry->User = false;

		pt_entry->PhysicalAddress = physical_address;

		hal_invl_tlb(reinterpret_cast<VoidPtr>(pt_entry));

		mmi_page_status(pt_entry);

		NE_PAGE_STORE& page_store = NE_PAGE_STORE::The();

		// Update Internal store.

		page_store.fInternalStore.fPde	 = pd_entry;
		page_store.fInternalStore.fPte	 = pt_entry;
		page_store.fInternalStore.fPAddr = (VoidPtr)(UIntPtr)physical_address;

		page_store.fStoreOp = No;

		return 0;
	}
} // namespace Kernel::HAL