CS350 COS
COS
Loading...
Searching...
No Matches
palloc.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013-2023 Ali Mashtizadeh
3 * All rights reserved.
4 */
5
6#include <stdbool.h>
7#include <stdint.h>
8#include <stdarg.h>
9#include <string.h>
10
11#include <sys/cdefs.h>
12#include <sys/kassert.h>
13#include <sys/kdebug.h>
14#include <sys/kmem.h>
15#include <sys/queue.h>
16#include <sys/spinlock.h>
17
18// PGSIZE
19#include <machine/amd64.h>
20#include <machine/pmap.h>
21
22/* 'FREEPAGE' */
23#define FREEPAGE_MAGIC_FREE 0x4652454550414745ULL
24/* 'ALLOCATE' */
25#define FREEPAGE_MAGIC_INUSE 0x414c4c4f43415445ULL
26
30
31typedef struct FreePage
32{
34 LIST_ENTRY(FreePage) entries;
36
37typedef struct PageInfo
38{
41
45LIST_HEAD(FreeListHead, FreePage) freeList;
46
47/*
48 * Initializes the page allocator
49 */
50void
52{
53 totalPages = 0;
54 freePages = 0;
55
57
58 LIST_INIT(&freeList);
61}
62
70void
72{
73 void *pageInfoOld = pageInfoTable;
74
77 Panic("Cannot back pageInfoTable!");
78 }
79
81 memcpy(pageInfoTable, pageInfoOld, pageInfoLength);
82
83 // Free old pages
84}
85
91void
93{
94 uintptr_t i;
95 FreePage *pg;
96
97 if ((start % PGSIZE) != 0)
98 Panic("Region start is not page aligned!");
99 if ((len % PGSIZE) != 0)
100 Panic("Region length is not page aligned!");
101
102 /*
103 * PageInfo table isn't initialized on the first call to this function. We
104 * must allocate a temporary table that will be copied into the XMem region
105 * inside PAlloc_LateInit.
106 *
107 * Note that the PageInfo table is invalid for regions that are not added
108 * to the free list such as MMIO regions.
109 */
110 if (pageInfoTable == NULL) {
111 // Physical Address Offsets
113 uintptr_t end = base + len;
114
115 pageInfoLength = ROUNDUP(end / PGSIZE * sizeof(PageInfo), PGSIZE);
116 pageInfoTable = (PageInfo *)start;
117
118 start += pageInfoLength;
120
121 for (i = 0; i < (base / PGSIZE); i++) {
122 pageInfoTable[i].refCount = 1;
123 }
124 for (i = (base / PGSIZE); i < (end / PGSIZE); i++) {
125 pageInfoTable[i].refCount = 0;
126 }
127 for (i = 0; i < (pageInfoLength / PGSIZE); i++) {
128 pageInfoTable[i + (base / PGSIZE)].refCount = 1;
129 }
130 } else {
131 /*
132 * Only the first call to AddRegion should occur before the XMem region
133 * is initialized.
134 */
135
137
139 uintptr_t end = base + len;
140
141 uintptr_t newLength = ROUNDUP(end / PGSIZE * sizeof(PageInfo), PGSIZE);
142
143 if (!XMem_Allocate(pageInfoXMem, newLength))
144 Panic("Cannot allocate XMem region!");
145
146 // Initialize new pages
147 for (i = (base / PGSIZE); i < (end / PGSIZE); i++) {
148 pageInfoTable[i].refCount = 0;
149 }
150 }
151
153 for (i = 0; i < len; i += PGSIZE)
154 {
155 pg = (void *)(start + i);
157
158 totalPages++;
159 freePages++;
160
161 LIST_INSERT_HEAD(&freeList, pg, entries);
162 }
164}
165
171static inline PageInfo *
173{
174 uintptr_t entry = (uintptr_t)DMVA2PA(pg) / PGSIZE;
175 return &pageInfoTable[entry];
176}
177
187void *
189{
190 PageInfo *info;
191 FreePage *pg;
192
194 pg = LIST_FIRST(&freeList);
195 ASSERT(pg != NULL);
196 LIST_REMOVE(pg, entries);
197
199
200 info = PAllocGetInfo(pg);
201 ASSERT(info != NULL);
202 ASSERT(info->refCount == 0);
203 info->refCount++;
204
206
207 freePages--;
209
210 memset(pg, 0, PGSIZE);
211
212 return (void *)pg;
213}
214
220static void
221PAllocFreePage(void *region)
222{
223 FreePage *pg = (FreePage *)region;
224
225 ASSERT(((uintptr_t)region % PGSIZE) == 0);
226
227 LIST_INSERT_HEAD(&freeList, pg, entries);
228
229#ifndef NDEBUG
230 // Application can write this magic, but for
231 // debug builds we can use this as a double free check.
233
234 PageInfo *info = PAllocGetInfo(pg);
235 ASSERT(info->refCount == 0);
236#endif
237
239 freePages++;
240}
241
247void
249{
250 PageInfo *info = PAllocGetInfo(pg);
251
253 ASSERT(info->refCount != 0);
254 info->refCount++;
256}
257
264void
266{
267 PageInfo *info = PAllocGetInfo(pg);
268
270 ASSERT(info->refCount != 0);
271 info->refCount--;
272 if (info->refCount == 0)
273 PAllocFreePage(pg);
275}
276
277static void
278Debug_PAllocStats(int argc, const char *argv[])
279{
280 kprintf("Total Pages: %llu\n", totalPages);
281 kprintf("Allocated Pages: %llu\n", totalPages - freePages);
282 kprintf("Free Pages: %llu\n", freePages);
283}
284
285REGISTER_DBGCMD(pallocstats, "Page allocator statistics", Debug_PAllocStats);
286
287static void
288Debug_PAllocDump(int argc, const char *argv[])
289{
290 struct FreePage *it;
291
292 LIST_FOREACH(it, &freeList, entries) {
293 if (it->magic != FREEPAGE_MAGIC_FREE)
294 kprintf("Magic Corrupted! (%lx)\n", it->magic);
295 kprintf("Free %lx\n", (uintptr_t)it);
296 }
297}
298
299REGISTER_DBGCMD(pallocdump, "Dump page allocator's free list", Debug_PAllocDump);
300
#define ASSERT(_x)
Definition: kassert.h:8
int kprintf(const char *fmt,...)
Definition: printf.c:210
#define REGISTER_DBGCMD(_NAME, _DESC, _FUNC)
Definition: kdebug.h:11
void PAlloc_Init()
#define ROUNDUP(_x, _n)
Definition: malloc.c:32
#define PGSIZE
Definition: malloc.c:21
uint64_t len
Definition: multiboot.h:2
void PAlloc_Retain(void *pg)
Definition: palloc.c:248
void PAlloc_Release(void *pg)
Definition: palloc.c:265
PageInfo * pageInfoTable
Definition: palloc.c:43
#define FREEPAGE_MAGIC_FREE
Definition: palloc.c:23
uint64_t refCount
Definition: palloc.c:39
uint64_t magic
Definition: palloc.c:33
void * PAlloc_AllocPage()
Definition: palloc.c:188
static void PAllocFreePage(void *region)
Definition: palloc.c:221
uint64_t pageInfoLength
Definition: palloc.c:44
uint64_t totalPages
Definition: palloc.c:28
static PageInfo * PAllocGetInfo(void *pg)
Definition: palloc.c:172
#define FREEPAGE_MAGIC_INUSE
Definition: palloc.c:25
void PAlloc_AddRegion(uintptr_t start, uintptr_t len)
Definition: palloc.c:92
XMem * pageInfoXMem
Definition: palloc.c:42
static void Debug_PAllocDump(int argc, const char *argv[])
Definition: palloc.c:288
static void Debug_PAllocStats(int argc, const char *argv[])
Definition: palloc.c:278
void PAlloc_LateInit()
Definition: palloc.c:71
Spinlock pallocLock
Definition: palloc.c:27
uint64_t freePages
Definition: palloc.c:29
#define DMVA2PA(dmva)
Definition: pmap.h:47
#define LIST_INIT(head)
Definition: queue.h:430
#define LIST_REMOVE(elm, field)
Definition: queue.h:465
#define LIST_FIRST(head)
Definition: queue.h:408
#define LIST_FOREACH(var, head, field)
Definition: queue.h:410
#define LIST_INSERT_HEAD(head, elm, field)
Definition: queue.h:451
#define LIST_HEAD(name, type)
Definition: queue.h:363
#define LIST_ENTRY(type)
Definition: queue.h:371
static uint16_t base
Definition: sercons.c:37
void Spinlock_Unlock(Spinlock *lock) __UNLOCK_EX(*lock)
Definition: spinlock.c:109
#define SPINLOCK_TYPE_NORMAL
Definition: spinlock.h:12
void Spinlock_Lock(Spinlock *lock) __LOCK_EX(*lock)
Definition: spinlock.c:75
void Spinlock_Init(Spinlock *lock, const char *name, uint64_t type)
Definition: spinlock.c:43
#define NULL
Definition: stddef.h:6
void * memset(void *dst, int c, size_t len)
Definition: string.c:164
void * memcpy(void *dst, const void *src, size_t len)
Definition: string.c:177
uint64_t uintptr_t
Definition: types.h:16
unsigned long uint64_t
Definition: types.h:13
void Panic(const char *str)
Definition: vgacons.c:164
XMem * XMem_New()
Definition: xmem.c:47
bool XMem_Allocate(XMem *xmem, uintptr_t length)
Definition: xmem.c:92
uintptr_t XMem_GetBase(XMem *xmem)
Definition: xmem.c:80
Definition: xmem.c:18