The Pedigree Project  0.1
VirtualAddressSpace.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
23 #include "pedigree/kernel/utilities/utility.h"
24 
25 physical_uintptr_t VirtualAddressSpace::m_ZeroPage = 0;
26 
27 void *VirtualAddressSpace::expandHeap(ssize_t incr, size_t flags)
28 {
30  if (!m_ZeroPage)
31  {
32  m_ZeroPage = PMemoryManager.allocatePage();
34  {
35  ERROR("Could not prepare zero page.");
36  return 0;
37  }
38 
40 
42 
43  PMemoryManager.pin(m_ZeroPage);
44  }
45 
46  void *Heap = m_HeapEnd;
47  void *newHeapEnd = adjust_pointer(m_HeapEnd, incr);
48 
49  m_HeapEnd = reinterpret_cast<void *>(
50  reinterpret_cast<uintptr_t>(m_HeapEnd) &
52 
53  uintptr_t newEnd = reinterpret_cast<uintptr_t>(newHeapEnd);
54 
55  // Are we already at the end of the heap region?
56  if (newEnd >= getKernelHeapStart())
57  {
58  // Kernel check - except SLAM doesn't use expandHeap.
59  FATAL("expandHeap called for kernel heap!");
60  return 0;
61  }
62  else if (getDynamicStart())
63  {
64  if (newEnd >= getDynamicStart())
65  {
66  // Heap is about to run over into the dynamic memory mapping region.
67  // This is not allowed.
68  ERROR("Heap expansion no longer allowed; about to run into dynamic "
69  "memory area.");
70  return 0;
71  }
72  }
73  else if (newEnd >= getKernelStart())
74  {
75  // Nasty way of checking because by this point we'll have overrun the
76  // stack, but the best we can do.
77  ERROR("Heap expansion no longer allowed; have run over userspace "
78  "stacks and about to run into kernel area.");
79  return 0;
80  }
81 
82  int i = 0;
83  if (incr < 0)
84  {
85  while (reinterpret_cast<uintptr_t>(newHeapEnd) <
86  reinterpret_cast<uintptr_t>(m_HeapEnd))
87  {
89  void *unmapAddr = m_HeapEnd;
90  if (isMapped(unmapAddr))
91  {
92  // Unmap the virtual address
93  physical_uintptr_t phys = 0;
94  size_t mappingFlags = 0;
95  getMapping(unmapAddr, phys, mappingFlags);
96  unmap(unmapAddr);
97 
98  // Free the physical page
99  PMemoryManager.freePage(phys);
100  }
101 
102  // Drop back a page
103  m_HeapEnd = adjust_pointer(
105  i++;
106  }
107 
108  // Now that we've freed this section, the heap is actually at the end of
109  // the original memory...
110  Heap = m_HeapEnd;
111  }
112  else
113  {
114  while (reinterpret_cast<uintptr_t>(newHeapEnd) >
115  reinterpret_cast<uintptr_t>(m_HeapEnd))
116  {
117  // Map the zero page CoW - writes will trigger a page allocation.
118  // This is far more efficient than allocating every page
119  // immediately.
120  if (map(m_ZeroPage, m_HeapEnd,
121  (flags & ~VirtualAddressSpace::Write) |
123  {
124  // Map failed - probable double mapping. Go to the next page.
125  WARNING(
126  "VirtualAddressSpace::expandHeap() failed for "
127  << m_HeapEnd);
128  }
129  else
130  {
131  // One more reference to the zero page (the CoW operation, if it
132  // happens, will reduce the refcount - we need to make sure the
133  // page stays!).
134  PMemoryManager.pin(m_ZeroPage);
135  }
136 
137  // Go to the next address
138  m_HeapEnd =
140  i++;
141  }
142  }
143 
144  m_HeapEnd = newHeapEnd;
145  return Heap;
146 }
147 
149  void *virtualAddress, size_t pageCount)
150 {
151  for (size_t i = 0; i < pageCount; i++)
152  {
153  // Get the mapping for the current page
154  size_t flags;
155  physical_uintptr_t physicalAddress;
156  getMapping(virtualAddress, physicalAddress, flags);
157 
158  // Free the physical page
159  PhysicalMemoryManager::instance().freePage(physicalAddress);
160 
161  // Unmap the page from the virtual address space
162  unmap(virtualAddress);
163 
164  // Go to the next virtual page
165  virtualAddress = adjust_pointer(
166  virtualAddress, PhysicalMemoryManager::getPageSize());
167  }
168 }
169 
171  physical_uintptr_t physAddress, void *virtualAddress, size_t count,
172  size_t flags)
173 {
174  for (size_t i = 0; i < count; ++i)
175  {
176  size_t addend = PhysicalMemoryManager::getPageSize() * i;
177  if (!map(
178  physAddress + addend, adjust_pointer(virtualAddress, addend),
179  flags))
180  {
181  return false;
182  }
183  }
184 
185  return true;
186 }
virtual void unmap(void *virtualAddress)=0
static PhysicalMemoryManager & instance()
virtual void pin(physical_uintptr_t page)=0
virtual void getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
virtual bool isMapped(void *virtualAddress)=0
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
virtual uintptr_t getKernelStart() const =0
#define WARNING(text)
Definition: Log.h:78
uintptr_t physicalAddress(physical_uintptr_t address) PURE
Definition: utils.h:38
void rollbackHeapExpansion(void *virtualAddress, size_t pageCount)
virtual uintptr_t getKernelHeapStart() const =0
#define ERROR(text)
Definition: Log.h:82
virtual void * expandHeap(ssize_t incr, size_t flags)
virtual void freePage(physical_uintptr_t page)=0
virtual bool mapHuge(physical_uintptr_t physAddress, void *virtualAddress, size_t count, size_t flags)
#define FATAL(text)
Definition: Log.h:89