1/*
2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef KERNEL_ARCH_X86_PAGING_PAE_X86_PAGING_METHOD_PAE_H
6#define KERNEL_ARCH_X86_PAGING_PAE_X86_PAGING_METHOD_PAE_H
7
8
9#include <KernelExport.h>
10
11#include <lock.h>
12#include <vm/vm_types.h>
13
14#include "paging/pae/paging.h"
15#include "paging/X86PagingMethod.h"
16#include "paging/X86PagingStructures.h"
17
18
19#if B_HAIKU_PHYSICAL_BITS == 64
20
21
22class TranslationMapPhysicalPageMapper;
23class X86PhysicalPageMapper;
24
25
26class X86PagingMethodPAE : public X86PagingMethod {
27public:
28								X86PagingMethodPAE();
29	virtual						~X86PagingMethodPAE();
30
31	virtual	status_t			Init(kernel_args* args,
32									VMPhysicalPageMapper** _physicalPageMapper);
33	virtual	status_t			InitPostArea(kernel_args* args);
34
35	virtual	status_t			CreateTranslationMap(bool kernel,
36									VMTranslationMap** _map);
37
38	virtual	status_t			MapEarly(kernel_args* args,
39									addr_t virtualAddress,
40									phys_addr_t physicalAddress,
41									uint8 attributes,
42									page_num_t (*get_free_page)(kernel_args*));
43
44	virtual	bool				IsKernelPageAccessible(addr_t virtualAddress,
45									uint32 protection);
46
47			void*				Allocate32BitPage(
48									phys_addr_t& _physicalAddress,
49									void*& _handle);
50			void				Free32BitPage(void* address,
51									phys_addr_t physicalAddress, void* handle);
52
53	inline	X86PhysicalPageMapper* PhysicalPageMapper() const
54									{ return fPhysicalPageMapper; }
55	inline	TranslationMapPhysicalPageMapper* KernelPhysicalPageMapper() const
56									{ return fKernelPhysicalPageMapper; }
57
58	inline	pae_page_directory_pointer_table_entry*
59									KernelVirtualPageDirPointerTable() const;
60	inline	phys_addr_t			KernelPhysicalPageDirPointerTable() const;
61	inline	pae_page_directory_entry* const* KernelVirtualPageDirs() const
62									{ return fKernelVirtualPageDirs; }
63	inline	const phys_addr_t*	KernelPhysicalPageDirs() const
64									{ return fKernelPhysicalPageDirs; }
65
66	static	X86PagingMethodPAE*	Method();
67
68	static	void				PutPageTableInPageDir(
69									pae_page_directory_entry* entry,
70									phys_addr_t physicalTable,
71									uint32 attributes);
72	static	void				PutPageTableEntryInTable(
73									pae_page_table_entry* entry,
74									phys_addr_t physicalAddress,
75									uint32 attributes, uint32 memoryType,
76									bool globalPage);
77	static	uint64_t			SetTableEntry(uint64_t* entry,
78									uint64_t newEntry);
79	static	uint64_t			SetTableEntryFlags(uint64_t* entry,
80									uint64_t flags);
81	static	uint64_t			TestAndSetTableEntry(uint64_t* entry,
82									uint64_t newEntry, uint64_t oldEntry);
83	static	uint64_t			ClearTableEntry(uint64_t* entry);
84	static	uint64_t			ClearTableEntryFlags(uint64_t* entry,
85									uint64_t flags);
86
87	static	pae_page_directory_entry* PageDirEntryForAddress(
88									pae_page_directory_entry* const* pdpt,
89									addr_t address);
90
91	static	uint64				MemoryTypeToPageTableEntryFlags(
92									uint32 memoryType);
93
94private:
95			struct ToPAESwitcher;
96			struct PhysicalPageSlotPool;
97			friend struct PhysicalPageSlotPool;
98
99private:
100	inline	int32				_GetInitialPoolCount();
101
102			bool				_EarlyQuery(addr_t virtualAddress,
103									phys_addr_t* _physicalAddress);
104			pae_page_table_entry* _EarlyGetPageTable(phys_addr_t address);
105
106private:
107			X86PhysicalPageMapper* fPhysicalPageMapper;
108			TranslationMapPhysicalPageMapper* fKernelPhysicalPageMapper;
109
110			void*				fEarlyPageStructures;
111			size_t				fEarlyPageStructuresSize;
112			pae_page_directory_pointer_table_entry*
113									fKernelVirtualPageDirPointerTable;
114			phys_addr_t			fKernelPhysicalPageDirPointerTable;
115			pae_page_directory_entry* fKernelVirtualPageDirs[4];
116			phys_addr_t			fKernelPhysicalPageDirs[4];
117			addr_t				fFreeVirtualSlot;
118			pae_page_table_entry* fFreeVirtualSlotPTE;
119
120			mutex				fFreePagesLock;
121			vm_page*			fFreePages;
122			page_num_t			fFreePagesCount;
123};
124
125
126pae_page_directory_pointer_table_entry*
127X86PagingMethodPAE::KernelVirtualPageDirPointerTable() const
128{
129	return fKernelVirtualPageDirPointerTable;
130}
131
132
133phys_addr_t
134X86PagingMethodPAE::KernelPhysicalPageDirPointerTable() const
135{
136	return fKernelPhysicalPageDirPointerTable;
137}
138
139
140/*static*/ inline X86PagingMethodPAE*
141X86PagingMethodPAE::Method()
142{
143	return static_cast<X86PagingMethodPAE*>(gX86PagingMethod);
144}
145
146
147/*static*/ inline pae_page_directory_entry*
148X86PagingMethodPAE::PageDirEntryForAddress(
149	pae_page_directory_entry* const* pdpt, addr_t address)
150{
151	return pdpt[address >> 30]
152		+ (address / kPAEPageTableRange) % kPAEPageDirEntryCount;
153}
154
155
156/*static*/ inline uint64_t
157X86PagingMethodPAE::SetTableEntry(uint64_t* entry, uint64_t newEntry)
158{
159	return atomic_get_and_set64((int64*)entry, newEntry);
160}
161
162
163/*static*/ inline uint64_t
164X86PagingMethodPAE::SetTableEntryFlags(uint64_t* entry, uint64_t flags)
165{
166	return atomic_or64((int64*)entry, flags);
167}
168
169
170/*static*/ inline uint64_t
171X86PagingMethodPAE::TestAndSetTableEntry(uint64_t* entry,
172	uint64_t newEntry, uint64_t oldEntry)
173{
174	return atomic_test_and_set64((int64*)entry, newEntry, oldEntry);
175}
176
177
178/*static*/ inline uint64_t
179X86PagingMethodPAE::ClearTableEntry(uint64_t* entry)
180{
181	return SetTableEntry(entry, 0);
182}
183
184
185/*static*/ inline uint64_t
186X86PagingMethodPAE::ClearTableEntryFlags(uint64_t* entry, uint64_t flags)
187{
188	return atomic_and64((int64*)entry, ~flags);
189}
190
191
192/*static*/ inline uint64
193X86PagingMethodPAE::MemoryTypeToPageTableEntryFlags(uint32 memoryType)
194{
195	// ATM we only handle the uncacheable and write-through type explicitly. For
196	// all other types we rely on the MTRRs to be set up correctly. Since we set
197	// the default memory type to write-back and since the uncacheable type in
198	// the PTE overrides any MTRR attribute (though, as per the specs, that is
199	// not recommended for performance reasons), this reduces the work we
200	// actually *have* to do with the MTRRs to setting the remaining types
201	// (usually only write-combining for the frame buffer).
202	switch (memoryType) {
203		case B_MTR_UC:
204			return X86_PAE_PTE_CACHING_DISABLED | X86_PAE_PTE_WRITE_THROUGH;
205
206		case B_MTR_WC:
207			// X86_PTE_WRITE_THROUGH would be closer, but the combination with
208			// MTRR WC is "implementation defined" for Pentium Pro/II.
209			return 0;
210
211		case B_MTR_WT:
212			return X86_PAE_PTE_WRITE_THROUGH;
213
214		case B_MTR_WP:
215		case B_MTR_WB:
216		default:
217			return 0;
218	}
219}
220
221
222#endif	// B_HAIKU_PHYSICAL_BITS == 64
223
224
225#endif	// KERNEL_ARCH_X86_PAGING_PAE_X86_PAGING_METHOD_PAE_H
226