UbixOS  2.0
vmm_memory.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 <sys/io.h>
31 #include <ubixos/kpanic.h>
32 #include <lib/kprintf.h>
33 #include <lib/kmalloc.h>
34 #include <ubixos/vitals.h>
35 #include <ubixos/spinlock.h>
36 #include <assert.h>
37 
38 //MrOlsen (2016-01-11) NOTE: Need to Seperate Out CPU Specific Stuff Over Time
39 #include <i386/cpu.h>
40 
41 static uint32_t freePages = 0;
42 static struct spinLock vmmSpinLock = SPIN_LOCK_INITIALIZER;
43 //static struct spinLock vmmCowSpinLock = SPIN_LOCK_INITIALIZER;
44 
45 int numPages = 0x0;
46 
48 
49 /************************************************************************
50 
51  Function: void vmm_memMapInit();
52  Description: This Function Initializes The Memory Map For the System
53  Notes:
54 
55  02/20/2004 - Made It Report Real And Available Memory
56 
57  ************************************************************************/
58 int vmm_memMapInit() {
59  int i = 0x0;
60  int memStart = 0x0;
61 
62  /* Count System Memory */
64 
65  /* Set Memory Map To Point To First Physical Page That We Will Use */
67 
68  /* Initialize Map Make All Pages Not Available */
69  for (i = 0x0; i < numPages; i++) {
70  vmmMemoryMap[i].cowCounter = 0x0;
72  vmmMemoryMap[i].pid = vmmID;
74  }
75 
76  /* Calculate Start Of Free Memory */
77  memStart = (0x101000 / 0x1000);
78 
79  memStart += (((sizeof(mMap) * numPages) + (sizeof(mMap) - 1)) / 0x1000);
80 
81  /* Initialize All Free Pages To Available */
82  vmmMemoryMap[(0x100000 / 0x1000)].status = memAvail;
83 
84  freePages++;
85 
86  for (i = memStart; i < numPages; i++) {
88  freePages++;
89  }
90 
91  if (systemVitals)
92  systemVitals->freePages = freePages;
93 
94  /* Print Out Amount Of Memory */
95  kprintf("Real Memory: %iKB\n", numPages * 4);
96  kprintf("Available Memory: %iKB\n", freePages * 4);
97 
98  /* Return */
99  return (0);
100 }
101 
102 /************************************************************************
103 
104  Function: int countMemory();
105  Description: This Function Counts The Systems Physical Memory
106  Notes:
107 
108  02/20/2004 - Inspect For Quality And Approved
109 
110  ************************************************************************/
111 int countMemory() {
112  register uInt32 *mem = 0x0;
113  unsigned long memCount = -1, tempMemory = 0x0;
114  unsigned short memKb = 8;
115  unsigned char irq1State, irq2State;
116  unsigned long cr0 = 0x0;
117 
118  /*
119  * Save The States Of Both IRQ 1 And 2 So We Can Turn Them Off And Restore
120  * Them Later
121  */
122  irq1State = inportByte(0x21);
123  irq2State = inportByte(0xA1);
124 
125  /* Turn Off IRQ 1 And 2 To Prevent Chances Of Faults While Examining Memory */
126  outportByte(0x21, 0xFF);
127  outportByte(0xA1, 0xFF);
128 
129  /* Save The State Of Register CR0 */
130  cr0 = rcr0();
131 
132  /*
133  asm volatile (
134  "movl %%cr0, %%ebx\n"
135  : "=a" (cr0)
136  :
137  : "ebx"
138  );
139  */
140 
141  asm volatile ("wbinvd");
142 
143  load_cr0(cr0 | 0x00000001 | 0x40000000 | 0x20000000);
144 
145  /*
146  asm volatile (
147  "movl %%ebx, %%cr0\n"
148  :
149  : "a" (cr0 | 0x00000001 | 0x40000000 | 0x20000000)
150  : "ebx"
151  );
152  */
153 
154  while (memKb < 4096 && memCount != 0) {
155  memKb++;
156 
157  if (memCount == -1)
158  memCount = 8388608;
159  else
160  memCount += 1024 * 1024;
161 
162  mem = (uInt32 *) memCount;
163 
164  tempMemory = *mem;
165 
166  *mem = 0x55AA55AA;
167 
168  asm("": : :"memory");
169 
170  if (*mem != 0x55AA55AA) {
171  memCount = 0;
172  }
173  else {
174  *mem = 0xAA55AA55;
175  asm("": : :"memory");
176  if (*mem != 0xAA55AA55) {
177  memCount = 0;
178  }
179  }
180  asm("": : :"memory");
181  *mem = tempMemory;
182  }
183 
184  asm("nop");
185 
186  //MrOlsen (2016-01-10) NOTE: I don't like this but I start incrementing form the start.
187  memKb--;
188 
189  asm("nop");
190 
191  load_cr0(cr0);
192 
193  /*
194  asm volatile (
195  "movl %%ebx, %%cr0\n"
196  :
197  : "a" (cr0)
198  : "ebx"
199  );
200  */
201 
202  asm("nop");
203 
204  /* Restore States For Both IRQ 1 And 2 */
205  outportByte(0x21, irq1State);
206  outportByte(0xA1, irq2State);
207 
208  asm("nop");
209 
210  /* Return Amount Of Memory In Pages */
211  return ((memKb * 1024 * 1024) / PAGE_SIZE);
212 }
213 
214 /************************************************************************
215 
216  Function: uInt32 vmm_findFreePage(pid_t pid);
217 
218  Description: This Returns A Free Physical Page Address Then Marks It
219  Not Available As Well As Setting The PID To The Proccess
220  Allocating This Page
221  Notes:
222 
223  ************************************************************************/
225 
226  int i = 0x0;
227 
228  /* Lets Look For A Free Page */
229  if (pid < sysID)
230  kpanic("Error: invalid PID %i\n", pid);
231 
232  spinLock(&vmmSpinLock);
233 
234  for (i = 0; i <= numPages; i++) {
235 
236  /*
237  * If We Found A Free Page Set It To Not Available After That Set Its Own
238  * And Return The Address
239  */
240  if ((vmmMemoryMap[i].status == memAvail) && (vmmMemoryMap[i].cowCounter == 0)) {
242  vmmMemoryMap[i].pid = pid;
243  freePages--;
244  if (systemVitals)
245  systemVitals->freePages = freePages;
246 
247  spinUnlock(&vmmSpinLock);
248  return (vmmMemoryMap[i].pageAddr);
249  }
250  }
251 
252  /* If No Free Memory Is Found Return NULL */
253  kpanic("Out Of Memory!!!!");
254  return (0x0);
255 }
256 
257 /************************************************************************
258 
259  Function: int freePage(uInt32 pageAddr);
260 
261  Description: This Function Marks The Page As Free
262 
263  Notes:
264 
265  ************************************************************************/
266 int freePage(uint32_t pageAddr) {
267 
268  int pageIndex = 0x0;
269  assert((pageAddr & 0xFFF) == 0x0);
270 
271  /* Find The Page Index To The Memory Map */
272  pageIndex = (pageAddr / 4096);
273 
274  /* Check If Page COW Is Greater Then 0 If It Is Dec It If Not Free It */
275  if (vmmMemoryMap[pageIndex].cowCounter == 0) {
276 
277  /* Set Page As Avail So It Can Be Used Again */
278  spinLock(&vmmSpinLock);
279  vmmMemoryMap[pageIndex].status = memAvail;
280  vmmMemoryMap[pageIndex].cowCounter = 0x0;
281  vmmMemoryMap[pageIndex].pid = -2;
282  freePages++;
283  systemVitals->freePages = freePages;
284  spinUnlock(&vmmSpinLock);
285 
286  }
287  else {
288  /* Adjust The COW Counter */
289  adjustCowCounter(((uint32_t) vmmMemoryMap[pageIndex].pageAddr), -1);
290  }
291 
292  /* Return */
293  return (0);
294 }
295 
296 /************************************************************************
297 
298  Function: int adjustCowCounter(uInt32 baseAddr,int adjustment);
299 
300  Description: This Adjust The COW Counter For Page At baseAddr It Will
301  Error If The Count Goes Below 0
302 
303  Notes:
304 
305  08/01/02 - I Think If Counter Gets To 0 I Should Free The Page
306 
307  ************************************************************************/
308 int adjustCowCounter(uInt32 baseAddr, int adjustment) {
309 
310  int vmmMemoryMapIndex = (baseAddr / PAGE_SIZE);
311 
312  assert((baseAddr & 0xFFF) == 0x0);
313 
314  spinLock(&vmmSpinLock);
315  /* Adjust COW Counter */
316  vmmMemoryMap[vmmMemoryMapIndex].cowCounter += adjustment;
317 
318  if (vmmMemoryMap[vmmMemoryMapIndex].cowCounter <= 0) {
319 
320  if (vmmMemoryMap[vmmMemoryMapIndex].cowCounter < 0)
321  kprintf("ERROR: Why is COW less than 0");
322 
323  vmmMemoryMap[vmmMemoryMapIndex].cowCounter = 0x0;
324  vmmMemoryMap[vmmMemoryMapIndex].pid = vmmID;
325  vmmMemoryMap[vmmMemoryMapIndex].status = memAvail;
326  freePages++;
327  systemVitals->freePages = freePages;
328  }
329 
330  spinUnlock(&vmmSpinLock);
331  /* Return */
332  return (0);
333 }
334 
335 /************************************************************************
336 
337  Function: void vmm_freeProcessPages(pid_t pid);
338 
339  Description: This Function Will Free Up Memory For The Exiting Process
340 
341  Notes:
342 
343  08/04/02 - Added Checking For COW Pages First
344 
345  ************************************************************************/
346 
347 /* TODO: This can be greatly improved for performance but it gets the job done */
348 void vmm_freeProcessPages(pidType pid) {
349  int i = 0, x = 0;
350  uint32_t *tmpPageTable = 0x0;
351  uint32_t *tmpPageDir = (uInt32 *) PD_BASE_ADDR;
352 
353  spinLock(&vmmSpinLock);
354 
355  /* Check Page Directory For An Avail Page Table */
356  //NOTE: This cleans all memory space up to kernel space
357 #ifdef _IGNORE
358  for (i = 0; i < (PAGE_SIZE - (PAGE_SIZE / 4)); i++) {
359 
360  if (tmpPageDir[i] != 0) {
361 
362  /* Set Up Page Table Pointer */
363  tmpPageTable = (uint32_t *) (PT_BASE_ADDR + (i * PAGE_SIZE));
364 
365  /* Check The Page Table For COW Pages */
366  for (x = 0; x < PD_ENTRIES; x++) {
367 
368  /* If The Page Is COW Adjust COW Counter */
369  if (((uint32_t) tmpPageTable[x] & PAGE_COW) == PAGE_COW) {
370  adjustCowCounter(((uint32_t) tmpPageTable[x] & 0xFFFFF000), -1);
371  }
372  }
373  }
374  }
375 #endif
376 
377  /* Loop Through Pages To Find Pages Owned By Process */
378  for (i = 0; i < numPages; i++) {
379  if (vmmMemoryMap[i].pid == pid) {
380  /* Check To See If The cowCounter Is Zero If So We Can Ree It */
381  if (vmmMemoryMap[i].cowCounter == 0) {
383  vmmMemoryMap[i].cowCounter = 0x0;
384  vmmMemoryMap[i].pid = vmmID;
385  freePages++;
386  systemVitals->freePages = freePages;
387  }
388  else {
389  spinUnlock(&vmmSpinLock);
390  adjustCowCounter((i * PAGE_SIZE), -1);
391  spinLock(&vmmSpinLock);
392  }
393  }
394  }
395 
396  /* Return */
397  spinUnlock(&vmmSpinLock);
398  return;
399 }
spinlock.h
mMap::pid
pid_t pid
Definition: vmm.h:106
uInt32
unsigned long int uInt32
Definition: objgfx30.h:49
mem
Definition: mem.c:264
PAGE_COW
#define PAGE_COW
Definition: paging.h:64
outportByte
void outportByte(unsigned int, unsigned char)
outputut one byte to specified port
Definition: io.c:72
memNotavail
#define memNotavail
Definition: vmm.h:42
assert
#define assert(e)
Definition: assert.h:64
assert.h
mMap::cowCounter
int cowCounter
Definition: vmm.h:107
spinUnlock
void spinUnlock(spinLock_t *lock)
Definition: spinlock.c:36
vmm.h
mMap::pageAddr
uint32_t pageAddr
Definition: vmm.h:103
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
mMap
Definition: vmm.h:102
adjustCowCounter
int adjustCowCounter(uInt32 baseAddr, int adjustment)
Definition: vmm_memory.c:303
spinLock
void spinLock(spinLock_t *lock)
Definition: spinlock.c:55
numPages
int numPages
Definition: vmm_memory.c:45
inportByte
unsigned char inportByte(unsigned int)
input one byte from specified port
Definition: io.c:38
countMemory
int countMemory()
Definition: vmm_memory.c:109
kpanic.h
freePage
int freePage(uint32_t pageAddr)
Definition: vmm_memory.c:262
systemVitals
vitalsNode * systemVitals
Definition: vitals.c:35
cpu.h
kprintf.h
vmm_findFreePage
uint32_t vmm_findFreePage(pidType pid)
Definition: vmm_memory.c:221
mMap::status
u_int16_t status
Definition: vmm.h:104
vitals.h
vmmMemoryMap
mMap * vmmMemoryMap
Definition: vmm_memory.c:47
PD_BASE_ADDR
#define PD_BASE_ADDR
Definition: paging.h:45
uint32_t
__uint32_t uint32_t
Definition: types.h:46
VMM_MMAP_ADDR_RMODE
#define VMM_MMAP_ADDR_RMODE
Definition: vmm.h:51
pidType
int pidType
Definition: types.h:75
vmm_freeProcessPages
void vmm_freeProcessPages(pidType pid)
Definition: vmm_memory.c:342
vitalsStruct::freePages
uint32_t freePages
Definition: vitals.h:43
spinLock
Definition: spinlock.h:41
io.h
vmmID
#define vmmID
Definition: vmm.h:43
PD_ENTRIES
#define PD_ENTRIES
Definition: paging.h:48
PAGE_SIZE
#define PAGE_SIZE
Definition: paging.h:37
memAvail
#define memAvail
Definition: vmm.h:41
vmm_memMapInit
int vmm_memMapInit()
Definition: vmm_memory.c:57
kprintf
int kprintf(const char *,...)
Definition: kprintf.c:259
PT_BASE_ADDR
#define PT_BASE_ADDR
Definition: paging.h:46
kmalloc.h
sysID
#define sysID
Definition: kmalloc.h:38