FreeNOS
IntelPageDirectory.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <SplitAllocator.h>
19#include <MemoryBlock.h>
20#include "IntelConstant.h"
21#include "IntelPageDirectory.h"
22
23#define PAGE_NONE 0
24#define PAGE_PRESENT 1
25#define PAGE_READ 0
26#define PAGE_EXEC 0
27#define PAGE_WRITE 2
28#define PAGE_USER 4
29#define PAGE_SECTION (1 << 7)
30
38#define DIRENTRY(vaddr) \
39 ((vaddr) >> DIRSHIFT)
40
42{
43 u32 entry = m_tables[ DIRENTRY(virt) ];
44
45 // Check if the page table is present.
46 if (!(entry & PAGE_PRESENT))
47 return ZERO;
48 else
49 return (IntelPageTable *) alloc->toVirtual(entry & PAGEMASK);
50}
51
53 Address from,
54 Address to)
55{
56 while (from < to)
57 {
58 m_tables[ DIRENTRY(from) ] = directory->m_tables[ DIRENTRY(from) ];
59 from += MegaByte(4);
60 }
62}
63
65 Address phys,
66 Memory::Access access,
67 SplitAllocator *alloc)
68{
69 IntelPageTable *table = getPageTable(virt, alloc);
70 Allocator::Range allocPhys, allocVirt;
71
72 // Check if the page table is present.
73 if (!table)
74 {
75 allocPhys.address = 0;
76 allocPhys.size = sizeof(IntelPageTable);
77 allocPhys.alignment = PAGESIZE;
78
79 // Allocate a new page table
80 if (alloc->allocate(allocPhys, allocVirt) != Allocator::Success)
82
83 MemoryBlock::set((void *)allocVirt.address, 0, sizeof(IntelPageTable));
84
85 // Assign to the page directory
86 m_tables[ DIRENTRY(virt) ] = allocPhys.address | PAGE_PRESENT | PAGE_WRITE | flags(access);
87 table = getPageTable(virt, alloc);
88 }
89 return table->map(virt, phys, access);
90}
91
93{
94 IntelPageTable *table = getPageTable(virt, alloc);
95 if (!table)
97 else
98 return table->unmap(virt);
99}
100
102 Address *phys,
103 SplitAllocator *alloc) const
104{
105 IntelPageTable *table = getPageTable(virt, alloc);
106 if (!table)
107 {
108 if (m_tables[DIRENTRY(virt)] & PAGE_SECTION)
109 {
110 const Address offsetInSection = virt % MegaByte(4);
111
112 *phys = (m_tables[DIRENTRY(virt)] & SECTIONMASK) +
113 ((offsetInSection / PAGESIZE) * PAGESIZE);
115 }
117 }
118 else
119 return table->translate(virt, phys);
120}
121
123 Memory::Access *access,
124 SplitAllocator *alloc) const
125{
126 IntelPageTable *table = getPageTable(virt, alloc);
127 if (!table)
129 else
130 return table->access(virt, access);
131}
132
134{
135 u32 f = 0;
136
138 if (access & Memory::User) f |= PAGE_USER;
139
140 return f;
141}
142
144 const Address phys)
145{
146 // Some pages that are part of the boot core's memory region
147 // are mapped on secondary cores. They can't be released there.
148 const Address allocBase = alloc->base();
149 const Size allocSize = alloc->size();
150 if (phys < allocBase || phys > allocBase + allocSize)
151 {
152 return;
153 }
154
155 // Note that some pages may have double mappings.
156 // Avoid attempting to release the same page twice or more.
157 if (alloc->isAllocated(phys))
158 {
159 alloc->release(phys);
160 }
161}
162
164 SplitAllocator *alloc)
165{
166 Address phys;
167
168 // Walk the full range of memory specified
169 for (Size addr = range.virt; addr < range.virt + range.size; addr += PAGESIZE)
170 {
171 IntelPageTable *table = getPageTable(addr, alloc);
172 if (table == ZERO)
173 {
175 }
176
177 if (table->translate(addr, &phys) != MemoryContext::Success)
178 {
180 }
181
182 releasePhysical(alloc, phys);
183 table->unmap(addr);
184 }
185
187}
188
190 SplitAllocator *alloc,
191 const bool tablesOnly)
192{
193 Address phys;
194
195 // Input must be aligned to section address
196 if (range.virt & ~SECTIONMASK)
197 {
199 }
200
201 // Walk the page directory
202 for (Size addr = range.virt; addr < range.virt + range.size; addr += MegaByte(4))
203 {
204 IntelPageTable *table = getPageTable(addr, alloc);
205 if (!table)
206 {
207 continue;
208 }
209
210 // Release mapped pages, if requested
211 if (!tablesOnly)
212 {
213 for (Size i = 0; i < MegaByte(4); i += PAGESIZE)
214 {
215 if (table->translate(i, &phys) == MemoryContext::Success)
216 {
217 releasePhysical(alloc, phys);
218 }
219 }
220 }
221 // Release page table
222 alloc->release(m_tables[ DIRENTRY(addr) ] & PAGEMASK);
223 m_tables[ DIRENTRY(addr) ] = 0;
224 }
225
227}
#define DIRENTRY(vaddr)
Entry inside the page directory of a given virtual address.
u32 entry[]
Definition IntelACPI.h:1
u32 flags
Definition IntelACPI.h:3
#define PAGE_SECTION
#define PAGE_PRESENT
#define PAGE_USER
#define PAGE_WRITE
Address base() const
Get memory base address for allocations.
Definition Allocator.cpp:69
virtual Size size() const
Get memory size.
Definition Allocator.cpp:64
Intel page directory implementation.
MemoryContext::Result unmap(Address virt, SplitAllocator *alloc)
Remove virtual address mapping.
u32 flags(Memory::Access access) const
Convert Memory::Access to page directory flags.
void releasePhysical(SplitAllocator *alloc, const Address phys)
Release a single physical page.
IntelPageTable * getPageTable(Address virt, SplitAllocator *alloc) const
Retrieve second level page table.
MemoryContext::Result translate(Address virt, Address *phys, SplitAllocator *alloc) const
Translate virtual address to physical address.
MemoryContext::Result map(Address virt, Address phys, Memory::Access access, SplitAllocator *alloc)
Map a virtual address to a physical address.
MemoryContext::Result access(Address virt, Memory::Access *access, SplitAllocator *alloc) const
Get Access flags for a virtual address.
u32 m_tables[1024]
Array of page directory entries.
MemoryContext::Result releaseRange(const Memory::Range range, SplitAllocator *alloc)
Release range of memory.
MemoryContext::Result releaseSection(const Memory::Range range, SplitAllocator *alloc, const bool tablesOnly)
Release memory sections.
MemoryContext::Result copy(IntelPageDirectory *directory, Address from, Address to)
Copy mappings from another directory.
Intel second level page table implementation.
MemoryContext::Result map(Address virt, Address phys, Memory::Access access)
Map a virtual address to a physical address.
MemoryContext::Result access(Address virt, Memory::Access *access) const
Get Access flags for a virtual address.
MemoryContext::Result translate(Address virt, Address *phys) const
Translate virtual address to physical address.
MemoryContext::Result unmap(Address virt)
Remove virtual address mapping.
static void * set(void *dest, int ch, unsigned count)
Fill memory with a constant byte.
Result
Result codes.
Allocator which separates kernel mapped memory at virtual and physical addresses.
virtual Result allocate(Range &args)
Allocate physical memory.
bool isAllocated(const Address page) const
Check if a physical page is allocated.
Address toVirtual(const Address phys) const
Convert Address to virtual pointer.
virtual Result release(const Address addr)
Release memory page.
#define PAGESIZE
ARM uses 4K pages.
Definition ARMConstant.h:97
#define PAGEMASK
Mask to find the page.
#define SECTIONMASK
Mask for large 1MiB section mappings.
unsigned int u32
Unsigned 32-bit number.
Definition Types.h:53
unsigned long Address
A memory address.
Definition Types.h:131
#define MegaByte(v)
Convert megabytes to bytes.
Definition Macros.h:57
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define ZERO
Zero value.
Definition Macros.h:43
Access
Memory access flags.
Definition Memory.h:39
@ User
Definition Memory.h:44
@ Writable
Definition Memory.h:42
Describes a range of memory.
Definition Allocator.h:66
Size alignment
Alignment in bytes or ZERO for default alignment.
Definition Allocator.h:69
Address address
Starting address of the memory range.
Definition Allocator.h:67
Size size
Amount of memory in bytes.
Definition Allocator.h:68
Memory range.
Definition Memory.h:56
Size size
Size in number of bytes.
Definition Memory.h:59
Address virt
Virtual address.
Definition Memory.h:57