summaryrefslogtreecommitdiff
path: root/kernel/old/include/vm.h
blob: 6e3935ec215ab5822afb9c99e09570b35e913037 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
/**
** @file	vm.h
**
** @author	CSCI-452 class of 20245
**
** @brief	Virtual memory-related declarations.
*/

#ifndef VM_H_
#define VM_H_

#include <defs.h>
#include <types.h>

#include <procs.h>

/*
** VM layout of the system
**
** User processes use the first 4MB of the 32-bit address space; see the
** next comment for details.
**
** Kernel virtual addresses are in the "higher half" range, beginning
** at 0x80000000.  We define our mapping such that virtual address
** 0x8nnnnnnn maps to physical address 0x0nnnnnnn, so converting between
** the two is trivial.
*/

/*
** VM layout of process' address space
**
** Processes are limited to the first 4MB of the 32-bit address space:
**
**  Address Range            Contents
**  =======================  ================================
**  0x00000000 - 0x00000fff  page 0 is inaccessible
**  0x00001000 - 0x000..fff  text occupies pages 1 - N
**  0x000..000 - 0x000..fff  data occupies pages N+1 - N+d
**  0x000..000 - 0x000..fff  bss occupies pages N+d+1 - N+d+b
**  0x000..000 - 0x003fdfff  unusable
**  0x003fe000 - 0x003fffff  stack occupies last two pages
**
** This gives us the following page table structure:
**
** Page directory:
**   Entries    Contents
**   ========   ==============================
**   0          point to PMT for address space
**   1 - 1023   invalid
**
** Page map table:
**   Entries         Contents
**   ========        ==============================
**   0               invalid
**   1 - N           text frames
**   N+1 - N+d       data frames
**   N+d+1 - N+d+b   bss frames
**   N+d+b+1 - 1021  invalid
**   1022 - 1023     stack frames
*/

/*
** General (C and/or assembly) definitions
*/

// user virtual addresses
#define USER_TEXT      0x00001000
#define USER_STACK     0x003fe000
#define USER_STK_END   0x00400000

// how to find the addresses of the stack pages in the VM hierarchy
// user address space is the first 4MB of virtual memory
#define USER_PDE       0
// the stack occupies the last two pages of the address space
#define USER_STK_PTE1  1022
#define USER_STK_PTE2  1023

// some important memory addresses
#define KERN_BASE      0x80000000    // start of "kernel" memory
#define EXT_BASE       0x00100000    // start of "extended" memory (1MB)
#define DEV_BASE       0xfe000000    // "device" memory
#define PHYS_TOP       0x3fffffff    // last usable physical address (1GB - 1)

// where the kernel actually lives
#define KERN_PLINK     0x00010000
#define KERN_VLINK     (KERN_BASE + KERN_PLINK)

// number of entries in a page directory or page table
#define N_PDE          1024
#define N_PTE          1024

// index field shift counts and masks
#define PDIX_SHIFT     22
#define PTIX_SHIFT     12
#define PIX2I_MASK     0x3ff

// physical/virtual converters that don't use casting
// (usable from anywhere)
#define V2PNC(a)       ((a) - KERN_BASE)
#define P2VNC(a)       ((a) + KERN_BASE)

// page-size address rounding macros
#define SZ_PG_M1       MOD4K_BITS
#define SZ_PG_MASK     MOD4K_MASK
#define PGUP(a)        (((a)+SZ_PG_M1) & SZ_PG_MASK)
#define PGDOWN(a)      ((a) & SZ_PG_MASK)

// page directory entry bit fields
#define PDE_P          0x00000001	// 1 = present
#define PDE_RW         0x00000002	// 1 = writable
#define PDE_US         0x00000004	// 1 = user and system usable
#define PDE_PWT        0x00000008	// cache: 1 = write-through
#define PDE_PCD        0x00000010	// cache: 1 = disabled
#define PDE_A          0x00000020	// accessed
#define PDE_D          0x00000040	// dirty (4MB pages)
#define PDE_AVL1       0x00000040	// ignored (4KB pages)
#define PDE_PS         0x00000080	// 1 = 4MB page size
#define PDE_G          0x00000100	// global
#define PDE_AVL2       0x00000e00	// ignored
#define PDE_PAT        0x00001000	// (4MB pages) use page attribute table
#define PDE_PTA        0xfffff000	// page table address field (4KB pages)
#define PDE_FA         0xffc00000	// frame address field (4MB pages)

// page table entry bit fields
#define PTE_P          0x00000001	// present
#define PTE_RW         0x00000002	// 1 = writable
#define PTE_US         0x00000004	// 1 = user and system usable
#define PTE_PWT        0x00000008	// cache: 1 = write-through
#define PTE_PCD        0x00000010	// cache: 1 = disabled
#define PTE_A          0x00000020	// accessed
#define PTE_D          0x00000040	// dirty
#define PTE_PAT        0x00000080	// use page attribute table
#define PTE_G          0x00000100	// global
#define PTE_AVL2       0x00000e00	// ignored
#define PTE_FA         0xfffff000	// frame address field

// error code bit assignments for page faults
#define PFLT_P         0x00000001
#define PFLT_W         0x00000002
#define PFLT_US        0x00000004
#define PFLT_RSVD      0x00000008
#define PFLT_ID        0x00000010
#define PFLT_PK        0x00000020
#define PFLT_SS        0x00000040
#define PFLT_HLAT      0x00000080
#define PFLT_SGX       0x00008000
#define PFLT_UNUSED    0xffff7f00

#ifndef ASM_SRC

/*
** Start of C-only definitions
*/

// physical/virtual converters that do use casting
// (not usable from assembly)
#define V2P(a)         (((uint32_t)(a)) - KERN_BASE)
#define P2V(a)         (((uint32_t)(a)) + KERN_BASE)

// create a pde/pte from an integer frame number and permission bits
#define MKPDE(f,p)  ((pde_t)( TO_FRAME((f)) | (p) ))
#define MKPTE(f,p)  ((pte_t)( TO_FRAME((f)) | (p) ))

// is a PDE/PTE present?
// (P bit is in the same place in both)
#define IS_PRESENT(entry)  (((entry) & PDE_P) != 0 )

// is a PDE a 4MB page entry?
#define IS_LARGE(pde)      (((pde) & PDE_PS) != 0 )

// is this entry "system only" or "system and user"?
#define IS_SYSTEM(entry)   (((entry) & PDE_US) == 0 )
#define IS_USER(entry)     (((entry) & PDE_US) != 0 )

// low-order nine bits of PDEs and PTEs hold "permission" flag bits
#define PERMS_MASK          MOD4K_MASK

// 4KB frame numbers are 20 bits wide
#define	FRAME_4K_SHIFT 12
#define FRAME2I_4K_MASK    0x000fffff
#define TO_4KFRAME(n)      (((n)&FRAME2I_4K_MASK) << FRAME_4K_SHIFT)
#define GET_4KFRAME(n)     (((n) >> FRAME_4K_SHIFT)&F2I_4K_MASK)
#define PDE_4K_ADDR(n)     ((n) & MOD4K_MASK)
#define PTE_4K_ADDR(n)     ((n) & MOD4K_MASK)

// 4MB frame numbers are 10 bits wide
#define	FRAME_4M_SHIFT 22
#define FRAME2I_4M_MASK    0x000003ff
#define TO_4MFRAME(n)      (((n)&FRAME2I_4M_MASK) << FRAME_4M_SHIFT)
#define GET_4MFRAME(n)     (((n) >> FRAME_4M_SHIFT)&F2I_4M_MASK)
#define PDE_4M_ADDR(n)     ((n) & MOD4M_MASK)
#define PTE_4M_ADDR(n)     ((n) & MOD4M_MASK)

// extract the PMT address or frame address from a table entry
// PDEs could point to 4MB pages, or 4KB PMTs
#define PDE_ADDR(p)    (IS_LARGE(p)?(((uint32_t)p)&PDE_FA):(((uint32_t)p)&PDE_PTA))
// PTEs always point to 4KB pages
#define PTE_ADDR(p)    (((uint32_t)(p))&PTE_FA)
// everything has nine bits of permission flags
#define PERMS(p)       (((uint32_t)(p))&PERMS_MASK)

// extract the table indices from a 32-bit address
#define PDIX(v)        ((((uint32_t)(v)) >> PDIX_SHIFT) & PIX2I_MASK)
#define PTIX(v)        ((((uint32_t)(v)) >> PTIX_SHIFT) & PIX2I_MASK)

/*
** Types
*/

// page directory entries

// as a 32-bit word, in types.h
// typedef uint32_t pde_t;

// PDE for 4KB pages
typedef struct pdek_s {
	uint_t p    :1;   // present
	uint_t rw   :1;   // writable
	uint_t us   :1;   // user/supervisor
	uint_t pwt  :1;   // cache write-through
	uint_t pcd  :1;   // cache disable
	uint_t a    :1;   // accessed
	uint_t avl1 :1;   // ignored (available)
	uint_t ps   :1;   // page size (must be 0)
	uint_t avl2 :4;   // ignored (available)
	uint_t fa   :20;  // frame address
} pdek_f_t;

// PDE for 4MB pages
typedef struct pdem_s {
	uint_t p    :1;   // present
	uint_t rw   :1;   // writable
	uint_t us   :1;   // user/supervisor
	uint_t pwt  :1;   // cache write-through
	uint_t pcd  :1;   // cache disable
	uint_t a    :1;   // accessed
	uint_t d    :1;   // dirty
	uint_t ps   :1;   // page size (must be 1)
	uint_t g    :1;   // global
	uint_t avl  :3;   // ignored (available)
	uint_t fa   :20;  // frame address
} pdem_f_t;

// page table entries

// as a 32-bit word, in types.h
// typedef uint32_t pte_t;

// broken out into fields
typedef struct pte_s {
	uint_t p   :1;    // present
	uint_t rw  :1;    // writable
	uint_t us  :1;    // user/supervisor
	uint_t pwt :1;    // cache write-through
	uint_t pcd :1;    // cache disable
	uint_t a   :1;    // accessed
	uint_t d   :1;    // dirty
	uint_t pat :1;    // page attribute table in use
	uint_t g   :1;    // global
	uint_t avl :3;    // ignored (available)
	uint_t fa  :20;   // frame address
} ptef_t;

// page fault error code bits
// comment: meaning when 1 / meaning when 0
struct pfec_s {
	uint_t p    :1;		// page-level protection violation / !present
	uint_t w    :1;		// write / read
	uint_t us   :1;		// user-mode access / supervisor-mode access
	uint_t rsvd :1;		// reserved bit violation / not
	uint_t id   :1;		// instruction fetch / data fetch
	uint_t pk   :1;		// protection-key violation / !pk
	uint_t ss   :1;		// shadow stack access / !ss
	uint_t hlat :1;		// HLAT paging / ordinary paging or access rights
	uint_t xtr1 :7;		// unused
	uint_t sgz  :1;		// SGX-specific access control violation / !SGX
	uint_t xtr2 :16;	// more unused
};

typedef union pfec_u {
	uint32_t u;
	struct pfec_s s;
} pfec_t;

// Mapping descriptor for VA::PA mappings
typedef struct mapping_t {
	uint32_t va_start;  // starting virtual address for this range
	uint32_t pa_start;  // first physical address in the range
	uint32_t pa_end;    // last physical address in the range
	uint32_t perm;      // access control
} mapping_t;

/*
** Globals
*/

// created page directory for the kernel
extern pde_t *kpdir;

/*
** Prototypes
*/

/**
** Name:	vm_init
**
** Initialize the VM module
**
** Note: should not be called until after the memory free list has
** been set up.
*/
void vm_init( void );

/**
** Name:    vm_pagedup
**
** Duplicate a page of memory
**
** @param old  Pointer to the first byte of a page
**
** @return a pointer to the new, duplicate page, or NULL
*/
void *vm_pagedup( void *old );

/**
** Name:    vm_ptdup
**
** Duplicate a page directory entry
**
** @param dst   Pointer to where the duplicate should go
** @param curr  Pointer to the entry to be duplicated
**
** @return true on success, else false
*/
bool_t vm_ptdup( pde_t *dst, pde_t *curr );

/**
** Name:	vm_getpte
**
** Return the address of the PTE corresponding to the virtual address
** 'va' within the address space controlled by 'pgdir'. If there is no
** page table for that VA and 'alloc' is true, create the necessary
** page table entries.
**
** @param pdir   Pointer to the page directory to be searched
** @param va     The virtual address we're looking for
** @param alloc  Should we allocate a page table if there isn't one?
**
** @return A pointer to the page table entry for this VA, or NULL
*/
pte_t *vm_getpte( pde_t *pdir, const void *va, bool_t alloc );

/**
** Name:	vm_mkkvm
**
** Create the kernel's page table hierarchy
*/
pde_t *vm_mkkvm( void );

/**
** Name:	vm_mkuvm
**
** Create the page table hierarchy for a user process
*/
pde_t *vm_mkuvm( void );

/**
** Name:	vm_set_kvm
**
** Switch the page table register to the kernel's page directory
*/
void vm_set_kvm( void );

/**
** Name:	vm_set_uvm
**
** Switch the page table register to the page directory for a user process.
**
** @param p   The PCB of the user process
*/
void vm_set_uvm( pcb_t *p );

/**
** Name:    vm_add
**
** Add pages to the page hierarchy for a process, copying data into
** them if necessary.
**
** @param pdir   Pointer to the page directory to modify
** @param wr     "Writable" flag for the PTE
** @param sys    "System" flag for the PTE
** @param va     Starting VA of the range
** @param size   Amount of physical memory to allocate
** @param data   Pointer to data to copy, or NULL
** @param bytes  Number of bytes to copy
**
** @return status of the allocation attempt
*/
int vm_add( pde_t *pdir, bool_t wr, bool_t sys,
		void *va, uint32_t size, char *data, uint32_t bytes );

/**
** Name:	vm_free
**
** Deallocate a page table hierarchy and all physical memory frames
** in the user portion.
**
** @param pdir  Pointer to the page directory
*/
void vm_free( pde_t *pdir );

/*
** Name:	vm_map
**
** Create PTEs for virtual addresses starting at 'va' that refer to
** physical addresses in the range [pa, pa+size-1]. We aren't guaranteed
** that va is page-aligned.
**
** @param pdir  Page directory for this address space
** @param va    The starting virtual address
** @param size  Length of the range to be mapped
** @param pa    The starting physical address
** @param perm  Permission bits for the PTEs
*/
int vm_map( pde_t *pdir, void *va, uint_t size, uint_t pa, int perm );

/**
** Name:    vm_uvmdup
**
** Create a duplicate of the user portio of an existing page table
** hierarchy. We assume that the "new" page directory exists and
** the system portions of it should not be touched.
**
** @param old  Existing page directory
** @param new  New page directory
**
** @return status of the duplication attempt
*/
int vm_uvmdup( pde_t *old, pde_t *new );

#endif  /* !ASM_SRC */

#endif