summaryrefslogtreecommitdiffhomepage
path: root/Kernel/HALKit/AMD64/HalPageAlloc.cpp
blob: 4658a8aac717335b65c750703c8ad29034c6ae51 (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
/* -------------------------------------------

	Copyright SoftwareLabs

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

#include <ArchKit/ArchKit.hpp>
#include <HALKit/AMD64/HalPageAlloc.hpp>
#include <NewKit/Defines.hpp>
#include <NewKit/KernelCheck.hpp>

STATIC NewOS::Boolean kAllocationInProgress = false;

namespace NewOS
{
	namespace HAL
	{
		namespace Detail
		{
			struct VirtualMemoryHeader
			{
				UInt32	Magic;
				Boolean Present;
				Boolean ReadWrite;
				Boolean User;
				SizeT	PageSize;
			};

			struct VirtualMemoryHeaderTraits
			{
				/// @brief Get next header.
				/// @param current
				/// @return
				VirtualMemoryHeader* Next(VirtualMemoryHeader* current)
				{
					return current + sizeof(PTE) + current->PageSize;
				}

				/// @brief Get previous header.
				/// @param current
				/// @return
				VirtualMemoryHeader* Prev(VirtualMemoryHeader* current)
				{
					return current - sizeof(PTE) - current->PageSize;
				}
			};
		} // namespace Detail

		/// @brief Allocates a new page of memory.
		/// @param sz the size of it.
		/// @param rw read/write flag.
		/// @param user user flag.
		/// @return the page table of it.
		STATIC auto hal_try_alloc_new_page(Boolean rw, Boolean user, SizeT size) -> VoidPtr
		{
			if (kAllocationInProgress)
				return nullptr;

			kAllocationInProgress = true;

			constexpr auto cVMTMagic = 0xDEEFD00D;

			///! fetch from the start.
			Detail::VirtualMemoryHeader*	  vmHeader = reinterpret_cast<Detail::VirtualMemoryHeader*>(kKernelVirtualStart);
			Detail::VirtualMemoryHeaderTraits traits;

			while (vmHeader->Present &&
				   vmHeader->Magic != cVMTMagic)
			{
				vmHeader = traits.Next(vmHeader);
			}

			vmHeader->Magic		= cVMTMagic;
			vmHeader->Present	= true;
			vmHeader->ReadWrite = rw;
			vmHeader->User		= user;
			vmHeader->PageSize	= size;

			kAllocationInProgress = false;

			return reinterpret_cast<VoidPtr>(vmHeader);
		}

		/// @brief Allocate a new page to be used by the OS.
		/// @param rw read/write bit.
		/// @param user user bit.
		/// @return
		auto hal_alloc_page(Boolean rw, Boolean user, SizeT size) -> VoidPtr
		{
			/// Wait for a ongoing allocation to complete.
			while (kAllocationInProgress)
			{
				;
			}

			if (size == 0)
				++size;

			/// allocate new page.
			return hal_try_alloc_new_page(rw, user, size);
		}
	} // namespace HAL
} // namespace NewOS