UbixOS  2.0
copyvirtualspace.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2002-2018 The UbixOS Project.
3  * All rights reserved.
4  *
5  * This was developed by Christopher W. Olsen for the UbixOS Project.
6  *
7  * Redistribution and use in source and binary forms, with or without modification, are permitted
8  * provided that the following conditions are met:
9  *
10  * 1) Redistributions of source code must retain the above copyright notice, this list of
11  * conditions, the following disclaimer and the list of authors.
12  * 2) Redistributions in binary form must reproduce the above copyright notice, this list of
13  * conditions, the following disclaimer and the list of authors in the documentation and/or
14  * other materials provided with the distribution.
15  * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
16  * endorse or promote products derived from this software without specific prior written
17  * permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <vmm/vmm.h>
30 #include <vmm/paging.h>
31 #include <sys/kern_sysctl.h>
32 #include <ubixos/spinlock.h>
33 #include <ubixos/kpanic.h>
34 #include <string.h>
35 
36 static struct spinLock cvsSpinLock = SPIN_LOCK_INITIALIZER;
37 
38 /************************************************************************
39 
40  Function: void *vmm_copyVirtualSpace(pidType pid);
41 
42  Description: Creates A Copy Of A Virtual Space And Set All NON Kernel
43  Space To COW For A Fork This Will Also Alter The Parents
44  VM Space To Make That COW As Well
45 
46  Notes:
47 
48  08/02/02 - Added Passing Of pidType pid So We Can Better Keep Track Of
49  Which Task Has Which Physical Pages
50 
51  ************************************************************************/
52 void *vmm_copyVirtualSpace(pidType pid) {
53  void *newPageDirectoryAddress = 0x0;
54 
55  uint32_t *parentPageDirectory = 0x0, *newPageDirectory = 0x0;
56  uint32_t *parentPageTable = 0x0, *newPageTable = 0x0;
57  uint32_t *parentStackPage = 0x0, *newStackPage = 0x0;
58  uint16_t x = 0, i = 0, s = 0;
59 
60  spinLock(&cvsSpinLock);
61 
62  /* Set Address Of Parent Page Directory */
63  parentPageDirectory = (uint32_t *) PD_BASE_ADDR;
64 
65  /* Allocate A New Page For The New Page Directory */
66  if ((newPageDirectory = (uint32_t *) vmm_getFreeKernelPage(pid, 1)) == 0x0)
67  kpanic("Error: newPageDirectory == NULL, File: %s, Line: %i\n", __FILE__, __LINE__);
68 
69  /* Set newPageDirectoryAddress To The Newly Created Page Directories Page */
70  newPageDirectoryAddress = (void *) vmm_getPhysicalAddr((uint32_t) newPageDirectory);
71 
72  /* First Set Up A Flushed Page Directory */
73  bzero(newPageDirectory, PAGE_SIZE);
74 
75  /* Map Kernel Code Region Entries 0 & 1 */
76  newPageDirectory[0] = parentPageDirectory[0];
77  //XXX: We Dont Need This - newPageDirectory[1] = parentPageDirectory[1];
78 
79  if ((newPageTable = (uint32_t *) vmm_getFreeKernelPage(pid, 1)) == 0x0)
80  kpanic("Error: newPageTable == NULL, File: %s, Line: %i\n", __FILE__, __LINE__);
81 
82  parentPageTable = (uint32_t *) (PT_BASE_ADDR + (PAGE_SIZE * 1));
83 
84  for (x = 0; x < PT_ENTRIES; x++) {
85  if (((parentPageTable[x]) & PAGE_PRESENT) == PAGE_PRESENT) {
86 
87  /* Set Page To COW In Parent And Child Space */
88  newPageTable[x] = (((uint32_t) parentPageTable[x] & 0xFFFFF000) | (KERNEL_PAGE_DEFAULT | PAGE_COW));
89 
90  /* Increment The COW Counter For This Page */
91  if (((uint32_t) parentPageTable[x] & PAGE_COW) == PAGE_COW) {
92  adjustCowCounter(((uint32_t) parentPageTable[x] & 0xFFFFF000), 1);
93  }
94  else {
95  /* Add Two If This Is The First Time Setting To COW */
96  adjustCowCounter(((uint32_t) parentPageTable[x] & 0xFFFFF000), 2);
97  parentPageTable[x] |= PAGE_COW; // newPageTable[i];
98  }
99 
100  }
101  else
102  newPageTable[x] = parentPageTable[x];
103  }
104 
105  newPageDirectory[1] = (vmm_getPhysicalAddr((uint32_t) newPageTable) | KERNEL_PAGE_DEFAULT);
106 
107  vmm_unmapPage((uint32_t) newPageTable, 1);
108 
109  newPageTable = 0x0;
110 
111  /* Map The Kernel Memory Region Entry 770 Address 0xC0800000 */
112  for (x = PD_INDEX(VMM_KERN_START); x <= PD_INDEX(VMM_KERN_END); x++)
113  newPageDirectory[x] = parentPageDirectory[x];
114 
115  /* Map The Kernel Stack Region */
117  if ((parentPageDirectory[x] & PAGE_PRESENT) == PAGE_PRESENT) {
118  /* Set Parent To Propper Page Table */
119  parentPageTable = (uint32_t *) (PT_BASE_ADDR + (PAGE_SIZE * x));
120 
121  /* Allocate A New Page Table */
122  if ((newPageTable = (uint32_t *) vmm_getFreeKernelPage(pid, 1)) == 0x0)
123  kpanic("Error: newPageTable == NULL, File: %s, Line: %i\n", __FILE__, __LINE__);
124 
125  bzero(newPageTable, PAGE_SIZE);
126 
127  for (i = 0; i < PT_ENTRIES; i++) {
128  if ((parentPageTable[i] & PAGE_PRESENT) == PAGE_PRESENT) {
129 
130  /* Alloc A New Page For This Stack Page */
131  if ((newStackPage = (uint32_t *) vmm_getFreeKernelPage(pid, 1)) == 0x0)
132  kpanic("Error: newStackPage == NULL, File: %s, Line: %i\n", __FILE__, __LINE__);
133 
134  /* Set Pointer To Parents Stack Page */
135  parentStackPage = (uint32_t *) (((PAGE_SIZE * PD_ENTRIES) * x) + (PAGE_SIZE * i));
136 
137  /* Copy The Stack Byte For Byte (I Should Find A Faster Way) */
138  memcpy(newStackPage, parentStackPage, PAGE_SIZE);
139 
140  /* Insert New Stack Into Page Table */
141  newPageTable[i] = (vmm_getPhysicalAddr((uint32_t) newStackPage) | PAGE_DEFAULT | PAGE_STACK);
142 
143  /* Unmap From Kernel Space */
144  vmm_unmapPage((uint32_t) newStackPage, 1);
145  }
146  }
147  /* Put New Page Table Into New Page Directory */
148  newPageDirectory[x] = (vmm_getPhysicalAddr((uint32_t) newPageTable) | PAGE_DEFAULT);
149  /* Unmap Page From Kernel Space But Keep It Marked As Not Avail */
150  vmm_unmapPage((uint32_t) newPageTable, 1);
151  }
152  }
153 
154  /*
155  * Now For The Fun Stuff For Page Tables 2-767 We Must Map These And Set
156  * The Permissions On Every Mapped Pages To COW This Will Conserve Memory
157  * Because The Two VM Spaces Will Be Sharing Pages Unless an EXECVE Happens
158  *
159  * We start at the 4MB boundary as the first 4MB is special
160  */
161 
162  for (x = PD_INDEX(VMM_USER_START); x <= PD_INDEX(VMM_USER_END); x++) {
163 
164  /* If Page Table Exists Map It */
165  if ((parentPageDirectory[x] & PAGE_PRESENT) == PAGE_PRESENT) {
166 
167  /* Set Parent To Propper Page Table */
168  parentPageTable = (uint32_t *) (PT_BASE_ADDR + (PAGE_SIZE * x));
169 
170  /* Allocate A New Page Table */
171  if ((newPageTable = (uint32_t *) vmm_getFreeKernelPage(pid, 1)) == 0x0)
172  kpanic("Error: newPageTable == NULL, File: %s, Line: %i\n", __FILE__, __LINE__);
173 
174  bzero(newPageTable, PAGE_SIZE);
175 
176  /* Set Parent And New Pages To COW */
177  for (i = 0; i < PD_ENTRIES; i++) {
178 
179  /* If Page Is Mapped */
180  if ((parentPageTable[i] & PAGE_PRESENT) == PAGE_PRESENT) {
181 
182  /* Check To See If Its A Stack Page */
183  if (((uint32_t) parentPageTable[i] & PAGE_STACK) == PAGE_STACK) {
184 
185  /* Alloc A New Page For This Stack Page */
186  if ((newStackPage = (uint32_t *) vmm_getFreeKernelPage(pid, 1)) == 0x0)
187  kpanic("Error: newStackPage == NULL, File: %s, Line: %i\n", __FILE__, __LINE__);
188 
189  /* Set Pointer To Parents Stack Page */
190  parentStackPage = (uint32_t *) (((PAGE_SIZE * PD_ENTRIES) * x) + (PAGE_SIZE * i));
191 
192  /* Copy The Stack Byte For Byte (I Should Find A Faster Way) */
193  memcpy(newStackPage, parentStackPage, PAGE_SIZE);
194 
195  /* Insert New Stack Into Page Table */
196  newPageTable[i] = (vmm_getPhysicalAddr((uint32_t) newStackPage) | PAGE_DEFAULT | PAGE_STACK);
197 
198  /* Unmap From Kernel Space */
199  vmm_unmapPage((uint32_t) newStackPage, 1);
200 
201  }
202  else {
203 
204  /* Set Page To COW In Parent And Child Space */
205  newPageTable[i] = (((uint32_t) parentPageTable[i] & 0xFFFFF000) | (PAGE_DEFAULT | PAGE_COW));
206 
207  /* Increment The COW Counter For This Page */
208  if (((uint32_t) parentPageTable[i] & PAGE_COW) == PAGE_COW) {
209  adjustCowCounter(((uint32_t) parentPageTable[i] & 0xFFFFF000), 1);
210  }
211  else {
212  /* Add Two If This Is The First Time Setting To COW */
213  adjustCowCounter(((uint32_t) parentPageTable[i] & 0xFFFFF000), 2);
214  parentPageTable[i] |= PAGE_COW; // newPageTable[i];
215  }
216  }
217  }
218  else {
219  newPageTable[i] = (uint32_t) 0x0;
220  }
221  }
222 
223  /* Put New Page Table Into New Page Directory */
224  newPageDirectory[x] = (vmm_getPhysicalAddr((uint32_t) newPageTable) | PAGE_DEFAULT);
225  /* Unmap Page From Kernel Space But Keep It Marked As Not Avail */
226  vmm_unmapPage((uint32_t) newPageTable, 1);
227  }
228  }
229 
230  /*
231  * Allocate A New Page For The The First Page Table Where We Will Map The
232  * Lower Region First 4MB
233  */
234 
235  /*
236  *
237  * Map Page Directory Into VM Space
238  * First Page After Page Tables
239  * This must be mapped into the page directory before we map all 1024 page directories into the memory space
240  */
241  newPageTable = (uint32_t *) vmm_getFreePage(pid);
242 
243  newPageDirectory[PD_INDEX(PD_BASE_ADDR)] = (uint32_t) (vmm_getPhysicalAddr((uint32_t) newPageTable) | PAGE_DEFAULT);
244 
245  newPageTable[0] = (uint32_t) ((uint32_t) (newPageDirectoryAddress) | PAGE_DEFAULT);
246 
247  vmm_unmapPage((uint32_t) newPageTable, 1);
248 
249  /*
250  *
251  * Map Page Tables Into VM Space
252  * The First Page Table (4MB) Maps To All Page Directories
253  *
254  */
255 
256  newPageTable = (uint32_t *) vmm_getFreePage(pid);
257 
258  newPageDirectory[PD_INDEX(PT_BASE_ADDR)] = (uint32_t) (vmm_getPhysicalAddr((uint32_t) newPageTable) | PAGE_DEFAULT);
259 
260  /* Flush The Page From Garbage In Memory */
261  bzero(newPageTable, PAGE_SIZE);
262 
263  for (x = 0; x < PD_ENTRIES; x++)
264  newPageTable[x] = newPageDirectory[x];
265 
266  /* Unmap Page From Virtual Space */
267  vmm_unmapPage((uint32_t) newPageTable, 1);
268 
269  /* Now We Are Done With The Page Directory So Lets Unmap That Too */
270  vmm_unmapPage((uint32_t) newPageDirectory, 1);
271 
272  spinUnlock(&cvsSpinLock);
273 
274  /* Return Physical Address Of Page Directory */
275  return (newPageDirectoryAddress);
276 }
kern_sysctl.h
spinlock.h
PAGE_COW
#define PAGE_COW
Definition: paging.h:64
string.h
spinUnlock
void spinUnlock(spinLock_t *lock)
Definition: spinlock.c:36
vmm.h
vmm_getPhysicalAddr
uint32_t vmm_getPhysicalAddr(uint32_t)
Definition: getphysicaladdr.c:38
adjustCowCounter
int adjustCowCounter(uint32_t baseAddr, int adjustment)
SPIN_LOCK_INITIALIZER
#define SPIN_LOCK_INITIALIZER
Definition: spinlock.h:36
kpanic
void kpanic(const char *fmt,...)
print panic message and halt system
Definition: kpanic.c:41
bzero
#define bzero(buf, size)
Definition: gpt.h:37
VMM_KERN_START
#define VMM_KERN_START
Definition: vmm.h:64
memcpy
void * memcpy(const void *dst, const void *src, size_t length)
vmm_unmapPage
void vmm_unmapPage(uint32_t, unmapFlags_t)
Definition: unmappage.c:47
spinLock
void spinLock(spinLock_t *lock)
Definition: spinlock.c:55
uint16_t
__uint16_t uint16_t
Definition: types.h:45
kpanic.h
PT_ENTRIES
#define PT_ENTRIES
Definition: paging.h:49
PAGE_STACK
#define PAGE_STACK
Definition: paging.h:65
PD_INDEX
#define PD_INDEX(v_addr)
Definition: paging.h:40
PAGE_DEFAULT
#define PAGE_DEFAULT
Definition: paging.h:68
paging.h
PD_BASE_ADDR
#define PD_BASE_ADDR
Definition: paging.h:45
uint32_t
__uint32_t uint32_t
Definition: types.h:46
pidType
int pidType
Definition: types.h:75
VMM_KERN_STACK_START
#define VMM_KERN_STACK_START
Definition: vmm.h:67
vmm_getFreePage
void * vmm_getFreePage(pidType)
Definition: getfreepage.c:45
spinLock
Definition: spinlock.h:41
VMM_USER_START
#define VMM_USER_START
Definition: vmm.h:58
vmm_getFreeKernelPage
void * vmm_getFreeKernelPage(pidType pid, uint16_t count)
Definition: paging.c:291
PD_ENTRIES
#define PD_ENTRIES
Definition: paging.h:48
PAGE_SIZE
#define PAGE_SIZE
Definition: paging.h:37
KERNEL_PAGE_DEFAULT
#define KERNEL_PAGE_DEFAULT
Definition: paging.h:69
vmm_copyVirtualSpace
void * vmm_copyVirtualSpace(pidType pid)
Definition: copyvirtualspace.c:51
VMM_KERN_STACK_END
#define VMM_KERN_STACK_END
Definition: vmm.h:68
VMM_USER_END
#define VMM_USER_END
Definition: vmm.h:59
VMM_KERN_END
#define VMM_KERN_END
Definition: vmm.h:65
PT_BASE_ADDR
#define PT_BASE_ADDR
Definition: paging.h:46
PAGE_PRESENT
#define PAGE_PRESENT
Definition: paging.h:55